Added framebuffer support 02/255702/4
authorDavid Steele <david.steele@samsung.com>
Mon, 22 Mar 2021 17:59:56 +0000 (17:59 +0000)
committerAdam Bialogonski <adam.b@samsung.com>
Tue, 13 Apr 2021 09:43:27 +0000 (10:43 +0100)
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 <david.steele@samsung.com>
dali/internal/graphics/gles-impl/egl-graphics-controller.cpp
dali/internal/graphics/gles-impl/egl-graphics-controller.h
dali/internal/graphics/gles-impl/gles-graphics-framebuffer.cpp
dali/internal/graphics/gles-impl/gles-graphics-framebuffer.h
dali/internal/graphics/gles-impl/gles-graphics-texture.h

index 8fe7b73..2441515 100644 (file)
@@ -140,26 +140,33 @@ Integration::GlContextHelperAbstraction& EglGraphicsController::GetGlContextHelp
   return *mGlContextHelperAbstraction;
 }
 
-Graphics::UniquePtr<CommandBuffer>
-EglGraphicsController::CreateCommandBuffer(const CommandBufferCreateInfo&       commandBufferCreateInfo,
-                                           Graphics::UniquePtr<CommandBuffer>&& oldCommandBuffer)
+Graphics::UniquePtr<CommandBuffer> EglGraphicsController::CreateCommandBuffer(
+  const CommandBufferCreateInfo&       commandBufferCreateInfo,
+  Graphics::UniquePtr<CommandBuffer>&& oldCommandBuffer)
 {
   return NewObject<GLES::CommandBuffer>(commandBufferCreateInfo, *this, std::move(oldCommandBuffer));
 }
 
-Graphics::UniquePtr<Texture>
-EglGraphicsController::CreateTexture(const TextureCreateInfo& textureCreateInfo, Graphics::UniquePtr<Texture>&& oldTexture)
+Graphics::UniquePtr<Texture> EglGraphicsController::CreateTexture(
+  const TextureCreateInfo& textureCreateInfo, Graphics::UniquePtr<Texture>&& oldTexture)
 {
   return NewObject<GLES::Texture>(textureCreateInfo, *this, std::move(oldTexture));
 }
 
-Graphics::UniquePtr<Buffer>
-EglGraphicsController::CreateBuffer(const BufferCreateInfo& bufferCreateInfo, Graphics::UniquePtr<Buffer>&& oldBuffer)
+Graphics::UniquePtr<Buffer> EglGraphicsController::CreateBuffer(
+  const BufferCreateInfo& bufferCreateInfo, Graphics::UniquePtr<Buffer>&& oldBuffer)
 {
   return NewObject<GLES::Buffer>(bufferCreateInfo, *this, std::move(oldBuffer));
 }
 
-Graphics::UniquePtr<Pipeline> EglGraphicsController::CreatePipeline(const PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr<Graphics::Pipeline>&& oldPipeline)
+Graphics::UniquePtr<Framebuffer> EglGraphicsController::CreateFramebuffer(
+  const FramebufferCreateInfo& framebufferCreateInfo, Graphics::UniquePtr<Framebuffer>&& oldFramebuffer)
+{
+  return NewObject<GLES::Framebuffer>(framebufferCreateInfo, *this, std::move(oldFramebuffer));
+}
+
+Graphics::UniquePtr<Pipeline> EglGraphicsController::CreatePipeline(
+  const PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr<Graphics::Pipeline>&& oldPipeline)
 {
   // Create pipeline cache if needed
   if(!mPipelineCache)
@@ -170,7 +177,8 @@ Graphics::UniquePtr<Pipeline> EglGraphicsController::CreatePipeline(const Pipeli
   return mPipelineCache->GetPipeline(pipelineCreateInfo, std::move(oldPipeline));
 }
 
-Graphics::UniquePtr<Program> EglGraphicsController::CreateProgram(const ProgramCreateInfo& programCreateInfo, UniquePtr<Program>&& oldProgram)
+Graphics::UniquePtr<Program> EglGraphicsController::CreateProgram(
+  const ProgramCreateInfo& programCreateInfo, UniquePtr<Program>&& 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<GLES::Buffer>(mDiscardBufferQueue);
 
+  // Process Framebuffers
+  ProcessDiscardQueue<GLES::Framebuffer>(mDiscardFramebufferQueue);
+
   // Process pipelines
   ProcessDiscardQueue<GLES::Pipeline>(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<const GLES::Pipeline*>(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<const GLES::Framebuffer*>(currentFramebuffer)->Bind();
+          }
+
+          mContext->BindPipeline(pipeline);
           break;
         }
         case GLES::CommandType::DRAW:
index ccfe519..a4acea4 100644 (file)
@@ -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<Framebuffer> CreateFramebuffer(const FramebufferCreateInfo& framebufferCreateInfo, Graphics::UniquePtr<Framebuffer>&& oldFramebuffer) override
-  {
-    return nullptr;
-  }
+  Graphics::UniquePtr<Framebuffer> CreateFramebuffer(const FramebufferCreateInfo& framebufferCreateInfo, Graphics::UniquePtr<Framebuffer>&& 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<GLES::Shader*>        mDiscardShaderQueue;        ///< Discard queue of shaders
   std::queue<GLES::Sampler*>       mDiscardSamplerQueue;       ///< Discard queue of samplers
   std::queue<GLES::CommandBuffer*> mDiscardCommandBufferQueue; ///< Discard queue of command buffers
+  std::queue<GLES::Framebuffer*>   mCreateFramebufferQueue;    ///< Create queue for framebuffer resource
+  std::queue<GLES::Framebuffer*>   mDiscardFramebufferQueue;   ///< Discard queue for framebuffer resource
 
   std::queue<GLES::CommandBuffer*> mCommandQueue; ///< we may have more in the future
 
index 6869bd9..30ef207 100644 (file)
 
 // CLASS HEADER
 #include "gles-graphics-framebuffer.h"
+
+// external headers
+#include <dali/integration-api/gl-abstraction.h>
+#include <dali/integration-api/gl-defines.h>
+
+// Internal headers
+#include <dali/internal/graphics/gles-impl/gles-graphics-texture.h>
+#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<const GLES::Texture*>(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<const GLES::Texture*>(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<const GLES::Texture*>(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
index 784d3bd..5a63696 100644 (file)
@@ -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
index c6e46dc..f094fe0 100644 (file)
@@ -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<char> mStagingBuffer;