/*
- * 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.
#include "test-graphics-controller.h"
+#include <dali/graphics-api/graphics-types.h>
#include "test-graphics-buffer.h"
#include "test-graphics-command-buffer.h"
#include "test-graphics-framebuffer.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 <dali/integration-api/gl-defines.h>
+#include <any>
#include <cstdio>
#include <iostream>
+#include <memory>
#include <sstream>
namespace Dali
{
+namespace
+{
+template<class T>
+struct TestGraphicsDeleter
+{
+ TestGraphicsDeleter() = default;
+ void operator()(T* object)
+ {
+ // Discard resource
+ object->DiscardResource();
+ }
+};
+
+} //namespace
+
std::ostream& operator<<(std::ostream& o, const Graphics::BufferCreateInfo& bufferCreateInfo)
{
return o << "usage:" << std::hex << bufferCreateInfo.usage << ", size:" << std::dec << bufferCreateInfo.size;
<< " 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;
}
return o;
}
-
int GetNumComponents(Graphics::VertexInputFormat vertexFormat)
{
switch(vertexFormat)
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
{
};
TestGraphicsController::TestGraphicsController()
-: mCallStack(true, "TestGraphicsController."),
- mCommandBufferCallStack(true, "TestCommandBuffer."),
- mFrameBufferCallStack(true, "TestFrameBuffer.")
+: mCallStack(false, "TestGraphicsController."),
+ mCommandBufferCallStack(false, "TestCommandBuffer."),
+ mFrameBufferCallStack(false, "TestFrameBuffer.")
{
mCallStack.Enable(true);
mCommandBufferCallStack.Enable(true);
auto& trace = mGl.GetTextureTrace();
trace.Enable(true);
- trace.EnableLogging(true);
+ trace.EnableLogging(false);
}
-
void TestGraphicsController::SubmitCommandBuffers(const Graphics::SubmitInfo& submitInfo)
{
TraceCallStack::NamedParams namedParams;
}
case CommandType::BIND_UNIFORM_BUFFER:
{
- auto& bindings = cmd.data.bindUniformBuffers;
- auto buffer = bindings.standaloneUniformsBufferBinding;
+ if(currentPipeline)
+ {
+ auto& bindings = cmd.data.bindUniformBuffers;
+ auto buffer = bindings.standaloneUniformsBufferBinding;
- // based on reflection, issue gl calls
- buffer.buffer->BindAsUniformBuffer(static_cast<const TestGraphicsProgram*>(currentPipeline->programState.program));
+ // based on reflection, issue gl calls
+ buffer.buffer->BindAsUniformBuffer(static_cast<const TestGraphicsProgram*>(currentPipeline->programState.program), bindings.standaloneUniformsBufferBinding);
+ }
break;
}
case CommandType::BIND_SAMPLERS:
case CommandType::BIND_PIPELINE:
{
currentPipeline = Uncast<TestGraphicsPipeline>(cmd.data.bindPipeline.pipeline);
+ BindPipeline(currentPipeline);
+ break;
+ }
+ case CommandType::DRAW_NATIVE:
+ {
+ auto info = &cmd.data.draw.drawNative.drawNativeInfo;
- // Bind framebuffer if different. @todo Move to RenderPass
- auto framebuffer = currentPipeline->framebufferState.framebuffer;
- if(framebuffer && framebuffer != currentFramebuffer)
+ if(info->glesNativeInfo.eglSharedContextStoragePointer)
{
- auto graphicsFramebuffer = Uncast<TestGraphicsFramebuffer>(framebuffer);
- graphicsFramebuffer->Bind();
+ auto* anyContext = reinterpret_cast<std::any*>(info->glesNativeInfo.eglSharedContextStoragePointer);
+ *anyContext = reinterpret_cast<void*>(0x12345678u);
}
- else
- {
- if(currentFramebuffer)
- currentFramebuffer->Bind();
- else
- mGl.BindFramebuffer(GL_FRAMEBUFFER, 0);
- }
- BindPipeline(currentPipeline);
+
+ CallbackBase::ExecuteReturn<bool>(*info->callback, info->userData);
break;
}
case CommandType::DRAW:
{
- mGl.DrawArrays(GetTopology(currentPipeline->inputAssemblyState.topology),
- 0,
- cmd.data.draw.draw.vertexCount);
+ 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.DrawElements(GetTopology(currentPipeline->inputAssemblyState.topology),
- static_cast<GLsizei>(cmd.data.draw.drawIndexed.indexCount),
- GL_UNSIGNED_SHORT,
- reinterpret_cast<void*>(cmd.data.draw.drawIndexed.firstIndex));
+ if(currentPipeline)
+ {
+ if(cmd.data.draw.draw.instanceCount == 0)
+ {
+ mGl.DrawElements(GetTopology(currentPipeline->inputAssemblyState.topology),
+ static_cast<GLsizei>(cmd.data.draw.drawIndexed.indexCount),
+ GL_UNSIGNED_SHORT,
+ reinterpret_cast<void*>(cmd.data.draw.drawIndexed.firstIndex));
+ }
+ else
+ {
+ mGl.DrawElementsInstanced(GetTopology(currentPipeline->inputAssemblyState.topology),
+ static_cast<GLsizei>(cmd.data.draw.drawIndexed.indexCount),
+ GL_UNSIGNED_SHORT,
+ reinterpret_cast<void*>(cmd.data.draw.drawIndexed.firstIndex),
+ cmd.data.draw.drawIndexed.instanceCount);
+ }
+ }
break;
}
case CommandType::DRAW_INDEXED_INDIRECT:
{
- mGl.DrawElements(GetTopology(currentPipeline->inputAssemblyState.topology),
- static_cast<GLsizei>(cmd.data.draw.drawIndexed.indexCount),
- GL_UNSIGNED_SHORT,
- reinterpret_cast<void*>(cmd.data.draw.drawIndexed.firstIndex));
+ if(currentPipeline)
+ {
+ mGl.DrawElements(GetTopology(currentPipeline->inputAssemblyState.topology),
+ static_cast<GLsizei>(cmd.data.draw.drawIndexed.indexCount),
+ GL_UNSIGNED_SHORT,
+ reinterpret_cast<void*>(cmd.data.draw.drawIndexed.firstIndex));
+ }
break;
}
case CommandType::SET_SCISSOR:
mGl.Viewport(rect.x, rect.y, rect.width, rect.height);
break;
}
+
+ 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;
+ }
+
+ case CommandType::SET_STENCIL_TEST_ENABLE:
+ {
+ if(cmd.data.stencilTest.enabled)
+ {
+ mGl.Enable(GL_STENCIL_TEST);
+ }
+ else
+ {
+ mGl.Disable(GL_STENCIL_TEST);
+ }
+ break;
+ }
+
+ case CommandType::SET_STENCIL_FUNC:
+ {
+ mGl.StencilFunc(GLCompareOp(cmd.data.stencilFunc.compareOp).op,
+ cmd.data.stencilFunc.reference,
+ cmd.data.stencilFunc.compareMask);
+ break;
+ }
+
+ case CommandType::SET_STENCIL_WRITE_MASK:
+ {
+ mGl.StencilMask(cmd.data.stencilWriteMask.mask);
+ break;
+ }
+ case CommandType::SET_STENCIL_OP:
+ {
+ mGl.StencilOp(GLStencilOp(cmd.data.stencilOp.failOp).op,
+ GLStencilOp(cmd.data.stencilOp.depthFailOp).op,
+ GLStencilOp(cmd.data.stencilOp.passOp).op);
+ break;
+ }
+
+ case CommandType::SET_DEPTH_COMPARE_OP:
+ {
+ mGl.DepthFunc(GLCompareOp(cmd.data.depth.compareOp).op);
+ break;
+ }
+ case CommandType::SET_DEPTH_TEST_ENABLE:
+ {
+ if(cmd.data.depth.testEnabled)
+ {
+ mGl.Enable(GL_DEPTH_TEST);
+ }
+ else
+ {
+ mGl.Disable(GL_DEPTH_TEST);
+ }
+ break;
+ }
+ case CommandType::SET_DEPTH_WRITE_ENABLE:
+ {
+ mGl.DepthMask(cmd.data.depth.writeEnabled);
+ break;
+ }
+
case CommandType::EXECUTE_COMMAND_BUFFERS:
{
// Process secondary command buffers
for(auto& buf : cmd.data.executeCommandBuffers.buffers)
{
- ProcessCommandBuffer(*static_cast<TestGraphicsCommandBuffer*>(buf));
+ ProcessCommandBuffer(*Uncast<TestGraphicsCommandBuffer>(buf));
}
break;
}
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;
}
}
{
// Test scissor area and RT size
const auto& area = cmd.data.beginRenderPass.renderArea;
- if( area.x == 0 &&
- area.y == 0 &&
- area.width == renderTarget->mCreateInfo.extent.width &&
- area.height == renderTarget->mCreateInfo.extent.height )
+ 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.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);
}
}
case CommandType::END_RENDER_PASS:
{
+ if(cmd.data.endRenderPass.syncObject != nullptr)
+ {
+ auto syncObject = Uncast<TestGraphicsSyncObject>(cmd.data.endRenderPass.syncObject);
+ syncObject->InitializeResource(); // create the sync object.
+ }
break;
}
}
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<void*>(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
{
mGl.Disable(GL_BLEND);
}
+
+ auto* program = static_cast<const TestGraphicsProgram*>(pipeline->programState.program);
+ mGl.UseProgram(program->mImpl->mId);
}
/**
*/
void TestGraphicsController::PresentRenderTarget(Graphics::RenderTarget* renderTarget)
{
+ auto* rt = static_cast<const TestGraphicsRenderTarget*>(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);
}
/**
}
}
+void TestGraphicsController::GenerateTextureMipmaps(const Graphics::Texture& texture)
+{
+ mCallStack.PushCall("GenerateTextureMipmaps", "");
+
+ auto gfxTexture = Uncast<TestGraphicsTexture>(&texture);
+ mGl.BindTexture(gfxTexture->GetTarget(), 0);
+ mGl.GenerateMipmap(gfxTexture->GetTarget());
+}
+
bool TestGraphicsController::EnableDepthStencilBuffer(bool enableDepth, bool enableStencil)
{
TraceCallStack::NamedParams namedParams;
Graphics::UniquePtr<Graphics::Buffer> TestGraphicsController::CreateBuffer(const Graphics::BufferCreateInfo& createInfo, Graphics::UniquePtr<Graphics::Buffer>&& oldBuffer)
{
- std::ostringstream oss;
- oss << "bufferCreateInfo:" << createInfo;
- mCallStack.PushCall("CreateBuffer", oss.str());
- return Graphics::MakeUnique<TestGraphicsBuffer>(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<TestGraphicsBuffer, TestGraphicsDeleter<TestGraphicsBuffer>>(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<Graphics::CommandBuffer> TestGraphicsController::CreateCommandBuffer(const Graphics::CommandBufferCreateInfo& commandBufferCreateInfo, Graphics::UniquePtr<Graphics::CommandBuffer>&& oldCommandBuffer)
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;
}
mProgramCache.emplace_back();
- mProgramCache.back().programImpl = new TestGraphicsProgramImpl(mGl, programCreateInfo, mVertexFormats, mCustomUniforms);
+ mProgramCache.back().programImpl = new TestGraphicsProgramImpl(mGl, programCreateInfo, mVertexFormats, mCustomUniforms, mCustomUniformBlocks);
+
for(auto& shader : *(programCreateInfo.shaderState))
{
auto graphicsShader = Uncast<TestGraphicsShader>(shader.shader);
Graphics::UniquePtr<Graphics::RenderTarget> TestGraphicsController::CreateRenderTarget(const Graphics::RenderTargetCreateInfo& renderTargetCreateInfo, Graphics::UniquePtr<Graphics::RenderTarget>&& oldRenderTarget)
{
- mCallStack.PushCall("CreateRenderTarget", "");
+ TraceCallStack::NamedParams namedParams;
+ namedParams["surface"] << std::hex << renderTargetCreateInfo.surface;
+ mCallStack.PushCall("CreateRenderTarget", namedParams.str(), namedParams);
+
return Graphics::MakeUnique<TestGraphicsRenderTarget>(mGl, renderTargetCreateInfo);
}
+Graphics::UniquePtr<Graphics::SyncObject> TestGraphicsController::CreateSyncObject(
+ const Graphics::SyncObjectCreateInfo& syncObjectCreateInfo,
+ Graphics::UniquePtr<Graphics::SyncObject>&& oldSyncObject)
+{
+ mCallStack.PushCall("CreateSyncObject", "");
+ return Graphics::MakeUnique<TestGraphicsSyncObject>(mGraphicsSyncImpl, syncObjectCreateInfo);
+}
+
Graphics::UniquePtr<Graphics::Memory> TestGraphicsController::MapBufferRange(const Graphics::MapBufferInfo& mapInfo)
{
mCallStack.PushCall("MapBufferRange", "");
Graphics::MemoryRequirements TestGraphicsController::GetBufferMemoryRequirements(Graphics::Buffer& buffer) const
{
+ static GLint uniformAlign{0};
+
+ Graphics::MemoryRequirements reqs{};
mCallStack.PushCall("GetBufferMemoryRequirements", "");
- return Graphics::MemoryRequirements{};
+
+ auto gfxBuffer = Uncast<TestGraphicsBuffer>(&buffer);
+ if(gfxBuffer->mCreateInfo.usage & (0 | Graphics::BufferUsage::UNIFORM_BUFFER))
+ {
+ if(!uniformAlign)
+ {
+ // Throw off the shackles of constness
+ auto& gl = *const_cast<TestGlAbstraction*>(&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", "");