[Tizen] Do not skip rendering if update required keep rendering
[platform/core/uifw/dali-adaptor.git] / dali / internal / adaptor / common / combined-update-render-controller.cpp
index db68e43..712992d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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/public-api/common/dali-common.h"
 
 // INTERNAL INCLUDES
+#include <dali/integration-api/adaptor-framework/shader-precompiler.h>
 #include <dali/integration-api/adaptor-framework/trigger-event-factory.h>
 #include <dali/internal/adaptor/common/adaptor-internal-services.h>
 #include <dali/internal/adaptor/common/combined-update-render-controller-debug.h>
 #include <dali/internal/graphics/common/graphics-interface.h>
 #include <dali/internal/graphics/gles/egl-graphics.h>
 #include <dali/internal/system/common/environment-options.h>
+#include <dali/internal/system/common/texture-upload-manager-impl.h>
 #include <dali/internal/system/common/time-service.h>
 #include <dali/internal/thread/common/thread-settings-impl.h>
 #include <dali/internal/window-system/common/window-impl.h>
@@ -79,6 +81,15 @@ const uint64_t DEFAULT_FRAME_DURATION_IN_NANOSECONDS(DEFAULT_FRAME_DURATION_IN_S
  *  3) MAIN THREAD:           Sleep Request:  COUNTER = 0 -> Go to sleep
  */
 const unsigned int MAXIMUM_UPDATE_REQUESTS = 2;
+
+inline std::vector<char> StringToVector(const std::string& str)
+{
+  auto retval = std::vector<char>{};
+  retval.insert(retval.begin(), str.begin(), str.end());
+  retval.push_back('\0');
+  return retval;
+}
+
 } // unnamed namespace
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -98,6 +109,7 @@ CombinedUpdateRenderController::CombinedUpdateRenderController(AdaptorInternalSe
   mNotificationTrigger(adaptorInterfaces.GetProcessCoreEventsTrigger()),
   mSleepTrigger(NULL),
   mPreRenderCallback(NULL),
+  mTextureUploadManager(adaptorInterfaces.GetTextureUploadManager()),
   mUpdateRenderThread(NULL),
   mDefaultFrameDelta(0.0f),
   mDefaultFrameDurationMilliseconds(0u),
@@ -105,6 +117,7 @@ CombinedUpdateRenderController::CombinedUpdateRenderController(AdaptorInternalSe
   mDefaultHalfFrameNanoseconds(0u),
   mUpdateRequestCount(0u),
   mRunning(FALSE),
+  mVsyncRender(TRUE),
   mThreadId(0),
   mThreadMode(threadMode),
   mUpdateRenderRunCount(0),
@@ -112,6 +125,7 @@ CombinedUpdateRenderController::CombinedUpdateRenderController(AdaptorInternalSe
   mUpdateRenderThreadCanSleep(FALSE),
   mPendingRequestUpdate(FALSE),
   mUseElapsedTimeAfterWait(FALSE),
+  mIsPreCompileCancelled(FALSE),
   mNewSurface(NULL),
   mDeletedSurface(nullptr),
   mPostRendering(FALSE),
@@ -132,6 +146,8 @@ CombinedUpdateRenderController::CombinedUpdateRenderController(AdaptorInternalSe
     currentSurface->SetThreadSynchronization(*this);
   }
 
+  mVsyncRender = environmentOptions.VsyncRenderRequired();
+
   mSleepTrigger = TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &CombinedUpdateRenderController::ProcessSleepRequest), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER);
 }
 
@@ -309,6 +325,7 @@ void CombinedUpdateRenderController::ReplaceSurface(Dali::RenderSurfaceInterface
       ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
       mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will replace the surface now
       mNewSurface    = newSurface;
+      CancelPreCompile();
       mUpdateRenderThreadWaitCondition.Notify(lock);
     }
 
@@ -332,6 +349,7 @@ void CombinedUpdateRenderController::DeleteSurface(Dali::RenderSurfaceInterface*
       ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
       mPostRendering  = FALSE; // Clear the post-rendering flag as Update/Render thread will delete the surface now
       mDeletedSurface = surface;
+      CancelPreCompile();
       mUpdateRenderThreadWaitCondition.Notify(lock);
     }
 
@@ -368,6 +386,7 @@ void CombinedUpdateRenderController::ResizeSurface()
     ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
     // Surface is resized and the surface resized count is increased.
     mSurfaceResized++;
+    CancelPreCompile();
     mUpdateRenderThreadWaitCondition.Notify(lock);
   }
 }
@@ -446,6 +465,7 @@ void CombinedUpdateRenderController::RunUpdateRenderThread(int numberOfCycles, A
   mUpdateRenderThreadCanSleep = FALSE;
   mUploadWithoutRendering     = (updateMode == UpdateMode::SKIP_RENDER);
   LOG_COUNTER_EVENT("mUpdateRenderRunCount: %d, mUseElapsedTimeAfterWait: %d", mUpdateRenderRunCount, mUseElapsedTimeAfterWait);
+  CancelPreCompile();
   mUpdateRenderThreadWaitCondition.Notify(lock);
 }
 
@@ -459,6 +479,7 @@ void CombinedUpdateRenderController::StopUpdateRenderThread()
 {
   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
   mDestroyUpdateRenderThread = TRUE;
+  CancelPreCompile();
   mUpdateRenderThreadWaitCondition.Notify(lock);
 }
 
@@ -511,6 +532,8 @@ void CombinedUpdateRenderController::UpdateRenderThread()
   // Install a function for tracing
   mEnvironmentOptions.InstallTraceFunction();
 
+  TRACE_UPDATE_RENDER_BEGIN("DALI_RENDER_THREAD_INIT");
+
   LOG_UPDATE_RENDER("THREAD CREATED");
 
   // Initialize graphics
@@ -520,6 +543,9 @@ void CombinedUpdateRenderController::UpdateRenderThread()
   Dali::DisplayConnection& displayConnection = mAdaptorInterfaces.GetDisplayConnectionInterface();
   displayConnection.Initialize(); //@todo Move InitializeGraphics code into graphics implementation
 
+  // Setup graphics controller into upload manager.
+  GetImplementation(mTextureUploadManager).InitalizeGraphicsController(graphics.GetController());
+
   NotifyGraphicsInitialised();
 
   //@todo Vk swaps this around, but we need to support surfaceless context for multi-window
@@ -530,6 +556,21 @@ void CombinedUpdateRenderController::UpdateRenderThread()
 
   NotifyThreadInitialised();
 
+  // Initialize and create graphics resource for the shared context.
+  WindowContainer windows;
+  mAdaptorInterfaces.GetWindowContainerInterface(windows);
+
+  for(auto&& window : windows)
+  {
+    Dali::Integration::Scene      scene         = window->GetScene();
+    Dali::RenderSurfaceInterface* windowSurface = window->GetSurface();
+
+    if(scene && windowSurface)
+    {
+      windowSurface->InitializeGraphics();
+    }
+  }
+
   // Update time
   uint64_t lastFrameTime;
   TimeService::GetNanoseconds(lastFrameTime);
@@ -548,9 +589,44 @@ void CombinedUpdateRenderController::UpdateRenderThread()
   const bool         renderToFboEnabled  = 0u != renderToFboInterval;
   unsigned int       frameCount          = 0u;
 
+  TRACE_UPDATE_RENDER_END("DALI_RENDER_THREAD_INIT");
+  if(!mDestroyUpdateRenderThread)
+  {
+    ShaderPreCompiler::Get().Wait();
+    if(ShaderPreCompiler::Get().IsEnable())
+    {
+      std::vector<RawShaderData> precompiledShaderList;
+      ShaderPreCompiler::Get().GetPreCompileShaderList(precompiledShaderList);
+      DALI_LOG_RELEASE_INFO("ShaderPreCompiler[ENABLE], list size:%d \n", precompiledShaderList.size());
+      for(auto precompiledShader = precompiledShaderList.begin(); precompiledShader != precompiledShaderList.end(); ++precompiledShader)
+      {
+        if(mIsPreCompileCancelled == TRUE)
+        {
+          ShaderPreCompiler::Get().Awake();
+          DALI_LOG_RELEASE_INFO("ShaderPreCompiler[ENABLE], but stop precompile");
+          break;
+        }
+
+        auto numberOfPrecompiledShader = precompiledShader->shaderCount;
+        for(int i = 0; i < numberOfPrecompiledShader; ++i)
+        {
+          auto vertexShader   = graphics.GetController().GetGlAbstraction().GetVertexShaderPrefix() + std::string(precompiledShader->vertexPrefix[i].data()) + std::string(precompiledShader->vertexShader.data());
+          auto fragmentShader = graphics.GetController().GetGlAbstraction().GetFragmentShaderPrefix() + std::string(precompiledShader->fragmentPrefix[i].data()) + std::string(precompiledShader->fragmentShader.data());
+          PreCompileShader(std::move(vertexShader), std::move(fragmentShader));
+        }
+        DALI_LOG_RELEASE_INFO("ShaderPreCompiler[ENABLE], shader count :%d \n", numberOfPrecompiledShader);
+      }
+    }
+    else
+    {
+      DALI_LOG_RELEASE_INFO("ShaderPreCompiler[DISABLE] \n");
+    }
+  }
+
   while(UpdateRenderReady(useElapsedTime, updateRequired, timeToSleepUntil))
   {
     LOG_UPDATE_RENDER_TRACE;
+    TRACE_UPDATE_RENDER_BEGIN("DALI_UPDATE_RENDER");
 
     // For thread safe
     bool                          uploadOnly     = mUploadWithoutRendering;
@@ -595,6 +671,18 @@ void CombinedUpdateRenderController::UpdateRenderThread()
       SurfaceReplaced();
     }
 
+    //////////////////////////////
+    // TextureUploadRequest (phase #1)
+    //////////////////////////////
+
+    // Upload requested resources after resource context activated.
+    graphics.ActivateResourceContext();
+
+    const bool textureUploaded = mTextureUploadManager.ResourceUpload();
+
+    // Update & Render forcely if there exist some uploaded texture.
+    uploadOnly = textureUploaded ? false : uploadOnly;
+
     const bool isRenderingToFbo = renderToFboEnabled && ((0u == frameCount) || (0u != frameCount % renderToFboInterval));
     ++frameCount;
 
@@ -648,6 +736,12 @@ void CombinedUpdateRenderController::UpdateRenderThread()
       mNotificationTrigger.Trigger();
       LOG_UPDATE_RENDER("Notification Triggered");
     }
+  
+    if(uploadOnly && (keepUpdatingStatus & Dali::Integration::KeepUpdating::STAGE_KEEP_RENDERING))
+    {
+      // Render forcely if there exist some keep rendering required.
+      uploadOnly = false;
+    }
 
     // Optional logging of update/render status
     mUpdateStatusLogger.Log(keepUpdatingStatus);
@@ -669,8 +763,16 @@ void CombinedUpdateRenderController::UpdateRenderThread()
       }
     }
 
+    //////////////////////////////
+    // TextureUploadRequest (phase #2)
+    //////////////////////////////
+
+    // Upload requested resources after resource context activated.
     graphics.ActivateResourceContext();
 
+    // Since uploadOnly value used at Update side, we should not change uploadOnly value now even some textures are uploaded.
+    mTextureUploadManager.ResourceUpload();
+
     if(mFirstFrameAfterResume)
     {
       // mFirstFrameAfterResume is set to true when the thread is resumed
@@ -685,12 +787,14 @@ void CombinedUpdateRenderController::UpdateRenderThread()
     TRACE_UPDATE_RENDER_BEGIN("DALI_RENDER");
 
     // Upload shared resources
+    TRACE_UPDATE_RENDER_BEGIN("DALI_PRE_RENDER");
     mCore.PreRender(renderStatus, mForceClear);
+    TRACE_UPDATE_RENDER_END("DALI_PRE_RENDER");
 
     if(!uploadOnly || surfaceResized)
     {
       // Go through each window
-      WindowContainer windows;
+      windows.clear();
       mAdaptorInterfaces.GetWindowContainerInterface(windows);
 
       for(auto&& window : windows)
@@ -700,9 +804,10 @@ void CombinedUpdateRenderController::UpdateRenderThread()
 
         if(scene && windowSurface)
         {
+          TRACE_UPDATE_RENDER_SCOPE("DALI_RENDER_SCENE");
           Integration::RenderStatus windowRenderStatus;
 
-          const bool sceneSurfaceResized = scene.IsSurfaceRectChanged();
+          const uint32_t sceneSurfaceResized = scene.GetSurfaceRectChangedCount();
 
           // clear previous frame damaged render items rects, buffer history is tracked on surface level
           mDamagedRects.clear();
@@ -716,7 +821,7 @@ void CombinedUpdateRenderController::UpdateRenderThread()
           Rect<int> clippingRect; // Empty for fbo rendering
 
           // Switch to the context of the surface, merge damaged areas for previous frames
-          windowSurface->PreRender(sceneSurfaceResized, mDamagedRects, clippingRect); // Switch GL context
+          windowSurface->PreRender(sceneSurfaceResized > 0u, mDamagedRects, clippingRect); // Switch GL context
 
           // Render the surface
           mCore.RenderScene(windowRenderStatus, scene, false, clippingRect);
@@ -724,20 +829,26 @@ void CombinedUpdateRenderController::UpdateRenderThread()
           // Buffer swapping now happens when the surface render target is presented.
 
           // If surface is resized, the surface resized count is decreased.
-          if(DALI_UNLIKELY(sceneSurfaceResized))
+          if(DALI_UNLIKELY(sceneSurfaceResized > 0u))
           {
-            SurfaceResized();
+            SurfaceResized(sceneSurfaceResized);
           }
         }
       }
     }
+    else
+    {
+      DALI_LOG_RELEASE_INFO("DALI Rendering skip (upload only)\n");
+    }
 
+    TRACE_UPDATE_RENDER_BEGIN("DALI_POST_RENDER");
     if(!uploadOnly)
     {
       graphics.PostRender();
     }
 
     mCore.PostRender();
+    TRACE_UPDATE_RENDER_END("DALI_POST_RENDER");
 
     //////////////////////////////
     // DELETE SURFACE
@@ -811,18 +922,22 @@ void CombinedUpdateRenderController::UpdateRenderThread()
       }
     }
 
+    TRACE_UPDATE_RENDER_END("DALI_UPDATE_RENDER");
+
     // Render to FBO is intended to measure fps above 60 so sleep is not wanted.
-    if(0u == renderToFboInterval)
+    if(mVsyncRender && 0u == renderToFboInterval)
     {
+      TRACE_UPDATE_RENDER_SCOPE("DALI_UPDATE_RENDER_SLEEP");
       // Sleep until at least the the default frame duration has elapsed. This will return immediately if the specified end-time has already passed.
       TimeService::SleepUntil(timeToSleepUntil);
     }
   }
+  TRACE_UPDATE_RENDER_BEGIN("DALI_RENDER_THREAD_FINISH");
 
   // Inform core of context destruction
   mCore.ContextDestroyed();
 
-  WindowContainer windows;
+  windows.clear();
   mAdaptorInterfaces.GetWindowContainerInterface(windows);
 
   // Destroy surfaces
@@ -836,6 +951,8 @@ void CombinedUpdateRenderController::UpdateRenderThread()
 
   LOG_UPDATE_RENDER("THREAD DESTROYED");
 
+  TRACE_UPDATE_RENDER_END("DALI_RENDER_THREAD_FINISH");
+
   // Uninstall the logging function
   mEnvironmentOptions.UnInstallLogFunction();
 }
@@ -864,7 +981,9 @@ bool CombinedUpdateRenderController::UpdateRenderReady(bool& useElapsedTime, boo
     // of the first frame.
     timeToSleepUntil = 0;
 
+    TRACE_UPDATE_RENDER_BEGIN("DALI_UPDATE_RENDER_THREAD_WAIT_CONDITION");
     mUpdateRenderThreadWaitCondition.Wait(updateLock);
+    TRACE_UPDATE_RENDER_END("DALI_UPDATE_RENDER_THREAD_WAIT_CONDITION");
 
     if(!mUseElapsedTimeAfterWait)
     {
@@ -926,12 +1045,61 @@ void CombinedUpdateRenderController::SurfaceDeleted()
   mSurfaceSemaphore.Release(1);
 }
 
-void CombinedUpdateRenderController::SurfaceResized()
+void CombinedUpdateRenderController::SurfaceResized(uint32_t resizedCount)
 {
   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
-  if(mSurfaceResized)
+
+  if(mSurfaceResized >= resizedCount)
+  {
+    mSurfaceResized -= resizedCount;
+  }
+  else
+  {
+    mSurfaceResized = 0u;
+  }
+}
+
+void CombinedUpdateRenderController::PreCompileShader(std::string vertexShader, std::string fragmentShader)
+{
+  GraphicsInterface& graphics = mAdaptorInterfaces.GetGraphicsInterface();
+
+  Graphics::ShaderCreateInfo vertexShaderCreateInfo;
+  vertexShaderCreateInfo.SetPipelineStage(Graphics::PipelineStage::VERTEX_SHADER);
+  vertexShaderCreateInfo.SetSourceMode(Graphics::ShaderSourceMode::TEXT);
+  const std::vector<char>& vertexShaderSrc = StringToVector(std::move(vertexShader));
+  vertexShaderCreateInfo.SetSourceSize(vertexShaderSrc.size());
+  vertexShaderCreateInfo.SetSourceData(static_cast<const void*>(vertexShaderSrc.data()));
+  auto vertexGraphicsShader = graphics.GetController().CreateShader(vertexShaderCreateInfo, nullptr);
+
+  Graphics::ShaderCreateInfo fragmentShaderCreateInfo;
+  fragmentShaderCreateInfo.SetPipelineStage(Graphics::PipelineStage::FRAGMENT_SHADER);
+  fragmentShaderCreateInfo.SetSourceMode(Graphics::ShaderSourceMode::TEXT);
+  const std::vector<char>& fragmentShaderSrc = StringToVector(std::move(fragmentShader));
+  fragmentShaderCreateInfo.SetSourceSize(fragmentShaderSrc.size());
+  fragmentShaderCreateInfo.SetSourceData(static_cast<const void*>(fragmentShaderSrc.data()));
+  auto fragmentGraphicsShader = graphics.GetController().CreateShader(fragmentShaderCreateInfo, nullptr);
+
+  std::vector<Graphics::ShaderState> shaderStates{
+    Graphics::ShaderState()
+      .SetShader(*vertexGraphicsShader.get())
+      .SetPipelineStage(Graphics::PipelineStage::VERTEX_SHADER),
+    Graphics::ShaderState()
+      .SetShader(*fragmentGraphicsShader.get())
+      .SetPipelineStage(Graphics::PipelineStage::FRAGMENT_SHADER)};
+
+  auto createInfo = Graphics::ProgramCreateInfo();
+  createInfo.SetShaderState(shaderStates);
+
+  auto graphicsProgram = graphics.GetController().CreateProgram(createInfo, nullptr);
+  ShaderPreCompiler::Get().AddPreCompiledProgram(std::move(graphicsProgram));
+}
+
+void CombinedUpdateRenderController::CancelPreCompile()
+{
+  if(mIsPreCompileCancelled == FALSE)
   {
-    mSurfaceResized--;
+    mIsPreCompileCancelled = TRUE;
+    ShaderPreCompiler::Get().Awake();
   }
 }
 
@@ -966,6 +1134,7 @@ void CombinedUpdateRenderController::PostRenderComplete()
 {
   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
   mPostRendering = FALSE;
+  CancelPreCompile();
   mUpdateRenderThreadWaitCondition.Notify(lock);
 }