{
name = uniform.name.substr(0, iter);
auto arrayCount = std::stoi(uniform.name.substr(iter + 1));
+ iter = uniform.name.find("]");
+ std::string suffix;
+ if(iter != std::string::npos && iter + 1 != uniform.name.length())
+ {
+ suffix = uniform.name.substr(iter + 1); // If there is a suffix, it means its an element of an array of struct
+ }
+
for(int i = 0; i < arrayCount; ++i)
{
std::stringstream nss;
- nss << name << "[" << i << "]";
+ nss << name << "[" << i << "]" << suffix;
GetUniformLocation(program, nss.str().c_str()); // Generate a GL loc per element
}
}
for(const auto& data : mCustomUniforms)
{
fprintf(stderr, "\ncustom uniforms: %s\n", data.name.c_str());
- mDefaultUniformBlock.members.emplace_back();
- auto& item = mDefaultUniformBlock.members.back();
auto iter = data.name.find("[", 0);
int numElements = 1;
{
numElements = 1;
}
-
- item.name = baseName;
- item.binding = 0;
- item.bufferIndex = 0;
- item.uniformClass = Graphics::UniformClass::UNIFORM;
- item.type = data.type;
- item.numElements = numElements;
-
- for(int i = 0; i < numElements; ++i)
+ iter = data.name.find("]");
+ std::string suffix;
+ if(iter != std::string::npos && iter + 1 != data.name.length())
{
- std::stringstream elementNameStream;
- elementNameStream << baseName << "[" << i << "]";
+ suffix = data.name.substr(iter + 1); // If there is a suffix, it means it is an element of an array of struct
+ }
- item.locations.push_back(gl.GetUniformLocation(programId, elementNameStream.str().c_str()));
- item.offsets.push_back(offset);
- offset += GetSizeForType(data.type);
+ if(!suffix.empty())
+ {
+ // Write multiple items
+ for(int i = 0; i < numElements; ++i)
+ {
+ std::stringstream elementNameStream;
+ elementNameStream << baseName << "[" << i << "]" << suffix;
+ mDefaultUniformBlock.members.emplace_back();
+ auto& item = mDefaultUniformBlock.members.back();
+ item.name = elementNameStream.str();
+ item.binding = 0;
+ item.offsets.push_back(offset);
+ item.locations.push_back(gl.GetUniformLocation(programId, elementNameStream.str().c_str()));
+ item.bufferIndex = 0;
+ item.uniformClass = Graphics::UniformClass::UNIFORM;
+ item.type = data.type;
+ offset += GetSizeForType(data.type);
+ }
+ }
+ else
+ {
+ // Write 1 item with multiple elements
+ mDefaultUniformBlock.members.emplace_back();
+ auto& item = mDefaultUniformBlock.members.back();
+
+ item.name = baseName;
+ item.binding = 0;
+ item.bufferIndex = 0;
+ item.uniformClass = Graphics::UniformClass::UNIFORM;
+ item.type = data.type;
+ item.numElements = numElements;
+
+ for(int i = 0; i < numElements; ++i)
+ {
+ std::stringstream elementNameStream;
+ elementNameStream << baseName << "[" << i << "]";
+ item.locations.push_back(gl.GetUniformLocation(programId, elementNameStream.str().c_str()));
+ item.offsets.push_back(offset);
+ offset += GetSizeForType(data.type);
+ }
}
}
else
{
+ // Write 1 item with 1 element
+ mDefaultUniformBlock.members.emplace_back();
+ auto& item = mDefaultUniformBlock.members.back();
item.name = data.name;
item.binding = 0;
item.offsets.push_back(offset);
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
END_TEST;
}
+
+int UtcDaliRendererUniformArrayOfStruct(void)
+{
+ TestApplication application;
+ tet_infoline("Test that uniforms that are elements of arrays of structs can be accessed");
+
+ std::vector<UniformData> customUniforms{{"arrayof[10].color", Property::VECTOR4},
+ {"arrayof[10].position", Property::VECTOR2},
+ {"arrayof[10].normal", Property::VECTOR3}};
+
+ application.GetGraphicsController().AddCustomUniforms(customUniforms);
+
+ Geometry geometry = CreateQuadGeometry();
+ Shader shader = Shader::New("vertexSrc", "fragmentSrc");
+ Renderer renderer = Renderer::New(geometry, shader);
+ Actor actor = Actor::New();
+ actor.AddRenderer(renderer);
+ actor[Actor::Property::SIZE] = Vector2(120, 120);
+ application.GetScene().Add(actor);
+
+ // Define some properties to match the custom uniforms.
+ // Ensure they can be written & read back from the abstraction.
+
+ struct UniformIndexPair
+ {
+ Property::Index index;
+ std::string name;
+ UniformIndexPair(Property::Index index, std::string name)
+ : index(index),
+ name(name)
+ {
+ }
+ };
+ std::vector<UniformIndexPair> uniformIndices;
+
+ std::ostringstream oss;
+ for(int i = 0; i < 10; ++i)
+ {
+ Property::Index index;
+ oss << "arrayof[" << i << "].color";
+ Vector4 color = Color::WHITE;
+ color.r = 25.5f * i;
+ index = renderer.RegisterProperty(oss.str(), color);
+ uniformIndices.emplace_back(index, oss.str());
+
+ oss.str("");
+ oss.clear();
+ oss << "arrayof[" << i << "].position";
+ Vector2 pos(i, 10 + i * 5);
+ index = renderer.RegisterProperty(oss.str(), pos);
+ uniformIndices.emplace_back(index, oss.str());
+
+ oss.str("");
+ oss.clear();
+ oss << "arrayof[" << i << "].normal";
+ Vector3 normal(i, i * 10, i * 100);
+ index = renderer.RegisterProperty(oss.str(), normal);
+ uniformIndices.emplace_back(index, oss.str());
+ oss.str("");
+ oss.clear();
+ }
+ auto& gl = application.GetGlAbstraction();
+ TraceCallStack& callStack = gl.GetSetUniformTrace();
+ gl.EnableSetUniformCallTrace(true);
+
+ application.SendNotification();
+ application.Render();
+
+ // Check that the uniforms match.
+ TraceCallStack::NamedParams params;
+ for(auto& uniformInfo : uniformIndices)
+ {
+ Property::Value value = renderer.GetProperty(uniformInfo.index);
+ switch(value.GetType())
+ {
+ case Property::VECTOR2:
+ {
+ DALI_TEST_CHECK(callStack.FindMethodAndGetParameters(uniformInfo.name, params));
+ Vector2 setValue;
+ DALI_TEST_CHECK(gl.GetUniformValue<Vector2>(uniformInfo.name.c_str(), setValue));
+ DALI_TEST_EQUALS(value.Get<Vector2>(), setValue, 0.001f, TEST_LOCATION);
+ break;
+ }
+ case Property::VECTOR3:
+ {
+ DALI_TEST_CHECK(callStack.FindMethodAndGetParameters(uniformInfo.name, params));
+ Vector3 setValue;
+ DALI_TEST_CHECK(gl.GetUniformValue<Vector3>(uniformInfo.name.c_str(), setValue));
+ DALI_TEST_EQUALS(value.Get<Vector3>(), setValue, 0.001f, TEST_LOCATION);
+ break;
+ }
+ case Property::VECTOR4:
+ {
+ DALI_TEST_CHECK(callStack.FindMethodAndGetParameters(uniformInfo.name, params));
+ Vector4 setValue;
+ DALI_TEST_CHECK(gl.GetUniformValue<Vector4>(uniformInfo.name.c_str(), setValue));
+ DALI_TEST_EQUALS(value.Get<Vector4>(), setValue, 0.001f, TEST_LOCATION);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ // There is a hash in the property name's uniform map: check this in debugger
+ // There is a hash in the reflection. Check this in the debugger.
+
+ // Check that the reflection contains individual locs for each array entry's struct element
+ // and that it hashes the whole string
+
+ // Ensure that the property name's hash is also for the whole string.
+
+ END_TEST;
+}
{
auto uniformInfo = Graphics::UniformInfo{};
auto uniformFound = program.GetUniform(uniform.uniformName.GetCString(),
- uniform.uniformNameHashNoArray ? uniform.uniformNameHashNoArray
- : uniform.uniformNameHash,
+ uniform.uniformNameHash,
+ uniform.uniformNameHashNoArray,
uniformInfo);
uniform.uniformOffset = uniformInfo.offset;
Render::PipelineCache* mPipelineCache{nullptr};
- using Hash = unsigned long;
+ using Hash = std::size_t;
typedef const float& (PropertyInputImpl::*FuncGetter)(BufferIndex) const;
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
// 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});
// Calculate size of memory for uniform blocks
mUniformBlockRequirements.totalSizeRequired = 0;
- mUniformBlockRequirements.blockCount = graphicsReflection.GetUniformBlockCount();
- for (auto i = 0u; i < mUniformBlockRequirements.blockCount; ++i)
+ mUniformBlockRequirements.blockCount = graphicsReflection.GetUniformBlockCount();
+ for(auto i = 0u; i < mUniformBlockRequirements.blockCount; ++i)
{
auto blockSize = GetUniformBufferDataAlignment(graphicsReflection.GetUniformBlockSize(i));
mUniformBlockRequirements.totalSizeRequired += blockSize;
}
}
-void Program::SetGraphicsProgram( Graphics::UniquePtr<Graphics::Program>&& program )
+void Program::SetGraphicsProgram(Graphics::UniquePtr<Graphics::Program>&& program)
{
mGfxProgram = std::move(program);
BuildReflection(mGfxController.GetProgramReflection(*mGfxProgram.get()));
}
-
-bool Program::GetUniform(const std::string& name, size_t hashedName, Graphics::UniformInfo& out) const
+bool Program::GetUniform(const std::string& 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.
+
+ // 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;
+ const std::string* match = &name;
- hashedName = !hashedName ? CalculateHash(name, '[') : hashedName;
+ std::string baseName;
+ if(!name.empty() && name.back() == ']')
+ {
+ hash = hashedNameNoArray;
+ auto pos = name.rfind("[");
+ baseName = name.substr(0, pos - 1); // Remove subscript
+ match = &baseName;
+ }
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;
return true;
#define DALI_INTERNAL_PROGRAM_H
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
class Program
{
public:
+ using Hash = std::size_t;
+
/**
* Indices of default uniforms
*/
* @param[in] gfxController Reference to valid graphics Controller object
* @return pointer to the program
*/
- static Program* New(ProgramCache& cache, Internal::ShaderDataPtr shaderData, Graphics::Controller& gfxController);
+ static Program* New(ProgramCache& cache, Internal::ShaderDataPtr shaderData, Graphics::Controller& gfxController);
/**
* Set the projection matrix that has currently been sent
return mGfxProgram.get();
}
- void SetGraphicsProgram( Graphics::UniquePtr<Graphics::Program>&& program );
+ void SetGraphicsProgram(Graphics::UniquePtr<Graphics::Program>&& program);
/**
* Retrieves uniform data.
*
* @param name Name of uniform
* @param hashedName Hash value from name or 0 if unknown
+ * @param hashedNameNoArray Hash value from name without array index & trailing string, or 0 if unknown
* @param out Reference to output structure
*
* @return False when uniform is not found or due to hash collision the result is ambiguous
*/
- bool GetUniform(const std::string& name, size_t hashedName, Graphics::UniformInfo& out) const;
+ bool GetUniform(const std::string& name, Hash hashedName, Hash hashedNameNoArray, Graphics::UniformInfo& out) const;
/**
* Retrieves default uniform
using UniformReflectionContainer = std::vector<ReflectionUniformInfo>;
- UniformReflectionContainer mReflection{}; ///< Contains reflection build per program
- UniformReflectionContainer mReflectionDefaultUniforms{}; ///< Contains default uniforms
- UniformBlockMemoryRequirements mUniformBlockRequirements{}; ///< Memory requirements for uniform blocks
+ UniformReflectionContainer mReflection{}; ///< Contains reflection build per program
+ UniformReflectionContainer mReflectionDefaultUniforms{}; ///< Contains default uniforms
+ UniformBlockMemoryRequirements mUniformBlockRequirements{}; ///< Memory requirements for uniform blocks
};
} // namespace Internal
#define DALI_INTERNAL_SCENE_GRAPH_UNIFORM_MAP_H
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
arrayIndex(0u)
{
// Look for array index closing bracket
- auto pos = theUniformName.GetStringView().rfind("]");
+ auto nameStringView = theUniformName.GetStringView();
+ auto pos = nameStringView.rfind("]");
- // If found, extract the array index and store it
+ // If found, extract the array index and store it, if it's an element in an array of basic types.
if(pos != std::string::npos)
{
- auto pos0 = theUniformName.GetStringView().rfind("[", pos);
- arrayIndex = atoi(theUniformName.GetCString() + pos0 + 1);
+ auto pos0 = theUniformName.GetStringView().rfind("[", pos);
+ if(pos == nameStringView.length() - 1) // if element is in struct, don't set array index.
+ {
+ arrayIndex = atoi(theUniformName.GetCString() + pos0 + 1);
+ }
// Calculate hash from name without array index
uniformNameHashNoArray = Dali::CalculateHash(theUniformName.GetStringView().substr(0, pos0).data(), '[');
}