2 * Copyright (c) 2024 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/trace.h>
22 #include <dali/public-api/common/dali-common.h>
25 #include <dali/integration-api/adaptor-framework/render-surface-interface.h>
26 #include <dali/integration-api/debug.h>
27 #include <dali/integration-api/gl-abstraction.h>
28 #include <dali/integration-api/gl-defines.h>
29 #include <dali/integration-api/graphics-sync-abstraction.h>
30 #include <dali/integration-api/pixel-data-integ.h>
31 #include <dali/internal/graphics/gles-impl/egl-sync-object.h>
32 #include <dali/internal/graphics/gles-impl/gles-graphics-command-buffer.h>
33 #include <dali/internal/graphics/gles-impl/gles-graphics-pipeline.h>
34 #include <dali/internal/graphics/gles-impl/gles-graphics-program.h>
35 #include <dali/internal/graphics/gles-impl/gles-graphics-render-pass.h>
36 #include <dali/internal/graphics/gles-impl/gles-graphics-render-target.h>
37 #include <dali/internal/graphics/gles-impl/gles-graphics-shader.h>
38 #include <dali/internal/graphics/gles-impl/gles-graphics-texture.h>
39 #include <dali/internal/graphics/gles-impl/gles-graphics-types.h>
40 #include <dali/internal/graphics/gles-impl/gles-sync-object.h>
41 #include <dali/internal/graphics/gles-impl/gles3-graphics-memory.h>
42 #include <dali/internal/graphics/gles/egl-sync-implementation.h>
44 #include <dali/internal/graphics/gles/egl-graphics.h>
48 // Uncomment the following define to turn on frame dumping
49 //#define ENABLE_COMMAND_BUFFER_FRAME_DUMP 1
50 #include <dali/internal/graphics/gles-impl/egl-graphics-controller-debug.h>
53 namespace Dali::Graphics
58 * @brief Custom deleter for all Graphics objects created
59 * with use of the Controller.
61 * When Graphics object dies the unique pointer (Graphics::UniquePtr)
62 * doesn't destroy it directly but passes the ownership back
63 * to the Controller. The GLESDeleter is responsible for passing
64 * the object to the discard queue (by calling Resource::DiscardResource()).
69 GLESDeleter() = default;
71 void operator()(T* object)
73 // Discard resource (add it to discard queue)
74 object->DiscardResource();
79 * @brief Helper function allocating graphics object
81 * @param[in] info Create info structure
82 * @param[in] controller Controller object
83 * @param[out] out Unique pointer to the return object
85 template<class GLESType, class GfxCreateInfo, class T>
86 auto NewObject(const GfxCreateInfo& info, EglGraphicsController& controller, T&& oldObject)
89 using Type = typename T::element_type;
90 using UPtr = Graphics::UniquePtr<Type>;
91 if(info.allocationCallbacks)
93 auto* memory = info.allocationCallbacks->allocCallback(
96 info.allocationCallbacks->userData);
97 return UPtr(new(memory) GLESType(info, controller), GLESDeleter<GLESType>());
99 else // Use standard allocator
101 // We are given all object for recycling
104 auto reusedObject = oldObject.release();
105 // If succeeded, attach the object to the unique_ptr and return it back
106 if(static_cast<GLESType*>(reusedObject)->TryRecycle(info, controller))
108 return UPtr(reusedObject, GLESDeleter<GLESType>());
112 // can't reuse so kill object by giving it back to original
114 oldObject.reset(reusedObject);
118 // Create brand new object
119 return UPtr(new GLESType(info, controller), GLESDeleter<GLESType>());
123 template<class T0, class T1>
124 T0* CastObject(T1* apiObject)
126 return static_cast<T0*>(apiObject);
129 // Maximum size of texture upload buffer.
130 const uint32_t TEXTURE_UPLOAD_MAX_BUFER_SIZE_MB = 1;
132 DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_EGL, false);
135 EglGraphicsController::EglGraphicsController()
136 : mTextureDependencyChecker(*this),
141 EglGraphicsController::~EglGraphicsController()
143 while(!mPresentationCommandBuffers.empty())
145 auto presentCommandBuffer = const_cast<GLES::CommandBuffer*>(mPresentationCommandBuffers.front());
146 delete presentCommandBuffer;
147 mPresentationCommandBuffers.pop();
151 void EglGraphicsController::InitializeGLES(Integration::GlAbstraction& glAbstraction)
153 DALI_LOG_RELEASE_INFO("Initializing Graphics Controller Phase 1\n");
154 mGlAbstraction = &glAbstraction;
155 mContext = std::make_unique<GLES::Context>(*this, mGlAbstraction);
156 mCurrentContext = mContext.get();
159 void EglGraphicsController::Initialize(Integration::GraphicsSyncAbstraction& syncImplementation,
160 Internal::Adaptor::GraphicsInterface& graphicsInterface)
162 DALI_LOG_RELEASE_INFO("Initializing Graphics Controller Phase 2\n");
163 auto* syncImplPtr = static_cast<Internal::Adaptor::EglSyncImplementation*>(&syncImplementation);
165 mEglSyncImplementation = syncImplPtr;
166 mGraphics = &graphicsInterface;
169 void EglGraphicsController::FrameStart()
171 mCapacity = 0; // Reset the command buffer capacity at the start of the frame.
174 void EglGraphicsController::SubmitCommandBuffers(const SubmitInfo& submitInfo)
176 for(auto& cmdbuf : submitInfo.cmdBuffer)
178 // Push command buffers
179 auto* commandBuffer = static_cast<GLES::CommandBuffer*>(cmdbuf);
180 mCapacity += commandBuffer->GetCapacity();
181 mCommandQueue.push(commandBuffer);
184 // If flush bit set, flush all pending tasks
185 if(submitInfo.flags & (0 | SubmitFlagBits::FLUSH))
191 void EglGraphicsController::WaitIdle()
196 void EglGraphicsController::PresentRenderTarget(RenderTarget* renderTarget)
198 GLES::CommandBuffer* presentCommandBuffer{nullptr};
199 if(mPresentationCommandBuffers.empty())
201 CommandBufferCreateInfo info;
202 info.SetLevel(CommandBufferLevel::PRIMARY);
203 info.fixedCapacity = 1; // only one command
204 presentCommandBuffer = new GLES::CommandBuffer(info, *this);
208 presentCommandBuffer = const_cast<GLES::CommandBuffer*>(mPresentationCommandBuffers.front());
209 presentCommandBuffer->Reset();
210 mPresentationCommandBuffers.pop();
212 presentCommandBuffer->PresentRenderTarget(static_cast<GLES::RenderTarget*>(renderTarget));
213 SubmitInfo submitInfo;
214 submitInfo.cmdBuffer = {presentCommandBuffer};
215 submitInfo.flags = 0 | SubmitFlagBits::FLUSH;
216 SubmitCommandBuffers(submitInfo);
219 void EglGraphicsController::ResolvePresentRenderTarget(GLES::RenderTarget* renderTarget)
221 mCurrentContext->InvalidateDepthStencilBuffers();
223 auto* rt = static_cast<GLES::RenderTarget*>(renderTarget);
224 if(rt->GetCreateInfo().surface)
226 auto* surfaceInterface = reinterpret_cast<Dali::RenderSurfaceInterface*>(rt->GetCreateInfo().surface);
227 surfaceInterface->MakeContextCurrent();
228 surfaceInterface->PostRender();
232 void EglGraphicsController::PostRender()
234 mTextureDependencyChecker.Reset();
235 mSyncPool.AgeSyncObjects();
238 Integration::GlAbstraction& EglGraphicsController::GetGlAbstraction()
240 DALI_ASSERT_DEBUG(mGlAbstraction && "Graphics controller not initialized");
241 return *mGlAbstraction;
244 Integration::GraphicsConfig& EglGraphicsController::GetGraphicsConfig()
246 DALI_ASSERT_DEBUG(mGlAbstraction && "Graphics controller not initialized");
247 return *mGlAbstraction;
250 Internal::Adaptor::EglSyncImplementation& EglGraphicsController::GetEglSyncImplementation()
252 DALI_ASSERT_DEBUG(mEglSyncImplementation && "Sync implementation not initialized");
253 return *mEglSyncImplementation;
256 Graphics::UniquePtr<CommandBuffer> EglGraphicsController::CreateCommandBuffer(
257 const CommandBufferCreateInfo& commandBufferCreateInfo,
258 Graphics::UniquePtr<CommandBuffer>&& oldCommandBuffer)
260 return NewObject<GLES::CommandBuffer>(commandBufferCreateInfo, *this, std::move(oldCommandBuffer));
263 Graphics::UniquePtr<RenderPass> EglGraphicsController::CreateRenderPass(const RenderPassCreateInfo& renderPassCreateInfo, Graphics::UniquePtr<RenderPass>&& oldRenderPass)
265 return NewObject<GLES::RenderPass>(renderPassCreateInfo, *this, std::move(oldRenderPass));
268 Graphics::UniquePtr<Texture>
269 EglGraphicsController::CreateTexture(const TextureCreateInfo& textureCreateInfo, Graphics::UniquePtr<Texture>&& oldTexture)
271 return NewObject<GLES::Texture>(textureCreateInfo, *this, std::move(oldTexture));
274 Graphics::UniquePtr<Buffer> EglGraphicsController::CreateBuffer(
275 const BufferCreateInfo& bufferCreateInfo, Graphics::UniquePtr<Buffer>&& oldBuffer)
277 return NewObject<GLES::Buffer>(bufferCreateInfo, *this, std::move(oldBuffer));
280 Graphics::UniquePtr<Framebuffer> EglGraphicsController::CreateFramebuffer(
281 const FramebufferCreateInfo& framebufferCreateInfo, Graphics::UniquePtr<Framebuffer>&& oldFramebuffer)
283 return NewObject<GLES::Framebuffer>(framebufferCreateInfo, *this, std::move(oldFramebuffer));
286 Graphics::UniquePtr<Pipeline> EglGraphicsController::CreatePipeline(
287 const PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr<Graphics::Pipeline>&& oldPipeline)
289 // Create pipeline cache if needed
292 mPipelineCache = std::make_unique<GLES::PipelineCache>(*this);
295 return mPipelineCache->GetPipeline(pipelineCreateInfo, std::move(oldPipeline));
298 Graphics::UniquePtr<Program> EglGraphicsController::CreateProgram(
299 const ProgramCreateInfo& programCreateInfo, UniquePtr<Program>&& oldProgram)
301 // Create pipeline cache if needed
304 mPipelineCache = std::make_unique<GLES::PipelineCache>(*this);
307 return mPipelineCache->GetProgram(programCreateInfo, std::move(oldProgram));
310 Graphics::UniquePtr<Shader> EglGraphicsController::CreateShader(const ShaderCreateInfo& shaderCreateInfo, Graphics::UniquePtr<Shader>&& oldShader)
312 // Create pipeline cache if needed
315 mPipelineCache = std::make_unique<GLES::PipelineCache>(*this);
317 return mPipelineCache->GetShader(shaderCreateInfo, std::move(oldShader));
320 Graphics::UniquePtr<Sampler> EglGraphicsController::CreateSampler(const SamplerCreateInfo& samplerCreateInfo, Graphics::UniquePtr<Sampler>&& oldSampler)
322 return NewObject<GLES::Sampler>(samplerCreateInfo, *this, std::move(oldSampler));
325 Graphics::UniquePtr<RenderTarget> EglGraphicsController::CreateRenderTarget(const RenderTargetCreateInfo& renderTargetCreateInfo, Graphics::UniquePtr<RenderTarget>&& oldRenderTarget)
327 return NewObject<GLES::RenderTarget>(renderTargetCreateInfo, *this, std::move(oldRenderTarget));
330 Graphics::UniquePtr<SyncObject> EglGraphicsController::CreateSyncObject(const SyncObjectCreateInfo& syncObjectCreateInfo,
331 UniquePtr<SyncObject>&& oldSyncObject)
333 if(GetGLESVersion() < GLES::GLESVersion::GLES_30)
335 return NewObject<EGL::SyncObject>(syncObjectCreateInfo, *this, std::move(oldSyncObject));
339 return NewObject<GLES::SyncObject>(syncObjectCreateInfo, *this, std::move(oldSyncObject));
343 MemoryRequirements EglGraphicsController::GetBufferMemoryRequirements(Buffer& buffer) const
345 MemoryRequirements requirements{};
351 gl->GetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &align);
352 requirements.alignment = align;
357 TextureProperties EglGraphicsController::GetTextureProperties(const Texture& texture)
359 const GLES::Texture* glesTexture = static_cast<const GLES::Texture*>(&texture);
360 const auto& createInfo = glesTexture->GetCreateInfo();
362 TextureProperties properties{};
363 properties.format = createInfo.format;
364 properties.compressed = glesTexture->IsCompressed();
365 properties.extent2D = createInfo.size;
366 properties.nativeHandle = glesTexture->GetGLTexture();
367 // TODO: Skip format1, emulated, packed, directWriteAccessEnabled of TextureProperties for now
372 const Graphics::Reflection& EglGraphicsController::GetProgramReflection(const Graphics::Program& program)
374 return static_cast<const Graphics::GLES::Program*>(&program)->GetReflection();
377 void EglGraphicsController::CreateSurfaceContext(Dali::RenderSurfaceInterface* surface)
379 std::unique_ptr<GLES::Context> context = std::make_unique<GLES::Context>(*this, mGlAbstraction);
380 mSurfaceContexts.push_back(std::move(std::make_pair(surface, std::move(context))));
383 void EglGraphicsController::DeleteSurfaceContext(Dali::RenderSurfaceInterface* surface)
385 mSurfaceContexts.erase(std::remove_if(
386 mSurfaceContexts.begin(), mSurfaceContexts.end(), [surface](SurfaceContextPair& iter) { return surface == iter.first; }),
387 mSurfaceContexts.end());
390 void EglGraphicsController::ActivateResourceContext()
392 mCurrentContext = mContext.get();
393 mCurrentContext->GlContextCreated();
396 auto eglGraphics = dynamic_cast<Dali::Internal::Adaptor::EglGraphics*>(mGraphics);
399 mSharedContext = eglGraphics->GetEglImplementation().GetContext();
404 void EglGraphicsController::ActivateSurfaceContext(Dali::RenderSurfaceInterface* surface)
406 if(surface && mGraphics->IsResourceContextSupported())
408 auto iter = std::find_if(mSurfaceContexts.begin(), mSurfaceContexts.end(), [surface](SurfaceContextPair& iter) { return (iter.first == surface); });
410 if(iter != mSurfaceContexts.end())
412 mCurrentContext = iter->second.get();
413 mCurrentContext->GlContextCreated();
418 void EglGraphicsController::AddTexture(GLES::Texture& texture)
420 // Assuming we are on the correct context
421 mCreateTextureQueue.push(&texture);
424 void EglGraphicsController::AddBuffer(GLES::Buffer& buffer)
426 // Assuming we are on the correct context
427 mCreateBufferQueue.push(&buffer);
430 void EglGraphicsController::AddFramebuffer(GLES::Framebuffer& framebuffer)
432 // Assuming we are on the correct context
433 mCreateFramebufferQueue.push(&framebuffer);
436 void EglGraphicsController::ProcessDiscardQueues()
438 DALI_TRACE_SCOPE(gTraceFilter, "DALI_EGL_CONTROLLER_DISCARD_QUEUE");
441 ProcessDiscardSet<GLES::Texture>(mDiscardTextureSet);
444 ProcessDiscardQueue<GLES::Buffer>(mDiscardBufferQueue);
446 // Process Framebuffers
447 ProcessDiscardQueue<GLES::Framebuffer>(mDiscardFramebufferQueue);
449 // Process RenderPass
450 ProcessDiscardQueue<GLES::RenderPass>(mDiscardRenderPassQueue);
452 // Process RenderTarget
453 ProcessDiscardQueue<GLES::RenderTarget>(mDiscardRenderTargetQueue);
456 if(mPipelineCache && !mDiscardPipelineQueue.empty())
458 mPipelineCache->MarkPipelineCacheFlushRequired();
460 ProcessDiscardQueue(mDiscardPipelineQueue);
463 if(mPipelineCache && !mDiscardProgramQueue.empty())
465 mPipelineCache->MarkProgramCacheFlushRequired();
467 ProcessDiscardQueue<GLES::Program>(mDiscardProgramQueue);
470 ProcessDiscardQueue<GLES::Shader>(mDiscardShaderQueue);
473 ProcessDiscardQueue<GLES::Sampler>(mDiscardSamplerQueue);
475 // Process command buffers
476 ProcessDiscardQueue<GLES::CommandBuffer>(mDiscardCommandBufferQueue);
479 void EglGraphicsController::ProcessCreateQueues()
481 DALI_TRACE_SCOPE(gTraceFilter, "DALI_EGL_CONTROLLER_CREATE_QUEUE");
483 ProcessCreateQueue(mCreateTextureQueue);
486 ProcessCreateQueue(mCreateBufferQueue);
488 // Process framebuffers
489 ProcessCreateQueue(mCreateFramebufferQueue);
492 void EglGraphicsController::ProcessCommandBuffer(const GLES::CommandBuffer& commandBuffer)
495 const auto commands = commandBuffer.GetCommands(count);
497 DALI_TRACE_BEGIN_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_EGL_CONTROLLER_PROCESS", [&](std::ostringstream& oss) {
498 oss << "[commandCount:" << count << "]";
501 for(auto i = 0u; i < count; ++i)
503 auto& cmd = commands[i];
507 case GLES::CommandType::FLUSH:
509 // Nothing to do here
512 case GLES::CommandType::BIND_TEXTURES:
514 mCurrentContext->BindTextures(cmd.bindTextures.textureBindings.Ptr(), cmd.bindTextures.textureBindingsCount);
517 case GLES::CommandType::BIND_VERTEX_BUFFERS:
519 auto bindings = cmd.bindVertexBuffers.vertexBufferBindings.Ptr();
520 mCurrentContext->BindVertexBuffers(bindings, cmd.bindVertexBuffers.vertexBufferBindingsCount);
523 case GLES::CommandType::BIND_UNIFORM_BUFFER:
525 auto& bindings = cmd.bindUniformBuffers;
526 mCurrentContext->BindUniformBuffers(bindings.uniformBufferBindingsCount ? bindings.uniformBufferBindings.Ptr() : nullptr, bindings.uniformBufferBindingsCount, bindings.standaloneUniformsBufferBinding);
529 case GLES::CommandType::BIND_INDEX_BUFFER:
531 mCurrentContext->BindIndexBuffer(cmd.bindIndexBuffer);
534 case GLES::CommandType::BIND_SAMPLERS:
538 case GLES::CommandType::BIND_PIPELINE:
540 auto pipeline = static_cast<const GLES::Pipeline*>(cmd.bindPipeline.pipeline);
541 mCurrentContext->BindPipeline(pipeline);
544 case GLES::CommandType::DRAW:
546 mCurrentContext->Flush(false, cmd.draw, mTextureDependencyChecker);
549 case GLES::CommandType::DRAW_INDEXED:
551 mCurrentContext->Flush(false, cmd.draw, mTextureDependencyChecker);
554 case GLES::CommandType::DRAW_INDEXED_INDIRECT:
556 mCurrentContext->Flush(false, cmd.draw, mTextureDependencyChecker);
559 case GLES::CommandType::SET_SCISSOR: // @todo Consider correcting for orientation here?
561 mGlAbstraction->Scissor(cmd.scissor.region.x, cmd.scissor.region.y, cmd.scissor.region.width, cmd.scissor.region.height);
564 case GLES::CommandType::SET_SCISSOR_TEST:
566 mCurrentContext->SetScissorTestEnabled(cmd.scissorTest.enable);
569 case GLES::CommandType::SET_VIEWPORT: // @todo Consider correcting for orientation here?
571 mGlAbstraction->Viewport(cmd.viewport.region.x, cmd.viewport.region.y, cmd.viewport.region.width, cmd.viewport.region.height);
575 case GLES::CommandType::SET_COLOR_MASK:
577 mCurrentContext->ColorMask(cmd.colorMask.enabled);
580 case GLES::CommandType::CLEAR_STENCIL_BUFFER:
582 mCurrentContext->ClearStencilBuffer();
585 case GLES::CommandType::CLEAR_DEPTH_BUFFER:
587 mCurrentContext->ClearDepthBuffer();
591 case GLES::CommandType::SET_STENCIL_TEST_ENABLE:
593 mCurrentContext->SetStencilTestEnable(cmd.stencilTest.enabled);
597 case GLES::CommandType::SET_STENCIL_FUNC:
599 mCurrentContext->StencilFunc(cmd.stencilFunc.compareOp,
600 cmd.stencilFunc.reference,
601 cmd.stencilFunc.compareMask);
605 case GLES::CommandType::SET_STENCIL_WRITE_MASK:
607 mCurrentContext->StencilMask(cmd.stencilWriteMask.mask);
611 case GLES::CommandType::SET_STENCIL_OP:
613 mCurrentContext->StencilOp(cmd.stencilOp.failOp,
614 cmd.stencilOp.depthFailOp,
615 cmd.stencilOp.passOp);
619 case GLES::CommandType::SET_DEPTH_COMPARE_OP:
621 mCurrentContext->SetDepthCompareOp(cmd.depth.compareOp);
624 case GLES::CommandType::SET_DEPTH_TEST_ENABLE:
626 mCurrentContext->SetDepthTestEnable(cmd.depth.testEnabled);
629 case GLES::CommandType::SET_DEPTH_WRITE_ENABLE:
631 mCurrentContext->SetDepthWriteEnable(cmd.depth.writeEnabled);
635 case GLES::CommandType::BEGIN_RENDERPASS:
637 auto& renderTarget = *cmd.beginRenderPass.renderTarget;
638 const auto& targetInfo = renderTarget.GetCreateInfo();
640 if(targetInfo.surface)
642 // switch to surface context
643 mGraphics->ActivateSurfaceContext(static_cast<Dali::RenderSurfaceInterface*>(targetInfo.surface));
645 else if(targetInfo.framebuffer)
647 // switch to resource context
648 mGraphics->ActivateResourceContext();
651 mCurrentContext->BeginRenderPass(cmd.beginRenderPass);
655 case GLES::CommandType::END_RENDERPASS:
657 mCurrentContext->EndRenderPass(mTextureDependencyChecker);
659 // This sync object is to enable cpu to wait for rendering to complete, not gpu.
660 // It's only needed for reading the framebuffer texture in the client.
661 auto syncObject = const_cast<GLES::SyncObject*>(static_cast<const GLES::SyncObject*>(cmd.endRenderPass.syncObject));
664 syncObject->InitializeResource();
668 case GLES::CommandType::PRESENT_RENDER_TARGET:
670 ResolvePresentRenderTarget(cmd.presentRenderTarget.targetToPresent);
672 // The command buffer will be pushed into the queue of presentation command buffers
673 // for further reuse.
674 if(commandBuffer.GetCreateInfo().fixedCapacity == 1)
676 mPresentationCommandBuffers.push(&commandBuffer);
680 case GLES::CommandType::EXECUTE_COMMAND_BUFFERS:
682 // Process secondary command buffers
683 // todo: check validity of the secondaries
684 // there are operations which are illigal to be done
685 // within secondaries.
686 auto buffers = cmd.executeCommandBuffers.buffers.Ptr();
687 for(auto j = 0u; j < cmd.executeCommandBuffers.buffersCount; ++j)
689 auto& buf = buffers[j];
690 ProcessCommandBuffer(*static_cast<const GLES::CommandBuffer*>(buf));
694 case GLES::CommandType::DRAW_NATIVE:
696 auto* info = &cmd.drawNative.drawNativeInfo;
698 // ISOLATED execution mode will isolate GL graphics context from
699 // DALi renderning pipeline which is the safest way of rendering
700 // the 'injected' code.
701 if(info->executionMode == DrawNativeExecutionMode::ISOLATED)
703 mCurrentContext->PrepareForNativeRendering();
706 if(info->glesNativeInfo.eglSharedContextStoragePointer)
708 auto* anyContext = reinterpret_cast<std::any*>(info->glesNativeInfo.eglSharedContextStoragePointer);
709 *anyContext = mSharedContext;
712 CallbackBase::ExecuteReturn<bool>(*info->callback, info->userData);
713 if(info->executionMode == DrawNativeExecutionMode::ISOLATED)
715 mCurrentContext->RestoreFromNativeRendering();
719 // After native rendering reset all states and caches.
720 // This is going to be called only when DIRECT execution mode is used
721 // and some GL states need to be reset.
722 // This does not guarantee that after execution a custom GL code
723 // the main rendering pipeline will work correctly and it's a responsibility
724 // of developer to make sure the GL states are not interfering with main
725 // rendering pipeline (by restoring/cleaning up GL states after drawing).
726 mCurrentContext->ResetGLESState();
732 DALI_TRACE_END(gTraceFilter, "DALI_EGL_CONTROLLER_PROCESS");
735 void EglGraphicsController::ProcessCommandQueues()
739 while(!mCommandQueue.empty())
741 auto cmdBuf = mCommandQueue.front();
743 DUMP_FRAME_COMMAND_BUFFER(cmdBuf);
744 ProcessCommandBuffer(*cmdBuf);
750 void EglGraphicsController::ProcessTextureUpdateQueue()
752 if(mTextureUpdateRequests.empty())
756 DALI_TRACE_SCOPE(gTraceFilter, "DALI_EGL_CONTROLLER_TEXTURE_UPDATE");
757 while(!mTextureUpdateRequests.empty())
759 TextureUpdateRequest& request = mTextureUpdateRequests.front();
761 auto& info = request.first;
762 auto& source = request.second;
764 switch(source.sourceType)
766 case Graphics::TextureUpdateSourceInfo::Type::MEMORY:
767 case Graphics::TextureUpdateSourceInfo::Type::PIXEL_DATA:
769 // GPU memory must be already allocated.
771 // Check if it needs conversion
772 auto* texture = static_cast<GLES::Texture*>(info.dstTexture);
773 const auto& createInfo = texture->GetCreateInfo();
774 auto srcFormat = GLES::GLTextureFormatType(info.srcFormat).format;
775 auto srcType = GLES::GLTextureFormatType(info.srcFormat).type;
776 auto destInternalFormat = GLES::GLTextureFormatType(createInfo.format).internalFormat;
777 auto destFormat = GLES::GLTextureFormatType(createInfo.format).format;
779 // From render-texture.cpp
780 const bool isSubImage(info.dstOffset2D.x != 0 || info.dstOffset2D.y != 0 ||
781 info.srcExtent2D.width != (createInfo.size.width / (1 << info.level)) ||
782 info.srcExtent2D.height != (createInfo.size.height / (1 << info.level)));
784 uint8_t* sourceBuffer = nullptr;
785 bool sourceBufferReleaseRequired = false;
786 if(source.sourceType == Graphics::TextureUpdateSourceInfo::Type::MEMORY)
788 sourceBuffer = reinterpret_cast<uint8_t*>(source.memorySource.memory);
789 sourceBufferReleaseRequired = true;
793 Dali::Integration::PixelDataBuffer pixelBufferData = Dali::Integration::GetPixelDataBuffer(source.pixelDataSource.pixelData);
795 sourceBuffer = pixelBufferData.buffer + info.srcOffset;
796 sourceBufferReleaseRequired = Dali::Integration::IsPixelDataReleaseAfterUpload(source.pixelDataSource.pixelData) && info.srcOffset == 0u;
799 // Skip texture upload if given texture is already discarded for this render loop.
800 if(mDiscardTextureSet.find(texture) == mDiscardTextureSet.end())
802 auto sourceStride = info.srcStride;
803 std::vector<uint8_t> tempBuffer;
805 uint8_t* srcBuffer = sourceBuffer;
807 if(mGlAbstraction->TextureRequiresConverting(srcFormat, destFormat, isSubImage))
809 // Convert RGB to RGBA if necessary.
810 if(texture->TryConvertPixelData(sourceBuffer, info.srcFormat, createInfo.format, info.srcSize, info.srcStride, info.srcExtent2D.width, info.srcExtent2D.height, tempBuffer))
812 srcBuffer = &tempBuffer[0];
813 sourceStride = 0u; // Converted buffer compacted. make stride as 0.
814 srcFormat = destFormat;
815 srcType = GLES::GLTextureFormatType(createInfo.format).type;
819 // Calculate the maximum mipmap level for the texture
820 texture->SetMaxMipMapLevel(std::max(texture->GetMaxMipMapLevel(), info.level));
822 GLenum bindTarget{GL_TEXTURE_2D};
823 GLenum target{GL_TEXTURE_2D};
825 if(createInfo.textureType == Graphics::TextureType::TEXTURE_CUBEMAP)
827 bindTarget = GL_TEXTURE_CUBE_MAP;
828 target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + info.layer;
831 mGlAbstraction->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
832 mGlAbstraction->PixelStorei(GL_UNPACK_ROW_LENGTH, sourceStride);
834 mCurrentContext->BindTexture(bindTarget, texture->GetTextureTypeId(), texture->GetGLTexture());
838 if(!texture->IsCompressed())
840 mGlAbstraction->TexImage2D(target,
843 info.srcExtent2D.width,
844 info.srcExtent2D.height,
852 mGlAbstraction->CompressedTexImage2D(target,
855 info.srcExtent2D.width,
856 info.srcExtent2D.height,
864 if(!texture->IsCompressed())
866 mGlAbstraction->TexSubImage2D(target,
870 info.srcExtent2D.width,
871 info.srcExtent2D.height,
878 mGlAbstraction->CompressedTexSubImage2D(target,
882 info.srcExtent2D.width,
883 info.srcExtent2D.height,
891 if(sourceBufferReleaseRequired && sourceBuffer != nullptr)
893 if(source.sourceType == Graphics::TextureUpdateSourceInfo::Type::MEMORY)
895 free(reinterpret_cast<void*>(sourceBuffer));
899 Dali::Integration::ReleasePixelDataBuffer(source.pixelDataSource.pixelData);
906 // TODO: other sources
911 mTextureUpdateRequests.pop();
915 void EglGraphicsController::UpdateTextures(const std::vector<TextureUpdateInfo>& updateInfoList,
916 const std::vector<TextureUpdateSourceInfo>& sourceList)
919 for(auto& info : updateInfoList)
921 mTextureUpdateRequests.push(std::make_pair(info, sourceList[info.srcReference]));
922 auto& pair = mTextureUpdateRequests.back();
923 switch(pair.second.sourceType)
925 case Graphics::TextureUpdateSourceInfo::Type::MEMORY:
927 auto& info = pair.first;
928 auto& source = pair.second;
930 // allocate staging memory and copy the data
931 // TODO: using PBO with GLES3, this is just naive
934 uint8_t* stagingBuffer = reinterpret_cast<uint8_t*>(malloc(info.srcSize));
936 if(DALI_UNLIKELY(stagingBuffer == nullptr))
938 DALI_LOG_ERROR("malloc is failed. request malloc size : %u\n", info.srcSize);
942 uint8_t* srcMemory = &reinterpret_cast<uint8_t*>(source.memorySource.memory)[info.srcOffset];
944 std::copy(srcMemory, srcMemory + info.srcSize, stagingBuffer);
946 mTextureUploadTotalCPUMemoryUsed += info.srcSize;
949 // store staging buffer
950 source.memorySource.memory = stagingBuffer;
953 case Graphics::TextureUpdateSourceInfo::Type::PIXEL_DATA:
955 // Increase CPU memory usage since ownership of PixelData is now on mTextureUpdateRequests.
956 mTextureUploadTotalCPUMemoryUsed += info.srcSize;
959 case Graphics::TextureUpdateSourceInfo::Type::BUFFER:
961 // TODO, with PBO support
964 case Graphics::TextureUpdateSourceInfo::Type::TEXTURE:
966 // TODO texture 2 texture in-GPU copy
972 // If upload buffer exceeds maximum size, flush.
973 if(mTextureUploadTotalCPUMemoryUsed > TEXTURE_UPLOAD_MAX_BUFER_SIZE_MB * 1024 * 1024)
976 mTextureUploadTotalCPUMemoryUsed = 0;
980 void EglGraphicsController::ProcessTextureMipmapGenerationQueue()
982 if(mTextureMipmapGenerationRequests.empty())
986 DALI_TRACE_SCOPE(gTraceFilter, "DALI_EGL_CONTROLLER_TEXTURE_MIPMAP");
987 while(!mTextureMipmapGenerationRequests.empty())
989 auto* texture = mTextureMipmapGenerationRequests.front();
991 mCurrentContext->BindTexture(texture->GetGlTarget(), texture->GetTextureTypeId(), texture->GetGLTexture());
992 mCurrentContext->GenerateMipmap(texture->GetGlTarget());
994 mTextureMipmapGenerationRequests.pop();
998 void EglGraphicsController::GenerateTextureMipmaps(const Graphics::Texture& texture)
1000 mTextureMipmapGenerationRequests.push(static_cast<const GLES::Texture*>(&texture));
1003 Graphics::UniquePtr<Memory> EglGraphicsController::MapBufferRange(const MapBufferInfo& mapInfo)
1005 // Mapping buffer requires the object to be created NOW
1006 // Workaround - flush now, otherwise there will be given a staging buffer
1007 // in case when the buffer is not there yet
1008 if(!mCreateBufferQueue.empty())
1010 mGraphics->ActivateResourceContext();
1011 ProcessCreateQueues();
1014 if(GetGLESVersion() < GLES::GLESVersion::GLES_30)
1016 return Graphics::UniquePtr<Memory>(new GLES::Memory2(mapInfo, *this));
1020 return Graphics::UniquePtr<Memory>(new GLES::Memory3(mapInfo, *this));
1024 bool EglGraphicsController::GetProgramParameter(Graphics::Program& program, uint32_t parameterId, void* outData)
1026 return static_cast<GLES::Program*>(&program)->GetImplementation()->GetParameter(parameterId, outData);
1029 GLES::PipelineCache& EglGraphicsController::GetPipelineCache() const
1031 return *mPipelineCache;
1034 Graphics::Texture* EglGraphicsController::CreateTextureByResourceId(uint32_t resourceId, const Graphics::TextureCreateInfo& createInfo)
1036 Graphics::Texture* ret = nullptr;
1037 Graphics::UniquePtr<Graphics::Texture> texture;
1039 auto iter = mExternalTextureResources.find(resourceId);
1040 DALI_ASSERT_ALWAYS(iter == mExternalTextureResources.end());
1042 texture = CreateTexture(createInfo, std::move(texture));
1044 ret = texture.get();
1046 mExternalTextureResources.insert(std::make_pair(resourceId, std::move(texture)));
1051 void EglGraphicsController::DiscardTextureFromResourceId(uint32_t resourceId)
1053 auto iter = mExternalTextureResources.find(resourceId);
1054 if(iter != mExternalTextureResources.end())
1056 mExternalTextureResources.erase(iter);
1060 Graphics::Texture* EglGraphicsController::GetTextureFromResourceId(uint32_t resourceId)
1062 Graphics::Texture* ret = nullptr;
1064 auto iter = mExternalTextureResources.find(resourceId);
1065 if(iter != mExternalTextureResources.end())
1067 ret = iter->second.get();
1073 Graphics::UniquePtr<Graphics::Texture> EglGraphicsController::ReleaseTextureFromResourceId(uint32_t resourceId)
1075 Graphics::UniquePtr<Graphics::Texture> texture;
1077 auto iter = mExternalTextureResources.find(resourceId);
1078 if(iter != mExternalTextureResources.end())
1080 texture = std::move(iter->second);
1081 mExternalTextureResources.erase(iter);
1087 } // namespace Dali::Graphics