From 078e82a6559ca03396c015ca7c029f49517a6059 Mon Sep 17 00:00:00 2001 From: sunghyun kim Date: Thu, 21 Sep 2023 14:59:54 +0900 Subject: [PATCH] Apply Precompile shader Change-Id: I76880c50206efe8d63c8fa94b51e98c48018a71b --- .../adaptor-framework/shader-precompiler.cpp | 97 ++++++++++++++ .../adaptor-framework/shader-precompiler.h | 140 +++++++++++++++++++++ dali/integration-api/file.list | 2 + .../common/combined-update-render-controller.cpp | 112 ++++++++++++++++- .../common/combined-update-render-controller.h | 15 +++ 5 files changed, 364 insertions(+), 2 deletions(-) create mode 100644 dali/integration-api/adaptor-framework/shader-precompiler.cpp create mode 100644 dali/integration-api/adaptor-framework/shader-precompiler.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 index 0000000..7b3da3a --- /dev/null +++ b/dali/integration-api/adaptor-framework/shader-precompiler.cpp @@ -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 + +// EXTERNAL INCLUDES +#include + +namespace Dali +{ +std::unique_ptr 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 program) +{ + mProgram.push_back(move(program)); +} + +void ShaderPreCompiler::GetPreCompileShaderList(std::vector& shaderList) +{ + // move shader list + shaderList = mRawShaderList; +} + +void ShaderPreCompiler::SavePreCompileShaderList(std::vector& 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 index 0000000..6b14439 --- /dev/null +++ b/dali/integration-api/adaptor-framework/shader-precompiler.h @@ -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 +#include +#include +#include +#include + +// EXTERNAL HEDAER +#include +#include +#include +#include +#include + +namespace Dali +{ +struct RawShaderData +{ + int shaderCount; + std::vector vertexPrefix; + std::vector 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 program); + + /** + * @brief Gets the shader list to be precompiled + * + * @param[in] shaders shader data for precompile + */ + void GetPreCompileShaderList(std::vector& shaders); + + /** + * @brief Save the shader list to be precompiled + * + * @param[in] shaders shader data for precompile + */ + void SavePreCompileShaderList(std::vector& 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> mProgram; + static std::unique_ptr mInstance; + static std::once_flag mOnceFlag; + std::vector mRawShaderList; + ConditionalWait mConditionalWait; + Dali::Mutex mMutex; + bool mPrecompiled; + bool mEnabled; + bool mNeedsSleep{true}; +}; + +} // namespace Dali + +#endif // DALI_INTEGRATION_SHADER_PRECOMPILER_H diff --git a/dali/integration-api/file.list b/dali/integration-api/file.list index 11cacd7..be1de0c 100644 --- a/dali/integration-api/file.list +++ b/dali/integration-api/file.list @@ -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 ) diff --git a/dali/internal/adaptor/common/combined-update-render-controller.cpp b/dali/internal/adaptor/common/combined-update-render-controller.cpp index 3a8ad2c..a6ffa3b 100644 --- a/dali/internal/adaptor/common/combined-update-render-controller.cpp +++ b/dali/internal/adaptor/common/combined-update-render-controller.cpp @@ -25,6 +25,7 @@ #include "dali/public-api/common/dali-common.h" // INTERNAL INCLUDES +#include #include #include #include @@ -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 StringToVector(const std::string& str) +{ + auto retval = std::vector{}; + 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 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& vertexShaderSrc = StringToVector(std::move(vertexShader)); + vertexShaderCreateInfo.SetSourceSize(vertexShaderSrc.size()); + vertexShaderCreateInfo.SetSourceData(static_cast(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& fragmentShaderSrc = StringToVector(std::move(fragmentShader)); + fragmentShaderCreateInfo.SetSourceSize(fragmentShaderSrc.size()); + fragmentShaderCreateInfo.SetSourceData(static_cast(fragmentShaderSrc.data())); + auto fragmentGraphicsShader = graphics.GetController().CreateShader(fragmentShaderCreateInfo, nullptr); + + std::vector 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); } diff --git a/dali/internal/adaptor/common/combined-update-render-controller.h b/dali/internal/adaptor/common/combined-update-render-controller.h index bec2f70..8ca10f8 100644 --- a/dali/internal/adaptor/common/combined-update-render-controller.h +++ b/dali/internal/adaptor/common/combined-update-render-controller.h @@ -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). -- 2.7.4