Create render pass for surface rendering 21/256021/12
authorAdam Bialogonski <adam.b@samsung.com>
Tue, 30 Mar 2021 17:19:01 +0000 (18:19 +0100)
committerAdam Bialogonski <adam.b@samsung.com>
Tue, 13 Apr 2021 10:58:17 +0000 (11:58 +0100)
Change-Id: I09069aab42d4e7af67aee7700e2a4e4c2ec27db4

dali/integration-api/scene.cpp
dali/integration-api/scene.h
dali/internal/event/common/scene-impl.cpp
dali/internal/event/common/scene-impl.h
dali/internal/render/common/render-manager.cpp
dali/internal/update/common/scene-graph-scene.cpp
dali/internal/update/common/scene-graph-scene.h

index bbe1139..4963c8f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 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.
 // CLASS HEADER
 #include <dali/integration-api/scene.h>
 
-// INTERNAL INCLUDES
-#include <dali/internal/event/common/scene-impl.h>
+// EXTERNAL INCLUDES
+#include <dali/graphics-api/graphics-render-target.h>
 #include <dali/public-api/actors/layer.h>
 #include <dali/public-api/render-tasks/render-task-list.h>
 
+// INTERNAL INCLUDES
+#include <dali/internal/event/common/scene-impl.h>
+
 namespace Dali
 {
 namespace Integration
@@ -121,6 +124,11 @@ void Scene::Discard()
   GetImplementation(*this).Discard();
 }
 
+void Scene::SetSurfaceRenderTarget(Graphics::RenderTarget* renderTarget)
+{
+  GetImplementation(*this).SetSurfaceRenderTarget(renderTarget);
+}
+
 Integration::Scene Scene::Get(Actor actor)
 {
   return Dali::Integration::Scene(&GetImplementation(actor).GetScene());
index eeb191f..a553ff3 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_SCENE_H
 
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 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.
@@ -41,6 +41,11 @@ namespace Internal DALI_INTERNAL
 class Scene;
 }
 
+namespace Graphics
+{
+class RenderTarget;
+}
+
 namespace Integration
 {
 struct Event;
@@ -218,6 +223,13 @@ public:
   void Discard();
 
   /**
+   * @brief Sets the render target for the surface.
+   *
+   * @param[in] renderTarget The render target for the surface
+   */
+  void SetSurfaceRenderTarget(Graphics::RenderTarget* renderTarget);
+
+  /**
    * @brief Retrieve the Scene that the given actor belongs to.
    * @return The Scene.
    */
index 95104fb..6f72912 100644 (file)
@@ -316,6 +316,13 @@ bool Scene::IsSurfaceRectChanged() const
   return mSceneObject->IsSurfaceRectChanged();
 }
 
+void Scene::SetSurfaceRenderTarget(Graphics::RenderTarget* renderTarget)
+{
+  // Send the surface render target to SceneGraph::Scene
+  ThreadLocalStorage* tls = ThreadLocalStorage::GetInternal();
+  SetSurfaceRenderTargetMessage(tls->GetEventThreadServices(), *mSceneObject, renderTarget);
+}
+
 bool Scene::EmitKeyEventGeneratedSignal(const Dali::KeyEvent& event)
 {
   // Emit the KeyEventGenerated signal when KeyEvent is generated
index 1346448..96c3bc3 100644 (file)
@@ -257,6 +257,11 @@ public:
   bool IsSurfaceRectChanged() const;
 
   /**
+   * @copydoc Dali::Integration::Scene::SetSurfaceRenderTarget
+   */
+  void SetSurfaceRenderTarget(Graphics::RenderTarget* renderTarget);
+
+  /**
    * Used by the EventProcessor to emit key event signals.
    * @param[in] event The key event.
    */
index 2bab722..c4898da 100644 (file)
@@ -89,8 +89,8 @@ struct RenderManager::Impl
     uniformBufferManager.reset(new Render::UniformBufferManager(&graphicsController));
 
     // initialize main command buffer
-    auto info = Graphics::CommandBufferCreateInfo().SetLevel( Graphics::CommandBufferLevel::PRIMARY );
-    mainCommandBuffer = graphicsController.CreateCommandBuffer( info, nullptr );
+    auto info         = Graphics::CommandBufferCreateInfo().SetLevel(Graphics::CommandBufferLevel::PRIMARY);
+    mainCommandBuffer = graphicsController.CreateCommandBuffer(info, nullptr);
   }
 
   ~Impl()
@@ -186,8 +186,6 @@ struct RenderManager::Impl
   Graphics::UniquePtr<Graphics::CommandBuffer> mainCommandBuffer; ///< Main command buffer
 
   Graphics::UniquePtr<Graphics::RenderPass> mainRenderPass; ///< Main renderpass
-
-
 };
 
 RenderManager* RenderManager::New(Graphics::Controller&               graphicsController,
@@ -357,7 +355,7 @@ void RenderManager::RemoveFrameBuffer(Render::FrameBuffer* frameBuffer)
 
 void RenderManager::InitializeScene(SceneGraph::Scene* scene)
 {
-  scene->Initialize(*mImpl->CreateSceneContext());
+  scene->Initialize(*mImpl->CreateSceneContext(), mImpl->graphicsController);
   mImpl->sceneContainer.push_back(scene);
 }
 
@@ -375,7 +373,7 @@ void RenderManager::UninitializeScene(SceneGraph::Scene* scene)
 void RenderManager::SurfaceReplaced(SceneGraph::Scene* scene)
 {
   Context* newContext = mImpl->ReplaceSceneContext(scene->GetContext());
-  scene->Initialize(*newContext);
+  scene->Initialize(*newContext, mImpl->graphicsController);
 }
 
 void RenderManager::AttachColorTextureToFrameBuffer(Render::FrameBuffer* frameBuffer, Render::Texture* texture, uint32_t mipmapLevel, uint32_t layer)
@@ -514,10 +512,11 @@ void RenderManager::PreRender(Integration::RenderStatus& status, bool forceClear
     {
       mImpl->currentContext = &mImpl->context;
 
-      if(mImpl->currentContext->IsSurfacelessContextSupported())
-      {
-        mImpl->graphicsController.GetGlContextHelperAbstraction().MakeSurfacelessContextCurrent();
-      }
+      // Context switch now happens when the uploading happens in graphics side
+      //      if(mImpl->currentContext->IsSurfacelessContextSupported())
+      //      {
+      //        mImpl->graphicsController.GetGlContextHelperAbstraction().MakeSurfacelessContextCurrent();
+      //      }
 
       // Clear the current cached program when the context is switched
       mImpl->programController.ClearCurrentProgram();
@@ -846,32 +845,31 @@ void RenderManager::RenderScene(Integration::RenderStatus& status, Integration::
       // todo: use no-clear renderpass instead (not implemented yet)
 
       // Set the clear color for first color attachment
-      if( instruction.mIsClearColorSet )
+      if(instruction.mIsClearColorSet)
       {
         clearValues[0].color = {
           instruction.mClearColor.r,
           instruction.mClearColor.g,
           instruction.mClearColor.b,
-          instruction.mClearColor.a
-        };
+          instruction.mClearColor.a};
       }
       // offscreen buffer
       mainCommandBuffer->BeginRenderPass(
-        instruction.mFrameBuffer->GetGraphicsRenderPass( Graphics::AttachmentLoadOp::CLEAR, Graphics::AttachmentStoreOp::STORE ),
+        instruction.mFrameBuffer->GetGraphicsRenderPass(Graphics::AttachmentLoadOp::CLEAR, Graphics::AttachmentStoreOp::STORE),
         instruction.mFrameBuffer->GetGraphicsRenderTarget(),
-        { instruction.mFrameBuffer->GetWidth(), instruction.mFrameBuffer->GetHeight() },
-        clearValues
-        );
+        {instruction.mFrameBuffer->GetWidth(), instruction.mFrameBuffer->GetHeight()},
+        clearValues);
 
       if(mImpl->currentContext != &mImpl->context)
       {
         // Switch to shared context for off-screen buffer
         mImpl->currentContext = &mImpl->context;
 
-        if(mImpl->currentContext->IsSurfacelessContextSupported())
-        {
-          mImpl->graphicsController.GetGlContextHelperAbstraction().MakeSurfacelessContextCurrent();
-        }
+        // Context switch now happens when render pass starts
+        //        if(mImpl->currentContext->IsSurfacelessContextSupported())
+        //        {
+        //          mImpl->graphicsController.GetGlContextHelperAbstraction().MakeSurfacelessContextCurrent();
+        //        }
 
         // Clear the current cached program when the context is switched
         mImpl->programController.ClearCurrentProgram();
@@ -890,6 +888,24 @@ void RenderManager::RenderScene(Integration::RenderStatus& status, Integration::
           mImpl->programController.ClearCurrentProgram();
         }
       }
+
+      // surface
+      auto& clearValues = sceneObject->GetGraphicsRenderPassClearValues();
+
+      if(instruction.mIsClearColorSet)
+      {
+        clearValues[0].color = {
+          instruction.mClearColor.r,
+          instruction.mClearColor.g,
+          instruction.mClearColor.b,
+          instruction.mClearColor.a};
+      }
+
+      mainCommandBuffer->BeginRenderPass(
+        sceneObject->GetGraphicsRenderPass(),
+        sceneObject->GetSurfaceRenderTarget(),
+        {static_cast<uint32_t>(surfaceRect.width), static_cast<uint32_t>(surfaceRect.height)},
+        clearValues);
     }
 
     // Make sure that GL context must be created
@@ -901,7 +917,6 @@ void RenderManager::RenderScene(Integration::RenderStatus& status, Integration::
 
     if(instruction.mFrameBuffer)
     {
-
       //instruction.mFrameBuffer->Bind(*mImpl->currentContext);
       // @todo Temporarily set per renderer per pipeline. Should use RenderPass instead
 
@@ -913,17 +928,20 @@ void RenderManager::RenderScene(Integration::RenderStatus& status, Integration::
     }
     else
     {
-      mImpl->currentContext->BindFramebuffer(GL_FRAMEBUFFER, 0u);
+      //mImpl->currentContext->BindFramebuffer(GL_FRAMEBUFFER, 0u);
     }
 
     // @todo Should this be a command in it's own right?
     // @todo yes
     if(!instruction.mFrameBuffer)
     {
+      /*
       mImpl->currentContext->Viewport(surfaceRect.x,
                                       surfaceRect.y,
                                       surfaceRect.width,
                                       surfaceRect.height);
+                                      */
+
       /*
       mainCommandBuffer->SetViewport( {surfaceRect.x,
                                         surfaceRect.y,
@@ -936,6 +954,8 @@ void RenderManager::RenderScene(Integration::RenderStatus& status, Integration::
     // It is important to clear all 3 buffers when they are being used, for performance on deferred renderers
     // e.g. previously when the depth & stencil buffers were NOT cleared, it caused the DDK to exceed a "vertex count limit",
     // and then stall. That problem is only noticeable when rendering a large number of vertices per frame.
+
+    /*
     GLbitfield clearMask = GL_COLOR_BUFFER_BIT;
 
     mImpl->currentContext->ColorMask(true);
@@ -952,7 +972,7 @@ void RenderManager::RenderScene(Integration::RenderStatus& status, Integration::
       mImpl->currentContext->StencilMask(0xFF); // 8 bit stencil mask, all 1's
       clearMask |= GL_STENCIL_BUFFER_BIT;
     }
-
+    */
     if(!instruction.mIgnoreRenderToFbo && (instruction.mFrameBuffer != nullptr))
     {
       // Offscreen buffer rendering
@@ -1012,34 +1032,36 @@ void RenderManager::RenderScene(Integration::RenderStatus& status, Integration::
     // @todo The following block should be a command in it's own right.
     // Currently takes account of surface orientation in Context.
     // Or move entirely to RenderPass implementation
-    mImpl->currentContext->Viewport(viewportRect.x, viewportRect.y, viewportRect.width, viewportRect.height);
+    mainCommandBuffer->SetViewport( {
+      float(viewportRect.x),
+      float(viewportRect.y),
+      float(viewportRect.width),
+      float(viewportRect.height)} );
+
+    //mImpl->currentContext->Viewport(viewportRect.x, viewportRect.y, viewportRect.width, viewportRect.height);
     if(instruction.mIsClearColorSet)
     {
-      mImpl->currentContext->ClearColor(clearColor.r,
-                                        clearColor.g,
-                                        clearColor.b,
-                                        clearColor.a);
       if(!clearFullFrameRect)
       {
         if(!clippingRect.IsEmpty())
         {
-          mImpl->currentContext->SetScissorTest(true);
-          mImpl->currentContext->Scissor(clippingRect.x, clippingRect.y, clippingRect.width, clippingRect.height);
-          mImpl->currentContext->Clear(clearMask, Context::FORCE_CLEAR);
-          mImpl->currentContext->SetScissorTest(false);
+          //mImpl->currentContext->SetScissorTest(true);
+          //mImpl->currentContext->Scissor(clippingRect.x, clippingRect.y, clippingRect.width, clippingRect.height);
+          //mImpl->currentContext->Clear(clearMask, Context::FORCE_CLEAR);
+          //mImpl->currentContext->SetScissorTest(false);
         }
         else
         {
-          mImpl->currentContext->SetScissorTest(true);
-          mImpl->currentContext->Scissor(viewportRect.x, viewportRect.y, viewportRect.width, viewportRect.height);
-          mImpl->currentContext->Clear(clearMask, Context::FORCE_CLEAR);
-          mImpl->currentContext->SetScissorTest(false);
+          //mImpl->currentContext->SetScissorTest(true);
+          //mImpl->currentContext->Scissor(viewportRect.x, viewportRect.y, viewportRect.width, viewportRect.height);
+          //mImpl->currentContext->Clear(clearMask, Context::FORCE_CLEAR);
+          //mImpl->currentContext->SetScissorTest(false);
         }
       }
       else
       {
-        mImpl->currentContext->SetScissorTest(false);
-        mImpl->currentContext->Clear(clearMask, Context::FORCE_CLEAR);
+        //mImpl->currentContext->SetScissorTest(false);
+        //mImpl->currentContext->Clear(clearMask, Context::FORCE_CLEAR);
       }
     }
 
@@ -1122,10 +1144,11 @@ void RenderManager::RenderScene(Integration::RenderStatus& status, Integration::
       instruction.mRenderTracker = nullptr; // Only create once.
     }
 
-    if(renderToFbo)
-    {
-      mImpl->currentContext->Flush();
-    }
+    // This now happens when the render pass for frame buffer finishes
+    //    if(renderToFbo)
+    //    {
+    //      mImpl->currentContext->Flush();
+    //    }
 
     // End render pass
     mainCommandBuffer->EndRenderPass();
@@ -1143,10 +1166,11 @@ void RenderManager::PostRender(bool uploadOnly)
 
   if(!uploadOnly)
   {
-    if(mImpl->currentContext->IsSurfacelessContextSupported())
-    {
-      mImpl->graphicsController.GetGlContextHelperAbstraction().MakeSurfacelessContextCurrent();
-    }
+    // Context switch now happens outside the render manager
+    //    if(mImpl->currentContext->IsSurfacelessContextSupported())
+    //    {
+    //      mImpl->graphicsController.GetGlContextHelperAbstraction().MakeSurfacelessContextCurrent();
+    //    }
 
     GLenum attachments[] = {GL_DEPTH, GL_STENCIL};
     mImpl->context.InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments);
index 8779ba9..a4fb196 100644 (file)
@@ -44,9 +44,26 @@ Scene::~Scene()
   mFramePresentedCallbacks.clear();
 }
 
-void Scene::Initialize(Context& context)
+void Scene::Initialize(Context& context, Graphics::Controller& graphicsController)
 {
   mContext = &context;
+
+  // Create the render pass for the surface
+  std::vector<Graphics::AttachmentDescription> attachmentDescriptions;
+
+  // Default behaviour for color attachments is to CLEAR and STORE
+  mClearValues.clear();
+  Graphics::AttachmentDescription desc{};
+  desc.SetLoadOp(Graphics::AttachmentLoadOp::CLEAR);
+  desc.SetStoreOp(Graphics::AttachmentStoreOp::STORE);
+  attachmentDescriptions.push_back(desc);
+  mClearValues.emplace_back();
+
+  Graphics::RenderPassCreateInfo rpInfo{};
+  rpInfo.SetAttachments(attachmentDescriptions);
+
+  // Add default render pass (loadOp = clear)
+  mRenderPass = graphicsController.CreateRenderPass(rpInfo, nullptr);
 }
 
 Context* Scene::GetContext()
index ab6cde4..b41dd22 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 // INTERNAL INCLUDES
+#include <dali/graphics-api/graphics-controller.h>
 #include <dali/integration-api/scene.h>
 #include <dali/internal/common/message.h>
 #include <dali/internal/event/common/event-thread-services.h>
@@ -51,8 +52,9 @@ public:
   /**
    * Creates a scene object in the GPU.
    * @param[in] context The GL context
+   * @param[in] graphicsController The graphics controller
    */
-  void Initialize(Context& context);
+  void Initialize(Context& context, Graphics::Controller& graphicsController);
 
   /**
    * Gets the context holding the GL state of rendering for the scene
@@ -160,6 +162,46 @@ public:
    */
   bool IsSurfaceRectChanged();
 
+  /**
+   * Set the render target of the surface
+   *
+   * @param[in] renderTarget The render target.
+   */
+  void SetSurfaceRenderTarget(Graphics::RenderTarget* renderTarget)
+  {
+    mRenderTarget = renderTarget;
+  }
+
+  /**
+   * Get the render target created for the scene
+   *
+   * @return the render target
+   */
+  [[nodiscard]] Graphics::RenderTarget* GetSurfaceRenderTarget() const
+  {
+    return mRenderTarget;
+  }
+
+  /**
+   * Get the graphics render pass created for the scene
+   *
+   * @return the graphics render pass
+   */
+  [[nodiscard]] Graphics::RenderPass* GetGraphicsRenderPass() const
+  {
+    return mRenderPass.get();
+  }
+
+  /**
+   * Get an initialized array of clear values which then can be modified and accessed to BeginRenderPass() command.
+   *
+   * @return the array of clear values
+   */
+  [[nodiscard]] auto& GetGraphicsRenderPassClearValues()
+  {
+    return mClearValues;
+  }
+
 private:
   Context* mContext; ///< The context holding the GL state of rendering for the scene, not owned
 
@@ -176,6 +218,19 @@ private:
   Rect<int32_t> mSurfaceRect;        ///< The rectangle of surface which is related ot this scene.
   int32_t       mSurfaceOrientation; ///< The orientation of surface which is related of this scene
   bool          mSurfaceRectChanged; ///< The flag of surface's rectangle is changed when is resized, moved or rotated.
+
+  // Render pass and render target
+
+  /**
+   * Render pass is created on fly depending on Load and Store operations
+   * The default render pass (most likely to be used) is the load = CLEAR
+   * and store = STORE for color attachment.
+   */
+  Graphics::UniquePtr<Graphics::RenderPass> mRenderPass{nullptr};   ///< The render pass created to render the surface
+  Graphics::RenderTarget*                   mRenderTarget{nullptr}; ///< This is created in the event thread when surface is created/resized/replaced
+
+  // clear colors
+  std::vector<Graphics::ClearValue> mClearValues{};
 };
 
 /// Messages
@@ -223,6 +278,17 @@ inline void SetSurfaceOrientationMessage(EventThreadServices& eventThreadService
   new(slot) LocalType(&scene, &Scene::SetSurfaceOrientation, orientation);
 }
 
+inline void SetSurfaceRenderTargetMessage(EventThreadServices& eventThreadServices, const Scene& scene, Graphics::RenderTarget* renderTarget)
+{
+  using LocalType = MessageValue1<Scene, Graphics::RenderTarget*>;
+
+  // Reserve some memory inside the message queue
+  uint32_t* slot = eventThreadServices.ReserveMessageSlot(sizeof(LocalType));
+
+  // Construct message in the message queue memory; note that delete should not be called on the return value
+  new(slot) LocalType(&scene, &Scene::SetSurfaceRenderTarget, renderTarget);
+}
+
 } // namespace SceneGraph
 
 } // namespace Internal