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