--- /dev/null
+/*
+ * 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
--- /dev/null
+#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
#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>
* 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
///////////////////////////////////////////////////////////////////////////////////////////////////
mUpdateRenderThreadCanSleep(FALSE),
mPendingRequestUpdate(FALSE),
mUseElapsedTimeAfterWait(FALSE),
+ mIsPreCompileCancelled(FALSE),
mNewSurface(NULL),
mDeletedSurface(nullptr),
mPostRendering(FALSE),
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);
}
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);
}
ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
// Surface is resized and the surface resized count is increased.
mSurfaceResized++;
+ CancelPreCompile();
mUpdateRenderThreadWaitCondition.Notify(lock);
}
}
mUpdateRenderThreadCanSleep = FALSE;
mUploadWithoutRendering = (updateMode == UpdateMode::SKIP_RENDER);
LOG_COUNTER_EVENT("mUpdateRenderRunCount: %d, mUseElapsedTimeAfterWait: %d", mUpdateRenderRunCount, mUseElapsedTimeAfterWait);
+ CancelPreCompile();
mUpdateRenderThreadWaitCondition.Notify(lock);
}
{
ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
mDestroyUpdateRenderThread = TRUE;
+ CancelPreCompile();
mUpdateRenderThreadWaitCondition.Notify(lock);
}
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);
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))
{
if(!uploadOnly || surfaceResized)
{
// Go through each window
- WindowContainer windows;
+ windows.clear();
mAdaptorInterfaces.GetWindowContainerInterface(windows);
for(auto&& window : windows)
// Inform core of context destruction
mCore.ContextDestroyed();
- WindowContainer windows;
+ windows.clear();
mAdaptorInterfaces.GetWindowContainerInterface(windows);
// Destroy surfaces
}
}
+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
///////////////////////////////////////////////////////////////////////////////////////////////////
{
ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
mPostRendering = FALSE;
+ CancelPreCompile();
mUpdateRenderThreadWaitCondition.Notify(lock);
}