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