/*
- * 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.
#include <dali/internal/graphics/gles-impl/egl-graphics-controller.h>
// EXTERNAL INCLUDES
+#include <dali/integration-api/trace.h>
#include <dali/public-api/common/dali-common.h>
// INTERNAL INCLUDES
// Maximum size of texture upload buffer.
const uint32_t TEXTURE_UPLOAD_MAX_BUFER_SIZE_MB = 1;
+DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_EGL, false);
} // namespace
EglGraphicsController::EglGraphicsController()
{
DALI_LOG_RELEASE_INFO("Initializing Graphics Controller Phase 1\n");
mGlAbstraction = &glAbstraction;
- mContext = std::make_unique<GLES::Context>(*this);
+ mContext = std::make_unique<GLES::Context>(*this, mGlAbstraction);
mCurrentContext = mContext.get();
}
-void EglGraphicsController::Initialize(Integration::GraphicsSyncAbstraction& syncImplementation,
- Integration::GlContextHelperAbstraction& glContextHelperAbstraction,
- Internal::Adaptor::GraphicsInterface& graphicsInterface)
+void EglGraphicsController::Initialize(Integration::GraphicsSyncAbstraction& syncImplementation,
+ Internal::Adaptor::GraphicsInterface& graphicsInterface)
{
DALI_LOG_RELEASE_INFO("Initializing Graphics Controller Phase 2\n");
auto* syncImplPtr = static_cast<Internal::Adaptor::EglSyncImplementation*>(&syncImplementation);
- mEglSyncImplementation = syncImplPtr;
- mGlContextHelperAbstraction = &glContextHelperAbstraction;
- mGraphics = &graphicsInterface;
+ mEglSyncImplementation = syncImplPtr;
+ mGraphics = &graphicsInterface;
}
void EglGraphicsController::FrameStart()
return *mGlAbstraction;
}
-Integration::GlContextHelperAbstraction& EglGraphicsController::GetGlContextHelperAbstraction()
+Integration::GraphicsConfig& EglGraphicsController::GetGraphicsConfig()
{
- DALI_ASSERT_DEBUG(mGlContextHelperAbstraction && "Graphics controller not initialized");
- return *mGlContextHelperAbstraction;
+ DALI_ASSERT_DEBUG(mGlAbstraction && "Graphics controller not initialized");
+ return *mGlAbstraction;
}
Internal::Adaptor::EglSyncImplementation& EglGraphicsController::GetEglSyncImplementation()
Graphics::UniquePtr<Program> EglGraphicsController::CreateProgram(
const ProgramCreateInfo& programCreateInfo, UniquePtr<Program>&& oldProgram)
{
- // Create program cache if needed
+ // Create pipeline cache if needed
if(!mPipelineCache)
{
mPipelineCache = std::make_unique<GLES::PipelineCache>(*this);
Graphics::UniquePtr<Shader> EglGraphicsController::CreateShader(const ShaderCreateInfo& shaderCreateInfo, Graphics::UniquePtr<Shader>&& oldShader)
{
- return NewObject<GLES::Shader>(shaderCreateInfo, *this, std::move(oldShader));
+ // Create pipeline cache if needed
+ if(!mPipelineCache)
+ {
+ mPipelineCache = std::make_unique<GLES::PipelineCache>(*this);
+ }
+ return mPipelineCache->GetShader(shaderCreateInfo, std::move(oldShader));
}
Graphics::UniquePtr<Sampler> EglGraphicsController::CreateSampler(const SamplerCreateInfo& samplerCreateInfo, Graphics::UniquePtr<Sampler>&& oldSampler)
TextureProperties EglGraphicsController::GetTextureProperties(const Texture& texture)
{
const GLES::Texture* glesTexture = static_cast<const GLES::Texture*>(&texture);
- auto createInfo = glesTexture->GetCreateInfo();
+ const auto& createInfo = glesTexture->GetCreateInfo();
TextureProperties properties{};
properties.format = createInfo.format;
void EglGraphicsController::CreateSurfaceContext(Dali::RenderSurfaceInterface* surface)
{
- std::unique_ptr<GLES::Context> context = std::make_unique<GLES::Context>(*this);
+ std::unique_ptr<GLES::Context> context = std::make_unique<GLES::Context>(*this, mGlAbstraction);
mSurfaceContexts.push_back(std::move(std::make_pair(surface, std::move(context))));
}
void EglGraphicsController::ProcessDiscardQueues()
{
+ DALI_TRACE_SCOPE(gTraceFilter, "DALI_EGL_CONTROLLER_DISCARD_QUEUE");
+
// Process textures
- ProcessDiscardQueue<GLES::Texture>(mDiscardTextureQueue);
+ ProcessDiscardSet<GLES::Texture>(mDiscardTextureSet);
// Process buffers
ProcessDiscardQueue<GLES::Buffer>(mDiscardBufferQueue);
ProcessDiscardQueue<GLES::RenderTarget>(mDiscardRenderTargetQueue);
// Process pipelines
+ if(mPipelineCache && !mDiscardPipelineQueue.empty())
+ {
+ mPipelineCache->MarkPipelineCacheFlushRequired();
+ }
ProcessDiscardQueue(mDiscardPipelineQueue);
// Process programs
+ if(mPipelineCache && !mDiscardProgramQueue.empty())
+ {
+ mPipelineCache->MarkProgramCacheFlushRequired();
+ }
ProcessDiscardQueue<GLES::Program>(mDiscardProgramQueue);
// Process shaders
void EglGraphicsController::ProcessCreateQueues()
{
+ DALI_TRACE_SCOPE(gTraceFilter, "DALI_EGL_CONTROLLER_CREATE_QUEUE");
// Process textures
ProcessCreateQueue(mCreateTextureQueue);
{
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 << "]";
+ });
+
for(auto i = 0u; i < count; ++i)
{
auto& cmd = commands[i];
{
auto* info = &cmd.drawNative.drawNativeInfo;
- mCurrentContext->PrepareForNativeRendering();
+ // ISOLATED execution mode will isolate GL graphics context from
+ // DALi renderning pipeline which is the safest way of rendering
+ // the 'injected' code.
+ if(info->executionMode == DrawNativeExecutionMode::ISOLATED)
+ {
+ mCurrentContext->PrepareForNativeRendering();
+ }
if(info->glesNativeInfo.eglSharedContextStoragePointer)
{
}
CallbackBase::ExecuteReturn<bool>(*info->callback, info->userData);
-
- mCurrentContext->RestoreFromNativeRendering();
+ if(info->executionMode == DrawNativeExecutionMode::ISOLATED)
+ {
+ mCurrentContext->RestoreFromNativeRendering();
+ }
+ else
+ {
+ // After native rendering reset all states and caches.
+ // This is going to be called only when DIRECT execution mode is used
+ // and some GL states need to be reset.
+ // This does not guarantee that after execution a custom GL code
+ // the main rendering pipeline will work correctly and it's a responsibility
+ // of developer to make sure the GL states are not interfering with main
+ // rendering pipeline (by restoring/cleaning up GL states after drawing).
+ mCurrentContext->ResetGLESState();
+ }
break;
}
}
}
+ DALI_TRACE_END(gTraceFilter, "DALI_EGL_CONTROLLER_PROCESS");
}
void EglGraphicsController::ProcessCommandQueues()
void EglGraphicsController::ProcessTextureUpdateQueue()
{
+ if(mTextureUpdateRequests.empty())
+ {
+ return;
+ }
+ DALI_TRACE_SCOPE(gTraceFilter, "DALI_EGL_CONTROLLER_TEXTURE_UPDATE");
while(!mTextureUpdateRequests.empty())
{
TextureUpdateRequest& request = mTextureUpdateRequests.front();
info.srcExtent2D.width != (createInfo.size.width / (1 << info.level)) ||
info.srcExtent2D.height != (createInfo.size.height / (1 << info.level)));
- uint8_t* sourceBuffer;
+ uint8_t* sourceBuffer = nullptr;
+ bool sourceBufferReleaseRequired = false;
if(source.sourceType == Graphics::TextureUpdateSourceInfo::Type::MEMORY)
{
- sourceBuffer = reinterpret_cast<uint8_t*>(source.memorySource.memory);
+ sourceBuffer = reinterpret_cast<uint8_t*>(source.memorySource.memory);
+ sourceBufferReleaseRequired = true;
}
else
{
- // Get buffer of PixelData
Dali::Integration::PixelDataBuffer pixelBufferData = Dali::Integration::GetPixelDataBuffer(source.pixelDataSource.pixelData);
- sourceBuffer = pixelBufferData.buffer + info.srcOffset;
+ sourceBuffer = pixelBufferData.buffer + info.srcOffset;
+ sourceBufferReleaseRequired = Dali::Integration::IsPixelDataReleaseAfterUpload(source.pixelDataSource.pixelData) && info.srcOffset == 0u;
}
- auto sourceStride = info.srcStride;
- std::vector<uint8_t> tempBuffer;
-
- if(mGlAbstraction->TextureRequiresConverting(srcFormat, destFormat, isSubImage))
+ // Skip texture upload if given texture is already discarded for this render loop.
+ if(mDiscardTextureSet.find(texture) == mDiscardTextureSet.end())
{
- // Convert RGB to RGBA if necessary.
- if(texture->TryConvertPixelData(sourceBuffer, info.srcFormat, createInfo.format, info.srcSize, info.srcStride, info.srcExtent2D.width, info.srcExtent2D.height, tempBuffer))
+ auto sourceStride = info.srcStride;
+ std::vector<uint8_t> tempBuffer;
+
+ uint8_t* srcBuffer = sourceBuffer;
+
+ if(mGlAbstraction->TextureRequiresConverting(srcFormat, destFormat, isSubImage))
{
- sourceBuffer = &tempBuffer[0];
- sourceStride = 0u; // Converted buffer compacted. make stride as 0.
- srcFormat = destFormat;
- srcType = GLES::GLTextureFormatType(createInfo.format).type;
+ // Convert RGB to RGBA if necessary.
+ if(texture->TryConvertPixelData(sourceBuffer, info.srcFormat, createInfo.format, info.srcSize, info.srcStride, info.srcExtent2D.width, info.srcExtent2D.height, tempBuffer))
+ {
+ srcBuffer = &tempBuffer[0];
+ sourceStride = 0u; // Converted buffer compacted. make stride as 0.
+ srcFormat = destFormat;
+ srcType = GLES::GLTextureFormatType(createInfo.format).type;
+ }
}
- }
- // Calculate the maximum mipmap level for the texture
- texture->SetMaxMipMapLevel(std::max(texture->GetMaxMipMapLevel(), info.level));
+ // Calculate the maximum mipmap level for the texture
+ texture->SetMaxMipMapLevel(std::max(texture->GetMaxMipMapLevel(), info.level));
- GLenum bindTarget{GL_TEXTURE_2D};
- GLenum target{GL_TEXTURE_2D};
+ GLenum bindTarget{GL_TEXTURE_2D};
+ GLenum target{GL_TEXTURE_2D};
- if(createInfo.textureType == Graphics::TextureType::TEXTURE_CUBEMAP)
- {
- bindTarget = GL_TEXTURE_CUBE_MAP;
- target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + info.layer;
- }
+ if(createInfo.textureType == Graphics::TextureType::TEXTURE_CUBEMAP)
+ {
+ bindTarget = GL_TEXTURE_CUBE_MAP;
+ target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + info.layer;
+ }
- mGlAbstraction->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
- mGlAbstraction->PixelStorei(GL_UNPACK_ROW_LENGTH, sourceStride);
+ mGlAbstraction->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ mGlAbstraction->PixelStorei(GL_UNPACK_ROW_LENGTH, sourceStride);
- mCurrentContext->BindTexture(bindTarget, texture->GetTextureTypeId(), texture->GetGLTexture());
+ mCurrentContext->BindTexture(bindTarget, texture->GetTextureTypeId(), texture->GetGLTexture());
- if(!isSubImage)
- {
- if(!texture->IsCompressed())
+ if(!isSubImage)
{
- mGlAbstraction->TexImage2D(target,
- info.level,
- destInternalFormat,
- info.srcExtent2D.width,
- info.srcExtent2D.height,
- 0,
- srcFormat,
- srcType,
- sourceBuffer);
+ if(!texture->IsCompressed())
+ {
+ mGlAbstraction->TexImage2D(target,
+ info.level,
+ destInternalFormat,
+ info.srcExtent2D.width,
+ info.srcExtent2D.height,
+ 0,
+ srcFormat,
+ srcType,
+ srcBuffer);
+ }
+ else
+ {
+ mGlAbstraction->CompressedTexImage2D(target,
+ info.level,
+ destInternalFormat,
+ info.srcExtent2D.width,
+ info.srcExtent2D.height,
+ 0,
+ info.srcSize,
+ srcBuffer);
+ }
}
else
{
- mGlAbstraction->CompressedTexImage2D(target,
- info.level,
- destInternalFormat,
- info.srcExtent2D.width,
- info.srcExtent2D.height,
- 0,
- info.srcSize,
- sourceBuffer);
+ if(!texture->IsCompressed())
+ {
+ mGlAbstraction->TexSubImage2D(target,
+ info.level,
+ info.dstOffset2D.x,
+ info.dstOffset2D.y,
+ info.srcExtent2D.width,
+ info.srcExtent2D.height,
+ srcFormat,
+ srcType,
+ srcBuffer);
+ }
+ else
+ {
+ mGlAbstraction->CompressedTexSubImage2D(target,
+ info.level,
+ info.dstOffset2D.x,
+ info.dstOffset2D.y,
+ info.srcExtent2D.width,
+ info.srcExtent2D.height,
+ srcFormat,
+ info.srcSize,
+ srcBuffer);
+ }
}
}
- else
+
+ if(sourceBufferReleaseRequired && sourceBuffer != nullptr)
{
- if(!texture->IsCompressed())
+ if(source.sourceType == Graphics::TextureUpdateSourceInfo::Type::MEMORY)
{
- mGlAbstraction->TexSubImage2D(target,
- info.level,
- info.dstOffset2D.x,
- info.dstOffset2D.y,
- info.srcExtent2D.width,
- info.srcExtent2D.height,
- srcFormat,
- srcType,
- sourceBuffer);
+ free(reinterpret_cast<void*>(sourceBuffer));
}
else
{
- mGlAbstraction->CompressedTexSubImage2D(target,
- info.level,
- info.dstOffset2D.x,
- info.dstOffset2D.y,
- info.srcExtent2D.width,
- info.srcExtent2D.height,
- srcFormat,
- info.srcSize,
- sourceBuffer);
+ Dali::Integration::ReleasePixelDataBuffer(source.pixelDataSource.pixelData);
}
}
-
- if(source.sourceType == Graphics::TextureUpdateSourceInfo::Type::MEMORY)
- {
- // free staging memory
- free(source.memorySource.memory);
- }
break;
}
default:
uint8_t* stagingBuffer = reinterpret_cast<uint8_t*>(malloc(info.srcSize));
- uint8_t* srcMemory = &reinterpret_cast<uint8_t*>(source.memorySource.memory)[info.srcOffset];
+ if(DALI_UNLIKELY(stagingBuffer == nullptr))
+ {
+ DALI_LOG_ERROR("malloc is failed. request malloc size : %u\n", info.srcSize);
+ }
+ else
+ {
+ uint8_t* srcMemory = &reinterpret_cast<uint8_t*>(source.memorySource.memory)[info.srcOffset];
- std::copy(srcMemory, srcMemory + info.srcSize, stagingBuffer);
+ std::copy(srcMemory, srcMemory + info.srcSize, stagingBuffer);
- mTextureUploadTotalCPUMemoryUsed += info.srcSize;
+ mTextureUploadTotalCPUMemoryUsed += info.srcSize;
+ }
// store staging buffer
source.memorySource.memory = stagingBuffer;
void EglGraphicsController::ProcessTextureMipmapGenerationQueue()
{
+ if(mTextureMipmapGenerationRequests.empty())
+ {
+ return;
+ }
+ DALI_TRACE_SCOPE(gTraceFilter, "DALI_EGL_CONTROLLER_TEXTURE_MIPMAP");
while(!mTextureMipmapGenerationRequests.empty())
{
auto* texture = mTextureMipmapGenerationRequests.front();
return *mPipelineCache;
}
+Graphics::Texture* EglGraphicsController::CreateTextureByResourceId(uint32_t resourceId, const Graphics::TextureCreateInfo& createInfo)
+{
+ Graphics::Texture* ret = nullptr;
+ Graphics::UniquePtr<Graphics::Texture> texture;
+
+ auto iter = mExternalTextureResources.find(resourceId);
+ DALI_ASSERT_ALWAYS(iter == mExternalTextureResources.end());
+
+ texture = CreateTexture(createInfo, std::move(texture));
+
+ ret = texture.get();
+
+ mExternalTextureResources.insert(std::make_pair(resourceId, std::move(texture)));
+
+ return ret;
+}
+
+void EglGraphicsController::DiscardTextureFromResourceId(uint32_t resourceId)
+{
+ auto iter = mExternalTextureResources.find(resourceId);
+ if(iter != mExternalTextureResources.end())
+ {
+ mExternalTextureResources.erase(iter);
+ }
+}
+
+Graphics::Texture* EglGraphicsController::GetTextureFromResourceId(uint32_t resourceId)
+{
+ Graphics::Texture* ret = nullptr;
+
+ auto iter = mExternalTextureResources.find(resourceId);
+ if(iter != mExternalTextureResources.end())
+ {
+ ret = iter->second.get();
+ }
+
+ return ret;
+}
+
+Graphics::UniquePtr<Graphics::Texture> EglGraphicsController::ReleaseTextureFromResourceId(uint32_t resourceId)
+{
+ Graphics::UniquePtr<Graphics::Texture> texture;
+
+ auto iter = mExternalTextureResources.find(resourceId);
+ if(iter != mExternalTextureResources.end())
+ {
+ texture = std::move(iter->second);
+ mExternalTextureResources.erase(iter);
+ }
+
+ return texture;
+}
+
} // namespace Dali::Graphics