+class TestGraphicsTexture;
+class TestGraphicsBuffer;
+class TestGraphicsCommandBuffer;
+class TestGraphicsSampler;
+class TestGraphicsPipeline;
+
+enum class CommandType
+{
+ FLUSH = 1 << 0,
+ BIND_TEXTURES = 1 << 1,
+ BIND_SAMPLERS = 1 << 2,
+ BIND_VERTEX_BUFFERS = 1 << 3,
+ BIND_INDEX_BUFFER = 1 << 4,
+ BIND_UNIFORM_BUFFER = 1 << 5,
+ BIND_PIPELINE = 1 << 6,
+ DRAW = 1 << 7,
+ DRAW_INDEXED = 1 << 8,
+ DRAW_INDEXED_INDIRECT = 1 << 9,
+ SET_SCISSOR = 1 << 10,
+ SET_SCISSOR_TEST = 1 << 11,
+ SET_VIEWPORT = 1 << 12,
+ SET_VIEWPORT_TEST = 1 << 13,
+ BEGIN_RENDER_PASS = 1 << 14,
+ END_RENDER_PASS = 1 << 15,
+ EXECUTE_COMMAND_BUFFERS = 1 << 16,
+ SET_COLOR_MASK = 1 << 17,
+ CLEAR_STENCIL_BUFFER = 1 << 18,
+ CLEAR_DEPTH_BUFFER = 1 << 19,
+ SET_STENCIL_TEST_ENABLE = 1 << 20,
+ SET_STENCIL_WRITE_MASK = 1 << 21,
+ SET_STENCIL_OP = 1 << 22,
+ SET_STENCIL_FUNC = 1 << 23,
+ SET_DEPTH_COMPARE_OP = 1 << 24,
+ SET_DEPTH_TEST_ENABLE = 1 << 25,
+ SET_DEPTH_WRITE_ENABLE = 1 << 26,
+ DRAW_NATIVE = 1 << 27,
+};
+
+std::ostream& operator<<(std::ostream& os, Graphics::StencilOp op);
+
+std::ostream& operator<<(std::ostream& os, Graphics::CompareOp op);
+
+using CommandTypeMask = uint32_t;
+template<typename T>
+inline CommandTypeMask operator|(T flags, CommandType bit)
+{
+ return static_cast<CommandTypeMask>(flags) | static_cast<CommandTypeMask>(bit);
+}
+
+/**
+ * @brief Descriptor of single buffer binding within
+ * command buffer.
+ */
+struct VertexBufferBindingDescriptor
+{
+ const TestGraphicsBuffer* buffer{nullptr};
+ uint32_t offset{0u};
+};
+
+/**
+ * @brief Descriptor of ix buffer binding within
+ * command buffer.
+ */
+struct IndexBufferBindingDescriptor
+{
+ const TestGraphicsBuffer* buffer{nullptr};
+ uint32_t offset{};
+ Graphics::Format format{};
+};
+
+/**
+ * @brief Descriptor of uniform buffer binding within
+ * command buffer.
+ */
+struct UniformBufferBindingDescriptor
+{
+ const TestGraphicsBuffer* buffer{nullptr};
+ uint32_t binding{0u};
+ uint32_t offset{0u};
+ bool emulated; ///<true if UBO is emulated for old gfx API
+};
+
+/**
+ * @brief The descriptor of draw call
+ */
+struct DrawCallDescriptor
+{
+ /**
+ * @brief Enum specifying type of the draw call
+ */
+ enum class Type
+ {
+ DRAW,
+ DRAW_INDEXED,
+ DRAW_INDEXED_INDIRECT,
+ DRAW_NATIVE
+ };
+
+ Type type{}; ///< Type of the draw call
+
+ /**
+ * Union contains data for all types of draw calls.
+ */
+ union
+ {
+ /**
+ * @brief Vertex array draw
+ */
+ struct
+ {
+ uint32_t vertexCount;
+ uint32_t instanceCount;
+ uint32_t firstVertex;
+ uint32_t firstInstance;
+ } draw;
+
+ /**
+ * @brief Indexed draw
+ */
+ struct
+ {
+ uint32_t indexCount;
+ uint32_t instanceCount;
+ uint32_t firstIndex;
+ int32_t vertexOffset;
+ uint32_t firstInstance;
+ } drawIndexed;
+
+ /**
+ * @brief Indexed draw indirect
+ */
+ struct
+ {
+ const TestGraphicsBuffer* buffer;
+ uint32_t offset;
+ uint32_t drawCount;
+ uint32_t stride;
+ } drawIndexedIndirect;
+
+ struct
+ {
+ Graphics::DrawNativeInfo drawNativeInfo;
+ } drawNative;
+ };
+};
+
+/**
+ * Command structure allocates memory to store a single command
+ */
+struct Command
+{
+ Command()
+ {
+ }
+
+ Command(CommandType type)
+ : type(type)
+ {
+ // do non-trivial initialization
+ switch(type)
+ {
+ case CommandType::BEGIN_RENDER_PASS:
+ {
+ new(&data.beginRenderPass) CommandData::BeginRenderPassDescriptor();
+ break;
+ }
+ default:
+ {
+ }
+ }
+ }
+
+ ~Command()
+ {
+ switch(type)
+ {
+ case CommandType::BEGIN_RENDER_PASS:
+ {
+ data.beginRenderPass.~BeginRenderPassDescriptor();
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ /**
+ * @brief Copy constructor
+ * @param[in] rhs Command
+ */
+ Command(const Command& rhs)
+ {
+ switch(rhs.type)
+ {
+ case CommandType::BEGIN_RENDER_PASS:
+ {
+ new(&data.beginRenderPass) CommandData::BeginRenderPassDescriptor(rhs.data.beginRenderPass);
+ break;
+ }
+ case CommandType::END_RENDER_PASS:
+ {
+ data.endRenderPass = rhs.data.endRenderPass;
+ break;
+ }
+ case CommandType::EXECUTE_COMMAND_BUFFERS:
+ {
+ data.executeCommandBuffers = rhs.data.executeCommandBuffers;
+ break;
+ }
+
+ case CommandType::BIND_VERTEX_BUFFERS:
+ {
+ data.bindVertexBuffers = rhs.data.bindVertexBuffers;
+ break;
+ }
+ case CommandType::BIND_INDEX_BUFFER:
+ {
+ data.bindIndexBuffer = rhs.data.bindIndexBuffer;
+ break;
+ }
+ case CommandType::BIND_SAMPLERS:
+ {
+ data.bindSamplers = rhs.data.bindSamplers;
+ break;
+ }
+ case CommandType::BIND_TEXTURES:
+ {
+ data.bindTextures = rhs.data.bindTextures;
+ break;
+ }
+ case CommandType::BIND_PIPELINE:
+ {
+ data.bindPipeline = rhs.data.bindPipeline;
+ break;
+ }
+ case CommandType::BIND_UNIFORM_BUFFER:
+ {
+ data.bindUniformBuffers = rhs.data.bindUniformBuffers;
+ break;
+ }
+ case CommandType::DRAW_NATIVE:
+ {
+ data.draw.type = rhs.data.draw.type;
+ data.draw.drawNative = rhs.data.draw.drawNative;
+ break;
+ }
+ case CommandType::DRAW:
+ {
+ data.draw.type = rhs.data.draw.type;
+ data.draw.draw = rhs.data.draw.draw;
+ break;
+ }
+ case CommandType::DRAW_INDEXED:
+ {
+ data.draw.type = rhs.data.draw.type;
+ data.draw.drawIndexed = rhs.data.draw.drawIndexed;
+ break;
+ }
+ case CommandType::DRAW_INDEXED_INDIRECT:
+ {
+ data.draw.type = rhs.data.draw.type;
+ data.draw.drawIndexedIndirect = rhs.data.draw.drawIndexedIndirect;
+ break;
+ }
+ case CommandType::FLUSH:
+ {
+ // Nothing to do
+ break;
+ }
+ case CommandType::SET_SCISSOR:
+ {
+ data.scissor.region = rhs.data.scissor.region;
+ break;
+ }
+ case CommandType::SET_SCISSOR_TEST:
+ {
+ data.scissorTest.enable = rhs.data.scissorTest.enable;
+ break;
+ }
+ case CommandType::SET_VIEWPORT:
+ {
+ data.viewport.region = rhs.data.viewport.region;
+ break;
+ }
+ case CommandType::SET_VIEWPORT_TEST:
+ {
+ data.viewportTest.enable = rhs.data.viewportTest.enable;
+ break;
+ }
+ case CommandType::SET_COLOR_MASK:
+ {
+ data.colorMask.enabled = rhs.data.colorMask.enabled;
+ break;
+ }
+ case CommandType::CLEAR_STENCIL_BUFFER:
+ {
+ break;
+ }
+ case CommandType::CLEAR_DEPTH_BUFFER:
+ {
+ break;
+ }
+ case CommandType::SET_STENCIL_TEST_ENABLE:
+ {
+ data.stencilTest.enabled = rhs.data.stencilTest.enabled;
+ break;
+ }
+ case CommandType::SET_STENCIL_FUNC:
+ {
+ data.stencilFunc.compareMask = rhs.data.stencilFunc.compareMask;
+ data.stencilFunc.compareOp = rhs.data.stencilFunc.compareOp;
+ data.stencilFunc.reference = rhs.data.stencilFunc.reference;
+ break;
+ }
+ case CommandType::SET_STENCIL_WRITE_MASK:
+ {
+ data.stencilWriteMask.mask = rhs.data.stencilWriteMask.mask;
+ break;
+ }
+ case CommandType::SET_STENCIL_OP:
+ {
+ data.stencilOp.failOp = rhs.data.stencilOp.failOp;
+ data.stencilOp.depthFailOp = rhs.data.stencilOp.depthFailOp;
+ data.stencilOp.passOp = rhs.data.stencilOp.passOp;
+ break;
+ }
+
+ case CommandType::SET_DEPTH_COMPARE_OP:
+ {
+ data.depth.compareOp = rhs.data.depth.compareOp;
+ break;
+ }
+ case CommandType::SET_DEPTH_TEST_ENABLE:
+ {
+ data.depth.testEnabled = rhs.data.depth.testEnabled;
+ break;
+ }
+ case CommandType::SET_DEPTH_WRITE_ENABLE:
+ {
+ data.depth.writeEnabled = rhs.data.depth.writeEnabled;
+ break;
+ }
+ }
+ type = rhs.type;
+ }
+
+ /**
+ * @brief move constructor
+ * @param[in] rhs Command
+ */
+ Command(Command&& rhs) noexcept
+ {
+ switch(rhs.type)
+ {
+ case CommandType::BEGIN_RENDER_PASS:
+ {
+ new(&data.beginRenderPass) CommandData::BeginRenderPassDescriptor(std::move(rhs.data.beginRenderPass));
+ break;
+ }
+ case CommandType::END_RENDER_PASS:
+ {
+ data.endRenderPass = std::move(rhs.data.endRenderPass);
+ break;
+ }
+ case CommandType::EXECUTE_COMMAND_BUFFERS:
+ {
+ data.executeCommandBuffers = std::move(rhs.data.executeCommandBuffers);
+ break;
+ }
+ case CommandType::BIND_VERTEX_BUFFERS:
+ {
+ data.bindVertexBuffers = std::move(rhs.data.bindVertexBuffers);
+ break;
+ }
+ case CommandType::BIND_INDEX_BUFFER:
+ {
+ data.bindIndexBuffer = rhs.data.bindIndexBuffer;
+ break;
+ }
+ case CommandType::BIND_UNIFORM_BUFFER:
+ {
+ data.bindUniformBuffers = std::move(rhs.data.bindUniformBuffers);
+ break;
+ }
+ case CommandType::BIND_SAMPLERS:
+ {
+ data.bindSamplers = std::move(rhs.data.bindSamplers);
+ break;
+ }
+ case CommandType::BIND_TEXTURES:
+ {
+ data.bindTextures = std::move(rhs.data.bindTextures);
+ break;
+ }
+ case CommandType::BIND_PIPELINE:
+ {
+ data.bindPipeline = rhs.data.bindPipeline;
+ break;
+ }
+ case CommandType::DRAW_NATIVE:
+ {
+ data.draw.type = rhs.data.draw.type;
+ data.draw.drawNative = rhs.data.draw.drawNative;
+ break;
+ }
+ case CommandType::DRAW:
+ {
+ data.draw.type = rhs.data.draw.type;
+ data.draw.draw = rhs.data.draw.draw;
+ break;
+ }
+ case CommandType::DRAW_INDEXED:
+ {
+ data.draw.type = rhs.data.draw.type;
+ data.draw.drawIndexed = rhs.data.draw.drawIndexed;
+ break;
+ }
+ case CommandType::DRAW_INDEXED_INDIRECT:
+ {
+ data.draw.type = rhs.data.draw.type;
+ data.draw.drawIndexedIndirect = rhs.data.draw.drawIndexedIndirect;
+ break;
+ }
+ case CommandType::FLUSH:
+ {
+ // Nothing to do
+ break;
+ }
+ case CommandType::SET_SCISSOR:
+ {
+ data.scissor.region = rhs.data.scissor.region;
+ break;
+ }
+ case CommandType::SET_SCISSOR_TEST:
+ {
+ data.scissorTest.enable = rhs.data.scissorTest.enable;
+ break;
+ }
+ case CommandType::SET_VIEWPORT:
+ {
+ data.viewport.region = rhs.data.viewport.region;
+ break;
+ }
+ case CommandType::SET_VIEWPORT_TEST:
+ {
+ data.viewportTest.enable = rhs.data.viewportTest.enable;
+ break;
+ }
+
+ case CommandType::SET_COLOR_MASK:
+ {
+ data.colorMask.enabled = rhs.data.colorMask.enabled;
+ break;
+ }
+ case CommandType::CLEAR_STENCIL_BUFFER:
+ {
+ break;
+ }
+ case CommandType::CLEAR_DEPTH_BUFFER:
+ {
+ break;
+ }
+ case CommandType::SET_STENCIL_TEST_ENABLE:
+ {
+ data.stencilTest.enabled = rhs.data.stencilTest.enabled;
+ break;
+ }
+ case CommandType::SET_STENCIL_WRITE_MASK:
+ {
+ data.stencilWriteMask.mask = rhs.data.stencilWriteMask.mask;
+ break;
+ }
+ case CommandType::SET_STENCIL_OP:
+ {
+ data.stencilOp.failOp = rhs.data.stencilOp.failOp;
+ data.stencilOp.depthFailOp = rhs.data.stencilOp.depthFailOp;
+ data.stencilOp.passOp = rhs.data.stencilOp.passOp;
+ break;
+ }
+ case CommandType::SET_STENCIL_FUNC:
+ {
+ data.stencilFunc.compareMask = rhs.data.stencilFunc.compareMask;
+ data.stencilFunc.compareOp = rhs.data.stencilFunc.compareOp;
+ data.stencilFunc.reference = rhs.data.stencilFunc.reference;
+ break;
+ }
+ case CommandType::SET_DEPTH_COMPARE_OP:
+ {
+ data.depth.compareOp = rhs.data.depth.compareOp;
+ break;
+ }
+ case CommandType::SET_DEPTH_TEST_ENABLE:
+ {
+ data.depth.testEnabled = rhs.data.depth.testEnabled;
+ break;
+ }
+ case CommandType::SET_DEPTH_WRITE_ENABLE:
+ {
+ data.depth.writeEnabled = rhs.data.depth.writeEnabled;
+ break;
+ }
+ }
+ type = rhs.type;
+ }
+
+ CommandType type{CommandType::FLUSH}; ///< Type of command
+
+ union CommandData
+ {
+ CommandData()
+ {
+ }
+
+ ~CommandData()
+ {
+ } // do nothing
+
+ struct
+ {
+ std::vector<Graphics::TextureBinding> textureBindings;
+ } bindTextures{};
+
+ // BindSampler command
+ struct
+ {
+ std::vector<Graphics::SamplerBinding> samplerBindings;
+ } bindSamplers;
+
+ struct
+ {
+ using Binding = VertexBufferBindingDescriptor;
+ std::vector<Binding> vertexBufferBindings;
+ } bindVertexBuffers;
+
+ struct : public IndexBufferBindingDescriptor
+ {
+ } bindIndexBuffer;
+
+ struct
+ {
+ std::vector<UniformBufferBindingDescriptor> uniformBufferBindings{};
+ UniformBufferBindingDescriptor standaloneUniformsBufferBinding{};
+ } bindUniformBuffers;
+
+ struct
+ {
+ const TestGraphicsPipeline* pipeline{nullptr};
+ } bindPipeline;
+
+ struct : public DrawCallDescriptor
+ {
+ } draw;
+
+ struct
+ {
+ Graphics::Rect2D region;
+ } scissor;
+ struct
+ {
+ bool enable;
+ } scissorTest;
+ struct
+ {
+ Graphics::Viewport region;
+ } viewport;
+ struct
+ {
+ bool enable;
+ } viewportTest;
+
+ struct BeginRenderPassDescriptor
+ {
+ Graphics::RenderPass* renderPass;
+ Graphics::RenderTarget* renderTarget;
+ Graphics::Rect2D renderArea;
+ std::vector<Graphics::ClearValue> clearValues;
+ } beginRenderPass;
+
+ struct
+ {
+ Graphics::SyncObject* syncObject;
+ } endRenderPass;
+
+ struct
+ {
+ std::vector<const TestGraphicsCommandBuffer*> buffers;
+ } executeCommandBuffers;
+
+ struct
+ {
+ Graphics::CompareOp compareOp;
+ bool testEnabled;
+ bool writeEnabled;
+ } depth;
+
+ struct
+ {
+ Graphics::StencilOp failOp;
+ Graphics::StencilOp passOp;
+ Graphics::StencilOp depthFailOp;
+ } stencilOp;
+
+ struct
+ {
+ uint32_t mask;
+ } stencilWriteMask;
+
+ struct
+ {
+ uint32_t compareMask;
+ Graphics::CompareOp compareOp;
+ uint32_t reference;
+ } stencilFunc;
+
+ struct
+ {
+ bool enabled;
+ } stencilTest;
+
+ struct
+ {
+ bool enabled;
+ } colorMask;
+ } data;
+};
+