Memory Pool Logging
[platform/core/uifw/dali-adaptor.git] / dali / internal / graphics / gles-impl / gles-graphics-command-buffer.cpp
1 /*
2  * Copyright (c) 2022 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   // reset temp bindings
274   memset(sTempBindings, 0, sizeof(UniformBufferBindingDescriptor) * MAX_UNIFORM_BUFFER_BINDINGS);
275
276   auto maxBinding = 0u;
277
278   // find max binding and standalone UBO
279   for(const auto& binding : bindings)
280   {
281     if(binding.buffer)
282     {
283       auto glesBuffer = static_cast<const GLES::Buffer*>(binding.buffer);
284       if(glesBuffer->IsCPUAllocated()) // standalone uniforms
285       {
286         bindCmd.standaloneUniformsBufferBinding.buffer   = glesBuffer;
287         bindCmd.standaloneUniformsBufferBinding.offset   = binding.offset;
288         bindCmd.standaloneUniformsBufferBinding.binding  = binding.binding;
289         bindCmd.standaloneUniformsBufferBinding.emulated = true;
290       }
291       else // Bind regular UBO
292       {
293         auto& slot    = sTempBindings[binding.binding];
294         slot.buffer   = glesBuffer;
295         slot.offset   = binding.offset;
296         slot.binding  = binding.binding;
297         slot.emulated = false;
298         maxBinding    = std::max(maxBinding, binding.binding);
299       }
300     }
301   }
302   bindCmd.uniformBufferBindings      = nullptr;
303   bindCmd.uniformBufferBindingsCount = 0u;
304
305   // copy data
306   if(maxBinding)
307   {
308     auto destBindings = mCommandPool->Allocate<UniformBufferBindingDescriptor>(maxBinding + 1);
309     // copy
310     memcpy(destBindings.Ptr(), sTempBindings, sizeof(UniformBufferBindingDescriptor) * (maxBinding + 1));
311     bindCmd.uniformBufferBindings      = destBindings;
312     bindCmd.uniformBufferBindingsCount = maxBinding + 1;
313   }
314 }
315
316 void CommandBuffer::BindPipeline(const Graphics::Pipeline& pipeline)
317 {
318   auto command                   = mCommandPool->AllocateCommand(CommandType::BIND_PIPELINE);
319   command->bindPipeline.pipeline = static_cast<const GLES::Pipeline*>(&pipeline);
320 }
321
322 void CommandBuffer::BindTextures(const std::vector<TextureBinding>& textureBindings)
323 {
324   auto  command                        = mCommandPool->AllocateCommand(CommandType::BIND_TEXTURES);
325   auto& bindTexturesCmd                = command->bindTextures;
326   bindTexturesCmd.textureBindings      = mCommandPool->Allocate<TextureBinding>(textureBindings.size());
327   bindTexturesCmd.textureBindingsCount = textureBindings.size();
328   memcpy(bindTexturesCmd.textureBindings.Ptr(), textureBindings.data(), sizeof(TextureBinding) * textureBindings.size());
329 }
330
331 void CommandBuffer::BindSamplers(const std::vector<SamplerBinding>& samplerBindings)
332 {
333   auto  command                        = mCommandPool->AllocateCommand(CommandType::BIND_SAMPLERS);
334   auto& bindSamplersCmd                = command->bindSamplers;
335   bindSamplersCmd.samplerBindings      = mCommandPool->Allocate<SamplerBinding>(samplerBindings.size());
336   bindSamplersCmd.samplerBindingsCount = samplerBindings.size();
337   memcpy(bindSamplersCmd.samplerBindings.Ptr(), samplerBindings.data(), sizeof(TextureBinding) * samplerBindings.size());
338 }
339
340 void CommandBuffer::BindPushConstants(void*    data,
341                                       uint32_t size,
342                                       uint32_t binding)
343 {
344 }
345
346 void CommandBuffer::BindIndexBuffer(const Graphics::Buffer& buffer,
347                                     uint32_t                offset,
348                                     Format                  format)
349 {
350   auto command                    = mCommandPool->AllocateCommand(CommandType::BIND_INDEX_BUFFER);
351   command->bindIndexBuffer.buffer = static_cast<const GLES::Buffer*>(&buffer);
352   command->bindIndexBuffer.offset = offset;
353   command->bindIndexBuffer.format = format;
354 }
355
356 void CommandBuffer::BeginRenderPass(
357   Graphics::RenderPass*          renderPass,
358   Graphics::RenderTarget*        renderTarget,
359   Rect2D                         renderArea,
360   const std::vector<ClearValue>& clearValues)
361 {
362   auto  command                    = mCommandPool->AllocateCommand(CommandType::BEGIN_RENDERPASS);
363   auto& cmd                        = *command;
364   cmd.beginRenderPass.renderPass   = static_cast<GLES::RenderPass*>(renderPass);
365   cmd.beginRenderPass.renderTarget = static_cast<GLES::RenderTarget*>(renderTarget);
366   cmd.beginRenderPass.renderArea   = renderArea;
367
368   cmd.beginRenderPass.clearValues = mCommandPool->Allocate<ClearValue>(clearValues.size());
369   memcpy(cmd.beginRenderPass.clearValues.Ptr(), clearValues.data(), sizeof(ClearValue) * clearValues.size());
370   cmd.beginRenderPass.clearValuesCount = clearValues.size();
371 }
372
373 void CommandBuffer::EndRenderPass(Graphics::SyncObject* syncObject)
374 {
375   auto command                      = mCommandPool->AllocateCommand(CommandType::END_RENDERPASS);
376   command->endRenderPass.syncObject = static_cast<GLES::SyncObject*>(syncObject);
377 }
378
379 void CommandBuffer::ExecuteCommandBuffers(std::vector<const Graphics::CommandBuffer*>&& commandBuffers)
380 {
381   auto  command    = mCommandPool->AllocateCommand(CommandType::EXECUTE_COMMAND_BUFFERS);
382   auto& cmd        = command->executeCommandBuffers;
383   cmd.buffers      = mCommandPool->Allocate<const GLES::CommandBuffer*>(commandBuffers.size());
384   cmd.buffersCount = commandBuffers.size();
385   for(auto i = 0u; i < cmd.buffersCount; ++i)
386   {
387     cmd.buffers[i] = static_cast<const GLES::CommandBuffer*>(commandBuffers[i]);
388   }
389 }
390
391 void CommandBuffer::Draw(
392   uint32_t vertexCount,
393   uint32_t instanceCount,
394   uint32_t firstVertex,
395   uint32_t firstInstance)
396 {
397   auto  command          = mCommandPool->AllocateCommand(CommandType::DRAW);
398   auto& cmd              = command->draw;
399   cmd.type               = DrawCallDescriptor::Type::DRAW;
400   cmd.draw.vertexCount   = vertexCount;
401   cmd.draw.instanceCount = instanceCount;
402   cmd.draw.firstInstance = firstInstance;
403   cmd.draw.firstVertex   = firstVertex;
404 }
405
406 void CommandBuffer::DrawIndexed(
407   uint32_t indexCount,
408   uint32_t instanceCount,
409   uint32_t firstIndex,
410   int32_t  vertexOffset,
411   uint32_t firstInstance)
412 {
413   auto  command                 = mCommandPool->AllocateCommand(CommandType::DRAW_INDEXED);
414   auto& cmd                     = command->draw;
415   cmd.type                      = DrawCallDescriptor::Type::DRAW_INDEXED;
416   cmd.drawIndexed.firstIndex    = firstIndex;
417   cmd.drawIndexed.firstInstance = firstInstance;
418   cmd.drawIndexed.indexCount    = indexCount;
419   cmd.drawIndexed.vertexOffset  = vertexOffset;
420   cmd.drawIndexed.instanceCount = instanceCount;
421 }
422
423 void CommandBuffer::DrawIndexedIndirect(
424   Graphics::Buffer& buffer,
425   uint32_t          offset,
426   uint32_t          drawCount,
427   uint32_t          stride)
428 {
429   auto  command                     = mCommandPool->AllocateCommand(CommandType::DRAW_INDEXED_INDIRECT);
430   auto& cmd                         = command->draw;
431   cmd.type                          = DrawCallDescriptor::Type::DRAW_INDEXED_INDIRECT;
432   cmd.drawIndexedIndirect.buffer    = static_cast<const GLES::Buffer*>(&buffer);
433   cmd.drawIndexedIndirect.offset    = offset;
434   cmd.drawIndexedIndirect.drawCount = drawCount;
435   cmd.drawIndexedIndirect.stride    = stride;
436 }
437
438 void CommandBuffer::DrawNative(const DrawNativeInfo* drawNativeInfo)
439 {
440   auto  command = mCommandPool->AllocateCommand(CommandType::DRAW_NATIVE);
441   auto& cmd     = command->drawNative;
442   memcpy(&cmd.drawNativeInfo, drawNativeInfo, sizeof(DrawNativeInfo));
443 }
444
445 void CommandBuffer::Reset()
446 {
447   mCommandPool->Rollback(false);
448 }
449
450 void CommandBuffer::SetScissor(Graphics::Rect2D value)
451 {
452   auto command            = mCommandPool->AllocateCommand(CommandType::SET_SCISSOR);
453   command->scissor.region = value;
454 }
455
456 void CommandBuffer::SetScissorTestEnable(bool value)
457 {
458   auto command                = mCommandPool->AllocateCommand(CommandType::SET_SCISSOR_TEST);
459   command->scissorTest.enable = value;
460 }
461
462 void CommandBuffer::SetViewport(Viewport value)
463 {
464   auto command             = mCommandPool->AllocateCommand(CommandType::SET_VIEWPORT);
465   command->viewport.region = value;
466 }
467
468 void CommandBuffer::SetViewportEnable(bool value)
469 {
470   // There is no GL equivalent
471 }
472
473 void CommandBuffer::SetColorMask(bool enabled)
474 {
475   auto command               = mCommandPool->AllocateCommand(CommandType::SET_COLOR_MASK);
476   command->colorMask.enabled = enabled;
477 }
478
479 void CommandBuffer::ClearStencilBuffer()
480 {
481   mCommandPool->AllocateCommand(CommandType::CLEAR_STENCIL_BUFFER);
482 }
483
484 void CommandBuffer::SetStencilTestEnable(bool stencilEnable)
485 {
486   auto command                 = mCommandPool->AllocateCommand(CommandType::SET_STENCIL_TEST_ENABLE);
487   command->stencilTest.enabled = stencilEnable;
488 }
489
490 void CommandBuffer::SetStencilWriteMask(uint32_t writeMask)
491 {
492   auto command                   = mCommandPool->AllocateCommand(CommandType::SET_STENCIL_WRITE_MASK);
493   command->stencilWriteMask.mask = writeMask;
494 }
495
496 void CommandBuffer::SetStencilOp(Graphics::StencilOp failOp,
497                                  Graphics::StencilOp passOp,
498                                  Graphics::StencilOp depthFailOp)
499 {
500   auto  command   = mCommandPool->AllocateCommand(CommandType::SET_STENCIL_OP);
501   auto& cmd       = command->stencilOp;
502   cmd.failOp      = failOp;
503   cmd.passOp      = passOp;
504   cmd.depthFailOp = depthFailOp;
505 }
506
507 void CommandBuffer::SetStencilFunc(Graphics::CompareOp compareOp,
508                                    uint32_t            reference,
509                                    uint32_t            compareMask)
510 {
511   auto  command   = mCommandPool->AllocateCommand(CommandType::SET_STENCIL_FUNC);
512   auto& cmd       = command->stencilFunc;
513   cmd.compareOp   = compareOp;
514   cmd.compareMask = compareMask;
515   cmd.reference   = reference;
516 }
517
518 void CommandBuffer::SetDepthCompareOp(Graphics::CompareOp compareOp)
519 {
520   auto command             = mCommandPool->AllocateCommand(CommandType::SET_DEPTH_COMPARE_OP);
521   command->depth.compareOp = compareOp;
522 }
523
524 void CommandBuffer::SetDepthTestEnable(bool depthTestEnable)
525 {
526   auto command               = mCommandPool->AllocateCommand(CommandType::SET_DEPTH_TEST_ENABLE);
527   command->depth.testEnabled = depthTestEnable;
528 }
529 void CommandBuffer::SetDepthWriteEnable(bool depthWriteEnable)
530 {
531   auto command                = mCommandPool->AllocateCommand(CommandType::SET_DEPTH_WRITE_ENABLE);
532   command->depth.writeEnabled = depthWriteEnable;
533 }
534 void CommandBuffer::ClearDepthBuffer()
535 {
536   mCommandPool->AllocateCommand(CommandType::CLEAR_DEPTH_BUFFER);
537 }
538
539 void CommandBuffer::PresentRenderTarget(GLES::RenderTarget* renderTarget)
540 {
541   auto command                                 = mCommandPool->AllocateCommand(CommandType::PRESENT_RENDER_TARGET);
542   command->presentRenderTarget.targetToPresent = renderTarget;
543 }
544
545 [[nodiscard]] const Command* CommandBuffer::GetCommands(uint32_t& size) const
546 {
547   return mCommandPool->GetCommands(size);
548 }
549
550 void CommandBuffer::DestroyResource()
551 {
552   // Nothing to do
553 }
554
555 bool CommandBuffer::InitializeResource()
556 {
557   // Nothing to do
558   return true;
559 }
560
561 void CommandBuffer::DiscardResource()
562 {
563   GetController().DiscardResource(this);
564 }
565
566 std::size_t CommandBuffer::GetCapacity()
567 {
568   std::size_t total{0u};
569   if(mCommandPool)
570   {
571     total = mCommandPool->GetTotalCapacity();
572   }
573   return total;
574 }
575
576 } // namespace Dali::Graphics::GLES