void operator()(T* object)
{
- // Discard resource (add it to discard queue)
- object->DiscardResource();
+ // GLES object deleter should skip discard queue if controller shutting down
+ if(DALI_LIKELY(!EglGraphicsController::IsShuttingDown()))
+ {
+ // Discard resource (add it to discard queue)
+ object->DiscardResource();
+ }
+ else
+ {
+ // Destroy and delete object otherwise
+ if(DALI_LIKELY(object))
+ {
+ object->DestroyResource();
+ }
+ delete object;
+ }
}
};
const uint32_t TEXTURE_UPLOAD_MAX_BUFER_SIZE_MB = 1;
DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_EGL, false);
+
+bool gIsShuttingDown = true; ///< Global static flag to ensure that we have single graphics controller instance per each UpdateRender thread loop.
} // namespace
+bool EglGraphicsController::IsShuttingDown()
+{
+ return gIsShuttingDown;
+}
+
EglGraphicsController::EglGraphicsController()
: mTextureDependencyChecker(*this),
mSyncPool(*this)
void EglGraphicsController::InitializeGLES(Integration::GlAbstraction& glAbstraction)
{
DALI_LOG_RELEASE_INFO("Initializing Graphics Controller Phase 1\n");
+
mGlAbstraction = &glAbstraction;
mContext = std::make_unique<GLES::Context>(*this, mGlAbstraction);
mCurrentContext = mContext.get();
DALI_LOG_RELEASE_INFO("Initializing Graphics Controller Phase 2\n");
auto* syncImplPtr = static_cast<Internal::Adaptor::EglSyncImplementation*>(&syncImplementation);
+ DALI_ASSERT_ALWAYS(gIsShuttingDown && "Don't initialize Phase 2 EglGraphicsController twice");
+ gIsShuttingDown = false;
+
mEglSyncImplementation = syncImplPtr;
mGraphics = &graphicsInterface;
}
Flush();
}
+void EglGraphicsController::Shutdown()
+{
+ DALI_ASSERT_ALWAYS(!gIsShuttingDown && "Don't call EglGraphicsController::Shutdown twice");
+ gIsShuttingDown = true;
+
+ // Final flush
+ Flush();
+
+ if(mContext)
+ {
+ mContext->GlContextDestroyed();
+ }
+
+ for(auto&& context : mSurfaceContexts)
+ {
+ if(context.second)
+ {
+ context.second->GlContextDestroyed();
+ }
+ }
+}
+
void EglGraphicsController::PresentRenderTarget(RenderTarget* renderTarget)
{
GLES::CommandBuffer* presentCommandBuffer{nullptr};
void EglGraphicsController::DeleteSurfaceContext(Dali::Integration::RenderSurfaceInterface* surface)
{
mSurfaceContexts.erase(std::remove_if(
- mSurfaceContexts.begin(), mSurfaceContexts.end(), [surface](SurfaceContextPair& iter)
- { return surface == iter.first; }),
+ mSurfaceContexts.begin(), mSurfaceContexts.end(), [surface](SurfaceContextPair& iter) { return surface == iter.first; }),
mSurfaceContexts.end());
}
{
if(surface && mGraphics->IsResourceContextSupported())
{
- auto iter = std::find_if(mSurfaceContexts.begin(), mSurfaceContexts.end(), [surface](SurfaceContextPair& iter)
- { return (iter.first == surface); });
+ auto iter = std::find_if(mSurfaceContexts.begin(), mSurfaceContexts.end(), [surface](SurfaceContextPair& iter) { return (iter.first == surface); });
if(iter != mSurfaceContexts.end())
{
auto count = 0u;
const auto commands = commandBuffer.GetCommands(count);
- DALI_TRACE_BEGIN_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_EGL_CONTROLLER_PROCESS", [&](std::ostringstream& oss)
- { oss << "[commandCount:" << count << "]"; });
+ DALI_TRACE_BEGIN_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_EGL_CONTROLLER_PROCESS", [&](std::ostringstream& oss) { oss << "[commandCount:" << count << "]"; });
for(auto i = 0u; i < count; ++i)
{
class EglGraphicsController : public Graphics::Controller
{
public:
+ /**
+ * @brief Get whether is graphics controller shutting down or not.
+ */
+ static bool IsShuttingDown();
+
/**
* @brief Constructor
*/
/**
* @copydoc Dali::Graphics::Shutdown()
*/
- void Shutdown() override
- {
- mIsShuttingDown = true;
-
- // Final flush
- Flush();
-
- if(mContext)
- {
- mContext->GlContextDestroyed();
- }
-
- for(auto&& context : mSurfaceContexts)
- {
- if(context.second)
- {
- context.second->GlContextDestroyed();
- }
- }
- }
+ void Shutdown() override;
/**
* @copydoc Dali::Graphics::Destroy()
public:
[[nodiscard]] Integration::GlAbstraction* GetGL() const
{
- if(mIsShuttingDown)
+ if(DALI_UNLIKELY(IsShuttingDown()))
{
return nullptr;
}
mGLESVersion = glesVersion;
}
- bool IsShuttingDown() const
- {
- return mIsShuttingDown;
- }
-
/**
* @brief Reset texture cache in the contexts
*/
GLES::GLESVersion mGLESVersion{GLES::GLESVersion::GLES_20}; ///< Runtime supported GLES version
uint32_t mTextureUploadTotalCPUMemoryUsed{0u};
- bool mIsShuttingDown{false}; ///< Indicates whether the controller is shutting down
-
std::queue<const GLES::CommandBuffer*> mPresentationCommandBuffers{}; ///< Queue of reusable command buffers used by presentation engine
void* mSharedContext{nullptr}; ///< Shared EGL context
void SyncObject::DestroyResource()
{
+ if(DALI_UNLIKELY(EglGraphicsController::IsShuttingDown()))
+ {
+ return;
+ }
+ mEglSyncImplementation.DestroySyncObject(mEglSyncObject);
+ mEglSyncObject = nullptr;
}
bool SyncObject::InitializeResource()
{
// Called from custom deleter.
// Don't use discard queue, drop immediately.
- mEglSyncImplementation.DestroySyncObject(mEglSyncObject);
- mEglSyncObject = nullptr;
+ DestroyResource();
}
bool SyncObject::IsSynced()
void Buffer::InitializeGPUBuffer()
{
+ if(DALI_UNLIKELY(EglGraphicsController::IsShuttingDown()))
+ {
+ return;
+ }
+
auto context = mController.GetCurrentContext();
auto gl = mController.GetGL();
if(!gl || !context)
// Deestroy GPU allocation
else
{
- auto gl = mController.GetGL();
- if(gl)
+ if(DALI_LIKELY(!EglGraphicsController::IsShuttingDown()))
{
- gl->DeleteBuffers(1, &mBufferId);
+ auto gl = mController.GetGL();
+ if(gl)
+ {
+ gl->DeleteBuffers(1, &mBufferId);
+ }
}
}
}
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
void Framebuffer::DestroyResource()
{
- auto context = mController.GetCurrentContext();
- auto gl = mController.GetGL();
- if(gl && context && mInitialized)
+ if(DALI_LIKELY(!EglGraphicsController::IsShuttingDown()))
{
- if(mDepthBufferId)
+ auto context = mController.GetCurrentContext();
+ auto gl = mController.GetGL();
+ if(gl && context && mInitialized)
{
- gl->DeleteRenderbuffers(1, &mDepthBufferId);
- }
- if(mStencilBufferId)
- {
- gl->DeleteRenderbuffers(1, &mStencilBufferId);
- }
+ if(mDepthBufferId)
+ {
+ gl->DeleteRenderbuffers(1, &mDepthBufferId);
+ }
+ if(mStencilBufferId)
+ {
+ gl->DeleteRenderbuffers(1, &mStencilBufferId);
+ }
- context->DeleteFramebuffers(1, &mFramebufferId);
+ context->DeleteFramebuffers(1, &mFramebufferId);
- mFramebufferId = 0u;
- mInitialized = false;
+ mFramebufferId = 0u;
+ mInitialized = false;
+ }
}
}
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
void operator()(T* object)
{
- // Discard resource (add it to discard queue)
- object->DiscardResource();
- }
-};
-
-template<>
-struct CachedObjectDeleter<GLES::Program>
-{
- CachedObjectDeleter() = default;
-
- void operator()(GLES::Program* object)
- {
- // Program deleter should skip discard queue if controller shutting down
- if(!object->GetController().IsShuttingDown())
+ // Discard resource (add it to discard queue) if controller is not shutting down
+ if(DALI_LIKELY(!EglGraphicsController::IsShuttingDown()))
{
object->DiscardResource();
}
else
{
- // delete object otherwise
+ // Destroy and delete object otherwise
+ if(DALI_LIKELY(object))
+ {
+ object->DestroyResource();
+ }
delete object;
}
}
void PipelineImpl::Bind(const uint32_t glProgram) const
{
+ if(DALI_UNLIKELY(EglGraphicsController::IsShuttingDown()))
+ {
+ return; // Early out if shutting down
+ }
+
if(auto gl = GetController().GetGL())
{
gl->UseProgram(glProgram);
bool ProgramImpl::Destroy()
{
+ if(DALI_UNLIKELY(EglGraphicsController::IsShuttingDown()))
+ {
+ return false; // Early out if shutting down
+ }
+
if(mImpl->glProgram)
{
auto gl = mImpl->controller.GetGL();
const auto& extraInfos = reflection.GetStandaloneUniformExtraInfo();
+ if(DALI_UNLIKELY(EglGraphicsController::IsShuttingDown()))
+ {
+ return; // Early out if shutting down
+ }
+
auto* gl = GetController().GetGL();
if(!gl)
{
std::vector<uint8_t> sourcePreprocessed{};
size_t sourceOffset{0u}; /// byte offset of source data from original CreateInfo.
- /// It will be changed after call StripLegacyCodeIfNeeded
- /// More detail, createInfo.sourceData[0] == source[0] == (original CreateInfo).sourceData[sourceOffset];
+ /// It will be changed after call StripLegacyCodeIfNeeded
+ /// More detail, createInfo.sourceData[0] == source[0] == (original CreateInfo).sourceData[sourceOffset];
uint32_t glShader{};
uint32_t refCount{0u};
ShaderImpl::~ShaderImpl()
{
- if(!mImpl->controller.IsShuttingDown())
+ if(DALI_LIKELY(!EglGraphicsController::IsShuttingDown()))
{
mImpl->Destroy();
}
{
if(!mShader->Release())
{
+ if(DALI_UNLIKELY(EglGraphicsController::IsShuttingDown()))
+ {
+ return; // Early out if shutting down
+ }
+
GetImplementation()->GetController().GetPipelineCache().MarkShaderCacheFlushRequired();
}
}
void Shader::DiscardResource()
{
- auto& controller = GetImplementation()->GetController();
- if(!controller.IsShuttingDown())
- {
- controller.DiscardResource(this);
- }
+ GetImplementation()->GetController().DiscardResource(this);
}
uint32_t Shader::GetGLSLVersion() const
void Texture::DestroyResource()
{
- auto gl = mController.GetGL();
- if(!gl)
+ if(DALI_LIKELY(!EglGraphicsController::IsShuttingDown()))
{
- return;
- }
+ auto gl = mController.GetGL();
+ if(!gl)
+ {
+ return;
+ }
- // This is a proper destructor
- if(mTextureId)
- {
- gl->DeleteTextures(1, &mTextureId);
- }
- if(mCreateInfo.nativeImagePtr)
- {
- mCreateInfo.nativeImagePtr->DestroyResource();
+ // This is a proper destructor
+ if(mTextureId)
+ {
+ gl->DeleteTextures(1, &mTextureId);
+ }
+
+ // TODO : Shouldn't we call DestroyResource even if shutting down?
+ // For now, we use EglExtensions API at DestroyResource. So just block for now.
+ if(mCreateInfo.nativeImagePtr)
+ {
+ mCreateInfo.nativeImagePtr->DestroyResource();
+ }
}
}
void SyncObject::DestroyResource()
{
+ if(DALI_LIKELY(!EglGraphicsController::IsShuttingDown()))
+ {
+ auto gl = mController.GetGL();
+ if(gl)
+ {
+ gl->DeleteSync(mGlSyncObject);
+ }
+ mGlSyncObject = 0;
+ }
}
bool SyncObject::InitializeResource()
{
// Called from custom deleter.
// Don't use discard queue, drop immediately.
- auto gl = mController.GetGL();
- if(gl)
- {
- gl->DeleteSync(mGlSyncObject);
- }
- mGlSyncObject = 0;
+ DestroyResource();
}
bool SyncObject::IsSynced()
AgingSyncObject::~AgingSyncObject()
{
- if(!controller.IsShuttingDown())
+ if(DALI_LIKELY(!EglGraphicsController::IsShuttingDown()))
{
if(egl)
{
void Memory2::Unlock(bool flush)
{
- if(auto gl = mController.GetGL())
+ if(DALI_LIKELY(!EglGraphicsController::IsShuttingDown()))
{
- // for buffer...
- if(mMapObjectType == MapObjectType::BUFFER && mMappedPointer)
+ if(auto gl = mController.GetGL())
{
- auto buffer = static_cast<GLES::Buffer*>(mMapBufferInfo.buffer);
- if(!buffer->IsCPUAllocated())
+ // for buffer...
+ if(mMapObjectType == MapObjectType::BUFFER && mMappedPointer)
{
- buffer->Bind(BufferUsage::VERTEX_BUFFER);
- gl->BufferSubData(GL_ARRAY_BUFFER, GLintptr(mMapBufferInfo.offset), GLsizeiptr(mMapBufferInfo.size), mMappedPointer);
+ auto buffer = static_cast<GLES::Buffer*>(mMapBufferInfo.buffer);
+ if(!buffer->IsCPUAllocated())
+ {
+ buffer->Bind(BufferUsage::VERTEX_BUFFER);
+ gl->BufferSubData(GL_ARRAY_BUFFER, GLintptr(mMapBufferInfo.offset), GLsizeiptr(mMapBufferInfo.size), mMappedPointer);
+ }
}
- }
- if(mIsAllocatedLocally)
- {
- free(mMappedPointer);
- mMappedPointer = nullptr;
- }
+ if(mIsAllocatedLocally)
+ {
+ free(mMappedPointer);
+ mMappedPointer = nullptr;
+ }
- if(flush)
- {
- Flush();
+ if(flush)
+ {
+ Flush();
+ }
}
}
}
void* Memory3::LockRegion(uint32_t offset, uint32_t size)
{
- if(auto gl = mController.GetGL())
+ if(DALI_LIKELY(!EglGraphicsController::IsShuttingDown()))
{
- if(mMapObjectType == MapObjectType::BUFFER)
+ if(auto gl = mController.GetGL())
{
- auto buffer = static_cast<GLES::Buffer*>(mMapBufferInfo.buffer);
-
- if(buffer->IsCPUAllocated())
- {
- using Ptr = char*;
- mMappedPointer = Ptr(buffer->GetCPUAllocatedAddress()) + offset;
- }
- else
+ if(mMapObjectType == MapObjectType::BUFFER)
{
- gl->BindBuffer(GL_COPY_WRITE_BUFFER, buffer->GetGLBuffer());
- void* ptr = nullptr;
- ptr = gl->MapBufferRange(GL_COPY_WRITE_BUFFER, GLintptr(mMapBufferInfo.offset), GLsizeiptr(mMapBufferInfo.size), GL_MAP_WRITE_BIT);
- mMappedPointer = ptr;
+ auto buffer = static_cast<GLES::Buffer*>(mMapBufferInfo.buffer);
+
+ if(buffer->IsCPUAllocated())
+ {
+ using Ptr = char*;
+ mMappedPointer = Ptr(buffer->GetCPUAllocatedAddress()) + offset;
+ }
+ else
+ {
+ gl->BindBuffer(GL_COPY_WRITE_BUFFER, buffer->GetGLBuffer());
+ void* ptr = nullptr;
+ ptr = gl->MapBufferRange(GL_COPY_WRITE_BUFFER, GLintptr(mMapBufferInfo.offset), GLsizeiptr(mMapBufferInfo.size), GL_MAP_WRITE_BIT);
+ mMappedPointer = ptr;
+ }
+ return mMappedPointer;
}
- return mMappedPointer;
}
}
return nullptr;
void Memory3::Unlock(bool flush)
{
- if(auto gl = mController.GetGL())
+ if(DALI_LIKELY(!EglGraphicsController::IsShuttingDown()))
{
- if(mMapObjectType == MapObjectType::BUFFER && mMappedPointer)
+ if(auto gl = mController.GetGL())
{
- auto buffer = static_cast<GLES::Buffer*>(mMapBufferInfo.buffer);
- if(!buffer->IsCPUAllocated())
+ if(mMapObjectType == MapObjectType::BUFFER && mMappedPointer)
{
- gl->BindBuffer(GL_COPY_WRITE_BUFFER, buffer->GetGLBuffer());
- gl->UnmapBuffer(GL_COPY_WRITE_BUFFER);
+ auto buffer = static_cast<GLES::Buffer*>(mMapBufferInfo.buffer);
+ if(!buffer->IsCPUAllocated())
+ {
+ gl->BindBuffer(GL_COPY_WRITE_BUFFER, buffer->GetGLBuffer());
+ gl->UnmapBuffer(GL_COPY_WRITE_BUFFER);
+ }
}
- }
- if(flush)
- {
- Flush();
+ if(flush)
+ {
+ Flush();
+ }
}
mMappedPointer = nullptr;
EglSyncImplementation::~EglSyncImplementation()
{
+ for(auto& syncObject : mSyncObjects)
+ {
+ delete static_cast<EglSyncObject*>(syncObject);
+ }
+ mSyncObjects.Clear();
}
void EglSyncImplementation::Initialize(EglImplementation* eglImpl)