Merge "Adding sampler uniforms to GLES::Program/Reflection" into devel/graphics
[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   mCurrentContext = mContext.get();
104 }
105
106 void EglGraphicsController::Initialize(Integration::GlSyncAbstraction&          glSyncAbstraction,
107                                        Integration::GlContextHelperAbstraction& glContextHelperAbstraction,
108                                        Internal::Adaptor::GraphicsInterface&    graphicsInterface)
109 {
110   DALI_LOG_RELEASE_INFO("Initializing New Graphics Controller #2\n");
111   mGlSyncAbstraction          = &glSyncAbstraction;
112   mGlContextHelperAbstraction = &glContextHelperAbstraction;
113   mGraphics                   = &graphicsInterface;
114 }
115
116 void EglGraphicsController::SubmitCommandBuffers(const SubmitInfo& submitInfo)
117 {
118   for(auto& cmdbuf : submitInfo.cmdBuffer)
119   {
120     // Push command buffers
121     mCommandQueue.push(static_cast<GLES::CommandBuffer*>(cmdbuf));
122   }
123
124   // If flush bit set, flush all pending tasks
125   if(submitInfo.flags & (0 | SubmitFlagBits::FLUSH))
126   {
127     Flush();
128   }
129 }
130
131 void EglGraphicsController::PresentRenderTarget(RenderTarget* renderTarget)
132 {
133   // Use command buffer to execute presentation (we should pool it)
134   CommandBufferCreateInfo info;
135   info.SetLevel(CommandBufferLevel::PRIMARY);
136   info.fixedCapacity        = 1; // only one command
137   auto presentCommandBuffer = new GLES::CommandBuffer(info, *this);
138   presentCommandBuffer->PresentRenderTarget(static_cast<GLES::RenderTarget*>(renderTarget));
139   SubmitInfo submitInfo;
140   submitInfo.cmdBuffer = {presentCommandBuffer};
141   submitInfo.flags     = 0 | SubmitFlagBits::FLUSH;
142   SubmitCommandBuffers(submitInfo);
143 }
144
145 void EglGraphicsController::ResolvePresentRenderTarget(GLES::RenderTarget* renderTarget)
146 {
147   auto* rt = static_cast<GLES::RenderTarget*>(renderTarget);
148   if(rt->GetCreateInfo().surface)
149   {
150     auto* surfaceInterface = reinterpret_cast<Dali::RenderSurfaceInterface*>(rt->GetCreateInfo().surface);
151     surfaceInterface->MakeContextCurrent();
152     surfaceInterface->PostRender();
153   }
154 }
155
156 Integration::GlAbstraction& EglGraphicsController::GetGlAbstraction()
157 {
158   DALI_ASSERT_DEBUG(mGlAbstraction && "Graphics controller not initialized");
159   return *mGlAbstraction;
160 }
161
162 Integration::GlSyncAbstraction& EglGraphicsController::GetGlSyncAbstraction()
163 {
164   DALI_ASSERT_DEBUG(mGlSyncAbstraction && "Graphics controller not initialized");
165   return *mGlSyncAbstraction;
166 }
167
168 Integration::GlContextHelperAbstraction& EglGraphicsController::GetGlContextHelperAbstraction()
169 {
170   DALI_ASSERT_DEBUG(mGlContextHelperAbstraction && "Graphics controller not initialized");
171   return *mGlContextHelperAbstraction;
172 }
173
174 Graphics::UniquePtr<CommandBuffer> EglGraphicsController::CreateCommandBuffer(
175   const CommandBufferCreateInfo&       commandBufferCreateInfo,
176   Graphics::UniquePtr<CommandBuffer>&& oldCommandBuffer)
177 {
178   return NewObject<GLES::CommandBuffer>(commandBufferCreateInfo, *this, std::move(oldCommandBuffer));
179 }
180
181 Graphics::UniquePtr<RenderPass> EglGraphicsController::CreateRenderPass(const RenderPassCreateInfo& renderPassCreateInfo, Graphics::UniquePtr<RenderPass>&& oldRenderPass)
182 {
183   return NewObject<GLES::RenderPass>(renderPassCreateInfo, *this, std::move(oldRenderPass));
184 }
185
186 Graphics::UniquePtr<Texture>
187 EglGraphicsController::CreateTexture(const TextureCreateInfo& textureCreateInfo, Graphics::UniquePtr<Texture>&& oldTexture)
188 {
189   return NewObject<GLES::Texture>(textureCreateInfo, *this, std::move(oldTexture));
190 }
191
192 Graphics::UniquePtr<Buffer> EglGraphicsController::CreateBuffer(
193   const BufferCreateInfo& bufferCreateInfo, Graphics::UniquePtr<Buffer>&& oldBuffer)
194 {
195   return NewObject<GLES::Buffer>(bufferCreateInfo, *this, std::move(oldBuffer));
196 }
197
198 Graphics::UniquePtr<Framebuffer> EglGraphicsController::CreateFramebuffer(
199   const FramebufferCreateInfo& framebufferCreateInfo, Graphics::UniquePtr<Framebuffer>&& oldFramebuffer)
200 {
201   return NewObject<GLES::Framebuffer>(framebufferCreateInfo, *this, std::move(oldFramebuffer));
202 }
203
204 Graphics::UniquePtr<Pipeline> EglGraphicsController::CreatePipeline(
205   const PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr<Graphics::Pipeline>&& oldPipeline)
206 {
207   // Create pipeline cache if needed
208   if(!mPipelineCache)
209   {
210     mPipelineCache = std::make_unique<GLES::PipelineCache>(*this);
211   }
212
213   return mPipelineCache->GetPipeline(pipelineCreateInfo, std::move(oldPipeline));
214 }
215
216 Graphics::UniquePtr<Program> EglGraphicsController::CreateProgram(
217   const ProgramCreateInfo& programCreateInfo, UniquePtr<Program>&& oldProgram)
218 {
219   // Create program cache if needed
220   if(!mPipelineCache)
221   {
222     mPipelineCache = std::make_unique<GLES::PipelineCache>(*this);
223   }
224
225   return mPipelineCache->GetProgram(programCreateInfo, std::move(oldProgram));
226 }
227
228 Graphics::UniquePtr<Shader> EglGraphicsController::CreateShader(const ShaderCreateInfo& shaderCreateInfo, Graphics::UniquePtr<Shader>&& oldShader)
229 {
230   return NewObject<GLES::Shader>(shaderCreateInfo, *this, std::move(oldShader));
231 }
232
233 Graphics::UniquePtr<Sampler> EglGraphicsController::CreateSampler(const SamplerCreateInfo& samplerCreateInfo, Graphics::UniquePtr<Sampler>&& oldSampler)
234 {
235   return NewObject<GLES::Sampler>(samplerCreateInfo, *this, std::move(oldSampler));
236 }
237
238 Graphics::UniquePtr<RenderTarget> EglGraphicsController::CreateRenderTarget(const RenderTargetCreateInfo& renderTargetCreateInfo, Graphics::UniquePtr<RenderTarget>&& oldRenderTarget)
239 {
240   return NewObject<GLES::RenderTarget>(renderTargetCreateInfo, *this, std::move(oldRenderTarget));
241 }
242
243 const Graphics::Reflection& EglGraphicsController::GetProgramReflection(const Graphics::Program& program)
244 {
245   return static_cast<const Graphics::GLES::Program*>(&program)->GetReflection();
246 }
247
248 void EglGraphicsController::CreateSurfaceContext(Dali::RenderSurfaceInterface* surface)
249 {
250   std::unique_ptr<GLES::Context> context = std::make_unique<GLES::Context>(*this);
251   mSurfaceContexts.push_back(std::move(std::make_pair(surface, std::move(context))));
252 }
253
254 void EglGraphicsController::DeleteSurfaceContext(Dali::RenderSurfaceInterface* surface)
255 {
256   mSurfaceContexts.erase(std::remove_if(
257                            mSurfaceContexts.begin(), mSurfaceContexts.end(), [surface](SurfaceContextPair& iter) { return surface == iter.first; }),
258                          mSurfaceContexts.end());
259 }
260
261 void EglGraphicsController::ActivateResourceContext()
262 {
263   mCurrentContext = mContext.get();
264 }
265
266 void EglGraphicsController::ActivateSurfaceContext(Dali::RenderSurfaceInterface* surface)
267 {
268   if(surface && mGraphics->IsResourceContextSupported())
269   {
270     auto iter = std::find_if(mSurfaceContexts.begin(), mSurfaceContexts.end(), [surface](SurfaceContextPair& iter) {
271       return (iter.first == surface);
272     });
273
274     if(iter != mSurfaceContexts.end())
275     {
276       mCurrentContext = iter->second.get();
277     }
278   }
279 }
280
281 void EglGraphicsController::AddTexture(GLES::Texture& texture)
282 {
283   // Assuming we are on the correct context
284   mCreateTextureQueue.push(&texture);
285 }
286
287 void EglGraphicsController::AddBuffer(GLES::Buffer& buffer)
288 {
289   // Assuming we are on the correct context
290   mCreateBufferQueue.push(&buffer);
291 }
292
293 void EglGraphicsController::AddFramebuffer(GLES::Framebuffer& framebuffer)
294 {
295   // Assuming we are on the correct context
296   mCreateFramebufferQueue.push(&framebuffer);
297 }
298
299 void EglGraphicsController::ProcessDiscardQueues()
300 {
301   // Process textures
302   ProcessDiscardQueue<GLES::Texture>(mDiscardTextureQueue);
303
304   // Process buffers
305   ProcessDiscardQueue<GLES::Buffer>(mDiscardBufferQueue);
306
307   // Process Framebuffers
308   ProcessDiscardQueue<GLES::Framebuffer>(mDiscardFramebufferQueue);
309
310   // Process pipelines
311   ProcessDiscardQueue<GLES::Pipeline>(mDiscardPipelineQueue);
312
313   // Process programs
314   ProcessDiscardQueue<GLES::Program>(mDiscardProgramQueue);
315
316   // Process shaders
317   ProcessDiscardQueue<GLES::Shader>(mDiscardShaderQueue);
318
319   // Process samplers
320   ProcessDiscardQueue<GLES::Sampler>(mDiscardSamplerQueue);
321
322   // Process command buffers
323   ProcessDiscardQueue<GLES::CommandBuffer>(mDiscardCommandBufferQueue);
324 }
325
326 void EglGraphicsController::ProcessCreateQueues()
327 {
328   // Process textures
329   ProcessCreateQueue(mCreateTextureQueue);
330
331   // Process buffers
332   ProcessCreateQueue(mCreateBufferQueue);
333
334   // Process framebuffers
335   ProcessCreateQueue(mCreateFramebufferQueue);
336 }
337
338 void EglGraphicsController::ProcessCommandBuffer(GLES::CommandBuffer& commandBuffer)
339 {
340   for(auto& cmd : commandBuffer.GetCommands())
341   {
342     // process command
343     switch(cmd.type)
344     {
345       case GLES::CommandType::FLUSH:
346       {
347         // Nothing to do here
348         break;
349       }
350       case GLES::CommandType::BIND_TEXTURES:
351       {
352         mCurrentContext->BindTextures(cmd.bindTextures.textureBindings);
353         break;
354       }
355       case GLES::CommandType::BIND_VERTEX_BUFFERS:
356       {
357         auto& bindings = cmd.bindVertexBuffers.vertexBufferBindings;
358         mCurrentContext->BindVertexBuffers(bindings);
359         break;
360       }
361       case GLES::CommandType::BIND_UNIFORM_BUFFER:
362       {
363         auto& bindings = cmd.bindUniformBuffers;
364         mCurrentContext->BindUniformBuffers(bindings.uniformBufferBindings, bindings.standaloneUniformsBufferBinding);
365         break;
366       }
367       case GLES::CommandType::BIND_INDEX_BUFFER:
368       {
369         mCurrentContext->BindIndexBuffer(cmd.bindIndexBuffer);
370         break;
371       }
372       case GLES::CommandType::BIND_SAMPLERS:
373       {
374         break;
375       }
376       case GLES::CommandType::BIND_PIPELINE:
377       {
378         auto pipeline = static_cast<const GLES::Pipeline*>(cmd.bindPipeline.pipeline);
379         mCurrentContext->BindPipeline(pipeline);
380         break;
381       }
382       case GLES::CommandType::DRAW:
383       {
384         mCurrentContext->Flush(false, cmd.draw);
385         break;
386       }
387       case GLES::CommandType::DRAW_INDEXED:
388       {
389         mCurrentContext->Flush(false, cmd.draw);
390         break;
391       }
392       case GLES::CommandType::DRAW_INDEXED_INDIRECT:
393       {
394         mCurrentContext->Flush(false, cmd.draw);
395         break;
396       }
397       case GLES::CommandType::SET_SCISSOR: // @todo Consider correcting for orientation here?
398       {
399         mGlAbstraction->Scissor(cmd.scissor.region.x, cmd.scissor.region.y, cmd.scissor.region.width, cmd.scissor.region.height);
400         break;
401       }
402       case GLES::CommandType::SET_SCISSOR_TEST:
403       {
404         if(cmd.scissorTest.enable)
405         {
406           mGlAbstraction->Enable(GL_SCISSOR_TEST);
407         }
408         else
409         {
410           mGlAbstraction->Disable(GL_SCISSOR_TEST);
411         }
412         break;
413       }
414       case GLES::CommandType::SET_VIEWPORT: // @todo Consider correcting for orientation here?
415       {
416         mGlAbstraction->Viewport(cmd.viewport.region.x, cmd.viewport.region.y, cmd.viewport.region.width, cmd.viewport.region.height);
417         break;
418       }
419       case GLES::CommandType::BEGIN_RENDERPASS:
420       {
421         auto&       renderTarget = *cmd.beginRenderPass.renderTarget;
422         const auto& targetInfo   = renderTarget.GetCreateInfo();
423
424         if(targetInfo.surface)
425         {
426           // switch to surface context
427           mGraphics->ActivateSurfaceContext(static_cast<Dali::RenderSurfaceInterface*>(targetInfo.surface));
428         }
429         else if(targetInfo.framebuffer)
430         {
431           // switch to resource context
432           mGraphics->ActivateResourceContext();
433         }
434
435         mCurrentContext->BeginRenderPass(cmd.beginRenderPass);
436         break;
437       }
438       case GLES::CommandType::END_RENDERPASS:
439       {
440         mCurrentContext->EndRenderPass();
441         break;
442       }
443       case GLES::CommandType::PRESENT_RENDER_TARGET:
444       {
445         ResolvePresentRenderTarget(cmd.presentRenderTarget.targetToPresent);
446
447         // push this command buffer to the discard queue
448         mDiscardCommandBufferQueue.push(&commandBuffer);
449         break;
450       }
451       case GLES::CommandType::EXECUTE_COMMAND_BUFFERS:
452       {
453         // Process secondary command buffers
454         // todo: check validity of the secondaries
455         //       there are operations which are illigal to be done
456         //       within secondaries.
457         for(auto& buf : cmd.executeCommandBuffers.buffers)
458         {
459           ProcessCommandBuffer(*static_cast<GLES::CommandBuffer*>(buf));
460         }
461         break;
462       }
463     }
464   }
465 }
466
467 void EglGraphicsController::ProcessCommandQueues()
468 {
469   // TODO: command queue per context, sync between queues should be
470   // done externally
471   currentFramebuffer = nullptr;
472
473   while(!mCommandQueue.empty())
474   {
475     auto cmdBuf = mCommandQueue.front();
476     mCommandQueue.pop();
477     ProcessCommandBuffer(*cmdBuf);
478   }
479 }
480
481 void EglGraphicsController::ProcessTextureUpdateQueue()
482 {
483   while(!mTextureUpdateRequests.empty())
484   {
485     TextureUpdateRequest& request = mTextureUpdateRequests.front();
486
487     auto& info   = request.first;
488     auto& source = request.second;
489
490     if(source.sourceType == Graphics::TextureUpdateSourceInfo::Type::MEMORY)
491     {
492       // GPU memory must be already allocated (glTexImage2D())
493       auto*       texture    = static_cast<GLES::Texture*>(info.dstTexture);
494       const auto& createInfo = texture->GetCreateInfo();
495
496       mGlAbstraction->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
497
498       mGlAbstraction->BindTexture(GL_TEXTURE_2D, texture->GetGLTexture());
499       mGlAbstraction->TexSubImage2D(GL_TEXTURE_2D,
500                                     info.level,
501                                     info.dstOffset2D.x,
502                                     info.dstOffset2D.y,
503                                     info.srcExtent2D.width,
504                                     info.srcExtent2D.height,
505                                     GLES::GLTextureFormatType(createInfo.format).format,
506                                     GLES::GLTextureFormatType(createInfo.format).type,
507                                     source.memorySource.memory);
508
509       // free staging memory
510       free(source.memorySource.memory);
511     }
512     else
513     {
514       // TODO: other sources
515     }
516
517     mTextureUpdateRequests.pop();
518   }
519 }
520
521 void EglGraphicsController::UpdateTextures(const std::vector<TextureUpdateInfo>&       updateInfoList,
522                                            const std::vector<TextureUpdateSourceInfo>& sourceList)
523 {
524   // Store updates
525   for(auto& info : updateInfoList)
526   {
527     mTextureUpdateRequests.push(std::make_pair(info, sourceList[info.srcReference]));
528     auto& pair = mTextureUpdateRequests.back();
529     switch(pair.second.sourceType)
530     {
531       case Graphics::TextureUpdateSourceInfo::Type::MEMORY:
532       {
533         auto& info   = pair.first;
534         auto& source = pair.second;
535
536         // allocate staging memory and copy the data
537         // TODO: using PBO with GLES3, this is just naive
538         // oldschool way
539
540         char* stagingBuffer = reinterpret_cast<char*>(malloc(info.srcSize));
541         std::copy(&reinterpret_cast<char*>(source.memorySource.memory)[info.srcOffset],
542                   reinterpret_cast<char*>(source.memorySource.memory) + info.srcSize,
543                   stagingBuffer);
544
545         // store staging buffer
546         source.memorySource.memory = stagingBuffer;
547         break;
548       }
549       case Graphics::TextureUpdateSourceInfo::Type::BUFFER:
550       {
551         // TODO, with PBO support
552         break;
553       }
554       case Graphics::TextureUpdateSourceInfo::Type::TEXTURE:
555       {
556         // TODO texture 2 texture in-GPU copy
557         break;
558       }
559     }
560   }
561 }
562
563 Graphics::UniquePtr<Memory> EglGraphicsController::MapBufferRange(const MapBufferInfo& mapInfo)
564 {
565   mGraphics->ActivateResourceContext();
566
567   // Mapping buffer requires the object to be created NOW
568   // Workaround - flush now, otherwise there will be given a staging buffer
569   // in case when the buffer is not there yet
570   ProcessCreateQueues();
571
572   if(GetGLESVersion() < GLES::GLESVersion::GLES_30)
573   {
574     return Graphics::UniquePtr<Memory>(new GLES::Memory2(mapInfo, *this));
575   }
576   else
577   {
578     return Graphics::UniquePtr<Memory>(new GLES::Memory3(mapInfo, *this));
579   }
580 }
581
582 bool EglGraphicsController::GetProgramParameter(Graphics::Program& program, uint32_t parameterId, void* outData)
583 {
584   return static_cast<GLES::Program*>(&program)->GetImplementation()->GetParameter(parameterId, outData);
585 }
586
587 GLES::PipelineCache& EglGraphicsController::GetPipelineCache() const
588 {
589   return *mPipelineCache;
590 }
591
592 } // namespace Dali::Graphics