X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali%2Finternal%2Frender%2Frenderers%2Frender-renderer.cpp;h=7a19c6b77072a021ca7e0e34f2a7b1650e1ca49d;hb=c4750afbf79f15bf71e2aa8ef54f84750463aae2;hp=4885c4e3f31e74484b0f0bb73b94644801ca08d3;hpb=05833e368a62563bee31689952d11f23a51a7834;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 4885c4e..7a19c6b 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. @@ -19,189 +19,121 @@ #include // INTERNAL INCLUDES -#include #include #include #include +#include +#include +#include #include #include #include -#include +#include #include #include #include #include +#include +#include #include -#include +#include #include +#include -namespace Dali -{ -namespace Internal +namespace Dali::Internal { namespace { -// Size of uniform buffer page used when resizing -constexpr uint32_t UBO_PAGE_SIZE = 8192u; - -// UBO allocation threshold below which the UBO will shrink -constexpr auto UBO_SHRINK_THRESHOLD = 0.75f; - -// Helper to get the vertex input format -Dali::Graphics::VertexInputFormat GetPropertyVertexFormat(Property::Type propertyType) +// Helper to get the property value getter by type +typedef const float& (PropertyInputImpl::*FuncGetter)(BufferIndex) const; +constexpr FuncGetter GetPropertyValueGetter(Property::Type type) { - Dali::Graphics::VertexInputFormat type{}; - - switch(propertyType) + switch(type) { - case Property::NONE: - case Property::STRING: - case Property::ARRAY: - case Property::MAP: - case Property::EXTENTS: // i4? - case Property::RECTANGLE: // i4/f4? - case Property::ROTATION: - { - type = Dali::Graphics::VertexInputFormat::UNDEFINED; - break; - } case Property::BOOLEAN: { - type = Dali::Graphics::VertexInputFormat::UNDEFINED; // type = GL_BYTE; @todo new type for this? - break; + return FuncGetter(&PropertyInputImpl::GetBoolean); } case Property::INTEGER: { - type = Dali::Graphics::VertexInputFormat::INTEGER; // (short) - break; + return FuncGetter(&PropertyInputImpl::GetInteger); } case Property::FLOAT: { - type = Dali::Graphics::VertexInputFormat::FLOAT; - break; + return FuncGetter(&PropertyInputImpl::GetFloat); } case Property::VECTOR2: { - type = Dali::Graphics::VertexInputFormat::FVECTOR2; - break; + return FuncGetter(&PropertyInputImpl::GetVector2); } case Property::VECTOR3: { - type = Dali::Graphics::VertexInputFormat::FVECTOR3; - break; + return FuncGetter(&PropertyInputImpl::GetVector3); } case Property::VECTOR4: { - type = Dali::Graphics::VertexInputFormat::FVECTOR4; - break; + return FuncGetter(&PropertyInputImpl::GetVector4); } case Property::MATRIX3: { - type = Dali::Graphics::VertexInputFormat::FLOAT; - break; + return FuncGetter(&PropertyInputImpl::GetMatrix3); } case Property::MATRIX: { - type = Dali::Graphics::VertexInputFormat::FLOAT; - break; + return FuncGetter(&PropertyInputImpl::GetMatrix); + } + default: + { + return nullptr; } } - - return type; } -constexpr Graphics::CullMode ConvertCullFace(Dali::FaceCullingMode::Type mode) +/** + * Helper function that returns size of uniform datatypes based + * on property type. + */ +constexpr int GetPropertyValueSizeForUniform(Property::Type type) { - switch(mode) + switch(type) { - case Dali::FaceCullingMode::NONE: + case Property::Type::BOOLEAN: { - return Graphics::CullMode::NONE; + return sizeof(bool); } - case Dali::FaceCullingMode::FRONT: + case Property::Type::FLOAT: { - return Graphics::CullMode::FRONT; + return sizeof(float); } - case Dali::FaceCullingMode::BACK: + case Property::Type::INTEGER: { - return Graphics::CullMode::BACK; + return sizeof(int); } - case Dali::FaceCullingMode::FRONT_AND_BACK: + case Property::Type::VECTOR2: { - return Graphics::CullMode::FRONT_AND_BACK; + return sizeof(Vector2); } - } - return Graphics::CullMode::NONE; -} - -constexpr Graphics::BlendFactor ConvertBlendFactor(BlendFactor::Type blendFactor) -{ - switch(blendFactor) - { - case BlendFactor::ZERO: - return Graphics::BlendFactor::ZERO; - case BlendFactor::ONE: - return Graphics::BlendFactor::ONE; - case BlendFactor::SRC_COLOR: - return Graphics::BlendFactor::SRC_COLOR; - case BlendFactor::ONE_MINUS_SRC_COLOR: - return Graphics::BlendFactor::ONE_MINUS_SRC_COLOR; - case BlendFactor::SRC_ALPHA: - return Graphics::BlendFactor::SRC_ALPHA; - case BlendFactor::ONE_MINUS_SRC_ALPHA: - return Graphics::BlendFactor::ONE_MINUS_SRC_ALPHA; - case BlendFactor::DST_ALPHA: - return Graphics::BlendFactor::DST_ALPHA; - case BlendFactor::ONE_MINUS_DST_ALPHA: - return Graphics::BlendFactor::ONE_MINUS_DST_ALPHA; - case BlendFactor::DST_COLOR: - return Graphics::BlendFactor::DST_COLOR; - case BlendFactor::ONE_MINUS_DST_COLOR: - return Graphics::BlendFactor::ONE_MINUS_DST_COLOR; - case BlendFactor::SRC_ALPHA_SATURATE: - return Graphics::BlendFactor::SRC_ALPHA_SATURATE; - case BlendFactor::CONSTANT_COLOR: - return Graphics::BlendFactor::CONSTANT_COLOR; - case BlendFactor::ONE_MINUS_CONSTANT_COLOR: - return Graphics::BlendFactor::ONE_MINUS_CONSTANT_COLOR; - case BlendFactor::CONSTANT_ALPHA: - return Graphics::BlendFactor::CONSTANT_ALPHA; - case BlendFactor::ONE_MINUS_CONSTANT_ALPHA: - return Graphics::BlendFactor::ONE_MINUS_CONSTANT_ALPHA; - } - return Graphics::BlendFactor{}; -} - -constexpr Graphics::BlendOp ConvertBlendEquation(DevelBlendEquation::Type blendEquation) -{ - switch(blendEquation) - { - case DevelBlendEquation::ADD: - return Graphics::BlendOp::ADD; - case DevelBlendEquation::SUBTRACT: - return Graphics::BlendOp::SUBTRACT; - case DevelBlendEquation::REVERSE_SUBTRACT: - return Graphics::BlendOp::REVERSE_SUBTRACT; - case DevelBlendEquation::COLOR: - case DevelBlendEquation::COLOR_BURN: - case DevelBlendEquation::COLOR_DODGE: - case DevelBlendEquation::DARKEN: - case DevelBlendEquation::DIFFERENCE: - case DevelBlendEquation::EXCLUSION: - case DevelBlendEquation::HARD_LIGHT: - case DevelBlendEquation::HUE: - case DevelBlendEquation::LIGHTEN: - case DevelBlendEquation::LUMINOSITY: - case DevelBlendEquation::MAX: - case DevelBlendEquation::MIN: - case DevelBlendEquation::MULTIPLY: - case DevelBlendEquation::OVERLAY: - case DevelBlendEquation::SATURATION: - case DevelBlendEquation::SCREEN: - case DevelBlendEquation::SOFT_LIGHT: - return Graphics::BlendOp{}; - } - return Graphics::BlendOp{}; + 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; + } + }; } /** @@ -214,22 +146,57 @@ inline uint32_t GetUniformBufferDataAlignment(uint32_t dataSize) return ((dataSize / 256u) + ((dataSize % 256u) ? 1u : 0u)) * 256u; } +/** + * @brief Store latest bound 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 bound vertex attributes. False otherwise. + */ +inline bool ReuseLatestBoundVertexAttributes(const Render::Geometry* geometry) +{ + static const Render::Geometry* gLatestVertexBoundGeometry = nullptr; + if(gLatestVertexBoundGeometry == geometry) + { + return true; + } + gLatestVertexBoundGeometry = 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() +{ + // Reset latest geometry informations, So we can bind the first of geometry. + ReuseLatestBoundVertexAttributes(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) { - return new Renderer(dataProvider, geometry, blendingBitmask, blendColor, faceCullingMode, preMultipliedAlphaEnabled, depthWriteMode, depthTestMode, depthFunction, 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, @@ -244,12 +211,8 @@ Renderer::Renderer(SceneGraph::RenderDataProvider* dataProvider, StencilParameters& stencilParameters) : mGraphicsController(nullptr), mRenderDataProvider(dataProvider), - mContext(nullptr), mGeometry(geometry), mProgramCache(nullptr), - mUniformIndexMap(), - mAttributeLocations(), - mUniformsHash(), mStencilParameters(stencilParameters), mBlendingOptions(), mIndexedDrawFirstElement(0), @@ -258,10 +221,8 @@ Renderer::Renderer(SceneGraph::RenderDataProvider* dataProvider, mFaceCullingMode(faceCullingMode), mDepthWriteMode(depthWriteMode), mDepthTestMode(depthTestMode), - mUpdateAttributeLocations(true), - mPremultipledAlphaEnabled(preMultipliedAlphaEnabled), - mShaderChanged(false), - mUpdated(true) + mPremultipliedAlphaEnabled(preMultipliedAlphaEnabled), + mShaderChanged(false) { if(blendingBitmask != 0u) { @@ -271,130 +232,75 @@ Renderer::Renderer(SceneGraph::RenderDataProvider* dataProvider, mBlendingOptions.SetBlendColor(blendColor); } -void Renderer::Initialize(Context& context, Graphics::Controller& graphicsController, ProgramCache& programCache, Render::ShaderCache& shaderCache, Render::UniformBufferManager& uniformBufferManager) +void Renderer::Initialize(Graphics::Controller& graphicsController, ProgramCache& programCache, Render::ShaderCache& shaderCache, Render::UniformBufferManager& uniformBufferManager, Render::PipelineCache& pipelineCache) { - mContext = &context; mGraphicsController = &graphicsController; mProgramCache = &programCache; mShaderCache = &shaderCache; mUniformBufferManager = &uniformBufferManager; + mPipelineCache = &pipelineCache; } Renderer::~Renderer() = default; -void Renderer::SetGeometry(Render::Geometry* geometry) +void Renderer::operator delete(void* ptr) { - mGeometry = geometry; - mUpdateAttributeLocations = true; + gRenderRendererMemoryPool.FreeThreadSafe(static_cast(ptr)); } -void Renderer::SetDrawCommands(Dali::DevelRenderer::DrawCommand* pDrawCommands, uint32_t size) + +Renderer* Renderer::Get(RendererKey::KeyType rendererKey) { - mDrawCommands.clear(); - mDrawCommands.insert(mDrawCommands.end(), pDrawCommands, pDrawCommands + size); + return gRenderRendererMemoryPool.GetPtrFromKey(rendererKey); } -void Renderer::SetUniformFromProperty(BufferIndex bufferIndex, Program& program, UniformIndexMap& map) +void Renderer::SetGeometry(Render::Geometry* geometry) { - GLint location = program.GetUniformLocation(map.uniformIndex); - if(Program::UNIFORM_UNKNOWN != location) - { - // switch based on property type to use correct GL uniform setter - switch(map.propertyValue->GetType()) - { - case Property::INTEGER: - { - program.SetUniform1i(location, map.propertyValue->GetInteger(bufferIndex)); - break; - } - case Property::FLOAT: - { - program.SetUniform1f(location, map.propertyValue->GetFloat(bufferIndex)); - break; - } - case Property::VECTOR2: - { - Vector2 value(map.propertyValue->GetVector2(bufferIndex)); - program.SetUniform2f(location, value.x, value.y); - break; - } - - case Property::VECTOR3: - { - Vector3 value(map.propertyValue->GetVector3(bufferIndex)); - program.SetUniform3f(location, value.x, value.y, value.z); - break; - } - - case Property::VECTOR4: - { - Vector4 value(map.propertyValue->GetVector4(bufferIndex)); - program.SetUniform4f(location, value.x, value.y, value.z, value.w); - break; - } - - case Property::ROTATION: - { - Quaternion value(map.propertyValue->GetQuaternion(bufferIndex)); - program.SetUniform4f(location, value.mVector.x, value.mVector.y, value.mVector.z, value.mVector.w); - break; - } - - case Property::MATRIX: - { - const Matrix& value = map.propertyValue->GetMatrix(bufferIndex); - program.SetUniformMatrix4fv(location, 1, value.AsFloat()); - break; - } - - case Property::MATRIX3: - { - const Matrix3& value = map.propertyValue->GetMatrix3(bufferIndex); - program.SetUniformMatrix3fv(location, 1, value.AsFloat()); - break; - } + mGeometry = geometry; +} - default: - { - // Other property types are ignored - break; - } - } - } +void Renderer::SetDrawCommands(Dali::DevelRenderer::DrawCommand* pDrawCommands, uint32_t size) +{ + mDrawCommands.clear(); + mDrawCommands.insert(mDrawCommands.end(), pDrawCommands, pDrawCommands + size); } -void Renderer::BindTextures(Program& program, Graphics::CommandBuffer& commandBuffer, Vector& boundTextures) +void Renderer::BindTextures(Graphics::CommandBuffer& commandBuffer, Vector& boundTextures) { uint32_t textureUnit = 0; - GLint uniformLocation(-1); - std::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(program.GetSamplerUniformLocation(i, uniformLocation)) + 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}; + boundTextures.PushBack(graphicsTexture); + const Graphics::TextureBinding textureBinding{graphicsTexture, graphicsSampler, textureUnit}; textureBindings.push_back(textureBinding); - program.SetUniform1i(uniformLocation, textureUnit); // Get through shader reflection ++textureUnit; } } } - if(textureBindings.size() > 0) + if(!textureBindings.empty()) { commandBuffer.BindTextures(textureBindings); } @@ -403,49 +309,41 @@ void Renderer::BindTextures(Program& program, Graphics::CommandBuffer& commandBu void Renderer::SetFaceCullingMode(FaceCullingMode::Type mode) { mFaceCullingMode = mode; - mUpdated = true; } void Renderer::SetBlendingBitMask(uint32_t bitmask) { mBlendingOptions.SetBitmask(bitmask); - mUpdated = true; } void Renderer::SetBlendColor(const Vector4& color) { mBlendingOptions.SetBlendColor(color); - mUpdated = true; } void Renderer::SetIndexedDrawFirstElement(uint32_t firstElement) { mIndexedDrawFirstElement = firstElement; - mUpdated = true; } void Renderer::SetIndexedDrawElementsCount(uint32_t elementsCount) { mIndexedDrawElementsCount = elementsCount; - mUpdated = true; } void Renderer::EnablePreMultipliedAlpha(bool enable) { - mPremultipledAlphaEnabled = enable; - mUpdated = true; + mPremultipliedAlphaEnabled = enable; } void Renderer::SetDepthWriteMode(DepthWriteMode::Type depthWriteMode) { mDepthWriteMode = depthWriteMode; - mUpdated = true; } void Renderer::SetDepthTestMode(DepthTestMode::Type depthTestMode) { mDepthTestMode = depthTestMode; - mUpdated = true; } DepthWriteMode::Type Renderer::GetDepthWriteMode() const @@ -461,7 +359,6 @@ DepthTestMode::Type Renderer::GetDepthTestMode() const void Renderer::SetDepthFunction(DepthFunction::Type depthFunction) { mDepthFunction = depthFunction; - mUpdated = true; } DepthFunction::Type Renderer::GetDepthFunction() const @@ -472,7 +369,6 @@ DepthFunction::Type Renderer::GetDepthFunction() const void Renderer::SetRenderMode(RenderMode::Type renderMode) { mStencilParameters.renderMode = renderMode; - mUpdated = true; } RenderMode::Type Renderer::GetRenderMode() const @@ -483,7 +379,6 @@ RenderMode::Type Renderer::GetRenderMode() const void Renderer::SetStencilFunction(StencilFunction::Type stencilFunction) { mStencilParameters.stencilFunction = stencilFunction; - mUpdated = true; } StencilFunction::Type Renderer::GetStencilFunction() const @@ -494,7 +389,6 @@ StencilFunction::Type Renderer::GetStencilFunction() const void Renderer::SetStencilFunctionMask(int stencilFunctionMask) { mStencilParameters.stencilFunctionMask = stencilFunctionMask; - mUpdated = true; } int Renderer::GetStencilFunctionMask() const @@ -505,7 +399,6 @@ int Renderer::GetStencilFunctionMask() const void Renderer::SetStencilFunctionReference(int stencilFunctionReference) { mStencilParameters.stencilFunctionReference = stencilFunctionReference; - mUpdated = true; } int Renderer::GetStencilFunctionReference() const @@ -516,7 +409,6 @@ int Renderer::GetStencilFunctionReference() const void Renderer::SetStencilMask(int stencilMask) { mStencilParameters.stencilMask = stencilMask; - mUpdated = true; } int Renderer::GetStencilMask() const @@ -527,7 +419,6 @@ int Renderer::GetStencilMask() const void Renderer::SetStencilOperationOnFail(StencilOperation::Type stencilOperationOnFail) { mStencilParameters.stencilOperationOnFail = stencilOperationOnFail; - mUpdated = true; } StencilOperation::Type Renderer::GetStencilOperationOnFail() const @@ -538,7 +429,6 @@ StencilOperation::Type Renderer::GetStencilOperationOnFail() const void Renderer::SetStencilOperationOnZFail(StencilOperation::Type stencilOperationOnZFail) { mStencilParameters.stencilOperationOnZFail = stencilOperationOnZFail; - mUpdated = true; } StencilOperation::Type Renderer::GetStencilOperationOnZFail() const @@ -549,7 +439,6 @@ StencilOperation::Type Renderer::GetStencilOperationOnZFail() const void Renderer::SetStencilOperationOnZPass(StencilOperation::Type stencilOperationOnZPass) { mStencilParameters.stencilOperationOnZPass = stencilOperationOnZPass; - mUpdated = true; } StencilOperation::Type Renderer::GetStencilOperationOnZPass() const @@ -562,7 +451,7 @@ void Renderer::Upload() mGeometry->Upload(*mGraphicsController); } -bool Renderer::Render(Context& context, +bool Renderer::Render(Graphics::CommandBuffer& commandBuffer, BufferIndex bufferIndex, const SceneGraph::NodeDataProvider& node, const Matrix& modelMatrix, @@ -581,6 +470,55 @@ bool Renderer::Render(Context& conte return false; } + // Check if there is render callback + if(mRenderCallback) + { + if(!mRenderCallbackInput) + { + mRenderCallbackInput = std::unique_ptr(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) @@ -597,172 +535,192 @@ bool Renderer::Render(Context& conte return false; } - // Create command buffer if not present - if(!mGraphicsCommandBuffer) - { - mGraphicsCommandBuffer = mGraphicsController->CreateCommandBuffer( - Graphics::CommandBufferCreateInfo() - .SetLevel(Graphics::CommandBufferLevel::SECONDARY), - nullptr); - } - else - { - mGraphicsCommandBuffer->Reset(); - } - - auto& commandBuffer = mGraphicsCommandBuffer; - // Set blending mode if(!mDrawCommands.empty()) { - blend = (commands[0]->queue == DevelRenderer::RENDER_QUEUE_OPAQUE ? false : blend); + blend = (commands[0]->queue != DevelRenderer::RENDER_QUEUE_OPAQUE) && blend; } // 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), - (shaderData->GetHints() & Dali::Shader::Hint::MODIFIES_GEOMETRY) != 0x0); + 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; } - // Temporarily create a pipeline here - this will be used for transporting - // topology, vertex format, attrs, rasterization state - mGraphicsPipeline = PrepareGraphicsPipeline(*program, instruction, blend, std::move(mGraphicsPipeline)); + // 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); - commandBuffer->BindPipeline(*mGraphicsPipeline.get()); + commandBuffer.BindPipeline(pipeline); - BindTextures(*program, *commandBuffer.get(), boundTextures); + BindTextures(commandBuffer, boundTextures); - BuildUniformIndexMap(bufferIndex, node, size, *program); + std::size_t nodeIndex = BuildUniformIndexMap(bufferIndex, node, size, *program); - WriteUniformBuffer(bufferIndex, *commandBuffer.get(), 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 - //@todo manage mDrawCommands in the same way as above command buffer?! - if(mDrawCommands.empty()) + // Reuse latest bound vertex attributes location, or Bind buffers to attribute locations. + if(ReuseLatestBoundVertexAttributes(mGeometry) || mGeometry->BindVertexAttributes(commandBuffer)) { - drawn = mGeometry->Draw(*mGraphicsController, *commandBuffer.get(), mIndexedDrawFirstElement, mIndexedDrawElementsCount); - } - else - { - for(auto& cmd : commands) + if(mDrawCommands.empty()) { - // @todo This should generate a command buffer per cmd - // Tests WILL fail. (Temporarily commented out) - mGeometry->Draw(*mGraphicsController, *commandBuffer.get(), cmd->firstIndex, cmd->elementCount); + drawn = mGeometry->Draw(*mGraphicsController, commandBuffer, mIndexedDrawFirstElement, mIndexedDrawElementsCount); + } + else + { + for(auto& cmd : commands) + { + drawn |= mGeometry->Draw(*mGraphicsController, commandBuffer, cmd->firstIndex, cmd->elementCount); + } } } - - // Command buffer contains Texture bindings, vertex bindings, index buffer binding, pipeline(vertex format) - // @todo We should return the command buffer(s) and let the calling method submit - // If not drawn, then don't add command buffer to submit info, and if empty, don't - // submit. - /* - if(drawn) + else { - Graphics::SubmitInfo submitInfo{{}, 0 | Graphics::SubmitFlagBits::FLUSH}; - submitInfo.cmdBuffer.push_back(commandBuffer.get()); - mGraphicsController->SubmitCommandBuffers(submitInfo); + // BindVertexAttributes failed. Reset cached geometry. + ReuseLatestBoundVertexAttributes(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; + + // 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(uniformMapDataProvider.GetUniformMapChanged(bufferIndex) || - node.GetUniformMapChanged(bufferIndex) || - mUniformIndexMap.Count() == 0 || - mShaderChanged) + 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(); - uint32_t 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].uniformIndex = program.RegisterUniform(uniformMap[mapIndex].uniformName); - 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) { - uint32_t uniformIndex = program.RegisterUniform(uniformMapNode[nodeMapIndex].uniformName); - bool found(false); - for(uint32_t i = 0; i < uniformMap.Count(); ++i) + auto hash = uniformMapNode[nodeMapIndex].uniformNameHash; + auto& name = uniformMapNode[nodeMapIndex].uniformName; + bool found(false); + for(uint32_t i = 0; i < mapCount; ++i) { - if(mUniformIndexMap[i].uniformIndex == uniformIndex) + 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].uniformIndex = uniformIndex; - 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); } + return renderItemMapIndex; } void Renderer::WriteUniformBuffer( @@ -775,67 +733,48 @@ 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 uniformBlockAllocationBytes{0u}; - uint32_t uniformBlockMaxSize{0u}; uint32_t uboOffset{0u}; auto& reflection = mGraphicsController->GetProgramReflection(program->GetGraphicsProgram()); - for(auto i = 0u; i < reflection.GetUniformBlockCount(); ++i) - { - auto blockSize = GetUniformBufferDataAlignment(reflection.GetUniformBlockSize(i)); - if(uniformBlockMaxSize < blockSize) - { - uniformBlockMaxSize = blockSize; - } - uniformBlockAllocationBytes += blockSize; - } - auto pagedAllocation = ((uniformBlockAllocationBytes / UBO_PAGE_SIZE + 1u)) * UBO_PAGE_SIZE; + uint32_t uniformBlockAllocationBytes = program->GetUniformBlocksMemoryRequirements().totalSizeRequired; - // Allocate twice memory as required by the uniform buffers - // todo: memory usage backlog to use optimal allocation - if(uniformBlockAllocationBytes && !mUniformBuffer[bufferIndex]) - { - mUniformBuffer[bufferIndex] = mUniformBufferManager->AllocateUniformBuffer(pagedAllocation); - } - else if(uniformBlockAllocationBytes && (mUniformBuffer[bufferIndex]->GetSize() < pagedAllocation || - (pagedAllocation < uint32_t(float(mUniformBuffer[bufferIndex]->GetSize()) * UBO_SHRINK_THRESHOLD)))) + // Create uniform buffer view from uniform buffer + Graphics::UniquePtr uboView{nullptr}; + if(uniformBlockAllocationBytes) { - mUniformBuffer[bufferIndex]->Reserve(pagedAllocation); - } - - // Clear UBO - if(mUniformBuffer[bufferIndex]) - { - mUniformBuffer[bufferIndex]->Fill(0, 0u, 0u); + auto uboPoolView = mUniformBufferManager->GetUniformBufferViewPool(bufferIndex); + uboView = uboPoolView->CreateUniformBufferView(uniformBlockAllocationBytes); } // update the uniform buffer // pass shared UBO and offset, return new offset for next item to be used // don't process bindings if there are no uniform buffers allocated - auto ubo = mUniformBuffer[bufferIndex].get(); - if(ubo) + if(uboView) { auto uboCount = reflection.GetUniformBlockCount(); mUniformBufferBindings.resize(uboCount); std::vector* bindings{&mUniformBufferBindings}; + mUniformBufferBindings[0].buffer = uboView->GetBuffer(&mUniformBufferBindings[0].offset); + // Write default uniforms - WriteDefaultUniform(program->GetDefaultUniform(Program::DefaultUniformIndex::MODEL_MATRIX), *ubo, *bindings, modelMatrix); - WriteDefaultUniform(program->GetDefaultUniform(Program::DefaultUniformIndex::VIEW_MATRIX), *ubo, *bindings, viewMatrix); - WriteDefaultUniform(program->GetDefaultUniform(Program::DefaultUniformIndex::PROJECTION_MATRIX), *ubo, *bindings, projectionMatrix); - WriteDefaultUniform(program->GetDefaultUniform(Program::DefaultUniformIndex::MODEL_VIEW_MATRIX), *ubo, *bindings, modelViewMatrix); + WriteDefaultUniform(program->GetDefaultUniform(Program::DefaultUniformIndex::MODEL_MATRIX), *uboView, modelMatrix); + WriteDefaultUniform(program->GetDefaultUniform(Program::DefaultUniformIndex::VIEW_MATRIX), *uboView, viewMatrix); + WriteDefaultUniform(program->GetDefaultUniform(Program::DefaultUniformIndex::PROJECTION_MATRIX), *uboView, projectionMatrix); + WriteDefaultUniform(program->GetDefaultUniform(Program::DefaultUniformIndex::MODEL_VIEW_MATRIX), *uboView, modelViewMatrix); auto mvpUniformInfo = program->GetDefaultUniform(Program::DefaultUniformIndex::MVP_MATRIX); if(mvpUniformInfo && !mvpUniformInfo->name.empty()) { Matrix modelViewProjectionMatrix(false); - Matrix::Multiply(modelViewProjectionMatrix, modelViewMatrix, projectionMatrix); - WriteDefaultUniform(mvpUniformInfo, *ubo, *bindings, modelViewProjectionMatrix); + MatrixUtils::MultiplyProjectionMatrix(modelViewProjectionMatrix, modelViewMatrix, projectionMatrix); + WriteDefaultUniform(mvpUniformInfo, *uboView, modelViewProjectionMatrix); } auto normalUniformInfo = program->GetDefaultUniform(Program::DefaultUniformIndex::NORMAL_MATRIX); @@ -844,60 +783,62 @@ void Renderer::WriteUniformBuffer( Matrix3 normalMatrix(modelViewMatrix); normalMatrix.Invert(); normalMatrix.Transpose(); - WriteDefaultUniform(normalUniformInfo, *ubo, *bindings, normalMatrix); + WriteDefaultUniform(normalUniformInfo, *uboView, normalMatrix); } - Vector4 finalColor; - const Vector4& color = node.GetRenderColor(bufferIndex); - if(mPremultipledAlphaEnabled) + 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), *ubo, *bindings, finalColor); + 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, *ubo, 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), *ubo, *bindings, size); + WriteDefaultUniform(program->GetDefaultUniform(Program::DefaultUniformIndex::SIZE), *uboView, size); commandBuffer.BindUniformBuffers(*bindings); } } template -bool Renderer::WriteDefaultUniform(const Graphics::UniformInfo* uniformInfo, Render::UniformBuffer& ubo, const std::vector& bindings, const T& data) +bool Renderer::WriteDefaultUniform(const Graphics::UniformInfo* uniformInfo, Render::UniformBufferView& ubo, const T& data) { if(uniformInfo && !uniformInfo->name.empty()) { - WriteUniform(ubo, bindings, *uniformInfo, data); + WriteUniform(ubo, *uniformInfo, data); return true; } return false; } template -void Renderer::WriteUniform(Render::UniformBuffer& ubo, const std::vector& bindings, const Graphics::UniformInfo& uniformInfo, const T& data) +void Renderer::WriteUniform(Render::UniformBufferView& ubo, const Graphics::UniformInfo& uniformInfo, const T& data) { - WriteUniform(ubo, bindings, uniformInfo, &data, sizeof(T)); + WriteUniform(ubo, uniformInfo, &data, sizeof(T)); } -void Renderer::WriteUniform(Render::UniformBuffer& ubo, const std::vector& bindings, const Graphics::UniformInfo& uniformInfo, const void* data, uint32_t size) +void Renderer::WriteUniform(Render::UniformBufferView& ubo, const Graphics::UniformInfo& uniformInfo, const void* data, uint32_t size) { - ubo.Write(data, size, bindings[uniformInfo.bufferIndex].offset + uniformInfo.offset); + ubo.Write(data, size, ubo.GetOffset() + uniformInfo.offset); } void Renderer::FillUniformBuffer(Program& program, const SceneGraph::RenderInstruction& instruction, - Render::UniformBuffer& ubo, + 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(); @@ -908,103 +849,55 @@ void Renderer::FillUniformBuffer(Program& p { mUniformBufferBindings[i].dataSize = reflection.GetUniformBlockSize(i); mUniformBufferBindings[i].binding = reflection.GetUniformBlockBinding(i); - mUniformBufferBindings[i].offset = dataOffset; dataOffset += GetUniformBufferDataAlignment(mUniformBufferBindings[i].dataSize); - mUniformBufferBindings[i].buffer = ubo.GetBuffer(); + 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 uniformInfo = Graphics::UniformInfo{}; - auto uniformFound = program.GetUniform((*iter).uniformName.GetCString(), - (*iter).uniformNameHashNoArray ? (*iter).uniformNameHashNoArray - : (*iter).uniformNameHash, - uniformInfo); + auto& uniform = *iter; + int arrayIndex = uniform.arrayIndex; - if(uniformFound) + if(!uniform.uniformFunc) { - auto dst = mUniformBufferBindings[uniformInfo.bufferIndex].offset + uniformInfo.offset; + auto uniformInfo = Graphics::UniformInfo{}; + auto uniformFound = program.GetUniform(uniform.uniformName.GetStringView(), + uniform.uniformNameHash, + uniform.uniformNameHashNoArray, + uniformInfo); - switch((*iter).propertyValue->GetType()) + uniform.uniformOffset = uniformInfo.offset; + uniform.uniformLocation = uniformInfo.location; + + if(uniformFound) { - case Property::Type::BOOLEAN: - { - ubo.Write(&(*iter).propertyValue->GetBoolean(updateBufferIndex), - sizeof(bool), - dst + static_cast(sizeof(bool)) * arrayIndex); - break; - } - case Property::Type::INTEGER: - { - ubo.Write(&(*iter).propertyValue->GetInteger(updateBufferIndex), - sizeof(int32_t), - dst + static_cast(sizeof(int32_t)) * arrayIndex); - break; - } - case Property::Type::FLOAT: - { - ubo.Write(&(*iter).propertyValue->GetFloat(updateBufferIndex), - sizeof(float), - dst + static_cast(sizeof(float)) * arrayIndex); - break; - } - case Property::Type::VECTOR2: - { - ubo.Write(&(*iter).propertyValue->GetVector2(updateBufferIndex), - sizeof(Vector2), - dst + static_cast(sizeof(Vector2)) * arrayIndex); - break; - } - case Property::Type::VECTOR3: - { - ubo.Write(&(*iter).propertyValue->GetVector3(updateBufferIndex), - sizeof(Vector3), - dst + static_cast(sizeof(Vector3)) * arrayIndex); - break; - } - case Property::Type::VECTOR4: - { - ubo.Write(&(*iter).propertyValue->GetVector4(updateBufferIndex), - sizeof(Vector4), - dst + static_cast(sizeof(Vector4)) * arrayIndex); - break; - } - case Property::Type::MATRIX: - { - ubo.Write(&(*iter).propertyValue->GetMatrix(updateBufferIndex), - sizeof(Matrix), - dst + static_cast(sizeof(Matrix)) * arrayIndex); - break; - } - case Property::Type::MATRIX3: - { - // todo: handle data padding properly - // Vulkan: - // - //const auto& matrix = &(*iter).propertyValue->GetMatrix3(updateBufferIndex); - //for(int i = 0; i < 3; ++i) - //{ - //ubo.Write(&matrix->AsFloat()[i * 3], - // sizeof(float) * 3, - // dst + (i * static_cast(sizeof(Vector4)))); - //} - // GL: - ubo.Write(&(*iter).propertyValue->GetMatrix3(updateBufferIndex), - sizeof(Matrix3), - dst + static_cast(sizeof(Matrix3)) * arrayIndex); - break; - } - default: - { - } + 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() + 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); + } } } // write output bindings @@ -1014,8 +907,7 @@ void Renderer::FillUniformBuffer(Program& p offset = dataOffset; } -void Renderer::SetSortAttributes(BufferIndex bufferIndex, - SceneGraph::RenderInstructionProcessor::SortAttributes& sortAttributes) const +void Renderer::SetSortAttributes(SceneGraph::RenderInstructionProcessor::SortAttributes& sortAttributes) const { sortAttributes.shader = &(mRenderDataProvider->GetShader()); sortAttributes.geometry = mGeometry; @@ -1026,226 +918,63 @@ 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 || mUpdateAttributeLocations || 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; } -Graphics::UniquePtr Renderer::PrepareGraphicsPipeline( +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, - bool blend, - Graphics::UniquePtr&& oldPipeline) + const SceneGraph::NodeDataProvider& node, + bool blend) { - Graphics::InputAssemblyState inputAssemblyState{}; - Graphics::VertexInputState vertexInputState{}; - Graphics::ProgramState programState{}; - uint32_t bindingIndex{0u}; - - if(mUpdateAttributeLocations || mGeometry->AttributesChanged()) - { - mAttributeLocations.Clear(); - mUpdateAttributeLocations = true; - } - - auto& reflection = mGraphicsController->GetProgramReflection(program.GetGraphicsProgram()); - - /** - * Bind Attributes - */ - uint32_t base = 0; - for(auto&& vertexBuffer : mGeometry->GetVertexBuffers()) - { - const VertexBuffer::Format& vertexFormat = *vertexBuffer->GetFormat(); - - vertexInputState.bufferBindings.emplace_back(vertexFormat.size, // stride - Graphics::VertexInputRate::PER_VERTEX); + // Prepare query info + PipelineCacheQueryInfo queryInfo{}; + queryInfo.program = &program; + queryInfo.renderer = this; + queryInfo.geometry = mGeometry; + queryInfo.blendingEnabled = blend; + queryInfo.blendingOptions = &mBlendingOptions; + queryInfo.alphaPremultiplied = mPremultipliedAlphaEnabled; + queryInfo.cameraUsingReflection = instruction.GetCamera()->GetReflectionUsed(); - const uint32_t attributeCount = vertexBuffer->GetAttributeCount(); - for(uint32_t i = 0; i < attributeCount; ++i) - { - if(mUpdateAttributeLocations) - { - auto attributeName = vertexBuffer->GetAttributeName(i); - int32_t pLocation = reflection.GetVertexAttributeLocation(std::string(attributeName.GetStringView())); - if(-1 == pLocation) - { - DALI_LOG_WARNING("Attribute not found in the shader: %s\n", attributeName.GetCString()); - } - mAttributeLocations.PushBack(pLocation); - } - - uint32_t location = static_cast(mAttributeLocations[base + i]); + queryInfo.GenerateHash(); - vertexInputState.attributes.emplace_back(location, - bindingIndex, - vertexFormat.components[i].offset, - GetPropertyVertexFormat(vertexFormat.components[i].type)); - } - base += attributeCount; - ++bindingIndex; - } - mUpdateAttributeLocations = false; + // Find or generate new pipeline. + auto pipelineResult = mPipelineCache->GetPipeline(queryInfo, true); - // Get the topology - inputAssemblyState.SetTopology(mGeometry->GetTopology()); - - // Get the program - programState.SetProgram(program.GetGraphicsProgram()); - - Graphics::RasterizationState rasterizationState{}; - - //Set cull face mode - const Dali::Internal::SceneGraph::Camera* cam = instruction.GetCamera(); - if(cam->GetReflectionUsed()) - { - auto adjFaceCullingMode = mFaceCullingMode; - switch(mFaceCullingMode) - { - case FaceCullingMode::Type::FRONT: - { - adjFaceCullingMode = FaceCullingMode::Type::BACK; - break; - } - case FaceCullingMode::Type::BACK: - { - adjFaceCullingMode = FaceCullingMode::Type::FRONT; - break; - } - default: - { - // nothing to do, leave culling as it is - } - } - rasterizationState.SetCullMode(ConvertCullFace(adjFaceCullingMode)); - } - else - { - rasterizationState.SetCullMode(ConvertCullFace(mFaceCullingMode)); - } - - rasterizationState.SetFrontFace(Graphics::FrontFace::COUNTER_CLOCKWISE); - - /** - * Set Polygon mode - */ - switch(mGeometry->GetTopology()) - { - case Graphics::PrimitiveTopology::TRIANGLE_LIST: - case Graphics::PrimitiveTopology::TRIANGLE_STRIP: - case Graphics::PrimitiveTopology::TRIANGLE_FAN: - rasterizationState.SetPolygonMode(Graphics::PolygonMode::FILL); - break; - case Graphics::PrimitiveTopology::LINE_LIST: - case Graphics::PrimitiveTopology::LINE_LOOP: - case Graphics::PrimitiveTopology::LINE_STRIP: - rasterizationState.SetPolygonMode(Graphics::PolygonMode::LINE); - break; - case Graphics::PrimitiveTopology::POINT_LIST: - rasterizationState.SetPolygonMode(Graphics::PolygonMode::POINT); - break; - } - - // @todo How to signal a blend barrier is needed? - //if(mBlendingOptions.IsAdvancedBlendEquationApplied() && mPremultipledAlphaEnabled) - //{ - // context.BlendBarrier(); - //} - - Graphics::ColorBlendState colorBlendState{}; - colorBlendState.SetBlendEnable(false); - - if(blend) - { - colorBlendState.SetBlendEnable(true); - - Graphics::BlendOp rgbOp = ConvertBlendEquation(mBlendingOptions.GetBlendEquationRgb()); - Graphics::BlendOp alphaOp = ConvertBlendEquation(mBlendingOptions.GetBlendEquationRgb()); - if(mBlendingOptions.IsAdvancedBlendEquationApplied() && mPremultipledAlphaEnabled) - { - if(rgbOp != alphaOp) - { - DALI_LOG_ERROR("Advanced Blend Equation MUST be applied by using BlendEquation.\n"); - alphaOp = rgbOp; - } - } - - colorBlendState - .SetSrcColorBlendFactor(ConvertBlendFactor(mBlendingOptions.GetBlendSrcFactorRgb())) - .SetSrcAlphaBlendFactor(ConvertBlendFactor(mBlendingOptions.GetBlendSrcFactorAlpha())) - .SetDstColorBlendFactor(ConvertBlendFactor(mBlendingOptions.GetBlendDestFactorRgb())) - .SetDstAlphaBlendFactor(ConvertBlendFactor(mBlendingOptions.GetBlendDestFactorAlpha())) - .SetColorBlendOp(rgbOp) - .SetAlphaBlendOp(alphaOp); - - // Blend color is optional and rarely used - Vector4* blendColor = const_cast(mBlendingOptions.GetBlendColor()); - if(blendColor) - { - colorBlendState.SetBlendConstants(blendColor->AsFloat()); - } - } + // should be never null? + return *pipelineResult.pipeline; +} - // Take the program into use so we can send uniforms to it - // @todo Remove this call entirely! - program.Use(); - - mUpdated = true; - - // Create a new pipeline - // @todo Passed as pointers - shallow copy will break. Implementation MUST deep copy. - return mGraphicsController->CreatePipeline( - Graphics::PipelineCreateInfo() - .SetInputAssemblyState(&inputAssemblyState) - .SetVertexInputState(&vertexInputState) - .SetRasterizationState(&rasterizationState) - .SetColorBlendState(&colorBlendState) - .SetProgramState(&programState) - .SetNextExtension(&mLegacyProgram), - std::move(oldPipeline)); +void Renderer::SetRenderCallback(RenderCallback* callback) +{ + mRenderCallback = callback; } } // namespace Render -} // namespace Internal - -} // namespace Dali +} // namespace Dali::Internal