+ }
+ }
+ else
+ {
+ // BindVertexAttributes failed. Reset cached geometry.
+ ReuseLatestBindedVertexAttributes(nullptr);
+ }
+
+ return drawn;
+}
+
+std::size_t Renderer::BuildUniformIndexMap(BufferIndex bufferIndex, const SceneGraph::NodeDataProvider& node, const Vector3& size, Program& program)
+{
+ // Check if the map has changed
+ DALI_ASSERT_DEBUG(mRenderDataProvider && "No Uniform map data provider available");
+
+ const SceneGraph::UniformMapDataProvider& uniformMapDataProvider = mRenderDataProvider->GetUniformMapDataProvider();
+ const SceneGraph::CollectedUniformMap& uniformMap = uniformMapDataProvider.GetCollectedUniformMap();
+ const SceneGraph::UniformMap& uniformMapNode = node.GetNodeUniformMap();
+
+ bool updateMaps;
+
+ // Usual case is to only have 1 node, however we do allow multiple nodes to reuse the same
+ // renderer, so we have to cache uniform map per render item (node / renderer pair).
+
+ // Specially, if node don't have uniformMap, we mark nodePtr as nullptr.
+ // So, all nodes without uniformMap will share same UniformIndexMap, contains only render data providers.
+ const auto nodePtr = uniformMapNode.Count() ? &node : nullptr;
+
+ const auto nodeChangeCounter = nodePtr ? uniformMapNode.GetChangeCounter() : 0;
+ const auto renderItemMapChangeCounter = uniformMap.GetChangeCounter();
+
+ auto iter = std::find_if(mNodeIndexMap.begin(), mNodeIndexMap.end(), [nodePtr](RenderItemLookup& element) { return element.node == nodePtr; });
+
+ std::size_t renderItemMapIndex;
+ if(iter == mNodeIndexMap.end())
+ {
+ renderItemMapIndex = mUniformIndexMaps.size();
+ RenderItemLookup renderItemLookup;
+ renderItemLookup.node = nodePtr;
+ renderItemLookup.index = renderItemMapIndex;
+ renderItemLookup.nodeChangeCounter = nodeChangeCounter;
+ renderItemLookup.renderItemMapChangeCounter = renderItemMapChangeCounter;
+ mNodeIndexMap.emplace_back(renderItemLookup);
+
+ updateMaps = true;
+ mUniformIndexMaps.resize(mUniformIndexMaps.size() + 1);
+ }
+ else
+ {
+ renderItemMapIndex = iter->index;
+
+ updateMaps = (nodeChangeCounter != iter->nodeChangeCounter) ||
+ (renderItemMapChangeCounter != iter->renderItemMapChangeCounter) ||
+ (mUniformIndexMaps[renderItemMapIndex].size() == 0);
+
+ iter->nodeChangeCounter = nodeChangeCounter;
+ iter->renderItemMapChangeCounter = renderItemMapChangeCounter;
+ }
+
+ if(updateMaps || mShaderChanged)
+ {
+ // Reset shader pointer
+ mShaderChanged = false;
+
+ const uint32_t mapCount = uniformMap.Count();
+ const uint32_t mapNodeCount = uniformMapNode.Count();
+
+ mUniformIndexMaps[renderItemMapIndex].clear(); // Clear contents, but keep memory if we don't change size
+ mUniformIndexMaps[renderItemMapIndex].resize(mapCount + mapNodeCount);
+
+ // Copy uniform map into mUniformIndexMap
+ uint32_t mapIndex = 0;
+ for(; mapIndex < mapCount; ++mapIndex)
+ {
+ mUniformIndexMaps[renderItemMapIndex][mapIndex].propertyValue = uniformMap.mUniformMap[mapIndex].propertyPtr;
+ mUniformIndexMaps[renderItemMapIndex][mapIndex].uniformName = uniformMap.mUniformMap[mapIndex].uniformName;
+ mUniformIndexMaps[renderItemMapIndex][mapIndex].uniformNameHash = uniformMap.mUniformMap[mapIndex].uniformNameHash;
+ mUniformIndexMaps[renderItemMapIndex][mapIndex].uniformNameHashNoArray = uniformMap.mUniformMap[mapIndex].uniformNameHashNoArray;
+ mUniformIndexMaps[renderItemMapIndex][mapIndex].arrayIndex = uniformMap.mUniformMap[mapIndex].arrayIndex;
+ }
+
+ for(uint32_t nodeMapIndex = 0; nodeMapIndex < mapNodeCount; ++nodeMapIndex)
+ {
+ auto hash = uniformMapNode[nodeMapIndex].uniformNameHash;
+ auto& name = uniformMapNode[nodeMapIndex].uniformName;
+ bool found(false);
+ for(uint32_t i = 0; i < mapCount; ++i)
+ {
+ if(mUniformIndexMaps[renderItemMapIndex][i].uniformNameHash == hash &&
+ mUniformIndexMaps[renderItemMapIndex][i].uniformName == name)
+ {
+ mUniformIndexMaps[renderItemMapIndex][i].propertyValue = uniformMapNode[nodeMapIndex].propertyPtr;
+ found = true;
+ break;
+ }
+ }
+
+ if(!found)