Changes to constness of command buffer
[platform/core/uifw/dali-adaptor.git] / dali / internal / graphics / gles-impl / egl-graphics-controller.cpp
1 /*
2  * Copyright (c) 2021 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 // CLASS HEADER
18 #include <dali/internal/graphics/gles-impl/egl-graphics-controller.h>
19
20 // INTERNAL INCLUDES
21 #include <dali/integration-api/adaptor-framework/render-surface-interface.h>
22 #include <dali/integration-api/debug.h>
23 #include <dali/integration-api/gl-abstraction.h>
24 #include <dali/integration-api/gl-defines.h>
25 #include <dali/internal/graphics/gles-impl/gles-graphics-command-buffer.h>
26 #include <dali/internal/graphics/gles-impl/gles-graphics-pipeline.h>
27 #include <dali/internal/graphics/gles-impl/gles-graphics-render-pass.h>
28 #include <dali/internal/graphics/gles-impl/gles-graphics-render-target.h>
29 #include <dali/internal/graphics/gles-impl/gles-graphics-shader.h>
30 #include <dali/internal/graphics/gles-impl/gles-graphics-texture.h>
31 #include <dali/internal/graphics/gles-impl/gles-graphics-types.h>
32 #include <dali/internal/graphics/gles-impl/gles3-graphics-memory.h>
33 #include <dali/public-api/common/dali-common.h>
34 #include "gles-graphics-program.h"
35
36 namespace Dali::Graphics
37 {
38 namespace
39 {
40 /**
41  * @brief Custom deleter for all Graphics objects created
42  * with use of the Controller.
43  *
44  * When Graphics object dies the unique pointer (Graphics::UniquePtr)
45  * doesn't destroy it directly but passes the ownership back
46  * to the Controller. The GLESDeleter is responsible for passing
47  * the object to the discard queue (by calling Resource::DiscardResource()).
48  */
49 template<typename T>
50 struct GLESDeleter
51 {
52   GLESDeleter() = default;
53
54   void operator()(T* object)
55   {
56     // Discard resource (add it to discard queue)
57     object->DiscardResource();
58   }
59 };
60
61 /**
62  * @brief Helper function allocating graphics object
63  *
64  * @param[in] info Create info structure
65  * @param[in] controller Controller object
66  * @param[out] out Unique pointer to the return object
67  */
68 template<class GLESType, class GfxCreateInfo, class T>
69 auto NewObject(const GfxCreateInfo& info, EglGraphicsController& controller, T&& oldObject)
70 {
71   // Use allocator
72   using Type = typename T::element_type;
73   using UPtr = Graphics::UniquePtr<Type>;
74   if(info.allocationCallbacks)
75   {
76     auto* memory = info.allocationCallbacks->allocCallback(
77       sizeof(GLESType),
78       0,
79       info.allocationCallbacks->userData);
80     return UPtr(new(memory) GLESType(info, controller), GLESDeleter<GLESType>());
81   }
82   else // Use standard allocator
83   {
84     return UPtr(new GLESType(info, controller), GLESDeleter<GLESType>());
85   }
86 }
87
88 template<class T0, class T1>
89 T0* CastObject(T1* apiObject)
90 {
91   return static_cast<T0*>(apiObject);
92 }
93
94 } // namespace
95
96 EglGraphicsController::~EglGraphicsController() = default;
97
98 void EglGraphicsController::InitializeGLES(Integration::GlAbstraction& glAbstraction)
99 {
100   DALI_LOG_RELEASE_INFO("Initializing New Graphics Controller #1\n");
101   mGlAbstraction = &glAbstraction;
102   mContext       = std::make_unique<GLES::Context>(*this);
103 }
104
105 void EglGraphicsController::Initialize(Integration::GlSyncAbstraction&          glSyncAbstraction,
106                                        Integration::GlContextHelperAbstraction& glContextHelperAbstraction,
107                                        Internal::Adaptor::GraphicsInterface&    graphicsInterface)
108 {
109   DALI_LOG_RELEASE_INFO("Initializing New Graphics Controller #2\n");
110   mGlSyncAbstraction          = &glSyncAbstraction;
111   mGlContextHelperAbstraction = &glContextHelperAbstraction;
112   mGraphics                   = &graphicsInterface;
113 }
114
115 void EglGraphicsController::SubmitCommandBuffers(const SubmitInfo& submitInfo)
116 {
117   for(auto& cmdbuf : submitInfo.cmdBuffer)
118   {
119     // Push command buffers
120     mCommandQueue.push(static_cast<GLES::CommandBuffer*>(cmdbuf));
121   }
122
123   // If flush bit set, flush all pending tasks
124   if(submitInfo.flags & (0 | SubmitFlagBits::FLUSH))
125   {
126     Flush();
127   }
128 }
129
130 void EglGraphicsController::PresentRenderTarget(RenderTarget* renderTarget)
131 {
132   // Use command buffer to execute presentation (we should pool it)
133   CommandBufferCreateInfo info;
134   info.SetLevel(CommandBufferLevel::PRIMARY);
135   info.fixedCapacity        = 1; // only one command
136   auto presentCommandBuffer = new GLES::CommandBuffer(info, *this);
137   presentCommandBuffer->PresentRenderTarget(static_cast<GLES::RenderTarget*>(renderTarget));
138   SubmitInfo submitInfo;
139   submitInfo.cmdBuffer = {presentCommandBuffer};
140   submitInfo.flags     = 0 | SubmitFlagBits::FLUSH;
141   SubmitCommandBuffers(submitInfo);
142 }
143
144 void EglGraphicsController::ResolvePresentRenderTarget(GLES::RenderTarget* renderTarget)
145 {
146   auto* rt = static_cast<GLES::RenderTarget*>(renderTarget);
147   if(rt->GetCreateInfo().surface)
148   {
149     auto* surfaceInterface = reinterpret_cast<Dali::RenderSurfaceInterface*>(rt->GetCreateInfo().surface);
150     surfaceInterface->MakeContextCurrent();
151     surfaceInterface->PostRender();
152   }
153 }
154
155 Integration::GlAbstraction& EglGraphicsController::GetGlAbstraction()
156 {
157   DALI_ASSERT_DEBUG(mGlAbstraction && "Graphics controller not initialized");
158   return *mGlAbstraction;
159 }
160
161 Integration::GlSyncAbstraction& EglGraphicsController::GetGlSyncAbstraction()
162 {
163   DALI_ASSERT_DEBUG(mGlSyncAbstraction && "Graphics controller not initialized");
164   return *mGlSyncAbstraction;
165 }
166
167 Integration::GlContextHelperAbstraction& EglGraphicsController::GetGlContextHelperAbstraction()
168 {
169   DALI_ASSERT_DEBUG(mGlContextHelperAbstraction && "Graphics controller not initialized");
170   return *mGlContextHelperAbstraction;
171 }
172
173 Graphics::UniquePtr<CommandBuffer> EglGraphicsController::CreateCommandBuffer(
174   const CommandBufferCreateInfo&       commandBufferCreateInfo,
175   Graphics::UniquePtr<CommandBuffer>&& oldCommandBuffer)
176 {
177   return NewObject<GLES::CommandBuffer>(commandBufferCreateInfo, *this, std::move(oldCommandBuffer));
178 }
179
180 Graphics::UniquePtr<RenderPass> EglGraphicsController::CreateRenderPass(const RenderPassCreateInfo& renderPassCreateInfo, Graphics::UniquePtr<RenderPass>&& oldRenderPass)
181 {
182   return NewObject<GLES::RenderPass>(renderPassCreateInfo, *this, std::move(oldRenderPass));
183 }
184
185 Graphics::UniquePtr<Texture>
186 EglGraphicsController::CreateTexture(const TextureCreateInfo& textureCreateInfo, Graphics::UniquePtr<Texture>&& oldTexture)
187 {
188   return NewObject<GLES::Texture>(textureCreateInfo, *this, std::move(oldTexture));
189 }
190
191 Graphics::UniquePtr<Buffer> EglGraphicsController::CreateBuffer(
192   const BufferCreateInfo& bufferCreateInfo, Graphics::UniquePtr<Buffer>&& oldBuffer)
193 {
194   return NewObject<GLES::Buffer>(bufferCreateInfo, *this, std::move(oldBuffer));
195 }
196
197 Graphics::UniquePtr<Framebuffer> EglGraphicsController::CreateFramebuffer(
198   const FramebufferCreateInfo& framebufferCreateInfo, Graphics::UniquePtr<Framebuffer>&& oldFramebuffer)
199 {
200   return NewObject<GLES::Framebuffer>(framebufferCreateInfo, *this, std::move(oldFramebuffer));
201 }
202
203 Graphics::UniquePtr<Pipeline> EglGraphicsController::CreatePipeline(
204   const PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr<Graphics::Pipeline>&& oldPipeline)
205 {
206   // Create pipeline cache if needed
207   if(!mPipelineCache)
208   {
209     mPipelineCache = std::make_unique<GLES::PipelineCache>(*this);
210   }
211
212   return mPipelineCache->GetPipeline(pipelineCreateInfo, std::move(oldPipeline));
213 }
214
215 Graphics::UniquePtr<Program> EglGraphicsController::CreateProgram(
216   const ProgramCreateInfo& programCreateInfo, UniquePtr<Program>&& oldProgram)
217 {
218   // Create program cache if needed
219   if(!mPipelineCache)
220   {
221     mPipelineCache = std::make_unique<GLES::PipelineCache>(*this);
222   }
223
224   return mPipelineCache->GetProgram(programCreateInfo, std::move(oldProgram));
225 }
226
227 Graphics::UniquePtr<Shader> EglGraphicsController::CreateShader(const ShaderCreateInfo& shaderCreateInfo, Graphics::UniquePtr<Shader>&& oldShader)
228 {
229   return NewObject<GLES::Shader>(shaderCreateInfo, *this, std::move(oldShader));
230 }
231
232 Graphics::UniquePtr<Sampler> EglGraphicsController::CreateSampler(const SamplerCreateInfo& samplerCreateInfo, Graphics::UniquePtr<Sampler>&& oldSampler)
233 {
234   return NewObject<GLES::Sampler>(samplerCreateInfo, *this, std::move(oldSampler));
235 }
236
237 Graphics::UniquePtr<RenderTarget> EglGraphicsController::CreateRenderTarget(const RenderTargetCreateInfo& renderTargetCreateInfo, Graphics::UniquePtr<RenderTarget>&& oldRenderTarget)
238 {
239   return NewObject<GLES::RenderTarget>(renderTargetCreateInfo, *this, std::move(oldRenderTarget));
240 }
241
242 const Graphics::Reflection& EglGraphicsController::GetProgramReflection(const Graphics::Program& program)
243 {
244   return static_cast<const Graphics::GLES::Program*>(&program)->GetReflection();
245 }
246
247 void EglGraphicsController::AddTexture(GLES::Texture& texture)
248 {
249   // Assuming we are on the correct context
250   mCreateTextureQueue.push(&texture);
251 }
252
253 void EglGraphicsController::AddBuffer(GLES::Buffer& buffer)
254 {
255   // Assuming we are on the correct context
256   mCreateBufferQueue.push(&buffer);
257 }
258
259 void EglGraphicsController::AddFramebuffer(GLES::Framebuffer& framebuffer)
260 {
261   // Assuming we are on the correct context
262   mCreateFramebufferQueue.push(&framebuffer);
263 }
264
265 void EglGraphicsController::ProcessDiscardQueues()
266 {
267   // Process textures
268   ProcessDiscardQueue<GLES::Texture>(mDiscardTextureQueue);
269
270   // Process buffers
271   ProcessDiscardQueue<GLES::Buffer>(mDiscardBufferQueue);
272
273   // Process Framebuffers
274   ProcessDiscardQueue<GLES::Framebuffer>(mDiscardFramebufferQueue);
275
276   // Process pipelines
277   ProcessDiscardQueue<GLES::Pipeline>(mDiscardPipelineQueue);
278
279   // Process programs
280   ProcessDiscardQueue<GLES::Program>(mDiscardProgramQueue);
281
282   // Process shaders
283   ProcessDiscardQueue<GLES::Shader>(mDiscardShaderQueue);
284
285   // Process samplers
286   ProcessDiscardQueue<GLES::Sampler>(mDiscardSamplerQueue);
287
288   // Process command buffers
289   ProcessDiscardQueue<GLES::CommandBuffer>(mDiscardCommandBufferQueue);
290 }
291
292 void EglGraphicsController::ProcessCreateQueues()
293 {
294   // Process textures
295   ProcessCreateQueue(mCreateTextureQueue);
296
297   // Process buffers
298   ProcessCreateQueue(mCreateBufferQueue);
299
300   // Process framebuffers
301   ProcessCreateQueue(mCreateFramebufferQueue);
302 }
303
304 void EglGraphicsController::ProcessCommandBuffer(const GLES::CommandBuffer& commandBuffer)
305 {
306   for(auto& cmd : commandBuffer.GetCommands())
307   {
308     // process command
309     switch(cmd.type)
310     {
311       case GLES::CommandType::FLUSH:
312       {
313         // Nothing to do here
314         break;
315       }
316       case GLES::CommandType::BIND_TEXTURES:
317       {
318         mContext->BindTextures(cmd.bindTextures.textureBindings);
319         break;
320       }
321       case GLES::CommandType::BIND_VERTEX_BUFFERS:
322       {
323         auto& bindings = cmd.bindVertexBuffers.vertexBufferBindings;
324         mContext->BindVertexBuffers(bindings);
325         break;
326       }
327       case GLES::CommandType::BIND_UNIFORM_BUFFER:
328       {
329         auto& bindings = cmd.bindUniformBuffers;
330         mContext->BindUniformBuffers(bindings.uniformBufferBindings, bindings.standaloneUniformsBufferBinding);
331         break;
332       }
333       case GLES::CommandType::BIND_INDEX_BUFFER:
334       {
335         mContext->BindIndexBuffer(cmd.bindIndexBuffer);
336         break;
337       }
338       case GLES::CommandType::BIND_SAMPLERS:
339       {
340         break;
341       }
342       case GLES::CommandType::BIND_PIPELINE:
343       {
344         auto pipeline = static_cast<const GLES::Pipeline*>(cmd.bindPipeline.pipeline);
345         mContext->BindPipeline(pipeline);
346         break;
347       }
348       case GLES::CommandType::DRAW:
349       {
350         mContext->Flush(false, cmd.draw);
351         break;
352       }
353       case GLES::CommandType::DRAW_INDEXED:
354       {
355         mContext->Flush(false, cmd.draw);
356         break;
357       }
358       case GLES::CommandType::DRAW_INDEXED_INDIRECT:
359       {
360         mContext->Flush(false, cmd.draw);
361         break;
362       }
363       case GLES::CommandType::SET_SCISSOR: // @todo Consider correcting for orientation here?
364       {
365         mGlAbstraction->Scissor(cmd.scissor.region.x, cmd.scissor.region.y, cmd.scissor.region.width, cmd.scissor.region.height);
366         break;
367       }
368       case GLES::CommandType::SET_SCISSOR_TEST:
369       {
370         if(cmd.scissorTest.enable)
371         {
372           mGlAbstraction->Enable(GL_SCISSOR_TEST);
373         }
374         else
375         {
376           mGlAbstraction->Disable(GL_SCISSOR_TEST);
377         }
378         break;
379       }
380       case GLES::CommandType::SET_VIEWPORT: // @todo Consider correcting for orientation here?
381       {
382         mGlAbstraction->Viewport(cmd.viewport.region.x, cmd.viewport.region.y, cmd.viewport.region.width, cmd.viewport.region.height);
383         break;
384       }
385       case GLES::CommandType::BEGIN_RENDERPASS:
386       {
387         mContext->BeginRenderPass(cmd.beginRenderPass);
388         break;
389       }
390       case GLES::CommandType::END_RENDERPASS:
391       {
392         mContext->EndRenderPass();
393         break;
394       }
395       case GLES::CommandType::PRESENT_RENDER_TARGET:
396       {
397         ResolvePresentRenderTarget(cmd.presentRenderTarget.targetToPresent);
398
399         // push this command buffer to the discard queue
400         mDiscardCommandBufferQueue.push(const_cast<GLES::CommandBuffer*>(&commandBuffer));
401         break;
402       }
403       case GLES::CommandType::EXECUTE_COMMAND_BUFFERS:
404       {
405         // Process secondary command buffers
406         // todo: check validity of the secondaries
407         //       there are operations which are illigal to be done
408         //       within secondaries.
409         for(auto& buf : cmd.executeCommandBuffers.buffers)
410         {
411           ProcessCommandBuffer(*static_cast<const GLES::CommandBuffer*>(buf));
412         }
413         break;
414       }
415     }
416   }
417 }
418
419 void EglGraphicsController::ProcessCommandQueues()
420 {
421   // TODO: command queue per context, sync between queues should be
422   // done externally
423   currentFramebuffer = nullptr;
424
425   while(!mCommandQueue.empty())
426   {
427     auto cmdBuf = mCommandQueue.front();
428     mCommandQueue.pop();
429     ProcessCommandBuffer(*cmdBuf);
430   }
431 }
432
433 void EglGraphicsController::ProcessTextureUpdateQueue()
434 {
435   while(!mTextureUpdateRequests.empty())
436   {
437     TextureUpdateRequest& request = mTextureUpdateRequests.front();
438
439     auto& info   = request.first;
440     auto& source = request.second;
441
442     if(source.sourceType == Graphics::TextureUpdateSourceInfo::Type::MEMORY)
443     {
444       // GPU memory must be already allocated (glTexImage2D())
445       auto*       texture    = static_cast<GLES::Texture*>(info.dstTexture);
446       const auto& createInfo = texture->GetCreateInfo();
447
448       mGlAbstraction->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
449
450       mGlAbstraction->BindTexture(GL_TEXTURE_2D, texture->GetGLTexture());
451       mGlAbstraction->TexSubImage2D(GL_TEXTURE_2D,
452                                     info.level,
453                                     info.dstOffset2D.x,
454                                     info.dstOffset2D.y,
455                                     info.srcExtent2D.width,
456                                     info.srcExtent2D.height,
457                                     GLES::GLTextureFormatType(createInfo.format).format,
458                                     GLES::GLTextureFormatType(createInfo.format).type,
459                                     source.memorySource.memory);
460
461       // free staging memory
462       free(source.memorySource.memory);
463     }
464     else
465     {
466       // TODO: other sources
467     }
468
469     mTextureUpdateRequests.pop();
470   }
471 }
472
473 void EglGraphicsController::UpdateTextures(const std::vector<TextureUpdateInfo>&       updateInfoList,
474                                            const std::vector<TextureUpdateSourceInfo>& sourceList)
475 {
476   // Store updates
477   for(auto& info : updateInfoList)
478   {
479     mTextureUpdateRequests.push(std::make_pair(info, sourceList[info.srcReference]));
480     auto& pair = mTextureUpdateRequests.back();
481     switch(pair.second.sourceType)
482     {
483       case Graphics::TextureUpdateSourceInfo::Type::MEMORY:
484       {
485         auto& info   = pair.first;
486         auto& source = pair.second;
487
488         // allocate staging memory and copy the data
489         // TODO: using PBO with GLES3, this is just naive
490         // oldschool way
491
492         char* stagingBuffer = reinterpret_cast<char*>(malloc(info.srcSize));
493         std::copy(&reinterpret_cast<char*>(source.memorySource.memory)[info.srcOffset],
494                   reinterpret_cast<char*>(source.memorySource.memory) + info.srcSize,
495                   stagingBuffer);
496
497         // store staging buffer
498         source.memorySource.memory = stagingBuffer;
499         break;
500       }
501       case Graphics::TextureUpdateSourceInfo::Type::BUFFER:
502       {
503         // TODO, with PBO support
504         break;
505       }
506       case Graphics::TextureUpdateSourceInfo::Type::TEXTURE:
507       {
508         // TODO texture 2 texture in-GPU copy
509         break;
510       }
511     }
512   }
513 }
514
515 Graphics::UniquePtr<Memory> EglGraphicsController::MapBufferRange(const MapBufferInfo& mapInfo)
516 {
517   mGraphics->ActivateResourceContext();
518
519   // Mapping buffer requires the object to be created NOW
520   // Workaround - flush now, otherwise there will be given a staging buffer
521   // in case when the buffer is not there yet
522   ProcessCreateQueues();
523
524   if(GetGLESVersion() < GLES::GLESVersion::GLES_30)
525   {
526     return Graphics::UniquePtr<Memory>(new GLES::Memory2(mapInfo, *this));
527   }
528   else
529   {
530     return Graphics::UniquePtr<Memory>(new GLES::Memory3(mapInfo, *this));
531   }
532 }
533
534 bool EglGraphicsController::GetProgramParameter(Graphics::Program& program, uint32_t parameterId, void* outData)
535 {
536   return static_cast<GLES::Program*>(&program)->GetImplementation()->GetParameter(parameterId, outData);
537 }
538
539 GLES::PipelineCache& EglGraphicsController::GetPipelineCache() const
540 {
541   return *mPipelineCache;
542 }
543
544 } // namespace Dali::Graphics