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