From 41f3d5f5f98ba14d05623ca27aa90af06cee3356 Mon Sep 17 00:00:00 2001 From: "Eunki, Hong" Date: Tue, 11 Jun 2024 16:55:55 +0900 Subject: [PATCH] [Tizen] Support for recognizing legacy shaders. This reverts commit a6078655a74f289dd2497bec6b0dfc582cb5130e. Change-Id: I6f67507c22224fb86b087c2cabed664b693bf733 --- automated-tests/src/dali-internal/CMakeLists.txt | 1 + .../src/dali-internal/utc-Dali-Internal-Shader.cpp | 98 ++++++++++++++++++++++ dali/graphics-api/graphics-shader-create-info.h | 15 +++- dali/integration-api/file.list | 2 + dali/integration-api/testing.cpp | 33 ++++++++ dali/integration-api/testing.h | 43 ++++++++++ dali/internal/common/shader-data.h | 71 ++++++++++++++-- dali/internal/event/rendering/shader-impl.cpp | 24 +++++- dali/internal/event/rendering/shader-impl.h | 8 ++ dali/internal/render/renderers/render-renderer.cpp | 7 +- 10 files changed, 287 insertions(+), 15 deletions(-) create mode 100644 automated-tests/src/dali-internal/utc-Dali-Internal-Shader.cpp create mode 100644 dali/integration-api/testing.cpp create mode 100644 dali/integration-api/testing.h diff --git a/automated-tests/src/dali-internal/CMakeLists.txt b/automated-tests/src/dali-internal/CMakeLists.txt index 1a85735..8247542 100644 --- a/automated-tests/src/dali-internal/CMakeLists.txt +++ b/automated-tests/src/dali-internal/CMakeLists.txt @@ -28,6 +28,7 @@ SET(TC_SOURCES utc-Dali-Internal-PinchGestureProcessor.cpp utc-Dali-Internal-PipelineCache.cpp utc-Dali-Internal-RotationGesture.cpp + utc-Dali-Internal-Shader.cpp utc-Dali-Internal-TapGesture.cpp utc-Dali-Internal-TapGestureProcessor.cpp utc-Dali-Internal-Texture.cpp diff --git a/automated-tests/src/dali-internal/utc-Dali-Internal-Shader.cpp b/automated-tests/src/dali-internal/utc-Dali-Internal-Shader.cpp new file mode 100644 index 0000000..ec9cfa9 --- /dev/null +++ b/automated-tests/src/dali-internal/utc-Dali-Internal-Shader.cpp @@ -0,0 +1,98 @@ +/* +* 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. +* 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. +* +*/ + +#include +#include // DALI_PROPERTY_TABLE_BEGIN, DALI_PROPERTY, DALI_PROPERTY_TABLE_END +#include +#include +#include +#include +#include +#include + +using namespace Dali; + +int UtcDaliShaderTestVersion(void) +{ + TestApplication application; + + std::string vertexShader = + "//@version 100\n" + "some code\n"; + std::string fragmentShader = + "//@version 101\n" + "some code\n"; + + Dali::Shader shader = Dali::Shader::New(vertexShader, fragmentShader); + { + auto vertexPrefix = Dali::Shader::GetVertexShaderPrefix(); + auto fragmentPrefix = Dali::Shader::GetFragmentShaderPrefix(); + + DALI_TEST_EQUALS(vertexPrefix.substr(0, 20), "//@legacy-prefix-end", TEST_LOCATION); + DALI_TEST_EQUALS(fragmentPrefix.substr(0, 20), "//@legacy-prefix-end", TEST_LOCATION); + } + + // Test version number in the shader data + Dali::Internal::ThreadLocalStorage& tls = Dali::Internal::ThreadLocalStorage::Get(); + Dali::Internal::ShaderFactory& shaderFactory = tls.GetShaderFactory(); + size_t shaderHash; + Internal::ShaderDataPtr shaderData = shaderFactory.Load(vertexShader, fragmentShader, {}, {}, "", shaderHash); + + bool dataValid = (shaderData != nullptr); + DALI_TEST_EQUALS(dataValid, true, TEST_LOCATION); + + DALI_TEST_EQUALS(shaderData->GetVertexShaderVersion(), 100, TEST_LOCATION); + DALI_TEST_EQUALS(shaderData->GetFragmentShaderVersion(), 101, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliShaderWithPrefixTestVersion(void) +{ + TestApplication application; + + std::string vertexShader = + "//@version 100\n" + "some code\n"; + std::string fragmentShader = + "//@version 101\n" + "some code\n"; + + auto vertexPrefix = Dali::Shader::GetVertexShaderPrefix(); + auto fragmentPrefix = Dali::Shader::GetFragmentShaderPrefix(); + + Dali::Shader shader = Dali::Shader::New( + vertexPrefix + vertexShader, + fragmentPrefix + fragmentShader); + + DALI_TEST_EQUALS(vertexPrefix.substr(0, 20), "//@legacy-prefix-end", TEST_LOCATION); + DALI_TEST_EQUALS(fragmentPrefix.substr(0, 20), "//@legacy-prefix-end", TEST_LOCATION); + + // Test version number in the shader data + Dali::Internal::ThreadLocalStorage& tls = Dali::Internal::ThreadLocalStorage::Get(); + Dali::Internal::ShaderFactory& shaderFactory = tls.GetShaderFactory(); + size_t shaderHash; + Internal::ShaderDataPtr shaderData = shaderFactory.Load(vertexShader, fragmentShader, {}, {}, "", shaderHash); + + bool dataValid = (shaderData != nullptr); + DALI_TEST_EQUALS(dataValid, true, TEST_LOCATION); + + DALI_TEST_EQUALS(shaderData->GetVertexShaderVersion(), 100, TEST_LOCATION); + DALI_TEST_EQUALS(shaderData->GetFragmentShaderVersion(), 101, TEST_LOCATION); + + END_TEST; +} \ No newline at end of file diff --git a/dali/graphics-api/graphics-shader-create-info.h b/dali/graphics-api/graphics-shader-create-info.h index 2476c79..24cbfcf 100644 --- a/dali/graphics-api/graphics-shader-create-info.h +++ b/dali/graphics-api/graphics-shader-create-info.h @@ -2,7 +2,7 @@ #define DALI_GRAPHICS_SHADER_CREATE_INFO_H /* - * Copyright (c) 2021 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. @@ -117,6 +117,18 @@ struct ShaderCreateInfo } /** + * @brief Sets shader code DALi-specific version + * + * @param[in] value shader version + * @return reference to this structure + */ + auto& SetShaderVersion(uint32_t value) + { + shaderVersion = value; + return *this; + } + + /** * @brief Sets allocation callbacks which will be used when object is created * and destroyed. * @@ -148,6 +160,7 @@ struct ShaderCreateInfo const void* sourceData{nullptr}; uint32_t sourceSize{0u}; ShaderSourceMode sourceMode{}; + uint32_t shaderVersion{}; const AllocationCallbacks* allocationCallbacks{nullptr}; }; diff --git a/dali/integration-api/file.list b/dali/integration-api/file.list index 7b6dc9a..bf08a16 100644 --- a/dali/integration-api/file.list +++ b/dali/integration-api/file.list @@ -13,6 +13,7 @@ SET( platform_abstraction_src_files ${platform_abstraction_src_dir}/profiling.cpp ${platform_abstraction_src_dir}/render-task-list-integ.cpp ${platform_abstraction_src_dir}/scene.cpp + ${platform_abstraction_src_dir}/testing.cpp ${platform_abstraction_src_dir}/texture-integ.cpp ${platform_abstraction_src_dir}/trace.cpp ) @@ -52,6 +53,7 @@ SET( platform_abstraction_header_files ${platform_abstraction_src_dir}/resource-policies.h ${platform_abstraction_src_dir}/resource-types.h ${platform_abstraction_src_dir}/scene.h + ${platform_abstraction_src_dir}/testing.h ${platform_abstraction_src_dir}/texture-integ.h ${platform_abstraction_src_dir}/trace.h ) diff --git a/dali/integration-api/testing.cpp b/dali/integration-api/testing.cpp new file mode 100644 index 0000000..5b916b4 --- /dev/null +++ b/dali/integration-api/testing.cpp @@ -0,0 +1,33 @@ +/* +* 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. +* 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. +* +*/ + +#include +#include + +namespace Dali +{ +namespace Integration +{ +namespace Test +{ +std::string GenerateTaggedShaderPrefix(std::string prefix) +{ + return Internal::Shader::GenerateTaggedShaderPrefix(prefix); +} +} // Namespace Test +} // Namespace Integration +} // Namespace Dali diff --git a/dali/integration-api/testing.h b/dali/integration-api/testing.h new file mode 100644 index 0000000..ea2c993 --- /dev/null +++ b/dali/integration-api/testing.h @@ -0,0 +1,43 @@ +#ifndef DALI_INTEGRATION_TESTING_H +#define DALI_INTEGRATION_TESTING_H + +/* + * 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. + * 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. + * + */ + +#include + +namespace Dali +{ +namespace Integration +{ +/** + * This functions should be used only within automated tests suit + */ +namespace Test +{ +/** + * @brief Generates internal tag for shader prefix + * @param[in] prefix Prefix to generate tag for + * @return Tagged prefix + */ +std::string GenerateTaggedShaderPrefix(std::string prefix); + +} // Namespace Test +} // Namespace Integration +} // Namespace Dali + +#endif \ No newline at end of file diff --git a/dali/internal/common/shader-data.h b/dali/internal/common/shader-data.h index 10e58b4..f52accd 100644 --- a/dali/internal/common/shader-data.h +++ b/dali/internal/common/shader-data.h @@ -72,6 +72,8 @@ public: mRenderPassTag(renderPassTag), mName(name) { + UpdateShaderVersion(mVertexShader, mVertexShaderVersion); + UpdateShaderVersion(mFragmentShader, mFragmentShaderVersion); } /** @@ -91,6 +93,8 @@ public: mRenderPassTag(renderPassTag), mName(name) { + UpdateShaderVersion(mVertexShader, mVertexShaderVersion); + UpdateShaderVersion(mFragmentShader, mFragmentShaderVersion); } /** @@ -110,6 +114,8 @@ public: mRenderPassTag(renderPassTag), mName(name) { + UpdateShaderVersion(mVertexShader, mVertexShaderVersion); + UpdateShaderVersion(mFragmentShader, mFragmentShaderVersion); } /** @@ -276,19 +282,66 @@ public: // API return mName; } + /** + * Returns DALi specific vertex shader version + * @return valid version number + */ + uint32_t GetVertexShaderVersion() const + { + return mVertexShaderVersion; + } + + /** + * Returns DALi specific fragment shader version + * @return valid version number + */ + uint32_t GetFragmentShaderVersion() const + { + return mFragmentShaderVersion; + } + private: // Not implemented ShaderData(const ShaderData& other); ///< no copying of this object ShaderData& operator=(const ShaderData& rhs); ///< no copying of this object -private: // Data - std::size_t mShaderHash; ///< hash key created with vertex and fragment shader code - std::vector mVertexShader; ///< source code for vertex program - std::vector mFragmentShader; ///< source code for fragment program - Dali::Shader::Hint::Value mHints; ///< take a hint - Dali::Vector mBuffer; ///< buffer containing compiled binary bytecode - Graphics::ShaderSourceMode mSourceMode; ///< Source mode of shader data ( text or binary ) - uint32_t mRenderPassTag{0u}; ///< Render Pass Tag for this shader - std::string mName{""}; ///< Name for this shader +private: + /** + * Updates shader version. + */ + void UpdateShaderVersion(std::vector& code, uint32_t& outVersion) + { + // The version may be updated only for GLSL language. + // If we support direct SPIRV this will be skipped + std::string_view strView = code.data(); + + // find first occurence of 'version' tag + // the tag is expected at the start of line + static const std::string VERSION_TAG = "//@version"; + + auto pos = strView.find(VERSION_TAG); + if(pos != std::string_view::npos && (pos == 0 || strView[pos - 1] == '\n')) + { + char* end; + // Update version + outVersion = std::strtoul(strView.data() + pos + VERSION_TAG.length(), &end, 10); + } + else + { + outVersion = 0; + } + } + +private: // Data + std::size_t mShaderHash; ///< hash key created with vertex and fragment shader code + std::vector mVertexShader; ///< source code for vertex program + std::vector mFragmentShader; ///< source code for fragment program + Dali::Shader::Hint::Value mHints; ///< take a hint + Dali::Vector mBuffer; ///< buffer containing compiled binary bytecode + Graphics::ShaderSourceMode mSourceMode; ///< Source mode of shader data ( text or binary ) + uint32_t mRenderPassTag{0u}; ///< Render Pass Tag for this shader + std::string mName{""}; ///< Name for this shader + uint32_t mVertexShaderVersion; ///< Vertex shader version + uint32_t mFragmentShaderVersion; ///< Fragment shader version }; } // namespace Internal diff --git a/dali/internal/event/rendering/shader-impl.cpp b/dali/internal/event/rendering/shader-impl.cpp index de3c95e..76e1e04 100644 --- a/dali/internal/event/rendering/shader-impl.cpp +++ b/dali/internal/event/rendering/shader-impl.cpp @@ -343,13 +343,33 @@ std::string Shader::GetShaderVersionPrefix() std::string Shader::GetVertexShaderPrefix() { Dali::Internal::ThreadLocalStorage& tls = Dali::Internal::ThreadLocalStorage::Get(); - return tls.GetVertexShaderPrefix(); + return GenerateTaggedShaderPrefix(tls.GetVertexShaderPrefix()); } std::string Shader::GetFragmentShaderPrefix() { Dali::Internal::ThreadLocalStorage& tls = Dali::Internal::ThreadLocalStorage::Get(); - return tls.GetFragmentShaderPrefix(); + return GenerateTaggedShaderPrefix(tls.GetFragmentShaderPrefix()); +} + +std::string Shader::GenerateTaggedShaderPrefix(const std::string& shaderPrefix) +{ + // The tag is added at the top of vertex/fragment shader and + // contains an offset where the source code starts after + // the prefix. + // This offset is used later by the graphics backend to ignore + // the legacy prefix if provided with new versioned shader. + // When shader contains tagged prefix, then it starts with: + // "//@legacy-prefix-end " tag. + static const std::string TAG = "//@legacy-prefix-end "; + const uint32_t OFFSET_DIGITS = 5; // offset allocates 5 digits + + auto prefix = std::string(TAG + "00000\n") + shaderPrefix; + auto prefixLength = prefix.length(); + char tmp = *(prefix.data() + TAG.length() + OFFSET_DIGITS); + std::snprintf(prefix.data() + TAG.size(), OFFSET_DIGITS + 1, "%05d", int(prefixLength)); + *(prefix.data() + TAG.length() + OFFSET_DIGITS) = tmp; + return prefix; } } // namespace Internal diff --git a/dali/internal/event/rendering/shader-impl.h b/dali/internal/event/rendering/shader-impl.h index ccde312..0f597d1 100644 --- a/dali/internal/event/rendering/shader-impl.h +++ b/dali/internal/event/rendering/shader-impl.h @@ -141,6 +141,14 @@ public: * @copydoc Dali::Shader::GetFragmentShaderPrefix() */ static std::string GetFragmentShaderPrefix(); + +public: + /** + * Generates tag 'legacy-prefix-end' with end position of + * prefix text to make shader code parsing easier. + * Function is public to be testable + */ + static std::string GenerateTaggedShaderPrefix(const std::string& shaderPrefix); }; } // namespace Internal diff --git a/dali/internal/render/renderers/render-renderer.cpp b/dali/internal/render/renderers/render-renderer.cpp index 4320a43..975664a 100644 --- a/dali/internal/render/renderers/render-renderer.cpp +++ b/dali/internal/render/renderers/render-renderer.cpp @@ -421,6 +421,7 @@ Program* Renderer::PrepareProgram(const SceneGraph::RenderInstruction& instructi const std::vector& vertexShaderSrc = shaderData->GetShaderForPipelineStage(Graphics::PipelineStage::VERTEX_SHADER); vertexShaderCreateInfo.SetSourceSize(vertexShaderSrc.size()); vertexShaderCreateInfo.SetSourceData(static_cast(vertexShaderSrc.data())); + vertexShaderCreateInfo.SetShaderVersion(shaderData->GetVertexShaderVersion()); auto vertexShader = mGraphicsController->CreateShader(vertexShaderCreateInfo, nullptr); Graphics::ShaderCreateInfo fragmentShaderCreateInfo; @@ -429,6 +430,7 @@ Program* Renderer::PrepareProgram(const SceneGraph::RenderInstruction& instructi const std::vector& fragmentShaderSrc = shaderData->GetShaderForPipelineStage(Graphics::PipelineStage::FRAGMENT_SHADER); fragmentShaderCreateInfo.SetSourceSize(fragmentShaderSrc.size()); fragmentShaderCreateInfo.SetSourceData(static_cast(fragmentShaderSrc.data())); + fragmentShaderCreateInfo.SetShaderVersion(shaderData->GetFragmentShaderVersion()); auto fragmentShader = mGraphicsController->CreateShader(fragmentShaderCreateInfo, nullptr); std::vector shaderStates{ @@ -490,9 +492,8 @@ bool Renderer::Render(Graphics::CommandBuffer& comma mRenderCallbackInput->usingOwnEglContext = isolatedNotDirect; // Set storage for the context to be used info.glesNativeInfo.eglSharedContextStoragePointer = &mRenderCallbackInput->eglContext; - info.executionMode = isolatedNotDirect ? - Graphics::DrawNativeExecutionMode::ISOLATED : Graphics::DrawNativeExecutionMode::DIRECT; - info.reserved = nullptr; + info.executionMode = isolatedNotDirect ? Graphics::DrawNativeExecutionMode::ISOLATED : Graphics::DrawNativeExecutionMode::DIRECT; + info.reserved = nullptr; auto& textureResources = mRenderCallback->GetTextureResources(); -- 2.7.4