void DumpCommandBuffer(FILE* output, const GLES::CommandBuffer* commandBuffer)
{
- bool first{true};
- for(auto& cmd : commandBuffer->GetCommands())
+ bool first{true};
+ uint32_t count = 0u;
+ const auto command = commandBuffer->GetCommands(count);
+ for(auto i = 0u; i < count; ++i)
{
+ auto& cmd = command[i];
if(!first)
{
fprintf(output, ",");
cmd.beginRenderPass.renderArea.height);
fprintf(output, "\"clearValues\":[");
bool firstV = true;
- for(auto& value : cmd.beginRenderPass.clearValues)
+ for(auto i = 0u; i < cmd.beginRenderPass.clearValuesCount; ++i)
{
+ auto value = cmd.beginRenderPass.clearValues.Ptr()[i];
if(!firstV)
{
fprintf(output, ",");
{
fprintf(output, "{\"Cmd\":\"EXECUTE_COMMAND_BUFFERS\",\n\"buffers\":[");
bool firstBuf{true};
- for(auto& buf : cmd.executeCommandBuffers.buffers)
+ for(auto i = 0u; i < cmd.executeCommandBuffers.buffersCount; ++i)
{
+ const auto buf = cmd.executeCommandBuffers.buffers.Ptr()[i];
if(!firstBuf)
{
fprintf(output, ", ");
}
firstBuf = false;
- DumpCommandBuffer(output, static_cast<const GLES::CommandBuffer*>(buf));
+ DumpCommandBuffer(output, buf);
}
fprintf(output, "]\n}");
break;
void EglGraphicsController::PresentRenderTarget(RenderTarget* renderTarget)
{
- // Use command buffer to execute presentation (we should pool it)
- CommandBufferCreateInfo info;
- info.SetLevel(CommandBufferLevel::PRIMARY);
- info.fixedCapacity = 1; // only one command
- auto presentCommandBuffer = new GLES::CommandBuffer(info, *this);
+ GLES::CommandBuffer* presentCommandBuffer{nullptr};
+ if(mPresentationCommandBuffers.empty())
+ {
+ CommandBufferCreateInfo info;
+ info.SetLevel(CommandBufferLevel::PRIMARY);
+ info.fixedCapacity = 1; // only one command
+ presentCommandBuffer = new GLES::CommandBuffer(info, *this);
+ }
+ else
+ {
+ presentCommandBuffer = const_cast<GLES::CommandBuffer*>(mPresentationCommandBuffers.front());
+ presentCommandBuffer->Reset();
+ mPresentationCommandBuffers.pop();
+ }
presentCommandBuffer->PresentRenderTarget(static_cast<GLES::RenderTarget*>(renderTarget));
SubmitInfo submitInfo;
submitInfo.cmdBuffer = {presentCommandBuffer};
void EglGraphicsController::ProcessCommandBuffer(const GLES::CommandBuffer& commandBuffer)
{
- for(auto& cmd : commandBuffer.GetCommands())
+ auto count = 0u;
+ const auto commands = commandBuffer.GetCommands(count);
+ for(auto i = 0u; i < count; ++i)
{
+ auto& cmd = commands[i];
// process command
switch(cmd.type)
{
}
case GLES::CommandType::BIND_TEXTURES:
{
- mCurrentContext->BindTextures(cmd.bindTextures.textureBindings);
+ mCurrentContext->BindTextures(cmd.bindTextures.textureBindings.Ptr(), cmd.bindTextures.textureBindingsCount);
break;
}
case GLES::CommandType::BIND_VERTEX_BUFFERS:
{
- auto& bindings = cmd.bindVertexBuffers.vertexBufferBindings;
- mCurrentContext->BindVertexBuffers(bindings);
+ auto bindings = cmd.bindVertexBuffers.vertexBufferBindings.Ptr();
+ mCurrentContext->BindVertexBuffers(bindings, cmd.bindVertexBuffers.vertexBufferBindingsCount);
break;
}
case GLES::CommandType::BIND_UNIFORM_BUFFER:
{
auto& bindings = cmd.bindUniformBuffers;
- mCurrentContext->BindUniformBuffers(bindings.uniformBufferBindings, bindings.standaloneUniformsBufferBinding);
+ mCurrentContext->BindUniformBuffers(bindings.uniformBufferBindingsCount ? bindings.uniformBufferBindings.Ptr() : nullptr, bindings.uniformBufferBindingsCount, bindings.standaloneUniformsBufferBinding);
break;
}
case GLES::CommandType::BIND_INDEX_BUFFER:
{
ResolvePresentRenderTarget(cmd.presentRenderTarget.targetToPresent);
- // push this command buffer to the discard queue
- mDiscardCommandBufferQueue.push(const_cast<GLES::CommandBuffer*>(&commandBuffer));
+ // The command buffer will be pushed into the queue of presentation command buffers
+ // for further reuse.
+ if(commandBuffer.GetCreateInfo().fixedCapacity == 1)
+ {
+ mPresentationCommandBuffers.push(&commandBuffer);
+ }
break;
}
case GLES::CommandType::EXECUTE_COMMAND_BUFFERS:
// todo: check validity of the secondaries
// there are operations which are illigal to be done
// within secondaries.
- for(auto& buf : cmd.executeCommandBuffers.buffers)
+ auto buffers = cmd.executeCommandBuffers.buffers.Ptr();
+ for(auto j = 0u; j < cmd.executeCommandBuffers.buffersCount; ++j)
{
+ auto& buf = buffers[j];
ProcessCommandBuffer(*static_cast<const GLES::CommandBuffer*>(buf));
}
break;
void EglGraphicsController::ProcessCommandQueues()
{
- // TODO: command queue per context, sync between queues should be
- // done externally
- currentFramebuffer = nullptr;
-
DUMP_FRAME_START();
while(!mCommandQueue.empty())
bool mIsShuttingDown{false}; ///< Indicates whether the controller is shutting down
- // todo: to be removed after renderpass
- const Graphics::Framebuffer* currentFramebuffer{nullptr};
+ std::queue<const GLES::CommandBuffer*> mPresentationCommandBuffers{}; ///< Queue of reusable command buffers used by presentation engine
};
} // namespace Graphics
}
}
-void Context::BindTextures(const std::vector<Graphics::TextureBinding>& bindings)
+void Context::BindTextures(const Graphics::TextureBinding* bindings, uint32_t count)
{
// for each texture allocate slot
- for(const auto& binding : bindings)
+ for(auto i = 0u; i < count; ++i)
{
+ auto& binding = bindings[i];
+
// Resize binding array if needed
if(mImpl->mCurrentTextureBindings.size() <= binding.binding)
{
}
}
-void Context::BindVertexBuffers(const std::vector<GLES::VertexBufferBindingDescriptor>& bindings)
+void Context::BindVertexBuffers(const GLES::VertexBufferBindingDescriptor* bindings, uint32_t count)
{
- if(bindings.size() > mImpl->mCurrentVertexBufferBindings.size())
+ if(count > mImpl->mCurrentVertexBufferBindings.size())
{
- mImpl->mCurrentVertexBufferBindings.resize(bindings.size());
+ mImpl->mCurrentVertexBufferBindings.resize(count);
}
// Copy only set slots
- std::copy_if(bindings.begin(), bindings.end(), mImpl->mCurrentVertexBufferBindings.begin(), [](auto& item) {
+ std::copy_if(bindings, bindings + count, mImpl->mCurrentVertexBufferBindings.begin(), [](auto& item) {
return (nullptr != item.buffer);
});
}
mImpl->mNewPipeline = &newPipeline->GetPipeline();
}
-void Context::BindUniformBuffers(const std::vector<UniformBufferBindingDescriptor>& uboBindings,
- const UniformBufferBindingDescriptor& standaloneBindings)
+void Context::BindUniformBuffers(const UniformBufferBindingDescriptor* uboBindings,
+ uint32_t uboCount,
+ const UniformBufferBindingDescriptor& standaloneBindings)
{
if(standaloneBindings.buffer)
{
mImpl->mCurrentStandaloneUBOBinding = standaloneBindings;
}
- if(uboBindings.size() >= mImpl->mCurrentUBOBindings.size())
+ if(uboCount >= mImpl->mCurrentUBOBindings.size())
{
- mImpl->mCurrentUBOBindings.resize(uboBindings.size() + 1);
+ mImpl->mCurrentUBOBindings.resize(uboCount + 1);
}
- auto it = uboBindings.begin();
- for(auto i = 0u; i < uboBindings.size(); ++i)
+ auto it = uboBindings;
+ for(auto i = 0u; i < uboCount; ++i)
{
if(it->buffer)
{
// Something goes wrong here if Alpha mask is GL_TRUE
ColorMask(true);
+ const auto clearValues = renderPassBegin.clearValues.Ptr();
+
if(!mImpl->mGlStateCache.mClearColorSet ||
- mImpl->mGlStateCache.mClearColor.r != renderPassBegin.clearValues[0].color.r ||
- mImpl->mGlStateCache.mClearColor.g != renderPassBegin.clearValues[0].color.g ||
- mImpl->mGlStateCache.mClearColor.b != renderPassBegin.clearValues[0].color.b ||
- mImpl->mGlStateCache.mClearColor.a != renderPassBegin.clearValues[0].color.a)
+ mImpl->mGlStateCache.mClearColor.r != clearValues[0].color.r ||
+ mImpl->mGlStateCache.mClearColor.g != clearValues[0].color.g ||
+ mImpl->mGlStateCache.mClearColor.b != clearValues[0].color.b ||
+ mImpl->mGlStateCache.mClearColor.a != clearValues[0].color.a)
{
- gl.ClearColor(renderPassBegin.clearValues[0].color.r,
- renderPassBegin.clearValues[0].color.g,
- renderPassBegin.clearValues[0].color.b,
- renderPassBegin.clearValues[0].color.a);
+ gl.ClearColor(clearValues[0].color.r,
+ clearValues[0].color.g,
+ clearValues[0].color.b,
+ clearValues[0].color.a);
mImpl->mGlStateCache.mClearColorSet = true;
- mImpl->mGlStateCache.mClearColor = Vector4(renderPassBegin.clearValues[0].color.r,
- renderPassBegin.clearValues[0].color.g,
- renderPassBegin.clearValues[0].color.b,
- renderPassBegin.clearValues[0].color.a);
+ mImpl->mGlStateCache.mClearColor = Vector4(clearValues[0].color.r,
+ clearValues[0].color.g,
+ clearValues[0].color.b,
+ clearValues[0].color.a);
}
}
* @param[in] bindings List of bindings
*
*/
- void BindTextures(const std::vector<Graphics::TextureBinding>& bindings);
+ void BindTextures(const Graphics::TextureBinding* bindings, uint32_t count);
/**
* @brief Vertex buffers to bind
* currently processed and copied into the local storage.
*/
- void BindVertexBuffers(const std::vector<GLES::VertexBufferBindingDescriptor>& bindings);
+ void BindVertexBuffers(const GLES::VertexBufferBindingDescriptor* bindings, uint32_t count);
/**
* @brief Binds index buffer
* @param[in] uboBindings real UBO binfins
* @param[in] standaloneBindings emulated (legacy) UBO object
*/
- void BindUniformBuffers(const std::vector<UniformBufferBindingDescriptor>& uboBindings, const UniformBufferBindingDescriptor& standaloneBindings);
+ void BindUniformBuffers(const UniformBufferBindingDescriptor* uboBindings, uint32_t uboCount, const UniformBufferBindingDescriptor& standaloneBindings);
/**
* @brief Resolves blend state on the currently attached pipeline
namespace Dali::Graphics::GLES
{
+class CommandPool
+{
+ static const uint32_t COMMAND_POOL_DEFAULT_INCREMENT = 1024 * 32; // 32kb banks
+ static const uint32_t MEMORY_POOL_DEFAULT_INCREMENT = 1024; // 4kb memory pool increment
+ static const uint32_t MEMORY_POOL_DEFAULT_ALIGNMENT = 64; // 64bytes alignment
+
+ template<class T>
+ struct Block
+ {
+ Block() = default;
+ ~Block()
+ {
+ if(ptr)
+ {
+ free(ptr);
+ }
+ }
+
+ T* ptr{nullptr};
+ uint32_t dataSize{0u};
+ uint32_t capacity{0u};
+ inline T& operator[](int index) const
+ {
+ return ptr[index];
+ }
+
+ inline void clear()
+ {
+ free(ptr);
+ capacity = 0;
+ dataSize = 0;
+ }
+
+ inline void resize(int newSize)
+ {
+ ptr = reinterpret_cast<T*>(realloc(ptr, newSize * sizeof(T)));
+ capacity = newSize;
+ dataSize = newSize;
+ }
+
+ inline T* data() const
+ {
+ return ptr;
+ }
+
+ inline uint32_t size() const
+ {
+ return dataSize;
+ }
+ };
+ // This memory pool guarantees all items will be placed
+ // in the continuous memory area but returned pointers are relative
+ // and require translation before using
+ template<class T, int Increment, int Alignment = 0>
+ struct MemoryPool
+ {
+ Block<T> data;
+ inline T& operator[](int index)
+ {
+ return data[index];
+ }
+ MemoryPool() = default;
+
+ IndirectPtr<T> Allocate(uint32_t count)
+ {
+ // set fixed capacity
+ if(fixedCapacity && data.size() != fixedCapacity)
+ {
+ data.resize(fixedCapacity);
+ totalCapacity = data.size();
+ }
+
+ // or resize dynamically
+ else if(data.size() <= offset + count)
+ {
+ data.resize(data.size() + Increment);
+
+ // update base pointer, required for address translation
+ totalCapacity = data.size();
+ }
+
+ basePtr = data.data();
+
+ IndirectPtr<T> retval{uint32_t(uintptr_t(&data[offset]) - uintptr_t(basePtr)), &basePtr};
+ size += count;
+ offset += count;
+
+ // align offset if needed (only if type size is 1)
+ if(Alignment && sizeof(T) == 1)
+ {
+ offset = ((offset / Alignment) * Alignment) + ((offset % Alignment) ? Alignment : 0);
+ }
+ return retval;
+ }
+
+ // Rolls back pool
+ void Rollback()
+ {
+ offset = 0;
+ size = 0;
+ }
+
+ // Discards all data and storage
+ void Clear()
+ {
+ data.clear();
+ totalCapacity = 0;
+ offset = 0;
+ size = 0;
+ }
+
+ uint32_t offset{0u};
+ uint32_t totalCapacity{0u};
+ uint32_t size{0u};
+ uint32_t increment{Increment};
+ uint32_t alignment{Alignment};
+ uint32_t fixedCapacity{0u};
+ void* basePtr{nullptr};
+ };
+
+ MemoryPool<uint8_t, MEMORY_POOL_DEFAULT_INCREMENT, MEMORY_POOL_DEFAULT_ALIGNMENT> memoryPool;
+ MemoryPool<Command, COMMAND_POOL_DEFAULT_INCREMENT, MEMORY_POOL_DEFAULT_ALIGNMENT> commandPool;
+
+public:
+ CommandPool() = default;
+ CommandPool(uint32_t fixedCapacity)
+ {
+ commandPool.fixedCapacity = fixedCapacity;
+ memoryPool.fixedCapacity = fixedCapacity * 1024;
+ }
+
+ /**
+ * Return value may become invalid if pool is resized (by allocating another command)
+ * @param type
+ * @return
+ */
+ Command* AllocateCommand(CommandType type)
+ {
+ auto command = commandPool.Allocate(1);
+ command->type = type;
+ auto* cmd = command.Ptr();
+ return cmd;
+ }
+
+ template<class T>
+ IndirectPtr<T> Allocate(uint32_t count)
+ {
+ const auto typeSize = sizeof(T);
+ const auto memoryRequired = typeSize * count;
+ auto ptr = memoryPool.Allocate(memoryRequired);
+
+ // Convert generic pointer and return
+ return IndirectPtr<T>{ptr.ptr, ptr.base};
+ }
+
+ // New (should not be needed)
+ template<class T>
+ T* New(uint32_t count)
+ {
+ auto ptr = Allocate<T>(count);
+ for(auto i = 0u; i < count; ++i)
+ {
+ new(&ptr[i]) T();
+ }
+ return ptr;
+ }
+
+ // TODO: explicit delete?
+ void Rollback(bool discard)
+ {
+ if(discard)
+ {
+ commandPool.Clear();
+ memoryPool.Clear();
+ }
+ else
+ {
+ commandPool.Rollback();
+ memoryPool.Rollback();
+ }
+ }
+
+ const Command* GetCommands(uint32_t& size) const
+ {
+ size = commandPool.size;
+ return commandPool.data.ptr;
+ }
+};
+
CommandBuffer::CommandBuffer(const Graphics::CommandBufferCreateInfo& createInfo, EglGraphicsController& controller)
: CommandBufferResource(createInfo, controller)
{
+ mCommandPool = std::make_unique<CommandPool>(createInfo.fixedCapacity);
}
CommandBuffer::~CommandBuffer() = default;
std::vector<const Graphics::Buffer*> buffers,
std::vector<uint32_t> offsets)
{
- mCommands.emplace_back(CommandType::BIND_VERTEX_BUFFERS);
- auto& bindings = mCommands.back().bindVertexBuffers.vertexBufferBindings;
- if(bindings.size() < firstBinding + buffers.size())
+ auto command = mCommandPool->AllocateCommand(CommandType::BIND_VERTEX_BUFFERS);
+ command->bindVertexBuffers.vertexBufferBindingsCount = firstBinding + buffers.size();
+ auto pBindings = mCommandPool->Allocate<GLES::VertexBufferBindingDescriptor>(firstBinding + buffers.size());
+
+ command->bindVertexBuffers.vertexBufferBindings = pBindings;
+ auto index = firstBinding;
+ for(auto& buf : buffers)
{
- bindings.resize(firstBinding + buffers.size());
- auto index = firstBinding;
- for(auto& buf : buffers)
- {
- bindings[index].buffer = static_cast<const GLES::Buffer*>(buf);
- bindings[index].offset = offsets[index - firstBinding];
- index++;
- }
+ pBindings[index].buffer = static_cast<const GLES::Buffer*>(buf);
+ pBindings[index].offset = offsets[index - firstBinding];
+ index++;
}
}
void CommandBuffer::BindUniformBuffers(const std::vector<Graphics::UniformBufferBinding>& bindings)
{
- mCommands.emplace_back(CommandType::BIND_UNIFORM_BUFFER);
- auto& cmd = mCommands.back();
+ auto command = mCommandPool->AllocateCommand(CommandType::BIND_UNIFORM_BUFFER);
+
+ auto& cmd = *command;
auto& bindCmd = cmd.bindUniformBuffers;
+
+ // temporary static set of binding slots (thread local)
+ static const auto MAX_UNIFORM_BUFFER_BINDINGS = 64; // TODO: this should be read from introspection
+
+ // TODO: could use vector?
+ static thread_local UniformBufferBindingDescriptor sTempBindings[MAX_UNIFORM_BUFFER_BINDINGS];
+
+ // reset temp bindings
+ memset(sTempBindings, 0, sizeof(UniformBufferBindingDescriptor) * MAX_UNIFORM_BUFFER_BINDINGS);
+
+ auto maxBinding = 0u;
+
+ // find max binding and standalone UBO
for(const auto& binding : bindings)
{
if(binding.buffer)
}
else // Bind regular UBO
{
- // resize binding slots
- if(binding.binding >= bindCmd.uniformBufferBindings.size())
- {
- bindCmd.uniformBufferBindings.resize(binding.binding + 1);
- }
- auto& slot = bindCmd.uniformBufferBindings[binding.binding];
+ auto& slot = sTempBindings[binding.binding];
slot.buffer = glesBuffer;
slot.offset = binding.offset;
slot.binding = binding.binding;
slot.emulated = false;
+ maxBinding = std::max(maxBinding, binding.binding);
}
}
}
+ bindCmd.uniformBufferBindings = nullptr;
+ bindCmd.uniformBufferBindingsCount = 0u;
+
+ // copy data
+ if(maxBinding)
+ {
+ auto destBindings = mCommandPool->Allocate<UniformBufferBindingDescriptor>(maxBinding + 1);
+ // copy
+ memcpy(destBindings.Ptr(), sTempBindings, sizeof(UniformBufferBindingDescriptor) * (maxBinding + 1));
+ bindCmd.uniformBufferBindings = destBindings;
+ bindCmd.uniformBufferBindingsCount = maxBinding + 1;
+ }
}
void CommandBuffer::BindPipeline(const Graphics::Pipeline& pipeline)
{
- mCommands.emplace_back(CommandType::BIND_PIPELINE);
- mCommands.back().bindPipeline.pipeline = static_cast<const GLES::Pipeline*>(&pipeline);
+ auto command = mCommandPool->AllocateCommand(CommandType::BIND_PIPELINE);
+ command->bindPipeline.pipeline = static_cast<const GLES::Pipeline*>(&pipeline);
}
void CommandBuffer::BindTextures(std::vector<TextureBinding>& textureBindings)
{
- mCommands.emplace_back(CommandType::BIND_TEXTURES);
- mCommands.back().bindTextures.textureBindings = std::move(textureBindings);
+ auto command = mCommandPool->AllocateCommand(CommandType::BIND_TEXTURES);
+ auto& bindTexturesCmd = command->bindTextures;
+ bindTexturesCmd.textureBindings = mCommandPool->Allocate<TextureBinding>(textureBindings.size());
+ bindTexturesCmd.textureBindingsCount = textureBindings.size();
+ memcpy(bindTexturesCmd.textureBindings.Ptr(), textureBindings.data(), sizeof(TextureBinding) * textureBindings.size());
}
void CommandBuffer::BindSamplers(std::vector<SamplerBinding>& samplerBindings)
{
- mCommands.emplace_back(CommandType::BIND_SAMPLERS);
- mCommands.back().bindSamplers.samplerBindings = std::move(samplerBindings);
+ auto command = mCommandPool->AllocateCommand(CommandType::BIND_SAMPLERS);
+ auto& bindSamplersCmd = command->bindSamplers;
+ bindSamplersCmd.samplerBindings = mCommandPool->Allocate<SamplerBinding>(samplerBindings.size());
+ bindSamplersCmd.samplerBindingsCount = samplerBindings.size();
+ memcpy(bindSamplersCmd.samplerBindings.Ptr(), samplerBindings.data(), sizeof(TextureBinding) * samplerBindings.size());
}
void CommandBuffer::BindPushConstants(void* data,
uint32_t offset,
Format format)
{
- mCommands.emplace_back(CommandType::BIND_INDEX_BUFFER);
- mCommands.back().bindIndexBuffer.buffer = static_cast<const GLES::Buffer*>(&buffer);
- mCommands.back().bindIndexBuffer.offset = offset;
- mCommands.back().bindIndexBuffer.format = format;
+ auto command = mCommandPool->AllocateCommand(CommandType::BIND_INDEX_BUFFER);
+ command->bindIndexBuffer.buffer = static_cast<const GLES::Buffer*>(&buffer);
+ command->bindIndexBuffer.offset = offset;
+ command->bindIndexBuffer.format = format;
}
void CommandBuffer::BeginRenderPass(
Rect2D renderArea,
std::vector<ClearValue> clearValues)
{
- mCommands.emplace_back(CommandType::BEGIN_RENDERPASS);
- auto& cmd = mCommands.back();
+ auto command = mCommandPool->AllocateCommand(CommandType::BEGIN_RENDERPASS);
+ auto& cmd = *command;
cmd.beginRenderPass.renderPass = static_cast<GLES::RenderPass*>(renderPass);
cmd.beginRenderPass.renderTarget = static_cast<GLES::RenderTarget*>(renderTarget);
cmd.beginRenderPass.renderArea = renderArea;
- cmd.beginRenderPass.clearValues = clearValues;
+
+ cmd.beginRenderPass.clearValues = mCommandPool->Allocate<ClearValue>(clearValues.size());
+ memcpy(cmd.beginRenderPass.clearValues.Ptr(), clearValues.data(), sizeof(ClearValue) * clearValues.size());
+ cmd.beginRenderPass.clearValuesCount = clearValues.size();
}
void CommandBuffer::EndRenderPass(Graphics::SyncObject* syncObject)
{
- mCommands.emplace_back(CommandType::END_RENDERPASS);
- auto& cmd = mCommands.back();
-
- cmd.endRenderPass.syncObject = static_cast<GLES::SyncObject*>(syncObject);
+ auto command = mCommandPool->AllocateCommand(CommandType::END_RENDERPASS);
+ command->endRenderPass.syncObject = static_cast<GLES::SyncObject*>(syncObject);
}
void CommandBuffer::ExecuteCommandBuffers(std::vector<const Graphics::CommandBuffer*>&& commandBuffers)
{
- mCommands.emplace_back(CommandType::EXECUTE_COMMAND_BUFFERS);
- auto& cmd = mCommands.back();
- cmd.executeCommandBuffers.buffers.reserve(commandBuffers.size());
- for(auto&& item : commandBuffers)
+ auto command = mCommandPool->AllocateCommand(CommandType::EXECUTE_COMMAND_BUFFERS);
+ auto& cmd = command->executeCommandBuffers;
+ cmd.buffers = mCommandPool->Allocate<const GLES::CommandBuffer*>(commandBuffers.size());
+ cmd.buffersCount = commandBuffers.size();
+ for(auto i = 0u; i < cmd.buffersCount; ++i)
{
- cmd.executeCommandBuffers.buffers.emplace_back(static_cast<const GLES::CommandBuffer*>(item));
+ cmd.buffers[i] = static_cast<const GLES::CommandBuffer*>(commandBuffers[i]);
}
}
uint32_t firstVertex,
uint32_t firstInstance)
{
- mCommands.emplace_back(CommandType::DRAW);
- auto& cmd = mCommands.back().draw;
+ auto command = mCommandPool->AllocateCommand(CommandType::DRAW);
+ auto& cmd = command->draw;
cmd.type = DrawCallDescriptor::Type::DRAW;
cmd.draw.vertexCount = vertexCount;
cmd.draw.instanceCount = instanceCount;
int32_t vertexOffset,
uint32_t firstInstance)
{
- mCommands.emplace_back(CommandType::DRAW_INDEXED);
- auto& cmd = mCommands.back().draw;
+ auto command = mCommandPool->AllocateCommand(CommandType::DRAW_INDEXED);
+ auto& cmd = command->draw;
cmd.type = DrawCallDescriptor::Type::DRAW_INDEXED;
cmd.drawIndexed.firstIndex = firstIndex;
cmd.drawIndexed.firstInstance = firstInstance;
uint32_t drawCount,
uint32_t stride)
{
- mCommands.emplace_back(CommandType::DRAW_INDEXED_INDIRECT);
- auto& cmd = mCommands.back().draw;
+ auto command = mCommandPool->AllocateCommand(CommandType::DRAW_INDEXED_INDIRECT);
+ auto& cmd = command->draw;
cmd.type = DrawCallDescriptor::Type::DRAW_INDEXED_INDIRECT;
cmd.drawIndexedIndirect.buffer = static_cast<const GLES::Buffer*>(&buffer);
cmd.drawIndexedIndirect.offset = offset;
void CommandBuffer::Reset()
{
- mCommands.clear();
+ mCommandPool->Rollback(false);
}
void CommandBuffer::SetScissor(Graphics::Rect2D value)
{
- mCommands.emplace_back(CommandType::SET_SCISSOR);
- mCommands.back().scissor.region = value;
+ auto command = mCommandPool->AllocateCommand(CommandType::SET_SCISSOR);
+ command->scissor.region = value;
}
void CommandBuffer::SetScissorTestEnable(bool value)
{
- mCommands.emplace_back(CommandType::SET_SCISSOR_TEST);
- mCommands.back().scissorTest.enable = value;
+ auto command = mCommandPool->AllocateCommand(CommandType::SET_SCISSOR_TEST);
+ command->scissorTest.enable = value;
}
void CommandBuffer::SetViewport(Viewport value)
{
- mCommands.emplace_back(CommandType::SET_VIEWPORT);
- mCommands.back().viewport.region = value;
+ auto command = mCommandPool->AllocateCommand(CommandType::SET_VIEWPORT);
+ command->viewport.region = value;
}
void CommandBuffer::SetViewportEnable(bool value)
void CommandBuffer::SetColorMask(bool enabled)
{
- mCommands.emplace_back(CommandType::SET_COLOR_MASK);
- auto& cmd = mCommands.back().colorMask;
- ;
- cmd.enabled = enabled;
+ auto command = mCommandPool->AllocateCommand(CommandType::SET_COLOR_MASK);
+ command->colorMask.enabled = enabled;
}
void CommandBuffer::ClearStencilBuffer()
{
- mCommands.emplace_back(CommandType::CLEAR_STENCIL_BUFFER);
+ mCommandPool->AllocateCommand(CommandType::CLEAR_STENCIL_BUFFER);
}
void CommandBuffer::SetStencilTestEnable(bool stencilEnable)
{
- mCommands.emplace_back(CommandType::SET_STENCIL_TEST_ENABLE);
- mCommands.back().stencilTest.enabled = stencilEnable;
+ auto command = mCommandPool->AllocateCommand(CommandType::SET_STENCIL_TEST_ENABLE);
+ command->stencilTest.enabled = stencilEnable;
}
void CommandBuffer::SetStencilWriteMask(uint32_t writeMask)
{
- mCommands.emplace_back(CommandType::SET_STENCIL_WRITE_MASK);
- mCommands.back().stencilWriteMask.mask = writeMask;
+ auto command = mCommandPool->AllocateCommand(CommandType::SET_STENCIL_WRITE_MASK);
+ command->stencilWriteMask.mask = writeMask;
}
void CommandBuffer::SetStencilOp(Graphics::StencilOp failOp,
Graphics::StencilOp passOp,
Graphics::StencilOp depthFailOp)
{
- mCommands.emplace_back(CommandType::SET_STENCIL_OP);
- auto& cmd = mCommands.back().stencilOp;
+ auto command = mCommandPool->AllocateCommand(CommandType::SET_STENCIL_OP);
+ auto& cmd = command->stencilOp;
cmd.failOp = failOp;
cmd.passOp = passOp;
cmd.depthFailOp = depthFailOp;
uint32_t reference,
uint32_t compareMask)
{
- mCommands.emplace_back(CommandType::SET_STENCIL_FUNC);
- auto& cmd = mCommands.back().stencilFunc;
+ auto command = mCommandPool->AllocateCommand(CommandType::SET_STENCIL_FUNC);
+ auto& cmd = command->stencilFunc;
cmd.compareOp = compareOp;
cmd.compareMask = compareMask;
cmd.reference = reference;
void CommandBuffer::SetDepthCompareOp(Graphics::CompareOp compareOp)
{
- mCommands.emplace_back(CommandType::SET_DEPTH_COMPARE_OP);
- mCommands.back().depth.compareOp = compareOp;
+ auto command = mCommandPool->AllocateCommand(CommandType::SET_DEPTH_COMPARE_OP);
+ command->depth.compareOp = compareOp;
}
void CommandBuffer::SetDepthTestEnable(bool depthTestEnable)
{
- mCommands.emplace_back(CommandType::SET_DEPTH_TEST_ENABLE);
- mCommands.back().depth.testEnabled = depthTestEnable;
+ auto command = mCommandPool->AllocateCommand(CommandType::SET_DEPTH_TEST_ENABLE);
+ command->depth.testEnabled = depthTestEnable;
}
void CommandBuffer::SetDepthWriteEnable(bool depthWriteEnable)
{
- mCommands.emplace_back(CommandType::SET_DEPTH_WRITE_ENABLE);
- mCommands.back().depth.writeEnabled = depthWriteEnable;
+ auto command = mCommandPool->AllocateCommand(CommandType::SET_DEPTH_WRITE_ENABLE);
+ command->depth.writeEnabled = depthWriteEnable;
}
void CommandBuffer::ClearDepthBuffer()
{
- mCommands.emplace_back(CommandType::CLEAR_DEPTH_BUFFER);
+ mCommandPool->AllocateCommand(CommandType::CLEAR_DEPTH_BUFFER);
}
void CommandBuffer::PresentRenderTarget(GLES::RenderTarget* renderTarget)
{
- mCommands.emplace_back(CommandType::PRESENT_RENDER_TARGET);
- mCommands.back().presentRenderTarget.targetToPresent = renderTarget;
+ auto command = mCommandPool->AllocateCommand(CommandType::PRESENT_RENDER_TARGET);
+ command->presentRenderTarget.targetToPresent = renderTarget;
}
-[[nodiscard]] const std::vector<Command>& CommandBuffer::GetCommands() const
+[[nodiscard]] const Command* CommandBuffer::GetCommands(uint32_t& size) const
{
- return mCommands;
+ return mCommandPool->GetCommands(size);
}
void CommandBuffer::DestroyResource()
#include "gles-graphics-types.h"
#include "gles-sync-object.h"
+#include <cstring>
+
namespace Dali::Graphics::GLES
{
class Pipeline;
class RenderPass;
class Framebuffer;
class CommandBuffer;
+class CommandPool;
enum class CommandType
{
FLUSH,
*/
struct Command
{
- Command() = delete;
-
- Command(CommandType commandType)
+ Command()
{
- type = commandType;
- switch(type)
- {
- case CommandType::BIND_VERTEX_BUFFERS:
- {
- new(&bindVertexBuffers) decltype(bindVertexBuffers);
- break;
- }
- case CommandType::BIND_TEXTURES:
- {
- new(&bindTextures) decltype(bindTextures);
- break;
- }
- case CommandType::BEGIN_RENDERPASS:
- {
- // run destructor
- new(&beginRenderPass) decltype(beginRenderPass);
- break;
- }
- default:
- {
- }
- }
}
- ~Command()
+ explicit Command(CommandType commandType)
{
- switch(type)
- {
- case CommandType::BIND_VERTEX_BUFFERS:
- {
- InvokeDestructor(bindVertexBuffers);
- break;
- }
- case CommandType::BIND_TEXTURES:
- {
- InvokeDestructor(bindTextures);
- break;
- }
- case CommandType::BEGIN_RENDERPASS:
- {
- // run destructor
- InvokeDestructor(beginRenderPass);
- break;
- }
- default:
- {
- }
- }
+ type = commandType;
}
- /**
- * @brief Copy constructor
- * @param[in] rhs Command
- */
- Command(const Command& rhs)
- {
- switch(rhs.type)
- {
- case CommandType::BIND_VERTEX_BUFFERS:
- {
- new(&bindVertexBuffers) decltype(bindVertexBuffers);
- bindVertexBuffers = rhs.bindVertexBuffers;
- break;
- }
- case CommandType::BIND_INDEX_BUFFER:
- {
- bindIndexBuffer = rhs.bindIndexBuffer;
- break;
- }
- case CommandType::BIND_SAMPLERS:
- {
- bindSamplers = rhs.bindSamplers;
- break;
- }
- case CommandType::BIND_TEXTURES:
- {
- new(&bindTextures) decltype(bindTextures);
- bindTextures = rhs.bindTextures;
- break;
- }
- case CommandType::BIND_PIPELINE:
- {
- bindPipeline = rhs.bindPipeline;
- break;
- }
- case CommandType::BIND_UNIFORM_BUFFER:
- {
- bindUniformBuffers = rhs.bindUniformBuffers;
- break;
- }
- case CommandType::DRAW:
- {
- draw.type = rhs.draw.type;
- draw.draw = rhs.draw.draw;
- break;
- }
- case CommandType::DRAW_INDEXED:
- {
- draw.type = rhs.draw.type;
- draw.drawIndexed = rhs.draw.drawIndexed;
- break;
- }
- case CommandType::DRAW_INDEXED_INDIRECT:
- {
- draw.type = rhs.draw.type;
- draw.drawIndexedIndirect = rhs.draw.drawIndexedIndirect;
- break;
- }
- case CommandType::BEGIN_RENDERPASS:
- {
- new(&beginRenderPass) BeginRenderPassDescriptor(rhs.beginRenderPass);
- break;
- }
- case CommandType::END_RENDERPASS:
- {
- endRenderPass.syncObject = rhs.endRenderPass.syncObject;
- break;
- }
- case CommandType::EXECUTE_COMMAND_BUFFERS:
- {
- executeCommandBuffers = rhs.executeCommandBuffers;
- break;
- }
- case CommandType::FLUSH:
- {
- // Nothing to do
- break;
- }
- case CommandType::SET_SCISSOR:
- {
- scissor.region = rhs.scissor.region;
- break;
- }
- case CommandType::SET_SCISSOR_TEST:
- {
- scissorTest.enable = rhs.scissorTest.enable;
- break;
- }
- case CommandType::SET_VIEWPORT:
- {
- viewport.region = rhs.viewport.region;
- break;
- }
- case CommandType::PRESENT_RENDER_TARGET:
- {
- presentRenderTarget = rhs.presentRenderTarget;
- break;
- }
- case CommandType::SET_COLOR_MASK:
- {
- colorMask.enabled = rhs.colorMask.enabled;
- break;
- }
- case CommandType::CLEAR_STENCIL_BUFFER:
- {
- break;
- }
- case CommandType::CLEAR_DEPTH_BUFFER:
- {
- break;
- }
- case CommandType::SET_STENCIL_TEST_ENABLE:
- {
- stencilTest.enabled = rhs.stencilTest.enabled;
- break;
- }
- case CommandType::SET_STENCIL_FUNC:
- {
- stencilFunc.compareMask = rhs.stencilFunc.compareMask;
- stencilFunc.compareOp = rhs.stencilFunc.compareOp;
- stencilFunc.reference = rhs.stencilFunc.reference;
- break;
- }
- case CommandType::SET_STENCIL_WRITE_MASK:
- {
- stencilWriteMask.mask = rhs.stencilWriteMask.mask;
- break;
- }
- case CommandType::SET_STENCIL_OP:
- {
- stencilOp.failOp = rhs.stencilOp.failOp;
- stencilOp.depthFailOp = rhs.stencilOp.depthFailOp;
- stencilOp.passOp = rhs.stencilOp.passOp;
- break;
- }
-
- case CommandType::SET_DEPTH_COMPARE_OP:
- {
- depth.compareOp = rhs.depth.compareOp;
- break;
- }
- case CommandType::SET_DEPTH_TEST_ENABLE:
- {
- depth.testEnabled = rhs.depth.testEnabled;
- break;
- }
- case CommandType::SET_DEPTH_WRITE_ENABLE:
- {
- depth.writeEnabled = rhs.depth.writeEnabled;
- break;
- }
- }
- type = rhs.type;
- }
+ ~Command() = default;
/**
- * @brief Move constructor
+ * @brief Copy constructor
* @param[in] rhs Command
*/
- Command(Command&& rhs) noexcept
- {
- switch(rhs.type)
- {
- case CommandType::BIND_VERTEX_BUFFERS:
- {
- new(&bindVertexBuffers) decltype(bindVertexBuffers);
- bindVertexBuffers = std::move(rhs.bindVertexBuffers);
- break;
- }
- case CommandType::BIND_INDEX_BUFFER:
- {
- bindIndexBuffer = rhs.bindIndexBuffer;
- break;
- }
- case CommandType::BIND_UNIFORM_BUFFER:
- {
- bindUniformBuffers = std::move(rhs.bindUniformBuffers);
- break;
- }
- case CommandType::BIND_SAMPLERS:
- {
- bindSamplers = std::move(rhs.bindSamplers);
- break;
- }
- case CommandType::BIND_TEXTURES:
- {
- new(&bindTextures) decltype(bindTextures);
- bindTextures = std::move(rhs.bindTextures);
- break;
- }
- case CommandType::BIND_PIPELINE:
- {
- bindPipeline = rhs.bindPipeline;
- break;
- }
- case CommandType::DRAW:
- {
- draw.type = rhs.draw.type;
- draw.draw = rhs.draw.draw;
- break;
- }
- case CommandType::DRAW_INDEXED:
- {
- draw.type = rhs.draw.type;
- draw.drawIndexed = rhs.draw.drawIndexed;
- break;
- }
- case CommandType::DRAW_INDEXED_INDIRECT:
- {
- draw.type = rhs.draw.type;
- draw.drawIndexedIndirect = rhs.draw.drawIndexedIndirect;
- break;
- }
- case CommandType::BEGIN_RENDERPASS:
- {
- new(&beginRenderPass) BeginRenderPassDescriptor(std::move(rhs.beginRenderPass));
- break;
- }
- case CommandType::END_RENDERPASS:
- {
- endRenderPass.syncObject = rhs.endRenderPass.syncObject;
- break;
- }
- case CommandType::EXECUTE_COMMAND_BUFFERS:
- {
- executeCommandBuffers = std::move(rhs.executeCommandBuffers);
- break;
- }
- case CommandType::FLUSH:
- {
- // Nothing to do
- break;
- }
- case CommandType::SET_SCISSOR:
- {
- scissor.region = rhs.scissor.region;
- break;
- }
- case CommandType::SET_SCISSOR_TEST:
- {
- scissorTest.enable = rhs.scissorTest.enable;
- break;
- }
- case CommandType::SET_VIEWPORT:
- {
- viewport.region = rhs.viewport.region;
- break;
- }
- case CommandType::PRESENT_RENDER_TARGET:
- {
- presentRenderTarget = rhs.presentRenderTarget;
- break;
- }
- case CommandType::SET_COLOR_MASK:
- {
- colorMask.enabled = rhs.colorMask.enabled;
- break;
- }
- case CommandType::CLEAR_STENCIL_BUFFER:
- {
- break;
- }
- case CommandType::CLEAR_DEPTH_BUFFER:
- {
- break;
- }
- case CommandType::SET_STENCIL_TEST_ENABLE:
- {
- stencilTest.enabled = rhs.stencilTest.enabled;
- break;
- }
- case CommandType::SET_STENCIL_FUNC:
- {
- stencilFunc.compareMask = rhs.stencilFunc.compareMask;
- stencilFunc.compareOp = rhs.stencilFunc.compareOp;
- stencilFunc.reference = rhs.stencilFunc.reference;
- break;
- }
- case CommandType::SET_STENCIL_WRITE_MASK:
- {
- stencilWriteMask.mask = rhs.stencilWriteMask.mask;
- break;
- }
- case CommandType::SET_STENCIL_OP:
- {
- stencilOp.failOp = rhs.stencilOp.failOp;
- stencilOp.depthFailOp = rhs.stencilOp.depthFailOp;
- stencilOp.passOp = rhs.stencilOp.passOp;
- break;
- }
-
- case CommandType::SET_DEPTH_COMPARE_OP:
- {
- depth.compareOp = rhs.depth.compareOp;
- break;
- }
- case CommandType::SET_DEPTH_TEST_ENABLE:
- {
- depth.testEnabled = rhs.depth.testEnabled;
- break;
- }
- case CommandType::SET_DEPTH_WRITE_ENABLE:
- {
- depth.writeEnabled = rhs.depth.writeEnabled;
- break;
- }
- }
- type = rhs.type;
- }
+ Command(const Command& rhs) = default;
+ Command& operator=(const Command& rhs) = default;
+ Command(Command&& rhs) noexcept = delete;
+ Command& operator=(Command&& rhs) = delete;
CommandType type{CommandType::FLUSH}; ///< Type of command
{
struct
{
- std::vector<Graphics::TextureBinding> textureBindings;
+ IndirectPtr<Graphics::TextureBinding> textureBindings;
+ uint32_t textureBindingsCount;
} bindTextures{};
// BindSampler command
struct
{
- std::vector<Graphics::SamplerBinding> samplerBindings;
+ IndirectPtr<Graphics::SamplerBinding> samplerBindings;
+ uint32_t samplerBindingsCount;
} bindSamplers;
struct
{
using Binding = GLES::VertexBufferBindingDescriptor;
- std::vector<Binding> vertexBufferBindings;
+ IndirectPtr<Binding> vertexBufferBindings;
+ uint32_t vertexBufferBindingsCount;
} bindVertexBuffers;
struct : public IndexBufferBindingDescriptor
struct
{
- std::vector<UniformBufferBindingDescriptor> uniformBufferBindings{};
+ IndirectPtr<UniformBufferBindingDescriptor> uniformBufferBindings;
+ uint32_t uniformBufferBindingsCount;
UniformBufferBindingDescriptor standaloneUniformsBufferBinding{};
} bindUniformBuffers;
struct
{
- std::vector<const GLES::CommandBuffer*> buffers;
+ IndirectPtr<const GLES::CommandBuffer*> buffers;
+ uint32_t buffersCount;
} executeCommandBuffers;
struct
*/
void PresentRenderTarget(GLES::RenderTarget* renderTarget);
- [[nodiscard]] const std::vector<Command>& GetCommands() const;
+ /**
+ * @brief Returns pointer to the list of command and size of the list
+ *
+ * @param[out] size Size of the list
+ * @return Valid pointer to the list of commands
+ */
+ [[nodiscard]] const Command* GetCommands(uint32_t& size) const;
/**
* @brief Destroy the associated resources
void DiscardResource() override;
private:
- std::vector<Command> mCommands; ///< List of commands in this command buffer
+ std::unique_ptr<CommandPool> mCommandPool; ///< Pool of commands and transient memory
};
} // namespace Dali::Graphics::GLES
};
/**
+ * This class stores indirect pointer, used by the CommandBuffer
+ * to store data allocated within resizeable pool
+ */
+template<class T>
+struct IndirectPtr
+{
+ uint32_t ptr; // relative pointer
+ void** base; // base pointer
+
+ inline T* operator->()
+ {
+ return reinterpret_cast<T*>((reinterpret_cast<uint8_t*>(*base) + ptr));
+ }
+
+ inline T& operator*()
+ {
+ return *reinterpret_cast<T*>((reinterpret_cast<uint8_t*>(*base) + ptr));
+ }
+
+ // Returns indirect pointer casted to requested type
+ T* Ptr() const
+ {
+ auto val = reinterpret_cast<T*>((reinterpret_cast<uint8_t*>(*base) + ptr));
+ return val;
+ }
+
+ inline T& operator[](int index)
+ {
+ return reinterpret_cast<T*>((reinterpret_cast<uint8_t*>(*base) + ptr))[index];
+ }
+
+ // Fake assignment operator for void* type
+ inline IndirectPtr<T>& operator=(void* p)
+ {
+ ptr = 0;
+ base = nullptr;
+ return *this;
+ }
+};
+
+/**
* The descriptor of BeginRenderPass command
*/
struct BeginRenderPassDescriptor
{
- const GLES::RenderPass* renderPass{};
- const GLES::RenderTarget* renderTarget{};
- Rect2D renderArea{};
- std::vector<ClearValue> clearValues{};
+ const GLES::RenderPass* renderPass;
+ const GLES::RenderTarget* renderTarget;
+ Rect2D renderArea;
+ IndirectPtr<ClearValue> clearValues;
+ uint32_t clearValuesCount;
};
} // namespace Dali::Graphics::GLES