/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
// EXTERNAL INCLUDES
#include <cstring>
-#include <iomanip>
#include <map>
// INTERNAL INCLUDES
#include <dali/graphics-api/graphics-program.h>
#include <dali/graphics-api/graphics-reflection.h>
#include <dali/integration-api/debug.h>
-#include <dali/integration-api/gl-defines.h>
#include <dali/internal/common/shader-data.h>
#include <dali/internal/render/common/performance-monitor.h>
+#include <dali/internal/render/renderers/uniform-buffer-manager.h>
#include <dali/internal/render/shaders/program-cache.h>
#include <dali/public-api/common/constants.h>
#include <dali/public-api/common/dali-common.h>
// LOCAL STUFF
namespace
{
-const char* const gStdUniforms[Program::UNIFORM_TYPE_LAST] =
- {
- "uMvpMatrix", // UNIFORM_MVP_MATRIX
- "uModelView", // UNIFORM_MODELVIEW_MATRIX
- "uProjection", // UNIFORM_PROJECTION_MATRIX
- "uModelMatrix", // UNIFORM_MODEL_MATRIX,
- "uViewMatrix", // UNIFORM_VIEW_MATRIX,
- "uNormalMatrix", // UNIFORM_NORMAL_MATRIX
- "uColor", // UNIFORM_COLOR
- "sTexture", // UNIFORM_SAMPLER
- "sTextureRect", // UNIFORM_SAMPLER_RECT
- "sEffect", // UNIFORM_EFFECT_SAMPLER
- "uSize" // UNIFORM_SIZE
-};
-
const unsigned int NUMBER_OF_DEFAULT_UNIFORMS = static_cast<unsigned int>(Program::DefaultUniformIndex::COUNT);
/**
CalculateHash(std::string("uModelView")),
CalculateHash(std::string("uNormalMatrix")),
CalculateHash(std::string("uProjection")),
+ CalculateHash(std::string("uScale")),
CalculateHash(std::string("uSize")),
- CalculateHash(std::string("uColor"))};
+ CalculateHash(std::string("uColor")),
+ CalculateHash(std::string("uActorColor"))};
+
+/**
+ * Helper function to calculate the correct alignment of data for uniform buffers
+ * @param dataSize size of uniform buffer
+ * @return size of data aligned to given size
+ */
+inline uint32_t AlignSize(uint32_t dataSize, uint32_t alignSize)
+{
+ return ((dataSize / alignSize) + ((dataSize % alignSize) ? 1u : 0u)) * alignSize;
+}
} // namespace
// IMPLEMENTATION
-Program* Program::New(ProgramCache& cache, Internal::ShaderDataPtr shaderData, Graphics::Controller& gfxController, Graphics::UniquePtr<Graphics::Program>&& gfxProgram, bool modifiesGeometry)
+Program* Program::New(ProgramCache& cache, const Internal::ShaderDataPtr& shaderData, Graphics::Controller& gfxController)
{
- uint32_t programId{0u};
-
- // Get program id and use it as hash for the cache
- // in order to maintain current functionality as long as needed
- gfxController.GetProgramParameter(*gfxProgram, 1, &programId);
-
- size_t shaderHash = programId;
+ size_t shaderHash = shaderData->GetHashValue();
Program* program = cache.GetProgram(shaderHash);
if(nullptr == program)
{
// program not found so create it
- program = new Program(cache, shaderData, gfxController, std::move(gfxProgram), modifiesGeometry);
+ program = new Program(cache, shaderData, gfxController);
+
+ DALI_LOG_INFO(Debug::Filter::gShader, Debug::Verbose, "Program::New() created a unique program:\n VertexShader:\n%s\n\n FragShader:\n%s\n", shaderData->GetVertexShader(), shaderData->GetFragmentShader());
cache.AddProgram(shaderHash, program);
}
return program;
}
-uint32_t Program::RegisterUniform(ConstString name)
-{
- uint32_t index = 0;
- // find the value from cache
- for(; index < static_cast<uint32_t>(mUniformLocations.size()); ++index)
- {
- if(mUniformLocations[index].first == name)
- {
- // name found so return index
- return index;
- }
- }
- // if we get here, index is one past end so push back the new name
- mUniformLocations.push_back(std::make_pair(name, UNIFORM_NOT_QUERIED));
- return index;
-}
-
-bool Program::ModifiesGeometry()
-{
- return mModifiesGeometry;
-}
-
-Program::Program(ProgramCache& cache, Internal::ShaderDataPtr shaderData, Graphics::Controller& controller, Graphics::UniquePtr<Graphics::Program>&& gfxProgram, bool modifiesGeometry)
+Program::Program(ProgramCache& cache, Internal::ShaderDataPtr shaderData, Graphics::Controller& controller)
: mCache(cache),
- mProjectionMatrix(nullptr),
- mViewMatrix(nullptr),
- mProgramId(0),
- mGfxProgram(std::move(gfxProgram)),
+ mGfxProgram(nullptr),
mGfxController(controller),
- mProgramData(shaderData),
- mModifiesGeometry(modifiesGeometry)
+ mProgramData(std::move(shaderData))
{
- // reserve space for standard uniforms
- mUniformLocations.reserve(UNIFORM_TYPE_LAST);
-
- // reset built in uniform names in cache
- for(uint32_t i = 0; i < UNIFORM_TYPE_LAST; ++i)
- {
- RegisterUniform(ConstString(gStdUniforms[i]));
- }
-
- // reset values
- ResetUniformCache();
-
- // Get program id and use it as hash for the cache
- // in order to maintain current functionality as long as needed
- mGfxController.GetProgramParameter(*mGfxProgram, 1, &mProgramId);
-
- BuildReflection(controller.GetProgramReflection(*mGfxProgram.get()));
}
-Program::~Program()
-{
-}
+Program::~Program() = default;
-void Program::ResetUniformCache()
-{
- // reset all gl uniform locations
- for(uint32_t i = 0; i < mUniformLocations.size(); ++i)
- {
- // reset gl program locations and names
- mUniformLocations[i].second = UNIFORM_NOT_QUERIED;
- }
-
- mSamplerUniformLocations.clear();
-
- // reset uniform caches
- mSizeUniformCache.x = mSizeUniformCache.y = mSizeUniformCache.z = 0.f;
-
- for(uint32_t i = 0; i < MAX_UNIFORM_CACHE_SIZE; ++i)
- {
- // GL initializes uniforms to 0
- mUniformCacheInt[i] = 0;
- mUniformCacheFloat[i] = 0.0f;
- mUniformCacheFloat2[i][0] = 0.0f;
- mUniformCacheFloat2[i][1] = 0.0f;
- mUniformCacheFloat4[i][0] = 0.0f;
- mUniformCacheFloat4[i][1] = 0.0f;
- mUniformCacheFloat4[i][2] = 0.0f;
- mUniformCacheFloat4[i][3] = 0.0f;
- }
-}
-
-void Program::BuildReflection(const Graphics::Reflection& graphicsReflection)
+void Program::BuildReflection(const Graphics::Reflection& graphicsReflection, Render::UniformBufferManager& uniformBufferManager)
{
mReflectionDefaultUniforms.clear();
mReflectionDefaultUniforms.resize(NUMBER_OF_DEFAULT_UNIFORMS);
// for each member store data
for(const auto& item : uboInfo.members)
{
+ // Add a hash for the whole name.
+ //
+ // If the name represents an array of basic types, it won't contain an index
+ // operator "[",NN,"]".
+ //
+ // If the name represents an element in an array of structs, it will contain an
+ // index operator, but should be hashed in full.
auto hashValue = CalculateHash(item.name);
mReflection.emplace_back(ReflectionUniformInfo{hashValue, false, item});
mReflection.back().uniformInfo.bufferIndex = i;
// Update default uniforms
- for(auto i = 0u; i < NUMBER_OF_DEFAULT_UNIFORMS; ++i)
+ for(auto j = 0u; j < NUMBER_OF_DEFAULT_UNIFORMS; ++j)
{
- if(hashValue == DEFAULT_UNIFORM_HASHTABLE[i])
+ if(hashValue == DEFAULT_UNIFORM_HASHTABLE[j])
{
- mReflectionDefaultUniforms[i] = mReflection.back();
+ mReflectionDefaultUniforms[j] = mReflection.back();
break;
}
}
}
// add samplers
- auto samplers = graphicsReflection.GetSamplers();
+ auto samplers = graphicsReflection.GetSamplers(); // Only holds first element of arrays without [].
for(const auto& sampler : samplers)
{
mReflection.emplace_back(ReflectionUniformInfo{CalculateHash(sampler.name), false, sampler});
item.hasCollision = hashTest[item.hashValue];
}
}
+
+ mUniformBlockMemoryRequirements.blockSize.resize(uniformBlockCount);
+ mUniformBlockMemoryRequirements.blockSizeAligned.resize(uniformBlockCount);
+ mUniformBlockMemoryRequirements.blockCount = uniformBlockCount;
+ mUniformBlockMemoryRequirements.totalSizeRequired = 0u;
+ mUniformBlockMemoryRequirements.totalCpuSizeRequired = 0u;
+ mUniformBlockMemoryRequirements.totalGpuSizeRequired = 0u;
+
+ for(auto i = 0u; i < uniformBlockCount; ++i)
+ {
+ Graphics::UniformBlockInfo uboInfo;
+ graphicsReflection.GetUniformBlock(i, uboInfo);
+ bool standaloneUniformBlock = (i == 0);
+
+ auto blockSize = graphicsReflection.GetUniformBlockSize(i);
+ uint32_t blockAlignment = uniformBufferManager.GetUniformBlockAlignment(standaloneUniformBlock);
+ auto alignedBlockSize = AlignSize(blockSize, blockAlignment);
+
+ mUniformBlockMemoryRequirements.blockSize[i] = blockSize;
+ mUniformBlockMemoryRequirements.blockSizeAligned[i] = alignedBlockSize;
+
+ mUniformBlockMemoryRequirements.totalSizeRequired += alignedBlockSize;
+ mUniformBlockMemoryRequirements.totalCpuSizeRequired += (standaloneUniformBlock) ? alignedBlockSize : 0;
+ mUniformBlockMemoryRequirements.totalGpuSizeRequired += (standaloneUniformBlock) ? 0 : alignedBlockSize;
+ }
+}
+
+void Program::SetGraphicsProgram(Graphics::UniquePtr<Graphics::Program>&& program, Render::UniformBufferManager& uniformBufferManager)
+{
+ mGfxProgram = std::move(program);
+ BuildReflection(mGfxController.GetProgramReflection(*mGfxProgram.get()), uniformBufferManager);
}
-bool Program::GetUniform(const std::string& name, size_t hashedName, Graphics::UniformInfo& out) const
+bool Program::GetUniform(const std::string_view& name, Hash hashedName, Hash hashedNameNoArray, Graphics::UniformInfo& out) const
{
if(mReflection.empty())
{
return false;
}
+ DALI_ASSERT_DEBUG(hashedName != 0 && "GetUniform() hash is not set");
+
+ // If name contains a "]", but has nothing after, it's an element in an array,
+ // The reflection doesn't contain such elements, it only contains the name without square brackets
+ // Use the hash without array subscript.
- hashedName = !hashedName ? CalculateHash(name, '[') : hashedName;
+ // If the name contains a "]" anywhere but the end, it's a structure element. The reflection
+ // does contain such elements, so use normal hash.
+ Hash hash = hashedName;
+ std::string_view match = name;
+
+ int arrayIndex = 0;
+
+ if(!name.empty() && name.back() == ']')
+ {
+ auto pos = name.rfind("[");
+ if(pos != std::string::npos)
+ {
+ hash = hashedNameNoArray;
+ match = name.substr(0, pos); // Remove subscript
+ arrayIndex = atoi(&name[pos + 1]);
+ }
+ }
for(const ReflectionUniformInfo& item : mReflection)
{
- if(item.hashValue == hashedName)
+ if(item.hashValue == hash)
{
- if(!item.hasCollision || item.uniformInfo.name == name)
+ if(!item.hasCollision || item.uniformInfo.name == match)
{
out = item.uniformInfo;
+
+ // Array out of bounds
+ if(item.uniformInfo.elementCount > 0 && arrayIndex >= int(item.uniformInfo.elementCount))
+ {
+ DALI_LOG_ERROR("Uniform %s, array index out of bound [%d >= %d]!\n",
+ item.uniformInfo.name.c_str(),
+ int(arrayIndex),
+ int(item.uniformInfo.elementCount));
+ return false;
+ }
return true;
}
else