From: Adam Bialogonski Date: Thu, 25 Feb 2021 17:03:36 +0000 (+0000) Subject: Shader support X-Git-Tag: graphics-backend-pre-release-2~3 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F09%2F254109%2F11;p=platform%2Fcore%2Fuifw%2Fdali-adaptor.git Shader support - program implementation - pipeline cache upgraded - pipeline cache supports caching program - shader reflection bound with Program - added shader compilation and program linking Change-Id: I53569d04848410b21150ca239b6f9b01015310b9 --- diff --git a/automated-tests/src/dali-adaptor-internal/CMakeLists.txt b/automated-tests/src/dali-adaptor-internal/CMakeLists.txt index 51f3cf7..7f3a34c 100644 --- a/automated-tests/src/dali-adaptor-internal/CMakeLists.txt +++ b/automated-tests/src/dali-adaptor-internal/CMakeLists.txt @@ -34,6 +34,7 @@ LIST(APPEND TC_SOURCES ../dali-adaptor/dali-test-suite-utils/test-graphics-controller.cpp ../dali-adaptor/dali-test-suite-utils/test-graphics-texture.cpp ../dali-adaptor/dali-test-suite-utils/test-graphics-pipeline.cpp + ../dali-adaptor/dali-test-suite-utils/test-graphics-program.cpp ../dali-adaptor/dali-test-suite-utils/test-graphics-reflection.cpp ../dali-adaptor/dali-test-suite-utils/test-graphics-sampler.cpp ../dali-adaptor/dali-test-suite-utils/test-native-image.cpp diff --git a/automated-tests/src/dali-adaptor/CMakeLists.txt b/automated-tests/src/dali-adaptor/CMakeLists.txt index b29d3ff..1039a3f 100644 --- a/automated-tests/src/dali-adaptor/CMakeLists.txt +++ b/automated-tests/src/dali-adaptor/CMakeLists.txt @@ -32,6 +32,7 @@ LIST(APPEND TC_SOURCES dali-test-suite-utils/test-graphics-command-buffer.cpp dali-test-suite-utils/test-graphics-controller.cpp dali-test-suite-utils/test-graphics-pipeline.cpp + dali-test-suite-utils/test-graphics-program.cpp dali-test-suite-utils/test-graphics-reflection.cpp dali-test-suite-utils/test-graphics-texture.cpp dali-test-suite-utils/test-graphics-sampler.cpp diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-controller.cpp b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-controller.cpp index 41d13c9..45fbfa3 100644 --- a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-controller.cpp +++ b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-controller.cpp @@ -18,6 +18,7 @@ #include "test-graphics-buffer.h" #include "test-graphics-command-buffer.h" +#include "test-graphics-program.h" #include "test-graphics-reflection.h" #include "test-graphics-sampler.h" #include "test-graphics-texture.h" @@ -705,6 +706,12 @@ Graphics::UniquePtr TestGraphicsController::CreatePipeline(c return std::make_unique(mGl, pipelineCreateInfo); } +Graphics::UniquePtr TestGraphicsController::CreateProgram(const Graphics::ProgramCreateInfo& programCreateInfo, Graphics::UniquePtr&& oldProgram) +{ + mCallStack.PushCall("CreateProgram", ""); + return Graphics::MakeUnique(mGl, programCreateInfo, mVertexFormats); +} + Graphics::UniquePtr TestGraphicsController::CreateShader(const Graphics::ShaderCreateInfo& shaderCreateInfo, Graphics::UniquePtr&& oldShader) { mCallStack.PushCall("Controller::CreateShader", ""); @@ -767,12 +774,11 @@ const Graphics::TextureProperties& TestGraphicsController::GetTextureProperties( return textureProperties; } -const Graphics::Reflection& TestGraphicsController::GetPipelineReflection(const Graphics::Pipeline& pipeline) +const Graphics::Reflection& TestGraphicsController::GetProgramReflection(const Graphics::Program& program) { - static TestGraphicsReflection reflection(mGl); - mCallStack.PushCall("Controller::GetPipelineReflection", ""); + mCallStack.PushCall("Controller::GetProgramReflection", ""); - return reflection; + return static_cast(&program)->GetReflection(); } bool TestGraphicsController::PipelineEquals(const Graphics::Pipeline& pipeline0, const Graphics::Pipeline& pipeline1) const @@ -781,4 +787,10 @@ bool TestGraphicsController::PipelineEquals(const Graphics::Pipeline& pipeline0, return false; } +bool TestGraphicsController::GetProgramParameter(Graphics::Program& program, uint32_t parameterId, void* outData) +{ + mCallStack.PushCall("Controller::GetProgramParameter", ""); + return false; +} + } // namespace Dali diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-controller.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-controller.h index bf2ba21..2ee3de4 100644 --- a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-controller.h +++ b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-controller.h @@ -176,6 +176,14 @@ public: Graphics::UniquePtr CreatePipeline(const Graphics::PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr&& oldPipeline) override; /** + * @brief Creates new Program object + * + * @param[in] programCreateInfo The valid ProgramCreateInfo structure + * @return pointer to the Program object + */ + Graphics::UniquePtr CreateProgram(const Graphics::ProgramCreateInfo& programCreateInfo, Graphics::UniquePtr&& oldProgram) override; + + /** * @brief Creates new Shader object * * @param[in] shaderCreateInfo The valid ShaderCreateInfo structure @@ -268,12 +276,12 @@ public: const Graphics::TextureProperties& GetTextureProperties(const Graphics::Texture& texture) override; /** - * @brief Returns the reflection of the given pipeline + * @brief Returns the reflection of the given program * - * @param[in] pipeline The pipeline - * @return The reflection of the pipeline + * @param[in] program The program + * @return The reflection of the program */ - const Graphics::Reflection& GetPipelineReflection(const Graphics::Pipeline& pipeline) override; + const Graphics::Reflection& GetProgramReflection(const Graphics::Program& program) override; /** * @brief Tests whether two Pipelines are the same. @@ -284,9 +292,33 @@ public: */ bool PipelineEquals(const Graphics::Pipeline& pipeline0, const Graphics::Pipeline& pipeline1) const override; +public: // Test Functions + void SetVertexFormats(Property::Array& vfs) + { + mVertexFormats = vfs; + } + + void ClearSubmitStack() + { + mSubmitStack.clear(); + } + + /** + * @brief Retrieves program parameters + * + * This function can be used to retrieve data from internal implementation + * + * @param[in] program Valid program object + * @param[in] parameterId Integer parameter id + * @param[out] outData Pointer to output memory + * @return True on success + */ + bool GetProgramParameter(Graphics::Program& program, uint32_t parameterId, void* outData) override; + public: - mutable TraceCallStack mCallStack; - mutable TraceCallStack mCommandBufferCallStack; + mutable TraceCallStack mCallStack; + mutable TraceCallStack mCommandBufferCallStack; + mutable std::vector mSubmitStack; TestGlAbstraction mGl; TestGlSyncAbstraction mGlSyncAbstraction; @@ -294,6 +326,8 @@ public: bool isDiscardQueueEmptyResult{true}; bool isDrawOnResumeRequiredResult{true}; + + Property::Array mVertexFormats; }; } // namespace Dali diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-pipeline.cpp b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-pipeline.cpp index 0cc4194..d303d56 100644 --- a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-pipeline.cpp +++ b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-pipeline.cpp @@ -26,8 +26,8 @@ TestGraphicsPipeline::TestGraphicsPipeline(TestGlAbstraction& gl, const Graphics if(createInfo.colorBlendState) colorBlendState = *createInfo.colorBlendState; - if(createInfo.shaderState) - shaderState = *createInfo.shaderState; + if(createInfo.programState) + programState = *createInfo.programState; if(createInfo.viewportState) viewportState = *createInfo.viewportState; diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-pipeline.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-pipeline.h index 666e0d4..dc3a58d 100644 --- a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-pipeline.h +++ b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-pipeline.h @@ -31,7 +31,7 @@ public: TestGlAbstraction& mGl; Graphics::ColorBlendState colorBlendState; - std::vector shaderState; + Graphics::ProgramState programState; Graphics::ViewportState viewportState; Graphics::FramebufferState framebufferState; Graphics::Pipeline basePipeline; diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-program.cpp b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-program.cpp new file mode 100644 index 0000000..5b8c02c --- /dev/null +++ b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-program.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2021 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 "test-graphics-program.h" + +namespace Dali +{ +TestGraphicsProgram::TestGraphicsProgram(TestGlAbstraction& gl, const Graphics::ProgramCreateInfo& createInfo, Property::Array& vertexFormats) +: mGl(gl), + mCreateInfo(createInfo), + mReflection(gl) +{ +} + +} // namespace Dali diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-program.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-program.h new file mode 100644 index 0000000..2bd04de --- /dev/null +++ b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-program.h @@ -0,0 +1,53 @@ +#ifndef DALI_TEST_GRAPHICS_PROGRAM_H +#define DALI_TEST_GRAPHICS_PROGRAM_H + +/* + * Copyright (c) 2021 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 +#include "test-gl-abstraction.h" +#include "test-graphics-reflection.h" + +namespace Dali +{ +class TestGraphicsProgram : public Graphics::Program +{ +public: + TestGraphicsProgram(TestGlAbstraction& gl, const Graphics::ProgramCreateInfo& createInfo, Property::Array& vertexFormats); + + // For API + const TestGraphicsReflection& GetReflection() const + { + // Build a reflection + return mReflection; + } + + // For tests + TestGraphicsReflection& GetProgamReflection() + { + return mReflection; + } + +public: + TestGlAbstraction& mGl; + Graphics::ProgramCreateInfo mCreateInfo; + TestGraphicsReflection mReflection; +}; + +} // namespace Dali + +#endif //DALI_TEST_GRAPHICS_PROGRAM_H diff --git a/automated-tests/src/dali-graphics/CMakeLists.txt b/automated-tests/src/dali-graphics/CMakeLists.txt index e1c48a8..8e0a197 100644 --- a/automated-tests/src/dali-graphics/CMakeLists.txt +++ b/automated-tests/src/dali-graphics/CMakeLists.txt @@ -20,6 +20,7 @@ LIST(APPEND TC_SOURCES ../dali-adaptor/dali-test-suite-utils/test-graphics-texture.cpp ../dali-adaptor/dali-test-suite-utils/test-graphics-sampler.cpp ../dali-adaptor/dali-test-suite-utils/test-graphics-pipeline.cpp + ../dali-adaptor/dali-test-suite-utils/test-graphics-program.cpp ../dali-adaptor/dali-test-suite-utils/test-graphics-reflection.cpp ../dali-adaptor/dali-test-suite-utils/test-native-image.cpp ../dali-adaptor/dali-test-suite-utils/test-platform-abstraction.cpp diff --git a/automated-tests/src/dali-platform-abstraction/CMakeLists.txt b/automated-tests/src/dali-platform-abstraction/CMakeLists.txt index 3fdc341..2335408 100644 --- a/automated-tests/src/dali-platform-abstraction/CMakeLists.txt +++ b/automated-tests/src/dali-platform-abstraction/CMakeLists.txt @@ -23,6 +23,7 @@ LIST(APPEND TC_SOURCES ../dali-adaptor/dali-test-suite-utils/test-graphics-texture.cpp ../dali-adaptor/dali-test-suite-utils/test-graphics-sampler.cpp ../dali-adaptor/dali-test-suite-utils/test-graphics-pipeline.cpp + ../dali-adaptor/dali-test-suite-utils/test-graphics-program.cpp ../dali-adaptor/dali-test-suite-utils/test-graphics-reflection.cpp ../dali-adaptor/dali-test-suite-utils/test-native-image.cpp ../dali-adaptor/dali-test-suite-utils/test-platform-abstraction.cpp diff --git a/dali/internal/graphics/gles-impl/egl-graphics-controller.cpp b/dali/internal/graphics/gles-impl/egl-graphics-controller.cpp index ef507a7..86fa049 100644 --- a/dali/internal/graphics/gles-impl/egl-graphics-controller.cpp +++ b/dali/internal/graphics/gles-impl/egl-graphics-controller.cpp @@ -26,6 +26,7 @@ #include #include #include +#include "gles-graphics-program.h" namespace Dali::Graphics { @@ -152,11 +153,6 @@ EglGraphicsController::CreateBuffer(const BufferCreateInfo& bufferCreateInfo, Gr return NewObject(bufferCreateInfo, *this, std::move(oldBuffer)); } -Graphics::UniquePtr EglGraphicsController::CreateShader(const ShaderCreateInfo& shaderCreateInfo, Graphics::UniquePtr&& oldShader) -{ - return NewObject(shaderCreateInfo, *this, std::move(oldShader)); -} - Graphics::UniquePtr EglGraphicsController::CreatePipeline(const PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr&& oldPipeline) { // Create pipeline cache if needed @@ -168,6 +164,27 @@ Graphics::UniquePtr EglGraphicsController::CreatePipeline(const Pipeli return mPipelineCache->GetPipeline(pipelineCreateInfo, std::move(oldPipeline)); } +Graphics::UniquePtr EglGraphicsController::CreateProgram(const ProgramCreateInfo& programCreateInfo, UniquePtr&& oldProgram) +{ + // Create program cache if needed + if(!mPipelineCache) + { + mPipelineCache = std::make_unique(*this); + } + + return mPipelineCache->GetProgram(programCreateInfo, std::move(oldProgram)); +} + +Graphics::UniquePtr EglGraphicsController::CreateShader(const ShaderCreateInfo& shaderCreateInfo, Graphics::UniquePtr&& oldShader) +{ + return NewObject(shaderCreateInfo, *this, std::move(oldShader)); +} + +const Graphics::Reflection& EglGraphicsController::GetProgramReflection(const Graphics::Program& program) +{ + return static_cast(&program)->GetReflection(); +} + void EglGraphicsController::AddTexture(GLES::Texture& texture) { // Assuming we are on the correct context @@ -187,6 +204,12 @@ void EglGraphicsController::ProcessDiscardQueues() // Process buffers ProcessDiscardQueue(mDiscardBufferQueue); + + // Process pipelines + ProcessDiscardQueue(mDiscardPipelineQueue); + + // Process programs + ProcessDiscardQueue(mDiscardProgramQueue); } void EglGraphicsController::ProcessCreateQueues() @@ -355,4 +378,14 @@ Graphics::UniquePtr EglGraphicsController::MapBufferRange(const MapBuffe return Graphics::UniquePtr(new GLES::Memory(mapInfo, *this)); } +bool EglGraphicsController::GetProgramParameter(Graphics::Program& program, uint32_t parameterId, void* outData) +{ + return static_cast(&program)->GetImplementation()->GetParameter(parameterId, outData); +} + +GLES::PipelineCache& EglGraphicsController::GetPipelineCache() const +{ + return *mPipelineCache; +} + } // namespace Dali::Graphics diff --git a/dali/internal/graphics/gles-impl/egl-graphics-controller.h b/dali/internal/graphics/gles-impl/egl-graphics-controller.h index c7d85c0..70f6d8c 100644 --- a/dali/internal/graphics/gles-impl/egl-graphics-controller.h +++ b/dali/internal/graphics/gles-impl/egl-graphics-controller.h @@ -25,8 +25,8 @@ #include "gles-context.h" #include "gles-graphics-buffer.h" #include "gles-graphics-memory.h" -#include "gles-graphics-pipeline.h" #include "gles-graphics-pipeline-cache.h" +#include "gles-graphics-pipeline.h" #include "gles-graphics-reflection.h" #include "gles-graphics-texture.h" @@ -196,6 +196,11 @@ public: Graphics::UniquePtr CreatePipeline(const PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr&& oldPipeline) override; /** + * @copydoc Dali::Graphics::CreateProgram() + */ + Graphics::UniquePtr CreateProgram(const ProgramCreateInfo& programCreateInfo, UniquePtr&& oldProgram) override; + + /** * @copydoc Dali::Graphics::CreateShader() */ Graphics::UniquePtr CreateShader(const ShaderCreateInfo& shaderCreateInfo, Graphics::UniquePtr&& oldShader) override; @@ -264,11 +269,8 @@ public: /** * @copydoc Dali::Graphics::Controller::GetPipelineReflection() */ - const Reflection& GetPipelineReflection(const Pipeline& pipeline) override - { - static GLES::Reflection dummy(*this); - return dummy; - } + + [[nodiscard]] const Reflection& GetProgramReflection(const Graphics::Program& program) override; /** * @copydoc Dali::Graphics::PipelineEquals() @@ -317,6 +319,30 @@ public: } /** + * @brief Pushes Program to the discard queue + * + * Function is called from the UniquePtr custom deleter. + * + * @param[in] program Pointer to the program + */ + void DiscardResource(GLES::Program* program) + { + mDiscardProgramQueue.push(program); + } + + /** + * @brief Pushes Pipeline to the discard queue + * + * Function is called from the UniquePtr custom deleter. + * + * @param[in] program Pointer to the pipeline + */ + void DiscardResource(GLES::Pipeline* pipeline) + { + mDiscardPipelineQueue.push(pipeline); + } + + /** * @brief Flushes all pending updates * * Function flushes all pending resource constructions, @@ -330,11 +356,14 @@ public: // Process updates ProcessTextureUpdateQueue(); + // Process main command queue + ProcessCommandQueues(); + // Process discards ProcessDiscardQueues(); - // Process main command queue - ProcessCommandQueues(); + // Flush pipeline cache to remove unused pipelines + GetPipelineCache().FlushCache(); } // Test update to tick controller, usually it will run own thread @@ -409,6 +438,26 @@ public: */ void ProcessTextureUpdateQueue(); + /** + * @brief Returns program custom parameter + * + * This function can be used as a backdoor in order to retrieve + * certain data out of implementation + * + * @param[in] program Valid Program object + * @param parameterId Integer id of parameter + * @param outData Output data + * @return True if parameter retrieved + */ + bool GetProgramParameter(Graphics::Program& program, uint32_t parameterId, void* outData) override; + + /** + * @brief Returns pipeline cache object + * + * @return Valid pipeline cache object + */ + [[nodiscard]] GLES::PipelineCache& GetPipelineCache() const; + private: Integration::GlAbstraction* mGlAbstraction{nullptr}; Integration::GlSyncAbstraction* mGlSyncAbstraction{nullptr}; @@ -420,6 +469,10 @@ private: std::queue mCreateBufferQueue; ///< Create queue for buffer resource std::queue mDiscardBufferQueue; ///< Discard queue for buffer resource + std::queue mDiscardProgramQueue; ///< Discard queue for program resource + + std::queue mDiscardPipelineQueue; ///< Discard queue of pipelines + std::queue mCommandQueue; ///< we may have more in the future using TextureUpdateRequest = std::pair; diff --git a/dali/internal/graphics/gles-impl/file.list b/dali/internal/graphics/gles-impl/file.list index e251745..6195634 100644 --- a/dali/internal/graphics/gles-impl/file.list +++ b/dali/internal/graphics/gles-impl/file.list @@ -8,6 +8,7 @@ SET( adaptor_graphics_gles_src_files ${adaptor_graphics_gles_src_files} ${adaptor_graphics_dir}/gles-impl/gles-graphics-framebuffer.cpp ${adaptor_graphics_dir}/gles-impl/gles-graphics-memory.cpp ${adaptor_graphics_dir}/gles-impl/gles-graphics-pipeline.cpp + ${adaptor_graphics_dir}/gles-impl/gles-graphics-program.cpp ${adaptor_graphics_dir}/gles-impl/gles-graphics-reflection.cpp ${adaptor_graphics_dir}/gles-impl/gles-graphics-render-pass.cpp ${adaptor_graphics_dir}/gles-impl/gles-graphics-render-target.cpp diff --git a/dali/internal/graphics/gles-impl/gles-context.cpp b/dali/internal/graphics/gles-impl/gles-context.cpp index 3d965ad..50eb479 100644 --- a/dali/internal/graphics/gles-impl/gles-context.cpp +++ b/dali/internal/graphics/gles-impl/gles-context.cpp @@ -70,6 +70,7 @@ void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall) mImpl->mCurrentPipeline = mImpl->mNewPipeline; mImpl->mNewPipeline = nullptr; } + mImpl->mCurrentPipeline->GetPipeline().Bind(nullptr); // Blend state ResolveBlendState(); diff --git a/dali/internal/graphics/gles-impl/gles-graphics-pipeline-cache.cpp b/dali/internal/graphics/gles-impl/gles-graphics-pipeline-cache.cpp index 9e69c77..4b178a2 100644 --- a/dali/internal/graphics/gles-impl/gles-graphics-pipeline-cache.cpp +++ b/dali/internal/graphics/gles-impl/gles-graphics-pipeline-cache.cpp @@ -15,29 +15,267 @@ * */ -// CLASS HEADER #include "gles-graphics-pipeline-cache.h" - -// INTERNAL INCLUDES +#include #include "gles-graphics-pipeline.h" +#include "gles-graphics-program.h" namespace Dali::Graphics::GLES { /** - * @brief Implementation of pipeline cache + * @brief custom delete function for cached object + */ +template +struct CachedObjectDeleter +{ + CachedObjectDeleter() = default; + + void operator()(T* object) + { + // Discard resource (add it to discard queue) + object->DiscardResource(); + } +}; + +/** + * @brief The order of states being stored in the cache and mask + */ +enum class StateLookupIndex : uint32_t +{ + COLOR_BLEND_STATE_BIT = 0, + VIEWPORT_STATE_BIT = 1, + FRAMEBUFFER_STATE_BIT = 2, + BASE_PIPELINE_STATE_BIT = 3, + DEPTH_STENCIL_STATE_BIT = 4, + RASTERIZATION_STATE_BIT = 5, + VERTEX_INPUT_STATE_BIT = 6, + INPUT_ASSEMBLY_STATE_BIT = 7, + MAX_STATE = 8 +}; + +/** + * Helper float compare function + */ +static bool cmpf(float A, float B, float epsilon = 0.005f) +{ + return (fabs(A - B) < epsilon); +} + +/** + * Helper operators + */ +static bool operator==(const Graphics::Viewport& lhs, const Graphics::Viewport& rhs) +{ + return cmpf(lhs.x, rhs.x) && + cmpf(lhs.y, rhs.y) && + cmpf(lhs.width, rhs.width) && + cmpf(lhs.height, rhs.height) && + cmpf(lhs.minDepth, rhs.minDepth) && + cmpf(lhs.maxDepth, rhs.maxDepth); +} + +static bool operator==(const Graphics::Rect2D& lhs, const Graphics::Rect2D& rhs) +{ + return cmpf(lhs.x, rhs.x) && + cmpf(lhs.y, rhs.y) && + cmpf(lhs.width, rhs.width) && + cmpf(lhs.height, rhs.height); +} + +static bool operator==(const Graphics::StencilOpState& lhs, const Graphics::StencilOpState& rhs) +{ + return lhs.failOp == rhs.failOp && + lhs.passOp == rhs.passOp && + lhs.depthFailOp == rhs.depthFailOp && + lhs.compareOp == rhs.compareOp && + lhs.compareMask == rhs.compareMask && + lhs.writeMask == rhs.writeMask && + lhs.reference == rhs.reference; +} + +static bool +operator==(const Dali::Graphics::VertexInputState::Attribute& lhs, + const Dali::Graphics::VertexInputState::Attribute& rhs) +{ + return lhs.location == rhs.location && + lhs.binding == rhs.binding && + lhs.offset == rhs.offset && + lhs.format == rhs.format; +} + +static bool +operator==(const Dali::Graphics::VertexInputState::Binding& lhs, const Dali::Graphics::VertexInputState::Binding& rhs) +{ + return lhs.stride == rhs.stride && + lhs.inputRate == rhs.inputRate; +} + +using PipelineStateCompateFunctionType = bool(const Graphics::PipelineCreateInfo*, + const Graphics::PipelineCreateInfo*); + +static std::vector STATE_COMPARE_FUNC_TABLE{}; + +/** + * @brief Initialises compare function lookup table + */ +void InitialiseStateCompareLookupTable() +{ + STATE_COMPARE_FUNC_TABLE = { + [](const auto* lhs, const auto* rhs) -> bool // colorBlendState + { + const auto& lcb = *lhs->colorBlendState; + const auto& rcb = *rhs->colorBlendState; + return lcb.logicOpEnable == rcb.logicOpEnable && + lcb.logicOp == rcb.logicOp && + cmpf(lcb.blendConstants[0], rcb.blendConstants[0]) && + cmpf(lcb.blendConstants[1], rcb.blendConstants[1]) && + cmpf(lcb.blendConstants[2], rcb.blendConstants[2]) && + cmpf(lcb.blendConstants[3], rcb.blendConstants[3]) && + lcb.blendEnable == rcb.blendEnable && + lcb.srcColorBlendFactor == rcb.srcColorBlendFactor && + lcb.dstColorBlendFactor == rcb.dstColorBlendFactor && + lcb.colorBlendOp == rcb.colorBlendOp && + lcb.srcAlphaBlendFactor == rcb.srcAlphaBlendFactor && + lcb.dstAlphaBlendFactor == rcb.dstAlphaBlendFactor && + lcb.alphaBlendOp == rcb.alphaBlendOp && + lcb.colorComponentWriteBits == rcb.colorComponentWriteBits; + }, + [](const auto* lhs, const auto* rhs) -> bool // viewport state + { + const auto& lvp = *lhs->viewportState; + const auto& rvp = *rhs->viewportState; + return lvp.viewport == rvp.viewport && + lvp.scissor == rvp.scissor && + lvp.scissorTestEnable == rvp.scissorTestEnable; + }, + [](const auto* lhs, const auto* rhs) -> bool // framebufferState + { + const auto& lfb = *lhs->framebufferState; + const auto& rfb = *rhs->framebufferState; + return lfb.framebuffer == rfb.framebuffer; + }, + [](const auto* lhs, const auto* rhs) -> bool // basePipeline + { + return lhs->basePipeline == rhs->basePipeline; + }, + [](const auto* lhs, const auto* rhs) -> bool // depthStencilState + { + const auto& lds = *lhs->depthStencilState; + const auto& rds = *rhs->depthStencilState; + return lds.depthTestEnable == rds.depthTestEnable && + lds.depthWriteEnable == rds.depthWriteEnable && + lds.depthCompareOp == rds.depthCompareOp && + lds.stencilTestEnable == rds.stencilTestEnable && + lds.front == rds.front && + lds.back == rds.back; + }, + [](const auto* lhs, const auto* rhs) -> bool // rasterizationState + { + const auto& lrs = *lhs->rasterizationState; + const auto& rrs = *rhs->rasterizationState; + return lrs.cullMode == rrs.cullMode && + lrs.polygonMode == rrs.polygonMode && + lrs.frontFace == rrs.frontFace; + }, + [](const auto* lhs, const auto* rhs) -> bool // vertexInputState + { + const auto& lvi = *lhs->vertexInputState; + const auto& rvi = *rhs->vertexInputState; + return lvi.bufferBindings.size() == rvi.bufferBindings.size() && + lvi.attributes.size() == rvi.attributes.size() && + std::equal(lvi.bufferBindings.begin(), lvi.bufferBindings.end(), rvi.bufferBindings.begin(), [](const auto& lhs, const auto& rhs) { + return operator==(lhs, rhs); + }) && + std::equal(lvi.attributes.begin(), lvi.attributes.end(), rvi.attributes.begin(), [](const auto& lhs, const auto& rhs) { + return operator==(lhs, rhs); + }); + }, + [](const auto* lhs, const auto* rhs) -> bool // inputAssemblyState + { + const auto& lia = *lhs->inputAssemblyState; + const auto& ria = *rhs->inputAssemblyState; + return lia.topology == ria.topology && + lia.primitiveRestartEnable == ria.primitiveRestartEnable; + }, + }; +} + +/** + * @brief Helper function calculating the bitmask of set states + * + * @param[in] info Valid PipelineCreateInfo structure + * @return bitmask of set states + */ +inline uint32_t GetStateBitmask(const PipelineCreateInfo& info) +{ + uint32_t mask{0u}; + mask |= bool(info.colorBlendState) << int(StateLookupIndex::COLOR_BLEND_STATE_BIT); + mask |= bool(info.viewportState) << int(StateLookupIndex::VIEWPORT_STATE_BIT); + mask |= bool(info.framebufferState) << int(StateLookupIndex::FRAMEBUFFER_STATE_BIT); + mask |= bool(info.basePipeline) << int(StateLookupIndex::BASE_PIPELINE_STATE_BIT); + mask |= bool(info.depthStencilState) << int(StateLookupIndex::DEPTH_STENCIL_STATE_BIT); + mask |= bool(info.rasterizationState) << int(StateLookupIndex::RASTERIZATION_STATE_BIT); + mask |= bool(info.vertexInputState) << int(StateLookupIndex::VERTEX_INPUT_STATE_BIT); + mask |= bool(info.inputAssemblyState) << int(StateLookupIndex::INPUT_ASSEMBLY_STATE_BIT); + return mask; +} + +/** + * @brief Implementation of cache */ struct PipelineCache::Impl { + /** + * @brief Constructor + */ explicit Impl(EglGraphicsController& _controller) : controller(_controller) { + // Initialise lookup table + InitialiseStateCompareLookupTable(); } + /** + * @brief destructor + */ ~Impl() = default; - EglGraphicsController& controller; + /** + * @brief Structure describes a single cache entry + */ + struct CacheEntry + { + CacheEntry() = default; + + CacheEntry(UniquePtr&& _pipeline, uint32_t _bitmask) + : pipeline(std::move(_pipeline)), + stateBitmask(_bitmask) + { + } + + ~CacheEntry() = default; + + CacheEntry(CacheEntry&&) = default; + CacheEntry& operator=(CacheEntry&&) = default; + + UniquePtr pipeline{nullptr}; + uint32_t stateBitmask{0u}; + }; - std::vector> mPipelines; + EglGraphicsController& controller; + std::vector entries; + + /** + * @brief Sorted array of shaders used to create program + */ + struct ProgramCacheEntry + { + // sorted array of shaders + std::vector shaders; + UniquePtr program{nullptr}; + }; + + std::vector programEntries; }; PipelineCache::PipelineCache(EglGraphicsController& controller) @@ -49,108 +287,180 @@ PipelineCache::~PipelineCache() = default; PipelineImpl* PipelineCache::FindPipelineImpl(const PipelineCreateInfo& info) { - // hashing by shaders and then states, shaders should use the same pointers - for(auto& pipeline : mImpl->mPipelines) + auto bitmask = GetStateBitmask(info); + + for(auto& entry : mImpl->entries) { + auto& pipeline = entry.pipeline; auto& cacheInfo = pipeline->GetCreateInfo(); - - if(!info.shaderState) + if(!info.programState) { continue; } - // TODO: Hash the structures. In GLES the order should not matter - // (it matters now to keep it simple) - if(info.shaderState->size() == cacheInfo.shaderState->size()) + // Check whether the program is the same + if(info.programState->program) { - if(memcmp(info.shaderState->data(), cacheInfo.shaderState->data(), sizeof(info.shaderState->size() * sizeof(ShaderState))) != 0) + const auto& lhsProgram = *static_cast(info.programState->program); + const auto& rhsProgram = *static_cast(cacheInfo.programState->program); + if(lhsProgram != rhsProgram) { - continue; // early exit + continue; } - // test null states - // TODO: create and store such bitmask when pipeline - // is being constructed! - uint32_t infoBits = - (info.inputAssemblyState ? 1 << 0 : 0) | - (info.vertexInputState ? 1 << 1 : 0) | - (info.viewportState ? 1 << 2 : 0) | - (info.depthStencilState ? 1 << 3 : 0) | - (info.colorBlendState ? 1 << 4 : 0) | - (info.framebufferState ? 1 << 5 : 0) | - (info.rasterizationState ? 1 << 6 : 0) | - (info.basePipeline ? 1 << 7 : 0); - - uint32_t cacheBits = - (cacheInfo.inputAssemblyState ? 1 << 0 : 0) | - (cacheInfo.vertexInputState ? 1 << 1 : 0) | - (cacheInfo.viewportState ? 1 << 2 : 0) | - (cacheInfo.depthStencilState ? 1 << 3 : 0) | - (cacheInfo.colorBlendState ? 1 << 4 : 0) | - (cacheInfo.framebufferState ? 1 << 5 : 0) | - (cacheInfo.rasterizationState ? 1 << 6 : 0) | - (cacheInfo.basePipeline ? 1 << 7 : 0); - - if(cacheBits != infoBits) + // Test whether set states bitmask matches + if(entry.stateBitmask != bitmask) { - continue; // early exit + continue; } - // Now compare states - // TODO: hash the binary content on pipeline creation - // TODO: optimize by adding a lookup table storing size - // of each field and generalizing the type (void*) - - auto updateResult = [](const auto& lhs, const auto& rhs) { - if(!rhs) return 0; - return memcmp(lhs, rhs, sizeof(decltype(*rhs))); - }; - - auto result = 0u; - result |= updateResult(info.vertexInputState, cacheInfo.vertexInputState); - result |= updateResult(info.inputAssemblyState, cacheInfo.inputAssemblyState); - result |= updateResult(info.rasterizationState, cacheInfo.rasterizationState); - result |= updateResult(info.framebufferState, cacheInfo.framebufferState); - result |= updateResult(info.colorBlendState, cacheInfo.colorBlendState); - result |= updateResult(info.depthStencilState, cacheInfo.depthStencilState); - result |= updateResult(info.viewportState, cacheInfo.viewportState); - - // early exit - if(!result) + // Now test only for states that are set + auto i = 0; + for(i = 0; i < int(StateLookupIndex::MAX_STATE); ++i) { - continue; + // Test only set states + if((entry.stateBitmask & (1 << i))) + { + if(!STATE_COMPARE_FUNC_TABLE[i](&info, &cacheInfo)) + { + break; + } + } } - // For now ignoring dynamic state mask and allocator - + // TODO: For now ignoring dynamic state mask and allocator // Getting as far as here, we have found our pipeline impl - return pipeline.get(); + if(i == int(StateLookupIndex::MAX_STATE)) + { + return pipeline.get(); + } + } + } + return nullptr; +} + +ProgramImpl* PipelineCache::FindProgramImpl(const ProgramCreateInfo& info) +{ + if(mImpl->programEntries.empty()) + { + return nullptr; + } + + // assert if no shaders given + std::vector shaders; + shaders.reserve(info.shaderState->size()); + + for(auto& state : *info.shaderState) + { + shaders.push_back(state.shader); + } + + // sort + std::sort(shaders.begin(), shaders.end()); + + for(auto& item : mImpl->programEntries) + { + if(item.shaders.size() != shaders.size()) + { + continue; + } + + int k = shaders.size(); + while(--k >= 0 && item.shaders[k] == shaders[k]) + ; + + if(k < 0) + { + return item.program.get(); } } return nullptr; } -Graphics::UniquePtr PipelineCache::GetPipeline(const PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr&& oldPipeline) +Graphics::UniquePtr PipelineCache::GetPipeline(const PipelineCreateInfo& pipelineCreateInfo, + Graphics::UniquePtr&& oldPipeline) { - // create or get from cache auto cachedPipeline = FindPipelineImpl(pipelineCreateInfo); + // Return same pointer if nothing changed + if(oldPipeline && *static_cast(oldPipeline.get()) == cachedPipeline) + { + return std::move(oldPipeline); + } + if(!cachedPipeline) { // create new pipeline - auto pipeline = MakeUnique(pipelineCreateInfo, mImpl->controller); + auto pipeline = MakeUnique(pipelineCreateInfo, mImpl->controller, *this); cachedPipeline = pipeline.get(); // add it to cache - mImpl->mPipelines.emplace_back(std::move(pipeline)); + mImpl->entries.emplace_back(std::move(pipeline), GetStateBitmask(pipelineCreateInfo)); } - else + + auto wrapper = MakeUnique>(*cachedPipeline); + return std::move(wrapper); +} + +Graphics::UniquePtr PipelineCache::GetProgram(const ProgramCreateInfo& programCreateInfo, + Graphics::UniquePtr&& oldProgram) +{ + ProgramImpl* cachedProgram = FindProgramImpl(programCreateInfo); + + // Return same pointer if nothing changed + if(oldProgram && *static_cast(oldProgram.get()) == cachedProgram) { + return std::move(oldProgram); } - // create new pipeline wrapper n - auto wrapper = MakeUnique(*cachedPipeline); + + if(!cachedProgram) + { + // create new pipeline + auto program = MakeUnique(programCreateInfo, mImpl->controller); + + program->Create(); + + cachedProgram = program.get(); + + // add it to cache + mImpl->programEntries.emplace_back(); + auto& item = mImpl->programEntries.back(); + item.program = std::move(program); + for(auto& state : *programCreateInfo.shaderState) + { + item.shaders.push_back(state.shader); + } + + std::sort(item.shaders.begin(), item.shaders.end()); + } + + auto wrapper = MakeUnique>(cachedProgram); return std::move(wrapper); } +void PipelineCache::FlushCache() +{ + decltype(mImpl->entries) newEntries; + newEntries.reserve(mImpl->entries.size()); + + for(auto& entry : mImpl->entries) + { + // Move items which are still in use into the new array + if(entry.pipeline->GetRefCount() != 0) + { + newEntries.emplace_back(std::move(entry)); + } + } + + // Move temporary array in place of stored cache + // Unused pipelines will be deleted automatically + mImpl->entries = std::move(newEntries); + + // TODO: program cache may require similar action. However, + // since there is always one wrapper for Program object + // kept in the pipeline, then death of pipeline will result + // killing the program (if program isn't in use anymore) +} + } // namespace Dali::Graphics::GLES \ No newline at end of file diff --git a/dali/internal/graphics/gles-impl/gles-graphics-pipeline-cache.h b/dali/internal/graphics/gles-impl/gles-graphics-pipeline-cache.h index f93e079..9c1a16b 100644 --- a/dali/internal/graphics/gles-impl/gles-graphics-pipeline-cache.h +++ b/dali/internal/graphics/gles-impl/gles-graphics-pipeline-cache.h @@ -21,6 +21,8 @@ // EXTERNAL INCLUDES #include #include +#include +#include // INTERNAL INCLUDES #include "gles-graphics-resource.h" @@ -32,7 +34,8 @@ namespace GLES { class Pipeline; class PipelineImpl; - +class Program; +class ProgramImpl; /** * @brief PipelineCache manages pipeline and program * objects so there are no duplicates created. @@ -62,6 +65,26 @@ public: */ Graphics::UniquePtr GetPipeline(const PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr&& oldPipeline); + /** + * @brief Retrieves program matching the spec + * + * Function returns either existing program if one is found + * in the cache or creates new one. + * + * @param[in] programCreateInfo Valid ProgramCreateInfo structure + * @param[in] oldProgram previous program object + * @return Program object + */ + Graphics::UniquePtr GetProgram(const ProgramCreateInfo& pipelineCreateInfo, Graphics::UniquePtr&& oldProgram); + + /** + * @brief Flushes pipeline and program cache + * + * Removes cached items when they are no longer needed. This function + * should be called at the very end of Controller render loop iteration. + */ + void FlushCache(); + private: /** * @brief Finds pipeline implementation based on the spec @@ -70,6 +93,13 @@ private: */ PipelineImpl* FindPipelineImpl(const PipelineCreateInfo& info); + /** + * @brief Finds program implementation based on the spec + * @param[in] info Valid create info structure + * @return Returns pointer to program or nullptr + */ + ProgramImpl* FindProgramImpl(const ProgramCreateInfo& info); + private: struct Impl; std::unique_ptr mImpl; diff --git a/dali/internal/graphics/gles-impl/gles-graphics-pipeline.cpp b/dali/internal/graphics/gles-impl/gles-graphics-pipeline.cpp index dbebefb..8cc9491 100644 --- a/dali/internal/graphics/gles-impl/gles-graphics-pipeline.cpp +++ b/dali/internal/graphics/gles-impl/gles-graphics-pipeline.cpp @@ -19,21 +19,13 @@ #include "gles-graphics-pipeline.h" // EXTERNAL INCLUDES -#include #include #include // INTERNAL INCLUDES #include "egl-graphics-controller.h" -#include "gles-graphics-shader.h" - -namespace -{ -struct LegacyProgram : Dali::Graphics::ExtensionCreateInfo -{ - uint32_t programId; -}; -} // namespace +#include "gles-graphics-pipeline-cache.h" +#include "gles-graphics-program.h" namespace Dali::Graphics::GLES { @@ -44,19 +36,25 @@ struct PipelineImpl::PipelineState { PipelineState() = default; ~PipelineState() = default; - ColorBlendState colorBlendState; - DepthStencilState depthStencilState; - std::vector shaderState; - ViewportState viewportState; - FramebufferState framebufferState; - RasterizationState rasterizationState; - VertexInputState vertexInputState; - InputAssemblyState inputAssemblyState; + + // for maintaining correct lifecycle, the owned program + // wrapper must be created + UniquePtr program; + + ColorBlendState colorBlendState; + DepthStencilState depthStencilState; + ProgramState programState; + ViewportState viewportState; + FramebufferState framebufferState; + RasterizationState rasterizationState; + VertexInputState vertexInputState; + InputAssemblyState inputAssemblyState; + + PipelineCache* pipelineCache{}; }; -PipelineImpl::PipelineImpl(const Graphics::PipelineCreateInfo& createInfo, Graphics::EglGraphicsController& controller) -: mController(controller), - mReflection(controller) +PipelineImpl::PipelineImpl(const Graphics::PipelineCreateInfo& createInfo, Graphics::EglGraphicsController& controller, PipelineCache& pipelineCache) +: mController(controller) { // the creation is deferred so it's needed to copy certain parts of the CreateInfo structure mPipelineState = std::make_unique(); @@ -66,31 +64,22 @@ PipelineImpl::PipelineImpl(const Graphics::PipelineCreateInfo& createInfo, Graph CopyStateIfSet(createInfo.inputAssemblyState, mPipelineState->inputAssemblyState, &mCreateInfo.inputAssemblyState); CopyStateIfSet(createInfo.vertexInputState, mPipelineState->vertexInputState, &mCreateInfo.vertexInputState); CopyStateIfSet(createInfo.rasterizationState, mPipelineState->rasterizationState, &mCreateInfo.rasterizationState); + CopyStateIfSet(createInfo.programState, mPipelineState->programState, &mCreateInfo.programState); CopyStateIfSet(createInfo.framebufferState, mPipelineState->framebufferState, &mCreateInfo.framebufferState); CopyStateIfSet(createInfo.colorBlendState, mPipelineState->colorBlendState, &mCreateInfo.colorBlendState); CopyStateIfSet(createInfo.depthStencilState, mPipelineState->depthStencilState, &mCreateInfo.depthStencilState); - CopyStateIfSet(createInfo.shaderState, mPipelineState->shaderState, &mCreateInfo.shaderState); + CopyStateIfSet(createInfo.programState, mPipelineState->programState, &mCreateInfo.programState); CopyStateIfSet(createInfo.viewportState, mPipelineState->viewportState, &mCreateInfo.viewportState); - if(createInfo.nextExtension) - { - LegacyProgram* legacyProgram = static_cast(createInfo.nextExtension); - mGlProgram = legacyProgram->programId; - mReflection.SetGlProgram(mGlProgram); - printf("GLES::Pipeline: mProgramId: %u\n", mGlProgram); - } + // This program doesn't need custom deleter + auto programImpl = static_cast(createInfo.programState->program)->GetImplementation(); + mPipelineState->program = MakeUnique(programImpl); - const std::vector* shaderStates = mCreateInfo.shaderState; - if(shaderStates) - { - printf("GLES::Pipeline: shaderStates %p, shaderStates size: %lu\n", shaderStates, shaderStates->size()); + // To make sure the program is alive as long as the pipeline is! + mCreateInfo.programState->program = mPipelineState->program.get(); - std::for_each(shaderStates->begin(), shaderStates->end(), [](Graphics::ShaderState shaderState) { - const Graphics::Shader* shader = shaderState.shader; - Graphics::PipelineStage pipelineStage = shaderState.pipelineStage; - printf("GLES::Pipeline: shader: %p, pipelineStage: %d\n", shader, static_cast(pipelineStage)); - }); - } + // Set pipeline cache + mPipelineState->pipelineCache = &pipelineCache; } const PipelineCreateInfo& PipelineImpl::GetCreateInfo() const @@ -103,92 +92,11 @@ auto& PipelineImpl::GetController() const return mController; } -bool PipelineImpl::InitializeResource() -{ - auto& gl = *GetController().GetGL(); - // mGlProgram = gl.CreateProgram(); - - for(auto& shader : mPipelineState->shaderState) - { - // TODO: Compile shader (shouldn't compile if already did so) - const auto glesShader = static_cast(shader.shader); - if(glesShader->Compile()) - { - // Attach shader - gl.AttachShader(mGlProgram, glesShader->GetGLShader()); - } - else - { - // failure - gl.DeleteProgram(mGlProgram); - return false; - } - } - - // Link program - gl.LinkProgram(mGlProgram); - - // Check for errors - // TODO: - - return true; -} - -void PipelineImpl::DestroyResource() -{ - if(mGlProgram) - { - auto& gl = *GetController().GetGL(); - gl.DeleteProgram(mGlProgram); - } -} - -void PipelineImpl::DiscardResource() -{ - // Pass program to discard queue -} - -uint32_t PipelineImpl::GetGLProgram() const -{ - return mGlProgram; -} - -// FIXME: THIS FUNCTION IS NOT IN USE YET, REQUIRES PROPER PIPELINE void PipelineImpl::Bind(GLES::PipelineImpl* prevPipeline) { - // Same pipeline to bind, nothing to do - if(prevPipeline == this) - { - return; - } - - auto& gl = *GetController().GetGL(); - - // ------------------ VIEWPORT - - const auto& viewportState = mPipelineState->viewportState; - auto setViewportState = [this, &gl, viewportState]() { - if(viewportState.scissorTestEnable) - { - gl.Enable(GL_SCISSOR_TEST); - const auto& scissor = mPipelineState->viewportState.scissor; - gl.Scissor(scissor.x, scissor.y, scissor.width, scissor.height); - } - else - { - gl.Disable(GL_SCISSOR_TEST); - const auto& scissor = mPipelineState->viewportState.scissor; - gl.Scissor(scissor.x, scissor.y, scissor.width, scissor.height); - } - }; - - // Resolve viewport/scissor state change - ExecuteStateChange(setViewportState, prevPipeline->GetCreateInfo().viewportState, &mPipelineState->viewportState); - - // ---------------------- PROGRAM - auto program = mGlProgram; - - gl.UseProgram(program); + auto& gl = *GetController().GetGL(); + auto glProgram = static_cast(GetCreateInfo().programState->program)->GetImplementation()->GetGlProgram(); + gl.UseProgram(glProgram); } void PipelineImpl::Retain() @@ -220,4 +128,19 @@ EglGraphicsController& Pipeline::GetController() const return mPipeline.GetController(); } +Pipeline::~Pipeline() +{ + // decrease refcount + if(mPipeline.GetRefCount()) + { + mPipeline.Release(); + } +} + +void Pipeline::DiscardResource() +{ + // Send pipeline to discard queue if refcount is 0 + GetController().DiscardResource(this); +} + } // namespace Dali::Graphics::GLES diff --git a/dali/internal/graphics/gles-impl/gles-graphics-pipeline.h b/dali/internal/graphics/gles-impl/gles-graphics-pipeline.h index e8b734f..fca74fa 100644 --- a/dali/internal/graphics/gles-impl/gles-graphics-pipeline.h +++ b/dali/internal/graphics/gles-impl/gles-graphics-pipeline.h @@ -29,11 +29,15 @@ namespace Dali::Graphics::GLES { -using PipelineResource = Resource; +class PipelineCache; /** - * @brief PipelineWrapper is the object - * returned to the client-side + * @brief PipelineImpl is the implementation of Pipeline + * + * PipelineImpl is owned by the pipeline cache. The client-side + * will receive Graphics::Pipeline objects which are only + * wrappers for this implementation. The lifecycle of + * PipelineImpl is managed by the PipelineCache. */ class PipelineImpl { @@ -42,8 +46,9 @@ public: * @brief Constructor * @param[in] createInfo valid TextureCreateInfo structure * @param[in] controller Reference to the Controller + * @param[in] pipelineCache Reference to valid pipeline cache */ - PipelineImpl(const Graphics::PipelineCreateInfo& createInfo, Graphics::EglGraphicsController& controller); + PipelineImpl(const Graphics::PipelineCreateInfo& createInfo, Graphics::EglGraphicsController& controller, PipelineCache& pipelineCache); /** * @brief Destructor @@ -51,29 +56,6 @@ public: ~PipelineImpl(); /** - * @brief Destroys all the low-level resources used by the class - */ - void DestroyResource(); - - /** - * @brief Initializes low-level resources - * - * @return Tron success - */ - bool InitializeResource(); - - /** - * @brief Discards object - */ - void DiscardResource(); - - /** - * @brief returns GL program id - * @return GL program id - */ - [[nodiscard]] uint32_t GetGLProgram() const; - - /** * @brief Binds pipeline * * Binds Pipeline by binding GL program and flushing state. @@ -86,37 +68,35 @@ public: void Bind(GLES::PipelineImpl* prevPipeline); /** - * Executes state change function if condition met + * @brief Increases ref count */ - template - void ExecuteStateChange(FUNC& func, const STATE* prevPipelineState, const STATE* thisPipelineState) - { - if(!prevPipelineState) - { - func(); - } - else - { - // binary test and execute when different - if(memcmp(prevPipelineState, thisPipelineState, sizeof(STATE)) != 0) - { - func(); - } - } - } - void Retain(); + /** + * @brief Decreases ref count + */ void Release(); + /** + * @brief Retrieves ref count + * @return Refcount value + */ [[nodiscard]] uint32_t GetRefCount() const; + /** + * @brief Returns PipelineCreateInfo structure + * + * @return PipelineCreateInfo structure + */ [[nodiscard]] const PipelineCreateInfo& GetCreateInfo() const; + /** + * @brief Returns controller + * + * @return Reference to the Controller + */ [[nodiscard]] auto& GetController() const; - Graphics::GLES::Reflection& GetReflection(); - private: /** * @brief Helper function. Copies state if pointer is set @@ -146,30 +126,29 @@ private: } } - // Pipeline state is stored as a copy of create info - // data. + // Pipeline state is store locally so any assigned pointers on a + // client-side may go safely out of scope. struct PipelineState; std::unique_ptr mPipelineState; EglGraphicsController& mController; PipelineCreateInfo mCreateInfo; - Graphics::GLES::Reflection mReflection; - - uint32_t mGlProgram{0u}; - uint32_t mRefCount{0u}; }; /** - * @brief Pipeline class wraps a unique pipeline object - * + * @brief Pipeline class wraps the PipelineImpl */ class Pipeline : public Graphics::Pipeline { public: Pipeline() = delete; + /** + * @brief Constructor + * @param pipeline Pipeline implementation + */ explicit Pipeline(GLES::PipelineImpl& pipeline) : mPipeline(pipeline) { @@ -177,21 +156,57 @@ public: mPipeline.Retain(); } - ~Pipeline() override - { - // decrease refcount - mPipeline.Release(); - } + /** + * @brief Destructor + */ + ~Pipeline() override; + /** + * @brief Returns pipeline implementation + * + * @return Valid pipeline implementation + */ [[nodiscard]] auto& GetPipeline() const { return mPipeline; } + /** + * @brief Returns create info structure + * + * @return Valid create info structure + */ [[nodiscard]] const PipelineCreateInfo& GetCreateInfo() const; + /** + * @brief Returns controller + * + * @return reference to Controller + */ [[nodiscard]] EglGraphicsController& GetController() const; + bool operator==(const PipelineImpl* impl) const + { + return &mPipeline == impl; + } + + /** + * @brief Run by UniquePtr to discard resource + */ + void DiscardResource(); + + /** + * @brief Destroy resource + * + * Despite this class doesn't inherit Resource it must provide + * (so it won't duplicate same data) same set of functions + * so it can work with resource management functions of Controller. + */ + void DestroyResource() + { + // Nothing to do here + } + private: GLES::PipelineImpl& mPipeline; }; diff --git a/dali/internal/graphics/gles-impl/gles-graphics-program.cpp b/dali/internal/graphics/gles-impl/gles-graphics-program.cpp new file mode 100644 index 0000000..2e28eca --- /dev/null +++ b/dali/internal/graphics/gles-impl/gles-graphics-program.cpp @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2021 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 "gles-graphics-program.h" + +// INTERNAL HEADERS +#include "egl-graphics-controller.h" +#include "gles-graphics-reflection.h" +#include "gles-graphics-shader.h" + +// EXTERNAL HEADERS +#include +#include + +namespace Dali::Graphics::GLES +{ +struct ProgramImpl::Impl +{ + explicit Impl(EglGraphicsController& _controller, const ProgramCreateInfo& info) + : controller(_controller) + { + createInfo = info; + if(info.shaderState) + { + createInfo.shaderState = new std::vector(*info.shaderState); + } + } + + ~Impl() + { + delete createInfo.shaderState; + } + + EglGraphicsController& controller; + ProgramCreateInfo createInfo; + uint32_t glProgram{}; + uint32_t refCount{0u}; + + std::unique_ptr reflection{nullptr}; +}; + +ProgramImpl::ProgramImpl(const Graphics::ProgramCreateInfo& createInfo, Graphics::EglGraphicsController& controller) +{ + // Create implementation + mImpl = std::make_unique(controller, createInfo); + + // Build reflection + mImpl->reflection = std::make_unique(*this, controller); +} + +ProgramImpl::~ProgramImpl() = default; + +bool ProgramImpl::Destroy() +{ + if(mImpl->glProgram) + { + auto& gl = *mImpl->controller.GetGL(); + gl.DeleteProgram(mImpl->glProgram); + return true; + } + return false; +} + +bool ProgramImpl::Create() +{ + // Create and link new program + auto& gl = *mImpl->controller.GetGL(); + auto program = gl.CreateProgram(); + + const auto& info = mImpl->createInfo; + for(const auto& state : *info.shaderState) + { + const auto* shader = static_cast(state.shader); + + // Compile shader first (ignored when compiled) + shader->Compile(); + + gl.AttachShader(program, shader->GetGLShader()); + } + gl.LinkProgram(program); + + GLint status{0}; + gl.GetProgramiv(program, GL_LINK_STATUS, &status); + if(status != GL_TRUE) + { + char output[4096]; + GLsizei size{0u}; + gl.GetProgramInfoLog(program, 4096, &size, output); + + // log on error + // TODO: un-printf-it + printf("Log: %s\n", output); + gl.DeleteProgram(program); + return false; + } + + mImpl->glProgram = program; + + // Initialize reflection + mImpl->reflection->BuildUniformReflection(); + mImpl->reflection->BuildVertexAttributeReflection(); + mImpl->reflection->BuildUniformBlockReflection(); + + return true; +} + +uint32_t ProgramImpl::GetGlProgram() const +{ + return mImpl->glProgram; +} + +uint32_t ProgramImpl::Retain() +{ + return ++mImpl->refCount; +} + +uint32_t ProgramImpl::Release() +{ + return --mImpl->refCount; +} + +const Graphics::Reflection& ProgramImpl::GetReflection() const +{ + return *mImpl->reflection; +} + +bool ProgramImpl::GetParameter(uint32_t parameterId, void* out) +{ + if(parameterId == 1) // a magic number to access program id + { + *reinterpret_castglProgram)>(out) = mImpl->glProgram; + return true; + } + return false; +} + +EglGraphicsController& ProgramImpl::GetController() const +{ + return mImpl->controller; +} + +const ProgramCreateInfo& ProgramImpl::GetCreateInfo() const +{ + return mImpl->createInfo; +} + +Program::~Program() +{ + // Destroy GL resources of implementation. This should happen + // only if there's no more pipelines using this program so + // it is safe to do it in the destructor + if(!mProgram->Release()) + { + mProgram->Destroy(); + } +} + +const Graphics::Reflection& Program::GetReflection() const +{ + return mProgram->GetReflection(); +} + +EglGraphicsController& Program::GetController() const +{ + return GetImplementation()->GetController(); +} + +const ProgramCreateInfo& Program::GetCreateInfo() const +{ + return GetImplementation()->GetCreateInfo(); +} + +void Program::DiscardResource() +{ + GetController().DiscardResource(this); +} + +}; // namespace Dali::Graphics::GLES diff --git a/dali/internal/graphics/gles-impl/gles-graphics-program.h b/dali/internal/graphics/gles-impl/gles-graphics-program.h new file mode 100644 index 0000000..a080012 --- /dev/null +++ b/dali/internal/graphics/gles-impl/gles-graphics-program.h @@ -0,0 +1,225 @@ +#ifndef DALI_GRAPHICS_GLES_PROGRAM_H +#define DALI_GRAPHICS_GLES_PROGRAM_H + +/* + * Copyright (c) 2021 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. + */ + +// EXTERNAL INCLUDES +#include +#include + +// INTERNAL INCLUDES +#include "gles-graphics-resource.h" + +namespace Dali::Graphics +{ +class Reflection; +namespace GLES +{ +/** + * @brief Program implementation + * + * Program implementation is owned only by the PipelineCache + * + * Like pipeline, it's created and managed by the PipelineCache + */ +class ProgramImpl +{ +public: + /** + * @brief Constructor + * + * @param[in] createInfo Valid create info structure + * @param[in] controller Valid reference to the controller object + */ + ProgramImpl(const Graphics::ProgramCreateInfo& createInfo, Graphics::EglGraphicsController& controller); + + /** + * @brief Destructor + */ + ~ProgramImpl(); + + /** + * @brief Destroys GL resources associated with the Program + * + * @return True on success + */ + bool Destroy(); + + /** + * @brief Creates GL resource for this Program + * + * @return True on success + */ + bool Create(); + + /** + * @brief Returns GL program id + * + * @return GL program id + */ + [[nodiscard]] uint32_t GetGlProgram() const; + + /** + * @brief Increases ref count + * + * @return new refcount + */ + uint32_t Retain(); + + /** + * @brief Decreases ref count + * + * @return New refcount + */ + uint32_t Release(); + + /** + * @brief Returns reflection + * + * @return Valid reflection associated with the Program + */ + [[nodiscard]] const Graphics::Reflection& GetReflection() const; + + /** + * @brief Returns controller + * + * @return Valid Controller object + */ + [[nodiscard]] EglGraphicsController& GetController() const; + + /** + * @brief Returns create info structure + * + * @return Reference to valid create info structure + */ + [[nodiscard]] const ProgramCreateInfo& GetCreateInfo() const; + + /** + * @brief Returns parameter value specified by parameterId + * + * This function can be used as a backdoor into the implementation + * used to retrieve internal data. + * + * @param[in] parameterId Integer parameter id + * @param[out] out Pointer to write to + * + * @return True on success + */ + bool GetParameter(uint32_t parameterId, void* out); + +private: + friend class Program; + + struct Impl; + std::unique_ptr mImpl; +}; + +/////////////////////////////////////////////////////////////// + +/** + * @brief Wrapper for the pipeline implementation + * + * This object is returned back to the client-side + */ +class Program : public Graphics::Program +{ +public: + /** + * @brief Constructor + * + * @param[in] impl Pointer to valid implementation + */ + explicit Program(ProgramImpl* impl) + : mProgram(impl) + { + mProgram->Retain(); + } + + /** + * @brief Destructor + */ + ~Program() override; + + /** + * @brief Returns reference to the Reflection object + + * @return Reflection + */ + [[nodiscard]] const Graphics::Reflection& GetReflection() const; + + /** + * @brief Retrieves internal program implementation + * + * @return Valid pointer to the ProgramImpl object + */ + [[nodiscard]] ProgramImpl* GetImplementation() const + { + return mProgram; + } + + /** + * @brief Returns controller + * + * @return controller + */ + [[nodiscard]] EglGraphicsController& GetController() const; + + /** + * @brief Returns create info structure + * + * @return create info structure + */ + [[nodiscard]] const ProgramCreateInfo& GetCreateInfo() const; + + bool operator==(const GLES::Program& program) const + { + return (program.mProgram == mProgram); + } + + bool operator==(const GLES::ProgramImpl* programImpl) const + { + return (programImpl == mProgram); + } + + bool operator!=(const GLES::Program& program) const + { + return (program.mProgram != mProgram); + } + + /** + * @brief Run by UniquePtr to discard resource + */ + void DiscardResource(); + + /** + * @brief Destroying GL resources + * + * This function is kept for compatibility with Resource<> class + * so can the object can be use with templated functions. + */ + void DestroyResource() + { + // nothing to do here + } + +private: + ProgramImpl* mProgram{nullptr}; +}; +} // namespace GLES +} // namespace Dali::Graphics + +#endif //DALI_GRAPHICS_PROGRAM_H diff --git a/dali/internal/graphics/gles-impl/gles-graphics-reflection.cpp b/dali/internal/graphics/gles-impl/gles-graphics-reflection.cpp index 4450557..2668ba2 100644 --- a/dali/internal/graphics/gles-impl/gles-graphics-reflection.cpp +++ b/dali/internal/graphics/gles-impl/gles-graphics-reflection.cpp @@ -25,6 +25,8 @@ #include #include +#include "gles-graphics-program.h" + #include namespace @@ -48,7 +50,7 @@ Dali::Graphics::VertexInputAttributeFormat GetVertexAttributeTypeFormat(GLenum t } } -int GetGLDataTypeSize(GLenum type) +uint32_t GetGLDataTypeSize(GLenum type) { // There are many more types than what are covered here, but // they are not supported in dali. @@ -87,33 +89,29 @@ bool SortByLocation(Dali::Graphics::UniformInfo a, Dali::Graphics::UniformInfo b } // namespace -namespace Dali -{ -namespace Graphics -{ -namespace GLES +namespace Dali::Graphics::GLES { -Reflection::Reflection(Graphics::EglGraphicsController& controller) +Reflection::Reflection(GLES::ProgramImpl& program, Graphics::EglGraphicsController& controller) : Graphics::Reflection(), mController(controller), - mGlProgram(0u) + mProgram(program) { } -Reflection::~Reflection() -{ -} +Reflection::~Reflection() = default; void Reflection::BuildVertexAttributeReflection() { + auto glProgram = mProgram.GetGlProgram(); + int written, size, location, maxLength, nAttribs; GLenum type; char* name; auto gl = mController.GetGL(); - gl->GetProgramiv(mGlProgram, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxLength); - gl->GetProgramiv(mGlProgram, GL_ACTIVE_ATTRIBUTES, &nAttribs); + gl->GetProgramiv(glProgram, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxLength); + gl->GetProgramiv(glProgram, GL_ACTIVE_ATTRIBUTES, &nAttribs); mVertexInputAttributes.clear(); mVertexInputAttributes.resize(nAttribs); @@ -121,8 +119,8 @@ void Reflection::BuildVertexAttributeReflection() name = new GLchar[maxLength]; for(int i = 0; i < nAttribs; i++) { - gl->GetActiveAttrib(mGlProgram, i, maxLength, &written, &size, &type, name); - location = gl->GetAttribLocation(mGlProgram, name); + gl->GetActiveAttrib(glProgram, i, maxLength, &written, &size, &type, name); + location = gl->GetAttribLocation(glProgram, name); AttributeInfo attributeInfo; attributeInfo.location = location; @@ -136,6 +134,8 @@ void Reflection::BuildVertexAttributeReflection() void Reflection::BuildUniformReflection() { + auto glProgram = mProgram.GetGlProgram(); + int maxLen; char* name; @@ -143,8 +143,8 @@ void Reflection::BuildUniformReflection() auto gl = mController.GetGL(); - gl->GetProgramiv(mGlProgram, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLen); - gl->GetProgramiv(mGlProgram, GL_ACTIVE_UNIFORMS, &numUniforms); + gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLen); + gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORMS, &numUniforms); mUniformBlocks.clear(); mDefaultUniformBlock.members.clear(); @@ -152,20 +152,19 @@ void Reflection::BuildUniformReflection() name = new char[maxLen]; - int maxUniformLocations; - gl->GetProgramiv(mGlProgram, GL_MAX_UNIFORM_LOCATIONS, &maxUniformLocations); + using UniformLocationSizePair = std::pair; + std::vector uniformSizes; - std::vector uniformSize; - uniformSize.reserve(maxUniformLocations); + uniformSizes.reserve(numUniforms); for(int i = 0; i < numUniforms; ++i) { int size; GLenum type; int written; - gl->GetActiveUniform(mGlProgram, i, maxLen, &written, &size, &type, name); - int location = gl->GetUniformLocation(mGlProgram, name); - uniformSize[location] = GetGLDataTypeSize(type); + gl->GetActiveUniform(glProgram, i, maxLen, &written, &size, &type, name); + int location = gl->GetUniformLocation(glProgram, name); + uniformSizes.push_back(std::make_pair(location, GetGLDataTypeSize(type))); Dali::Graphics::UniformInfo uniformInfo; uniformInfo.name = name; @@ -198,10 +197,21 @@ void Reflection::BuildUniformReflection() // Calculate the uniform offset for(unsigned int i = 0; i < mDefaultUniformBlock.members.size(); ++i) { - mDefaultUniformBlock.members[i].offset = i == 0 ? 0 : mDefaultUniformBlock.members[i - 1].offset + uniformSize[mDefaultUniformBlock.members[i - 1].location]; + if(i == 0) + { + mDefaultUniformBlock.members[i].offset = 0; + } + else + { + uint32_t previousUniformLocation = mDefaultUniformBlock.members[i - 1].location; + auto previousUniform = std::find_if(uniformSizes.begin(), uniformSizes.end(), [&previousUniformLocation](const UniformLocationSizePair& iter) { return iter.first == previousUniformLocation; }); + mDefaultUniformBlock.members[i].offset = mDefaultUniformBlock.members[i - 1].offset + previousUniform->second; + } } - mDefaultUniformBlock.size = mDefaultUniformBlock.members.back().offset + uniformSize[mDefaultUniformBlock.members.back().location]; + uint32_t lastUniformLocation = mDefaultUniformBlock.members.back().location; + auto lastUniform = std::find_if(uniformSizes.begin(), uniformSizes.end(), [&lastUniformLocation](const UniformLocationSizePair& iter) { return iter.first == lastUniformLocation; }); + mDefaultUniformBlock.size = mDefaultUniformBlock.members.back().offset + lastUniform->second; mUniformBlocks.push_back(mDefaultUniformBlock); @@ -211,16 +221,16 @@ void Reflection::BuildUniformReflection() // TODO: Maybe this is not needed if uniform block is not support by dali shaders? void Reflection::BuildUniformBlockReflection() { - auto gl = mController.GetGL(); - - int numUniformBlocks = 0; - gl->GetProgramiv(mGlProgram, GL_ACTIVE_UNIFORM_BLOCKS, &numUniformBlocks); + auto gl = mController.GetGL(); + auto glProgram = mProgram.GetGlProgram(); + int numUniformBlocks = 0; + gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORM_BLOCKS, &numUniformBlocks); mUniformBlocks.clear(); mUniformBlocks.resize(numUniformBlocks); int uniformBlockMaxLength = 0; - gl->GetProgramiv(mGlProgram, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &uniformBlockMaxLength); + gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &uniformBlockMaxLength); char* uniformBlockName = new char[uniformBlockMaxLength]; for(int i = 0; i < numUniformBlocks; i++) @@ -228,9 +238,9 @@ void Reflection::BuildUniformBlockReflection() int length; int blockBinding; int blockDataSize; - gl->GetActiveUniformBlockName(mGlProgram, i, uniformBlockMaxLength, &length, uniformBlockName); - gl->GetActiveUniformBlockiv(mGlProgram, i, GL_UNIFORM_BLOCK_BINDING, &blockBinding); - gl->GetActiveUniformBlockiv(mGlProgram, i, GL_UNIFORM_BLOCK_DATA_SIZE, &blockDataSize); + gl->GetActiveUniformBlockName(glProgram, i, uniformBlockMaxLength, &length, uniformBlockName); + gl->GetActiveUniformBlockiv(glProgram, i, GL_UNIFORM_BLOCK_BINDING, &blockBinding); + gl->GetActiveUniformBlockiv(glProgram, i, GL_UNIFORM_BLOCK_DATA_SIZE, &blockDataSize); Dali::Graphics::UniformBlockInfo uniformBlockInfo; uniformBlockInfo.name = uniformBlockName; @@ -238,12 +248,12 @@ void Reflection::BuildUniformBlockReflection() uniformBlockInfo.binding = blockBinding; int nUnis; - gl->GetActiveUniformBlockiv(mGlProgram, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &nUnis); + gl->GetActiveUniformBlockiv(glProgram, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &nUnis); int* unifIndexes = new GLint[nUnis]; - gl->GetActiveUniformBlockiv(mGlProgram, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, unifIndexes); + gl->GetActiveUniformBlockiv(glProgram, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, unifIndexes); char* uniformName{}; int maxUniLen; - gl->GetProgramiv(mGlProgram, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniLen); + gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniLen); for(int unif = 0; unif < nUnis; ++unif) { @@ -251,8 +261,8 @@ void Reflection::BuildUniformBlockReflection() int size; GLenum type; - gl->GetActiveUniform(mGlProgram, uniIndex, maxUniLen, &length, &size, &type, uniformName); - int location = gl->GetUniformLocation(mGlProgram, uniformName); + gl->GetActiveUniform(glProgram, uniIndex, maxUniLen, &length, &size, &type, uniformName); + int location = gl->GetUniformLocation(glProgram, uniformName); Dali::Graphics::UniformInfo uniform; uniform.name = uniformName; @@ -472,14 +482,4 @@ Graphics::ShaderLanguage Reflection::GetLanguage() const return Graphics::ShaderLanguage::GLSL_3_2; } -void Reflection::SetGlProgram(uint32_t glProgram) -{ - mGlProgram = glProgram; - - BuildVertexAttributeReflection(); - BuildUniformReflection(); -} - -} // namespace GLES -} // namespace Graphics -} // namespace Dali +} // namespace Dali::Graphics::GLES diff --git a/dali/internal/graphics/gles-impl/gles-graphics-reflection.h b/dali/internal/graphics/gles-impl/gles-graphics-reflection.h index 1e07a01..b06fb24 100644 --- a/dali/internal/graphics/gles-impl/gles-graphics-reflection.h +++ b/dali/internal/graphics/gles-impl/gles-graphics-reflection.h @@ -22,14 +22,13 @@ #include #include -namespace Dali -{ -namespace Graphics +namespace Dali::Graphics { class EglGraphicsController; namespace GLES { +class ProgramImpl; constexpr uint32_t ERROR_ATTRIBUTE_NOT_FOUND(-1u); /** @@ -46,8 +45,9 @@ constexpr uint32_t ERROR_ATTRIBUTE_NOT_FOUND(-1u); class Reflection : public Dali::Graphics::Reflection { public: - Reflection(Graphics::EglGraphicsController& controller); - virtual ~Reflection(); + explicit Reflection(GLES::ProgramImpl& program, Graphics::EglGraphicsController& controller); + + ~Reflection() override; // not copyable Reflection(const Reflection&) = delete; @@ -59,7 +59,7 @@ public: * @param [in] name The name of vertex attribute * @return The index of the vertex attribute in the shader */ - uint32_t GetVertexAttributeLocation(const std::string& name) const; + [[nodiscard]] uint32_t GetVertexAttributeLocation(const std::string& name) const override; /** * @brief Gets the format of a vertex attribute. @@ -67,7 +67,7 @@ public: * @param [in] location The location of vertex attribute * @return The format of a vertex attribute */ - Dali::Graphics::VertexInputAttributeFormat GetVertexAttributeFormat(uint32_t location) const; + [[nodiscard]] Dali::Graphics::VertexInputAttributeFormat GetVertexAttributeFormat(uint32_t location) const override; /** * @brief Gets the name of a vertex attribute. @@ -75,14 +75,14 @@ public: * @param [in] location The location of vertex attribute * @return The name of the vertex attribute */ - std::string GetVertexAttributeName(uint32_t location) const; + [[nodiscard]] std::string GetVertexAttributeName(uint32_t location) const override; /** * @brief Gets the locations of all the vertex attribute in the shader. * * @return A vector of the locations of all the vertex attributes in the shader */ - std::vector GetVertexAttributeLocations() const; + [[nodiscard]] std::vector GetVertexAttributeLocations() const override; // Uniform blocks @@ -91,7 +91,7 @@ public: * * @return The number of uniform blocks */ - uint32_t GetUniformBlockCount() const; + [[nodiscard]] uint32_t GetUniformBlockCount() const override; /** * @brief Gets the binding point to which the uniform block with the given index is binded. @@ -99,7 +99,7 @@ public: * @param [in] index The index of the uniform block * @return The binding point */ - uint32_t GetUniformBlockBinding(uint32_t index) const; + [[nodiscard]] uint32_t GetUniformBlockBinding(uint32_t index) const override; /** * @brief Gets the size of the uniform block with the given index. @@ -107,7 +107,7 @@ public: * @param [in] index The index of the uniform block * @return The size of the uniform block */ - uint32_t GetUniformBlockSize(uint32_t index) const; + [[nodiscard]] uint32_t GetUniformBlockSize(uint32_t index) const override; /** * @brief Retrieves the information of the uniform block with the given index. @@ -118,14 +118,14 @@ public: * @param [out] out A structure that contains the information of the uniform block * @return Whether the uniform block exists or not */ - bool GetUniformBlock(uint32_t index, Dali::Graphics::UniformBlockInfo& out) const; + bool GetUniformBlock(uint32_t index, Dali::Graphics::UniformBlockInfo& out) const override; /** * @brief Gets the binding points of all the uniform blocks in the shader. * * @return A vector of binding points */ - std::vector GetUniformBlockLocations() const; + [[nodiscard]] std::vector GetUniformBlockLocations() const override; /** * @brief Gets the name of uniform block with the given index. @@ -133,7 +133,7 @@ public: * @param [in] blockIndex The index of the uniform block * @return The name of the uniform block */ - std::string GetUniformBlockName(uint32_t blockIndex) const; + [[nodiscard]] std::string GetUniformBlockName(uint32_t blockIndex) const override; /** * @brief Gets the number of uniforms in the uniform block with the given index. @@ -141,7 +141,7 @@ public: * @param [in] blockIndex The index of the uniform block * @return The number of uniforms in the uniform block */ - uint32_t GetUniformBlockMemberCount(uint32_t blockIndex) const; + [[nodiscard]] uint32_t GetUniformBlockMemberCount(uint32_t blockIndex) const override; /** * @brief Gets the name of the uniform in the given location within the uniform block. @@ -150,7 +150,7 @@ public: * @param [in] memberLocation The location of the uniform within the uniform block * @return The name of the uniform */ - std::string GetUniformBlockMemberName(uint32_t blockIndex, uint32_t memberLocation) const; + [[nodiscard]] std::string GetUniformBlockMemberName(uint32_t blockIndex, uint32_t memberLocation) const override; /** * @brief Gets the byte offset of the uniform in the given location within the uniform block. @@ -159,7 +159,7 @@ public: * @param [in] memberLocation The location of the uniform within the uniform block * @return The byte offset of the uniform */ - uint32_t GetUniformBlockMemberOffset(uint32_t blockIndex, uint32_t memberLocation) const; + [[nodiscard]] uint32_t GetUniformBlockMemberOffset(uint32_t blockIndex, uint32_t memberLocation) const override; // Named uniforms @@ -170,7 +170,7 @@ public: * @param [out] out The information of the uniform * @return Whether the uniform exists or not */ - bool GetNamedUniform(const std::string& name, Dali::Graphics::UniformInfo& out) const; + [[nodiscard]] bool GetNamedUniform(const std::string& name, Dali::Graphics::UniformInfo& out) const override; // Sampler @@ -179,7 +179,7 @@ public: * * @return A vector of the sampler uniforms */ - std::vector GetSamplers() const; + [[nodiscard]] std::vector GetSamplers() const override; // Language @@ -188,18 +188,9 @@ public: * * @return The language of the shader */ - Graphics::ShaderLanguage GetLanguage() const; - - // Other + [[nodiscard]] Graphics::ShaderLanguage GetLanguage() const override; - /** - * @brief Set the program object whose reflection to be built - * - * @param [in] glProgram The program object - */ - void SetGlProgram(uint32_t glProgram); - -private: +public: /** * @brief Build the reflection of vertex attributes */ @@ -221,7 +212,7 @@ protected: private: Graphics::EglGraphicsController& mController; ///< The Graphics controller - uint32_t mGlProgram; ///< The GL program object + GLES::ProgramImpl& mProgram; ///< The Program object struct AttributeInfo { @@ -237,7 +228,6 @@ private: }; } // namespace GLES -} // namespace Graphics -} // namespace Dali +} // namespace Dali::Graphics #endif // DALI_GRAPHICS_GLES_REFLECTION_H diff --git a/dali/internal/graphics/gles-impl/gles-graphics-shader.cpp b/dali/internal/graphics/gles-impl/gles-graphics-shader.cpp index 1bbfe92..04a1239 100644 --- a/dali/internal/graphics/gles-impl/gles-graphics-shader.cpp +++ b/dali/internal/graphics/gles-impl/gles-graphics-shader.cpp @@ -15,28 +15,115 @@ * */ +// CLASS HEADER #include "gles-graphics-shader.h" -#include -#include -#include "egl-graphics-controller.h" -#include +// INTERNAL INCLUDES +#include "egl-graphics-controller.h" -namespace Dali +namespace Dali::Graphics::GLES { -namespace Graphics -{ -namespace GLES +struct Shader::Impl { + Impl() = default; + ~Impl() = default; + + std::vector source{}; + uint32_t glShader{}; +}; + Shader::Shader(const Graphics::ShaderCreateInfo& createInfo, Graphics::EglGraphicsController& controller) : ShaderResource(createInfo, controller) { - if(mCreateInfo.sourceData && mCreateInfo.sourceSize) + // push shader to the create queue + mImpl = std::make_unique(); + + // Make a copy of source code + mImpl->source.resize(createInfo.sourceSize); + std::copy(reinterpret_cast(mCreateInfo.sourceData), + reinterpret_cast(mCreateInfo.sourceData) + mCreateInfo.sourceSize, + mImpl->source.begin()); + + // Substitute pointer + mCreateInfo.sourceData = mImpl->source.data(); +} + +bool Shader::Compile() const +{ + auto& gl = *GetController().GetGL(); + if(!mImpl->glShader) { - printf("GLES::Shader: stage: %d, sourceMode: %d, size: %u, source:\n\n%s\n", (int)mCreateInfo.pipelineStage, (int)mCreateInfo.sourceMode, mCreateInfo.sourceSize, static_cast(mCreateInfo.sourceData)); + GLenum pipelineStage{0u}; + switch(GetCreateInfo().pipelineStage) + { + case Graphics::PipelineStage::TOP_OF_PIPELINE: + { + break; + } + case Graphics::PipelineStage::VERTEX_SHADER: + { + pipelineStage = GL_VERTEX_SHADER; + break; + } + case Graphics::PipelineStage::GEOMETRY_SHADER: + { + break; + } + case Graphics::PipelineStage::FRAGMENT_SHADER: + { + pipelineStage = GL_FRAGMENT_SHADER; + break; + } + case Graphics::PipelineStage::COMPUTE_SHADER: + { + break; + } + case Graphics::PipelineStage::TESSELATION_CONTROL: + { + break; + } + case Graphics::PipelineStage::TESSELATION_EVALUATION: + { + break; + } + case Graphics::PipelineStage::BOTTOM_OF_PIPELINE: + { + break; + } + } + + if(pipelineStage) + { + auto shader = gl.CreateShader(pipelineStage); + const auto src = reinterpret_cast(GetCreateInfo().sourceData); + GLint size = GetCreateInfo().sourceSize; + gl.ShaderSource(shader, 1, const_cast(&src), &size); + gl.CompileShader(shader); + + GLint status{0}; + gl.GetShaderiv(shader, GL_COMPILE_STATUS, &status); + if(status != GL_TRUE) + { + char output[4096]; + GLsizei size{0u}; + gl.GetShaderInfoLog(shader, 4096, &size, output); + printf("Code: %s\n", reinterpret_cast(GetCreateInfo().sourceData)); + printf("Log: %s\n", output); + gl.DeleteShader(shader); + return false; + } + + // TODO: check error + mImpl->glShader = shader; + } + return true; } + return true; +} + +uint32_t Shader::GetGLShader() const +{ + return mImpl->glShader; } -} // namespace GLES -} // namespace Graphics -} // namespace Dali +} // namespace Dali::Graphics::GLES \ No newline at end of file diff --git a/dali/internal/graphics/gles-impl/gles-graphics-shader.h b/dali/internal/graphics/gles-impl/gles-graphics-shader.h index f5802af..d96223f 100644 --- a/dali/internal/graphics/gles-impl/gles-graphics-shader.h +++ b/dali/internal/graphics/gles-impl/gles-graphics-shader.h @@ -67,11 +67,7 @@ public: * @brief Compiles shader * @return */ - bool Compile() const - { - mGlShader = 0; - return true; - } + bool Compile() const; /** * @brief Called when UniquePtr<> on client-side dies @@ -81,13 +77,11 @@ public: // TODO: Implement moving to the discard queue } - uint32_t GetGLShader() const - { - return mGlShader; - } + uint32_t GetGLShader() const; private: - mutable uint32_t mGlShader; + struct Impl; + std::unique_ptr mImpl; }; } // namespace Dali::Graphics::GLES