/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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/integration-api/debug.h>
#include <dali/integration-api/gl-abstraction.h>
#include <dali/integration-api/gl-defines.h>
+#include <dali/integration-api/graphics-sync-abstraction.h>
+#include <dali/internal/graphics/gles-impl/egl-sync-object.h>
#include <dali/internal/graphics/gles-impl/gles-graphics-command-buffer.h>
#include <dali/internal/graphics/gles-impl/gles-graphics-pipeline.h>
+#include <dali/internal/graphics/gles-impl/gles-graphics-program.h>
#include <dali/internal/graphics/gles-impl/gles-graphics-render-pass.h>
#include <dali/internal/graphics/gles-impl/gles-graphics-render-target.h>
#include <dali/internal/graphics/gles-impl/gles-graphics-shader.h>
#include <dali/internal/graphics/gles-impl/gles-graphics-texture.h>
#include <dali/internal/graphics/gles-impl/gles-graphics-types.h>
+#include <dali/internal/graphics/gles-impl/gles-sync-object.h>
#include <dali/internal/graphics/gles-impl/gles3-graphics-memory.h>
+#include <dali/internal/graphics/gles/egl-sync-implementation.h>
#include <dali/public-api/common/dali-common.h>
-#include "gles-graphics-program.h"
+
+#include <dali/internal/graphics/gles/egl-graphics.h>
+
+#include <any>
// Uncomment the following define to turn on frame dumping
//#define ENABLE_COMMAND_BUFFER_FRAME_DUMP 1
} // namespace
-EglGraphicsController::~EglGraphicsController() = default;
+EglGraphicsController::EglGraphicsController()
+: mTextureDependencyChecker(*this),
+ mSyncPool(*this)
+{
+}
+
+EglGraphicsController::~EglGraphicsController()
+{
+ while(!mPresentationCommandBuffers.empty())
+ {
+ auto presentCommandBuffer = const_cast<GLES::CommandBuffer*>(mPresentationCommandBuffers.front());
+ delete presentCommandBuffer;
+ mPresentationCommandBuffers.pop();
+ }
+}
void EglGraphicsController::InitializeGLES(Integration::GlAbstraction& glAbstraction)
{
mCurrentContext = mContext.get();
}
-void EglGraphicsController::Initialize(Integration::GlSyncAbstraction& glSyncAbstraction,
+void EglGraphicsController::Initialize(Integration::GraphicsSyncAbstraction& syncImplementation,
Integration::GlContextHelperAbstraction& glContextHelperAbstraction,
Internal::Adaptor::GraphicsInterface& graphicsInterface)
{
DALI_LOG_RELEASE_INFO("Initializing New Graphics Controller #2\n");
- mGlSyncAbstraction = &glSyncAbstraction;
+ auto* syncImplPtr = static_cast<Internal::Adaptor::EglSyncImplementation*>(&syncImplementation);
+
+ mEglSyncImplementation = syncImplPtr;
mGlContextHelperAbstraction = &glContextHelperAbstraction;
mGraphics = &graphicsInterface;
}
void EglGraphicsController::PresentRenderTarget(RenderTarget* renderTarget)
{
- // Use command buffer to execute presentation (we should pool it)
- CommandBufferCreateInfo info;
- info.SetLevel(CommandBufferLevel::PRIMARY);
- info.fixedCapacity = 1; // only one command
- auto presentCommandBuffer = new GLES::CommandBuffer(info, *this);
+ GLES::CommandBuffer* presentCommandBuffer{nullptr};
+ if(mPresentationCommandBuffers.empty())
+ {
+ CommandBufferCreateInfo info;
+ info.SetLevel(CommandBufferLevel::PRIMARY);
+ info.fixedCapacity = 1; // only one command
+ presentCommandBuffer = new GLES::CommandBuffer(info, *this);
+ }
+ else
+ {
+ presentCommandBuffer = const_cast<GLES::CommandBuffer*>(mPresentationCommandBuffers.front());
+ presentCommandBuffer->Reset();
+ mPresentationCommandBuffers.pop();
+ }
presentCommandBuffer->PresentRenderTarget(static_cast<GLES::RenderTarget*>(renderTarget));
SubmitInfo submitInfo;
submitInfo.cmdBuffer = {presentCommandBuffer};
void EglGraphicsController::ResolvePresentRenderTarget(GLES::RenderTarget* renderTarget)
{
+ mCurrentContext->InvalidateDepthStencilBuffers();
+
auto* rt = static_cast<GLES::RenderTarget*>(renderTarget);
if(rt->GetCreateInfo().surface)
{
}
}
-Integration::GlAbstraction& EglGraphicsController::GetGlAbstraction()
+void EglGraphicsController::PostRender()
{
- DALI_ASSERT_DEBUG(mGlAbstraction && "Graphics controller not initialized");
- return *mGlAbstraction;
+ mTextureDependencyChecker.Reset();
+ mSyncPool.AgeSyncObjects();
}
-Integration::GlSyncAbstraction& EglGraphicsController::GetGlSyncAbstraction()
+Integration::GlAbstraction& EglGraphicsController::GetGlAbstraction()
{
- DALI_ASSERT_DEBUG(mGlSyncAbstraction && "Graphics controller not initialized");
- return *mGlSyncAbstraction;
+ DALI_ASSERT_DEBUG(mGlAbstraction && "Graphics controller not initialized");
+ return *mGlAbstraction;
}
Integration::GlContextHelperAbstraction& EglGraphicsController::GetGlContextHelperAbstraction()
return *mGlContextHelperAbstraction;
}
+Internal::Adaptor::EglSyncImplementation& EglGraphicsController::GetEglSyncImplementation()
+{
+ DALI_ASSERT_DEBUG(mEglSyncImplementation && "Sync implementation not initialized");
+ return *mEglSyncImplementation;
+}
+
Graphics::UniquePtr<CommandBuffer> EglGraphicsController::CreateCommandBuffer(
const CommandBufferCreateInfo& commandBufferCreateInfo,
Graphics::UniquePtr<CommandBuffer>&& oldCommandBuffer)
return NewObject<GLES::RenderTarget>(renderTargetCreateInfo, *this, std::move(oldRenderTarget));
}
+Graphics::UniquePtr<SyncObject> EglGraphicsController::CreateSyncObject(const SyncObjectCreateInfo& syncObjectCreateInfo,
+ UniquePtr<SyncObject>&& oldSyncObject)
+{
+ if(GetGLESVersion() < GLES::GLESVersion::GLES_30)
+ {
+ return NewObject<EGL::SyncObject>(syncObjectCreateInfo, *this, std::move(oldSyncObject));
+ }
+ else
+ {
+ return NewObject<GLES::SyncObject>(syncObjectCreateInfo, *this, std::move(oldSyncObject));
+ }
+}
+
+TextureProperties EglGraphicsController::GetTextureProperties(const Texture& texture)
+{
+ const GLES::Texture* glesTexture = static_cast<const GLES::Texture*>(&texture);
+ auto createInfo = glesTexture->GetCreateInfo();
+
+ TextureProperties properties{};
+ properties.format = createInfo.format;
+ properties.compressed = glesTexture->IsCompressed();
+ properties.extent2D = createInfo.size;
+ properties.nativeHandle = glesTexture->GetGLTexture();
+ //TODO: Skip format1, emulated, packed, directWriteAccessEnabled of TextureProperties for now
+
+ return properties;
+}
+
const Graphics::Reflection& EglGraphicsController::GetProgramReflection(const Graphics::Program& program)
{
return static_cast<const Graphics::GLES::Program*>(&program)->GetReflection();
void EglGraphicsController::ActivateResourceContext()
{
mCurrentContext = mContext.get();
+ mCurrentContext->GlContextCreated();
+
+ if(!mSharedContext)
+ {
+ auto eglGraphics = dynamic_cast<Dali::Internal::Adaptor::EglGraphics*>(mGraphics);
+ if(eglGraphics)
+ {
+ mSharedContext = eglGraphics->GetEglImplementation().GetContext();
+ }
+ }
}
void EglGraphicsController::ActivateSurfaceContext(Dali::RenderSurfaceInterface* surface)
if(iter != mSurfaceContexts.end())
{
mCurrentContext = iter->second.get();
+ mCurrentContext->GlContextCreated();
}
}
}
// Process Framebuffers
ProcessDiscardQueue<GLES::Framebuffer>(mDiscardFramebufferQueue);
+ // Process RenderPass
+ ProcessDiscardQueue<GLES::RenderPass>(mDiscardRenderPassQueue);
+
+ // Process RenderTarget
+ ProcessDiscardQueue<GLES::RenderTarget>(mDiscardRenderTargetQueue);
+
// Process pipelines
- ProcessDiscardQueue<GLES::Pipeline>(mDiscardPipelineQueue);
+ ProcessDiscardQueue(mDiscardPipelineQueue);
// Process programs
ProcessDiscardQueue<GLES::Program>(mDiscardProgramQueue);
void EglGraphicsController::ProcessCommandBuffer(const GLES::CommandBuffer& commandBuffer)
{
- for(auto& cmd : commandBuffer.GetCommands())
+ auto count = 0u;
+ const auto commands = commandBuffer.GetCommands(count);
+ for(auto i = 0u; i < count; ++i)
{
+ auto& cmd = commands[i];
// process command
switch(cmd.type)
{
}
case GLES::CommandType::BIND_TEXTURES:
{
- mCurrentContext->BindTextures(cmd.bindTextures.textureBindings);
+ mCurrentContext->BindTextures(cmd.bindTextures.textureBindings.Ptr(), cmd.bindTextures.textureBindingsCount);
break;
}
case GLES::CommandType::BIND_VERTEX_BUFFERS:
{
- auto& bindings = cmd.bindVertexBuffers.vertexBufferBindings;
- mCurrentContext->BindVertexBuffers(bindings);
+ auto bindings = cmd.bindVertexBuffers.vertexBufferBindings.Ptr();
+ mCurrentContext->BindVertexBuffers(bindings, cmd.bindVertexBuffers.vertexBufferBindingsCount);
break;
}
case GLES::CommandType::BIND_UNIFORM_BUFFER:
{
auto& bindings = cmd.bindUniformBuffers;
- mCurrentContext->BindUniformBuffers(bindings.uniformBufferBindings, bindings.standaloneUniformsBufferBinding);
+ mCurrentContext->BindUniformBuffers(bindings.uniformBufferBindingsCount ? bindings.uniformBufferBindings.Ptr() : nullptr, bindings.uniformBufferBindingsCount, bindings.standaloneUniformsBufferBinding);
break;
}
case GLES::CommandType::BIND_INDEX_BUFFER:
}
case GLES::CommandType::DRAW:
{
- mCurrentContext->Flush(false, cmd.draw);
+ mCurrentContext->Flush(false, cmd.draw, mTextureDependencyChecker);
break;
}
case GLES::CommandType::DRAW_INDEXED:
{
- mCurrentContext->Flush(false, cmd.draw);
+ mCurrentContext->Flush(false, cmd.draw, mTextureDependencyChecker);
break;
}
case GLES::CommandType::DRAW_INDEXED_INDIRECT:
{
- mCurrentContext->Flush(false, cmd.draw);
+ mCurrentContext->Flush(false, cmd.draw, mTextureDependencyChecker);
break;
}
case GLES::CommandType::SET_SCISSOR: // @todo Consider correcting for orientation here?
}
case GLES::CommandType::SET_SCISSOR_TEST:
{
- if(cmd.scissorTest.enable)
- {
- mGlAbstraction->Enable(GL_SCISSOR_TEST);
- }
- else
- {
- mGlAbstraction->Disable(GL_SCISSOR_TEST);
- }
+ mCurrentContext->SetScissorTestEnabled(cmd.scissorTest.enable);
break;
}
case GLES::CommandType::SET_VIEWPORT: // @todo Consider correcting for orientation here?
}
mCurrentContext->BeginRenderPass(cmd.beginRenderPass);
+
break;
}
case GLES::CommandType::END_RENDERPASS:
{
- mCurrentContext->EndRenderPass();
+ mCurrentContext->EndRenderPass(mTextureDependencyChecker);
+
+ // This sync object is to enable cpu to wait for rendering to complete, not gpu.
+ // It's only needed for reading the framebuffer texture in the client.
+ auto syncObject = const_cast<GLES::SyncObject*>(static_cast<const GLES::SyncObject*>(cmd.endRenderPass.syncObject));
+ if(syncObject)
+ {
+ syncObject->InitializeResource();
+ }
break;
}
case GLES::CommandType::PRESENT_RENDER_TARGET:
{
ResolvePresentRenderTarget(cmd.presentRenderTarget.targetToPresent);
- // push this command buffer to the discard queue
- mDiscardCommandBufferQueue.push(const_cast<GLES::CommandBuffer*>(&commandBuffer));
+ // The command buffer will be pushed into the queue of presentation command buffers
+ // for further reuse.
+ if(commandBuffer.GetCreateInfo().fixedCapacity == 1)
+ {
+ mPresentationCommandBuffers.push(&commandBuffer);
+ }
break;
}
case GLES::CommandType::EXECUTE_COMMAND_BUFFERS:
// todo: check validity of the secondaries
// there are operations which are illigal to be done
// within secondaries.
- for(auto& buf : cmd.executeCommandBuffers.buffers)
+ auto buffers = cmd.executeCommandBuffers.buffers.Ptr();
+ for(auto j = 0u; j < cmd.executeCommandBuffers.buffersCount; ++j)
{
+ auto& buf = buffers[j];
ProcessCommandBuffer(*static_cast<const GLES::CommandBuffer*>(buf));
}
break;
}
+ case GLES::CommandType::DRAW_NATIVE:
+ {
+ auto* info = &cmd.drawNative.drawNativeInfo;
+
+ mCurrentContext->PrepareForNativeRendering();
+
+ if(info->glesNativeInfo.eglSharedContextStoragePointer)
+ {
+ auto* anyContext = reinterpret_cast<std::any*>(info->glesNativeInfo.eglSharedContextStoragePointer);
+ *anyContext = mSharedContext;
+ }
+
+ CallbackBase::ExecuteReturn<bool>(*info->callback, info->userData);
+
+ mCurrentContext->RestoreFromNativeRendering();
+ break;
+ }
}
}
}
void EglGraphicsController::ProcessCommandQueues()
{
- // TODO: command queue per context, sync between queues should be
- // done externally
- currentFramebuffer = nullptr;
-
DUMP_FRAME_START();
while(!mCommandQueue.empty())
info.srcExtent2D.height != (createInfo.size.height / (1 << info.level)));
auto* sourceBuffer = reinterpret_cast<uint8_t*>(source.memorySource.memory);
+ auto sourceStride = info.srcStride;
std::vector<uint8_t> tempBuffer;
+
if(mGlAbstraction->TextureRequiresConverting(srcFormat, destFormat, isSubImage))
{
// Convert RGB to RGBA if necessary.
- texture->TryConvertPixelData(source.memorySource.memory, info.srcFormat, createInfo.format, info.srcSize, info.srcExtent2D.width, info.srcExtent2D.height, tempBuffer);
- sourceBuffer = &tempBuffer[0];
- srcFormat = destFormat;
- srcType = GLES::GLTextureFormatType(createInfo.format).type;
+ if(texture->TryConvertPixelData(source.memorySource.memory, info.srcFormat, createInfo.format, info.srcSize, info.srcStride, info.srcExtent2D.width, info.srcExtent2D.height, tempBuffer))
+ {
+ sourceBuffer = &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
}
mGlAbstraction->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
- mGlAbstraction->BindTexture(bindTarget, texture->GetGLTexture());
+ mGlAbstraction->PixelStorei(GL_UNPACK_ROW_LENGTH, sourceStride);
+
+ mCurrentContext->BindTexture(bindTarget, texture->GetTextureTypeId(), texture->GetGLTexture());
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,
+ sourceBuffer);
+ }
+ else
+ {
+ mGlAbstraction->CompressedTexImage2D(target,
+ info.level,
+ destInternalFormat,
+ info.srcExtent2D.width,
+ info.srcExtent2D.height,
+ 0,
+ info.srcSize,
+ sourceBuffer);
+ }
}
else
{
- mGlAbstraction->TexSubImage2D(target,
- info.level,
- info.dstOffset2D.x,
- info.dstOffset2D.y,
- info.srcExtent2D.width,
- info.srcExtent2D.height,
- srcFormat,
- srcType,
- sourceBuffer);
+ if(!texture->IsCompressed())
+ {
+ mGlAbstraction->TexSubImage2D(target,
+ info.level,
+ info.dstOffset2D.x,
+ info.dstOffset2D.y,
+ info.srcExtent2D.width,
+ info.srcExtent2D.height,
+ srcFormat,
+ srcType,
+ sourceBuffer);
+ }
+ else
+ {
+ mGlAbstraction->CompressedTexSubImage2D(target,
+ info.level,
+ info.dstOffset2D.x,
+ info.dstOffset2D.y,
+ info.srcExtent2D.width,
+ info.srcExtent2D.height,
+ srcFormat,
+ info.srcSize,
+ sourceBuffer);
+ }
}
// free staging memory
free(source.memorySource.memory);
// TODO: using PBO with GLES3, this is just naive
// oldschool way
- char* stagingBuffer = reinterpret_cast<char*>(malloc(info.srcSize));
- std::copy(&reinterpret_cast<char*>(source.memorySource.memory)[info.srcOffset],
- reinterpret_cast<char*>(source.memorySource.memory) + info.srcSize,
- stagingBuffer);
+ uint8_t* stagingBuffer = reinterpret_cast<uint8_t*>(malloc(info.srcSize));
+
+ uint8_t* srcMemory = &reinterpret_cast<uint8_t*>(source.memorySource.memory)[info.srcOffset];
+
+ std::copy(srcMemory, srcMemory + info.srcSize, stagingBuffer);
mTextureUploadTotalCPUMemoryUsed += info.srcSize;
}
// If upload buffer exceeds maximum size, flush.
- if(mTextureUploadTotalCPUMemoryUsed > TEXTURE_UPLOAD_MAX_BUFER_SIZE_MB * 1024)
+ if(mTextureUploadTotalCPUMemoryUsed > TEXTURE_UPLOAD_MAX_BUFER_SIZE_MB * 1024 * 1024)
{
Flush();
mTextureUploadTotalCPUMemoryUsed = 0;
{
auto* texture = mTextureMipmapGenerationRequests.front();
- mGlAbstraction->BindTexture(texture->GetGlTarget(), texture->GetGLTexture());
- mGlAbstraction->GenerateMipmap(texture->GetGlTarget());
+ mCurrentContext->BindTexture(texture->GetGlTarget(), texture->GetTextureTypeId(), texture->GetGLTexture());
+ mCurrentContext->GenerateMipmap(texture->GetGlTarget());
mTextureMipmapGenerationRequests.pop();
}