Limits texture upload buffer to 1MB and flushes upload requests
[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 // Maximum size of texture upload buffer.
92 const uint32_t TEXTURE_UPLOAD_MAX_BUFER_SIZE_MB = 1;
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 }
104
105 void EglGraphicsController::Initialize(Integration::GlSyncAbstraction&          glSyncAbstraction,
106                                        Integration::GlContextHelperAbstraction& glContextHelperAbstraction)
107 {
108   DALI_LOG_RELEASE_INFO("Initializing New Graphics Controller #2\n");
109   mGlSyncAbstraction          = &glSyncAbstraction;
110   mGlContextHelperAbstraction = &glContextHelperAbstraction;
111 }
112
113 void EglGraphicsController::SubmitCommandBuffers(const SubmitInfo& submitInfo)
114 {
115   for(auto& cmdbuf : submitInfo.cmdBuffer)
116   {
117     // Push command buffers
118     mCommandQueue.push(static_cast<GLES::CommandBuffer*>(cmdbuf));
119   }
120
121   // If flush bit set, flush all pending tasks
122   if(submitInfo.flags & (0 | SubmitFlagBits::FLUSH))
123   {
124     Flush();
125   }
126 }
127
128 Integration::GlAbstraction& EglGraphicsController::GetGlAbstraction()
129 {
130   DALI_ASSERT_DEBUG(mGlAbstraction && "Graphics controller not initialized");
131   return *mGlAbstraction;
132 }
133
134 Integration::GlSyncAbstraction& EglGraphicsController::GetGlSyncAbstraction()
135 {
136   DALI_ASSERT_DEBUG(mGlSyncAbstraction && "Graphics controller not initialized");
137   return *mGlSyncAbstraction;
138 }
139
140 Integration::GlContextHelperAbstraction& EglGraphicsController::GetGlContextHelperAbstraction()
141 {
142   DALI_ASSERT_DEBUG(mGlContextHelperAbstraction && "Graphics controller not initialized");
143   return *mGlContextHelperAbstraction;
144 }
145
146 Graphics::UniquePtr<CommandBuffer>
147 EglGraphicsController::CreateCommandBuffer(const CommandBufferCreateInfo&       commandBufferCreateInfo,
148                                            Graphics::UniquePtr<CommandBuffer>&& oldCommandBuffer)
149 {
150   return NewObject<GLES::CommandBuffer>(commandBufferCreateInfo, *this, std::move(oldCommandBuffer));
151 }
152
153 Graphics::UniquePtr<Texture>
154 EglGraphicsController::CreateTexture(const TextureCreateInfo& textureCreateInfo, Graphics::UniquePtr<Texture>&& oldTexture)
155 {
156   return NewObject<GLES::Texture>(textureCreateInfo, *this, std::move(oldTexture));
157 }
158
159 Graphics::UniquePtr<Buffer>
160 EglGraphicsController::CreateBuffer(const BufferCreateInfo& bufferCreateInfo, Graphics::UniquePtr<Buffer>&& oldBuffer)
161 {
162   return NewObject<GLES::Buffer>(bufferCreateInfo, *this, std::move(oldBuffer));
163 }
164
165 Graphics::UniquePtr<Pipeline> EglGraphicsController::CreatePipeline(const PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr<Graphics::Pipeline>&& oldPipeline)
166 {
167   // Create pipeline cache if needed
168   if(!mPipelineCache)
169   {
170     mPipelineCache = std::make_unique<GLES::PipelineCache>(*this);
171   }
172
173   return mPipelineCache->GetPipeline(pipelineCreateInfo, std::move(oldPipeline));
174 }
175
176 Graphics::UniquePtr<Program> EglGraphicsController::CreateProgram(const ProgramCreateInfo& programCreateInfo, UniquePtr<Program>&& oldProgram)
177 {
178   // Create program cache if needed
179   if(!mPipelineCache)
180   {
181     mPipelineCache = std::make_unique<GLES::PipelineCache>(*this);
182   }
183
184   return mPipelineCache->GetProgram(programCreateInfo, std::move(oldProgram));
185 }
186
187 Graphics::UniquePtr<Shader> EglGraphicsController::CreateShader(const ShaderCreateInfo& shaderCreateInfo, Graphics::UniquePtr<Shader>&& oldShader)
188 {
189   return NewObject<GLES::Shader>(shaderCreateInfo, *this, std::move(oldShader));
190 }
191
192 Graphics::UniquePtr<Sampler> EglGraphicsController::CreateSampler(const SamplerCreateInfo& samplerCreateInfo, Graphics::UniquePtr<Sampler>&& oldSampler)
193 {
194   return NewObject<GLES::Sampler>(samplerCreateInfo, *this, std::move(oldSampler));
195 }
196
197 const Graphics::Reflection& EglGraphicsController::GetProgramReflection(const Graphics::Program& program)
198 {
199   return static_cast<const Graphics::GLES::Program*>(&program)->GetReflection();
200 }
201
202 void EglGraphicsController::AddTexture(GLES::Texture& texture)
203 {
204   // Assuming we are on the correct context
205   mCreateTextureQueue.push(&texture);
206 }
207
208 void EglGraphicsController::AddBuffer(GLES::Buffer& buffer)
209 {
210   // Assuming we are on the correct context
211   mCreateBufferQueue.push(&buffer);
212 }
213
214 void EglGraphicsController::ProcessDiscardQueues()
215 {
216   // Process textures
217   ProcessDiscardQueue<GLES::Texture>(mDiscardTextureQueue);
218
219   // Process buffers
220   ProcessDiscardQueue<GLES::Buffer>(mDiscardBufferQueue);
221
222   // Process pipelines
223   ProcessDiscardQueue<GLES::Pipeline>(mDiscardPipelineQueue);
224
225   // Process programs
226   ProcessDiscardQueue<GLES::Program>(mDiscardProgramQueue);
227
228   // Process shaders
229   ProcessDiscardQueue<GLES::Shader>(mDiscardShaderQueue);
230
231   // Process samplers
232   ProcessDiscardQueue<GLES::Sampler>(mDiscardSamplerQueue);
233
234   // Process command buffers
235   ProcessDiscardQueue<GLES::CommandBuffer>(mDiscardCommandBufferQueue);
236 }
237
238 void EglGraphicsController::ProcessCreateQueues()
239 {
240   // Process textures
241   ProcessCreateQueue(mCreateTextureQueue);
242
243   // Process buffers
244   ProcessCreateQueue(mCreateBufferQueue);
245 }
246
247 void EglGraphicsController::ProcessCommandQueues()
248 {
249   // TODO: command queue per context, sync between queues should be
250   // done externally
251
252   while(!mCommandQueue.empty())
253   {
254     auto cmdBuf = mCommandQueue.front();
255     mCommandQueue.pop();
256
257     for(auto& cmd : cmdBuf->GetCommands())
258     {
259       // process command
260       switch(cmd.type)
261       {
262         case GLES::CommandType::FLUSH:
263         {
264           // Nothing to do here
265           break;
266         }
267         case GLES::CommandType::BIND_TEXTURES:
268         {
269           mContext->BindTextures(cmd.bindTextures.textureBindings);
270           break;
271         }
272         case GLES::CommandType::BIND_VERTEX_BUFFERS:
273         {
274           auto& bindings = cmd.bindVertexBuffers.vertexBufferBindings;
275           mContext->BindVertexBuffers(bindings);
276           break;
277         }
278         case GLES::CommandType::BIND_UNIFORM_BUFFER:
279         {
280           auto& bindings = cmd.bindUniformBuffers;
281           mContext->BindUniformBuffers(bindings.uniformBufferBindings, bindings.standaloneUniformsBufferBinding);
282           break;
283         }
284         case GLES::CommandType::BIND_INDEX_BUFFER:
285         {
286           mContext->BindIndexBuffer(cmd.bindIndexBuffer);
287           break;
288         }
289         case GLES::CommandType::BIND_SAMPLERS:
290         {
291           break;
292         }
293         case GLES::CommandType::BIND_PIPELINE:
294         {
295           mContext->BindPipeline(cmd.bindPipeline.pipeline);
296           break;
297         }
298         case GLES::CommandType::DRAW:
299         {
300           mContext->Flush(false, cmd.draw);
301           break;
302         }
303         case GLES::CommandType::DRAW_INDEXED:
304         {
305           mContext->Flush(false, cmd.draw);
306           break;
307         }
308         case GLES::CommandType::DRAW_INDEXED_INDIRECT:
309         {
310           mContext->Flush(false, cmd.draw);
311           break;
312         }
313         case GLES::CommandType::SET_SCISSOR: // @todo Consider correcting for orientation here?
314         {
315           mGlAbstraction->Scissor(cmd.scissor.region.x, cmd.scissor.region.y, cmd.scissor.region.width, cmd.scissor.region.height);
316           break;
317         }
318         case GLES::CommandType::SET_SCISSOR_TEST:
319         {
320           if(cmd.scissorTest.enable)
321           {
322             mGlAbstraction->Enable(GL_SCISSOR_TEST);
323           }
324           else
325           {
326             mGlAbstraction->Disable(GL_SCISSOR_TEST);
327           }
328           break;
329         }
330         case GLES::CommandType::SET_VIEWPORT: // @todo Consider correcting for orientation here?
331         {
332           mGlAbstraction->Viewport(cmd.viewport.region.x, cmd.viewport.region.y, cmd.viewport.region.width, cmd.viewport.region.height);
333           break;
334         }
335       }
336     }
337   }
338 }
339
340 void EglGraphicsController::ProcessTextureUpdateQueue()
341 {
342   while(!mTextureUpdateRequests.empty())
343   {
344     TextureUpdateRequest& request = mTextureUpdateRequests.front();
345
346     auto& info   = request.first;
347     auto& source = request.second;
348
349     if(source.sourceType == Graphics::TextureUpdateSourceInfo::Type::MEMORY)
350     {
351       // GPU memory must be already allocated (glTexImage2D())
352       auto*       texture    = static_cast<GLES::Texture*>(info.dstTexture);
353       const auto& createInfo = texture->GetCreateInfo();
354
355       mGlAbstraction->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
356
357       mGlAbstraction->BindTexture(GL_TEXTURE_2D, texture->GetGLTexture());
358       mGlAbstraction->TexSubImage2D(GL_TEXTURE_2D,
359                                     info.level,
360                                     info.dstOffset2D.x,
361                                     info.dstOffset2D.y,
362                                     info.srcExtent2D.width,
363                                     info.srcExtent2D.height,
364                                     GLES::GLTextureFormatType(createInfo.format).format,
365                                     GLES::GLTextureFormatType(createInfo.format).type,
366                                     source.memorySource.memory);
367
368       // free staging memory
369       free(source.memorySource.memory);
370     }
371     else
372     {
373       // TODO: other sources
374     }
375
376     mTextureUpdateRequests.pop();
377   }
378 }
379
380 void EglGraphicsController::UpdateTextures(const std::vector<TextureUpdateInfo>&       updateInfoList,
381                                            const std::vector<TextureUpdateSourceInfo>& sourceList)
382 {
383   // Store updates
384   for(auto& info : updateInfoList)
385   {
386     mTextureUpdateRequests.push(std::make_pair(info, sourceList[info.srcReference]));
387     auto& pair = mTextureUpdateRequests.back();
388     switch(pair.second.sourceType)
389     {
390       case Graphics::TextureUpdateSourceInfo::Type::MEMORY:
391       {
392         auto& info   = pair.first;
393         auto& source = pair.second;
394
395         // allocate staging memory and copy the data
396         // TODO: using PBO with GLES3, this is just naive
397         // oldschool way
398
399         char* stagingBuffer = reinterpret_cast<char*>(malloc(info.srcSize));
400         std::copy(&reinterpret_cast<char*>(source.memorySource.memory)[info.srcOffset],
401                   reinterpret_cast<char*>(source.memorySource.memory) + info.srcSize,
402                   stagingBuffer);
403
404         mTextureUploadTotalCPUMemoryUsed += info.srcSize;
405
406         // store staging buffer
407         source.memorySource.memory = stagingBuffer;
408         break;
409       }
410       case Graphics::TextureUpdateSourceInfo::Type::BUFFER:
411       {
412         // TODO, with PBO support
413         break;
414       }
415       case Graphics::TextureUpdateSourceInfo::Type::TEXTURE:
416       {
417         // TODO texture 2 texture in-GPU copy
418         break;
419       }
420     }
421   }
422
423   // If upload buffer exceeds maximum size, flush.
424   if( mTextureUploadTotalCPUMemoryUsed > TEXTURE_UPLOAD_MAX_BUFER_SIZE_MB*1024 )
425   {
426     Flush();
427     mTextureUploadTotalCPUMemoryUsed = 0;
428   }
429 }
430
431 Graphics::UniquePtr<Memory> EglGraphicsController::MapBufferRange(const MapBufferInfo& mapInfo)
432 {
433   // Mapping buffer requires the object to be created NOW
434   // Workaround - flush now, otherwise there will be given a staging buffer
435   // in case when the buffer is not there yet
436   ProcessCreateQueues();
437
438   if(GetGLESVersion() < GLES::GLESVersion::GLES_30)
439   {
440     return Graphics::UniquePtr<Memory>(new GLES::Memory2(mapInfo, *this));
441   }
442   else
443   {
444     return Graphics::UniquePtr<Memory>(new GLES::Memory3(mapInfo, *this));
445   }
446 }
447
448 bool EglGraphicsController::GetProgramParameter(Graphics::Program& program, uint32_t parameterId, void* outData)
449 {
450   return static_cast<GLES::Program*>(&program)->GetImplementation()->GetParameter(parameterId, outData);
451 }
452
453 GLES::PipelineCache& EglGraphicsController::GetPipelineCache() const
454 {
455   return *mPipelineCache;
456 }
457
458 } // namespace Dali::Graphics