Merge "Added shader support to pipeline cache" into devel/master
[platform/core/uifw/dali-adaptor.git] / dali / internal / graphics / gles-impl / gles-graphics-pipeline-cache.cpp
old mode 100755 (executable)
new mode 100644 (file)
index 69f45b7..b567a27
 #include "gles-graphics-pipeline.h"
 #include "gles-graphics-program.h"
 
+namespace
+{
+constexpr uint32_t CACHE_CLEAN_FLUSH_COUNT = 3600u; // 60fps * 60sec / ~3 flushes per frame
+}
+
 namespace Dali::Graphics::GLES
 {
 /**
@@ -245,7 +250,10 @@ struct PipelineCache::Impl
    * @brief Constructor
    */
   explicit Impl(EglGraphicsController& _controller)
-  : controller(_controller)
+  : controller(_controller),
+    pipelineEntriesFlushRequired(false),
+    programEntriesFlushRequired(false),
+    shaderEntriesFlushRequired(false)
   {
     // Initialise lookup table
     InitialiseStateCompareLookupTable();
@@ -285,9 +293,6 @@ struct PipelineCache::Impl
     uint32_t                stateBitmask{0u};
   };
 
-  EglGraphicsController&  controller;
-  std::vector<CacheEntry> entries;
-
   /**
    * @brief Sorted array of shaders used to create program
    */
@@ -298,7 +303,19 @@ struct PipelineCache::Impl
     UniquePtr<ProgramImpl>               program{nullptr};
   };
 
+  struct ShaderCacheEntry
+  {
+    UniquePtr<ShaderImpl> shaderImpl{nullptr};
+  };
+
+  EglGraphicsController&         controller;
+  std::vector<CacheEntry>        entries;
   std::vector<ProgramCacheEntry> programEntries;
+  std::vector<ShaderCacheEntry>  shaderEntries;
+
+  bool pipelineEntriesFlushRequired : 1;
+  bool programEntriesFlushRequired : 1;
+  bool shaderEntriesFlushRequired : 1;
 };
 
 PipelineCache::PipelineCache(EglGraphicsController& controller)
@@ -442,7 +459,7 @@ Graphics::UniquePtr<Graphics::Program> PipelineCache::GetProgram(const ProgramCr
     // create new pipeline
     auto program = MakeUnique<GLES::ProgramImpl>(programCreateInfo, mImpl->controller);
 
-    program->Create();
+    program->Create(); // Don't currently handle failure.
 
     cachedProgram = program.get();
 
@@ -462,28 +479,143 @@ Graphics::UniquePtr<Graphics::Program> PipelineCache::GetProgram(const ProgramCr
   return std::move(wrapper);
 }
 
+ShaderImpl* PipelineCache::FindShaderImpl(const ShaderCreateInfo& shaderCreateInfo)
+{
+  if(!mImpl->shaderEntries.empty())
+  {
+    for(auto& item : mImpl->shaderEntries)
+    {
+      auto& itemInfo = item.shaderImpl->GetCreateInfo();
+      if(itemInfo.pipelineStage != shaderCreateInfo.pipelineStage ||
+         itemInfo.shaderlanguage != shaderCreateInfo.shaderlanguage ||
+         itemInfo.sourceMode != shaderCreateInfo.sourceMode ||
+         itemInfo.sourceSize != shaderCreateInfo.sourceSize)
+      {
+        continue;
+      }
+
+      if(memcmp(itemInfo.sourceData, shaderCreateInfo.sourceData, itemInfo.sourceSize) == 0)
+      {
+        return item.shaderImpl.get();
+      }
+    }
+  }
+  return nullptr;
+}
+
+Graphics::UniquePtr<Graphics::Shader> PipelineCache::GetShader(const ShaderCreateInfo&                 shaderCreateInfo,
+                                                               Graphics::UniquePtr<Graphics::Shader>&& oldShader)
+{
+  ShaderImpl* cachedShader = FindShaderImpl(shaderCreateInfo);
+
+  // Return same pointer if nothing changed
+  if(oldShader && *static_cast<GLES::Shader*>(oldShader.get()) == cachedShader)
+  {
+    return std::move(oldShader);
+  }
+
+  if(!cachedShader)
+  {
+    auto shader  = MakeUnique<GLES::ShaderImpl>(shaderCreateInfo, mImpl->controller);
+    cachedShader = shader.get();
+
+    mImpl->shaderEntries.emplace_back();
+    mImpl->shaderEntries.back().shaderImpl = std::move(shader);
+  }
+  auto wrapper = MakeUnique<GLES::Shader, CachedObjectDeleter<GLES::Shader>>(cachedShader);
+  return std::move(wrapper);
+}
+
 void PipelineCache::FlushCache()
 {
-  decltype(mImpl->entries) newEntries;
-  newEntries.reserve(mImpl->entries.size());
+  if(mImpl->pipelineEntriesFlushRequired)
+  {
+    decltype(mImpl->entries) newEntries;
+    newEntries.reserve(mImpl->entries.size());
 
-  for(auto& entry : mImpl->entries)
+    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);
+
+    mImpl->pipelineEntriesFlushRequired = false;
+  }
+
+  if(mImpl->programEntriesFlushRequired)
   {
-    // Move items which are still in use into the new array
-    if(entry.pipeline->GetRefCount() != 0)
+    // Program cache require similar action.
+    decltype(mImpl->programEntries) newProgramEntries;
+    newProgramEntries.reserve(mImpl->programEntries.size());
+
+    for(auto& entry : mImpl->programEntries)
     {
-      newEntries.emplace_back(std::move(entry));
+      // Move items which are still in use into the new array
+      if(entry.program->GetRefCount() != 0)
+      {
+        newProgramEntries.emplace_back(std::move(entry));
+      }
     }
+
+    mImpl->programEntries = std::move(newProgramEntries);
+
+    mImpl->programEntriesFlushRequired = false;
   }
 
-  // Move temporary array in place of stored cache
-  // Unused pipelines will be deleted automatically
-  mImpl->entries = std::move(newEntries);
+  if(mImpl->shaderEntriesFlushRequired)
+  {
+    // There is at least 1 unused shader
+    mImpl->shaderEntriesFlushRequired = false;
+    bool deleteRequired{false};
+    for(auto& entry : mImpl->shaderEntries)
+    {
+      if(entry.shaderImpl->GetRefCount() == 0)
+      {
+        mImpl->shaderEntriesFlushRequired = true;
+        auto frameCount                   = entry.shaderImpl->IncreaseFlushCount();
+        if(frameCount > CACHE_CLEAN_FLUSH_COUNT)
+        {
+          deleteRequired = true;
+        }
+      }
+    }
+    if(deleteRequired)
+    {
+      decltype(mImpl->shaderEntries) newShaderEntries;
+      newShaderEntries.reserve(mImpl->shaderEntries.size());
+      for(auto& entry : mImpl->shaderEntries)
+      {
+        if(entry.shaderImpl->GetRefCount() > 0 ||
+           entry.shaderImpl->GetFlushCount() <= CACHE_CLEAN_FLUSH_COUNT)
+        {
+          newShaderEntries.emplace_back(std::move(entry));
+        }
+      }
+      mImpl->shaderEntries = std::move(newShaderEntries);
+    }
+  }
+}
+
+void PipelineCache::MarkPipelineCacheFlushRequired()
+{
+  mImpl->pipelineEntriesFlushRequired = true;
+}
 
-  // 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)
+void PipelineCache::MarkProgramCacheFlushRequired()
+{
+  mImpl->programEntriesFlushRequired = true;
+}
+
+void PipelineCache::MarkShaderCacheFlushRequired()
+{
+  mImpl->shaderEntriesFlushRequired = true;
 }
 
 } // namespace Dali::Graphics::GLES