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