2 * Copyright (c) 2023 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include "gles-graphics-command-buffer.h"
22 #include "egl-graphics-controller.h"
23 #include "gles-graphics-buffer.h"
24 #include "gles-graphics-framebuffer.h"
25 #include "gles-graphics-pipeline.h"
26 #include "gles-graphics-render-pass.h"
27 #include "gles-graphics-render-target.h"
28 #include "gles-graphics-texture.h"
30 namespace Dali::Graphics::GLES
34 static constexpr uint32_t COMMAND_POOL_DEFAULT_INCREMENT = 1024 * 32 / sizeof(Command); // 32kb banks
35 static const uint32_t MEMORY_POOL_DEFAULT_INCREMENT = 1024; // 1kb memory pool increment
36 static const uint32_t MEMORY_POOL_DEFAULT_ALIGNMENT = 64; // 64bytes alignment
51 uint32_t dataSize{0u};
52 uint32_t capacity{0u};
53 inline T& operator[](int index) const
65 inline void resize(int newSize)
67 ptr = reinterpret_cast<T*>(realloc(ptr, newSize * sizeof(T)));
68 capacity = newSize * sizeof(T);
72 inline T* data() const
77 inline uint32_t size() const
82 // This memory pool guarantees all items will be placed
83 // in the continuous memory area but returned pointers are relative
84 // and require translation before using
85 template<class T, int Increment, int Alignment = 0>
89 inline T& operator[](int index)
93 MemoryPool() = default;
95 IndirectPtr<T> Allocate(uint32_t count)
100 // resize data size when capacity is not setuped.
101 // Note if totalCapacity is bigger than fixedCapacity,
102 // just skip here and resize dynamically
103 if(DALI_UNLIKELY(totalCapacity < fixedCapacity))
105 data.resize(fixedCapacity);
106 totalCapacity = data.size();
110 // Resize dynamically
111 if(DALI_UNLIKELY(totalCapacity < offset + count))
113 // Resize the memory size as ceil((offset + count - totalCapacity)) / Increment) * Increment
114 // So the incremented size of data is always multiplied of the value Increment.
115 data.resize(data.size() + ((offset + count - totalCapacity - 1) / Increment + 1) * Increment);
117 // update base pointer, required for address translation
118 totalCapacity = data.size();
121 basePtr = data.data();
123 IndirectPtr<T> retval{uint32_t(uintptr_t(&data[offset]) - uintptr_t(basePtr)), &basePtr};
127 // align offset if needed (only if type size is 1)
128 if(Alignment && sizeof(T) == 1)
130 offset = ((offset / Alignment) * Alignment) + ((offset % Alignment) ? Alignment : 0);
142 // Discards all data and storage
152 uint32_t totalCapacity{0u};
154 uint32_t increment{Increment};
155 uint32_t alignment{Alignment};
156 uint32_t fixedCapacity{0u};
157 void* basePtr{nullptr};
160 MemoryPool<uint8_t, MEMORY_POOL_DEFAULT_INCREMENT, MEMORY_POOL_DEFAULT_ALIGNMENT> memoryPool;
161 MemoryPool<Command, COMMAND_POOL_DEFAULT_INCREMENT, MEMORY_POOL_DEFAULT_ALIGNMENT> commandPool;
164 CommandPool() = default;
165 CommandPool(uint32_t fixedCapacity)
167 commandPool.fixedCapacity = fixedCapacity;
168 memoryPool.fixedCapacity = fixedCapacity * 1024;
172 * Return value may become invalid if pool is resized (by allocating another command)
176 Command* AllocateCommand(CommandType type)
178 auto command = commandPool.Allocate(1);
179 command->type = type;
180 auto* cmd = command.Ptr();
185 IndirectPtr<T> Allocate(uint32_t count)
187 const auto typeSize = sizeof(T);
188 const auto memoryRequired = typeSize * count;
189 auto ptr = memoryPool.Allocate(memoryRequired);
191 // Convert generic pointer and return
192 return IndirectPtr<T>{ptr.ptr, ptr.base};
195 // New (should not be needed)
197 T* New(uint32_t count)
199 auto ptr = Allocate<T>(count);
200 for(auto i = 0u; i < count; ++i)
207 // TODO: explicit delete?
208 void Rollback(bool discard)
217 commandPool.Rollback();
218 memoryPool.Rollback();
222 const Command* GetCommands(uint32_t& size) const
224 size = commandPool.size;
225 return commandPool.data.ptr;
228 std::size_t GetTotalCapacity() const
230 return commandPool.data.capacity + memoryPool.data.capacity;
234 CommandBuffer::CommandBuffer(const Graphics::CommandBufferCreateInfo& createInfo, EglGraphicsController& controller)
235 : CommandBufferResource(createInfo, controller)
237 mCommandPool = std::make_unique<CommandPool>(createInfo.fixedCapacity);
240 CommandBuffer::~CommandBuffer() = default;
242 void CommandBuffer::BindVertexBuffers(uint32_t firstBinding,
243 const std::vector<const Graphics::Buffer*>& buffers,
244 const std::vector<uint32_t>& offsets)
246 auto command = mCommandPool->AllocateCommand(CommandType::BIND_VERTEX_BUFFERS);
247 command->bindVertexBuffers.vertexBufferBindingsCount = firstBinding + static_cast<uint32_t>(buffers.size());
248 auto pBindings = mCommandPool->Allocate<GLES::VertexBufferBindingDescriptor>(firstBinding + buffers.size());
250 command->bindVertexBuffers.vertexBufferBindings = pBindings;
251 auto index = firstBinding;
252 for(auto& buf : buffers)
254 pBindings[index].buffer = static_cast<const GLES::Buffer*>(buf);
255 pBindings[index].offset = offsets[index - firstBinding];
260 void CommandBuffer::BindUniformBuffers(const std::vector<Graphics::UniformBufferBinding>& bindings)
262 auto command = mCommandPool->AllocateCommand(CommandType::BIND_UNIFORM_BUFFER);
264 auto& cmd = *command;
265 auto& bindCmd = cmd.bindUniformBuffers;
267 // temporary static set of binding slots (thread local)
268 static const auto MAX_UNIFORM_BUFFER_BINDINGS = 64; // TODO: this should be read from introspection
270 static const UniformBufferBindingDescriptor NULL_DESCRIPTOR{nullptr, 0, 0, 0, 0, false};
271 static thread_local std::vector<UniformBufferBindingDescriptor> sTempBindings(MAX_UNIFORM_BUFFER_BINDINGS, NULL_DESCRIPTOR);
273 // reset temp bindings
274 std::fill_n(sTempBindings.begin(), MAX_UNIFORM_BUFFER_BINDINGS, NULL_DESCRIPTOR);
276 memset(&bindCmd.standaloneUniformsBufferBinding, 0, sizeof(UniformBufferBindingDescriptor));
278 // find max binding and standalone UBO
279 auto maxBinding = 0u;
280 bool hasBindings = false;
281 for(const auto& binding : bindings)
285 auto glesBuffer = static_cast<const GLES::Buffer*>(binding.buffer);
286 if(glesBuffer->IsCPUAllocated()) // standalone uniforms
288 bindCmd.standaloneUniformsBufferBinding.buffer = glesBuffer;
289 bindCmd.standaloneUniformsBufferBinding.binding = binding.binding;
290 bindCmd.standaloneUniformsBufferBinding.offset = binding.offset;
291 bindCmd.standaloneUniformsBufferBinding.emulated = true;
293 else // Bind regular UBO
295 auto& slot = sTempBindings[binding.binding];
297 slot.buffer = glesBuffer;
298 slot.binding = binding.binding;
299 slot.offset = binding.offset;
300 slot.dataSize = binding.dataSize;
302 slot.emulated = false;
304 maxBinding = std::max(maxBinding, binding.binding);
309 bindCmd.uniformBufferBindings = nullptr;
310 bindCmd.uniformBufferBindingsCount = 0u;
315 auto destBindings = mCommandPool->Allocate<UniformBufferBindingDescriptor>(maxBinding + 1);
317 auto size = sizeof(UniformBufferBindingDescriptor) * (maxBinding + 1);
318 if(!(size % sizeof(intptr_t)))
320 auto* srcPtr = reinterpret_cast<intptr_t*>(&sTempBindings[0]);
321 auto* dstPtr = reinterpret_cast<intptr_t*>(destBindings.Ptr());
322 for(auto i = 0u; i < size / sizeof(intptr_t); ++i)
324 *dstPtr++ = *srcPtr++;
329 memcpy(destBindings.Ptr(), &sTempBindings[0], size);
331 bindCmd.uniformBufferBindings = destBindings;
332 bindCmd.uniformBufferBindingsCount = maxBinding + 1;
336 void CommandBuffer::BindPipeline(const Graphics::Pipeline& pipeline)
338 auto command = mCommandPool->AllocateCommand(CommandType::BIND_PIPELINE);
339 command->bindPipeline.pipeline = static_cast<const GLES::Pipeline*>(&pipeline);
342 void CommandBuffer::BindTextures(const std::vector<TextureBinding>& textureBindings)
344 auto command = mCommandPool->AllocateCommand(CommandType::BIND_TEXTURES);
345 auto& bindTexturesCmd = command->bindTextures;
346 bindTexturesCmd.textureBindings = mCommandPool->Allocate<TextureBinding>(textureBindings.size());
347 bindTexturesCmd.textureBindingsCount = textureBindings.size();
348 memcpy(bindTexturesCmd.textureBindings.Ptr(), textureBindings.data(), sizeof(TextureBinding) * textureBindings.size());
351 void CommandBuffer::BindSamplers(const std::vector<SamplerBinding>& samplerBindings)
353 auto command = mCommandPool->AllocateCommand(CommandType::BIND_SAMPLERS);
354 auto& bindSamplersCmd = command->bindSamplers;
355 bindSamplersCmd.samplerBindings = mCommandPool->Allocate<SamplerBinding>(samplerBindings.size());
356 bindSamplersCmd.samplerBindingsCount = samplerBindings.size();
357 memcpy(bindSamplersCmd.samplerBindings.Ptr(), samplerBindings.data(), sizeof(TextureBinding) * samplerBindings.size());
360 void CommandBuffer::BindPushConstants(void* data,
366 void CommandBuffer::BindIndexBuffer(const Graphics::Buffer& buffer,
370 auto command = mCommandPool->AllocateCommand(CommandType::BIND_INDEX_BUFFER);
371 command->bindIndexBuffer.buffer = static_cast<const GLES::Buffer*>(&buffer);
372 command->bindIndexBuffer.offset = offset;
373 command->bindIndexBuffer.format = format;
376 void CommandBuffer::BeginRenderPass(
377 Graphics::RenderPass* renderPass,
378 Graphics::RenderTarget* renderTarget,
380 const std::vector<ClearValue>& clearValues)
382 auto command = mCommandPool->AllocateCommand(CommandType::BEGIN_RENDERPASS);
383 auto& cmd = *command;
384 cmd.beginRenderPass.renderPass = static_cast<GLES::RenderPass*>(renderPass);
385 cmd.beginRenderPass.renderTarget = static_cast<GLES::RenderTarget*>(renderTarget);
386 cmd.beginRenderPass.renderArea = renderArea;
388 cmd.beginRenderPass.clearValues = mCommandPool->Allocate<ClearValue>(clearValues.size());
389 memcpy(cmd.beginRenderPass.clearValues.Ptr(), clearValues.data(), sizeof(ClearValue) * clearValues.size());
390 cmd.beginRenderPass.clearValuesCount = clearValues.size();
393 void CommandBuffer::EndRenderPass(Graphics::SyncObject* syncObject)
395 auto command = mCommandPool->AllocateCommand(CommandType::END_RENDERPASS);
396 command->endRenderPass.syncObject = static_cast<GLES::SyncObject*>(syncObject);
399 void CommandBuffer::ExecuteCommandBuffers(std::vector<const Graphics::CommandBuffer*>&& commandBuffers)
401 auto command = mCommandPool->AllocateCommand(CommandType::EXECUTE_COMMAND_BUFFERS);
402 auto& cmd = command->executeCommandBuffers;
403 cmd.buffers = mCommandPool->Allocate<const GLES::CommandBuffer*>(commandBuffers.size());
404 cmd.buffersCount = commandBuffers.size();
405 for(auto i = 0u; i < cmd.buffersCount; ++i)
407 cmd.buffers[i] = static_cast<const GLES::CommandBuffer*>(commandBuffers[i]);
411 void CommandBuffer::Draw(
412 uint32_t vertexCount,
413 uint32_t instanceCount,
414 uint32_t firstVertex,
415 uint32_t firstInstance)
417 auto command = mCommandPool->AllocateCommand(CommandType::DRAW);
418 auto& cmd = command->draw;
419 cmd.type = DrawCallDescriptor::Type::DRAW;
420 cmd.draw.vertexCount = vertexCount;
421 cmd.draw.instanceCount = instanceCount;
422 cmd.draw.firstInstance = firstInstance;
423 cmd.draw.firstVertex = firstVertex;
426 void CommandBuffer::DrawIndexed(
428 uint32_t instanceCount,
430 int32_t vertexOffset,
431 uint32_t firstInstance)
433 auto command = mCommandPool->AllocateCommand(CommandType::DRAW_INDEXED);
434 auto& cmd = command->draw;
435 cmd.type = DrawCallDescriptor::Type::DRAW_INDEXED;
436 cmd.drawIndexed.firstIndex = firstIndex;
437 cmd.drawIndexed.firstInstance = firstInstance;
438 cmd.drawIndexed.indexCount = indexCount;
439 cmd.drawIndexed.vertexOffset = vertexOffset;
440 cmd.drawIndexed.instanceCount = instanceCount;
443 void CommandBuffer::DrawIndexedIndirect(
444 Graphics::Buffer& buffer,
449 auto command = mCommandPool->AllocateCommand(CommandType::DRAW_INDEXED_INDIRECT);
450 auto& cmd = command->draw;
451 cmd.type = DrawCallDescriptor::Type::DRAW_INDEXED_INDIRECT;
452 cmd.drawIndexedIndirect.buffer = static_cast<const GLES::Buffer*>(&buffer);
453 cmd.drawIndexedIndirect.offset = offset;
454 cmd.drawIndexedIndirect.drawCount = drawCount;
455 cmd.drawIndexedIndirect.stride = stride;
458 void CommandBuffer::DrawNative(const DrawNativeInfo* drawNativeInfo)
460 auto command = mCommandPool->AllocateCommand(CommandType::DRAW_NATIVE);
461 auto& cmd = command->drawNative;
462 memcpy(&cmd.drawNativeInfo, drawNativeInfo, sizeof(DrawNativeInfo));
465 void CommandBuffer::Reset()
467 mCommandPool->Rollback(false);
470 void CommandBuffer::SetScissor(Graphics::Rect2D value)
472 auto command = mCommandPool->AllocateCommand(CommandType::SET_SCISSOR);
473 command->scissor.region = value;
476 void CommandBuffer::SetScissorTestEnable(bool value)
478 auto command = mCommandPool->AllocateCommand(CommandType::SET_SCISSOR_TEST);
479 command->scissorTest.enable = value;
482 void CommandBuffer::SetViewport(Viewport value)
484 auto command = mCommandPool->AllocateCommand(CommandType::SET_VIEWPORT);
485 command->viewport.region = value;
488 void CommandBuffer::SetViewportEnable(bool value)
490 // There is no GL equivalent
493 void CommandBuffer::SetColorMask(bool enabled)
495 auto command = mCommandPool->AllocateCommand(CommandType::SET_COLOR_MASK);
496 command->colorMask.enabled = enabled;
499 void CommandBuffer::ClearStencilBuffer()
501 mCommandPool->AllocateCommand(CommandType::CLEAR_STENCIL_BUFFER);
504 void CommandBuffer::SetStencilTestEnable(bool stencilEnable)
506 auto command = mCommandPool->AllocateCommand(CommandType::SET_STENCIL_TEST_ENABLE);
507 command->stencilTest.enabled = stencilEnable;
510 void CommandBuffer::SetStencilWriteMask(uint32_t writeMask)
512 auto command = mCommandPool->AllocateCommand(CommandType::SET_STENCIL_WRITE_MASK);
513 command->stencilWriteMask.mask = writeMask;
516 void CommandBuffer::SetStencilOp(Graphics::StencilOp failOp,
517 Graphics::StencilOp passOp,
518 Graphics::StencilOp depthFailOp)
520 auto command = mCommandPool->AllocateCommand(CommandType::SET_STENCIL_OP);
521 auto& cmd = command->stencilOp;
524 cmd.depthFailOp = depthFailOp;
527 void CommandBuffer::SetStencilFunc(Graphics::CompareOp compareOp,
529 uint32_t compareMask)
531 auto command = mCommandPool->AllocateCommand(CommandType::SET_STENCIL_FUNC);
532 auto& cmd = command->stencilFunc;
533 cmd.compareOp = compareOp;
534 cmd.compareMask = compareMask;
535 cmd.reference = reference;
538 void CommandBuffer::SetDepthCompareOp(Graphics::CompareOp compareOp)
540 auto command = mCommandPool->AllocateCommand(CommandType::SET_DEPTH_COMPARE_OP);
541 command->depth.compareOp = compareOp;
544 void CommandBuffer::SetDepthTestEnable(bool depthTestEnable)
546 auto command = mCommandPool->AllocateCommand(CommandType::SET_DEPTH_TEST_ENABLE);
547 command->depth.testEnabled = depthTestEnable;
549 void CommandBuffer::SetDepthWriteEnable(bool depthWriteEnable)
551 auto command = mCommandPool->AllocateCommand(CommandType::SET_DEPTH_WRITE_ENABLE);
552 command->depth.writeEnabled = depthWriteEnable;
554 void CommandBuffer::ClearDepthBuffer()
556 mCommandPool->AllocateCommand(CommandType::CLEAR_DEPTH_BUFFER);
559 void CommandBuffer::PresentRenderTarget(GLES::RenderTarget* renderTarget)
561 auto command = mCommandPool->AllocateCommand(CommandType::PRESENT_RENDER_TARGET);
562 command->presentRenderTarget.targetToPresent = renderTarget;
565 [[nodiscard]] const Command* CommandBuffer::GetCommands(uint32_t& size) const
567 return mCommandPool->GetCommands(size);
570 void CommandBuffer::DestroyResource()
575 bool CommandBuffer::InitializeResource()
581 void CommandBuffer::DiscardResource()
583 GetController().DiscardResource(this);
586 std::size_t CommandBuffer::GetCapacity()
588 std::size_t total{0u};
591 total = mCommandPool->GetTotalCapacity();
596 } // namespace Dali::Graphics::GLES