X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali%2Finternal%2Frender%2Frenderers%2Frender-renderer.cpp;h=45aa582d4e2da75fbcc8a71ecd0faea97c0e7872;hb=a513234144a775134eff3a24144983a5e374d1d5;hp=4a2a786a4f7800e254ded37b4c5fd4b90642cf16;hpb=03322c06634902f9ac347f069609eb23d8abb281;p=platform%2Fcore%2Fuifw%2Fdali-core.git diff --git a/dali/internal/render/renderers/render-renderer.cpp b/dali/internal/render/renderers/render-renderer.cpp index 4a2a786..45aa582 100644 --- a/dali/internal/render/renderers/render-renderer.cpp +++ b/dali/internal/render/renderers/render-renderer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 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. @@ -22,9 +22,13 @@ #include #include #include +#include +#include +#include #include #include #include +#include #include #include #include @@ -34,14 +38,14 @@ #include #include #include -#include +#include namespace Dali::Internal { namespace { // Helper to get the property value getter by type -typedef const float&(PropertyInputImpl::*FuncGetter )(BufferIndex) const; +typedef const float& (PropertyInputImpl::*FuncGetter)(BufferIndex) const; constexpr FuncGetter GetPropertyValueGetter(Property::Type type) { switch(type) @@ -89,18 +93,42 @@ constexpr FuncGetter GetPropertyValueGetter(Property::Type type) * Helper function that returns size of uniform datatypes based * on property type. */ -constexpr int GetPropertyValueSizeForUniform( Property::Type type ) +constexpr int GetPropertyValueSizeForUniform(Property::Type type) { switch(type) { - case Property::Type::BOOLEAN:{ return sizeof(bool);} - case Property::Type::FLOAT:{ return sizeof(float);} - case Property::Type::INTEGER:{ return sizeof(int);} - case Property::Type::VECTOR2:{ return sizeof(Vector2);} - case Property::Type::VECTOR3:{ return sizeof(Vector3);} - case Property::Type::VECTOR4:{ return sizeof(Vector4);} - case Property::Type::MATRIX3:{ return sizeof(Matrix3);} - case Property::Type::MATRIX:{ return sizeof(Matrix);} + case Property::Type::BOOLEAN: + { + return sizeof(bool); + } + case Property::Type::FLOAT: + { + return sizeof(float); + } + case Property::Type::INTEGER: + { + return sizeof(int); + } + case Property::Type::VECTOR2: + { + return sizeof(Vector2); + } + case Property::Type::VECTOR3: + { + return sizeof(Vector3); + } + case Property::Type::VECTOR4: + { + return sizeof(Vector4); + } + case Property::Type::MATRIX3: + { + return sizeof(Matrix3); + } + case Property::Type::MATRIX: + { + return sizeof(Matrix); + } default: { return 0; @@ -118,22 +146,57 @@ inline uint32_t GetUniformBufferDataAlignment(uint32_t dataSize) return ((dataSize / 256u) + ((dataSize % 256u) ? 1u : 0u)) * 256u; } +/** + * @brief Store latest binded RenderGeometry, and help that we can skip duplicated vertex attributes bind. + * + * @param[in] geometry Current geometry to be used, or nullptr if render finished + * @return True if we can reuse latest binded vertex attributes. False otherwise. + */ +inline bool ReuseLatestBindedVertexAttributes(const Render::Geometry* geometry) +{ + static const Render::Geometry* gLatestVertexBindedGeometry = nullptr; + if(gLatestVertexBindedGeometry == geometry) + { + return true; + } + gLatestVertexBindedGeometry = geometry; + return false; +} + } // namespace namespace Render { -Renderer* Renderer::New(SceneGraph::RenderDataProvider* dataProvider, - Render::Geometry* geometry, - uint32_t blendingBitmask, - const Vector4& blendColor, - FaceCullingMode::Type faceCullingMode, - bool preMultipliedAlphaEnabled, - DepthWriteMode::Type depthWriteMode, - DepthTestMode::Type depthTestMode, - DepthFunction::Type depthFunction, - StencilParameters& stencilParameters) +namespace +{ +MemoryPoolObjectAllocator gRenderRendererMemoryPool; +} + +void Renderer::PrepareCommandBuffer() { - return new Renderer(dataProvider, geometry, blendingBitmask, blendColor, faceCullingMode, preMultipliedAlphaEnabled, depthWriteMode, depthTestMode, depthFunction, stencilParameters); + // Reset latest geometry informations, So we can bind the first of geometry. + ReuseLatestBindedVertexAttributes(nullptr); + + // todo : Fill here as many caches as we can store for reduce the number of command buffers +} + +RendererKey Renderer::NewKey(SceneGraph::RenderDataProvider* dataProvider, + Render::Geometry* geometry, + uint32_t blendingBitmask, + const Vector4& blendColor, + FaceCullingMode::Type faceCullingMode, + bool preMultipliedAlphaEnabled, + DepthWriteMode::Type depthWriteMode, + DepthTestMode::Type depthTestMode, + DepthFunction::Type depthFunction, + StencilParameters& stencilParameters) +{ + void* ptr = gRenderRendererMemoryPool.AllocateRawThreadSafe(); + auto key = gRenderRendererMemoryPool.GetKeyFromPtr(static_cast(ptr)); + + // Use placement new to construct renderer. + new(ptr) Renderer(dataProvider, geometry, blendingBitmask, blendColor, faceCullingMode, preMultipliedAlphaEnabled, depthWriteMode, depthTestMode, depthFunction, stencilParameters); + return RendererKey(key); } Renderer::Renderer(SceneGraph::RenderDataProvider* dataProvider, @@ -150,8 +213,6 @@ Renderer::Renderer(SceneGraph::RenderDataProvider* dataProvider, mRenderDataProvider(dataProvider), mGeometry(geometry), mProgramCache(nullptr), - mUniformIndexMap(), - mUniformsHash(), mStencilParameters(stencilParameters), mBlendingOptions(), mIndexedDrawFirstElement(0), @@ -161,8 +222,7 @@ Renderer::Renderer(SceneGraph::RenderDataProvider* dataProvider, mDepthWriteMode(depthWriteMode), mDepthTestMode(depthTestMode), mPremultipliedAlphaEnabled(preMultipliedAlphaEnabled), - mShaderChanged(false), - mUpdated(true) + mShaderChanged(false) { if(blendingBitmask != 0u) { @@ -183,11 +243,21 @@ void Renderer::Initialize(Graphics::Controller& graphicsController, ProgramCache Renderer::~Renderer() = default; +void Renderer::operator delete(void* ptr) +{ + gRenderRendererMemoryPool.FreeThreadSafe(static_cast(ptr)); +} + +Renderer* Renderer::Get(RendererKey::KeyType rendererKey) +{ + return gRenderRendererMemoryPool.GetPtrFromKey(rendererKey); +} + void Renderer::SetGeometry(Render::Geometry* geometry) { - mGeometry = geometry; - mUpdated = true; + mGeometry = geometry; } + void Renderer::SetDrawCommands(Dali::DevelRenderer::DrawCommand* pDrawCommands, uint32_t size) { mDrawCommands.clear(); @@ -198,26 +268,35 @@ void Renderer::BindTextures(Graphics::CommandBuffer& commandBuffer, Vector& samplers(mRenderDataProvider->GetSamplers()); - std::vector& textures(mRenderDataProvider->GetTextures()); + auto textures(mRenderDataProvider->GetTextures()); + auto samplers(mRenderDataProvider->GetSamplers()); std::vector textureBindings; - for(uint32_t i = 0; i < static_cast(textures.size()); ++i) // not expecting more than uint32_t of textures + + if(textures != nullptr) { - if(textures[i] && textures[i]->GetGraphicsObject()) + const std::uint32_t texturesCount(static_cast(textures->Count())); + textureBindings.reserve(texturesCount); + + for(uint32_t i = 0; i < texturesCount; ++i) // not expecting more than uint32_t of textures { - // if the sampler exists, - // if it's default, delete the graphics object - // otherwise re-initialize it if dirty + if((*textures)[i] && (*textures)[i]->GetGraphicsObject()) + { + Graphics::Texture* graphicsTexture = (*textures)[i]->GetGraphicsObject(); + // if the sampler exists, + // if it's default, delete the graphics object + // otherwise re-initialize it if dirty - const Graphics::Sampler* graphicsSampler = (samplers[i] ? samplers[i]->GetGraphicsObject() - : nullptr); + const Graphics::Sampler* graphicsSampler = samplers ? ((*samplers)[i] ? (*samplers)[i]->GetGraphicsObject() + : nullptr) + : nullptr; - boundTextures.PushBack(textures[i]->GetGraphicsObject()); - const Graphics::TextureBinding textureBinding{textures[i]->GetGraphicsObject(), graphicsSampler, textureUnit}; - textureBindings.push_back(textureBinding); + boundTextures.PushBack(graphicsTexture); + const Graphics::TextureBinding textureBinding{graphicsTexture, graphicsSampler, textureUnit}; + textureBindings.push_back(textureBinding); - ++textureUnit; + ++textureUnit; + } } } @@ -230,49 +309,41 @@ void Renderer::BindTextures(Graphics::CommandBuffer& commandBuffer, Vector(new RenderCallbackInput); + } + + Graphics::DrawNativeInfo info{}; + info.api = Graphics::DrawNativeAPI::GLES; + info.callback = &static_cast(*mRenderCallback); + info.userData = mRenderCallbackInput.get(); + + // Set storage for the context to be used + info.glesNativeInfo.eglSharedContextStoragePointer = &mRenderCallbackInput->eglContext; + info.reserved = nullptr; + + auto& textureResources = mRenderCallback->GetTextureResources(); + + if(!textureResources.empty()) + { + mRenderCallbackTextureBindings.clear(); + mRenderCallbackInput->textureBindings.resize(textureResources.size()); + auto i = 0u; + for(auto& texture : textureResources) + { + auto& textureImpl = GetImplementation(texture); + auto graphicsTexture = textureImpl.GetRenderTextureKey()->GetGraphicsObject(); + + auto properties = mGraphicsController->GetTextureProperties(*graphicsTexture); + + mRenderCallbackTextureBindings.emplace_back(graphicsTexture); + mRenderCallbackInput->textureBindings[i++] = properties.nativeHandle; + } + info.textureCount = mRenderCallbackTextureBindings.size(); + info.textureList = mRenderCallbackTextureBindings.data(); + } + + // pass render callback input + mRenderCallbackInput->size = size; + mRenderCallbackInput->projection = projectionMatrix; + + MatrixUtils::MultiplyProjectionMatrix(mRenderCallbackInput->mvp, modelViewMatrix, projectionMatrix); + + // submit draw + commandBuffer.DrawNative(&info); + return true; + } + // Prepare commands std::vector commands; for(auto& cmd : mDrawCommands) @@ -431,42 +542,46 @@ bool Renderer::Render(Graphics::CommandBuffer& comma } // Create Program - ShaderDataPtr shaderData = mRenderDataProvider->GetShader().GetShaderData(); - const std::vector& vertShader = shaderData->GetShaderForPipelineStage(Graphics::PipelineStage::VERTEX_SHADER); - const std::vector& fragShader = shaderData->GetShaderForPipelineStage(Graphics::PipelineStage::FRAGMENT_SHADER); - Dali::Graphics::Shader& vertexShader = mShaderCache->GetShader( - vertShader, - Graphics::PipelineStage::VERTEX_SHADER, - shaderData->GetSourceMode()); - - Dali::Graphics::Shader& fragmentShader = mShaderCache->GetShader( - fragShader, - Graphics::PipelineStage::FRAGMENT_SHADER, - shaderData->GetSourceMode()); - - std::vector shaderStates{ - Graphics::ShaderState() - .SetShader(vertexShader) - .SetPipelineStage(Graphics::PipelineStage::VERTEX_SHADER), - Graphics::ShaderState() - .SetShader(fragmentShader) - .SetPipelineStage(Graphics::PipelineStage::FRAGMENT_SHADER)}; - - auto createInfo = Graphics::ProgramCreateInfo(); - createInfo.SetShaderState(shaderStates); - - auto graphicsProgram = mGraphicsController->CreateProgram(createInfo, nullptr); - Program* program = Program::New(*mProgramCache, - shaderData, - *mGraphicsController, - std::move(graphicsProgram)); + ShaderDataPtr shaderData = mRenderDataProvider->GetShader().GetShaderData(); + Program* program = Program::New(*mProgramCache, + shaderData, + *mGraphicsController); if(!program) { - DALI_LOG_ERROR("Failed to get program for shader at address %p.\n", reinterpret_cast(&mRenderDataProvider->GetShader())); + DALI_LOG_ERROR("Failed to get program for shader at address %p.\n", reinterpret_cast(&mRenderDataProvider->GetShader())); return false; } + // If program doesn't have Gfx program object assigned yet, prepare it. + if(!program->GetGraphicsProgramPtr()) + { + const std::vector& vertShader = shaderData->GetShaderForPipelineStage(Graphics::PipelineStage::VERTEX_SHADER); + const std::vector& fragShader = shaderData->GetShaderForPipelineStage(Graphics::PipelineStage::FRAGMENT_SHADER); + Dali::Graphics::Shader& vertexShader = mShaderCache->GetShader( + vertShader, + Graphics::PipelineStage::VERTEX_SHADER, + shaderData->GetSourceMode()); + + Dali::Graphics::Shader& fragmentShader = mShaderCache->GetShader( + fragShader, + Graphics::PipelineStage::FRAGMENT_SHADER, + shaderData->GetSourceMode()); + + std::vector shaderStates{ + Graphics::ShaderState() + .SetShader(vertexShader) + .SetPipelineStage(Graphics::PipelineStage::VERTEX_SHADER), + Graphics::ShaderState() + .SetShader(fragmentShader) + .SetPipelineStage(Graphics::PipelineStage::FRAGMENT_SHADER)}; + + auto createInfo = Graphics::ProgramCreateInfo(); + createInfo.SetShaderState(shaderStates); + auto graphicsProgram = mGraphicsController->CreateProgram(createInfo, nullptr); + program->SetGraphicsProgram(std::move(graphicsProgram)); + } + // Prepare the graphics pipeline. This may either re-use an existing pipeline or create a new one. auto& pipeline = PrepareGraphicsPipeline(*program, instruction, node, blend); @@ -474,95 +589,138 @@ bool Renderer::Render(Graphics::CommandBuffer& comma BindTextures(commandBuffer, boundTextures); - BuildUniformIndexMap(bufferIndex, node, size, *program); + std::size_t nodeIndex = BuildUniformIndexMap(bufferIndex, node, size, *program); - WriteUniformBuffer(bufferIndex, commandBuffer, program, instruction, node, modelMatrix, modelViewMatrix, viewMatrix, projectionMatrix, size); + WriteUniformBuffer(bufferIndex, commandBuffer, program, instruction, node, modelMatrix, modelViewMatrix, viewMatrix, projectionMatrix, size, nodeIndex); bool drawn = false; // Draw can fail if there are no vertex buffers or they haven't been uploaded yet // @todo We should detect this case much earlier to prevent unnecessary work - if(mDrawCommands.empty()) + // Reuse latest binded vertex attributes location, or Bind buffers to attribute locations. + if(ReuseLatestBindedVertexAttributes(mGeometry) || mGeometry->BindVertexAttributes(commandBuffer)) { - drawn = mGeometry->Draw(*mGraphicsController, commandBuffer, mIndexedDrawFirstElement, mIndexedDrawElementsCount); + if(mDrawCommands.empty()) + { + drawn = mGeometry->Draw(*mGraphicsController, commandBuffer, mIndexedDrawFirstElement, mIndexedDrawElementsCount); + } + else + { + for(auto& cmd : commands) + { + drawn |= mGeometry->Draw(*mGraphicsController, commandBuffer, cmd->firstIndex, cmd->elementCount); + } + } } else { - for(auto& cmd : commands) - { - mGeometry->Draw(*mGraphicsController, commandBuffer, cmd->firstIndex, cmd->elementCount); - } + // BindVertexAttributes failed. Reset cached geometry. + ReuseLatestBindedVertexAttributes(nullptr); } - mUpdated = false; return drawn; } -void Renderer::BuildUniformIndexMap(BufferIndex bufferIndex, const SceneGraph::NodeDataProvider& node, const Vector3& size, Program& program) +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->GetUniformMap(); + const SceneGraph::UniformMapDataProvider& uniformMapDataProvider = mRenderDataProvider->GetUniformMapDataProvider(); + const SceneGraph::CollectedUniformMap& uniformMap = uniformMapDataProvider.GetCollectedUniformMap(); + const SceneGraph::UniformMap& uniformMapNode = node.GetNodeUniformMap(); + + bool updateMaps; - if(uniformMapDataProvider.GetUniformMapChanged(bufferIndex) || - node.GetUniformMapChanged(bufferIndex) || - mUniformIndexMap.Count() == 0 || - mShaderChanged) + // 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 SceneGraph::CollectedUniformMap& uniformMap = uniformMapDataProvider.GetUniformMap(bufferIndex); - const SceneGraph::CollectedUniformMap& uniformMapNode = node.GetUniformMap(bufferIndex); + const uint32_t mapCount = uniformMap.Count(); + const uint32_t mapNodeCount = uniformMapNode.Count(); - auto maxMaps = static_cast(uniformMap.Count() + uniformMapNode.Count()); // 4,294,967,295 maps should be enough - mUniformIndexMap.Clear(); // Clear contents, but keep memory if we don't change size - mUniformIndexMap.Resize(maxMaps); + 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 < uniformMap.Count(); ++mapIndex) + for(; mapIndex < mapCount; ++mapIndex) { - mUniformIndexMap[mapIndex].propertyValue = uniformMap[mapIndex].propertyPtr; - mUniformIndexMap[mapIndex].uniformName = uniformMap[mapIndex].uniformName; - mUniformIndexMap[mapIndex].uniformNameHash = uniformMap[mapIndex].uniformNameHash; - mUniformIndexMap[mapIndex].uniformNameHashNoArray = uniformMap[mapIndex].uniformNameHashNoArray; - mUniformIndexMap[mapIndex].arrayIndex = uniformMap[mapIndex].arrayIndex; + 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 < uniformMapNode.Count(); ++nodeMapIndex) + 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 < uniformMap.Count(); ++i) + for(uint32_t i = 0; i < mapCount; ++i) { - if(mUniformIndexMap[i].uniformNameHash == hash && - mUniformIndexMap[i].uniformName == name) + if(mUniformIndexMaps[renderItemMapIndex][i].uniformNameHash == hash && + mUniformIndexMaps[renderItemMapIndex][i].uniformName == name) { - mUniformIndexMap[i].propertyValue = uniformMapNode[nodeMapIndex].propertyPtr; - found = true; + mUniformIndexMaps[renderItemMapIndex][i].propertyValue = uniformMapNode[nodeMapIndex].propertyPtr; + found = true; break; } } if(!found) { - mUniformIndexMap[mapIndex].propertyValue = uniformMapNode[nodeMapIndex].propertyPtr; - mUniformIndexMap[mapIndex].uniformName = uniformMapNode[nodeMapIndex].uniformName; - mUniformIndexMap[mapIndex].uniformNameHash = uniformMapNode[nodeMapIndex].uniformNameHash; - mUniformIndexMap[mapIndex].uniformNameHashNoArray = uniformMapNode[nodeMapIndex].uniformNameHashNoArray; - mUniformIndexMap[mapIndex].arrayIndex = uniformMapNode[nodeMapIndex].arrayIndex; + mUniformIndexMaps[renderItemMapIndex][mapIndex].propertyValue = uniformMapNode[nodeMapIndex].propertyPtr; + mUniformIndexMaps[renderItemMapIndex][mapIndex].uniformName = uniformMapNode[nodeMapIndex].uniformName; + mUniformIndexMaps[renderItemMapIndex][mapIndex].uniformNameHash = uniformMapNode[nodeMapIndex].uniformNameHash; + mUniformIndexMaps[renderItemMapIndex][mapIndex].uniformNameHashNoArray = uniformMapNode[nodeMapIndex].uniformNameHashNoArray; + mUniformIndexMaps[renderItemMapIndex][mapIndex].arrayIndex = uniformMapNode[nodeMapIndex].arrayIndex; ++mapIndex; } } - mUniformIndexMap.Resize(mapIndex); + mUniformIndexMaps[renderItemMapIndex].resize(mapIndex); } - - // @todo Temporary workaround to reduce workload each frame. Find a better way. - auto& sceneGraphRenderer = const_cast(static_cast(uniformMapDataProvider)); - sceneGraphRenderer.AgeUniformMap(); + return renderItemMapIndex; } void Renderer::WriteUniformBuffer( @@ -575,12 +733,13 @@ void Renderer::WriteUniformBuffer( const Matrix& modelViewMatrix, const Matrix& viewMatrix, const Matrix& projectionMatrix, - const Vector3& size) + const Vector3& size, + std::size_t nodeIndex) { // Create the UBO uint32_t uboOffset{0u}; - auto &reflection = mGraphicsController->GetProgramReflection(program->GetGraphicsProgram()); + auto& reflection = mGraphicsController->GetProgramReflection(program->GetGraphicsProgram()); uint32_t uniformBlockAllocationBytes = program->GetUniformBlocksMemoryRequirements().totalSizeRequired; @@ -589,8 +748,7 @@ void Renderer::WriteUniformBuffer( if(uniformBlockAllocationBytes) { auto uboPoolView = mUniformBufferManager->GetUniformBufferViewPool(bufferIndex); - - uboView = uboPoolView->CreateUniformBufferView(uniformBlockAllocationBytes); + uboView = uboPoolView->CreateUniformBufferView(uniformBlockAllocationBytes); } // update the uniform buffer @@ -615,7 +773,7 @@ void Renderer::WriteUniformBuffer( if(mvpUniformInfo && !mvpUniformInfo->name.empty()) { Matrix modelViewProjectionMatrix(false); - Matrix::Multiply(modelViewProjectionMatrix, modelViewMatrix, projectionMatrix); + MatrixUtils::MultiplyProjectionMatrix(modelViewProjectionMatrix, modelViewMatrix, projectionMatrix); WriteDefaultUniform(mvpUniformInfo, *uboView, modelViewProjectionMatrix); } @@ -628,21 +786,22 @@ void Renderer::WriteUniformBuffer( WriteDefaultUniform(normalUniformInfo, *uboView, normalMatrix); } - Vector4 finalColor; - const Vector4& color = node.GetRenderColor(bufferIndex); + Vector4 finalColor; ///< Applied renderer's opacity color + const Vector4& color = node.GetRenderColor(bufferIndex); ///< Actor's original color if(mPremultipliedAlphaEnabled) { - float alpha = color.a * mRenderDataProvider->GetOpacity(bufferIndex); - finalColor = Vector4(color.r * alpha, color.g * alpha, color.b * alpha, alpha); + const float& alpha = color.a * mRenderDataProvider->GetOpacity(bufferIndex); + finalColor = Vector4(color.r * alpha, color.g * alpha, color.b * alpha, alpha); } else { finalColor = Vector4(color.r, color.g, color.b, color.a * mRenderDataProvider->GetOpacity(bufferIndex)); } WriteDefaultUniform(program->GetDefaultUniform(Program::DefaultUniformIndex::COLOR), *uboView, finalColor); + WriteDefaultUniform(program->GetDefaultUniform(Program::DefaultUniformIndex::ACTOR_COLOR), *uboView, color); // Write uniforms from the uniform map - FillUniformBuffer(*program, instruction, *uboView, bindings, uboOffset, bufferIndex); + FillUniformBuffer(*program, instruction, *uboView, bindings, uboOffset, bufferIndex, nodeIndex); // Write uSize in the end, as it shouldn't be overridable by dynamic properties. WriteDefaultUniform(program->GetDefaultUniform(Program::DefaultUniformIndex::SIZE), *uboView, size); @@ -678,7 +837,8 @@ void Renderer::FillUniformBuffer(Program& p Render::UniformBufferView& ubo, std::vector*& outBindings, uint32_t& offset, - BufferIndex updateBufferIndex) + BufferIndex updateBufferIndex, + std::size_t nodeIndex) { auto& reflection = mGraphicsController->GetProgramReflection(program.GetGraphicsProgram()); auto uboCount = reflection.GetUniformBlockCount(); @@ -693,26 +853,47 @@ void Renderer::FillUniformBuffer(Program& p dataOffset += GetUniformBufferDataAlignment(mUniformBufferBindings[i].dataSize); mUniformBufferBindings[i].buffer = ubo.GetBuffer(&mUniformBufferBindings[i].offset); - for(UniformIndexMappings::Iterator iter = mUniformIndexMap.Begin(), - end = mUniformIndexMap.End(); + for(auto iter = mUniformIndexMaps[nodeIndex].begin(), + end = mUniformIndexMaps[nodeIndex].end(); iter != end; ++iter) { - // @todo This means parsing the uniform string every frame. Instead, store the array index if present. - int arrayIndex = (*iter).arrayIndex; + auto& uniform = *iter; + int arrayIndex = uniform.arrayIndex; + + if(!uniform.uniformFunc) + { + auto uniformInfo = Graphics::UniformInfo{}; + auto uniformFound = program.GetUniform(uniform.uniformName.GetStringView(), + uniform.uniformNameHash, + uniform.uniformNameHashNoArray, + uniformInfo); - auto uniformInfo = Graphics::UniformInfo{}; - auto uniformFound = program.GetUniform((*iter).uniformName.GetCString(), - (*iter).uniformNameHashNoArray ? (*iter).uniformNameHashNoArray - : (*iter).uniformNameHash, - uniformInfo); + uniform.uniformOffset = uniformInfo.offset; + uniform.uniformLocation = uniformInfo.location; - if(uniformFound) + if(uniformFound) + { + auto dst = ubo.GetOffset() + uniformInfo.offset; + const auto typeSize = GetPropertyValueSizeForUniform((*iter).propertyValue->GetType()); + const auto dest = dst + static_cast(typeSize) * arrayIndex; + const auto func = GetPropertyValueGetter((*iter).propertyValue->GetType()); + + ubo.Write(&((*iter).propertyValue->*func)(updateBufferIndex), + typeSize, + dest); + + uniform.uniformSize = typeSize; + uniform.uniformFunc = func; + } + } + else { - auto dst = ubo.GetOffset() + uniformInfo.offset; - const auto typeSize = GetPropertyValueSizeForUniform( (*iter).propertyValue->GetType() ); - const auto dest = dst + static_cast(typeSize) * arrayIndex; - const auto func = GetPropertyValueGetter((*iter).propertyValue->GetType()); + auto dst = ubo.GetOffset() + uniform.uniformOffset; + const auto typeSize = uniform.uniformSize; + const auto dest = dst + static_cast(typeSize) * arrayIndex; + const auto func = uniform.uniformFunc; + ubo.Write(&((*iter).propertyValue->*func)(updateBufferIndex), typeSize, dest); @@ -737,77 +918,60 @@ void Renderer::SetShaderChanged(bool value) mShaderChanged = value; } -bool Renderer::Updated(BufferIndex bufferIndex, const SceneGraph::NodeDataProvider* node) +bool Renderer::Updated(BufferIndex bufferIndex) { - if(mUpdated) - { - mUpdated = false; - return true; - } - - if(mShaderChanged || mGeometry->AttributesChanged()) + if(mRenderCallback || mShaderChanged || mGeometry->AttributesChanged() || mRenderDataProvider->IsUpdated()) { return true; } - for(const auto& texture : mRenderDataProvider->GetTextures()) + auto* textures = mRenderDataProvider->GetTextures(); + if(textures) { - if(texture && texture->IsNativeImage()) + for(auto iter = textures->Begin(), end = textures->End(); iter < end; ++iter) { - return true; + auto texture = *iter; + if(texture && texture->Updated()) + { + return true; + } } } - - uint64_t hash = 0xc70f6907UL; - const SceneGraph::CollectedUniformMap& uniformMapNode = node->GetUniformMap(bufferIndex); - for(const auto& uniformProperty : uniformMapNode) - { - hash = uniformProperty.propertyPtr->Hash(bufferIndex, hash); - } - - const SceneGraph::UniformMapDataProvider& uniformMapDataProvider = mRenderDataProvider->GetUniformMap(); - const SceneGraph::CollectedUniformMap& uniformMap = uniformMapDataProvider.GetUniformMap(bufferIndex); - for(const auto& uniformProperty : uniformMap) - { - hash = uniformProperty.propertyPtr->Hash(bufferIndex, hash); - } - - if(mUniformsHash != hash) - { - mUniformsHash = hash; - return true; - } - return false; } +Vector4 Renderer::GetVisualTransformedUpdateArea(BufferIndex bufferIndex, const Vector4& originalUpdateArea) const noexcept +{ + return mRenderDataProvider->GetVisualTransformedUpdateArea(bufferIndex, originalUpdateArea); +} + Graphics::Pipeline& Renderer::PrepareGraphicsPipeline( Program& program, const Dali::Internal::SceneGraph::RenderInstruction& instruction, const SceneGraph::NodeDataProvider& node, bool blend) { - if(mGeometry->AttributesChanged()) - { - mUpdated = true; - } - // Prepare query info PipelineCacheQueryInfo queryInfo{}; - queryInfo.program = &program; - queryInfo.renderer = this; - queryInfo.geometry = mGeometry; - queryInfo.blendingEnabled = blend; - queryInfo.blendingOptions = &mBlendingOptions; - queryInfo.alphaPremultiplied = mPremultipliedAlphaEnabled; + queryInfo.program = &program; + queryInfo.renderer = this; + queryInfo.geometry = mGeometry; + queryInfo.blendingEnabled = blend; + queryInfo.blendingOptions = &mBlendingOptions; + queryInfo.alphaPremultiplied = mPremultipliedAlphaEnabled; queryInfo.cameraUsingReflection = instruction.GetCamera()->GetReflectionUsed(); - auto pipelineResult = mPipelineCache->GetPipeline( queryInfo, true ); + auto pipelineResult = mPipelineCache->GetPipeline(queryInfo, true); // should be never null? return *pipelineResult.pipeline; } +void Renderer::SetRenderCallback(RenderCallback* callback) +{ + mRenderCallback = callback; +} + } // namespace Render } // namespace Dali::Internal