1 //
2 // Copyright 2019 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 // SecondaryCommandBuffer:
7 // CPU-side storage of commands to delay GPU-side allocation until commands are submitted.
8 //
9
10 #include "libANGLE/renderer/vulkan/SecondaryCommandBuffer.h"
11 #include "common/debug.h"
12 #include "libANGLE/renderer/vulkan/vk_utils.h"
13
14 namespace rx
15 {
16 namespace vk
17 {
18 namespace priv
19 {
20 namespace
21 {
GetCommandString(CommandID id)22 const char *GetCommandString(CommandID id)
23 {
24 switch (id)
25 {
26 case CommandID::Invalid:
27 return "--Invalid--";
28 case CommandID::BeginQuery:
29 return "BeginQuery";
30 case CommandID::BeginTransformFeedback:
31 return "BeginTransformFeedback";
32 case CommandID::BindComputePipeline:
33 return "BindComputePipeline";
34 case CommandID::BindDescriptorSets:
35 return "BindDescriptorSets";
36 case CommandID::BindGraphicsPipeline:
37 return "BindGraphicsPipeline";
38 case CommandID::BindIndexBuffer:
39 return "BindIndexBuffer";
40 case CommandID::BindTransformFeedbackBuffers:
41 return "BindTransformFeedbackBuffers";
42 case CommandID::BindVertexBuffers:
43 return "BindVertexBuffers";
44 case CommandID::BlitImage:
45 return "BlitImage";
46 case CommandID::BufferBarrier:
47 return "BufferBarrier";
48 case CommandID::ClearAttachments:
49 return "ClearAttachments";
50 case CommandID::ClearColorImage:
51 return "ClearColorImage";
52 case CommandID::ClearDepthStencilImage:
53 return "ClearDepthStencilImage";
54 case CommandID::CopyBuffer:
55 return "CopyBuffer";
56 case CommandID::CopyBufferToImage:
57 return "CopyBufferToImage";
58 case CommandID::CopyImage:
59 return "CopyImage";
60 case CommandID::CopyImageToBuffer:
61 return "CopyImageToBuffer";
62 case CommandID::Dispatch:
63 return "Dispatch";
64 case CommandID::DispatchIndirect:
65 return "DispatchIndirect";
66 case CommandID::Draw:
67 return "Draw";
68 case CommandID::DrawIndexed:
69 return "DrawIndexed";
70 case CommandID::DrawIndexedBaseVertex:
71 return "DrawIndexedBaseVertex";
72 case CommandID::DrawIndexedIndirect:
73 return "DrawIndexedIndirect";
74 case CommandID::DrawIndexedInstanced:
75 return "DrawIndexedInstanced";
76 case CommandID::DrawIndexedInstancedBaseVertex:
77 return "DrawIndexedInstancedBaseVertex";
78 case CommandID::DrawIndexedInstancedBaseVertexBaseInstance:
79 return "DrawIndexedInstancedBaseVertexBaseInstance";
80 case CommandID::DrawIndirect:
81 return "DrawIndirect";
82 case CommandID::DrawInstanced:
83 return "DrawInstanced";
84 case CommandID::DrawInstancedBaseInstance:
85 return "DrawInstancedBaseInstance";
86 case CommandID::EndQuery:
87 return "EndQuery";
88 case CommandID::EndTransformFeedback:
89 return "EndTransformFeedback";
90 case CommandID::ExecutionBarrier:
91 return "ExecutionBarrier";
92 case CommandID::FillBuffer:
93 return "FillBuffer";
94 case CommandID::ImageBarrier:
95 return "ImageBarrier";
96 case CommandID::MemoryBarrier:
97 return "MemoryBarrier";
98 case CommandID::PipelineBarrier:
99 return "PipelineBarrier";
100 case CommandID::PushConstants:
101 return "PushConstants";
102 case CommandID::ResetEvent:
103 return "ResetEvent";
104 case CommandID::ResetQueryPool:
105 return "ResetQueryPool";
106 case CommandID::ResolveImage:
107 return "ResolveImage";
108 case CommandID::SetEvent:
109 return "SetEvent";
110 case CommandID::WaitEvents:
111 return "WaitEvents";
112 case CommandID::WriteTimestamp:
113 return "WriteTimestamp";
114 default:
115 // Need this to work around MSVC warning 4715.
116 UNREACHABLE();
117 return "--unreachable--";
118 }
119 }
120 } // namespace
121
NextCommand(const CommandHeader * command)122 ANGLE_INLINE const CommandHeader *NextCommand(const CommandHeader *command)
123 {
124 return reinterpret_cast<const CommandHeader *>(reinterpret_cast<const uint8_t *>(command) +
125 command->size);
126 }
127
128 // Parse the cmds in this cmd buffer into given primary cmd buffer
executeCommands(VkCommandBuffer cmdBuffer)129 void SecondaryCommandBuffer::executeCommands(VkCommandBuffer cmdBuffer)
130 {
131 for (const CommandHeader *command : mCommands)
132 {
133 for (const CommandHeader *currentCommand = command;
134 currentCommand->id != CommandID::Invalid; currentCommand = NextCommand(currentCommand))
135 {
136 switch (currentCommand->id)
137 {
138 case CommandID::BeginQuery:
139 {
140 const BeginQueryParams *params = getParamPtr<BeginQueryParams>(currentCommand);
141 vkCmdBeginQuery(cmdBuffer, params->queryPool, params->query, params->flags);
142 break;
143 }
144 case CommandID::BeginTransformFeedback:
145 {
146 const BeginTransformFeedbackParams *params =
147 getParamPtr<BeginTransformFeedbackParams>(currentCommand);
148 const VkBuffer *counterBuffers =
149 Offset<VkBuffer>(params, sizeof(BeginTransformFeedbackParams));
150 // Workaround for AMD driver bug where it expects the offsets array to be
151 // non-null
152 gl::TransformFeedbackBuffersArray<VkDeviceSize> offsets;
153 offsets.fill(0);
154 vkCmdBeginTransformFeedbackEXT(cmdBuffer, 0, params->bufferCount,
155 counterBuffers, offsets.data());
156 break;
157 }
158 case CommandID::BindComputePipeline:
159 {
160 const BindPipelineParams *params =
161 getParamPtr<BindPipelineParams>(currentCommand);
162 vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, params->pipeline);
163 break;
164 }
165 case CommandID::BindDescriptorSets:
166 {
167 const BindDescriptorSetParams *params =
168 getParamPtr<BindDescriptorSetParams>(currentCommand);
169 const VkDescriptorSet *descriptorSets =
170 Offset<VkDescriptorSet>(params, sizeof(BindDescriptorSetParams));
171 const uint32_t *dynamicOffsets = Offset<uint32_t>(
172 descriptorSets, sizeof(VkDescriptorSet) * params->descriptorSetCount);
173 vkCmdBindDescriptorSets(cmdBuffer, params->pipelineBindPoint, params->layout,
174 params->firstSet, params->descriptorSetCount,
175 descriptorSets, params->dynamicOffsetCount,
176 dynamicOffsets);
177 break;
178 }
179 case CommandID::BindGraphicsPipeline:
180 {
181 const BindPipelineParams *params =
182 getParamPtr<BindPipelineParams>(currentCommand);
183 vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, params->pipeline);
184 break;
185 }
186 case CommandID::BindIndexBuffer:
187 {
188 const BindIndexBufferParams *params =
189 getParamPtr<BindIndexBufferParams>(currentCommand);
190 vkCmdBindIndexBuffer(cmdBuffer, params->buffer, params->offset,
191 params->indexType);
192 break;
193 }
194 case CommandID::BindTransformFeedbackBuffers:
195 {
196 const BindTransformFeedbackBuffersParams *params =
197 getParamPtr<BindTransformFeedbackBuffersParams>(currentCommand);
198 const VkBuffer *buffers =
199 Offset<VkBuffer>(params, sizeof(BindTransformFeedbackBuffersParams));
200 const VkDeviceSize *offsets =
201 Offset<VkDeviceSize>(buffers, sizeof(VkBuffer) * params->bindingCount);
202 const VkDeviceSize *sizes =
203 Offset<VkDeviceSize>(offsets, sizeof(VkDeviceSize) * params->bindingCount);
204 vkCmdBindTransformFeedbackBuffersEXT(cmdBuffer, 0, params->bindingCount,
205 buffers, offsets, sizes);
206 break;
207 }
208 case CommandID::BindVertexBuffers:
209 {
210 const BindVertexBuffersParams *params =
211 getParamPtr<BindVertexBuffersParams>(currentCommand);
212 const VkBuffer *buffers =
213 Offset<VkBuffer>(params, sizeof(BindVertexBuffersParams));
214 const VkDeviceSize *offsets =
215 Offset<VkDeviceSize>(buffers, sizeof(VkBuffer) * params->bindingCount);
216 vkCmdBindVertexBuffers(cmdBuffer, 0, params->bindingCount, buffers, offsets);
217 break;
218 }
219 case CommandID::BlitImage:
220 {
221 const BlitImageParams *params = getParamPtr<BlitImageParams>(currentCommand);
222 vkCmdBlitImage(cmdBuffer, params->srcImage,
223 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, params->dstImage,
224 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ¶ms->region,
225 params->filter);
226 break;
227 }
228 case CommandID::BufferBarrier:
229 {
230 const BufferBarrierParams *params =
231 getParamPtr<BufferBarrierParams>(currentCommand);
232 vkCmdPipelineBarrier(cmdBuffer, params->srcStageMask, params->dstStageMask, 0,
233 0, nullptr, 1, ¶ms->bufferMemoryBarrier, 0, nullptr);
234 break;
235 }
236 case CommandID::ClearAttachments:
237 {
238 const ClearAttachmentsParams *params =
239 getParamPtr<ClearAttachmentsParams>(currentCommand);
240 const VkClearAttachment *attachments =
241 Offset<VkClearAttachment>(params, sizeof(ClearAttachmentsParams));
242 vkCmdClearAttachments(cmdBuffer, params->attachmentCount, attachments, 1,
243 ¶ms->rect);
244 break;
245 }
246 case CommandID::ClearColorImage:
247 {
248 const ClearColorImageParams *params =
249 getParamPtr<ClearColorImageParams>(currentCommand);
250 vkCmdClearColorImage(cmdBuffer, params->image, params->imageLayout,
251 ¶ms->color, 1, ¶ms->range);
252 break;
253 }
254 case CommandID::ClearDepthStencilImage:
255 {
256 const ClearDepthStencilImageParams *params =
257 getParamPtr<ClearDepthStencilImageParams>(currentCommand);
258 vkCmdClearDepthStencilImage(cmdBuffer, params->image, params->imageLayout,
259 ¶ms->depthStencil, 1, ¶ms->range);
260 break;
261 }
262 case CommandID::CopyBuffer:
263 {
264 const CopyBufferParams *params = getParamPtr<CopyBufferParams>(currentCommand);
265 const VkBufferCopy *regions =
266 Offset<VkBufferCopy>(params, sizeof(CopyBufferParams));
267 vkCmdCopyBuffer(cmdBuffer, params->srcBuffer, params->destBuffer,
268 params->regionCount, regions);
269 break;
270 }
271 case CommandID::CopyBufferToImage:
272 {
273 const CopyBufferToImageParams *params =
274 getParamPtr<CopyBufferToImageParams>(currentCommand);
275 vkCmdCopyBufferToImage(cmdBuffer, params->srcBuffer, params->dstImage,
276 params->dstImageLayout, 1, ¶ms->region);
277 break;
278 }
279 case CommandID::CopyImage:
280 {
281 const CopyImageParams *params = getParamPtr<CopyImageParams>(currentCommand);
282 vkCmdCopyImage(cmdBuffer, params->srcImage, params->srcImageLayout,
283 params->dstImage, params->dstImageLayout, 1, ¶ms->region);
284 break;
285 }
286 case CommandID::CopyImageToBuffer:
287 {
288 const CopyImageToBufferParams *params =
289 getParamPtr<CopyImageToBufferParams>(currentCommand);
290 vkCmdCopyImageToBuffer(cmdBuffer, params->srcImage, params->srcImageLayout,
291 params->dstBuffer, 1, ¶ms->region);
292 break;
293 }
294 case CommandID::Dispatch:
295 {
296 const DispatchParams *params = getParamPtr<DispatchParams>(currentCommand);
297 vkCmdDispatch(cmdBuffer, params->groupCountX, params->groupCountY,
298 params->groupCountZ);
299 break;
300 }
301 case CommandID::DispatchIndirect:
302 {
303 const DispatchIndirectParams *params =
304 getParamPtr<DispatchIndirectParams>(currentCommand);
305 vkCmdDispatchIndirect(cmdBuffer, params->buffer, params->offset);
306 break;
307 }
308 case CommandID::Draw:
309 {
310 const DrawParams *params = getParamPtr<DrawParams>(currentCommand);
311 vkCmdDraw(cmdBuffer, params->vertexCount, 1, params->firstVertex, 0);
312 break;
313 }
314 case CommandID::DrawIndexed:
315 {
316 const DrawIndexedParams *params =
317 getParamPtr<DrawIndexedParams>(currentCommand);
318 vkCmdDrawIndexed(cmdBuffer, params->indexCount, 1, 0, 0, 0);
319 break;
320 }
321 case CommandID::DrawIndexedBaseVertex:
322 {
323 const DrawIndexedBaseVertexParams *params =
324 getParamPtr<DrawIndexedBaseVertexParams>(currentCommand);
325 vkCmdDrawIndexed(cmdBuffer, params->indexCount, 1, 0, params->vertexOffset, 0);
326 break;
327 }
328 case CommandID::DrawIndexedIndirect:
329 {
330 const DrawIndexedIndirectParams *params =
331 getParamPtr<DrawIndexedIndirectParams>(currentCommand);
332 vkCmdDrawIndexedIndirect(cmdBuffer, params->buffer, params->offset, 1, 0);
333 break;
334 }
335 case CommandID::DrawIndexedInstanced:
336 {
337 const DrawIndexedInstancedParams *params =
338 getParamPtr<DrawIndexedInstancedParams>(currentCommand);
339 vkCmdDrawIndexed(cmdBuffer, params->indexCount, params->instanceCount, 0, 0, 0);
340 break;
341 }
342 case CommandID::DrawIndexedInstancedBaseVertex:
343 {
344 const DrawIndexedInstancedBaseVertexParams *params =
345 getParamPtr<DrawIndexedInstancedBaseVertexParams>(currentCommand);
346 vkCmdDrawIndexed(cmdBuffer, params->indexCount, params->instanceCount, 0,
347 params->vertexOffset, 0);
348 break;
349 }
350 case CommandID::DrawIndexedInstancedBaseVertexBaseInstance:
351 {
352 const DrawIndexedInstancedBaseVertexBaseInstanceParams *params =
353 getParamPtr<DrawIndexedInstancedBaseVertexBaseInstanceParams>(
354 currentCommand);
355 vkCmdDrawIndexed(cmdBuffer, params->indexCount, params->instanceCount,
356 params->firstIndex, params->vertexOffset,
357 params->firstInstance);
358 break;
359 }
360 case CommandID::DrawIndirect:
361 {
362 const DrawIndirectParams *params =
363 getParamPtr<DrawIndirectParams>(currentCommand);
364 vkCmdDrawIndirect(cmdBuffer, params->buffer, params->offset, 1, 0);
365 break;
366 }
367 case CommandID::DrawInstanced:
368 {
369 const DrawInstancedParams *params =
370 getParamPtr<DrawInstancedParams>(currentCommand);
371 vkCmdDraw(cmdBuffer, params->vertexCount, params->instanceCount,
372 params->firstVertex, 0);
373 break;
374 }
375 case CommandID::DrawInstancedBaseInstance:
376 {
377 const DrawInstancedBaseInstanceParams *params =
378 getParamPtr<DrawInstancedBaseInstanceParams>(currentCommand);
379 vkCmdDraw(cmdBuffer, params->vertexCount, params->instanceCount,
380 params->firstVertex, params->firstInstance);
381 break;
382 }
383 case CommandID::EndQuery:
384 {
385 const EndQueryParams *params = getParamPtr<EndQueryParams>(currentCommand);
386 vkCmdEndQuery(cmdBuffer, params->queryPool, params->query);
387 break;
388 }
389 case CommandID::EndTransformFeedback:
390 {
391 const EndTransformFeedbackParams *params =
392 getParamPtr<EndTransformFeedbackParams>(currentCommand);
393 const VkBuffer *counterBuffers =
394 Offset<VkBuffer>(params, sizeof(EndTransformFeedbackParams));
395 // Workaround for AMD driver bug where it expects the offsets array to be
396 // non-null
397 gl::TransformFeedbackBuffersArray<VkDeviceSize> offsets;
398 offsets.fill(0);
399 vkCmdEndTransformFeedbackEXT(cmdBuffer, 0, params->bufferCount, counterBuffers,
400 offsets.data());
401 break;
402 }
403 case CommandID::ExecutionBarrier:
404 {
405 const ExecutionBarrierParams *params =
406 getParamPtr<ExecutionBarrierParams>(currentCommand);
407 vkCmdPipelineBarrier(cmdBuffer, params->stageMask, params->stageMask, 0, 0,
408 nullptr, 0, nullptr, 0, nullptr);
409 break;
410 }
411 case CommandID::FillBuffer:
412 {
413 const FillBufferParams *params = getParamPtr<FillBufferParams>(currentCommand);
414 vkCmdFillBuffer(cmdBuffer, params->dstBuffer, params->dstOffset, params->size,
415 params->data);
416 break;
417 }
418 case CommandID::ImageBarrier:
419 {
420 const ImageBarrierParams *params =
421 getParamPtr<ImageBarrierParams>(currentCommand);
422 vkCmdPipelineBarrier(cmdBuffer, params->srcStageMask, params->dstStageMask, 0,
423 0, nullptr, 0, nullptr, 1, ¶ms->imageMemoryBarrier);
424 break;
425 }
426 case CommandID::MemoryBarrier:
427 {
428 const MemoryBarrierParams *params =
429 getParamPtr<MemoryBarrierParams>(currentCommand);
430 vkCmdPipelineBarrier(cmdBuffer, params->srcStageMask, params->dstStageMask, 0,
431 1, ¶ms->memoryBarrier, 0, nullptr, 0, nullptr);
432 break;
433 }
434 case CommandID::PipelineBarrier:
435 {
436 const PipelineBarrierParams *params =
437 getParamPtr<PipelineBarrierParams>(currentCommand);
438 const VkMemoryBarrier *memoryBarriers =
439 Offset<VkMemoryBarrier>(params, sizeof(PipelineBarrierParams));
440 const VkBufferMemoryBarrier *bufferMemoryBarriers =
441 Offset<VkBufferMemoryBarrier>(
442 memoryBarriers, params->memoryBarrierCount * sizeof(VkMemoryBarrier));
443 const VkImageMemoryBarrier *imageMemoryBarriers = Offset<VkImageMemoryBarrier>(
444 bufferMemoryBarriers,
445 params->bufferMemoryBarrierCount * sizeof(VkBufferMemoryBarrier));
446 vkCmdPipelineBarrier(cmdBuffer, params->srcStageMask, params->dstStageMask,
447 params->dependencyFlags, params->memoryBarrierCount,
448 memoryBarriers, params->bufferMemoryBarrierCount,
449 bufferMemoryBarriers, params->imageMemoryBarrierCount,
450 imageMemoryBarriers);
451 break;
452 }
453 case CommandID::PushConstants:
454 {
455 const PushConstantsParams *params =
456 getParamPtr<PushConstantsParams>(currentCommand);
457 const void *data = Offset<void>(params, sizeof(PushConstantsParams));
458 vkCmdPushConstants(cmdBuffer, params->layout, params->flag, params->offset,
459 params->size, data);
460 break;
461 }
462 case CommandID::ResetEvent:
463 {
464 const ResetEventParams *params = getParamPtr<ResetEventParams>(currentCommand);
465 vkCmdResetEvent(cmdBuffer, params->event, params->stageMask);
466 break;
467 }
468 case CommandID::ResetQueryPool:
469 {
470 const ResetQueryPoolParams *params =
471 getParamPtr<ResetQueryPoolParams>(currentCommand);
472 vkCmdResetQueryPool(cmdBuffer, params->queryPool, params->firstQuery,
473 params->queryCount);
474 break;
475 }
476 case CommandID::ResolveImage:
477 {
478 const ResolveImageParams *params =
479 getParamPtr<ResolveImageParams>(currentCommand);
480 vkCmdResolveImage(cmdBuffer, params->srcImage,
481 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, params->dstImage,
482 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ¶ms->region);
483 break;
484 }
485 case CommandID::SetEvent:
486 {
487 const SetEventParams *params = getParamPtr<SetEventParams>(currentCommand);
488 vkCmdSetEvent(cmdBuffer, params->event, params->stageMask);
489 break;
490 }
491 case CommandID::WaitEvents:
492 {
493 const WaitEventsParams *params = getParamPtr<WaitEventsParams>(currentCommand);
494 const VkEvent *events = Offset<VkEvent>(params, sizeof(WaitEventsParams));
495 const VkMemoryBarrier *memoryBarriers =
496 Offset<VkMemoryBarrier>(events, params->eventCount * sizeof(VkEvent));
497 const VkBufferMemoryBarrier *bufferMemoryBarriers =
498 Offset<VkBufferMemoryBarrier>(
499 memoryBarriers, params->memoryBarrierCount * sizeof(VkMemoryBarrier));
500 const VkImageMemoryBarrier *imageMemoryBarriers = Offset<VkImageMemoryBarrier>(
501 bufferMemoryBarriers,
502 params->bufferMemoryBarrierCount * sizeof(VkBufferMemoryBarrier));
503 vkCmdWaitEvents(cmdBuffer, params->eventCount, events, params->srcStageMask,
504 params->dstStageMask, params->memoryBarrierCount,
505 memoryBarriers, params->bufferMemoryBarrierCount,
506 bufferMemoryBarriers, params->imageMemoryBarrierCount,
507 imageMemoryBarriers);
508 break;
509 }
510 case CommandID::WriteTimestamp:
511 {
512 const WriteTimestampParams *params =
513 getParamPtr<WriteTimestampParams>(currentCommand);
514 vkCmdWriteTimestamp(cmdBuffer, params->pipelineStage, params->queryPool,
515 params->query);
516 break;
517 }
518 default:
519 {
520 UNREACHABLE();
521 break;
522 }
523 }
524 }
525 }
526 }
527
getMemoryUsageStats(size_t * usedMemoryOut,size_t * allocatedMemoryOut) const528 void SecondaryCommandBuffer::getMemoryUsageStats(size_t *usedMemoryOut,
529 size_t *allocatedMemoryOut) const
530 {
531 *allocatedMemoryOut = kBlockSize * mCommands.size();
532
533 *usedMemoryOut = 0;
534 for (const CommandHeader *command : mCommands)
535 {
536 const CommandHeader *commandEnd = command;
537 while (commandEnd->id != CommandID::Invalid)
538 {
539 commandEnd = NextCommand(commandEnd);
540 }
541
542 *usedMemoryOut += reinterpret_cast<const uint8_t *>(commandEnd) -
543 reinterpret_cast<const uint8_t *>(command) + sizeof(CommandHeader::id);
544 }
545
546 ASSERT(*usedMemoryOut <= *allocatedMemoryOut);
547 }
548
dumpCommands(const char * separator) const549 std::string SecondaryCommandBuffer::dumpCommands(const char *separator) const
550 {
551 std::stringstream result;
552 for (const CommandHeader *command : mCommands)
553 {
554 for (const CommandHeader *currentCommand = command;
555 currentCommand->id != CommandID::Invalid; currentCommand = NextCommand(currentCommand))
556 {
557 result << GetCommandString(currentCommand->id) << separator;
558 }
559 }
560 return result.str();
561 }
562
563 } // namespace priv
564 } // namespace vk
565 } // namespace rx
566