Merge "Move Clipboard to TextClipboard" into devel/master
[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   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);
272
273   // reset temp bindings
274   std::fill_n(sTempBindings.begin(), MAX_UNIFORM_BUFFER_BINDINGS, NULL_DESCRIPTOR);
275
276   memset(&bindCmd.standaloneUniformsBufferBinding, 0, sizeof(UniformBufferBindingDescriptor));
277
278   // find max binding and standalone UBO
279   auto maxBinding  = 0u;
280   bool hasBindings = false;
281   for(const auto& binding : bindings)
282   {
283     if(binding.buffer)
284     {
285       auto glesBuffer = static_cast<const GLES::Buffer*>(binding.buffer);
286       if(glesBuffer->IsCPUAllocated()) // standalone uniforms
287       {
288         bindCmd.standaloneUniformsBufferBinding.buffer   = glesBuffer;
289         bindCmd.standaloneUniformsBufferBinding.binding  = binding.binding;
290         bindCmd.standaloneUniformsBufferBinding.offset   = binding.offset;
291         bindCmd.standaloneUniformsBufferBinding.emulated = true;
292       }
293       else // Bind regular UBO
294       {
295         auto& slot = sTempBindings[binding.binding];
296
297         slot.buffer     = glesBuffer;
298         slot.binding    = binding.binding;
299         slot.offset     = binding.offset;
300         slot.dataSize   = binding.dataSize;
301         slot.blockIndex = 0;
302         slot.emulated   = false;
303
304         maxBinding  = std::max(maxBinding, binding.binding);
305         hasBindings = true;
306       }
307     }
308   }
309   bindCmd.uniformBufferBindings      = nullptr;
310   bindCmd.uniformBufferBindingsCount = 0u;
311
312   // copy data
313   if(hasBindings)
314   {
315     auto destBindings = mCommandPool->Allocate<UniformBufferBindingDescriptor>(maxBinding + 1);
316     // copy
317     auto size = sizeof(UniformBufferBindingDescriptor) * (maxBinding + 1);
318     if(!(size % sizeof(intptr_t)))
319     {
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)
323       {
324         *dstPtr++ = *srcPtr++;
325       }
326     }
327     else
328     {
329       memcpy(destBindings.Ptr(), &sTempBindings[0], size);
330     }
331     bindCmd.uniformBufferBindings      = destBindings;
332     bindCmd.uniformBufferBindingsCount = maxBinding + 1;
333   }
334 }
335
336 void CommandBuffer::BindPipeline(const Graphics::Pipeline& pipeline)
337 {
338   auto command                   = mCommandPool->AllocateCommand(CommandType::BIND_PIPELINE);
339   command->bindPipeline.pipeline = static_cast<const GLES::Pipeline*>(&pipeline);
340 }
341
342 void CommandBuffer::BindTextures(const std::vector<TextureBinding>& textureBindings)
343 {
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());
349 }
350
351 void CommandBuffer::BindSamplers(const std::vector<SamplerBinding>& samplerBindings)
352 {
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());
358 }
359
360 void CommandBuffer::BindPushConstants(void*    data,
361                                       uint32_t size,
362                                       uint32_t binding)
363 {
364 }
365
366 void CommandBuffer::BindIndexBuffer(const Graphics::Buffer& buffer,
367                                     uint32_t                offset,
368                                     Format                  format)
369 {
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;
374 }
375
376 void CommandBuffer::BeginRenderPass(
377   Graphics::RenderPass*          renderPass,
378   Graphics::RenderTarget*        renderTarget,
379   Rect2D                         renderArea,
380   const std::vector<ClearValue>& clearValues)
381 {
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;
387
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();
391 }
392
393 void CommandBuffer::EndRenderPass(Graphics::SyncObject* syncObject)
394 {
395   auto command                      = mCommandPool->AllocateCommand(CommandType::END_RENDERPASS);
396   command->endRenderPass.syncObject = static_cast<GLES::SyncObject*>(syncObject);
397 }
398
399 void CommandBuffer::ExecuteCommandBuffers(std::vector<const Graphics::CommandBuffer*>&& commandBuffers)
400 {
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)
406   {
407     cmd.buffers[i] = static_cast<const GLES::CommandBuffer*>(commandBuffers[i]);
408   }
409 }
410
411 void CommandBuffer::Draw(
412   uint32_t vertexCount,
413   uint32_t instanceCount,
414   uint32_t firstVertex,
415   uint32_t firstInstance)
416 {
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;
424 }
425
426 void CommandBuffer::DrawIndexed(
427   uint32_t indexCount,
428   uint32_t instanceCount,
429   uint32_t firstIndex,
430   int32_t  vertexOffset,
431   uint32_t firstInstance)
432 {
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;
441 }
442
443 void CommandBuffer::DrawIndexedIndirect(
444   Graphics::Buffer& buffer,
445   uint32_t          offset,
446   uint32_t          drawCount,
447   uint32_t          stride)
448 {
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;
456 }
457
458 void CommandBuffer::DrawNative(const DrawNativeInfo* drawNativeInfo)
459 {
460   auto  command = mCommandPool->AllocateCommand(CommandType::DRAW_NATIVE);
461   auto& cmd     = command->drawNative;
462   memcpy(&cmd.drawNativeInfo, drawNativeInfo, sizeof(DrawNativeInfo));
463 }
464
465 void CommandBuffer::Reset()
466 {
467   mCommandPool->Rollback(false);
468 }
469
470 void CommandBuffer::SetScissor(Graphics::Rect2D value)
471 {
472   auto command            = mCommandPool->AllocateCommand(CommandType::SET_SCISSOR);
473   command->scissor.region = value;
474 }
475
476 void CommandBuffer::SetScissorTestEnable(bool value)
477 {
478   auto command                = mCommandPool->AllocateCommand(CommandType::SET_SCISSOR_TEST);
479   command->scissorTest.enable = value;
480 }
481
482 void CommandBuffer::SetViewport(Viewport value)
483 {
484   auto command             = mCommandPool->AllocateCommand(CommandType::SET_VIEWPORT);
485   command->viewport.region = value;
486 }
487
488 void CommandBuffer::SetViewportEnable(bool value)
489 {
490   // There is no GL equivalent
491 }
492
493 void CommandBuffer::SetColorMask(bool enabled)
494 {
495   auto command               = mCommandPool->AllocateCommand(CommandType::SET_COLOR_MASK);
496   command->colorMask.enabled = enabled;
497 }
498
499 void CommandBuffer::ClearStencilBuffer()
500 {
501   mCommandPool->AllocateCommand(CommandType::CLEAR_STENCIL_BUFFER);
502 }
503
504 void CommandBuffer::SetStencilTestEnable(bool stencilEnable)
505 {
506   auto command                 = mCommandPool->AllocateCommand(CommandType::SET_STENCIL_TEST_ENABLE);
507   command->stencilTest.enabled = stencilEnable;
508 }
509
510 void CommandBuffer::SetStencilWriteMask(uint32_t writeMask)
511 {
512   auto command                   = mCommandPool->AllocateCommand(CommandType::SET_STENCIL_WRITE_MASK);
513   command->stencilWriteMask.mask = writeMask;
514 }
515
516 void CommandBuffer::SetStencilOp(Graphics::StencilOp failOp,
517                                  Graphics::StencilOp passOp,
518                                  Graphics::StencilOp depthFailOp)
519 {
520   auto  command   = mCommandPool->AllocateCommand(CommandType::SET_STENCIL_OP);
521   auto& cmd       = command->stencilOp;
522   cmd.failOp      = failOp;
523   cmd.passOp      = passOp;
524   cmd.depthFailOp = depthFailOp;
525 }
526
527 void CommandBuffer::SetStencilFunc(Graphics::CompareOp compareOp,
528                                    uint32_t            reference,
529                                    uint32_t            compareMask)
530 {
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;
536 }
537
538 void CommandBuffer::SetDepthCompareOp(Graphics::CompareOp compareOp)
539 {
540   auto command             = mCommandPool->AllocateCommand(CommandType::SET_DEPTH_COMPARE_OP);
541   command->depth.compareOp = compareOp;
542 }
543
544 void CommandBuffer::SetDepthTestEnable(bool depthTestEnable)
545 {
546   auto command               = mCommandPool->AllocateCommand(CommandType::SET_DEPTH_TEST_ENABLE);
547   command->depth.testEnabled = depthTestEnable;
548 }
549 void CommandBuffer::SetDepthWriteEnable(bool depthWriteEnable)
550 {
551   auto command                = mCommandPool->AllocateCommand(CommandType::SET_DEPTH_WRITE_ENABLE);
552   command->depth.writeEnabled = depthWriteEnable;
553 }
554 void CommandBuffer::ClearDepthBuffer()
555 {
556   mCommandPool->AllocateCommand(CommandType::CLEAR_DEPTH_BUFFER);
557 }
558
559 void CommandBuffer::PresentRenderTarget(GLES::RenderTarget* renderTarget)
560 {
561   auto command                                 = mCommandPool->AllocateCommand(CommandType::PRESENT_RENDER_TARGET);
562   command->presentRenderTarget.targetToPresent = renderTarget;
563 }
564
565 [[nodiscard]] const Command* CommandBuffer::GetCommands(uint32_t& size) const
566 {
567   return mCommandPool->GetCommands(size);
568 }
569
570 void CommandBuffer::DestroyResource()
571 {
572   // Nothing to do
573 }
574
575 bool CommandBuffer::InitializeResource()
576 {
577   // Nothing to do
578   return true;
579 }
580
581 void CommandBuffer::DiscardResource()
582 {
583   GetController().DiscardResource(this);
584 }
585
586 std::size_t CommandBuffer::GetCapacity()
587 {
588   std::size_t total{0u};
589   if(mCommandPool)
590   {
591     total = mCommandPool->GetTotalCapacity();
592   }
593   return total;
594 }
595
596 } // namespace Dali::Graphics::GLES