Merge "Implement some more speed-up : don't copy geometry" into devel/master
[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;
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
229 CommandBuffer::CommandBuffer(const Graphics::CommandBufferCreateInfo& createInfo, EglGraphicsController& controller)
230 : CommandBufferResource(createInfo, controller)
231 {
232   mCommandPool = std::make_unique<CommandPool>(createInfo.fixedCapacity);
233 }
234
235 CommandBuffer::~CommandBuffer() = default;
236
237 void CommandBuffer::BindVertexBuffers(uint32_t                                    firstBinding,
238                                       const std::vector<const Graphics::Buffer*>& buffers,
239                                       const std::vector<uint32_t>&                offsets)
240 {
241   auto command                                         = mCommandPool->AllocateCommand(CommandType::BIND_VERTEX_BUFFERS);
242   command->bindVertexBuffers.vertexBufferBindingsCount = firstBinding + buffers.size();
243   auto pBindings                                       = mCommandPool->Allocate<GLES::VertexBufferBindingDescriptor>(firstBinding + buffers.size());
244
245   command->bindVertexBuffers.vertexBufferBindings = pBindings;
246   auto index                                      = firstBinding;
247   for(auto& buf : buffers)
248   {
249     pBindings[index].buffer = static_cast<const GLES::Buffer*>(buf);
250     pBindings[index].offset = offsets[index - firstBinding];
251     index++;
252   }
253 }
254
255 void CommandBuffer::BindUniformBuffers(const std::vector<Graphics::UniformBufferBinding>& bindings)
256 {
257   auto command = mCommandPool->AllocateCommand(CommandType::BIND_UNIFORM_BUFFER);
258
259   auto& cmd     = *command;
260   auto& bindCmd = cmd.bindUniformBuffers;
261
262   // temporary static set of binding slots (thread local)
263   static const auto MAX_UNIFORM_BUFFER_BINDINGS = 64; // TODO: this should be read from introspection
264
265   // TODO: could use vector?
266   static thread_local UniformBufferBindingDescriptor sTempBindings[MAX_UNIFORM_BUFFER_BINDINGS];
267
268   // reset temp bindings
269   memset(sTempBindings, 0, sizeof(UniformBufferBindingDescriptor) * MAX_UNIFORM_BUFFER_BINDINGS);
270
271   auto maxBinding = 0u;
272
273   // find max binding and standalone UBO
274   for(const auto& binding : bindings)
275   {
276     if(binding.buffer)
277     {
278       auto glesBuffer = static_cast<const GLES::Buffer*>(binding.buffer);
279       if(glesBuffer->IsCPUAllocated()) // standalone uniforms
280       {
281         bindCmd.standaloneUniformsBufferBinding.buffer   = glesBuffer;
282         bindCmd.standaloneUniformsBufferBinding.offset   = binding.offset;
283         bindCmd.standaloneUniformsBufferBinding.binding  = binding.binding;
284         bindCmd.standaloneUniformsBufferBinding.emulated = true;
285       }
286       else // Bind regular UBO
287       {
288         auto& slot    = sTempBindings[binding.binding];
289         slot.buffer   = glesBuffer;
290         slot.offset   = binding.offset;
291         slot.binding  = binding.binding;
292         slot.emulated = false;
293         maxBinding    = std::max(maxBinding, binding.binding);
294       }
295     }
296   }
297   bindCmd.uniformBufferBindings      = nullptr;
298   bindCmd.uniformBufferBindingsCount = 0u;
299
300   // copy data
301   if(maxBinding)
302   {
303     auto destBindings = mCommandPool->Allocate<UniformBufferBindingDescriptor>(maxBinding + 1);
304     // copy
305     memcpy(destBindings.Ptr(), sTempBindings, sizeof(UniformBufferBindingDescriptor) * (maxBinding + 1));
306     bindCmd.uniformBufferBindings      = destBindings;
307     bindCmd.uniformBufferBindingsCount = maxBinding + 1;
308   }
309 }
310
311 void CommandBuffer::BindPipeline(const Graphics::Pipeline& pipeline)
312 {
313   auto command                   = mCommandPool->AllocateCommand(CommandType::BIND_PIPELINE);
314   command->bindPipeline.pipeline = static_cast<const GLES::Pipeline*>(&pipeline);
315 }
316
317 void CommandBuffer::BindTextures(const std::vector<TextureBinding>& textureBindings)
318 {
319   auto  command                        = mCommandPool->AllocateCommand(CommandType::BIND_TEXTURES);
320   auto& bindTexturesCmd                = command->bindTextures;
321   bindTexturesCmd.textureBindings      = mCommandPool->Allocate<TextureBinding>(textureBindings.size());
322   bindTexturesCmd.textureBindingsCount = textureBindings.size();
323   memcpy(bindTexturesCmd.textureBindings.Ptr(), textureBindings.data(), sizeof(TextureBinding) * textureBindings.size());
324 }
325
326 void CommandBuffer::BindSamplers(const std::vector<SamplerBinding>& samplerBindings)
327 {
328   auto  command                        = mCommandPool->AllocateCommand(CommandType::BIND_SAMPLERS);
329   auto& bindSamplersCmd                = command->bindSamplers;
330   bindSamplersCmd.samplerBindings      = mCommandPool->Allocate<SamplerBinding>(samplerBindings.size());
331   bindSamplersCmd.samplerBindingsCount = samplerBindings.size();
332   memcpy(bindSamplersCmd.samplerBindings.Ptr(), samplerBindings.data(), sizeof(TextureBinding) * samplerBindings.size());
333 }
334
335 void CommandBuffer::BindPushConstants(void*    data,
336                                       uint32_t size,
337                                       uint32_t binding)
338 {
339 }
340
341 void CommandBuffer::BindIndexBuffer(const Graphics::Buffer& buffer,
342                                     uint32_t                offset,
343                                     Format                  format)
344 {
345   auto command                    = mCommandPool->AllocateCommand(CommandType::BIND_INDEX_BUFFER);
346   command->bindIndexBuffer.buffer = static_cast<const GLES::Buffer*>(&buffer);
347   command->bindIndexBuffer.offset = offset;
348   command->bindIndexBuffer.format = format;
349 }
350
351 void CommandBuffer::BeginRenderPass(
352   Graphics::RenderPass*          renderPass,
353   Graphics::RenderTarget*        renderTarget,
354   Rect2D                         renderArea,
355   const std::vector<ClearValue>& clearValues)
356 {
357   auto  command                    = mCommandPool->AllocateCommand(CommandType::BEGIN_RENDERPASS);
358   auto& cmd                        = *command;
359   cmd.beginRenderPass.renderPass   = static_cast<GLES::RenderPass*>(renderPass);
360   cmd.beginRenderPass.renderTarget = static_cast<GLES::RenderTarget*>(renderTarget);
361   cmd.beginRenderPass.renderArea   = renderArea;
362
363   cmd.beginRenderPass.clearValues = mCommandPool->Allocate<ClearValue>(clearValues.size());
364   memcpy(cmd.beginRenderPass.clearValues.Ptr(), clearValues.data(), sizeof(ClearValue) * clearValues.size());
365   cmd.beginRenderPass.clearValuesCount = clearValues.size();
366 }
367
368 void CommandBuffer::EndRenderPass(Graphics::SyncObject* syncObject)
369 {
370   auto command                      = mCommandPool->AllocateCommand(CommandType::END_RENDERPASS);
371   command->endRenderPass.syncObject = static_cast<GLES::SyncObject*>(syncObject);
372 }
373
374 void CommandBuffer::ExecuteCommandBuffers(std::vector<const Graphics::CommandBuffer*>&& commandBuffers)
375 {
376   auto  command    = mCommandPool->AllocateCommand(CommandType::EXECUTE_COMMAND_BUFFERS);
377   auto& cmd        = command->executeCommandBuffers;
378   cmd.buffers      = mCommandPool->Allocate<const GLES::CommandBuffer*>(commandBuffers.size());
379   cmd.buffersCount = commandBuffers.size();
380   for(auto i = 0u; i < cmd.buffersCount; ++i)
381   {
382     cmd.buffers[i] = static_cast<const GLES::CommandBuffer*>(commandBuffers[i]);
383   }
384 }
385
386 void CommandBuffer::Draw(
387   uint32_t vertexCount,
388   uint32_t instanceCount,
389   uint32_t firstVertex,
390   uint32_t firstInstance)
391 {
392   auto  command          = mCommandPool->AllocateCommand(CommandType::DRAW);
393   auto& cmd              = command->draw;
394   cmd.type               = DrawCallDescriptor::Type::DRAW;
395   cmd.draw.vertexCount   = vertexCount;
396   cmd.draw.instanceCount = instanceCount;
397   cmd.draw.firstInstance = firstInstance;
398   cmd.draw.firstVertex   = firstVertex;
399 }
400
401 void CommandBuffer::DrawIndexed(
402   uint32_t indexCount,
403   uint32_t instanceCount,
404   uint32_t firstIndex,
405   int32_t  vertexOffset,
406   uint32_t firstInstance)
407 {
408   auto  command                 = mCommandPool->AllocateCommand(CommandType::DRAW_INDEXED);
409   auto& cmd                     = command->draw;
410   cmd.type                      = DrawCallDescriptor::Type::DRAW_INDEXED;
411   cmd.drawIndexed.firstIndex    = firstIndex;
412   cmd.drawIndexed.firstInstance = firstInstance;
413   cmd.drawIndexed.indexCount    = indexCount;
414   cmd.drawIndexed.vertexOffset  = vertexOffset;
415   cmd.drawIndexed.instanceCount = instanceCount;
416 }
417
418 void CommandBuffer::DrawIndexedIndirect(
419   Graphics::Buffer& buffer,
420   uint32_t          offset,
421   uint32_t          drawCount,
422   uint32_t          stride)
423 {
424   auto  command                     = mCommandPool->AllocateCommand(CommandType::DRAW_INDEXED_INDIRECT);
425   auto& cmd                         = command->draw;
426   cmd.type                          = DrawCallDescriptor::Type::DRAW_INDEXED_INDIRECT;
427   cmd.drawIndexedIndirect.buffer    = static_cast<const GLES::Buffer*>(&buffer);
428   cmd.drawIndexedIndirect.offset    = offset;
429   cmd.drawIndexedIndirect.drawCount = drawCount;
430   cmd.drawIndexedIndirect.stride    = stride;
431 }
432
433 void CommandBuffer::Reset()
434 {
435   mCommandPool->Rollback(false);
436 }
437
438 void CommandBuffer::SetScissor(Graphics::Rect2D value)
439 {
440   auto command            = mCommandPool->AllocateCommand(CommandType::SET_SCISSOR);
441   command->scissor.region = value;
442 }
443
444 void CommandBuffer::SetScissorTestEnable(bool value)
445 {
446   auto command                = mCommandPool->AllocateCommand(CommandType::SET_SCISSOR_TEST);
447   command->scissorTest.enable = value;
448 }
449
450 void CommandBuffer::SetViewport(Viewport value)
451 {
452   auto command             = mCommandPool->AllocateCommand(CommandType::SET_VIEWPORT);
453   command->viewport.region = value;
454 }
455
456 void CommandBuffer::SetViewportEnable(bool value)
457 {
458   // There is no GL equivalent
459 }
460
461 void CommandBuffer::SetColorMask(bool enabled)
462 {
463   auto command               = mCommandPool->AllocateCommand(CommandType::SET_COLOR_MASK);
464   command->colorMask.enabled = enabled;
465 }
466
467 void CommandBuffer::ClearStencilBuffer()
468 {
469   mCommandPool->AllocateCommand(CommandType::CLEAR_STENCIL_BUFFER);
470 }
471
472 void CommandBuffer::SetStencilTestEnable(bool stencilEnable)
473 {
474   auto command                 = mCommandPool->AllocateCommand(CommandType::SET_STENCIL_TEST_ENABLE);
475   command->stencilTest.enabled = stencilEnable;
476 }
477
478 void CommandBuffer::SetStencilWriteMask(uint32_t writeMask)
479 {
480   auto command                   = mCommandPool->AllocateCommand(CommandType::SET_STENCIL_WRITE_MASK);
481   command->stencilWriteMask.mask = writeMask;
482 }
483
484 void CommandBuffer::SetStencilOp(Graphics::StencilOp failOp,
485                                  Graphics::StencilOp passOp,
486                                  Graphics::StencilOp depthFailOp)
487 {
488   auto  command   = mCommandPool->AllocateCommand(CommandType::SET_STENCIL_OP);
489   auto& cmd       = command->stencilOp;
490   cmd.failOp      = failOp;
491   cmd.passOp      = passOp;
492   cmd.depthFailOp = depthFailOp;
493 }
494
495 void CommandBuffer::SetStencilFunc(Graphics::CompareOp compareOp,
496                                    uint32_t            reference,
497                                    uint32_t            compareMask)
498 {
499   auto  command   = mCommandPool->AllocateCommand(CommandType::SET_STENCIL_FUNC);
500   auto& cmd       = command->stencilFunc;
501   cmd.compareOp   = compareOp;
502   cmd.compareMask = compareMask;
503   cmd.reference   = reference;
504 }
505
506 void CommandBuffer::SetDepthCompareOp(Graphics::CompareOp compareOp)
507 {
508   auto command             = mCommandPool->AllocateCommand(CommandType::SET_DEPTH_COMPARE_OP);
509   command->depth.compareOp = compareOp;
510 }
511
512 void CommandBuffer::SetDepthTestEnable(bool depthTestEnable)
513 {
514   auto command               = mCommandPool->AllocateCommand(CommandType::SET_DEPTH_TEST_ENABLE);
515   command->depth.testEnabled = depthTestEnable;
516 }
517 void CommandBuffer::SetDepthWriteEnable(bool depthWriteEnable)
518 {
519   auto command                = mCommandPool->AllocateCommand(CommandType::SET_DEPTH_WRITE_ENABLE);
520   command->depth.writeEnabled = depthWriteEnable;
521 }
522 void CommandBuffer::ClearDepthBuffer()
523 {
524   mCommandPool->AllocateCommand(CommandType::CLEAR_DEPTH_BUFFER);
525 }
526
527 void CommandBuffer::PresentRenderTarget(GLES::RenderTarget* renderTarget)
528 {
529   auto command                                 = mCommandPool->AllocateCommand(CommandType::PRESENT_RENDER_TARGET);
530   command->presentRenderTarget.targetToPresent = renderTarget;
531 }
532
533 [[nodiscard]] const Command* CommandBuffer::GetCommands(uint32_t& size) const
534 {
535   return mCommandPool->GetCommands(size);
536 }
537
538 void CommandBuffer::DestroyResource()
539 {
540   // Nothing to do
541 }
542
543 bool CommandBuffer::InitializeResource()
544 {
545   // Nothing to do
546   return true;
547 }
548
549 void CommandBuffer::DiscardResource()
550 {
551   GetController().DiscardResource(this);
552 }
553
554 } // namespace Dali::Graphics::GLES