X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=automated-tests%2Fsrc%2Fdali-toolkit%2Fdali-toolkit-test-utils%2Ftest-graphics-controller.cpp;h=08867195432360e2a431ff8c9e8ef6e26dcf6296;hp=51f0721432e4e1cd728b3a2769d944ab1139b006;hb=HEAD;hpb=950447e00422e94e22ce64a69a13ebf1235b12c6 diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-controller.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-controller.cpp index 51f0721..24bb51e 100644 --- a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-controller.cpp +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-controller.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,49 +16,41 @@ #include "test-graphics-controller.h" +#include #include "test-graphics-buffer.h" #include "test-graphics-command-buffer.h" +#include "test-graphics-framebuffer.h" #include "test-graphics-reflection.h" +#include "test-graphics-render-pass.h" +#include "test-graphics-render-target.h" #include "test-graphics-sampler.h" #include "test-graphics-shader.h" +#include "test-graphics-sync-object.h" #include "test-graphics-texture.h" #include +#include #include #include +#include #include namespace Dali { -template -T* Uncast(const Graphics::CommandBuffer* object) +namespace { - return const_cast(static_cast(object)); -} - -template -T* Uncast(const Graphics::Texture* object) -{ - return const_cast(static_cast(object)); -} - -template -T* Uncast(const Graphics::Sampler* object) -{ - return const_cast(static_cast(object)); -} - -template -T* Uncast(const Graphics::Buffer* object) +template +struct TestGraphicsDeleter { - return const_cast(static_cast(object)); -} + TestGraphicsDeleter() = default; + void operator()(T* object) + { + // Discard resource + object->DiscardResource(); + } +}; -template -T* Uncast(const Graphics::Shader* object) -{ - return const_cast(static_cast(object)); -} +} //namespace std::ostream& operator<<(std::ostream& o, const Graphics::BufferCreateInfo& bufferCreateInfo) { @@ -104,7 +96,7 @@ std::ostream& operator<<(std::ostream& o, const Graphics::TextureCreateInfo& cre << " usageFlags:" << std::hex << createInfo.usageFlags << " data:" << std::hex << createInfo.data << " dataSize:" << std::dec << createInfo.dataSize - << " nativeImagePtr:" << std::hex << createInfo.nativeImagePtr; + << " nativeImagePtr:" << std::hex << createInfo.nativeImagePtr.Get(); return o; } @@ -173,70 +165,34 @@ std::ostream& operator<<(std::ostream& o, const Graphics::SamplerCreateInfo& cre return o; } -class TestGraphicsMemory : public Graphics::Memory +std::ostream& operator<<(std::ostream& o, const Graphics::ColorAttachment& colorAttachment) { -public: - TestGraphicsMemory(TraceCallStack& callStack, TestGraphicsBuffer& buffer, uint32_t mappedOffset, uint32_t mappedSize) - : mCallStack(callStack), - mBuffer(buffer), - mMappedOffset(mappedOffset), - mMappedSize(mappedSize), - mLockedOffset(0u), - mLockedSize(0u) - { - } - - void* LockRegion(uint32_t offset, uint32_t size) override - { - std::ostringstream o; - o << offset << ", " << size; - mCallStack.PushCall("Memory::LockRegion", o.str()); - - if(offset > mMappedOffset + mMappedSize || - size + offset > mMappedOffset + mMappedSize) - { - fprintf(stderr, "TestGraphics.Memory::LockRegion() Out of bounds"); - mBuffer.memory.resize(mMappedOffset + offset + size); // Grow to prevent memcpy from crashing - } - mLockedOffset = offset; - mLockedSize = size; - return &mBuffer.memory[mMappedOffset + offset]; - } + o << "attachmentId:" << colorAttachment.attachmentId + << " layerId:" << colorAttachment.layerId + << " levelId:" << colorAttachment.levelId + << " texture:" << colorAttachment.texture; + return o; +} - void Unlock(bool flush) override - { - mCallStack.PushCall("Memory::Unlock", (flush ? "Flush" : "NoFlush")); - if(flush) - { - Flush(); - } - } +std::ostream& operator<<(std::ostream& o, const Graphics::DepthStencilAttachment& depthStencilAttachment) +{ + o << "depthTexture:" << depthStencilAttachment.depthTexture + << "depthLevel:" << depthStencilAttachment.depthLevel + << "stencilTexture:" << depthStencilAttachment.stencilTexture + << "stencilLevel:" << depthStencilAttachment.stencilLevel; + return o; +} - void Flush() override +std::ostream& operator<<(std::ostream& o, const Graphics::FramebufferCreateInfo& createInfo) +{ + o << "colorAttachments:"; + for(auto i = 0u; i < createInfo.colorAttachments.size(); ++i) { - mCallStack.PushCall("Memory::Flush", ""); - mBuffer.Bind(); - mBuffer.Upload(mMappedOffset + mLockedOffset, mLockedSize); - mBuffer.Unbind(); + o << "[" << i << "]=" << createInfo.colorAttachments[i] << " "; } - - TraceCallStack& mCallStack; - TestGraphicsBuffer& mBuffer; - uint32_t mMappedOffset; - uint32_t mMappedSize; - uint32_t mLockedOffset; - uint32_t mLockedSize; -}; - -TestGraphicsController::TestGraphicsController() -: mCallStack(true, "TestGraphicsController."), - mCommandBufferCallStack(true, "TestCommandBuffer.") -{ - mCallStack.Enable(true); - mCommandBufferCallStack.Enable(true); - auto& trace = mGl.GetTextureTrace(); - trace.Enable(true); - trace.EnableLogging(true); + o << "depthStencilAttachment:" << createInfo.depthStencilAttachment; + o << "size: " << createInfo.size; + return o; } int GetNumComponents(Graphics::VertexInputFormat vertexFormat) @@ -441,12 +397,222 @@ GLenum GetBlendOp(Graphics::BlendOp blendOp) case Graphics::BlendOp::MAX: op = GL_MAX; break; - - // @todo Add advanced blend equations + case Graphics::BlendOp::MULTIPLY: + { + op = GL_MULTIPLY; + break; + } + case Graphics::BlendOp::SCREEN: + { + op = GL_SCREEN; + break; + } + case Graphics::BlendOp::OVERLAY: + { + op = GL_OVERLAY; + break; + } + case Graphics::BlendOp::DARKEN: + { + op = GL_DARKEN; + break; + } + case Graphics::BlendOp::LIGHTEN: + { + op = GL_LIGHTEN; + break; + } + case Graphics::BlendOp::COLOR_DODGE: + { + op = GL_COLORDODGE; + break; + } + case Graphics::BlendOp::COLOR_BURN: + { + op = GL_COLORBURN; + break; + } + case Graphics::BlendOp::HARD_LIGHT: + { + op = GL_HARDLIGHT; + break; + } + case Graphics::BlendOp::SOFT_LIGHT: + { + op = GL_SOFTLIGHT; + break; + } + case Graphics::BlendOp::DIFFERENCE: + { + op = GL_DIFFERENCE; + break; + } + case Graphics::BlendOp::EXCLUSION: + { + op = GL_EXCLUSION; + break; + } + case Graphics::BlendOp::HUE: + { + op = GL_HSL_HUE; + break; + } + case Graphics::BlendOp::SATURATION: + { + op = GL_HSL_SATURATION; + break; + } + case Graphics::BlendOp::COLOR: + { + op = GL_HSL_COLOR; + break; + } + case Graphics::BlendOp::LUMINOSITY: + { + op = GL_HSL_LUMINOSITY; + break; + } } return op; } +struct GLCompareOp +{ + constexpr explicit GLCompareOp(Graphics::CompareOp compareOp) + { + switch(compareOp) + { + case Graphics::CompareOp::NEVER: + op = GL_NEVER; + break; + case Graphics::CompareOp::LESS: + op = GL_LESS; + break; + case Graphics::CompareOp::EQUAL: + op = GL_EQUAL; + break; + case Graphics::CompareOp::LESS_OR_EQUAL: + op = GL_LEQUAL; + break; + case Graphics::CompareOp::GREATER: + op = GL_GREATER; + break; + case Graphics::CompareOp::NOT_EQUAL: + op = GL_NOTEQUAL; + break; + case Graphics::CompareOp::GREATER_OR_EQUAL: + op = GL_GEQUAL; + break; + case Graphics::CompareOp::ALWAYS: + op = GL_ALWAYS; + break; + } + } + GLenum op{GL_LESS}; +}; + +struct GLStencilOp +{ + constexpr explicit GLStencilOp(Graphics::StencilOp stencilOp) + { + switch(stencilOp) + { + case Graphics::StencilOp::KEEP: + op = GL_KEEP; + break; + case Graphics::StencilOp::ZERO: + op = GL_ZERO; + break; + case Graphics::StencilOp::REPLACE: + op = GL_REPLACE; + break; + case Graphics::StencilOp::INCREMENT_AND_CLAMP: + op = GL_INCR; + break; + case Graphics::StencilOp::DECREMENT_AND_CLAMP: + op = GL_DECR; + break; + case Graphics::StencilOp::INVERT: + op = GL_INVERT; + break; + case Graphics::StencilOp::INCREMENT_AND_WRAP: + op = GL_INCR_WRAP; + break; + case Graphics::StencilOp::DECREMENT_AND_WRAP: + op = GL_DECR_WRAP; + break; + } + } + GLenum op{GL_KEEP}; +}; + +class TestGraphicsMemory : public Graphics::Memory +{ +public: + TestGraphicsMemory(TraceCallStack& callStack, TestGraphicsBuffer& buffer, uint32_t mappedOffset, uint32_t mappedSize) + : mCallStack(callStack), + mBuffer(buffer), + mMappedOffset(mappedOffset), + mMappedSize(mappedSize), + mLockedOffset(0u), + mLockedSize(0u) + { + } + + void* LockRegion(uint32_t offset, uint32_t size) override + { + std::ostringstream o; + o << offset << ", " << size; + mCallStack.PushCall("Memory::LockRegion", o.str()); + + if(offset > mMappedOffset + mMappedSize || + size + offset > mMappedOffset + mMappedSize) + { + fprintf(stderr, "TestGraphics.Memory::LockRegion() Out of bounds"); + mBuffer.memory.resize(mMappedOffset + offset + size); // Grow to prevent memcpy from crashing + } + mLockedOffset = offset; + mLockedSize = size; + return &mBuffer.memory[mMappedOffset + offset]; + } + + void Unlock(bool flush) override + { + mCallStack.PushCall("Memory::Unlock", (flush ? "Flush" : "NoFlush")); + if(flush) + { + Flush(); + } + } + + void Flush() override + { + mCallStack.PushCall("Memory::Flush", ""); + mBuffer.Bind(); + mBuffer.Upload(mMappedOffset + mLockedOffset, mLockedSize); + mBuffer.Unbind(); + } + + TraceCallStack& mCallStack; + TestGraphicsBuffer& mBuffer; + uint32_t mMappedOffset; + uint32_t mMappedSize; + uint32_t mLockedOffset; + uint32_t mLockedSize; +}; + +TestGraphicsController::TestGraphicsController() +: mCallStack(false, "TestGraphicsController."), + mCommandBufferCallStack(false, "TestCommandBuffer."), + mFrameBufferCallStack(false, "TestFrameBuffer.") +{ + mCallStack.Enable(true); + mCommandBufferCallStack.Enable(true); + auto& trace = mGl.GetTextureTrace(); + trace.Enable(true); + trace.EnableLogging(false); +} + void TestGraphicsController::SubmitCommandBuffers(const Graphics::SubmitInfo& submitInfo) { TraceCallStack::NamedParams namedParams; @@ -460,202 +626,475 @@ void TestGraphicsController::SubmitCommandBuffers(const Graphics::SubmitInfo& su for(auto& graphicsCommandBuffer : submitInfo.cmdBuffer) { auto commandBuffer = Uncast(graphicsCommandBuffer); + ProcessCommandBuffer(*commandBuffer); + } +} + +void TestGraphicsController::ProcessCommandBuffer(TestGraphicsCommandBuffer& commandBuffer) +{ + bool scissorEnabled = false; + TestGraphicsFramebuffer* currentFramebuffer{nullptr}; + TestGraphicsPipeline* currentPipeline{nullptr}; - auto value = commandBuffer->GetCommandsByType(0 | CommandType::BIND_TEXTURES); - if(!value.empty()) + for(auto& cmd : commandBuffer.GetCommands()) + { + // process command + switch(cmd.type) { - // must be fixed - for(auto& binding : value[0]->data.bindTextures.textureBindings) + case CommandType::FLUSH: + { + // Nothing to do here + break; + } + case CommandType::BIND_TEXTURES: { - if(binding.texture) + for(auto& binding : cmd.data.bindTextures.textureBindings) { - auto texture = Uncast(binding.texture); - - texture->Bind(binding.binding); - - if(binding.sampler) + if(binding.texture) { - auto sampler = Uncast(binding.sampler); - if(sampler) + auto texture = Uncast(binding.texture); + texture->Bind(binding.binding); + + if(binding.sampler) { - sampler->Apply(texture->GetTarget()); + auto sampler = Uncast(binding.sampler); + if(sampler) + { + sampler->Apply(texture->GetTarget()); + } } - } - texture->Prepare(); // Ensure native texture is ready + texture->Prepare(); // Ensure native texture is ready + } } + break; } - } - - // IndexBuffer binding, - auto bindIndexBufferCmds = commandBuffer->GetCommandsByType(0 | CommandType::BIND_INDEX_BUFFER); - if(!bindIndexBufferCmds.empty()) - { - auto& indexBufferBinding = bindIndexBufferCmds[0]->data.bindIndexBuffer; - if(indexBufferBinding.buffer) + case CommandType::BIND_VERTEX_BUFFERS: { - auto buffer = Uncast(indexBufferBinding.buffer); - buffer->Bind(); + for(auto& binding : cmd.data.bindVertexBuffers.vertexBufferBindings) + { + auto graphicsBuffer = binding.buffer; + auto vertexBuffer = Uncast(graphicsBuffer); + vertexBuffer->Bind(); + } + break; } - } + case CommandType::BIND_INDEX_BUFFER: + { + auto& indexBufferBinding = cmd.data.bindIndexBuffer; + if(indexBufferBinding.buffer) + { + auto buffer = Uncast(indexBufferBinding.buffer); + buffer->Bind(); + } + break; + } + case CommandType::BIND_UNIFORM_BUFFER: + { + if(currentPipeline) + { + auto& bindings = cmd.data.bindUniformBuffers; + auto buffer = bindings.standaloneUniformsBufferBinding; - // VertexBuffer binding, - auto bindVertexBufferCmds = commandBuffer->GetCommandsByType(0 | CommandType::BIND_VERTEX_BUFFERS); - if(!bindVertexBufferCmds.empty()) - { - for(auto& binding : bindVertexBufferCmds[0]->data.bindVertexBuffers.vertexBufferBindings) + // based on reflection, issue gl calls + buffer.buffer->BindAsUniformBuffer(static_cast(currentPipeline->programState.program), bindings.standaloneUniformsBufferBinding); + } + break; + } + case CommandType::BIND_SAMPLERS: + { + break; + } + case CommandType::BIND_PIPELINE: { - auto graphicsBuffer = binding.buffer; - auto vertexBuffer = Uncast(graphicsBuffer); - vertexBuffer->Bind(); + currentPipeline = Uncast(cmd.data.bindPipeline.pipeline); + BindPipeline(currentPipeline); + break; } - } + case CommandType::DRAW_NATIVE: + { + auto info = &cmd.data.draw.drawNative.drawNativeInfo; - bool scissorEnabled = false; + if(info->glesNativeInfo.eglSharedContextStoragePointer) + { + auto* anyContext = reinterpret_cast(info->glesNativeInfo.eglSharedContextStoragePointer); + *anyContext = reinterpret_cast(0x12345678u); + } - auto scissorTestList = commandBuffer->GetCommandsByType(0 | CommandType::SET_SCISSOR_TEST); - if(!scissorTestList.empty()) - { - if(scissorTestList[0]->data.scissorTest.enable) + CallbackBase::ExecuteReturn(*info->callback, info->userData); + break; + } + case CommandType::DRAW: + { + if(currentPipeline) + { + if(cmd.data.draw.draw.instanceCount == 0) + { + mGl.DrawArrays(GetTopology(currentPipeline->inputAssemblyState.topology), + cmd.data.draw.draw.firstVertex, + cmd.data.draw.draw.vertexCount); + } + else + { + mGl.DrawArraysInstanced(GetTopology(currentPipeline->inputAssemblyState.topology), + cmd.data.draw.draw.firstVertex, + cmd.data.draw.draw.vertexCount, + cmd.data.draw.draw.instanceCount); + } + } + break; + } + case CommandType::DRAW_INDEXED: { - mGl.Enable(GL_SCISSOR_TEST); - scissorEnabled = true; + if(currentPipeline) + { + if(cmd.data.draw.draw.instanceCount == 0) + { + mGl.DrawElements(GetTopology(currentPipeline->inputAssemblyState.topology), + static_cast(cmd.data.draw.drawIndexed.indexCount), + GL_UNSIGNED_SHORT, + reinterpret_cast(cmd.data.draw.drawIndexed.firstIndex)); + } + else + { + mGl.DrawElementsInstanced(GetTopology(currentPipeline->inputAssemblyState.topology), + static_cast(cmd.data.draw.drawIndexed.indexCount), + GL_UNSIGNED_SHORT, + reinterpret_cast(cmd.data.draw.drawIndexed.firstIndex), + cmd.data.draw.drawIndexed.instanceCount); + } + } + break; } - else + case CommandType::DRAW_INDEXED_INDIRECT: { - mGl.Disable(GL_SCISSOR_TEST); + if(currentPipeline) + { + mGl.DrawElements(GetTopology(currentPipeline->inputAssemblyState.topology), + static_cast(cmd.data.draw.drawIndexed.indexCount), + GL_UNSIGNED_SHORT, + reinterpret_cast(cmd.data.draw.drawIndexed.firstIndex)); + } + break; + } + case CommandType::SET_SCISSOR: + { + if(scissorEnabled) + { + auto& rect = cmd.data.scissor.region; + mGl.Scissor(rect.x, rect.y, rect.width, rect.height); + } + break; + } + case CommandType::SET_SCISSOR_TEST: + { + if(cmd.data.scissorTest.enable) + { + mGl.Enable(GL_SCISSOR_TEST); + scissorEnabled = true; + } + else + { + mGl.Disable(GL_SCISSOR_TEST); + scissorEnabled = false; + } + break; + } + case CommandType::SET_VIEWPORT_TEST: + { + break; + } + case CommandType::SET_VIEWPORT: // @todo Consider correcting for orientation here? + { + auto& rect = cmd.data.viewport.region; + mGl.Viewport(rect.x, rect.y, rect.width, rect.height); + break; } - } - - auto scissorList = commandBuffer->GetCommandsByType(0 | CommandType::SET_SCISSOR); - if(!scissorList.empty() && scissorEnabled) - { - auto& rect = scissorList[0]->data.scissor.region; - mGl.Scissor(rect.x, rect.y, rect.width, rect.height); - } - auto viewportList = commandBuffer->GetCommandsByType(0 | CommandType::SET_VIEWPORT); - if(!viewportList.empty()) - { - mGl.Viewport(viewportList[0]->data.viewport.region.x, viewportList[0]->data.viewport.region.y, viewportList[0]->data.viewport.region.width, viewportList[0]->data.viewport.region.height); - } + case CommandType::SET_COLOR_MASK: + { + // Set all channels to the same mask + const bool mask = cmd.data.colorMask.enabled; + mGl.ColorMask(mask, mask, mask, mask); + break; + } + case CommandType::CLEAR_STENCIL_BUFFER: + { + mGl.Clear(GL_STENCIL_BUFFER_BIT); + break; + } + case CommandType::CLEAR_DEPTH_BUFFER: + { + mGl.Clear(GL_DEPTH_BUFFER_BIT); + break; + } - // ignore viewport enable + case CommandType::SET_STENCIL_TEST_ENABLE: + { + if(cmd.data.stencilTest.enabled) + { + mGl.Enable(GL_STENCIL_TEST); + } + else + { + mGl.Disable(GL_STENCIL_TEST); + } + break; + } - // Pipeline attribute setup - auto bindPipelineCmds = commandBuffer->GetCommandsByType(0 | CommandType::BIND_PIPELINE); - if(!bindPipelineCmds.empty()) - { - auto pipeline = bindPipelineCmds[0]->data.bindPipeline.pipeline; - auto& vi = pipeline->vertexInputState; - for(auto& attribute : vi.attributes) + case CommandType::SET_STENCIL_FUNC: { - mGl.EnableVertexAttribArray(attribute.location); - uint32_t attributeOffset = attribute.offset; - GLsizei stride = vi.bufferBindings[attribute.binding].stride; - - mGl.VertexAttribPointer(attribute.location, - GetNumComponents(attribute.format), - GetGlType(attribute.format), - GL_FALSE, // Not normalized - stride, - reinterpret_cast(attributeOffset)); + mGl.StencilFunc(GLCompareOp(cmd.data.stencilFunc.compareOp).op, + cmd.data.stencilFunc.reference, + cmd.data.stencilFunc.compareMask); + break; } - // Cull face setup - auto& rasterizationState = pipeline->rasterizationState; - if(rasterizationState.cullMode == Graphics::CullMode::NONE) + case CommandType::SET_STENCIL_WRITE_MASK: { - mGl.Disable(GL_CULL_FACE); + mGl.StencilMask(cmd.data.stencilWriteMask.mask); + break; } - else + case CommandType::SET_STENCIL_OP: { - mGl.Enable(GL_CULL_FACE); - mGl.CullFace(GetCullFace(rasterizationState.cullMode)); + mGl.StencilOp(GLStencilOp(cmd.data.stencilOp.failOp).op, + GLStencilOp(cmd.data.stencilOp.depthFailOp).op, + GLStencilOp(cmd.data.stencilOp.passOp).op); + break; } - mGl.FrontFace(GetFrontFace(rasterizationState.frontFace)); - // We don't modify glPolygonMode in our context/abstraction from GL_FILL (the GL default), - // so it isn't present in the API (and won't have any tests!) - - // Blending setup - auto& colorBlendState = pipeline->colorBlendState; - if(colorBlendState.blendEnable) + case CommandType::SET_DEPTH_COMPARE_OP: { - mGl.Enable(GL_BLEND); - - mGl.BlendFuncSeparate(GetBlendFactor(colorBlendState.srcColorBlendFactor), - GetBlendFactor(colorBlendState.dstColorBlendFactor), - GetBlendFactor(colorBlendState.srcAlphaBlendFactor), - GetBlendFactor(colorBlendState.dstAlphaBlendFactor)); - if(colorBlendState.colorBlendOp != colorBlendState.alphaBlendOp) + mGl.DepthFunc(GLCompareOp(cmd.data.depth.compareOp).op); + break; + } + case CommandType::SET_DEPTH_TEST_ENABLE: + { + if(cmd.data.depth.testEnabled) { - mGl.BlendEquationSeparate(GetBlendOp(colorBlendState.colorBlendOp), GetBlendOp(colorBlendState.alphaBlendOp)); + mGl.Enable(GL_DEPTH_TEST); } else { - mGl.BlendEquation(GetBlendOp(colorBlendState.colorBlendOp)); + mGl.Disable(GL_DEPTH_TEST); } - mGl.BlendColor(colorBlendState.blendConstants[0], - colorBlendState.blendConstants[1], - colorBlendState.blendConstants[2], - colorBlendState.blendConstants[3]); + break; } - else + case CommandType::SET_DEPTH_WRITE_ENABLE: { - mGl.Disable(GL_BLEND); + mGl.DepthMask(cmd.data.depth.writeEnabled); + break; } - // draw call - auto topology = pipeline->inputAssemblyState.topology; - - // UniformBuffer binding (once we know pipeline) - auto bindUniformBuffersCmds = commandBuffer->GetCommandsByType(0 | CommandType::BIND_UNIFORM_BUFFER); - if(!bindUniformBuffersCmds.empty()) + case CommandType::EXECUTE_COMMAND_BUFFERS: { - auto buffer = bindUniformBuffersCmds[0]->data.bindUniformBuffers.standaloneUniformsBufferBinding; - - // based on reflection, issue gl calls - buffer.buffer->BindAsUniformBuffer(static_cast(pipeline->programState.program)); + // Process secondary command buffers + for(auto& buf : cmd.data.executeCommandBuffers.buffers) + { + ProcessCommandBuffer(*Uncast(buf)); + } + break; } - - auto drawCmds = commandBuffer->GetCommandsByType(0 | - CommandType::DRAW | - CommandType::DRAW_INDEXED_INDIRECT | - CommandType::DRAW_INDEXED); - - if(!drawCmds.empty()) + case CommandType::BEGIN_RENDER_PASS: { - if(drawCmds[0]->data.draw.type == DrawCallDescriptor::Type::DRAW_INDEXED) + auto renderTarget = Uncast(cmd.data.beginRenderPass.renderTarget); + + if(renderTarget) { - mGl.DrawElements(GetTopology(topology), - static_cast(drawCmds[0]->data.draw.drawIndexed.indexCount), - GL_UNSIGNED_SHORT, - reinterpret_cast(drawCmds[0]->data.draw.drawIndexed.firstIndex)); + auto fb = renderTarget->mCreateInfo.framebuffer; + if(fb) + { + if(currentFramebuffer != fb) + { + currentFramebuffer = Uncast(fb); + currentFramebuffer->Bind(); + } + } + else + { + mGl.BindFramebuffer(GL_FRAMEBUFFER, 0); + } } else { - mGl.DrawArrays(GetTopology(topology), 0, drawCmds[0]->data.draw.draw.vertexCount); + mGl.BindFramebuffer(GL_FRAMEBUFFER, 0); } + + auto& clearValues = cmd.data.beginRenderPass.clearValues; + if(clearValues.size() > 0) + { + const auto renderPass = static_cast(cmd.data.beginRenderPass.renderPass); + if(renderPass) + { + const auto& color0 = renderPass->attachments[0]; + GLuint mask = 0; + if(color0.loadOp == Graphics::AttachmentLoadOp::CLEAR) + { + mask |= GL_COLOR_BUFFER_BIT; + + // Set clear color (todo: cache it!) + // Something goes wrong here if Alpha mask is GL_TRUE + mGl.ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); + mGl.ClearColor(clearValues[0].color.r, + clearValues[0].color.g, + clearValues[0].color.b, + clearValues[0].color.a); + } + + // check for depth stencil + if(renderPass->attachments.size() > 1) + { + const auto& depthStencil = renderPass->attachments.back(); + if(depthStencil.loadOp == Graphics::AttachmentLoadOp::CLEAR) + { + mGl.DepthMask(true); + uint32_t depthClearColor = 0u; + if(clearValues.size() == renderPass->attachments.size()) + { + depthClearColor = clearValues.back().depthStencil.depth; + } + mGl.ClearDepthf(depthClearColor); + mask |= GL_DEPTH_BUFFER_BIT; + } + if(depthStencil.stencilLoadOp == Graphics::AttachmentLoadOp::CLEAR) + { + uint32_t stencilClearColor = 0u; + if(clearValues.size() == renderPass->attachments.size()) + { + stencilClearColor = clearValues.back().depthStencil.stencil; + } + mGl.ClearStencil(stencilClearColor); + mGl.StencilMask(0xFF); // Clear all the bitplanes (assume 8) + mask |= GL_STENCIL_BUFFER_BIT; + } + } + + if(mask != 0) + { + // Test scissor area and RT size + const auto& area = cmd.data.beginRenderPass.renderArea; + if(area.x == 0 && + area.y == 0 && + renderTarget && + area.width == renderTarget->mCreateInfo.extent.width && + area.height == renderTarget->mCreateInfo.extent.height) + { + mGl.Disable(GL_SCISSOR_TEST); + mGl.Clear(mask); + } + else + { + mGl.Enable(GL_SCISSOR_TEST); + mGl.Scissor(cmd.data.beginRenderPass.renderArea.x, cmd.data.beginRenderPass.renderArea.y, cmd.data.beginRenderPass.renderArea.width, cmd.data.beginRenderPass.renderArea.height); + mGl.Clear(mask); + mGl.Disable(GL_SCISSOR_TEST); + } + } + } + else + { + DALI_ASSERT_DEBUG(0 && "BeginRenderPass has no render pass"); + } + } + break; } - // attribute clear - for(auto& attribute : vi.attributes) + case CommandType::END_RENDER_PASS: { - mGl.DisableVertexAttribArray(attribute.location); + if(cmd.data.endRenderPass.syncObject != nullptr) + { + auto syncObject = Uncast(cmd.data.endRenderPass.syncObject); + syncObject->InitializeResource(); // create the sync object. + } + break; } } } } +void TestGraphicsController::BindPipeline(TestGraphicsPipeline* pipeline) +{ + auto& vi = pipeline->vertexInputState; + for(auto& attribute : vi.attributes) + { + mGl.EnableVertexAttribArray(attribute.location); + uint32_t attributeOffset = attribute.offset; + GLsizei stride = vi.bufferBindings[attribute.binding].stride; + + auto rate = vi.bufferBindings[attribute.binding].inputRate; + + mGl.VertexAttribPointer(attribute.location, + GetNumComponents(attribute.format), + GetGlType(attribute.format), + GL_FALSE, // Not normalized + stride, + reinterpret_cast(attributeOffset)); + if(rate == Graphics::VertexInputRate::PER_VERTEX) + { + mGl.VertexAttribDivisor(attribute.location, 0); + } + else if(rate == Graphics::VertexInputRate::PER_INSTANCE) + { + mGl.VertexAttribDivisor(attribute.location, 1); + } + } + + // Cull face setup + auto& rasterizationState = pipeline->rasterizationState; + if(rasterizationState.cullMode == Graphics::CullMode::NONE) + { + mGl.Disable(GL_CULL_FACE); + } + else + { + mGl.Enable(GL_CULL_FACE); + mGl.CullFace(GetCullFace(rasterizationState.cullMode)); + } + + mGl.FrontFace(GetFrontFace(rasterizationState.frontFace)); + + // Blending setup + auto& colorBlendState = pipeline->colorBlendState; + if(colorBlendState.blendEnable) + { + mGl.Enable(GL_BLEND); + + mGl.BlendFuncSeparate(GetBlendFactor(colorBlendState.srcColorBlendFactor), + GetBlendFactor(colorBlendState.dstColorBlendFactor), + GetBlendFactor(colorBlendState.srcAlphaBlendFactor), + GetBlendFactor(colorBlendState.dstAlphaBlendFactor)); + if(colorBlendState.colorBlendOp != colorBlendState.alphaBlendOp) + { + mGl.BlendEquationSeparate(GetBlendOp(colorBlendState.colorBlendOp), GetBlendOp(colorBlendState.alphaBlendOp)); + } + else + { + mGl.BlendEquation(GetBlendOp(colorBlendState.colorBlendOp)); + } + mGl.BlendColor(colorBlendState.blendConstants[0], + colorBlendState.blendConstants[1], + colorBlendState.blendConstants[2], + colorBlendState.blendConstants[3]); + } + else + { + mGl.Disable(GL_BLEND); + } + + auto* program = static_cast(pipeline->programState.program); + mGl.UseProgram(program->mImpl->mId); +} + /** * @brief Presents render target * @param renderTarget render target to present */ void TestGraphicsController::PresentRenderTarget(Graphics::RenderTarget* renderTarget) { + auto* rt = static_cast(renderTarget); TraceCallStack::NamedParams namedParams; namedParams["renderTarget"] << std::hex << renderTarget; - mCallStack.PushCall("PresentRenderTarget", "", namedParams); + namedParams["surface"] << std::hex << rt->mCreateInfo.surface; + mCallStack.PushCall("PresentRenderTarget", namedParams.str(), namedParams); } /** @@ -713,6 +1152,15 @@ void TestGraphicsController::UpdateTextures(const std::vector(&texture); + mGl.BindTexture(gfxTexture->GetTarget(), 0); + mGl.GenerateMipmap(gfxTexture->GetTarget()); +} + bool TestGraphicsController::EnableDepthStencilBuffer(bool enableDepth, bool enableStencil) { TraceCallStack::NamedParams namedParams; @@ -753,10 +1201,25 @@ bool TestGraphicsController::IsDrawOnResumeRequired() Graphics::UniquePtr TestGraphicsController::CreateBuffer(const Graphics::BufferCreateInfo& createInfo, Graphics::UniquePtr&& oldBuffer) { - std::ostringstream oss; - oss << "bufferCreateInfo:" << createInfo; - mCallStack.PushCall("CreateBuffer", oss.str()); - return Graphics::MakeUnique(mCallStack, mGl, createInfo.size, createInfo.usage); + TraceCallStack::NamedParams namedParams; + namedParams["usage"] << "0x" << std::hex << createInfo.usage; + namedParams["propertiesFlags"] << createInfo.propertiesFlags; + namedParams["size"] << createInfo.size; + mCallStack.PushCall("CreateBuffer", namedParams.str(), namedParams); + + auto ptr = Graphics::MakeUnique>(createInfo, *this, mGl, mCallStack); + mAllocatedBuffers.push_back(ptr.get()); + return ptr; +} + +void TestGraphicsController::DiscardBuffer(TestGraphicsBuffer* buffer) +{ + auto iter = std::find(mAllocatedBuffers.begin(), mAllocatedBuffers.end(), buffer); + if(iter != mAllocatedBuffers.end()) + { + mAllocatedBuffers.erase(iter); + } + delete buffer; } Graphics::UniquePtr TestGraphicsController::CreateCommandBuffer(const Graphics::CommandBufferCreateInfo& commandBufferCreateInfo, Graphics::UniquePtr&& oldCommandBuffer) @@ -770,7 +1233,7 @@ Graphics::UniquePtr TestGraphicsController::CreateComma Graphics::UniquePtr TestGraphicsController::CreateRenderPass(const Graphics::RenderPassCreateInfo& renderPassCreateInfo, Graphics::UniquePtr&& oldRenderPass) { mCallStack.PushCall("CreateRenderPass", ""); - return nullptr; + return Graphics::MakeUnique(mGl, renderPassCreateInfo); } Graphics::UniquePtr TestGraphicsController::CreateTexture(const Graphics::TextureCreateInfo& textureCreateInfo, Graphics::UniquePtr&& oldTexture) @@ -782,10 +1245,15 @@ Graphics::UniquePtr TestGraphicsController::CreateTexture(con return Graphics::MakeUnique(mGl, textureCreateInfo); } -Graphics::UniquePtr TestGraphicsController::CreateFramebuffer(const Graphics::FramebufferCreateInfo& framebufferCreateInfo, Graphics::UniquePtr&& oldFramebuffer) +Graphics::UniquePtr TestGraphicsController::CreateFramebuffer( + const Graphics::FramebufferCreateInfo& createInfo, + Graphics::UniquePtr&& oldFramebuffer) { - mCallStack.PushCall("CreateFramebuffer", ""); - return nullptr; + TraceCallStack::NamedParams namedParams; + namedParams["framebufferCreateInfo"] << createInfo; + mCallStack.PushCall("Controller::CreateFramebuffer", namedParams.str(), namedParams); + + return Graphics::MakeUnique(mFrameBufferCallStack, mGl, createInfo); } Graphics::UniquePtr TestGraphicsController::CreatePipeline(const Graphics::PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr&& oldPipeline) @@ -808,7 +1276,7 @@ Graphics::UniquePtr TestGraphicsController::CreateProgram(con source.resize(graphicsShader->mCreateInfo.sourceSize); memcpy(&source[0], graphicsShader->mCreateInfo.sourceData, graphicsShader->mCreateInfo.sourceSize); - if(!std::equal(source.begin(), source.end(), cacheEntry.shaders[shader.pipelineStage].begin())) + if(!std::equal(source.begin(), source.end(), cacheEntry.shaders[shader.pipelineStage].begin(), cacheEntry.shaders[shader.pipelineStage].end())) { found = false; break; @@ -821,7 +1289,8 @@ Graphics::UniquePtr TestGraphicsController::CreateProgram(con } mProgramCache.emplace_back(); - mProgramCache.back().programImpl = new TestGraphicsProgramImpl(mGl, programCreateInfo, mVertexFormats, mCustomUniforms); + mProgramCache.back().programImpl = new TestGraphicsProgramImpl(*this, mGl, programCreateInfo, mVertexFormats, mCustomUniforms, mCustomUniformBlocks); + for(auto& shader : *(programCreateInfo.shaderState)) { auto graphicsShader = Uncast(shader.shader); @@ -848,8 +1317,19 @@ Graphics::UniquePtr TestGraphicsController::CreateSampler(con Graphics::UniquePtr TestGraphicsController::CreateRenderTarget(const Graphics::RenderTargetCreateInfo& renderTargetCreateInfo, Graphics::UniquePtr&& oldRenderTarget) { - mCallStack.PushCall("CreateRenderTarget", ""); - return nullptr; + TraceCallStack::NamedParams namedParams; + namedParams["surface"] << std::hex << renderTargetCreateInfo.surface; + mCallStack.PushCall("CreateRenderTarget", namedParams.str(), namedParams); + + return Graphics::MakeUnique(mGl, renderTargetCreateInfo); +} + +Graphics::UniquePtr TestGraphicsController::CreateSyncObject( + const Graphics::SyncObjectCreateInfo& syncObjectCreateInfo, + Graphics::UniquePtr&& oldSyncObject) +{ + mCallStack.PushCall("CreateSyncObject", ""); + return Graphics::MakeUnique(mGraphicsSyncImpl, syncObjectCreateInfo); } Graphics::UniquePtr TestGraphicsController::MapBufferRange(const Graphics::MapBufferInfo& mapInfo) @@ -881,11 +1361,27 @@ Graphics::MemoryRequirements TestGraphicsController::GetTextureMemoryRequirement Graphics::MemoryRequirements TestGraphicsController::GetBufferMemoryRequirements(Graphics::Buffer& buffer) const { + static GLint uniformAlign{0}; + + Graphics::MemoryRequirements reqs{}; mCallStack.PushCall("GetBufferMemoryRequirements", ""); - return Graphics::MemoryRequirements{}; + + auto gfxBuffer = Uncast(&buffer); + if(gfxBuffer->mCreateInfo.usage & (0 | Graphics::BufferUsage::UNIFORM_BUFFER)) + { + if(!uniformAlign) + { + // Throw off the shackles of constness + auto& gl = *const_cast(&mGl); + gl.GetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniformAlign); + } + reqs.size = gfxBuffer->mCreateInfo.size; + reqs.alignment = uint32_t(uniformAlign); + } + return reqs; } -const Graphics::TextureProperties& TestGraphicsController::GetTextureProperties(const Graphics::Texture& texture) +Graphics::TextureProperties TestGraphicsController::GetTextureProperties(const Graphics::Texture& texture) { static Graphics::TextureProperties textureProperties{}; mCallStack.PushCall("GetTextureProperties", ""); @@ -913,4 +1409,71 @@ bool TestGraphicsController::GetProgramParameter(Graphics::Program& program, uin return graphicsProgram->GetParameter(parameterId, outData); } +Graphics::Texture* TestGraphicsController::CreateTextureByResourceId(uint32_t resourceId, const Graphics::TextureCreateInfo& createInfo) +{ + Graphics::Texture* ret = nullptr; + Graphics::UniquePtr texture; + TraceCallStack::NamedParams namedParams; + namedParams["resourceId"] << resourceId; + + auto iter = mTextureUploadBindMapper.find(resourceId); + DALI_ASSERT_ALWAYS(iter == mTextureUploadBindMapper.end()); + + // Create new graphics texture. + texture = CreateTexture(createInfo, std::move(texture)); + ret = texture.get(); + + mTextureUploadBindMapper.insert(std::make_pair(resourceId, std::move(texture))); + + mCallStack.PushCall("CreateTextureByResourceId", "", namedParams); + return ret; +} + +void TestGraphicsController::DiscardTextureFromResourceId(uint32_t resourceId) +{ + TraceCallStack::NamedParams namedParams; + namedParams["resourceId"] << resourceId; + + mTextureUploadBindMapper.erase(resourceId); + + mCallStack.PushCall("DiscardTextureFromResourceId", "", namedParams); +} + +Graphics::Texture* TestGraphicsController::GetTextureFromResourceId(uint32_t resourceId) +{ + TraceCallStack::NamedParams namedParams; + namedParams["resourceId"] << resourceId; + + Graphics::Texture* ret = nullptr; + + auto iter = mTextureUploadBindMapper.find(resourceId); + if(iter != mTextureUploadBindMapper.end()) + { + ret = iter->second.get(); + } + + mCallStack.PushCall("GetTextureFromResourceId", "", namedParams); + + return ret; +} + +Graphics::UniquePtr TestGraphicsController::ReleaseTextureFromResourceId(uint32_t resourceId) +{ + TraceCallStack::NamedParams namedParams; + namedParams["resourceId"] << resourceId; + + Graphics::UniquePtr texture; + + auto iter = mTextureUploadBindMapper.find(resourceId); + if(iter != mTextureUploadBindMapper.end()) + { + texture = std::move(iter->second); + mTextureUploadBindMapper.erase(iter); + } + + mCallStack.PushCall("ReleaseTextureFromResourceId", "", namedParams); + + return texture; +} + } // namespace Dali