1 #ifndef DALI_TEST_GRAPHICS_COMMAND_BUFFER_H
2 #define DALI_TEST_GRAPHICS_COMMAND_BUFFER_H
5 * Copyright (c) 2021 Samsung Electronics Co., Ltd.
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
20 #include <dali/graphics-api/graphics-command-buffer-create-info.h>
21 #include <dali/graphics-api/graphics-command-buffer.h>
22 #include <dali/graphics-api/graphics-pipeline.h>
23 #include <dali/graphics-api/graphics-types.h>
26 #include "test-gl-abstraction.h"
27 #include "test-graphics-buffer.h"
28 #include "test-graphics-pipeline.h"
29 #include "test-trace-call-stack.h"
33 class TestGraphicsTexture;
34 class TestGraphicsBuffer;
35 class TestGraphicsCommandBuffer;
36 class TestGraphicsSampler;
37 class TestGraphicsPipeline;
39 enum class CommandType
42 BIND_TEXTURES = 1 << 1,
43 BIND_SAMPLERS = 1 << 2,
44 BIND_VERTEX_BUFFERS = 1 << 3,
45 BIND_INDEX_BUFFER = 1 << 4,
46 BIND_UNIFORM_BUFFER = 1 << 5,
47 BIND_PIPELINE = 1 << 6,
49 DRAW_INDEXED = 1 << 8,
50 DRAW_INDEXED_INDIRECT = 1 << 9,
51 SET_SCISSOR = 1 << 10,
52 SET_SCISSOR_TEST = 1 << 11,
53 SET_VIEWPORT = 1 << 12,
54 SET_VIEWPORT_TEST = 1 << 13,
55 BEGIN_RENDER_PASS = 1 << 14,
56 END_RENDER_PASS = 1 << 15,
57 EXECUTE_COMMAND_BUFFERS = 1 << 16
60 using CommandTypeMask = uint32_t;
62 inline CommandTypeMask operator|(T flags, CommandType bit)
64 return static_cast<CommandTypeMask>(flags) | static_cast<CommandTypeMask>(bit);
68 * @brief Descriptor of single buffer binding within
71 struct VertexBufferBindingDescriptor
73 const TestGraphicsBuffer* buffer{nullptr};
78 * @brief Descriptor of ix buffer binding within
81 struct IndexBufferBindingDescriptor
83 const TestGraphicsBuffer* buffer{nullptr};
85 Graphics::Format format{};
89 * @brief Descriptor of uniform buffer binding within
92 struct UniformBufferBindingDescriptor
94 const TestGraphicsBuffer* buffer{nullptr};
97 bool emulated; ///<true if UBO is emulated for old gfx API
101 * @brief The descriptor of draw call
103 struct DrawCallDescriptor
106 * @brief Enum specifying type of the draw call
112 DRAW_INDEXED_INDIRECT
115 Type type{}; ///< Type of the draw call
118 * Union contains data for all types of draw calls.
123 * @brief Vertex array draw
127 uint32_t vertexCount;
128 uint32_t instanceCount;
129 uint32_t firstVertex;
130 uint32_t firstInstance;
134 * @brief Indexed draw
139 uint32_t instanceCount;
141 int32_t vertexOffset;
142 uint32_t firstInstance;
146 * @brief Indexed draw indirect
150 const TestGraphicsBuffer* buffer;
154 } drawIndexedIndirect;
159 * Command structure allocates memory to store a single command
167 Command(CommandType type)
170 // do non-trivial initialization
173 case CommandType::BEGIN_RENDER_PASS:
175 new(&data.beginRenderPass) CommandData::BeginRenderPassDescriptor();
188 case CommandType::BEGIN_RENDER_PASS:
190 data.beginRenderPass.~BeginRenderPassDescriptor();
201 * @brief Copy constructor
202 * @param[in] rhs Command
204 Command(const Command& rhs)
208 case CommandType::BEGIN_RENDER_PASS:
210 new(&data.beginRenderPass) CommandData::BeginRenderPassDescriptor(rhs.data.beginRenderPass);
213 case CommandType::END_RENDER_PASS:
215 data.endRenderPass = rhs.data.endRenderPass;
218 case CommandType::EXECUTE_COMMAND_BUFFERS:
220 data.executeCommandBuffers = rhs.data.executeCommandBuffers;
224 case CommandType::BIND_VERTEX_BUFFERS:
226 data.bindVertexBuffers = rhs.data.bindVertexBuffers;
229 case CommandType::BIND_INDEX_BUFFER:
231 data.bindIndexBuffer = rhs.data.bindIndexBuffer;
234 case CommandType::BIND_SAMPLERS:
236 data.bindSamplers = rhs.data.bindSamplers;
239 case CommandType::BIND_TEXTURES:
241 data.bindTextures = rhs.data.bindTextures;
244 case CommandType::BIND_PIPELINE:
246 data.bindPipeline = rhs.data.bindPipeline;
249 case CommandType::BIND_UNIFORM_BUFFER:
251 data.bindUniformBuffers = rhs.data.bindUniformBuffers;
254 case CommandType::DRAW:
256 data.draw.type = rhs.data.draw.type;
257 data.draw.draw = rhs.data.draw.draw;
260 case CommandType::DRAW_INDEXED:
262 data.draw.type = rhs.data.draw.type;
263 data.draw.drawIndexed = rhs.data.draw.drawIndexed;
266 case CommandType::DRAW_INDEXED_INDIRECT:
268 data.draw.type = rhs.data.draw.type;
269 data.draw.drawIndexedIndirect = rhs.data.draw.drawIndexedIndirect;
272 case CommandType::FLUSH:
277 case CommandType::SET_SCISSOR:
279 data.scissor.region = rhs.data.scissor.region;
282 case CommandType::SET_SCISSOR_TEST:
284 data.scissorTest.enable = rhs.data.scissorTest.enable;
287 case CommandType::SET_VIEWPORT:
289 data.viewport.region = rhs.data.viewport.region;
292 case CommandType::SET_VIEWPORT_TEST:
294 data.viewportTest.enable = rhs.data.viewportTest.enable;
302 * @brief move constructor
303 * @param[in] rhs Command
305 Command(Command&& rhs) noexcept
309 case CommandType::BEGIN_RENDER_PASS:
311 new(&data.beginRenderPass) CommandData::BeginRenderPassDescriptor(std::move(rhs.data.beginRenderPass));
314 case CommandType::END_RENDER_PASS:
316 data.endRenderPass = std::move(rhs.data.endRenderPass);
319 case CommandType::EXECUTE_COMMAND_BUFFERS:
321 data.executeCommandBuffers = std::move(rhs.data.executeCommandBuffers);
324 case CommandType::BIND_VERTEX_BUFFERS:
326 data.bindVertexBuffers = std::move(rhs.data.bindVertexBuffers);
329 case CommandType::BIND_INDEX_BUFFER:
331 data.bindIndexBuffer = rhs.data.bindIndexBuffer;
334 case CommandType::BIND_UNIFORM_BUFFER:
336 data.bindUniformBuffers = std::move(rhs.data.bindUniformBuffers);
339 case CommandType::BIND_SAMPLERS:
341 data.bindSamplers = std::move(rhs.data.bindSamplers);
344 case CommandType::BIND_TEXTURES:
346 data.bindTextures = std::move(rhs.data.bindTextures);
349 case CommandType::BIND_PIPELINE:
351 data.bindPipeline = rhs.data.bindPipeline;
354 case CommandType::DRAW:
356 data.draw.type = rhs.data.draw.type;
357 data.draw.draw = rhs.data.draw.draw;
360 case CommandType::DRAW_INDEXED:
362 data.draw.type = rhs.data.draw.type;
363 data.draw.drawIndexed = rhs.data.draw.drawIndexed;
366 case CommandType::DRAW_INDEXED_INDIRECT:
368 data.draw.type = rhs.data.draw.type;
369 data.draw.drawIndexedIndirect = rhs.data.draw.drawIndexedIndirect;
372 case CommandType::FLUSH:
377 case CommandType::SET_SCISSOR:
379 data.scissor.region = rhs.data.scissor.region;
382 case CommandType::SET_SCISSOR_TEST:
384 data.scissorTest.enable = rhs.data.scissorTest.enable;
387 case CommandType::SET_VIEWPORT:
389 data.viewport.region = rhs.data.viewport.region;
392 case CommandType::SET_VIEWPORT_TEST:
394 data.viewportTest.enable = rhs.data.viewportTest.enable;
401 CommandType type{CommandType::FLUSH}; ///< Type of command
415 std::vector<Graphics::TextureBinding> textureBindings;
418 // BindSampler command
421 std::vector<Graphics::SamplerBinding> samplerBindings;
426 using Binding = VertexBufferBindingDescriptor;
427 std::vector<Binding> vertexBufferBindings;
430 struct : public IndexBufferBindingDescriptor
436 std::vector<UniformBufferBindingDescriptor> uniformBufferBindings{};
437 UniformBufferBindingDescriptor standaloneUniformsBufferBinding{};
438 } bindUniformBuffers;
442 const TestGraphicsPipeline* pipeline{nullptr};
445 struct : public DrawCallDescriptor
451 Graphics::Rect2D region;
459 Graphics::Viewport region;
466 struct BeginRenderPassDescriptor
468 Graphics::RenderPass* renderPass;
469 Graphics::RenderTarget* renderTarget;
470 Graphics::Rect2D renderArea;
471 std::vector<Graphics::ClearValue> clearValues;
480 std::vector<const TestGraphicsCommandBuffer*> buffers;
481 } executeCommandBuffers;
486 class TestGraphicsCommandBuffer : public Graphics::CommandBuffer
489 TestGraphicsCommandBuffer(TraceCallStack& callstack, TestGlAbstraction& glAbstraction);
490 ~TestGraphicsCommandBuffer()
494 void BindVertexBuffers(uint32_t firstBinding,
495 std::vector<const Graphics::Buffer*> buffers,
496 std::vector<uint32_t> offsets) override
498 mCommands.emplace_back();
499 mCommands.back().type = CommandType::BIND_VERTEX_BUFFERS;
500 auto& bindings = mCommands.back().data.bindVertexBuffers.vertexBufferBindings;
501 if(bindings.size() < firstBinding + buffers.size())
503 bindings.resize(firstBinding + buffers.size());
504 auto index = firstBinding;
505 for(auto& buf : buffers)
507 bindings[index].buffer = static_cast<const TestGraphicsBuffer*>(buf);
508 bindings[index].offset = offsets[index - firstBinding];
512 mCallStack.PushCall("BindVertexBuffers", "");
515 void BindUniformBuffers(const std::vector<Graphics::UniformBufferBinding>& bindings) override
517 mCommands.emplace_back();
518 auto& cmd = mCommands.back();
519 cmd.type = CommandType::BIND_UNIFORM_BUFFER;
520 auto& bindCmd = cmd.data.bindUniformBuffers;
521 for(const auto& binding : bindings)
525 auto testBuffer = static_cast<const TestGraphicsBuffer*>(binding.buffer);
526 if(testBuffer->IsCPUAllocated()) // standalone uniforms
528 bindCmd.standaloneUniformsBufferBinding.buffer = testBuffer;
529 bindCmd.standaloneUniformsBufferBinding.offset = binding.offset;
530 bindCmd.standaloneUniformsBufferBinding.binding = binding.binding;
531 bindCmd.standaloneUniformsBufferBinding.emulated = true;
533 else // Bind regular UBO
535 // resize binding slots
536 if(binding.binding >= bindCmd.uniformBufferBindings.size())
538 bindCmd.uniformBufferBindings.resize(binding.binding + 1);
540 auto& slot = bindCmd.uniformBufferBindings[binding.binding];
541 slot.buffer = testBuffer;
542 slot.offset = binding.offset;
543 slot.binding = binding.binding;
544 slot.emulated = false;
548 mCallStack.PushCall("BindUniformBuffers", "");
551 void BindPipeline(const Graphics::Pipeline& pipeline) override
553 mCommands.emplace_back();
554 mCommands.back().type = CommandType::BIND_PIPELINE;
555 mCommands.back().data.bindPipeline.pipeline = static_cast<const TestGraphicsPipeline*>(&pipeline);
556 mCallStack.PushCall("BindPipeline", "");
559 void BindTextures(std::vector<Graphics::TextureBinding>& textureBindings) override
561 mCommands.emplace_back();
562 mCommands.back().type = CommandType::BIND_TEXTURES;
563 mCommands.back().data.bindTextures.textureBindings = std::move(textureBindings);
564 mCallStack.PushCall("BindTextures", "");
567 void BindSamplers(std::vector<Graphics::SamplerBinding>& samplerBindings) override
569 mCommands.emplace_back();
570 mCommands.back().data.bindSamplers.samplerBindings = std::move(samplerBindings);
571 mCallStack.PushCall("BindSamplers", "");
574 void BindPushConstants(void* data,
576 uint32_t binding) override
578 mCallStack.PushCall("BindPushConstants", "");
581 void BindIndexBuffer(const Graphics::Buffer& buffer,
583 Graphics::Format format) override
585 mCommands.emplace_back();
586 mCommands.back().type = CommandType::BIND_INDEX_BUFFER;
587 mCommands.back().data.bindIndexBuffer.buffer = static_cast<const TestGraphicsBuffer*>(&buffer);
588 mCommands.back().data.bindIndexBuffer.offset = offset;
589 mCommands.back().data.bindIndexBuffer.format = format;
590 mCallStack.PushCall("BindIndexBuffer", "");
593 void BeginRenderPass(
594 Graphics::RenderPass* renderPass,
595 Graphics::RenderTarget* renderTarget,
596 Graphics::Rect2D renderArea,
597 std::vector<Graphics::ClearValue> clearValues) override
599 mCommands.emplace_back(CommandType::BEGIN_RENDER_PASS);
600 auto& cmd = mCommands.back();
601 cmd.data.beginRenderPass.renderPass = renderPass;
602 cmd.data.beginRenderPass.renderTarget = renderTarget;
603 cmd.data.beginRenderPass.renderArea = renderArea;
604 cmd.data.beginRenderPass.clearValues = clearValues;
606 TraceCallStack::NamedParams namedParams;
607 namedParams["renderPass"] << std::hex << renderPass;
608 namedParams["renderTarget"] << std::hex << renderTarget;
609 namedParams["renderArea"] << renderArea.width << ", " << renderArea.height;
610 mCallStack.PushCall("BeginRenderPass", namedParams.str(), namedParams);
614 * @brief Ends current render pass
616 * This command must be issued in order to finalize the render pass.
617 * It's up to the implementation whether anything has to be done but
618 * the Controller may use end RP marker in order to resolve resource
619 * dependencies (for example, to know when target texture is ready
620 * before passing it to another render pass).
622 void EndRenderPass() override
624 mCallStack.PushCall("EndRenderPass", "");
627 void ExecuteCommandBuffers(std::vector<const CommandBuffer*>&& commandBuffers) override
629 mCommands.emplace_back();
630 auto& cmd = mCommands.back();
631 cmd.type = CommandType::EXECUTE_COMMAND_BUFFERS;
632 cmd.data.executeCommandBuffers.buffers.reserve(commandBuffers.size());
633 for(auto&& item : commandBuffers)
635 cmd.data.executeCommandBuffers.buffers.emplace_back(static_cast<const TestGraphicsCommandBuffer*>(item));
637 mCallStack.PushCall("ExecuteCommandBuffers", "");
641 uint32_t vertexCount,
642 uint32_t instanceCount,
643 uint32_t firstVertex,
644 uint32_t firstInstance) override
646 mCommands.emplace_back();
647 mCommands.back().type = CommandType::DRAW;
648 auto& cmd = mCommands.back().data.draw;
649 cmd.type = DrawCallDescriptor::Type::DRAW;
650 cmd.draw.vertexCount = vertexCount;
651 cmd.draw.instanceCount = instanceCount;
652 cmd.draw.firstInstance = firstInstance;
653 cmd.draw.firstVertex = firstVertex;
654 mCallStack.PushCall("Draw", "");
659 uint32_t instanceCount,
661 int32_t vertexOffset,
662 uint32_t firstInstance) override
664 mCommands.emplace_back();
665 mCommands.back().type = CommandType::DRAW_INDEXED;
666 auto& cmd = mCommands.back().data.draw;
667 cmd.type = DrawCallDescriptor::Type::DRAW_INDEXED;
668 cmd.drawIndexed.firstIndex = firstIndex;
669 cmd.drawIndexed.firstInstance = firstInstance;
670 cmd.drawIndexed.indexCount = indexCount;
671 cmd.drawIndexed.vertexOffset = vertexOffset;
672 cmd.drawIndexed.instanceCount = instanceCount;
673 mCallStack.PushCall("DrawIndexed", "");
676 void DrawIndexedIndirect(
677 Graphics::Buffer& buffer,
680 uint32_t stride) override
682 mCommands.emplace_back();
683 mCommands.back().type = CommandType::DRAW_INDEXED_INDIRECT;
684 auto& cmd = mCommands.back().data.draw;
685 cmd.type = DrawCallDescriptor::Type::DRAW_INDEXED_INDIRECT;
686 cmd.drawIndexedIndirect.buffer = static_cast<const TestGraphicsBuffer*>(&buffer);
687 cmd.drawIndexedIndirect.offset = offset;
688 cmd.drawIndexedIndirect.drawCount = drawCount;
689 cmd.drawIndexedIndirect.stride = stride;
690 mCallStack.PushCall("DrawIndexedIndirect", "");
693 void Reset() override
696 mCallStack.PushCall("Reset", "");
699 void SetScissor(Graphics::Rect2D value) override
701 TraceCallStack::NamedParams params;
702 params["x"] << value.x;
703 params["y"] << value.y;
704 params["width"] << value.width;
705 params["height"] << value.height;
706 mCallStack.PushCall("SetScissor", params.str(), params);
708 mCommands.emplace_back();
709 mCommands.back().type = CommandType::SET_SCISSOR;
710 mCommands.back().data.scissor.region = value;
713 void SetScissorTestEnable(bool value) override
715 TraceCallStack::NamedParams params;
716 params["value"] << (value ? "T" : "F");
717 mCallStack.PushCall("SetScissorTestEnable", params.str(), params);
719 mCommands.emplace_back();
720 mCommands.back().type = CommandType::SET_SCISSOR_TEST;
721 mCommands.back().data.scissorTest.enable = value;
724 void SetViewport(Graphics::Viewport value) override
726 TraceCallStack::NamedParams params;
727 params["x"] << value.x;
728 params["y"] << value.y;
729 params["width"] << value.width;
730 params["height"] << value.height;
731 params["minDepth"] << value.minDepth;
732 params["maxDepth"] << value.maxDepth;
733 mCallStack.PushCall("SetViewport", params.str(), params);
735 mCommands.emplace_back();
736 mCommands.back().type = CommandType::SET_VIEWPORT;
737 mCommands.back().data.viewport.region = value;
740 void SetViewportEnable(bool value) override
742 TraceCallStack::NamedParams params;
743 params["value"] << (value ? "T" : "F");
744 mCallStack.PushCall("SetViewportEnable", params.str(), params);
746 mCommands.emplace_back();
747 mCommands.back().type = CommandType::SET_VIEWPORT_TEST;
748 mCommands.back().data.viewportTest.enable = value;
751 [[nodiscard]] const std::vector<Command>& GetCommands() const
757 * Returns number of draw commands
760 int GetDrawCallsCount();
763 * Retrieves state resolve for selected draw call
764 * @param drawCommandIndex
766 void GetStateForDrawCall(int drawCallIndex);
769 * Retrieves commands of specified type
771 std::vector<const Command*> GetCommandsByType(CommandTypeMask mask) const;
773 std::vector<const Command*> GetChildCommandsByType(CommandTypeMask mask) const;
776 TraceCallStack& mCallStack;
777 TestGlAbstraction& mGlAbstraction;
779 std::vector<Command> mCommands;
784 #endif //DALI_TEST_GRAPHICS_COMMAND_BUFFER_H