Shader Reflection
[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/gl-abstraction.h>
22 #include <dali/integration-api/gl-defines.h>
23 #include <dali/internal/graphics/gles-impl/gles-graphics-command-buffer.h>
24 #include <dali/internal/graphics/gles-impl/gles-graphics-pipeline.h>
25 #include <dali/internal/graphics/gles-impl/gles-graphics-shader.h>
26 #include <dali/internal/graphics/gles-impl/gles-graphics-texture.h>
27 #include <dali/internal/graphics/gles-impl/gles-graphics-types.h>
28 #include <dali/public-api/common/dali-common.h>
29
30 namespace Dali::Graphics
31 {
32 namespace
33 {
34 /**
35  * @brief Custom deleter for all Graphics objects created
36  * with use of the Controller.
37  *
38  * When Graphics object dies the unique pointer (Graphics::UniquePtr)
39  * doesn't destroy it directly but passes the ownership back
40  * to the Controller. The GLESDeleter is responsible for passing
41  * the object to the discard queue (by calling Resource::DiscardResource()).
42  */
43 template<typename T>
44 struct GLESDeleter
45 {
46   GLESDeleter() = default;
47
48   void operator()(T* object)
49   {
50     // Discard resource (add it to discard queue)
51     object->DiscardResource();
52   }
53 };
54
55 /**
56  * @brief Helper function allocating graphics object
57  *
58  * @param[in] info Create info structure
59  * @param[in] controller Controller object
60  * @param[out] out Unique pointer to the return object
61  */
62 template<class GLESType, class GfxCreateInfo, class T>
63 auto NewObject(const GfxCreateInfo& info, EglGraphicsController& controller, T&& oldObject)
64 {
65   // Use allocator
66   using Type = typename T::element_type;
67   using UPtr = Graphics::UniquePtr<Type>;
68   if(info.allocationCallbacks)
69   {
70     auto* memory = info.allocationCallbacks->allocCallback(
71       sizeof(GLESType),
72       0,
73       info.allocationCallbacks->userData);
74     return UPtr(new(memory) GLESType(info, controller), GLESDeleter<GLESType>());
75   }
76   else // Use standard allocator
77   {
78     return UPtr(new GLESType(info, controller), GLESDeleter<GLESType>());
79   }
80 }
81
82 template<class T0, class T1>
83 T0* CastObject(T1* apiObject)
84 {
85   return static_cast<T0*>(apiObject);
86 }
87
88 } // namespace
89
90 void EglGraphicsController::InitializeGLES(Integration::GlAbstraction& glAbstraction)
91 {
92   mGlAbstraction = &glAbstraction;
93   mContext       = std::make_unique<GLES::Context>(*this);
94 }
95
96 void EglGraphicsController::Initialize(Integration::GlSyncAbstraction&          glSyncAbstraction,
97                                        Integration::GlContextHelperAbstraction& glContextHelperAbstraction)
98 {
99   mGlSyncAbstraction          = &glSyncAbstraction;
100   mGlContextHelperAbstraction = &glContextHelperAbstraction;
101 }
102
103 void EglGraphicsController::SubmitCommandBuffers(const SubmitInfo& submitInfo)
104 {
105   for(auto& cmdbuf : submitInfo.cmdBuffer)
106   {
107     // Push command buffers
108     mCommandQueue.push(static_cast<GLES::CommandBuffer*>(cmdbuf));
109   }
110
111   // If flush bit set, flush all pending tasks
112   if(submitInfo.flags & (0 | SubmitFlagBits::FLUSH))
113   {
114     Flush();
115   }
116 }
117
118 Integration::GlAbstraction& EglGraphicsController::GetGlAbstraction()
119 {
120   DALI_ASSERT_DEBUG(mGlAbstraction && "Graphics controller not initialized");
121   return *mGlAbstraction;
122 }
123
124 Integration::GlSyncAbstraction& EglGraphicsController::GetGlSyncAbstraction()
125 {
126   DALI_ASSERT_DEBUG(mGlSyncAbstraction && "Graphics controller not initialized");
127   return *mGlSyncAbstraction;
128 }
129
130 Integration::GlContextHelperAbstraction& EglGraphicsController::GetGlContextHelperAbstraction()
131 {
132   DALI_ASSERT_DEBUG(mGlContextHelperAbstraction && "Graphics controller not initialized");
133   return *mGlContextHelperAbstraction;
134 }
135
136 Graphics::UniquePtr<CommandBuffer>
137 EglGraphicsController::CreateCommandBuffer(const CommandBufferCreateInfo&       commandBufferCreateInfo,
138                                            Graphics::UniquePtr<CommandBuffer>&& oldCommandBuffer)
139 {
140   return NewObject<GLES::CommandBuffer>(commandBufferCreateInfo, *this, std::move(oldCommandBuffer));
141 }
142
143 Graphics::UniquePtr<Texture>
144 EglGraphicsController::CreateTexture(const TextureCreateInfo& textureCreateInfo, Graphics::UniquePtr<Texture>&& oldTexture)
145 {
146   return NewObject<GLES::Texture>(textureCreateInfo, *this, std::move(oldTexture));
147 }
148
149 Graphics::UniquePtr<Buffer>
150 EglGraphicsController::CreateBuffer(const BufferCreateInfo& bufferCreateInfo, Graphics::UniquePtr<Buffer>&& oldBuffer)
151 {
152   return NewObject<GLES::Buffer>(bufferCreateInfo, *this, std::move(oldBuffer));
153 }
154
155 Graphics::UniquePtr<Shader> EglGraphicsController::CreateShader(const ShaderCreateInfo& shaderCreateInfo, Graphics::UniquePtr<Shader>&& oldShader)
156 {
157   return NewObject<GLES::Shader>(shaderCreateInfo, *this, std::move(oldShader));
158 }
159
160 Graphics::UniquePtr<Pipeline> EglGraphicsController::CreatePipeline(const PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr<Graphics::Pipeline>&& oldPipeline)
161 {
162   // Create pipeline cache if needed
163   if(!mPipelineCache)
164   {
165     mPipelineCache = std::make_unique<GLES::PipelineCache>(*this);
166   }
167
168   return mPipelineCache->GetPipeline(pipelineCreateInfo, std::move(oldPipeline));
169 }
170
171 void EglGraphicsController::AddTexture(GLES::Texture& texture)
172 {
173   // Assuming we are on the correct context
174   mCreateTextureQueue.push(&texture);
175 }
176
177 void EglGraphicsController::AddBuffer(GLES::Buffer& buffer)
178 {
179   // Assuming we are on the correct context
180   mCreateBufferQueue.push(&buffer);
181 }
182
183 void EglGraphicsController::ProcessDiscardQueues()
184 {
185   // Process textures
186   ProcessDiscardQueue<GLES::Texture>(mDiscardTextureQueue);
187
188   // Process buffers
189   ProcessDiscardQueue<GLES::Buffer>(mDiscardBufferQueue);
190 }
191
192 void EglGraphicsController::ProcessCreateQueues()
193 {
194   // Process textures
195   ProcessCreateQueue(mCreateTextureQueue);
196
197   // Process buffers
198   ProcessCreateQueue(mCreateBufferQueue);
199 }
200
201 void EglGraphicsController::ProcessCommandQueues()
202 {
203   // TODO: command queue per context, sync between queues should be
204   // done externally
205
206   while(!mCommandQueue.empty())
207   {
208     auto cmdBuf = mCommandQueue.front();
209     mCommandQueue.pop();
210
211     for(auto& cmd : cmdBuf->GetCommands())
212     {
213       // process command
214       switch(cmd.type)
215       {
216         case GLES::CommandType::FLUSH:
217         {
218           // Nothing to do here
219           break;
220         }
221         case GLES::CommandType::BIND_TEXTURES:
222         {
223           mContext->BindTextures(cmd.bindTextures.textureBindings);
224           break;
225         }
226         case GLES::CommandType::BIND_VERTEX_BUFFERS:
227         {
228           auto& bindings = cmd.bindVertexBuffers.vertexBufferBindings;
229           mContext->BindVertexBuffers(bindings);
230           break;
231         }
232         case GLES::CommandType::BIND_INDEX_BUFFER:
233         {
234           mContext->BindIndexBuffer(cmd.bindIndexBuffer);
235           break;
236         }
237         case GLES::CommandType::BIND_SAMPLERS:
238         {
239           break;
240         }
241         case GLES::CommandType::BIND_PIPELINE:
242         {
243           mContext->BindPipeline(cmd.bindPipeline.pipeline);
244           break;
245         }
246         case GLES::CommandType::DRAW:
247         {
248           mContext->Flush(false, cmd.draw);
249           break;
250         }
251         case GLES::CommandType::DRAW_INDEXED:
252         {
253           mContext->Flush(false, cmd.draw);
254           break;
255         }
256         case GLES::CommandType::DRAW_INDEXED_INDIRECT:
257         {
258           mContext->Flush(false, cmd.draw);
259           break;
260         }
261       }
262     }
263   }
264 }
265
266 void EglGraphicsController::ProcessTextureUpdateQueue()
267 {
268   while(!mTextureUpdateRequests.empty())
269   {
270     TextureUpdateRequest& request = mTextureUpdateRequests.front();
271
272     auto& info   = request.first;
273     auto& source = request.second;
274
275     if(source.sourceType == Graphics::TextureUpdateSourceInfo::Type::MEMORY)
276     {
277       // GPU memory must be already allocated (glTexImage2D())
278       auto*       texture    = static_cast<GLES::Texture*>(info.dstTexture);
279       const auto& createInfo = texture->GetCreateInfo();
280
281       mGlAbstraction->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
282
283       mGlAbstraction->BindTexture(GL_TEXTURE_2D, texture->GetGLTexture());
284       mGlAbstraction->TexSubImage2D(GL_TEXTURE_2D,
285                                     info.level,
286                                     info.dstOffset2D.x,
287                                     info.dstOffset2D.y,
288                                     info.srcExtent2D.width,
289                                     info.srcExtent2D.height,
290                                     GLES::GLTextureFormatType(createInfo.format).format,
291                                     GLES::GLTextureFormatType(createInfo.format).type,
292                                     source.memorySource.memory);
293
294       // free staging memory
295       free(source.memorySource.memory);
296     }
297     else
298     {
299       // TODO: other sources
300     }
301
302     mTextureUpdateRequests.pop();
303   }
304 }
305
306 void EglGraphicsController::UpdateTextures(const std::vector<TextureUpdateInfo>&       updateInfoList,
307                                            const std::vector<TextureUpdateSourceInfo>& sourceList)
308 {
309   // Store updates
310   for(auto& info : updateInfoList)
311   {
312     mTextureUpdateRequests.push(std::make_pair(info, sourceList[info.srcReference]));
313     auto& pair = mTextureUpdateRequests.back();
314     switch(pair.second.sourceType)
315     {
316       case Graphics::TextureUpdateSourceInfo::Type::MEMORY:
317       {
318         auto& info   = pair.first;
319         auto& source = pair.second;
320
321         // allocate staging memory and copy the data
322         // TODO: using PBO with GLES3, this is just naive
323         // oldschool way
324
325         char* stagingBuffer = reinterpret_cast<char*>(malloc(info.srcSize));
326         std::copy(&reinterpret_cast<char*>(source.memorySource.memory)[info.srcOffset],
327                   reinterpret_cast<char*>(source.memorySource.memory) + info.srcSize,
328                   stagingBuffer);
329
330         // store staging buffer
331         source.memorySource.memory = stagingBuffer;
332         break;
333       }
334       case Graphics::TextureUpdateSourceInfo::Type::BUFFER:
335       {
336         // TODO, with PBO support
337         break;
338       }
339       case Graphics::TextureUpdateSourceInfo::Type::TEXTURE:
340       {
341         // TODO texture 2 texture in-GPU copy
342         break;
343       }
344     }
345   }
346 }
347
348 Graphics::UniquePtr<Memory> EglGraphicsController::MapBufferRange(const MapBufferInfo& mapInfo)
349 {
350   // Mapping buffer requires the object to be created NOW
351   // Workaround - flush now, otherwise there will be given a staging buffer
352   // in case when the buffer is not there yet
353   ProcessCreateQueues();
354
355   return Graphics::UniquePtr<Memory>(new GLES::Memory(mapInfo, *this));
356 }
357
358 } // namespace Dali::Graphics