2 * Copyright (c) 2021 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <dali/internal/graphics/gles-impl/egl-graphics-controller.h>
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"
32 namespace Dali::Graphics
37 * @brief Custom deleter for all Graphics objects created
38 * with use of the Controller.
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()).
48 GLESDeleter() = default;
50 void operator()(T* object)
52 // Discard resource (add it to discard queue)
53 object->DiscardResource();
58 * @brief Helper function allocating graphics object
60 * @param[in] info Create info structure
61 * @param[in] controller Controller object
62 * @param[out] out Unique pointer to the return object
64 template<class GLESType, class GfxCreateInfo, class T>
65 auto NewObject(const GfxCreateInfo& info, EglGraphicsController& controller, T&& oldObject)
68 using Type = typename T::element_type;
69 using UPtr = Graphics::UniquePtr<Type>;
70 if(info.allocationCallbacks)
72 auto* memory = info.allocationCallbacks->allocCallback(
75 info.allocationCallbacks->userData);
76 return UPtr(new(memory) GLESType(info, controller), GLESDeleter<GLESType>());
78 else // Use standard allocator
80 return UPtr(new GLESType(info, controller), GLESDeleter<GLESType>());
84 template<class T0, class T1>
85 T0* CastObject(T1* apiObject)
87 return static_cast<T0*>(apiObject);
92 void EglGraphicsController::InitializeGLES(Integration::GlAbstraction& glAbstraction)
94 DALI_LOG_RELEASE_INFO("Initializing New Graphics Controller #1\n");
95 mGlAbstraction = &glAbstraction;
96 mContext = std::make_unique<GLES::Context>(*this);
99 void EglGraphicsController::Initialize(Integration::GlSyncAbstraction& glSyncAbstraction,
100 Integration::GlContextHelperAbstraction& glContextHelperAbstraction)
102 DALI_LOG_RELEASE_INFO("Initializing New Graphics Controller #2\n");
103 mGlSyncAbstraction = &glSyncAbstraction;
104 mGlContextHelperAbstraction = &glContextHelperAbstraction;
107 void EglGraphicsController::SubmitCommandBuffers(const SubmitInfo& submitInfo)
109 for(auto& cmdbuf : submitInfo.cmdBuffer)
111 // Push command buffers
112 mCommandQueue.push(static_cast<GLES::CommandBuffer*>(cmdbuf));
115 // If flush bit set, flush all pending tasks
116 if(submitInfo.flags & (0 | SubmitFlagBits::FLUSH))
122 Integration::GlAbstraction& EglGraphicsController::GetGlAbstraction()
124 DALI_ASSERT_DEBUG(mGlAbstraction && "Graphics controller not initialized");
125 return *mGlAbstraction;
128 Integration::GlSyncAbstraction& EglGraphicsController::GetGlSyncAbstraction()
130 DALI_ASSERT_DEBUG(mGlSyncAbstraction && "Graphics controller not initialized");
131 return *mGlSyncAbstraction;
134 Integration::GlContextHelperAbstraction& EglGraphicsController::GetGlContextHelperAbstraction()
136 DALI_ASSERT_DEBUG(mGlContextHelperAbstraction && "Graphics controller not initialized");
137 return *mGlContextHelperAbstraction;
140 Graphics::UniquePtr<CommandBuffer>
141 EglGraphicsController::CreateCommandBuffer(const CommandBufferCreateInfo& commandBufferCreateInfo,
142 Graphics::UniquePtr<CommandBuffer>&& oldCommandBuffer)
144 return NewObject<GLES::CommandBuffer>(commandBufferCreateInfo, *this, std::move(oldCommandBuffer));
147 Graphics::UniquePtr<Texture>
148 EglGraphicsController::CreateTexture(const TextureCreateInfo& textureCreateInfo, Graphics::UniquePtr<Texture>&& oldTexture)
150 return NewObject<GLES::Texture>(textureCreateInfo, *this, std::move(oldTexture));
153 Graphics::UniquePtr<Buffer>
154 EglGraphicsController::CreateBuffer(const BufferCreateInfo& bufferCreateInfo, Graphics::UniquePtr<Buffer>&& oldBuffer)
156 return NewObject<GLES::Buffer>(bufferCreateInfo, *this, std::move(oldBuffer));
159 Graphics::UniquePtr<Pipeline> EglGraphicsController::CreatePipeline(const PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr<Graphics::Pipeline>&& oldPipeline)
161 // Create pipeline cache if needed
164 mPipelineCache = std::make_unique<GLES::PipelineCache>(*this);
167 return mPipelineCache->GetPipeline(pipelineCreateInfo, std::move(oldPipeline));
170 Graphics::UniquePtr<Program> EglGraphicsController::CreateProgram(const ProgramCreateInfo& programCreateInfo, UniquePtr<Program>&& oldProgram)
172 // Create program cache if needed
175 mPipelineCache = std::make_unique<GLES::PipelineCache>(*this);
178 return mPipelineCache->GetProgram(programCreateInfo, std::move(oldProgram));
181 Graphics::UniquePtr<Shader> EglGraphicsController::CreateShader(const ShaderCreateInfo& shaderCreateInfo, Graphics::UniquePtr<Shader>&& oldShader)
183 return NewObject<GLES::Shader>(shaderCreateInfo, *this, std::move(oldShader));
186 Graphics::UniquePtr<Sampler> EglGraphicsController::CreateSampler(const SamplerCreateInfo& samplerCreateInfo, Graphics::UniquePtr<Sampler>&& oldSampler)
188 return NewObject<GLES::Sampler>(samplerCreateInfo, *this, std::move(oldSampler));
191 const Graphics::Reflection& EglGraphicsController::GetProgramReflection(const Graphics::Program& program)
193 return static_cast<const Graphics::GLES::Program*>(&program)->GetReflection();
196 void EglGraphicsController::AddTexture(GLES::Texture& texture)
198 // Assuming we are on the correct context
199 mCreateTextureQueue.push(&texture);
202 void EglGraphicsController::AddBuffer(GLES::Buffer& buffer)
204 // Assuming we are on the correct context
205 mCreateBufferQueue.push(&buffer);
208 void EglGraphicsController::ProcessDiscardQueues()
211 ProcessDiscardQueue<GLES::Texture>(mDiscardTextureQueue);
214 ProcessDiscardQueue<GLES::Buffer>(mDiscardBufferQueue);
217 ProcessDiscardQueue<GLES::Pipeline>(mDiscardPipelineQueue);
220 ProcessDiscardQueue<GLES::Program>(mDiscardProgramQueue);
223 void EglGraphicsController::ProcessCreateQueues()
226 ProcessCreateQueue(mCreateTextureQueue);
229 ProcessCreateQueue(mCreateBufferQueue);
232 void EglGraphicsController::ProcessCommandQueues()
234 // TODO: command queue per context, sync between queues should be
237 while(!mCommandQueue.empty())
239 auto cmdBuf = mCommandQueue.front();
242 for(auto& cmd : cmdBuf->GetCommands())
247 case GLES::CommandType::FLUSH:
249 // Nothing to do here
252 case GLES::CommandType::BIND_TEXTURES:
254 mContext->BindTextures(cmd.bindTextures.textureBindings);
257 case GLES::CommandType::BIND_VERTEX_BUFFERS:
259 auto& bindings = cmd.bindVertexBuffers.vertexBufferBindings;
260 mContext->BindVertexBuffers(bindings);
263 case GLES::CommandType::BIND_INDEX_BUFFER:
265 mContext->BindIndexBuffer(cmd.bindIndexBuffer);
268 case GLES::CommandType::BIND_SAMPLERS:
272 case GLES::CommandType::BIND_PIPELINE:
274 mContext->BindPipeline(cmd.bindPipeline.pipeline);
277 case GLES::CommandType::DRAW:
279 mContext->Flush(false, cmd.draw);
282 case GLES::CommandType::DRAW_INDEXED:
284 mContext->Flush(false, cmd.draw);
287 case GLES::CommandType::DRAW_INDEXED_INDIRECT:
289 mContext->Flush(false, cmd.draw);
297 void EglGraphicsController::ProcessTextureUpdateQueue()
299 while(!mTextureUpdateRequests.empty())
301 TextureUpdateRequest& request = mTextureUpdateRequests.front();
303 auto& info = request.first;
304 auto& source = request.second;
306 if(source.sourceType == Graphics::TextureUpdateSourceInfo::Type::MEMORY)
308 // GPU memory must be already allocated (glTexImage2D())
309 auto* texture = static_cast<GLES::Texture*>(info.dstTexture);
310 const auto& createInfo = texture->GetCreateInfo();
312 mGlAbstraction->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
314 mGlAbstraction->BindTexture(GL_TEXTURE_2D, texture->GetGLTexture());
315 mGlAbstraction->TexSubImage2D(GL_TEXTURE_2D,
319 info.srcExtent2D.width,
320 info.srcExtent2D.height,
321 GLES::GLTextureFormatType(createInfo.format).format,
322 GLES::GLTextureFormatType(createInfo.format).type,
323 source.memorySource.memory);
325 // free staging memory
326 free(source.memorySource.memory);
330 // TODO: other sources
333 mTextureUpdateRequests.pop();
337 void EglGraphicsController::UpdateTextures(const std::vector<TextureUpdateInfo>& updateInfoList,
338 const std::vector<TextureUpdateSourceInfo>& sourceList)
341 for(auto& info : updateInfoList)
343 mTextureUpdateRequests.push(std::make_pair(info, sourceList[info.srcReference]));
344 auto& pair = mTextureUpdateRequests.back();
345 switch(pair.second.sourceType)
347 case Graphics::TextureUpdateSourceInfo::Type::MEMORY:
349 auto& info = pair.first;
350 auto& source = pair.second;
352 // allocate staging memory and copy the data
353 // TODO: using PBO with GLES3, this is just naive
356 char* stagingBuffer = reinterpret_cast<char*>(malloc(info.srcSize));
357 std::copy(&reinterpret_cast<char*>(source.memorySource.memory)[info.srcOffset],
358 reinterpret_cast<char*>(source.memorySource.memory) + info.srcSize,
361 // store staging buffer
362 source.memorySource.memory = stagingBuffer;
365 case Graphics::TextureUpdateSourceInfo::Type::BUFFER:
367 // TODO, with PBO support
370 case Graphics::TextureUpdateSourceInfo::Type::TEXTURE:
372 // TODO texture 2 texture in-GPU copy
379 Graphics::UniquePtr<Memory> EglGraphicsController::MapBufferRange(const MapBufferInfo& mapInfo)
381 // Mapping buffer requires the object to be created NOW
382 // Workaround - flush now, otherwise there will be given a staging buffer
383 // in case when the buffer is not there yet
384 ProcessCreateQueues();
386 return Graphics::UniquePtr<Memory>(new GLES::Memory(mapInfo, *this));
389 bool EglGraphicsController::GetProgramParameter(Graphics::Program& program, uint32_t parameterId, void* outData)
391 return static_cast<GLES::Program*>(&program)->GetImplementation()->GetParameter(parameterId, outData);
394 GLES::PipelineCache& EglGraphicsController::GetPipelineCache() const
396 return *mPipelineCache;
399 } // namespace Dali::Graphics