}
} // namespace
-PipelineCacheL0* PipelineCache::GetPipelineCacheL0(std::size_t hash, Program* program, Render::Geometry* geometry)
+PipelineCacheL0Ptr PipelineCache::GetPipelineCacheL0(std::size_t hash, 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(), [hash, program, geometry](PipelineCacheL0& item) { return ((item.hash == hash && item.program == program && item.geometry == geometry)); });
// Add new node to cache
if(it == level0nodes.end())
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;
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;
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();
- }
- else
- {
- retval = &*it;
+
+ it = level1nodes.insert(level1nodes.end(), std::move(item));
}
- return retval;
+
+ return it;
}
void PipelineCacheL0::ClearUnusedCache()
}
}
-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();
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);
}
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);
bool PipelineCacheL1::ClearUnusedCache()
{
- if(noBlend.referenceCount > 0)
- {
- return false;
- }
-
for(auto iter = level2nodes.begin(); iter != level2nodes.end();)
{
if(iter->referenceCount == 0)
}
}
+ if(!noBlends.empty() && noBlends.begin()->referenceCount > 0)
+ {
+ return false;
+ }
+
return level2nodes.empty();
}
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.hash, 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)
}
}
-void PipelineCache::ResetPipeline(PipelineCacheL2* pipelineCache)
+void PipelineCache::ResetPipeline(PipelineCachePtr pipelineCache)
{
- if(pipelineCache)
- {
- pipelineCache->referenceCount--;
- }
+ // TODO : Can we always assume that pipelineCache input is valid iterator?
+ pipelineCache->referenceCount--;
}
} // namespace Dali::Internal::Render
#include <dali/graphics-api/graphics-pipeline.h>
#include <dali/graphics-api/graphics-types.h>
#include <dali/internal/common/blending-options.h>
-
-// EXTERNAL INCLUDES
-#include <vector>
+#include <dali/public-api/common/list-wrapper.h>
namespace Dali::Internal
{
class Renderer;
class Geometry;
+struct PipelineCacheL2;
+struct PipelineCacheL1;
+struct PipelineCacheL0;
+using PipelineCacheL2Container = std::list<PipelineCacheL2>;
+using PipelineCacheL1Container = std::list<PipelineCacheL1>;
+using PipelineCacheL0Container = std::list<PipelineCacheL0>;
+using PipelineCacheL2Ptr = PipelineCacheL2Container::iterator;
+using PipelineCacheL1Ptr = PipelineCacheL1Container::iterator;
+using PipelineCacheL0Ptr = PipelineCacheL0Container::iterator;
+
+using PipelineCachePtr = PipelineCacheL2Ptr;
+
/**
* Cache Level 2 : Last level of cache, stores actual pipeline
*/
{
uint32_t hash{};
uint32_t referenceCount{0u};
- Graphics::ColorBlendState colorBlendState;
- Graphics::UniquePtr<Graphics::Pipeline> pipeline;
+ Graphics::ColorBlendState colorBlendState{};
+ Graphics::UniquePtr<Graphics::Pipeline> pipeline{};
};
/**
*/
struct PipelineCacheL1
{
- PipelineCacheL2* GetPipelineCacheL2(bool blend, bool premul, BlendingOptions& blendingOptions);
+ PipelineCacheL2Ptr GetPipelineCacheL2(bool blend, bool premul, BlendingOptions& blendingOptions);
/**
* @brief Clear unused caches.
Graphics::RasterizationState rs{};
Graphics::InputAssemblyState ia{};
- PipelineCacheL2 noBlend; // special case
- std::vector<PipelineCacheL2> level2nodes;
+ PipelineCacheL2Container noBlends; // special case
+ PipelineCacheL2Container level2nodes;
};
/**
*/
struct PipelineCacheL0 // L0 cache
{
- PipelineCacheL1* GetPipelineCacheL1(Render::Renderer* renderer, bool usingReflection);
+ PipelineCacheL1Ptr GetPipelineCacheL1(Render::Renderer* renderer, bool usingReflection);
/**
* @brief Clear unused caches.
Program* program{};
Graphics::VertexInputState inputState;
- std::vector<PipelineCacheL1> level1nodes;
+ PipelineCacheL1Container level1nodes;
};
struct PipelineCacheQueryInfo
struct PipelineResult
{
Graphics::Pipeline* pipeline;
- PipelineCacheL2* level2;
+ PipelineCachePtr level2;
};
/**
/**
* Retrieves next cache level
*/
- PipelineCacheL0* GetPipelineCacheL0(std::size_t hash, Program* program, Render::Geometry* geometry);
+ PipelineCacheL0Ptr GetPipelineCacheL0(std::size_t hash, Program* program, Render::Geometry* geometry);
/**
* Retrieves pipeline matching queryInfo struct
* @brief Decrease the reference count of the pipeline cache.
* @param pipelineCache The pipeline cache to decrease the reference count
*/
- void ResetPipeline(PipelineCacheL2* pipelineCache);
+ void ResetPipeline(PipelineCachePtr pipelineCache);
private:
/**
void ClearUnusedCache();
private:
- Graphics::Controller* graphicsController{nullptr};
- std::vector<PipelineCacheL0> level0nodes;
+ Graphics::Controller* graphicsController{nullptr};
+ PipelineCacheL0Container level0nodes;
// Cache latest queries whether blend enabled or not.
// (Since most UI case (like Text and Image) enable blend, and most 3D case disable blend.)