Reset array of uniform buffer only required
[platform/core/uifw/dali-adaptor.git] / dali / internal / graphics / gles-impl / gles-graphics-command-buffer.cpp
1 /*
2  * Copyright (c) 2023 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include "gles-graphics-command-buffer.h"
20
21 // INTERNAL INCLUDES
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"
29
30 namespace Dali::Graphics::GLES
31 {
32 class CommandPool
33 {
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
37
38   template<class T>
39   struct Block
40   {
41     Block() = default;
42     ~Block()
43     {
44       if(ptr)
45       {
46         free(ptr);
47       }
48     }
49
50     T*        ptr{nullptr};
51     uint32_t  dataSize{0u};
52     uint32_t  capacity{0u};
53     inline T& operator[](int index) const
54     {
55       return ptr[index];
56     }
57
58     inline void clear()
59     {
60       free(ptr);
61       capacity = 0;
62       dataSize = 0;
63     }
64
65     inline void resize(int newSize)
66     {
67       ptr      = reinterpret_cast<T*>(realloc(ptr, newSize * sizeof(T)));
68       capacity = newSize * sizeof(T);
69       dataSize = newSize;
70     }
71
72     inline T* data() const
73     {
74       return ptr;
75     }
76
77     inline uint32_t size() const
78     {
79       return dataSize;
80     }
81   };
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>
86   struct MemoryPool
87   {
88     Block<T>  data;
89     inline T& operator[](int index)
90     {
91       return data[index];
92     }
93     MemoryPool() = default;
94
95     IndirectPtr<T> Allocate(uint32_t count)
96     {
97       // Set fixed capacity
98       if(fixedCapacity)
99       {
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))
104         {
105           data.resize(fixedCapacity);
106           totalCapacity = data.size();
107         }
108       }
109
110       // Resize dynamically
111       if(DALI_UNLIKELY(totalCapacity < offset + count))
112       {
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);
116
117         // update base pointer, required for address translation
118         totalCapacity = data.size();
119       }
120
121       basePtr = data.data();
122
123       IndirectPtr<T> retval{uint32_t(uintptr_t(&data[offset]) - uintptr_t(basePtr)), &basePtr};
124       size += count;
125       offset += count;
126
127       // align offset if needed (only if type size is 1)
128       if(Alignment && sizeof(T) == 1)
129       {
130         offset = ((offset / Alignment) * Alignment) + ((offset % Alignment) ? Alignment : 0);
131       }
132       return retval;
133     }
134
135     // Rolls back pool
136     void Rollback()
137     {
138       offset = 0;
139       size   = 0;
140     }
141
142     // Discards all data and storage
143     void Clear()
144     {
145       data.clear();
146       totalCapacity = 0;
147       offset        = 0;
148       size          = 0;
149     }
150
151     uint32_t offset{0u};
152     uint32_t totalCapacity{0u};
153     uint32_t size{0u};
154     uint32_t increment{Increment};
155     uint32_t alignment{Alignment};
156     uint32_t fixedCapacity{0u};
157     void*    basePtr{nullptr};
158   };
159
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;
162
163 public:
164   CommandPool() = default;
165   CommandPool(uint32_t fixedCapacity)
166   {
167     commandPool.fixedCapacity = fixedCapacity;
168     memoryPool.fixedCapacity  = fixedCapacity * 1024;
169   }
170
171   /**
172    * Return value may become invalid if pool is resized (by allocating another command)
173    * @param type
174    * @return
175    */
176   Command* AllocateCommand(CommandType type)
177   {
178     auto command  = commandPool.Allocate(1);
179     command->type = type;
180     auto* cmd     = command.Ptr();
181     return cmd;
182   }
183
184   template<class T>
185   IndirectPtr<T> Allocate(uint32_t count)
186   {
187     const auto typeSize       = sizeof(T);
188     const auto memoryRequired = typeSize * count;
189     auto       ptr            = memoryPool.Allocate(memoryRequired);
190
191     // Convert generic pointer and return
192     return IndirectPtr<T>{ptr.ptr, ptr.base};
193   }
194
195   // New (should not be needed)
196   template<class T>
197   T* New(uint32_t count)
198   {
199     auto ptr = Allocate<T>(count);
200     for(auto i = 0u; i < count; ++i)
201     {
202       new(&ptr[i]) T();
203     }
204     return ptr;
205   }
206
207   // TODO: explicit delete?
208   void Rollback(bool discard)
209   {
210     if(discard)
211     {
212       commandPool.Clear();
213       memoryPool.Clear();
214     }
215     else
216     {
217       commandPool.Rollback();
218       memoryPool.Rollback();
219     }
220   }
221
222   const Command* GetCommands(uint32_t& size) const
223   {
224     size = commandPool.size;
225     return commandPool.data.ptr;
226   }
227
228   std::size_t GetTotalCapacity() const
229   {
230     return commandPool.data.capacity + memoryPool.data.capacity;
231   }
232 };
233
234 CommandBuffer::CommandBuffer(const Graphics::CommandBufferCreateInfo& createInfo, EglGraphicsController& controller)
235 : CommandBufferResource(createInfo, controller)
236 {
237   mCommandPool = std::make_unique<CommandPool>(createInfo.fixedCapacity);
238 }
239
240 CommandBuffer::~CommandBuffer() = default;
241
242 void CommandBuffer::BindVertexBuffers(uint32_t                                    firstBinding,
243                                       const std::vector<const Graphics::Buffer*>& buffers,
244                                       const std::vector<uint32_t>&                offsets)
245 {
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());
249
250   command->bindVertexBuffers.vertexBufferBindings = pBindings;
251   auto index                                      = firstBinding;
252   for(auto& buf : buffers)
253   {
254     pBindings[index].buffer = static_cast<const GLES::Buffer*>(buf);
255     pBindings[index].offset = offsets[index - firstBinding];
256     index++;
257   }
258 }
259
260 void CommandBuffer::BindUniformBuffers(const std::vector<Graphics::UniformBufferBinding>& bindings)
261 {
262   auto command = mCommandPool->AllocateCommand(CommandType::BIND_UNIFORM_BUFFER);
263
264   auto& cmd     = *command;
265   auto& bindCmd = cmd.bindUniformBuffers;
266
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
269
270   // TODO: could use vector?
271   static thread_local UniformBufferBindingDescriptor sTempBindings[MAX_UNIFORM_BUFFER_BINDINGS];
272
273   auto maxBindingCount = 0u;
274
275   // find max binding and standalone UBO
276   for(const auto& binding : bindings)
277   {
278     if(binding.buffer)
279     {
280       auto glesBuffer = static_cast<const GLES::Buffer*>(binding.buffer);
281       if(glesBuffer->IsCPUAllocated()) // standalone uniforms
282       {
283         bindCmd.standaloneUniformsBufferBinding.buffer   = glesBuffer;
284         bindCmd.standaloneUniformsBufferBinding.offset   = binding.offset;
285         bindCmd.standaloneUniformsBufferBinding.binding  = binding.binding;
286         bindCmd.standaloneUniformsBufferBinding.emulated = true;
287       }
288       else // Bind regular UBO
289       {
290         if(DALI_UNLIKELY(maxBindingCount == 0u))
291         {
292           // We can assume here comes first time. Reset temp bindings
293           std::fill_n(sTempBindings, MAX_UNIFORM_BUFFER_BINDINGS, UniformBufferBindingDescriptor());
294         }
295         auto& slot    = sTempBindings[binding.binding];
296         slot.buffer   = glesBuffer;
297         slot.offset   = binding.offset;
298         slot.binding  = binding.binding;
299         slot.emulated = false;
300
301         maxBindingCount = std::max(maxBindingCount, binding.binding + 1u);
302       }
303     }
304   }
305   bindCmd.uniformBufferBindings      = nullptr;
306   bindCmd.uniformBufferBindingsCount = 0u;
307
308   // copy data
309   if(maxBindingCount)
310   {
311     auto destBindings = mCommandPool->Allocate<UniformBufferBindingDescriptor>(maxBindingCount);
312     // copy
313     memcpy(destBindings.Ptr(), sTempBindings, sizeof(UniformBufferBindingDescriptor) * (maxBindingCount));
314     bindCmd.uniformBufferBindings      = destBindings;
315     bindCmd.uniformBufferBindingsCount = maxBindingCount;
316   }
317 }
318
319 void CommandBuffer::BindPipeline(const Graphics::Pipeline& pipeline)
320 {
321   auto command                   = mCommandPool->AllocateCommand(CommandType::BIND_PIPELINE);
322   command->bindPipeline.pipeline = static_cast<const GLES::Pipeline*>(&pipeline);
323 }
324
325 void CommandBuffer::BindTextures(const std::vector<TextureBinding>& textureBindings)
326 {
327   auto  command                        = mCommandPool->AllocateCommand(CommandType::BIND_TEXTURES);
328   auto& bindTexturesCmd                = command->bindTextures;
329   bindTexturesCmd.textureBindings      = mCommandPool->Allocate<TextureBinding>(textureBindings.size());
330   bindTexturesCmd.textureBindingsCount = textureBindings.size();
331   memcpy(bindTexturesCmd.textureBindings.Ptr(), textureBindings.data(), sizeof(TextureBinding) * textureBindings.size());
332 }
333
334 void CommandBuffer::BindSamplers(const std::vector<SamplerBinding>& samplerBindings)
335 {
336   auto  command                        = mCommandPool->AllocateCommand(CommandType::BIND_SAMPLERS);
337   auto& bindSamplersCmd                = command->bindSamplers;
338   bindSamplersCmd.samplerBindings      = mCommandPool->Allocate<SamplerBinding>(samplerBindings.size());
339   bindSamplersCmd.samplerBindingsCount = samplerBindings.size();
340   memcpy(bindSamplersCmd.samplerBindings.Ptr(), samplerBindings.data(), sizeof(TextureBinding) * samplerBindings.size());
341 }
342
343 void CommandBuffer::BindPushConstants(void*    data,
344                                       uint32_t size,
345                                       uint32_t binding)
346 {
347 }
348
349 void CommandBuffer::BindIndexBuffer(const Graphics::Buffer& buffer,
350                                     uint32_t                offset,
351                                     Format                  format)
352 {
353   auto command                    = mCommandPool->AllocateCommand(CommandType::BIND_INDEX_BUFFER);
354   command->bindIndexBuffer.buffer = static_cast<const GLES::Buffer*>(&buffer);
355   command->bindIndexBuffer.offset = offset;
356   command->bindIndexBuffer.format = format;
357 }
358
359 void CommandBuffer::BeginRenderPass(
360   Graphics::RenderPass*          renderPass,
361   Graphics::RenderTarget*        renderTarget,
362   Rect2D                         renderArea,
363   const std::vector<ClearValue>& clearValues)
364 {
365   auto  command                    = mCommandPool->AllocateCommand(CommandType::BEGIN_RENDERPASS);
366   auto& cmd                        = *command;
367   cmd.beginRenderPass.renderPass   = static_cast<GLES::RenderPass*>(renderPass);
368   cmd.beginRenderPass.renderTarget = static_cast<GLES::RenderTarget*>(renderTarget);
369   cmd.beginRenderPass.renderArea   = renderArea;
370
371   cmd.beginRenderPass.clearValues = mCommandPool->Allocate<ClearValue>(clearValues.size());
372   memcpy(cmd.beginRenderPass.clearValues.Ptr(), clearValues.data(), sizeof(ClearValue) * clearValues.size());
373   cmd.beginRenderPass.clearValuesCount = clearValues.size();
374 }
375
376 void CommandBuffer::EndRenderPass(Graphics::SyncObject* syncObject)
377 {
378   auto command                      = mCommandPool->AllocateCommand(CommandType::END_RENDERPASS);
379   command->endRenderPass.syncObject = static_cast<GLES::SyncObject*>(syncObject);
380 }
381
382 void CommandBuffer::ExecuteCommandBuffers(std::vector<const Graphics::CommandBuffer*>&& commandBuffers)
383 {
384   auto  command    = mCommandPool->AllocateCommand(CommandType::EXECUTE_COMMAND_BUFFERS);
385   auto& cmd        = command->executeCommandBuffers;
386   cmd.buffers      = mCommandPool->Allocate<const GLES::CommandBuffer*>(commandBuffers.size());
387   cmd.buffersCount = commandBuffers.size();
388   for(auto i = 0u; i < cmd.buffersCount; ++i)
389   {
390     cmd.buffers[i] = static_cast<const GLES::CommandBuffer*>(commandBuffers[i]);
391   }
392 }
393
394 void CommandBuffer::Draw(
395   uint32_t vertexCount,
396   uint32_t instanceCount,
397   uint32_t firstVertex,
398   uint32_t firstInstance)
399 {
400   auto  command          = mCommandPool->AllocateCommand(CommandType::DRAW);
401   auto& cmd              = command->draw;
402   cmd.type               = DrawCallDescriptor::Type::DRAW;
403   cmd.draw.vertexCount   = vertexCount;
404   cmd.draw.instanceCount = instanceCount;
405   cmd.draw.firstInstance = firstInstance;
406   cmd.draw.firstVertex   = firstVertex;
407 }
408
409 void CommandBuffer::DrawIndexed(
410   uint32_t indexCount,
411   uint32_t instanceCount,
412   uint32_t firstIndex,
413   int32_t  vertexOffset,
414   uint32_t firstInstance)
415 {
416   auto  command                 = mCommandPool->AllocateCommand(CommandType::DRAW_INDEXED);
417   auto& cmd                     = command->draw;
418   cmd.type                      = DrawCallDescriptor::Type::DRAW_INDEXED;
419   cmd.drawIndexed.firstIndex    = firstIndex;
420   cmd.drawIndexed.firstInstance = firstInstance;
421   cmd.drawIndexed.indexCount    = indexCount;
422   cmd.drawIndexed.vertexOffset  = vertexOffset;
423   cmd.drawIndexed.instanceCount = instanceCount;
424 }
425
426 void CommandBuffer::DrawIndexedIndirect(
427   Graphics::Buffer& buffer,
428   uint32_t          offset,
429   uint32_t          drawCount,
430   uint32_t          stride)
431 {
432   auto  command                     = mCommandPool->AllocateCommand(CommandType::DRAW_INDEXED_INDIRECT);
433   auto& cmd                         = command->draw;
434   cmd.type                          = DrawCallDescriptor::Type::DRAW_INDEXED_INDIRECT;
435   cmd.drawIndexedIndirect.buffer    = static_cast<const GLES::Buffer*>(&buffer);
436   cmd.drawIndexedIndirect.offset    = offset;
437   cmd.drawIndexedIndirect.drawCount = drawCount;
438   cmd.drawIndexedIndirect.stride    = stride;
439 }
440
441 void CommandBuffer::DrawNative(const DrawNativeInfo* drawNativeInfo)
442 {
443   auto  command = mCommandPool->AllocateCommand(CommandType::DRAW_NATIVE);
444   auto& cmd     = command->drawNative;
445   memcpy(&cmd.drawNativeInfo, drawNativeInfo, sizeof(DrawNativeInfo));
446 }
447
448 void CommandBuffer::Reset()
449 {
450   mCommandPool->Rollback(false);
451 }
452
453 void CommandBuffer::SetScissor(Graphics::Rect2D value)
454 {
455   auto command            = mCommandPool->AllocateCommand(CommandType::SET_SCISSOR);
456   command->scissor.region = value;
457 }
458
459 void CommandBuffer::SetScissorTestEnable(bool value)
460 {
461   auto command                = mCommandPool->AllocateCommand(CommandType::SET_SCISSOR_TEST);
462   command->scissorTest.enable = value;
463 }
464
465 void CommandBuffer::SetViewport(Viewport value)
466 {
467   auto command             = mCommandPool->AllocateCommand(CommandType::SET_VIEWPORT);
468   command->viewport.region = value;
469 }
470
471 void CommandBuffer::SetViewportEnable(bool value)
472 {
473   // There is no GL equivalent
474 }
475
476 void CommandBuffer::SetColorMask(bool enabled)
477 {
478   auto command               = mCommandPool->AllocateCommand(CommandType::SET_COLOR_MASK);
479   command->colorMask.enabled = enabled;
480 }
481
482 void CommandBuffer::ClearStencilBuffer()
483 {
484   mCommandPool->AllocateCommand(CommandType::CLEAR_STENCIL_BUFFER);
485 }
486
487 void CommandBuffer::SetStencilTestEnable(bool stencilEnable)
488 {
489   auto command                 = mCommandPool->AllocateCommand(CommandType::SET_STENCIL_TEST_ENABLE);
490   command->stencilTest.enabled = stencilEnable;
491 }
492
493 void CommandBuffer::SetStencilWriteMask(uint32_t writeMask)
494 {
495   auto command                   = mCommandPool->AllocateCommand(CommandType::SET_STENCIL_WRITE_MASK);
496   command->stencilWriteMask.mask = writeMask;
497 }
498
499 void CommandBuffer::SetStencilOp(Graphics::StencilOp failOp,
500                                  Graphics::StencilOp passOp,
501                                  Graphics::StencilOp depthFailOp)
502 {
503   auto  command   = mCommandPool->AllocateCommand(CommandType::SET_STENCIL_OP);
504   auto& cmd       = command->stencilOp;
505   cmd.failOp      = failOp;
506   cmd.passOp      = passOp;
507   cmd.depthFailOp = depthFailOp;
508 }
509
510 void CommandBuffer::SetStencilFunc(Graphics::CompareOp compareOp,
511                                    uint32_t            reference,
512                                    uint32_t            compareMask)
513 {
514   auto  command   = mCommandPool->AllocateCommand(CommandType::SET_STENCIL_FUNC);
515   auto& cmd       = command->stencilFunc;
516   cmd.compareOp   = compareOp;
517   cmd.compareMask = compareMask;
518   cmd.reference   = reference;
519 }
520
521 void CommandBuffer::SetDepthCompareOp(Graphics::CompareOp compareOp)
522 {
523   auto command             = mCommandPool->AllocateCommand(CommandType::SET_DEPTH_COMPARE_OP);
524   command->depth.compareOp = compareOp;
525 }
526
527 void CommandBuffer::SetDepthTestEnable(bool depthTestEnable)
528 {
529   auto command               = mCommandPool->AllocateCommand(CommandType::SET_DEPTH_TEST_ENABLE);
530   command->depth.testEnabled = depthTestEnable;
531 }
532 void CommandBuffer::SetDepthWriteEnable(bool depthWriteEnable)
533 {
534   auto command                = mCommandPool->AllocateCommand(CommandType::SET_DEPTH_WRITE_ENABLE);
535   command->depth.writeEnabled = depthWriteEnable;
536 }
537 void CommandBuffer::ClearDepthBuffer()
538 {
539   mCommandPool->AllocateCommand(CommandType::CLEAR_DEPTH_BUFFER);
540 }
541
542 void CommandBuffer::PresentRenderTarget(GLES::RenderTarget* renderTarget)
543 {
544   auto command                                 = mCommandPool->AllocateCommand(CommandType::PRESENT_RENDER_TARGET);
545   command->presentRenderTarget.targetToPresent = renderTarget;
546 }
547
548 [[nodiscard]] const Command* CommandBuffer::GetCommands(uint32_t& size) const
549 {
550   return mCommandPool->GetCommands(size);
551 }
552
553 void CommandBuffer::DestroyResource()
554 {
555   // Nothing to do
556 }
557
558 bool CommandBuffer::InitializeResource()
559 {
560   // Nothing to do
561   return true;
562 }
563
564 void CommandBuffer::DiscardResource()
565 {
566   GetController().DiscardResource(this);
567 }
568
569 std::size_t CommandBuffer::GetCapacity()
570 {
571   std::size_t total{0u};
572   if(mCommandPool)
573   {
574     total = mCommandPool->GetTotalCapacity();
575   }
576   return total;
577 }
578
579 } // namespace Dali::Graphics::GLES