• 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/glslang_wrapper_utils.h"
15 #include "libANGLE/renderer/vulkan/BufferVk.h"
16 #include "libANGLE/renderer/vulkan/ContextVk.h"
17 #include "libANGLE/renderer/vulkan/FramebufferVk.h"
18 #include "libANGLE/renderer/vulkan/ProgramVk.h"
19 #include "libANGLE/renderer/vulkan/QueryVk.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     for (angle::SubjectIndex bufferIndex = 0;
36          bufferIndex < gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; ++bufferIndex)
37     {
38         mBufferObserverBindings.emplace_back(this, bufferIndex);
39     }
40 }
41 
~TransformFeedbackVk()42 TransformFeedbackVk::~TransformFeedbackVk() {}
43 
onDestroy(const gl::Context * context)44 void TransformFeedbackVk::onDestroy(const gl::Context *context)
45 {
46     ContextVk *contextVk   = vk::GetImpl(context);
47     RendererVk *rendererVk = contextVk->getRenderer();
48 
49     releaseCounterBuffers(rendererVk);
50 }
51 
releaseCounterBuffers(RendererVk * renderer)52 void TransformFeedbackVk::releaseCounterBuffers(RendererVk *renderer)
53 {
54     for (vk::BufferHelper &bufferHelper : mCounterBufferHelpers)
55     {
56         bufferHelper.release(renderer);
57     }
58     for (VkBuffer &buffer : mCounterBufferHandles)
59     {
60         buffer = VK_NULL_HANDLE;
61     }
62     for (VkDeviceSize &offset : mCounterBufferOffsets)
63     {
64         offset = 0;
65     }
66 }
67 
initializeXFBBuffersDesc(ContextVk * contextVk,size_t xfbBufferCount)68 void TransformFeedbackVk::initializeXFBBuffersDesc(ContextVk *contextVk, size_t xfbBufferCount)
69 {
70     mXFBBuffersDesc.reset();
71     for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex)
72     {
73         const gl::OffsetBindingPointer<gl::Buffer> &binding = mState.getIndexedBuffer(bufferIndex);
74         ASSERT(binding.get());
75 
76         BufferVk *bufferVk = vk::GetImpl(binding.get());
77 
78         if (bufferVk->isBufferValid())
79         {
80             mBufferHelpers[bufferIndex] = &bufferVk->getBuffer();
81             mBufferOffsets[bufferIndex] =
82                 binding.getOffset() + mBufferHelpers[bufferIndex]->getOffset();
83             mBufferSizes[bufferIndex] = gl::GetBoundBufferAvailableSize(binding);
84             mBufferObserverBindings[bufferIndex].bind(bufferVk);
85         }
86         else
87         {
88             // This can happen in error conditions.
89             vk::BufferHelper &nullBuffer = contextVk->getEmptyBuffer();
90             mBufferHelpers[bufferIndex]  = &nullBuffer;
91             mBufferOffsets[bufferIndex]  = 0;
92             mBufferSizes[bufferIndex]    = nullBuffer.getSize();
93             mBufferObserverBindings[bufferIndex].reset();
94         }
95 
96         mXFBBuffersDesc.updateTransformFeedbackBuffer(
97             bufferIndex, mBufferHelpers[bufferIndex]->getBufferSerial(),
98             mBufferOffsets[bufferIndex]);
99     }
100 }
101 
begin(const gl::Context * context,gl::PrimitiveMode primitiveMode)102 angle::Result TransformFeedbackVk::begin(const gl::Context *context,
103                                          gl::PrimitiveMode primitiveMode)
104 {
105     ContextVk *contextVk = vk::GetImpl(context);
106 
107     const gl::ProgramExecutable *executable = contextVk->getState().getProgramExecutable();
108     ASSERT(executable);
109     size_t xfbBufferCount = executable->getTransformFeedbackBufferCount();
110 
111     initializeXFBBuffersDesc(contextVk, xfbBufferCount);
112 
113     for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex)
114     {
115         mBufferHandles[bufferIndex] = mBufferHelpers[bufferIndex]->getBuffer().getHandle();
116         if (contextVk->getFeatures().supportsTransformFeedbackExtension.enabled)
117         {
118             if (mCounterBufferHandles[bufferIndex] == VK_NULL_HANDLE)
119             {
120                 vk::BufferHelper &bufferHelper = mCounterBufferHelpers[bufferIndex];
121                 ANGLE_TRY(bufferHelper.initSuballocation(
122                     contextVk, contextVk->getRenderer()->getDeviceLocalMemoryTypeIndex(), 16,
123                     contextVk->getRenderer()->getDefaultBufferAlignment()));
124                 mCounterBufferHandles[bufferIndex] = bufferHelper.getBuffer().getHandle();
125                 mCounterBufferOffsets[bufferIndex] = bufferHelper.getOffset();
126             }
127         }
128     }
129 
130     if (contextVk->getFeatures().supportsTransformFeedbackExtension.enabled)
131     {
132         mRebindTransformFeedbackBuffer = true;
133     }
134 
135     return contextVk->onBeginTransformFeedback(xfbBufferCount, mBufferHelpers,
136                                                mCounterBufferHelpers);
137 }
138 
end(const gl::Context * context)139 angle::Result TransformFeedbackVk::end(const gl::Context *context)
140 {
141     ContextVk *contextVk = vk::GetImpl(context);
142 
143     // If there's an active transform feedback query, accumulate the primitives drawn.
144     const gl::State &glState = context->getState();
145     gl::Query *transformFeedbackQuery =
146         glState.getActiveQuery(gl::QueryType::TransformFeedbackPrimitivesWritten);
147 
148     if (transformFeedbackQuery && contextVk->getFeatures().emulateTransformFeedback.enabled)
149     {
150         vk::GetImpl(transformFeedbackQuery)->onTransformFeedbackEnd(mState.getPrimitivesDrawn());
151     }
152 
153     for (angle::ObserverBinding &bufferBinding : mBufferObserverBindings)
154     {
155         bufferBinding.reset();
156     }
157 
158     contextVk->onEndTransformFeedback();
159 
160     releaseCounterBuffers(contextVk->getRenderer());
161 
162     return angle::Result::Continue;
163 }
164 
pause(const gl::Context * context)165 angle::Result TransformFeedbackVk::pause(const gl::Context *context)
166 {
167     ContextVk *contextVk = vk::GetImpl(context);
168 
169     if (contextVk->getFeatures().emulateTransformFeedback.enabled)
170     {
171         // Bind the empty buffer until we resume.
172         const gl::ProgramExecutable *executable = contextVk->getState().getProgramExecutable();
173         ASSERT(executable);
174         size_t xfbBufferCount = executable->getTransformFeedbackBufferCount();
175 
176         const vk::BufferHelper &emptyBuffer = contextVk->getEmptyBuffer();
177 
178         for (size_t xfbIndex = 0; xfbIndex < xfbBufferCount; ++xfbIndex)
179         {
180             mXFBBuffersDesc.updateTransformFeedbackBuffer(xfbIndex, emptyBuffer.getBufferSerial(),
181                                                           0);
182         }
183     }
184 
185     return contextVk->onPauseTransformFeedback();
186 }
187 
resume(const gl::Context * context)188 angle::Result TransformFeedbackVk::resume(const gl::Context *context)
189 {
190     ContextVk *contextVk                    = vk::GetImpl(context);
191     const gl::ProgramExecutable *executable = contextVk->getState().getProgramExecutable();
192     ASSERT(executable);
193     size_t xfbBufferCount = executable->getTransformFeedbackBufferCount();
194 
195     if (contextVk->getFeatures().emulateTransformFeedback.enabled)
196     {
197         initializeXFBBuffersDesc(contextVk, xfbBufferCount);
198     }
199 
200     return contextVk->onBeginTransformFeedback(xfbBufferCount, mBufferHelpers,
201                                                mCounterBufferHelpers);
202 }
203 
bindIndexedBuffer(const gl::Context * context,size_t index,const gl::OffsetBindingPointer<gl::Buffer> & binding)204 angle::Result TransformFeedbackVk::bindIndexedBuffer(
205     const gl::Context *context,
206     size_t index,
207     const gl::OffsetBindingPointer<gl::Buffer> &binding)
208 {
209     ContextVk *contextVk = vk::GetImpl(context);
210 
211     // Make sure the transform feedback buffers are bound to the program descriptor sets.
212     contextVk->invalidateCurrentTransformFeedbackBuffers();
213 
214     return angle::Result::Continue;
215 }
216 
updateDescriptorSetLayout(ContextVk * contextVk,const ShaderInterfaceVariableInfoMap & variableInfoMap,size_t xfbBufferCount,vk::DescriptorSetLayoutDesc * descSetLayoutOut) const217 void TransformFeedbackVk::updateDescriptorSetLayout(
218     ContextVk *contextVk,
219     const ShaderInterfaceVariableInfoMap &variableInfoMap,
220     size_t xfbBufferCount,
221     vk::DescriptorSetLayoutDesc *descSetLayoutOut) const
222 {
223     if (!contextVk->getFeatures().emulateTransformFeedback.enabled)
224     {
225         return;
226     }
227 
228     for (uint32_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex)
229     {
230         const ShaderInterfaceVariableInfo &info =
231             variableInfoMap.getTransformFeedbackInfo(gl::ShaderType::Vertex, bufferIndex);
232 
233         ASSERT(info.binding != std::numeric_limits<uint32_t>::max());
234 
235         descSetLayoutOut->update(info.binding, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
236                                  VK_SHADER_STAGE_VERTEX_BIT, nullptr);
237     }
238 }
239 
initDescriptorSet(vk::Context * context,UpdateDescriptorSetsBuilder * updateBuilder,vk::BufferHelper * emptyBuffer,const ShaderInterfaceVariableInfoMap & variableInfoMap,size_t xfbBufferCount,VkDescriptorSet descSet) const240 void TransformFeedbackVk::initDescriptorSet(vk::Context *context,
241                                             UpdateDescriptorSetsBuilder *updateBuilder,
242                                             vk::BufferHelper *emptyBuffer,
243                                             const ShaderInterfaceVariableInfoMap &variableInfoMap,
244                                             size_t xfbBufferCount,
245                                             VkDescriptorSet descSet) const
246 {
247     if (!context->getRenderer()->getFeatures().emulateTransformFeedback.enabled)
248     {
249         return;
250     }
251 
252     VkDescriptorBufferInfo *descriptorBufferInfo =
253         updateBuilder->allocDescriptorBufferInfos(xfbBufferCount);
254 
255     for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex)
256     {
257         VkDescriptorBufferInfo &bufferInfo = descriptorBufferInfo[bufferIndex];
258         bufferInfo.buffer                  = emptyBuffer->getBuffer().getHandle();
259         bufferInfo.offset                  = emptyBuffer->getOffset();
260         bufferInfo.range                   = emptyBuffer->getSize();
261     }
262 
263     writeDescriptorSet(context, updateBuilder, variableInfoMap, xfbBufferCount,
264                        descriptorBufferInfo, descSet);
265 }
266 
updateDescriptorSet(vk::Context * context,UpdateDescriptorSetsBuilder * updateBuilder,const gl::ProgramExecutable & executable,const ShaderInterfaceVariableInfoMap & variableInfoMap,VkDescriptorSet descSet) const267 void TransformFeedbackVk::updateDescriptorSet(vk::Context *context,
268                                               UpdateDescriptorSetsBuilder *updateBuilder,
269                                               const gl::ProgramExecutable &executable,
270                                               const ShaderInterfaceVariableInfoMap &variableInfoMap,
271                                               VkDescriptorSet descSet) const
272 {
273     RendererVk *renderer = context->getRenderer();
274 
275     if (!renderer->getFeatures().emulateTransformFeedback.enabled)
276     {
277         return;
278     }
279 
280     size_t xfbBufferCount = executable.getTransformFeedbackBufferCount();
281     const VkDeviceSize offsetAlignment =
282         renderer->getPhysicalDeviceProperties().limits.minStorageBufferOffsetAlignment;
283 
284     ASSERT(xfbBufferCount > 0);
285     ASSERT(executable.getTransformFeedbackBufferMode() != GL_INTERLEAVED_ATTRIBS ||
286            xfbBufferCount == 1);
287 
288     VkDescriptorBufferInfo *descriptorBufferInfo =
289         updateBuilder->allocDescriptorBufferInfos(xfbBufferCount);
290 
291     // Update buffer descriptor binding info for output buffers
292     for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex)
293     {
294         VkDescriptorBufferInfo &bufferInfo = descriptorBufferInfo[bufferIndex];
295 
296         bufferInfo.buffer = mBufferHandles[bufferIndex];
297         // Set the offset as close as possible to the requested offset while remaining aligned.
298         bufferInfo.offset = (mBufferOffsets[bufferIndex] / offsetAlignment) * offsetAlignment;
299         bufferInfo.range =
300             mBufferSizes[bufferIndex] + (mBufferOffsets[bufferIndex] - bufferInfo.offset);
301         ASSERT(bufferInfo.range != 0);
302     }
303 
304     writeDescriptorSet(context, updateBuilder, variableInfoMap, xfbBufferCount,
305                        descriptorBufferInfo, descSet);
306 }
307 
getBufferOffsets(ContextVk * contextVk,GLint drawCallFirstVertex,int32_t * offsetsOut,size_t offsetsSize) const308 void TransformFeedbackVk::getBufferOffsets(ContextVk *contextVk,
309                                            GLint drawCallFirstVertex,
310                                            int32_t *offsetsOut,
311                                            size_t offsetsSize) const
312 {
313     if (!contextVk->getFeatures().emulateTransformFeedback.enabled)
314     {
315         return;
316     }
317 
318     GLsizeiptr verticesDrawn                = mState.getVerticesDrawn();
319     const gl::ProgramExecutable *executable = contextVk->getState().getProgramExecutable();
320     ASSERT(executable);
321     const std::vector<GLsizei> &bufferStrides = executable->getTransformFeedbackStrides();
322     size_t xfbBufferCount                     = executable->getTransformFeedbackBufferCount();
323     const VkDeviceSize offsetAlignment        = contextVk->getRenderer()
324                                              ->getPhysicalDeviceProperties()
325                                              .limits.minStorageBufferOffsetAlignment;
326 
327     ASSERT(xfbBufferCount > 0);
328 
329     // The caller should make sure the offsets array has enough space.  The maximum possible
330     // number of outputs is gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS.
331     ASSERT(offsetsSize >= xfbBufferCount);
332 
333     for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex)
334     {
335         int64_t offsetFromDescriptor =
336             static_cast<int64_t>(mBufferOffsets[bufferIndex] % offsetAlignment);
337         int64_t drawCallVertexOffset = static_cast<int64_t>(verticesDrawn) - drawCallFirstVertex;
338 
339         int64_t writeOffset =
340             (offsetFromDescriptor + drawCallVertexOffset * bufferStrides[bufferIndex]) /
341             static_cast<int64_t>(sizeof(uint32_t));
342 
343         offsetsOut[bufferIndex] = static_cast<int32_t>(writeOffset);
344 
345         // Assert on overflow.  For now, support transform feedback up to 2GB.
346         ASSERT(offsetsOut[bufferIndex] == writeOffset);
347     }
348 }
349 
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)350 void TransformFeedbackVk::onSubjectStateChange(angle::SubjectIndex index,
351                                                angle::SubjectMessage message)
352 {
353     if (message == angle::SubjectMessage::BufferVkStorageChanged)
354     {
355         ASSERT(index < mBufferObserverBindings.size());
356         const gl::OffsetBindingPointer<gl::Buffer> &binding = mState.getIndexedBuffer(index);
357         ASSERT(binding.get());
358 
359         BufferVk *bufferVk = vk::GetImpl(binding.get());
360 
361         ASSERT(bufferVk->isBufferValid());
362         mBufferHelpers[index] = &bufferVk->getBuffer();
363         mBufferOffsets[index] = binding.getOffset() + mBufferHelpers[index]->getOffset();
364         mBufferSizes[index]   = gl::GetBoundBufferAvailableSize(binding);
365         mBufferObserverBindings[index].bind(bufferVk);
366 
367         mXFBBuffersDesc.updateTransformFeedbackBuffer(
368             index, mBufferHelpers[index]->getBufferSerial(), mBufferOffsets[index]);
369 
370         mBufferHandles[index] = mBufferHelpers[index]->getBuffer().getHandle();
371     }
372 }
373 
writeDescriptorSet(vk::Context * context,UpdateDescriptorSetsBuilder * updateBuilder,const ShaderInterfaceVariableInfoMap & variableInfoMap,size_t xfbBufferCount,VkDescriptorBufferInfo * bufferInfo,VkDescriptorSet descSet) const374 void TransformFeedbackVk::writeDescriptorSet(vk::Context *context,
375                                              UpdateDescriptorSetsBuilder *updateBuilder,
376                                              const ShaderInterfaceVariableInfoMap &variableInfoMap,
377                                              size_t xfbBufferCount,
378                                              VkDescriptorBufferInfo *bufferInfo,
379                                              VkDescriptorSet descSet) const
380 {
381     ASSERT(context->getRenderer()->getFeatures().emulateTransformFeedback.enabled);
382 
383     const ShaderInterfaceVariableInfo &info =
384         variableInfoMap.getTransformFeedbackInfo(gl::ShaderType::Vertex, 0);
385 
386     VkWriteDescriptorSet &writeDescriptorInfo = updateBuilder->allocWriteDescriptorSet();
387     writeDescriptorInfo.sType                 = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
388     writeDescriptorInfo.dstSet                = descSet;
389     writeDescriptorInfo.dstBinding            = info.binding;
390     writeDescriptorInfo.dstArrayElement       = 0;
391     writeDescriptorInfo.descriptorCount       = static_cast<uint32_t>(xfbBufferCount);
392     writeDescriptorInfo.descriptorType        = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
393     writeDescriptorInfo.pImageInfo            = nullptr;
394     writeDescriptorInfo.pBufferInfo           = bufferInfo;
395     writeDescriptorInfo.pTexelBufferView      = nullptr;
396 }
397 
398 }  // namespace rx
399