Apply Precompile shader 68/300268/10
authorsunghyun kim <scholb.kim@samsung.com>
Thu, 21 Sep 2023 05:59:54 +0000 (14:59 +0900)
committersunghyun kim <scholb.kim@samsung.com>
Mon, 27 Nov 2023 06:53:24 +0000 (15:53 +0900)
Change-Id: I76880c50206efe8d63c8fa94b51e98c48018a71b

dali/integration-api/adaptor-framework/shader-precompiler.cpp [new file with mode: 0644]
dali/integration-api/adaptor-framework/shader-precompiler.h [new file with mode: 0644]
dali/integration-api/file.list
dali/internal/adaptor/common/combined-update-render-controller.cpp
dali/internal/adaptor/common/combined-update-render-controller.h

diff --git a/dali/integration-api/adaptor-framework/shader-precompiler.cpp b/dali/integration-api/adaptor-framework/shader-precompiler.cpp
new file mode 100644 (file)
index 0000000..7b3da3a
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// CLASS HEADER
+#include <dali/integration-api/adaptor-framework/shader-precompiler.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+std::unique_ptr<ShaderPreCompiler> ShaderPreCompiler::mInstance = nullptr;
+std::once_flag ShaderPreCompiler::mOnceFlag;
+
+ShaderPreCompiler::ShaderPreCompiler()
+: mRawShaderList(),
+  mPrecompiled(false),
+  mEnabled(false)
+{
+}
+
+ShaderPreCompiler& ShaderPreCompiler::Get()
+{
+  std::call_once(mOnceFlag, []()
+                 { mInstance.reset(new ShaderPreCompiler); });
+
+  return *(mInstance.get());
+}
+
+void ShaderPreCompiler::AddPreCompiledProgram(Graphics::UniquePtr<Dali::Graphics::Program> program)
+{
+  mProgram.push_back(move(program));
+}
+
+void ShaderPreCompiler::GetPreCompileShaderList(std::vector<RawShaderData>& shaderList)
+{
+  // move shader list
+  shaderList = mRawShaderList;
+}
+
+void ShaderPreCompiler::SavePreCompileShaderList(std::vector<RawShaderData>& shaderList)
+{
+  mRawShaderList = shaderList;
+  mPrecompiled = true;
+  Awake();
+}
+
+bool ShaderPreCompiler::IsReady() const
+{
+  return mPrecompiled;
+}
+
+void ShaderPreCompiler::Enable()
+{
+  mEnabled = true;
+}
+
+bool ShaderPreCompiler::IsEnable()
+{
+  return mEnabled;
+}
+
+void ShaderPreCompiler::Wait()
+{
+  ConditionalWait::ScopedLock lock(mConditionalWait);
+  {
+    Dali::Mutex::ScopedLock mutexLock(mMutex);
+    if(!mNeedsSleep)
+    {
+      return;
+    }
+  }
+
+  mConditionalWait.Wait(lock);
+}
+
+void ShaderPreCompiler::Awake()
+{
+  ConditionalWait::ScopedLock lock(mConditionalWait);
+  Dali::Mutex::ScopedLock mutexLock(mMutex);
+  mNeedsSleep = false;
+  mConditionalWait.Notify(lock);
+}
+} // namespace Dali
diff --git a/dali/integration-api/adaptor-framework/shader-precompiler.h b/dali/integration-api/adaptor-framework/shader-precompiler.h
new file mode 100644 (file)
index 0000000..6b14439
--- /dev/null
@@ -0,0 +1,140 @@
+#ifndef DALI_INTEGRATION_SHADER_PRECOMPILER_H
+#define DALI_INTEGRATION_SHADER_PRECOMPILER_H
+
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL HEADER
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/object/base-handle.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/devel-api/threading/conditional-wait.h>
+#include <dali/devel-api/threading/mutex.h>
+
+// EXTERNAL HEDAER
+#include <string_view>
+#include <memory>
+#include <mutex>
+#include <dali/graphics-api/graphics-program.h>
+#include <dali/graphics-api/graphics-types.h>
+
+namespace Dali
+{
+struct RawShaderData
+{
+  int shaderCount;
+  std::vector<std::string_view> vertexPrefix;
+  std::vector<std::string_view> fragmentPrefix;
+  std::string_view vertexShader;
+  std::string_view fragmentShader;
+};
+
+/**
+ * ShaderPreCompiler  is used to precompile shaders.
+ * The precompiled shaders are stored in a file.
+ * @SINCE_2_2.45
+ */
+class DALI_CORE_API ShaderPreCompiler : public BaseHandle
+{
+public:
+  /**
+   * @brief Gets the singleton of ShaderPreCompiler object.
+   *
+   * @return A handle to the ShaderPreCompiler
+   */
+  static ShaderPreCompiler& Get();
+
+  /**
+   * @brief Add a precompiled program to the ShaderPreCompiler
+   *
+   * @param[in] program precompiled program
+   */
+  void AddPreCompiledProgram(Graphics::UniquePtr<Dali::Graphics::Program> program);
+
+  /**
+   * @brief Gets the shader list to be precompiled
+   *
+   *  @param[in] shaders shader data for precompile
+   */
+  void GetPreCompileShaderList(std::vector<RawShaderData>& shaders);
+
+  /**
+   * @brief Save the shader list to be precompiled
+   *
+   * @param[in] shaders shader data for precompile
+   */
+  void SavePreCompileShaderList(std::vector<RawShaderData>& shaders);
+
+  /**
+   * @brief Checks whether the precompiled list is ready or not
+   *
+   * @return true if precompile list is ready
+   */
+  bool IsReady() const;
+
+  /**
+   * @brief Enable the feature of precompile
+   *
+   */
+  void Enable();
+
+  /**
+   * @brief Check the feature of precompile is enabled or not
+   *
+   * @return true if the feature of precompile is enabled
+  */
+  bool IsEnable();
+
+  /**
+   * @brief Waiting for a list of shaders to be precompiled
+   *
+   */
+  void Wait();
+
+  /**
+   * @brief Awake waiting for a list of shaders to be precompiled
+   *
+   */
+  void Awake();
+
+private:
+  /**
+   * Construct a new ShaderPreCompiler.
+   */
+  ShaderPreCompiler();
+
+  // Undefined
+  ShaderPreCompiler(const ShaderPreCompiler&) = delete;
+
+  // Undefined
+  ShaderPreCompiler& operator=(const ShaderPreCompiler& rhs) = delete;
+
+private:
+  std::vector<Graphics::UniquePtr<Dali::Graphics::Program>> mProgram;
+  static std::unique_ptr<ShaderPreCompiler> mInstance;
+  static std::once_flag mOnceFlag;
+  std::vector<RawShaderData> mRawShaderList;
+  ConditionalWait mConditionalWait;
+  Dali::Mutex mMutex;
+  bool mPrecompiled;
+  bool mEnabled;
+  bool mNeedsSleep{true};
+};
+
+} // namespace Dali
+
+#endif // DALI_INTEGRATION_SHADER_PRECOMPILER_H
index 11cacd7..be1de0c 100644 (file)
@@ -4,6 +4,7 @@ SET( adaptor_integration_api_src_files
   ${adaptor_integration_api_dir}/adaptor-framework/scene-holder.cpp
   ${adaptor_integration_api_dir}/adaptor-framework/scene-holder-impl.cpp
   ${adaptor_integration_api_dir}/adaptor-framework/native-image-surface.cpp
+  ${adaptor_integration_api_dir}/adaptor-framework/shader-precompiler.cpp
 )
 
 
@@ -21,5 +22,6 @@ SET( adaptor_integration_api_header_files
   ${adaptor_integration_api_dir}/adaptor-framework/trigger-event-interface.h
   ${adaptor_integration_api_dir}/adaptor-framework/trigger-event-factory.h
   ${adaptor_integration_api_dir}/adaptor-framework/native-image-surface.h
+  ${adaptor_integration_api_dir}/adaptor-framework/shader-precompiler.h
 )
 
index 3a8ad2c..a6ffa3b 100644 (file)
@@ -25,6 +25,7 @@
 #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>
@@ -80,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
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -114,6 +124,7 @@ CombinedUpdateRenderController::CombinedUpdateRenderController(AdaptorInternalSe
   mUpdateRenderThreadCanSleep(FALSE),
   mPendingRequestUpdate(FALSE),
   mUseElapsedTimeAfterWait(FALSE),
+  mIsPreCompileCancelled(FALSE),
   mNewSurface(NULL),
   mDeletedSurface(nullptr),
   mPostRendering(FALSE),
@@ -311,6 +322,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);
     }
 
@@ -334,6 +346,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);
     }
 
@@ -370,6 +383,7 @@ void CombinedUpdateRenderController::ResizeSurface()
     ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
     // Surface is resized and the surface resized count is increased.
     mSurfaceResized++;
+    CancelPreCompile();
     mUpdateRenderThreadWaitCondition.Notify(lock);
   }
 }
@@ -448,6 +462,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);
 }
 
@@ -461,6 +476,7 @@ void CombinedUpdateRenderController::StopUpdateRenderThread()
 {
   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
   mDestroyUpdateRenderThread = TRUE;
+  CancelPreCompile();
   mUpdateRenderThreadWaitCondition.Notify(lock);
 }
 
@@ -537,6 +553,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);
@@ -556,6 +587,38 @@ void CombinedUpdateRenderController::UpdateRenderThread()
   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))
   {
@@ -722,7 +785,7 @@ void CombinedUpdateRenderController::UpdateRenderThread()
     if(!uploadOnly || surfaceResized)
     {
       // Go through each window
-      WindowContainer windows;
+      windows.clear();
       mAdaptorInterfaces.GetWindowContainerInterface(windows);
 
       for(auto&& window : windows)
@@ -859,7 +922,7 @@ void CombinedUpdateRenderController::UpdateRenderThread()
   // Inform core of context destruction
   mCore.ContextDestroyed();
 
-  WindowContainer windows;
+  windows.clear();
   mAdaptorInterfaces.GetWindowContainerInterface(windows);
 
   // Destroy surfaces
@@ -976,6 +1039,50 @@ void CombinedUpdateRenderController::SurfaceResized()
   }
 }
 
+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)
+  {
+    mIsPreCompileCancelled = TRUE;
+    ShaderPreCompiler::Get().Awake();
+  }
+}
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // ALL THREADS
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -1007,6 +1114,7 @@ void CombinedUpdateRenderController::PostRenderComplete()
 {
   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
   mPostRendering = FALSE;
+  CancelPreCompile();
   mUpdateRenderThreadWaitCondition.Notify(lock);
 }
 
index bec2f70..8ca10f8 100644 (file)
@@ -43,6 +43,7 @@ class TriggerEventInterface;
 
 namespace Internal
 {
+
 namespace Adaptor
 {
 class AdaptorInternalServices;
@@ -274,6 +275,19 @@ private:
   void SurfaceResized();
 
   /**
+   * PreCompile shaders for launching time
+   *
+   * @param[in] vertexShader vertexShader need to precompile
+   * @param[in] fragmentShader fragmentShader need to precompile
+  */
+  void PreCompileShader(std::string vertexShader, std::string fragmentShader);
+
+  /**
+   * Cancel the precompile
+  */
+  void CancelPreCompile();
+
+  /**
    * Helper for the thread calling the entry function
    * @param[in] This A pointer to the current object
    */
@@ -377,6 +391,7 @@ private:
                                                      ///< Ensures we do not go to sleep if we have not processed the most recent update-request.
 
   volatile unsigned int mUseElapsedTimeAfterWait; ///< Whether we should use the elapsed time after waiting (set by the event-thread, read by the update-render-thread).
+  volatile unsigned int mIsPreCompileCancelled;      ///< Whether we need to do precompile shader.
 
   Dali::RenderSurfaceInterface* volatile mNewSurface;     ///< Will be set to the new-surface if requested (set by the event-thread, read & cleared by the update-render thread).
   Dali::RenderSurfaceInterface* volatile mDeletedSurface; ///< Will be set to the deleted surface if requested (set by the event-thread, read & cleared by the update-render thread).