From fee67a7b174e7e282a56c86bb195ba2d7ef5ee08 Mon Sep 17 00:00:00 2001 From: David Steele Date: Mon, 22 Mar 2021 17:59:56 +0000 Subject: [PATCH] Added framebuffer support Added framebuffer object to handle color attachments and depth/stencil attachments. Added switching of framebuffer when pipeline changes. This is temporary, and should be tied instead to renderpass. Change-Id: I8146eca2005cc27466cc6a86519b8f44c28c64a7 Signed-off-by: David Steele --- .../graphics/gles-impl/egl-graphics-controller.cpp | 51 +++++-- .../graphics/gles-impl/egl-graphics-controller.h | 28 +++- .../gles-impl/gles-graphics-framebuffer.cpp | 168 +++++++++++++++++++++ .../graphics/gles-impl/gles-graphics-framebuffer.h | 44 +++--- .../graphics/gles-impl/gles-graphics-texture.h | 9 ++ 5 files changed, 267 insertions(+), 33 deletions(-) diff --git a/dali/internal/graphics/gles-impl/egl-graphics-controller.cpp b/dali/internal/graphics/gles-impl/egl-graphics-controller.cpp index 8fe7b73..2441515 100644 --- a/dali/internal/graphics/gles-impl/egl-graphics-controller.cpp +++ b/dali/internal/graphics/gles-impl/egl-graphics-controller.cpp @@ -140,26 +140,33 @@ Integration::GlContextHelperAbstraction& EglGraphicsController::GetGlContextHelp return *mGlContextHelperAbstraction; } -Graphics::UniquePtr -EglGraphicsController::CreateCommandBuffer(const CommandBufferCreateInfo& commandBufferCreateInfo, - Graphics::UniquePtr&& oldCommandBuffer) +Graphics::UniquePtr EglGraphicsController::CreateCommandBuffer( + const CommandBufferCreateInfo& commandBufferCreateInfo, + Graphics::UniquePtr&& oldCommandBuffer) { return NewObject(commandBufferCreateInfo, *this, std::move(oldCommandBuffer)); } -Graphics::UniquePtr -EglGraphicsController::CreateTexture(const TextureCreateInfo& textureCreateInfo, Graphics::UniquePtr&& oldTexture) +Graphics::UniquePtr EglGraphicsController::CreateTexture( + const TextureCreateInfo& textureCreateInfo, Graphics::UniquePtr&& oldTexture) { return NewObject(textureCreateInfo, *this, std::move(oldTexture)); } -Graphics::UniquePtr -EglGraphicsController::CreateBuffer(const BufferCreateInfo& bufferCreateInfo, Graphics::UniquePtr&& oldBuffer) +Graphics::UniquePtr EglGraphicsController::CreateBuffer( + const BufferCreateInfo& bufferCreateInfo, Graphics::UniquePtr&& oldBuffer) { return NewObject(bufferCreateInfo, *this, std::move(oldBuffer)); } -Graphics::UniquePtr EglGraphicsController::CreatePipeline(const PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr&& oldPipeline) +Graphics::UniquePtr EglGraphicsController::CreateFramebuffer( + const FramebufferCreateInfo& framebufferCreateInfo, Graphics::UniquePtr&& oldFramebuffer) +{ + return NewObject(framebufferCreateInfo, *this, std::move(oldFramebuffer)); +} + +Graphics::UniquePtr EglGraphicsController::CreatePipeline( + const PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr&& oldPipeline) { // Create pipeline cache if needed if(!mPipelineCache) @@ -170,7 +177,8 @@ Graphics::UniquePtr EglGraphicsController::CreatePipeline(const Pipeli return mPipelineCache->GetPipeline(pipelineCreateInfo, std::move(oldPipeline)); } -Graphics::UniquePtr EglGraphicsController::CreateProgram(const ProgramCreateInfo& programCreateInfo, UniquePtr&& oldProgram) +Graphics::UniquePtr EglGraphicsController::CreateProgram( + const ProgramCreateInfo& programCreateInfo, UniquePtr&& oldProgram) { // Create program cache if needed if(!mPipelineCache) @@ -208,6 +216,12 @@ void EglGraphicsController::AddBuffer(GLES::Buffer& buffer) mCreateBufferQueue.push(&buffer); } +void EglGraphicsController::AddFramebuffer(GLES::Framebuffer& framebuffer) +{ + // Assuming we are on the correct context + mCreateFramebufferQueue.push(&framebuffer); +} + void EglGraphicsController::ProcessDiscardQueues() { // Process textures @@ -216,6 +230,9 @@ void EglGraphicsController::ProcessDiscardQueues() // Process buffers ProcessDiscardQueue(mDiscardBufferQueue); + // Process Framebuffers + ProcessDiscardQueue(mDiscardFramebufferQueue); + // Process pipelines ProcessDiscardQueue(mDiscardPipelineQueue); @@ -239,12 +256,16 @@ void EglGraphicsController::ProcessCreateQueues() // Process buffers ProcessCreateQueue(mCreateBufferQueue); + + // Process framebuffers + ProcessCreateQueue(mCreateFramebufferQueue); } void EglGraphicsController::ProcessCommandQueues() { // TODO: command queue per context, sync between queues should be // done externally + const Graphics::Framebuffer* currentFramebuffer{nullptr}; while(!mCommandQueue.empty()) { @@ -289,7 +310,17 @@ void EglGraphicsController::ProcessCommandQueues() } case GLES::CommandType::BIND_PIPELINE: { - mContext->BindPipeline(cmd.bindPipeline.pipeline); + auto pipeline = static_cast(cmd.bindPipeline.pipeline); + + // Bind framebuffer if different. @todo Move to RenderPass + auto fbState = pipeline->GetCreateInfo().framebufferState; + if(fbState && fbState->framebuffer != currentFramebuffer) + { + currentFramebuffer = fbState->framebuffer; + static_cast(currentFramebuffer)->Bind(); + } + + mContext->BindPipeline(pipeline); break; } case GLES::CommandType::DRAW: diff --git a/dali/internal/graphics/gles-impl/egl-graphics-controller.h b/dali/internal/graphics/gles-impl/egl-graphics-controller.h index ccfe519..a4acea4 100644 --- a/dali/internal/graphics/gles-impl/egl-graphics-controller.h +++ b/dali/internal/graphics/gles-impl/egl-graphics-controller.h @@ -25,6 +25,7 @@ #include "gles-context.h" #include "gles-graphics-buffer.h" #include "gles-graphics-command-buffer.h" +#include "gles-graphics-framebuffer.h" #include "gles-graphics-pipeline-cache.h" #include "gles-graphics-pipeline.h" #include "gles-graphics-reflection.h" @@ -206,10 +207,7 @@ public: /** * @copydoc Dali::Graphics::CreateFramebuffer() */ - Graphics::UniquePtr CreateFramebuffer(const FramebufferCreateInfo& framebufferCreateInfo, Graphics::UniquePtr&& oldFramebuffer) override - { - return nullptr; - } + Graphics::UniquePtr CreateFramebuffer(const FramebufferCreateInfo& framebufferCreateInfo, Graphics::UniquePtr&& oldFramebuffer) override; /** * @copydoc Dali::Graphics::CreatePipeline() @@ -317,6 +315,12 @@ public: void AddBuffer(GLES::Buffer& buffer); /** + * @brief Adds framebuffer to the creation queue + * @param buffer + */ + void AddFramebuffer(GLES::Framebuffer& framebuffer); + + /** * @brief Pushes Bufer to the discard queue * * Function is called from the UniquePtr custom deleter. @@ -333,7 +337,7 @@ public: * * Function is called from the UniquePtr custom deleter. * - * @param[in] texture Pointer to the texture + * @param[in] buffer Pointer to the buffer object */ void DiscardResource(GLES::Buffer* buffer) { @@ -341,6 +345,18 @@ public: } /** + * @brief Pushes framebuffer to the discard queue + * + * Function is called from the UniquePtr custom deleter. + * + * @param[in] framebuffer Pointer to the framebuffer object + */ + void DiscardResource(GLES::Framebuffer* framebuffer) + { + mDiscardFramebufferQueue.push(framebuffer); + } + + /** * @brief Pushes Program to the discard queue * * Function is called from the UniquePtr custom deleter. @@ -552,6 +568,8 @@ private: std::queue mDiscardShaderQueue; ///< Discard queue of shaders std::queue mDiscardSamplerQueue; ///< Discard queue of samplers std::queue mDiscardCommandBufferQueue; ///< Discard queue of command buffers + std::queue mCreateFramebufferQueue; ///< Create queue for framebuffer resource + std::queue mDiscardFramebufferQueue; ///< Discard queue for framebuffer resource std::queue mCommandQueue; ///< we may have more in the future diff --git a/dali/internal/graphics/gles-impl/gles-graphics-framebuffer.cpp b/dali/internal/graphics/gles-impl/gles-graphics-framebuffer.cpp index 6869bd9..30ef207 100644 --- a/dali/internal/graphics/gles-impl/gles-graphics-framebuffer.cpp +++ b/dali/internal/graphics/gles-impl/gles-graphics-framebuffer.cpp @@ -17,3 +17,171 @@ // CLASS HEADER #include "gles-graphics-framebuffer.h" + +// external headers +#include +#include + +// Internal headers +#include +#include "egl-graphics-controller.h" + +namespace Dali::Graphics::GLES +{ +namespace +{ +const GLenum COLOR_ATTACHMENTS[] = + { + GL_COLOR_ATTACHMENT0, + GL_COLOR_ATTACHMENT1, + GL_COLOR_ATTACHMENT2, + GL_COLOR_ATTACHMENT3, + GL_COLOR_ATTACHMENT4, + GL_COLOR_ATTACHMENT5, + GL_COLOR_ATTACHMENT6, + GL_COLOR_ATTACHMENT7, +}; + +struct DEPTH_STENCIL_ATTACHMENT_TYPE +{ + constexpr explicit DEPTH_STENCIL_ATTACHMENT_TYPE(Graphics::Format textureFormat) + { + switch(textureFormat) + { + case Graphics::Format::D16_UNORM: + case Graphics::Format::D32_SFLOAT: + case Graphics::Format::X8_D24_UNORM_PACK32: + { + attachment = GL_DEPTH_ATTACHMENT; + break; + } + + case Graphics::Format::S8_UINT: // Probably won't work as a standalone texture. + { + attachment = GL_STENCIL_ATTACHMENT; + break; + } + + case Graphics::Format::D16_UNORM_S8_UINT: + case Graphics::Format::D24_UNORM_S8_UINT: + case Graphics::Format::D32_SFLOAT_S8_UINT: + { + attachment = GL_DEPTH_STENCIL_ATTACHMENT; + break; + } + default: + { + attachment = GL_NONE; + break; + } + } + } + Dali::GLenum attachment{GL_NONE}; +}; + +} // anonymous namespace + +Framebuffer::Framebuffer(const Graphics::FramebufferCreateInfo& createInfo, Graphics::EglGraphicsController& controller) +: FramebufferResource(createInfo, controller) +{ + // Add framebuffer to the Resource queue + mController.AddFramebuffer(*this); +} + +bool Framebuffer::InitializeResource() +{ + if(!mInitialized) + { + mInitialized = true; + auto gl = mController.GetGL(); + + gl->GenFramebuffers(1, &mFramebufferId); + gl->BindFramebuffer(GL_FRAMEBUFFER, mFramebufferId); + + for(Graphics::ColorAttachment& attachment : mCreateInfo.colorAttachments) + { + AttachTexture(attachment.texture, COLOR_ATTACHMENTS[attachment.attachmentId], attachment.layerId, attachment.levelId); + } + + // @todo is this per framebuffer, or more immediate state that needs setting when framebuffer changed? + gl->DrawBuffers(mCreateInfo.colorAttachments.size(), COLOR_ATTACHMENTS); + + if(mCreateInfo.depthStencilAttachment.depthTexture) + { + // Create a depth or depth/stencil render target. + auto depthTexture = static_cast(mCreateInfo.depthStencilAttachment.depthTexture); + auto attachmentId = DEPTH_STENCIL_ATTACHMENT_TYPE(depthTexture->GetCreateInfo().format).attachment; + + gl->GenRenderbuffers(1, &mDepthBufferId); + gl->BindRenderbuffer(GL_RENDERBUFFER, mDepthBufferId); + gl->RenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, mCreateInfo.size.width, mCreateInfo.size.height); + gl->FramebufferRenderbuffer(GL_FRAMEBUFFER, attachmentId, GL_RENDERBUFFER, mDepthBufferId); + + AttachTexture(depthTexture, attachmentId, 0, mCreateInfo.depthStencilAttachment.depthLevel); + } + + if(mCreateInfo.depthStencilAttachment.stencilTexture) + { + auto stencilTexture = static_cast(mCreateInfo.depthStencilAttachment.stencilTexture); + auto attachmentId = DEPTH_STENCIL_ATTACHMENT_TYPE(stencilTexture->GetCreateInfo().format).attachment; + + // Create a stencil render target. + gl->GenRenderbuffers(1, &mStencilBufferId); + gl->BindRenderbuffer(GL_RENDERBUFFER, mStencilBufferId); + gl->RenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, mCreateInfo.size.width, mCreateInfo.size.height); + gl->FramebufferRenderbuffer(GL_FRAMEBUFFER, attachmentId, GL_RENDERBUFFER, mStencilBufferId); + + AttachTexture(stencilTexture, attachmentId, 0, mCreateInfo.depthStencilAttachment.stencilLevel); + } + gl->BindFramebuffer(GL_FRAMEBUFFER, 0); + } + + return mInitialized; +} + +void Framebuffer::DestroyResource() +{ + auto gl = mController.GetGL(); + if(mInitialized) + { + if(mDepthBufferId) + { + gl->DeleteRenderbuffers(1, &mDepthBufferId); + } + if(mStencilBufferId) + { + gl->DeleteRenderbuffers(1, &mStencilBufferId); + } + + gl->DeleteFramebuffers(1, &mFramebufferId); + mFramebufferId = 0u; + mInitialized = false; + } +} + +void Framebuffer::DiscardResource() +{ + mController.DiscardResource(this); +} + +void Framebuffer::Bind() const +{ + auto gl = mController.GetGL(); + gl->BindFramebuffer(GL_FRAMEBUFFER, mFramebufferId); +} + +void Framebuffer::AttachTexture(const Graphics::Texture* texture, uint32_t attachmentId, uint32_t layerId, uint32_t levelId) +{ + auto gl = mController.GetGL(); + auto graphicsTexture = static_cast(texture); + if(graphicsTexture->GetCreateInfo().textureType == Graphics::TextureType::TEXTURE_2D) + { + gl->FramebufferTexture2D(GL_FRAMEBUFFER, attachmentId, graphicsTexture->GetGlTarget(), graphicsTexture->GetGLTexture(), levelId); + } + else + { + gl->FramebufferTexture2D(GL_FRAMEBUFFER, attachmentId, GL_TEXTURE_CUBE_MAP_POSITIVE_X + layerId, graphicsTexture->GetGLTexture(), levelId); + } +} + +} //namespace Dali::Graphics::GLES diff --git a/dali/internal/graphics/gles-impl/gles-graphics-framebuffer.h b/dali/internal/graphics/gles-impl/gles-graphics-framebuffer.h index 784d3bd..5a63696 100644 --- a/dali/internal/graphics/gles-impl/gles-graphics-framebuffer.h +++ b/dali/internal/graphics/gles-impl/gles-graphics-framebuffer.h @@ -37,10 +37,7 @@ public: * @param[in] createInfo Valid createInfo structure * @param[in] controller Reference to the controller */ - Framebuffer(const Graphics::FramebufferCreateInfo& createInfo, Graphics::EglGraphicsController& controller) - : FramebufferResource(createInfo, controller) - { - } + Framebuffer(const Graphics::FramebufferCreateInfo& createInfo, Graphics::EglGraphicsController& controller); /** * @brief Destructor @@ -50,31 +47,42 @@ public: /** * @brief Called when GL resources are destroyed */ - void DestroyResource() override - { - // TODO: Implement destroying the resource - } + void DestroyResource() override; /** * @brief Called when initializing the resource * * @return True on success */ - bool InitializeResource() override - { - // TODO: Implement initializing resource - return {}; - } + bool InitializeResource() override; /** * @brief Called when UniquePtr<> on client-side dies */ - void DiscardResource() override - { - // TODO: Implement moving to the discard queue - } + void DiscardResource() override; + + /** + * Used to bind the framebuffer, e.g. when offscreen changes + */ + void Bind() const; + +private: + /** + * Attach a texture to the specified attachment point + * @param[in] texture The texture to bind + * @param[in] attachmentId The attachment point to bind it to + * @param[in] layerId The texture layer (e.g. for cubemap) + * @param[in] levelId The texture mipmap level + */ + void AttachTexture(const Graphics::Texture* texture, uint32_t attachmentId, uint32_t layerId, uint32_t levelId); + +private: + uint32_t mFramebufferId{0u}; + uint32_t mDepthBufferId{0u}; + uint32_t mStencilBufferId{0u}; + bool mInitialized{false}; }; } // namespace Dali::Graphics::GLES -#endif \ No newline at end of file +#endif diff --git a/dali/internal/graphics/gles-impl/gles-graphics-texture.h b/dali/internal/graphics/gles-impl/gles-graphics-texture.h index c6e46dc..f094fe0 100644 --- a/dali/internal/graphics/gles-impl/gles-graphics-texture.h +++ b/dali/internal/graphics/gles-impl/gles-graphics-texture.h @@ -88,6 +88,15 @@ public: */ void Prepare(); + /** + * @brief Returns the GL Target + * @return the Gl target + */ + [[nodiscard]] GLenum GetGlTarget() const + { + return mGlTarget; + } + protected: private: std::vector mStagingBuffer; -- 2.7.4