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/adaptor-framework/render-surface-interface.h>
22 #include <dali/integration-api/debug.h>
23 #include <dali/integration-api/gl-abstraction.h>
24 #include <dali/integration-api/gl-defines.h>
25 #include <dali/internal/graphics/gles-impl/gles-graphics-command-buffer.h>
26 #include <dali/internal/graphics/gles-impl/gles-graphics-pipeline.h>
27 #include <dali/internal/graphics/gles-impl/gles-graphics-render-pass.h>
28 #include <dali/internal/graphics/gles-impl/gles-graphics-render-target.h>
29 #include <dali/internal/graphics/gles-impl/gles-graphics-shader.h>
30 #include <dali/internal/graphics/gles-impl/gles-graphics-texture.h>
31 #include <dali/internal/graphics/gles-impl/gles-graphics-types.h>
32 #include <dali/internal/graphics/gles-impl/gles3-graphics-memory.h>
33 #include <dali/public-api/common/dali-common.h>
34 #include "gles-graphics-program.h"
36 namespace Dali::Graphics
41 * @brief Custom deleter for all Graphics objects created
42 * with use of the Controller.
44 * When Graphics object dies the unique pointer (Graphics::UniquePtr)
45 * doesn't destroy it directly but passes the ownership back
46 * to the Controller. The GLESDeleter is responsible for passing
47 * the object to the discard queue (by calling Resource::DiscardResource()).
52 GLESDeleter() = default;
54 void operator()(T* object)
56 // Discard resource (add it to discard queue)
57 object->DiscardResource();
62 * @brief Helper function allocating graphics object
64 * @param[in] info Create info structure
65 * @param[in] controller Controller object
66 * @param[out] out Unique pointer to the return object
68 template<class GLESType, class GfxCreateInfo, class T>
69 auto NewObject(const GfxCreateInfo& info, EglGraphicsController& controller, T&& oldObject)
72 using Type = typename T::element_type;
73 using UPtr = Graphics::UniquePtr<Type>;
74 if(info.allocationCallbacks)
76 auto* memory = info.allocationCallbacks->allocCallback(
79 info.allocationCallbacks->userData);
80 return UPtr(new(memory) GLESType(info, controller), GLESDeleter<GLESType>());
82 else // Use standard allocator
84 return UPtr(new GLESType(info, controller), GLESDeleter<GLESType>());
88 template<class T0, class T1>
89 T0* CastObject(T1* apiObject)
91 return static_cast<T0*>(apiObject);
96 EglGraphicsController::~EglGraphicsController() = default;
98 void EglGraphicsController::InitializeGLES(Integration::GlAbstraction& glAbstraction)
100 DALI_LOG_RELEASE_INFO("Initializing New Graphics Controller #1\n");
101 mGlAbstraction = &glAbstraction;
102 mContext = std::make_unique<GLES::Context>(*this);
103 mCurrentContext = mContext.get();
106 void EglGraphicsController::Initialize(Integration::GlSyncAbstraction& glSyncAbstraction,
107 Integration::GlContextHelperAbstraction& glContextHelperAbstraction,
108 Internal::Adaptor::GraphicsInterface& graphicsInterface)
110 DALI_LOG_RELEASE_INFO("Initializing New Graphics Controller #2\n");
111 mGlSyncAbstraction = &glSyncAbstraction;
112 mGlContextHelperAbstraction = &glContextHelperAbstraction;
113 mGraphics = &graphicsInterface;
116 void EglGraphicsController::SubmitCommandBuffers(const SubmitInfo& submitInfo)
118 for(auto& cmdbuf : submitInfo.cmdBuffer)
120 // Push command buffers
121 mCommandQueue.push(static_cast<GLES::CommandBuffer*>(cmdbuf));
124 // If flush bit set, flush all pending tasks
125 if(submitInfo.flags & (0 | SubmitFlagBits::FLUSH))
131 void EglGraphicsController::PresentRenderTarget(RenderTarget* renderTarget)
133 // Use command buffer to execute presentation (we should pool it)
134 CommandBufferCreateInfo info;
135 info.SetLevel(CommandBufferLevel::PRIMARY);
136 info.fixedCapacity = 1; // only one command
137 auto presentCommandBuffer = new GLES::CommandBuffer(info, *this);
138 presentCommandBuffer->PresentRenderTarget(static_cast<GLES::RenderTarget*>(renderTarget));
139 SubmitInfo submitInfo;
140 submitInfo.cmdBuffer = {presentCommandBuffer};
141 submitInfo.flags = 0 | SubmitFlagBits::FLUSH;
142 SubmitCommandBuffers(submitInfo);
145 void EglGraphicsController::ResolvePresentRenderTarget(GLES::RenderTarget* renderTarget)
147 auto* rt = static_cast<GLES::RenderTarget*>(renderTarget);
148 if(rt->GetCreateInfo().surface)
150 auto* surfaceInterface = reinterpret_cast<Dali::RenderSurfaceInterface*>(rt->GetCreateInfo().surface);
151 surfaceInterface->MakeContextCurrent();
152 surfaceInterface->PostRender();
156 Integration::GlAbstraction& EglGraphicsController::GetGlAbstraction()
158 DALI_ASSERT_DEBUG(mGlAbstraction && "Graphics controller not initialized");
159 return *mGlAbstraction;
162 Integration::GlSyncAbstraction& EglGraphicsController::GetGlSyncAbstraction()
164 DALI_ASSERT_DEBUG(mGlSyncAbstraction && "Graphics controller not initialized");
165 return *mGlSyncAbstraction;
168 Integration::GlContextHelperAbstraction& EglGraphicsController::GetGlContextHelperAbstraction()
170 DALI_ASSERT_DEBUG(mGlContextHelperAbstraction && "Graphics controller not initialized");
171 return *mGlContextHelperAbstraction;
174 Graphics::UniquePtr<CommandBuffer> EglGraphicsController::CreateCommandBuffer(
175 const CommandBufferCreateInfo& commandBufferCreateInfo,
176 Graphics::UniquePtr<CommandBuffer>&& oldCommandBuffer)
178 return NewObject<GLES::CommandBuffer>(commandBufferCreateInfo, *this, std::move(oldCommandBuffer));
181 Graphics::UniquePtr<RenderPass> EglGraphicsController::CreateRenderPass(const RenderPassCreateInfo& renderPassCreateInfo, Graphics::UniquePtr<RenderPass>&& oldRenderPass)
183 return NewObject<GLES::RenderPass>(renderPassCreateInfo, *this, std::move(oldRenderPass));
186 Graphics::UniquePtr<Texture>
187 EglGraphicsController::CreateTexture(const TextureCreateInfo& textureCreateInfo, Graphics::UniquePtr<Texture>&& oldTexture)
189 return NewObject<GLES::Texture>(textureCreateInfo, *this, std::move(oldTexture));
192 Graphics::UniquePtr<Buffer> EglGraphicsController::CreateBuffer(
193 const BufferCreateInfo& bufferCreateInfo, Graphics::UniquePtr<Buffer>&& oldBuffer)
195 return NewObject<GLES::Buffer>(bufferCreateInfo, *this, std::move(oldBuffer));
198 Graphics::UniquePtr<Framebuffer> EglGraphicsController::CreateFramebuffer(
199 const FramebufferCreateInfo& framebufferCreateInfo, Graphics::UniquePtr<Framebuffer>&& oldFramebuffer)
201 return NewObject<GLES::Framebuffer>(framebufferCreateInfo, *this, std::move(oldFramebuffer));
204 Graphics::UniquePtr<Pipeline> EglGraphicsController::CreatePipeline(
205 const PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr<Graphics::Pipeline>&& oldPipeline)
207 // Create pipeline cache if needed
210 mPipelineCache = std::make_unique<GLES::PipelineCache>(*this);
213 return mPipelineCache->GetPipeline(pipelineCreateInfo, std::move(oldPipeline));
216 Graphics::UniquePtr<Program> EglGraphicsController::CreateProgram(
217 const ProgramCreateInfo& programCreateInfo, UniquePtr<Program>&& oldProgram)
219 // Create program cache if needed
222 mPipelineCache = std::make_unique<GLES::PipelineCache>(*this);
225 return mPipelineCache->GetProgram(programCreateInfo, std::move(oldProgram));
228 Graphics::UniquePtr<Shader> EglGraphicsController::CreateShader(const ShaderCreateInfo& shaderCreateInfo, Graphics::UniquePtr<Shader>&& oldShader)
230 return NewObject<GLES::Shader>(shaderCreateInfo, *this, std::move(oldShader));
233 Graphics::UniquePtr<Sampler> EglGraphicsController::CreateSampler(const SamplerCreateInfo& samplerCreateInfo, Graphics::UniquePtr<Sampler>&& oldSampler)
235 return NewObject<GLES::Sampler>(samplerCreateInfo, *this, std::move(oldSampler));
238 Graphics::UniquePtr<RenderTarget> EglGraphicsController::CreateRenderTarget(const RenderTargetCreateInfo& renderTargetCreateInfo, Graphics::UniquePtr<RenderTarget>&& oldRenderTarget)
240 return NewObject<GLES::RenderTarget>(renderTargetCreateInfo, *this, std::move(oldRenderTarget));
243 const Graphics::Reflection& EglGraphicsController::GetProgramReflection(const Graphics::Program& program)
245 return static_cast<const Graphics::GLES::Program*>(&program)->GetReflection();
248 void EglGraphicsController::CreateSurfaceContext(Dali::RenderSurfaceInterface* surface)
250 std::unique_ptr<GLES::Context> context = std::make_unique<GLES::Context>(*this);
251 mSurfaceContexts.push_back(std::move(std::make_pair(surface, std::move(context))));
254 void EglGraphicsController::DeleteSurfaceContext(Dali::RenderSurfaceInterface* surface)
256 mSurfaceContexts.erase(std::remove_if(
257 mSurfaceContexts.begin(), mSurfaceContexts.end(), [surface](SurfaceContextPair& iter) { return surface == iter.first; }),
258 mSurfaceContexts.end());
261 void EglGraphicsController::ActivateResourceContext()
263 mCurrentContext = mContext.get();
266 void EglGraphicsController::ActivateSurfaceContext(Dali::RenderSurfaceInterface* surface)
268 if(surface && mGraphics->IsResourceContextSupported())
270 auto iter = std::find_if(mSurfaceContexts.begin(), mSurfaceContexts.end(), [surface](SurfaceContextPair& iter) {
271 return (iter.first == surface);
274 if(iter != mSurfaceContexts.end())
276 mCurrentContext = iter->second.get();
281 void EglGraphicsController::AddTexture(GLES::Texture& texture)
283 // Assuming we are on the correct context
284 mCreateTextureQueue.push(&texture);
287 void EglGraphicsController::AddBuffer(GLES::Buffer& buffer)
289 // Assuming we are on the correct context
290 mCreateBufferQueue.push(&buffer);
293 void EglGraphicsController::AddFramebuffer(GLES::Framebuffer& framebuffer)
295 // Assuming we are on the correct context
296 mCreateFramebufferQueue.push(&framebuffer);
299 void EglGraphicsController::ProcessDiscardQueues()
302 ProcessDiscardQueue<GLES::Texture>(mDiscardTextureQueue);
305 ProcessDiscardQueue<GLES::Buffer>(mDiscardBufferQueue);
307 // Process Framebuffers
308 ProcessDiscardQueue<GLES::Framebuffer>(mDiscardFramebufferQueue);
311 ProcessDiscardQueue<GLES::Pipeline>(mDiscardPipelineQueue);
314 ProcessDiscardQueue<GLES::Program>(mDiscardProgramQueue);
317 ProcessDiscardQueue<GLES::Shader>(mDiscardShaderQueue);
320 ProcessDiscardQueue<GLES::Sampler>(mDiscardSamplerQueue);
322 // Process command buffers
323 ProcessDiscardQueue<GLES::CommandBuffer>(mDiscardCommandBufferQueue);
326 void EglGraphicsController::ProcessCreateQueues()
329 ProcessCreateQueue(mCreateTextureQueue);
332 ProcessCreateQueue(mCreateBufferQueue);
334 // Process framebuffers
335 ProcessCreateQueue(mCreateFramebufferQueue);
338 void EglGraphicsController::ProcessCommandBuffer(GLES::CommandBuffer& commandBuffer)
340 for(auto& cmd : commandBuffer.GetCommands())
345 case GLES::CommandType::FLUSH:
347 // Nothing to do here
350 case GLES::CommandType::BIND_TEXTURES:
352 mCurrentContext->BindTextures(cmd.bindTextures.textureBindings);
355 case GLES::CommandType::BIND_VERTEX_BUFFERS:
357 auto& bindings = cmd.bindVertexBuffers.vertexBufferBindings;
358 mCurrentContext->BindVertexBuffers(bindings);
361 case GLES::CommandType::BIND_UNIFORM_BUFFER:
363 auto& bindings = cmd.bindUniformBuffers;
364 mCurrentContext->BindUniformBuffers(bindings.uniformBufferBindings, bindings.standaloneUniformsBufferBinding);
367 case GLES::CommandType::BIND_INDEX_BUFFER:
369 mCurrentContext->BindIndexBuffer(cmd.bindIndexBuffer);
372 case GLES::CommandType::BIND_SAMPLERS:
376 case GLES::CommandType::BIND_PIPELINE:
378 auto pipeline = static_cast<const GLES::Pipeline*>(cmd.bindPipeline.pipeline);
379 mCurrentContext->BindPipeline(pipeline);
382 case GLES::CommandType::DRAW:
384 mCurrentContext->Flush(false, cmd.draw);
387 case GLES::CommandType::DRAW_INDEXED:
389 mCurrentContext->Flush(false, cmd.draw);
392 case GLES::CommandType::DRAW_INDEXED_INDIRECT:
394 mCurrentContext->Flush(false, cmd.draw);
397 case GLES::CommandType::SET_SCISSOR: // @todo Consider correcting for orientation here?
399 mGlAbstraction->Scissor(cmd.scissor.region.x, cmd.scissor.region.y, cmd.scissor.region.width, cmd.scissor.region.height);
402 case GLES::CommandType::SET_SCISSOR_TEST:
404 if(cmd.scissorTest.enable)
406 mGlAbstraction->Enable(GL_SCISSOR_TEST);
410 mGlAbstraction->Disable(GL_SCISSOR_TEST);
414 case GLES::CommandType::SET_VIEWPORT: // @todo Consider correcting for orientation here?
416 mGlAbstraction->Viewport(cmd.viewport.region.x, cmd.viewport.region.y, cmd.viewport.region.width, cmd.viewport.region.height);
419 case GLES::CommandType::BEGIN_RENDERPASS:
421 auto& renderTarget = *cmd.beginRenderPass.renderTarget;
422 const auto& targetInfo = renderTarget.GetCreateInfo();
424 if(targetInfo.surface)
426 // switch to surface context
427 mGraphics->ActivateSurfaceContext(static_cast<Dali::RenderSurfaceInterface*>(targetInfo.surface));
429 else if(targetInfo.framebuffer)
431 // switch to resource context
432 mGraphics->ActivateResourceContext();
435 mCurrentContext->BeginRenderPass(cmd.beginRenderPass);
438 case GLES::CommandType::END_RENDERPASS:
440 mCurrentContext->EndRenderPass();
443 case GLES::CommandType::PRESENT_RENDER_TARGET:
445 ResolvePresentRenderTarget(cmd.presentRenderTarget.targetToPresent);
448 case GLES::CommandType::EXECUTE_COMMAND_BUFFERS:
450 // Process secondary command buffers
451 // todo: check validity of the secondaries
452 // there are operations which are illigal to be done
453 // within secondaries.
454 for(auto& buf : cmd.executeCommandBuffers.buffers)
456 ProcessCommandBuffer(*static_cast<GLES::CommandBuffer*>(buf));
464 void EglGraphicsController::ProcessCommandQueues()
466 // TODO: command queue per context, sync between queues should be
468 currentFramebuffer = nullptr;
470 while(!mCommandQueue.empty())
472 auto cmdBuf = mCommandQueue.front();
474 ProcessCommandBuffer(*cmdBuf);
478 void EglGraphicsController::ProcessTextureUpdateQueue()
480 while(!mTextureUpdateRequests.empty())
482 TextureUpdateRequest& request = mTextureUpdateRequests.front();
484 auto& info = request.first;
485 auto& source = request.second;
487 if(source.sourceType == Graphics::TextureUpdateSourceInfo::Type::MEMORY)
489 // GPU memory must be already allocated (glTexImage2D())
490 auto* texture = static_cast<GLES::Texture*>(info.dstTexture);
491 const auto& createInfo = texture->GetCreateInfo();
493 mGlAbstraction->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
495 mGlAbstraction->BindTexture(GL_TEXTURE_2D, texture->GetGLTexture());
496 mGlAbstraction->TexSubImage2D(GL_TEXTURE_2D,
500 info.srcExtent2D.width,
501 info.srcExtent2D.height,
502 GLES::GLTextureFormatType(createInfo.format).format,
503 GLES::GLTextureFormatType(createInfo.format).type,
504 source.memorySource.memory);
506 // free staging memory
507 free(source.memorySource.memory);
511 // TODO: other sources
514 mTextureUpdateRequests.pop();
518 void EglGraphicsController::UpdateTextures(const std::vector<TextureUpdateInfo>& updateInfoList,
519 const std::vector<TextureUpdateSourceInfo>& sourceList)
522 for(auto& info : updateInfoList)
524 mTextureUpdateRequests.push(std::make_pair(info, sourceList[info.srcReference]));
525 auto& pair = mTextureUpdateRequests.back();
526 switch(pair.second.sourceType)
528 case Graphics::TextureUpdateSourceInfo::Type::MEMORY:
530 auto& info = pair.first;
531 auto& source = pair.second;
533 // allocate staging memory and copy the data
534 // TODO: using PBO with GLES3, this is just naive
537 char* stagingBuffer = reinterpret_cast<char*>(malloc(info.srcSize));
538 std::copy(&reinterpret_cast<char*>(source.memorySource.memory)[info.srcOffset],
539 reinterpret_cast<char*>(source.memorySource.memory) + info.srcSize,
542 // store staging buffer
543 source.memorySource.memory = stagingBuffer;
546 case Graphics::TextureUpdateSourceInfo::Type::BUFFER:
548 // TODO, with PBO support
551 case Graphics::TextureUpdateSourceInfo::Type::TEXTURE:
553 // TODO texture 2 texture in-GPU copy
560 Graphics::UniquePtr<Memory> EglGraphicsController::MapBufferRange(const MapBufferInfo& mapInfo)
562 mGraphics->ActivateResourceContext();
564 // Mapping buffer requires the object to be created NOW
565 // Workaround - flush now, otherwise there will be given a staging buffer
566 // in case when the buffer is not there yet
567 ProcessCreateQueues();
569 if(GetGLESVersion() < GLES::GLESVersion::GLES_30)
571 return Graphics::UniquePtr<Memory>(new GLES::Memory2(mapInfo, *this));
575 return Graphics::UniquePtr<Memory>(new GLES::Memory3(mapInfo, *this));
579 bool EglGraphicsController::GetProgramParameter(Graphics::Program& program, uint32_t parameterId, void* outData)
581 return static_cast<GLES::Program*>(&program)->GetImplementation()->GetParameter(parameterId, outData);
584 GLES::PipelineCache& EglGraphicsController::GetPipelineCache() const
586 return *mPipelineCache;
589 } // namespace Dali::Graphics