• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2016 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // TransformFeedbackVk.cpp:
7 //    Implements the class methods for TransformFeedbackVk.
8 //
9 
10 #include "libANGLE/renderer/vulkan/TransformFeedbackVk.h"
11 
12 #include "libANGLE/Context.h"
13 #include "libANGLE/Query.h"
14 #include "libANGLE/renderer/vulkan/BufferVk.h"
15 #include "libANGLE/renderer/vulkan/ContextVk.h"
16 #include "libANGLE/renderer/vulkan/FramebufferVk.h"
17 #include "libANGLE/renderer/vulkan/ProgramVk.h"
18 #include "libANGLE/renderer/vulkan/QueryVk.h"
19 #include "libANGLE/renderer/vulkan/ShaderInterfaceVariableInfoMap.h"
20 
21 #include "common/debug.h"
22 
23 namespace rx
24 {
TransformFeedbackVk(const gl::TransformFeedbackState & state)25 TransformFeedbackVk::TransformFeedbackVk(const gl::TransformFeedbackState &state)
26     : TransformFeedbackImpl(state),
27       mRebindTransformFeedbackBuffer(false),
28       mBufferHelpers{},
29       mBufferHandles{},
30       mBufferOffsets{},
31       mBufferSizes{},
32       mCounterBufferHandles{},
33       mCounterBufferOffsets{}
34 {
35     mBufferObserverBindings.reserve(gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS);
36     for (angle::SubjectIndex bufferIndex = 0;
37          bufferIndex < gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; ++bufferIndex)
38     {
39         mBufferObserverBindings.emplace_back(this, bufferIndex);
40     }
41 }
42 
~TransformFeedbackVk()43 TransformFeedbackVk::~TransformFeedbackVk() {}
44 
onDestroy(const gl::Context * context)45 void TransformFeedbackVk::onDestroy(const gl::Context *context)
46 {
47     ContextVk *contextVk   = vk::GetImpl(context);
48     releaseCounterBuffers(contextVk);
49 }
50 
releaseCounterBuffers(vk::Context * context)51 void TransformFeedbackVk::releaseCounterBuffers(vk::Context *context)
52 {
53     for (vk::BufferHelper &bufferHelper : mCounterBufferHelpers)
54     {
55         bufferHelper.release(context);
56     }
57     for (VkBuffer &buffer : mCounterBufferHandles)
58     {
59         buffer = VK_NULL_HANDLE;
60     }
61     for (VkDeviceSize &offset : mCounterBufferOffsets)
62     {
63         offset = 0;
64     }
65 }
66 
initializeXFBVariables(ContextVk * contextVk,uint32_t xfbBufferCount)67 void TransformFeedbackVk::initializeXFBVariables(ContextVk *contextVk, uint32_t xfbBufferCount)
68 {
69     for (uint32_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex)
70     {
71         const gl::OffsetBindingPointer<gl::Buffer> &binding = mState.getIndexedBuffer(bufferIndex);
72         ASSERT(binding.get());
73 
74         BufferVk *bufferVk = vk::GetImpl(binding.get());
75 
76         if (bufferVk->isBufferValid())
77         {
78             mBufferHelpers[bufferIndex] = &bufferVk->getBuffer();
79             mBufferOffsets[bufferIndex] =
80                 binding.getOffset() + mBufferHelpers[bufferIndex]->getOffset();
81             mBufferSizes[bufferIndex] = gl::GetBoundBufferAvailableSize(binding);
82             mBufferObserverBindings[bufferIndex].bind(bufferVk);
83         }
84         else
85         {
86             // This can happen in error conditions.
87             vk::BufferHelper &nullBuffer = contextVk->getEmptyBuffer();
88             mBufferHelpers[bufferIndex]  = &nullBuffer;
89             mBufferOffsets[bufferIndex]  = 0;
90             mBufferSizes[bufferIndex]    = nullBuffer.getSize();
91             mBufferObserverBindings[bufferIndex].reset();
92         }
93     }
94 }
95 
begin(const gl::Context * context,gl::PrimitiveMode primitiveMode)96 angle::Result TransformFeedbackVk::begin(const gl::Context *context,
97                                          gl::PrimitiveMode primitiveMode)
98 {
99     ContextVk *contextVk = vk::GetImpl(context);
100 
101     const gl::ProgramExecutable *executable = contextVk->getState().getProgramExecutable();
102     ASSERT(executable);
103     size_t xfbBufferCount = executable->getTransformFeedbackBufferCount();
104 
105     initializeXFBVariables(contextVk, static_cast<uint32_t>(xfbBufferCount));
106 
107     for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex)
108     {
109         mBufferHandles[bufferIndex] = mBufferHelpers[bufferIndex]->getBuffer().getHandle();
110         if (contextVk->getFeatures().supportsTransformFeedbackExtension.enabled)
111         {
112             if (mCounterBufferHandles[bufferIndex] == VK_NULL_HANDLE)
113             {
114                 vk::BufferHelper &bufferHelper = mCounterBufferHelpers[bufferIndex];
115                 ANGLE_TRY(contextVk->initBufferAllocation(
116                     &bufferHelper, contextVk->getRenderer()->getDeviceLocalMemoryTypeIndex(), 16,
117                     contextVk->getRenderer()->getDefaultBufferAlignment(),
118                     BufferUsageType::Static));
119                 mCounterBufferHandles[bufferIndex] = bufferHelper.getBuffer().getHandle();
120                 mCounterBufferOffsets[bufferIndex] = bufferHelper.getOffset();
121             }
122         }
123     }
124 
125     if (contextVk->getFeatures().supportsTransformFeedbackExtension.enabled)
126     {
127         mRebindTransformFeedbackBuffer = true;
128     }
129 
130     return contextVk->onBeginTransformFeedback(xfbBufferCount, mBufferHelpers,
131                                                mCounterBufferHelpers);
132 }
133 
end(const gl::Context * context)134 angle::Result TransformFeedbackVk::end(const gl::Context *context)
135 {
136     ContextVk *contextVk = vk::GetImpl(context);
137 
138     // If there's an active transform feedback query, accumulate the primitives drawn.
139     const gl::State &glState = context->getState();
140     gl::Query *transformFeedbackQuery =
141         glState.getActiveQuery(gl::QueryType::TransformFeedbackPrimitivesWritten);
142 
143     if (transformFeedbackQuery && contextVk->getFeatures().emulateTransformFeedback.enabled)
144     {
145         vk::GetImpl(transformFeedbackQuery)->onTransformFeedbackEnd(mState.getPrimitivesDrawn());
146     }
147 
148     for (angle::ObserverBinding &bufferBinding : mBufferObserverBindings)
149     {
150         bufferBinding.reset();
151     }
152 
153     contextVk->onEndTransformFeedback();
154 
155     releaseCounterBuffers(contextVk);
156 
157     return angle::Result::Continue;
158 }
159 
pause(const gl::Context * context)160 angle::Result TransformFeedbackVk::pause(const gl::Context *context)
161 {
162     ContextVk *contextVk = vk::GetImpl(context);
163     return contextVk->onPauseTransformFeedback();
164 }
165 
resume(const gl::Context * context)166 angle::Result TransformFeedbackVk::resume(const gl::Context *context)
167 {
168     ContextVk *contextVk                    = vk::GetImpl(context);
169     const gl::ProgramExecutable *executable = contextVk->getState().getProgramExecutable();
170     ASSERT(executable);
171     size_t xfbBufferCount = executable->getTransformFeedbackBufferCount();
172 
173     if (contextVk->getFeatures().emulateTransformFeedback.enabled)
174     {
175         initializeXFBVariables(contextVk, static_cast<uint32_t>(xfbBufferCount));
176     }
177 
178     return contextVk->onBeginTransformFeedback(xfbBufferCount, mBufferHelpers,
179                                                mCounterBufferHelpers);
180 }
181 
bindIndexedBuffer(const gl::Context * context,size_t index,const gl::OffsetBindingPointer<gl::Buffer> & binding)182 angle::Result TransformFeedbackVk::bindIndexedBuffer(
183     const gl::Context *context,
184     size_t index,
185     const gl::OffsetBindingPointer<gl::Buffer> &binding)
186 {
187     ContextVk *contextVk = vk::GetImpl(context);
188 
189     // Make sure the transform feedback buffers are bound to the program descriptor sets.
190     contextVk->invalidateCurrentTransformFeedbackBuffers();
191 
192     return angle::Result::Continue;
193 }
194 
getBufferOffsets(ContextVk * contextVk,GLint drawCallFirstVertex,int32_t * offsetsOut,size_t offsetsSize) const195 void TransformFeedbackVk::getBufferOffsets(ContextVk *contextVk,
196                                            GLint drawCallFirstVertex,
197                                            int32_t *offsetsOut,
198                                            size_t offsetsSize) const
199 {
200     if (!contextVk->getFeatures().emulateTransformFeedback.enabled)
201     {
202         return;
203     }
204 
205     GLsizeiptr verticesDrawn                = mState.getVerticesDrawn();
206     const gl::ProgramExecutable *executable = contextVk->getState().getProgramExecutable();
207     ASSERT(executable);
208     const std::vector<GLsizei> &bufferStrides = executable->getTransformFeedbackStrides();
209     size_t xfbBufferCount                     = executable->getTransformFeedbackBufferCount();
210     const VkDeviceSize offsetAlignment        = contextVk->getRenderer()
211                                              ->getPhysicalDeviceProperties()
212                                              .limits.minStorageBufferOffsetAlignment;
213 
214     ASSERT(xfbBufferCount > 0);
215 
216     // The caller should make sure the offsets array has enough space.  The maximum possible
217     // number of outputs is gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS.
218     ASSERT(offsetsSize >= xfbBufferCount);
219 
220     for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex)
221     {
222         int64_t offsetFromDescriptor =
223             static_cast<int64_t>(mBufferOffsets[bufferIndex] % offsetAlignment);
224         int64_t drawCallVertexOffset = static_cast<int64_t>(verticesDrawn) - drawCallFirstVertex;
225 
226         int64_t writeOffset =
227             (offsetFromDescriptor + drawCallVertexOffset * bufferStrides[bufferIndex]) /
228             static_cast<int64_t>(sizeof(uint32_t));
229 
230         offsetsOut[bufferIndex] = static_cast<int32_t>(writeOffset);
231 
232         // Assert on overflow.  For now, support transform feedback up to 2GB.
233         ASSERT(offsetsOut[bufferIndex] == writeOffset);
234     }
235 }
236 
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)237 void TransformFeedbackVk::onSubjectStateChange(angle::SubjectIndex index,
238                                                angle::SubjectMessage message)
239 {
240     if (message == angle::SubjectMessage::InternalMemoryAllocationChanged)
241     {
242         ASSERT(index < mBufferObserverBindings.size());
243         const gl::OffsetBindingPointer<gl::Buffer> &binding = mState.getIndexedBuffer(index);
244         ASSERT(binding.get());
245 
246         BufferVk *bufferVk = vk::GetImpl(binding.get());
247 
248         ASSERT(bufferVk->isBufferValid());
249         mBufferHelpers[index] = &bufferVk->getBuffer();
250         mBufferOffsets[index] = binding.getOffset() + mBufferHelpers[index]->getOffset();
251         mBufferSizes[index]   = std::min<VkDeviceSize>(gl::GetBoundBufferAvailableSize(binding),
252                                                        mBufferHelpers[index]->getSize());
253         mBufferObserverBindings[index].bind(bufferVk);
254         mBufferHandles[index] = mBufferHelpers[index]->getBuffer().getHandle();
255     }
256 }
257 
updateTransformFeedbackDescriptorDesc(const vk::Context * context,const gl::ProgramExecutable & executable,const ShaderInterfaceVariableInfoMap & variableInfoMap,const vk::WriteDescriptorDescs & writeDescriptorDescs,const vk::BufferHelper & emptyBuffer,bool activeUnpaused,vk::DescriptorSetDescBuilder * builder) const258 void TransformFeedbackVk::updateTransformFeedbackDescriptorDesc(
259     const vk::Context *context,
260     const gl::ProgramExecutable &executable,
261     const ShaderInterfaceVariableInfoMap &variableInfoMap,
262     const vk::WriteDescriptorDescs &writeDescriptorDescs,
263     const vk::BufferHelper &emptyBuffer,
264     bool activeUnpaused,
265     vk::DescriptorSetDescBuilder *builder) const
266 {
267     size_t xfbBufferCount = executable.getTransformFeedbackBufferCount();
268     for (uint32_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex)
269     {
270         if (mBufferHelpers[bufferIndex] && activeUnpaused)
271         {
272             builder->updateTransformFeedbackBuffer(context, variableInfoMap, writeDescriptorDescs,
273                                                    bufferIndex, *mBufferHelpers[bufferIndex],
274                                                    mBufferOffsets[bufferIndex],
275                                                    mBufferSizes[bufferIndex]);
276         }
277         else
278         {
279             builder->updateTransformFeedbackBuffer(context, variableInfoMap, writeDescriptorDescs,
280                                                    bufferIndex, emptyBuffer, 0,
281                                                    emptyBuffer.getSize());
282         }
283     }
284 }
285 
onNewDescriptorSet(const gl::ProgramExecutable & executable,const vk::SharedDescriptorSetCacheKey & sharedCacheKey)286 void TransformFeedbackVk::onNewDescriptorSet(const gl::ProgramExecutable &executable,
287                                              const vk::SharedDescriptorSetCacheKey &sharedCacheKey)
288 {
289     size_t xfbBufferCount = executable.getTransformFeedbackBufferCount();
290     for (uint32_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex)
291     {
292         if (mBufferHelpers[bufferIndex])
293         {
294             mBufferHelpers[bufferIndex]->onNewDescriptorSet(sharedCacheKey);
295         }
296     }
297 }
298 }  // namespace rx
299