X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali%2Finternal%2Frender%2Frenderers%2Fpipeline-cache.cpp;h=c2545c051cacd9ce77a4b6751bb1bbe922e092ff;hb=84603b1de6ca59dd2b04c16147c6ab5f38d54869;hp=3f655f4f130b2b5f8e3698e585f6c2026e946de1;hpb=5ce681b03e5a166933e79c3577dd0a7c8866d396;p=platform%2Fcore%2Fuifw%2Fdali-core.git diff --git a/dali/internal/render/renderers/pipeline-cache.cpp b/dali/internal/render/renderers/pipeline-cache.cpp index 3f655f4..c2545c0 100644 --- a/dali/internal/render/renderers/pipeline-cache.cpp +++ b/dali/internal/render/renderers/pipeline-cache.cpp @@ -29,6 +29,8 @@ namespace Dali::Internal::Render { namespace { +constexpr uint32_t CACHE_CLEAN_FRAME_COUNT = 600; // 60fps * 10sec + // Helper to get the vertex input format Dali::Graphics::VertexInputFormat GetPropertyVertexFormat(Property::Type propertyType) { @@ -190,10 +192,10 @@ constexpr Graphics::BlendOp ConvertBlendEquation(DevelBlendEquation::Type blendE } } // namespace -PipelineCacheL0* PipelineCache::GetPipelineCacheL0(std::size_t hash, Program* program, Render::Geometry* geometry) +PipelineCacheL0Ptr PipelineCache::GetPipelineCacheL0(Program* program, Render::Geometry* geometry) { - auto it = std::find_if(level0nodes.begin(), level0nodes.end(), [hash, program, geometry](PipelineCacheL0& item) { - return ((item.hash == hash && item.program == program && item.geometry == geometry)); + auto it = std::find_if(level0nodes.begin(), level0nodes.end(), [program, geometry](PipelineCacheL0& item) { + return ((item.program == program && item.geometry == geometry)); }); // Add new node to cache @@ -209,8 +211,14 @@ PipelineCacheL0* PipelineCache::GetPipelineCacheL0(std::size_t hash, Program* pr { const VertexBuffer::Format& vertexFormat = *vertexBuffer->GetFormat(); + uint32_t divisor = vertexBuffer->GetDivisor(); + Graphics::VertexInputRate vertexInputRate = (divisor == 0 + ? Graphics::VertexInputRate::PER_VERTEX + : Graphics::VertexInputRate::PER_INSTANCE); + vertexInputState.bufferBindings.emplace_back(vertexFormat.size, // stride - Graphics::VertexInputRate::PER_VERTEX); + vertexInputRate); + //@todo Add the actual rate to the graphics struct const uint32_t attributeCount = vertexBuffer->GetAttributeCount(); uint32_t lastBoundAttributeIndex = 0; @@ -237,18 +245,17 @@ PipelineCacheL0* PipelineCache::GetPipelineCacheL0(std::size_t hash, Program* pr ++bindingIndex; } PipelineCacheL0 level0; - level0.hash = hash; level0.program = program; level0.geometry = geometry; level0.inputState = vertexInputState; - level0nodes.emplace_back(std::move(level0)); - it = level0nodes.end() - 1; + + it = level0nodes.insert(level0nodes.end(), std::move(level0)); } - return &*it; + return it; } -PipelineCacheL1* PipelineCacheL0::GetPipelineCacheL1(Render::Renderer* renderer, bool usingReflection) +PipelineCacheL1Ptr PipelineCacheL0::GetPipelineCacheL1(Render::Renderer* renderer, bool usingReflection) { // hash must be collision free uint32_t hash = 0; @@ -293,11 +300,8 @@ PipelineCacheL1* PipelineCacheL0::GetPipelineCacheL1(Render::Renderer* renderer, hash = (topo & 0xffu) | ((cull << 8u) & 0xff00u) | ((uint32_t(poly) << 16u) & 0xff0000u); // If L1 not found by hash, create rasterization state describing pipeline and store it - auto it = std::find_if(level1nodes.begin(), level1nodes.end(), [hash](PipelineCacheL1& item) { - return item.hashCode == hash; - }); + auto it = std::find_if(level1nodes.begin(), level1nodes.end(), [hash](PipelineCacheL1& item) { return item.hashCode == hash; }); - PipelineCacheL1* retval = nullptr; if(it == level1nodes.end()) { PipelineCacheL1 item; @@ -306,39 +310,56 @@ PipelineCacheL1* PipelineCacheL0::GetPipelineCacheL1(Render::Renderer* renderer, item.rs.frontFace = Graphics::FrontFace::COUNTER_CLOCKWISE; item.rs.polygonMode = poly; // not in use item.ia.topology = geometry->GetTopology(); - level1nodes.emplace_back(std::move(item)); - retval = &level1nodes.back(); + + it = level1nodes.insert(level1nodes.end(), std::move(item)); } - else + + return it; +} + +void PipelineCacheL0::ClearUnusedCache() +{ + for(auto iter = level1nodes.begin(); iter != level1nodes.end();) { - retval = &*it; + if(iter->ClearUnusedCache()) + { + iter = level1nodes.erase(iter); + } + else + { + iter++; + } } - return retval; } -PipelineCacheL2* PipelineCacheL1::GetPipelineCacheL2(bool blend, bool premul, BlendingOptions& blendingOptions) +PipelineCacheL2Ptr PipelineCacheL1::GetPipelineCacheL2(bool blend, bool premul, BlendingOptions& blendingOptions) { // early out if(!blend) { + if(DALI_UNLIKELY(noBlends.empty())) + { + noBlends.emplace_back(PipelineCacheL2{}); + } + + auto& noBlend = *noBlends.begin(); + if(noBlend.pipeline == nullptr) { // reset all before returning if pipeline has never been created for that case noBlend.hash = 0; memset(&noBlend.colorBlendState, 0, sizeof(Graphics::ColorBlendState)); } - return &noBlend; + return noBlends.begin(); } auto bitmask = uint32_t(blendingOptions.GetBitmask()); // Find by bitmask (L2 entries must be sorted by bitmask) - auto it = std::find_if(level2nodes.begin(), level2nodes.end(), [bitmask](PipelineCacheL2& item) { - return item.hash == bitmask; - }); + auto it = std::find_if(level2nodes.begin(), level2nodes.end(), [bitmask](PipelineCacheL2& item) { return item.hash == bitmask; }); // TODO: find better way of blend constants lookup - PipelineCacheL2* retval = nullptr; + PipelineCacheL2Ptr retval = level2nodes.end(); if(it != level2nodes.end()) { bool hasBlendColor = blendingOptions.GetBlendColor(); @@ -347,20 +368,20 @@ PipelineCacheL2* PipelineCacheL1::GetPipelineCacheL2(bool blend, bool premul, Bl Vector4 v(it->colorBlendState.blendConstants); if(v == *blendingOptions.GetBlendColor()) { - retval = &*it; + retval = it; } ++it; } if(!hasBlendColor) { - retval = &*it; + retval = it; } } - if(!retval) + if(retval == level2nodes.end()) { // create new entry and return it with null pipeline - PipelineCacheL2 l2; + PipelineCacheL2 l2{}; l2.pipeline = nullptr; auto& colorBlendState = l2.colorBlendState; colorBlendState.SetBlendEnable(true); @@ -391,11 +412,10 @@ PipelineCacheL2* PipelineCacheL1::GetPipelineCacheL2(bool blend, bool premul, Bl } l2.hash = blendingOptions.GetBitmask(); - level2nodes.emplace_back(std::move(l2)); - std::sort(level2nodes.begin(), level2nodes.end(), [](PipelineCacheL2& lhs, PipelineCacheL2& rhs) { - return lhs.hash < rhs.hash; - }); + auto upperBound = std::upper_bound(level2nodes.begin(), level2nodes.end(), l2, [](const PipelineCacheL2& lhs, const PipelineCacheL2& rhs) { return lhs.hash < rhs.hash; }); + + level2nodes.insert(upperBound, std::move(l2)); // run same function to retrieve retval retval = GetPipelineCacheL2(blend, premul, blendingOptions); @@ -404,6 +424,28 @@ PipelineCacheL2* PipelineCacheL1::GetPipelineCacheL2(bool blend, bool premul, Bl return retval; } +bool PipelineCacheL1::ClearUnusedCache() +{ + for(auto iter = level2nodes.begin(); iter != level2nodes.end();) + { + if(iter->referenceCount == 0) + { + iter = level2nodes.erase(iter); + } + else + { + iter++; + } + } + + if(!noBlends.empty() && noBlends.begin()->referenceCount > 0) + { + return false; + } + + return level2nodes.empty(); +} + void PipelineCacheQueryInfo::GenerateHash() { // Lightweight hash value generation. @@ -453,12 +495,14 @@ PipelineResult PipelineCache::GetPipeline(const PipelineCacheQueryInfo& queryInf // If we can reuse latest bound pipeline, Fast return. if(ReuseLatestBoundPipeline(latestUsedCacheIndex, queryInfo)) { + mLatestResult[latestUsedCacheIndex].level2->referenceCount++; return mLatestResult[latestUsedCacheIndex]; } - auto* level0 = GetPipelineCacheL0(queryInfo.hash, queryInfo.program, queryInfo.geometry); - auto* level1 = level0->GetPipelineCacheL1(queryInfo.renderer, queryInfo.cameraUsingReflection); - auto* level2 = level1->GetPipelineCacheL2(queryInfo.blendingEnabled, queryInfo.alphaPremultiplied, *queryInfo.blendingOptions); + auto level0 = GetPipelineCacheL0(queryInfo.program, queryInfo.geometry); + auto level1 = level0->GetPipelineCacheL1(queryInfo.renderer, queryInfo.cameraUsingReflection); + + PipelineCachePtr level2 = level1->GetPipelineCacheL2(queryInfo.blendingEnabled, queryInfo.alphaPremultiplied, *queryInfo.blendingOptions); // Create new pipeline at level2 if requested if(level2->pipeline == nullptr && createNewIfNotFound) @@ -482,10 +526,10 @@ PipelineResult PipelineCache::GetPipeline(const PipelineCacheQueryInfo& queryInf PipelineResult result{}; result.pipeline = level2->pipeline.get(); - result.level0 = level0; - result.level1 = level1; result.level2 = level2; + level2->referenceCount++; + // Copy query and result mLatestQuery[latestUsedCacheIndex] = queryInfo; mLatestResult[latestUsedCacheIndex] = result; @@ -498,4 +542,39 @@ bool PipelineCache::ReuseLatestBoundPipeline(const int latestUsedCacheIndex, con return mLatestResult[latestUsedCacheIndex].pipeline != nullptr && PipelineCacheQueryInfo::Equal(queryInfo, mLatestQuery[latestUsedCacheIndex]); } +void PipelineCache::PreRender() +{ + CleanLatestUsedCache(); + + // We don't need to check this every frame + if(++mFrameCount >= CACHE_CLEAN_FRAME_COUNT) + { + mFrameCount = 0u; + ClearUnusedCache(); + } +} + +void PipelineCache::ClearUnusedCache() +{ + for(auto iter = level0nodes.begin(); iter != level0nodes.end();) + { + iter->ClearUnusedCache(); + + if(iter->level1nodes.empty()) + { + iter = level0nodes.erase(iter); + } + else + { + iter++; + } + } +} + +void PipelineCache::ResetPipeline(PipelineCachePtr pipelineCache) +{ + // TODO : Can we always assume that pipelineCache input is valid iterator? + pipelineCache->referenceCount--; +} + } // namespace Dali::Internal::Render