From: Adam Bialogonski Date: Fri, 12 Feb 2021 18:16:07 +0000 (+0000) Subject: Pipeline caching X-Git-Tag: graphics-backend-pre-release-2~5 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F16%2F253516%2F3;p=platform%2Fcore%2Fuifw%2Fdali-adaptor.git Pipeline caching - naive pipeline caching - returns unique_ptr to wrapper of pipeline rather than actual implementation - still requires optimization inside the pipeline implementation Change-Id: I53f31b08bc7174b35dc64e6fdc6166b4d9a038dc --- diff --git a/dali/internal/graphics/gles-impl/egl-graphics-controller.cpp b/dali/internal/graphics/gles-impl/egl-graphics-controller.cpp index e296bee..32cc491 100644 --- a/dali/internal/graphics/gles-impl/egl-graphics-controller.cpp +++ b/dali/internal/graphics/gles-impl/egl-graphics-controller.cpp @@ -151,9 +151,15 @@ EglGraphicsController::CreateBuffer(const BufferCreateInfo& bufferCreateInfo, Gr return NewObject(bufferCreateInfo, *this, std::move(oldBuffer)); } -Graphics::UniquePtr EglGraphicsController::CreatePipeline(const PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr&& oldPipeline) +Graphics::UniquePtr EglGraphicsController::CreatePipeline(const PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr&& oldPipeline) { - return NewObject(pipelineCreateInfo, *this, std::move(oldPipeline)); + // Create pipeline cache if needed + if(!mPipelineCache) + { + mPipelineCache = std::make_unique(*this); + } + + return mPipelineCache->GetPipeline(pipelineCreateInfo, std::move(oldPipeline)); } void EglGraphicsController::AddTexture(GLES::Texture& texture) diff --git a/dali/internal/graphics/gles-impl/egl-graphics-controller.h b/dali/internal/graphics/gles-impl/egl-graphics-controller.h index 6a1cfa1..790b252 100644 --- a/dali/internal/graphics/gles-impl/egl-graphics-controller.h +++ b/dali/internal/graphics/gles-impl/egl-graphics-controller.h @@ -25,6 +25,7 @@ #include "gles-context.h" #include "gles-graphics-buffer.h" #include "gles-graphics-memory.h" +#include "gles-graphics-pipeline-cache.h" #include "gles-graphics-texture.h" namespace Dali @@ -41,7 +42,8 @@ namespace Graphics namespace GLES { class CommandBuffer; -} +class PipelineCache; +} // namespace GLES /** * EGL Implementation of the graphics controller. @@ -416,6 +418,8 @@ private: std::queue mTextureUpdateRequests; std::unique_ptr mContext{nullptr}; ///< Context object handling command buffers execution + + std::unique_ptr mPipelineCache{nullptr}; ///< Internal pipeline cache }; } // namespace Graphics diff --git a/dali/internal/graphics/gles-impl/file.list b/dali/internal/graphics/gles-impl/file.list index 832ed14..6c30917 100644 --- a/dali/internal/graphics/gles-impl/file.list +++ b/dali/internal/graphics/gles-impl/file.list @@ -13,6 +13,7 @@ SET( adaptor_graphics_gles_src_files ${adaptor_graphics_gles_src_files} ${adaptor_graphics_dir}/gles-impl/gles-graphics-sampler.cpp ${adaptor_graphics_dir}/gles-impl/gles-graphics-shader.cpp ${adaptor_graphics_dir}/gles-impl/gles-graphics-texture.cpp + ${adaptor_graphics_dir}/gles-impl/gles-graphics-pipeline-cache.cpp ${adaptor_graphics_dir}/gles-impl/gles-context.cpp ) diff --git a/dali/internal/graphics/gles-impl/gles-graphics-pipeline-cache.cpp b/dali/internal/graphics/gles-impl/gles-graphics-pipeline-cache.cpp new file mode 100644 index 0000000..9e69c77 --- /dev/null +++ b/dali/internal/graphics/gles-impl/gles-graphics-pipeline-cache.cpp @@ -0,0 +1,156 @@ +/* + * 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-pipeline-cache.h" + +// INTERNAL INCLUDES +#include "gles-graphics-pipeline.h" + +namespace Dali::Graphics::GLES +{ +/** + * @brief Implementation of pipeline cache + */ +struct PipelineCache::Impl +{ + explicit Impl(EglGraphicsController& _controller) + : controller(_controller) + { + } + + ~Impl() = default; + + EglGraphicsController& controller; + + std::vector> mPipelines; +}; + +PipelineCache::PipelineCache(EglGraphicsController& controller) +{ + mImpl = std::make_unique(controller); +} + +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& cacheInfo = pipeline->GetCreateInfo(); + + if(!info.shaderState) + { + 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()) + { + if(memcmp(info.shaderState->data(), cacheInfo.shaderState->data(), sizeof(info.shaderState->size() * sizeof(ShaderState))) != 0) + { + continue; // early exit + } + + // 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) + { + continue; // early exit + } + + // 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) + { + continue; + } + + // For now ignoring dynamic state mask and allocator + + // Getting as far as here, we have found our pipeline impl + return pipeline.get(); + } + } + return nullptr; +} + +Graphics::UniquePtr PipelineCache::GetPipeline(const PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr&& oldPipeline) +{ + // create or get from cache + auto cachedPipeline = FindPipelineImpl(pipelineCreateInfo); + + if(!cachedPipeline) + { + // create new pipeline + auto pipeline = MakeUnique(pipelineCreateInfo, mImpl->controller); + + cachedPipeline = pipeline.get(); + + // add it to cache + mImpl->mPipelines.emplace_back(std::move(pipeline)); + } + else + { + } + // create new pipeline wrapper n + auto wrapper = MakeUnique(*cachedPipeline); + return std::move(wrapper); +} + +} // 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 new file mode 100644 index 0000000..f93e079 --- /dev/null +++ b/dali/internal/graphics/gles-impl/gles-graphics-pipeline-cache.h @@ -0,0 +1,79 @@ +#ifndef DALI_GRAPHICS_GLES_PIPELINE_CACHE_H +#define DALI_GRAPHICS_GLES_PIPELINE_CACHE_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 EglGraphicsController; +namespace GLES +{ +class Pipeline; +class PipelineImpl; + +/** + * @brief PipelineCache manages pipeline and program + * objects so there are no duplicates created. + */ +class PipelineCache +{ +public: + /** + * @brief Constructor + */ + explicit PipelineCache(EglGraphicsController& controller); + + /** + * @brief Destructor + */ + ~PipelineCache(); + + /** + * @brief Retrieves pipeline matching the spec + * + * Function returns either existing pipeline if one is found + * in the cache or creates new one. + * + * @param[in] pipelineCreateInfo Valid PipelineCreateInfo structure + * @param[in] oldPipeline previous pipeline object + * @return Pipeline object + */ + Graphics::UniquePtr GetPipeline(const PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr&& oldPipeline); + +private: + /** + * @brief Finds pipeline implementation based on the spec + * @param[in] info Valid create info structure + * @return Returns pointer to pipeline or nullptr + */ + PipelineImpl* FindPipelineImpl(const PipelineCreateInfo& info); + +private: + struct Impl; + std::unique_ptr mImpl; +}; +} // namespace GLES +} // namespace Dali::Graphics +#endif diff --git a/dali/internal/graphics/gles-impl/gles-graphics-pipeline.cpp b/dali/internal/graphics/gles-impl/gles-graphics-pipeline.cpp index 2f31d6e..b747a19 100644 --- a/dali/internal/graphics/gles-impl/gles-graphics-pipeline.cpp +++ b/dali/internal/graphics/gles-impl/gles-graphics-pipeline.cpp @@ -15,10 +15,15 @@ * */ +// CLASS HEADER #include "gles-graphics-pipeline.h" + +// EXTERNAL INCLUDES #include #include #include + +// INTERNAL INCLUDES #include "egl-graphics-controller.h" #include "gles-graphics-shader.h" @@ -27,10 +32,10 @@ namespace Dali::Graphics::GLES /** * Copy of pipeline state, can be also used for internal caching */ -struct Pipeline::PipelineState +struct PipelineImpl::PipelineState { - PipelineState() = default; - + PipelineState() = default; + ~PipelineState() = default; ColorBlendState colorBlendState; DepthStencilState depthStencilState; std::vector shaderState; @@ -41,11 +46,11 @@ struct Pipeline::PipelineState InputAssemblyState inputAssemblyState; }; -Pipeline::Pipeline(const Graphics::PipelineCreateInfo& createInfo, Graphics::EglGraphicsController& controller) -: PipelineResource(createInfo, controller) +PipelineImpl::PipelineImpl(const Graphics::PipelineCreateInfo& createInfo, Graphics::EglGraphicsController& controller) +: mController(controller) { // the creation is deferred so it's needed to copy certain parts of the CreateInfo structure - mPipelineState = std::make_unique(); + mPipelineState = std::make_unique(); // Make copies of structured pass by pointers and replace // stored create info structure fields @@ -59,7 +64,17 @@ Pipeline::Pipeline(const Graphics::PipelineCreateInfo& createInfo, Graphics::Egl CopyStateIfSet(createInfo.viewportState, mPipelineState->viewportState, &mCreateInfo.viewportState); } -bool Pipeline::InitializeResource() +const PipelineCreateInfo& PipelineImpl::GetCreateInfo() const +{ + return mCreateInfo; +} + +auto& PipelineImpl::GetController() const +{ + return mController; +} + +bool PipelineImpl::InitializeResource() { auto& gl = *GetController().GetGL(); mGlProgram = gl.CreateProgram(); @@ -90,7 +105,7 @@ bool Pipeline::InitializeResource() return true; } -void Pipeline::DestroyResource() +void PipelineImpl::DestroyResource() { if(mGlProgram) { @@ -99,18 +114,18 @@ void Pipeline::DestroyResource() } } -void Pipeline::DiscardResource() +void PipelineImpl::DiscardResource() { // Pass program to discard queue } -uint32_t Pipeline::GetGLProgram() const +uint32_t PipelineImpl::GetGLProgram() const { return mGlProgram; } // FIXME: THIS FUNCTION IS NOT IN USE YET, REQUIRES PROPER PIPELINE -void Pipeline::Bind(GLES::Pipeline* prevPipeline) +void PipelineImpl::Bind(GLES::PipelineImpl* prevPipeline) { // Same pipeline to bind, nothing to do if(prevPipeline == this) @@ -147,4 +162,33 @@ void Pipeline::Bind(GLES::Pipeline* prevPipeline) gl.UseProgram(program); } +void PipelineImpl::Retain() +{ + ++mRefCount; +} + +void PipelineImpl::Release() +{ + --mRefCount; +} + +uint32_t PipelineImpl::GetRefCount() const +{ + return mRefCount; +} + +PipelineImpl::~PipelineImpl() = default; + +// PIPELINE WRAPPER + +const PipelineCreateInfo& Pipeline::GetCreateInfo() const +{ + return mPipeline.GetCreateInfo(); +} + +EglGraphicsController& Pipeline::GetController() const +{ + return mPipeline.GetController(); +} + } // namespace Dali::Graphics::GLES \ No newline at end of file diff --git a/dali/internal/graphics/gles-impl/gles-graphics-pipeline.h b/dali/internal/graphics/gles-impl/gles-graphics-pipeline.h index 0f202e1..64dad5a 100644 --- a/dali/internal/graphics/gles-impl/gles-graphics-pipeline.h +++ b/dali/internal/graphics/gles-impl/gles-graphics-pipeline.h @@ -30,7 +30,11 @@ namespace Dali::Graphics::GLES { using PipelineResource = Resource; -class Pipeline : public PipelineResource +/** + * @brief PipelineWrapper is the object + * returned to the client-side + */ +class PipelineImpl { public: /** @@ -38,24 +42,29 @@ public: * @param[in] createInfo valid TextureCreateInfo structure * @param[in] controller Reference to the Controller */ - Pipeline(const Graphics::PipelineCreateInfo& createInfo, Graphics::EglGraphicsController& controller); + PipelineImpl(const Graphics::PipelineCreateInfo& createInfo, Graphics::EglGraphicsController& controller); + + /** + * @brief Destructor + */ + ~PipelineImpl(); /** * @brief Destroys all the low-level resources used by the class */ - void DestroyResource() override; + void DestroyResource(); /** * @brief Initializes low-level resources * * @return Tron success */ - bool InitializeResource() override; + bool InitializeResource(); /** * @brief Discards object */ - void DiscardResource() override; + void DiscardResource(); /** * @brief returns GL program id @@ -73,7 +82,7 @@ public: * * @param[in] prevPipeline previous pipeline */ - void Bind(GLES::Pipeline* prevPipeline); + void Bind(GLES::PipelineImpl* prevPipeline); /** * Executes state change function if condition met @@ -95,6 +104,16 @@ public: } } + void Retain(); + + void Release(); + + [[nodiscard]] uint32_t GetRefCount() const; + + [[nodiscard]] const PipelineCreateInfo& GetCreateInfo() const; + + [[nodiscard]] auto& GetController() const; + private: /** * @brief Helper function. Copies state if pointer is set @@ -127,9 +146,49 @@ private: // Pipeline state is stored as a copy of create info // data. struct PipelineState; - std::unique_ptr mPipelineState{}; + std::unique_ptr mPipelineState; + + EglGraphicsController& mController; + PipelineCreateInfo mCreateInfo; uint32_t mGlProgram{0u}; + + uint32_t mRefCount{0u}; +}; + +/** + * @brief Pipeline class wraps a unique pipeline object + * + */ +class Pipeline : public Graphics::Pipeline +{ +public: + Pipeline() = delete; + + explicit Pipeline(GLES::PipelineImpl& pipeline) + : mPipeline(pipeline) + { + // increase refcount + mPipeline.Retain(); + } + + ~Pipeline() override + { + // decrease refcount + mPipeline.Release(); + } + + [[nodiscard]] auto& GetPipeline() const + { + return mPipeline; + } + + [[nodiscard]] const PipelineCreateInfo& GetCreateInfo() const; + + [[nodiscard]] EglGraphicsController& GetController() const; + +private: + GLES::PipelineImpl& mPipeline; }; } // namespace Dali::Graphics::GLES