/*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 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 HEADER
#include <dali/internal/render/common/render-manager.h>
+// EXTERNAL INCLUDES
+#include <memory.h>
+
// INTERNAL INCLUDES
-#include <dali/public-api/actors/sampling.h>
-#include <dali/public-api/common/dali-common.h>
-#include <dali/public-api/common/stage.h>
-#include <dali/public-api/render-tasks/render-task.h>
-#include <dali/integration-api/debug.h>
+#include <dali/devel-api/threading/thread-pool.h>
#include <dali/integration-api/core.h>
-#include <dali/internal/common/owner-pointer.h>
+
+#include <dali/internal/event/common/scene-impl.h>
+
+#include <dali/internal/update/common/scene-graph-scene.h>
+#include <dali/internal/update/nodes/scene-graph-layer.h>
+#include <dali/internal/update/render-tasks/scene-graph-camera.h>
+
#include <dali/internal/render/common/render-algorithms.h>
#include <dali/internal/render/common/render-debug.h>
-#include <dali/internal/render/common/render-tracker.h>
-#include <dali/internal/render/common/render-instruction-container.h>
#include <dali/internal/render/common/render-instruction.h>
-#include <dali/internal/render/gl-resources/context.h>
-#include <dali/internal/render/gl-resources/frame-buffer-texture.h>
-#include <dali/internal/render/gl-resources/texture-cache.h>
+#include <dali/internal/render/common/render-tracker.h>
#include <dali/internal/render/queue/render-queue.h>
+#include <dali/internal/render/renderers/pipeline-cache.h>
#include <dali/internal/render/renderers/render-frame-buffer.h>
-#include <dali/internal/render/renderers/render-geometry.h>
-#include <dali/internal/render/renderers/render-renderer.h>
-#include <dali/internal/render/renderers/render-sampler.h>
+#include <dali/internal/render/renderers/render-texture.h>
+#include <dali/internal/render/renderers/shader-cache.h>
+#include <dali/internal/render/renderers/uniform-buffer-manager.h>
+#include <dali/internal/render/renderers/uniform-buffer-view-pool.h>
#include <dali/internal/render/shaders/program-controller.h>
+#include <memory>
+
namespace Dali
{
-
namespace Internal
{
-
namespace SceneGraph
{
+#if defined(DEBUG_ENABLED)
+namespace
+{
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_RENDER_MANAGER");
+} // unnamed namespace
+#endif
-typedef OwnerContainer< Render::Renderer* > RendererOwnerContainer;
-typedef RendererOwnerContainer::Iterator RendererOwnerIter;
-
-typedef OwnerContainer< Render::Geometry* > GeometryOwnerContainer;
-typedef GeometryOwnerContainer::Iterator GeometryOwnerIter;
-
-typedef OwnerContainer< Render::Sampler* > SamplerOwnerContainer;
-typedef SamplerOwnerContainer::Iterator SamplerOwnerIter;
-
-typedef OwnerContainer< Render::NewTexture* > TextureOwnerContainer;
-typedef TextureOwnerContainer::Iterator TextureOwnerIter;
-
-typedef OwnerContainer< Render::FrameBuffer* > FrameBufferOwnerContainer;
-typedef FrameBufferOwnerContainer::Iterator FrameBufferOwnerIter;
-
-typedef OwnerContainer< Render::PropertyBuffer* > PropertyBufferOwnerContainer;
-typedef PropertyBufferOwnerContainer::Iterator PropertyBufferOwnerIter;
-
-typedef OwnerContainer< Render::RenderTracker* > RenderTrackerContainer;
-typedef RenderTrackerContainer::Iterator RenderTrackerIter;
-typedef RenderTrackerContainer::ConstIterator RenderTrackerConstIter;
+namespace
+{
+inline Graphics::Rect2D RecalculateScissorArea(Graphics::Rect2D scissorArea, int orientation, Rect<int32_t> viewportRect)
+{
+ Graphics::Rect2D newScissorArea;
+ if(orientation == 90)
+ {
+ newScissorArea.x = viewportRect.height - (scissorArea.y + scissorArea.height);
+ newScissorArea.y = scissorArea.x;
+ newScissorArea.width = scissorArea.height;
+ newScissorArea.height = scissorArea.width;
+ }
+ else if(orientation == 180)
+ {
+ newScissorArea.x = viewportRect.width - (scissorArea.x + scissorArea.width);
+ newScissorArea.y = viewportRect.height - (scissorArea.y + scissorArea.height);
+ newScissorArea.width = scissorArea.width;
+ newScissorArea.height = scissorArea.height;
+ }
+ else if(orientation == 270)
+ {
+ newScissorArea.x = scissorArea.y;
+ newScissorArea.y = viewportRect.width - (scissorArea.x + scissorArea.width);
+ newScissorArea.width = scissorArea.height;
+ newScissorArea.height = scissorArea.width;
+ }
+ else
+ {
+ newScissorArea.x = scissorArea.x;
+ newScissorArea.y = scissorArea.y;
+ newScissorArea.width = scissorArea.width;
+ newScissorArea.height = scissorArea.height;
+ }
+ return newScissorArea;
+}
+} // namespace
/**
* Structure to contain internal data
*/
struct RenderManager::Impl
{
- Impl( Integration::GlAbstraction& glAbstraction,
- Integration::GlSyncAbstraction& glSyncAbstraction,
- LockedResourceQueue& textureUploadedQ,
- TextureUploadedDispatcher& postProcessDispatcher,
- GeometryBatcher& geometryBatcher )
- : context( glAbstraction ),
- glSyncAbstraction( glSyncAbstraction ),
+ Impl(Graphics::Controller& graphicsController,
+ Integration::DepthBufferAvailable depthBufferAvailableParam,
+ Integration::StencilBufferAvailable stencilBufferAvailableParam,
+ Integration::PartialUpdateAvailable partialUpdateAvailableParam)
+ : graphicsController(graphicsController),
renderQueue(),
- textureCache( renderQueue, postProcessDispatcher, context ),
- textureUploadedQueue( textureUploadedQ ),
- instructions(),
- backgroundColor( Dali::Stage::DEFAULT_BACKGROUND_COLOR ),
- frameCount( 0 ),
- renderBufferIndex( SceneGraphBuffers::INITIAL_UPDATE_BUFFER_INDEX ),
- defaultSurfaceRect(),
+ renderAlgorithms(graphicsController),
+ frameCount(0u),
+ renderBufferIndex(SceneGraphBuffers::INITIAL_UPDATE_BUFFER_INDEX),
rendererContainer(),
samplerContainer(),
textureContainer(),
frameBufferContainer(),
- renderersAdded( false ),
- firstRenderCompleted( false ),
- defaultShader( NULL ),
- programController( glAbstraction ),
- geometryBatcher( geometryBatcher )
+ lastFrameWasRendered(false),
+ programController(graphicsController),
+ shaderCache(graphicsController),
+ depthBufferAvailable(depthBufferAvailableParam),
+ stencilBufferAvailable(stencilBufferAvailableParam),
+ partialUpdateAvailable(partialUpdateAvailableParam)
{
+ // Create thread pool with just one thread ( there may be a need to create more threads in the future ).
+ threadPool = std::make_unique<Dali::ThreadPool>();
+ threadPool->Initialize(1u);
+
+ uniformBufferManager = std::make_unique<Render::UniformBufferManager>(&graphicsController);
+ pipelineCache = std::make_unique<Render::PipelineCache>(graphicsController);
}
~Impl()
{
+ threadPool.reset(nullptr); // reset now to maintain correct destruction order
}
- void AddRenderTracker( Render::RenderTracker* renderTracker )
+ void AddRenderTracker(Render::RenderTracker* renderTracker)
{
- DALI_ASSERT_DEBUG( renderTracker != NULL );
- mRenderTrackers.PushBack( renderTracker );
+ DALI_ASSERT_DEBUG(renderTracker != nullptr);
+ mRenderTrackers.PushBack(renderTracker);
}
- void RemoveRenderTracker( Render::RenderTracker* renderTracker )
+ void RemoveRenderTracker(Render::RenderTracker* renderTracker)
{
- DALI_ASSERT_DEBUG( renderTracker != NULL );
- for(RenderTrackerIter iter = mRenderTrackers.Begin(), end = mRenderTrackers.End(); iter != end; ++iter)
- {
- if( *iter == renderTracker )
- {
- mRenderTrackers.Erase( iter );
- break;
- }
- }
+ mRenderTrackers.EraseObject(renderTracker);
}
void UpdateTrackers()
{
- for(RenderTrackerIter iter = mRenderTrackers.Begin(), end = mRenderTrackers.End(); iter != end; ++iter)
+ for(auto&& iter : mRenderTrackers)
{
- (*iter)->PollSyncObject();
+ iter->PollSyncObject();
}
}
// the order is important for destruction,
- // programs are owned by context at the moment.
- Context context; ///< holds the GL state
- Integration::GlSyncAbstraction& glSyncAbstraction; ///< GL sync abstraction
- RenderQueue renderQueue; ///< A message queue for receiving messages from the update-thread.
- TextureCache textureCache; ///< Cache for all GL textures
- LockedResourceQueue& textureUploadedQueue; ///< A queue for requesting resource post processing in update thread
+ Graphics::Controller& graphicsController;
+ RenderQueue renderQueue; ///< A message queue for receiving messages from the update-thread.
+
+ std::vector<SceneGraph::Scene*> sceneContainer; ///< List of pointers to the scene graph objects of the scenes
- // Render instructions describe what should be rendered during RenderManager::Render()
- // Owned by RenderManager. Update manager updates instructions for the next frame while we render the current one
- RenderInstructionContainer instructions;
+ Render::RenderAlgorithms renderAlgorithms; ///< The RenderAlgorithms object is used to action the renders required by a RenderInstruction
- Vector4 backgroundColor; ///< The glClear color used at the beginning of each frame.
+ uint32_t frameCount; ///< The current frame count
+ BufferIndex renderBufferIndex; ///< The index of the buffer to read from; this is opposite of the "update" buffer
- unsigned int frameCount; ///< The current frame count
- BufferIndex renderBufferIndex; ///< The index of the buffer to read from; this is opposite of the "update" buffer
+ OwnerContainer<Render::Renderer*> rendererContainer; ///< List of owned renderers
+ OwnerContainer<Render::Sampler*> samplerContainer; ///< List of owned samplers
+ OwnerContainer<Render::Texture*> textureContainer; ///< List of owned textures
+ OwnerContainer<Render::FrameBuffer*> frameBufferContainer; ///< List of owned framebuffers
+ OwnerContainer<Render::VertexBuffer*> vertexBufferContainer; ///< List of owned vertex buffers
+ OwnerContainer<Render::Geometry*> geometryContainer; ///< List of owned Geometries
- Rect<int> defaultSurfaceRect; ///< Rectangle for the default surface we are rendering to
+ bool lastFrameWasRendered; ///< Keeps track of the last frame being rendered due to having render instructions
- RendererOwnerContainer rendererContainer; ///< List of owned renderers
- SamplerOwnerContainer samplerContainer; ///< List of owned samplers
- TextureOwnerContainer textureContainer; ///< List of owned textures
- FrameBufferOwnerContainer frameBufferContainer; ///< List of owned framebuffers
- PropertyBufferOwnerContainer propertyBufferContainer; ///< List of owned property buffers
- GeometryOwnerContainer geometryContainer; ///< List of owned Geometries
+ OwnerContainer<Render::RenderTracker*> mRenderTrackers; ///< List of render trackers
- bool renderersAdded;
+ ProgramController programController; ///< Owner of the programs
+ Render::ShaderCache shaderCache; ///< The cache for the graphics shaders
- RenderTrackerContainer mRenderTrackers; ///< List of render trackers
+ std::unique_ptr<Render::UniformBufferManager> uniformBufferManager; ///< The uniform buffer manager
+ std::unique_ptr<Render::PipelineCache> pipelineCache;
- bool firstRenderCompleted; ///< False until the first render is done
- Shader* defaultShader; ///< Default shader to use
- ProgramController programController; ///< Owner of the GL programs
+ Integration::DepthBufferAvailable depthBufferAvailable; ///< Whether the depth buffer is available
+ Integration::StencilBufferAvailable stencilBufferAvailable; ///< Whether the stencil buffer is available
+ Integration::PartialUpdateAvailable partialUpdateAvailable; ///< Whether the partial update is available
- SceneGraph::GeometryBatcher& geometryBatcher; ///< Instance of geometry batcher
+ std::unique_ptr<Dali::ThreadPool> threadPool; ///< The thread pool
+ Vector<Graphics::Texture*> boundTextures; ///< The textures bound for rendering
+ Vector<Graphics::Texture*> textureDependencyList; ///< The dependency list of bound textures
};
-RenderManager* RenderManager::New( Integration::GlAbstraction& glAbstraction,
- Integration::GlSyncAbstraction& glSyncAbstraction,
- SceneGraph::GeometryBatcher& geometryBatcher,
- LockedResourceQueue& textureUploadedQ )
+RenderManager* RenderManager::New(Graphics::Controller& graphicsController,
+ Integration::DepthBufferAvailable depthBufferAvailable,
+ Integration::StencilBufferAvailable stencilBufferAvailable,
+ Integration::PartialUpdateAvailable partialUpdateAvailable)
{
- RenderManager* manager = new RenderManager;
- manager->mImpl = new Impl( glAbstraction, glSyncAbstraction, textureUploadedQ, *manager, geometryBatcher );
+ auto* manager = new RenderManager;
+ manager->mImpl = new Impl(graphicsController,
+ depthBufferAvailable,
+ stencilBufferAvailable,
+ partialUpdateAvailable);
return manager;
}
RenderManager::RenderManager()
-: mImpl(NULL)
+: mImpl(nullptr)
{
}
return mImpl->renderQueue;
}
-TextureCache& RenderManager::GetTextureCache()
+void RenderManager::SetShaderSaver(ShaderSaver& upstream)
{
- return mImpl->textureCache;
}
-void RenderManager::ContextCreated()
+void RenderManager::AddRenderer(OwnerPointer<Render::Renderer>& renderer)
{
- mImpl->context.GlContextCreated();
- mImpl->programController.GlContextCreated();
+ // Initialize the renderer as we are now in render thread
+ renderer->Initialize(mImpl->graphicsController, mImpl->programController, mImpl->shaderCache, *(mImpl->uniformBufferManager.get()), *(mImpl->pipelineCache.get()));
- // renderers, textures and gpu buffers cannot reinitialize themselves
- // so they rely on someone reloading the data for them
+ mImpl->rendererContainer.PushBack(renderer.Release());
}
-void RenderManager::ContextDestroyed()
+void RenderManager::RemoveRenderer(Render::Renderer* renderer)
{
- mImpl->context.GlContextDestroyed();
- mImpl->programController.GlContextDestroyed();
+ mImpl->rendererContainer.EraseObject(renderer);
+}
- // inform texture cache
- mImpl->textureCache.GlContextDestroyed(); // Clears gl texture ids
+void RenderManager::AddSampler(OwnerPointer<Render::Sampler>& sampler)
+{
+ sampler->Initialize(mImpl->graphicsController);
+ mImpl->samplerContainer.PushBack(sampler.Release());
+}
- //Inform textures
- for( TextureOwnerIter iter = mImpl->textureContainer.Begin(); iter != mImpl->textureContainer.End(); ++iter )
- {
- (*iter)->GlContextDestroyed();
- }
+void RenderManager::RemoveSampler(Render::Sampler* sampler)
+{
+ mImpl->samplerContainer.EraseObject(sampler);
+}
- //Inform framebuffers
- for( FrameBufferOwnerIter iter = mImpl->frameBufferContainer.Begin(); iter != mImpl->frameBufferContainer.End(); ++iter )
- {
- (*iter)->GlContextDestroyed();
- }
+void RenderManager::AddTexture(OwnerPointer<Render::Texture>& texture)
+{
+ texture->Initialize(mImpl->graphicsController);
+ mImpl->textureContainer.PushBack(texture.Release());
+}
+
+void RenderManager::RemoveTexture(Render::Texture* texture)
+{
+ DALI_ASSERT_DEBUG(NULL != texture);
- // inform renderers
- RendererOwnerContainer::Iterator end = mImpl->rendererContainer.End();
- RendererOwnerContainer::Iterator iter = mImpl->rendererContainer.Begin();
- for( ; iter != end; ++iter )
+ // Find the texture, use std::find so we can do the erase safely
+ auto iter = std::find(mImpl->textureContainer.begin(), mImpl->textureContainer.end(), texture);
+
+ if(iter != mImpl->textureContainer.end())
{
- GlResourceOwner* renderer = *iter;
- renderer->GlContextDestroyed(); // Clear up vertex buffers
+ texture->Destroy();
+ mImpl->textureContainer.Erase(iter); // Texture found; now destroy it
}
}
-void RenderManager::DispatchTextureUploaded(ResourceId request)
+void RenderManager::UploadTexture(Render::Texture* texture, PixelDataPtr pixelData, const Texture::UploadParams& params)
{
- mImpl->textureUploadedQueue.PushBack( request );
+ texture->Upload(pixelData, params);
}
-void RenderManager::SetShaderSaver( ShaderSaver& upstream )
+void RenderManager::GenerateMipmaps(Render::Texture* texture)
{
- mImpl->programController.SetShaderSaver( upstream );
+ texture->GenerateMipmaps();
}
-RenderInstructionContainer& RenderManager::GetRenderInstructionContainer()
+void RenderManager::SetFilterMode(Render::Sampler* sampler, uint32_t minFilterMode, uint32_t magFilterMode)
{
- return mImpl->instructions;
+ sampler->SetFilterMode(static_cast<Dali::FilterMode::Type>(minFilterMode),
+ static_cast<Dali::FilterMode::Type>(magFilterMode));
}
-void RenderManager::SetBackgroundColor( const Vector4& color )
+void RenderManager::SetWrapMode(Render::Sampler* sampler, uint32_t rWrapMode, uint32_t sWrapMode, uint32_t tWrapMode)
{
- mImpl->backgroundColor = color;
+ sampler->SetWrapMode(static_cast<Dali::WrapMode::Type>(rWrapMode),
+ static_cast<Dali::WrapMode::Type>(sWrapMode),
+ static_cast<Dali::WrapMode::Type>(tWrapMode));
}
-void RenderManager::SetDefaultSurfaceRect(const Rect<int>& rect)
+void RenderManager::AddFrameBuffer(OwnerPointer<Render::FrameBuffer>& frameBuffer)
{
- mImpl->defaultSurfaceRect = rect;
+ Render::FrameBuffer* frameBufferPtr = frameBuffer.Release();
+ mImpl->frameBufferContainer.PushBack(frameBufferPtr);
+ frameBufferPtr->Initialize(mImpl->graphicsController);
}
-void RenderManager::AddRenderer( Render::Renderer* renderer )
+void RenderManager::RemoveFrameBuffer(Render::FrameBuffer* frameBuffer)
{
- // Initialize the renderer as we are now in render thread
- renderer->Initialize( mImpl->context, mImpl->textureCache );
+ DALI_ASSERT_DEBUG(nullptr != frameBuffer);
- mImpl->rendererContainer.PushBack( renderer );
+ // Find the framebuffer, use std:find so we can safely do the erase
+ auto iter = std::find(mImpl->frameBufferContainer.begin(), mImpl->frameBufferContainer.end(), frameBuffer);
- if( !mImpl->renderersAdded )
+ if(iter != mImpl->frameBufferContainer.end())
{
- mImpl->renderersAdded = true;
+ frameBuffer->Destroy();
+ mImpl->frameBufferContainer.Erase(iter); // frameBuffer found; now destroy it
}
}
-void RenderManager::RemoveRenderer( Render::Renderer* renderer )
+void RenderManager::InitializeScene(SceneGraph::Scene* scene)
{
- DALI_ASSERT_DEBUG( NULL != renderer );
-
- RendererOwnerContainer& renderers = mImpl->rendererContainer;
+ scene->Initialize(mImpl->graphicsController, mImpl->depthBufferAvailable, mImpl->stencilBufferAvailable);
+ mImpl->sceneContainer.push_back(scene);
+}
- // Find the renderer
- for ( RendererOwnerIter iter = renderers.Begin(); iter != renderers.End(); ++iter )
+void RenderManager::UninitializeScene(SceneGraph::Scene* scene)
+{
+ auto iter = std::find(mImpl->sceneContainer.begin(), mImpl->sceneContainer.end(), scene);
+ if(iter != mImpl->sceneContainer.end())
{
- if ( *iter == renderer )
- {
- renderers.Erase( iter ); // Renderer found; now destroy it
- break;
- }
+ mImpl->sceneContainer.erase(iter);
}
}
-void RenderManager::AddSampler( Render::Sampler* sampler )
+void RenderManager::SurfaceReplaced(SceneGraph::Scene* scene)
{
- mImpl->samplerContainer.PushBack( sampler );
+ scene->Initialize(mImpl->graphicsController, mImpl->depthBufferAvailable, mImpl->stencilBufferAvailable);
}
-void RenderManager::RemoveSampler( Render::Sampler* sampler )
+void RenderManager::AttachColorTextureToFrameBuffer(Render::FrameBuffer* frameBuffer, Render::Texture* texture, uint32_t mipmapLevel, uint32_t layer)
{
- DALI_ASSERT_DEBUG( NULL != sampler );
-
- SamplerOwnerContainer& samplers = mImpl->samplerContainer;
-
- // Find the sampler
- for ( SamplerOwnerIter iter = samplers.Begin(); iter != samplers.End(); ++iter )
- {
- if ( *iter == sampler )
- {
- samplers.Erase( iter ); // Sampler found; now destroy it
- break;
- }
- }
+ frameBuffer->AttachColorTexture(texture, mipmapLevel, layer);
}
-void RenderManager::AddTexture( Render::NewTexture* texture )
+void RenderManager::AttachDepthTextureToFrameBuffer(Render::FrameBuffer* frameBuffer, Render::Texture* texture, uint32_t mipmapLevel)
{
- mImpl->textureContainer.PushBack( texture );
- texture->Initialize(mImpl->context);
+ frameBuffer->AttachDepthTexture(texture, mipmapLevel);
}
-void RenderManager::RemoveTexture( Render::NewTexture* texture )
+void RenderManager::AttachDepthStencilTextureToFrameBuffer(Render::FrameBuffer* frameBuffer, Render::Texture* texture, uint32_t mipmapLevel)
{
- DALI_ASSERT_DEBUG( NULL != texture );
-
- TextureOwnerContainer& textures = mImpl->textureContainer;
-
- // Find the texture
- for ( TextureOwnerIter iter = textures.Begin(); iter != textures.End(); ++iter )
- {
- if ( *iter == texture )
- {
- texture->Destroy( mImpl->context );
- textures.Erase( iter ); // Texture found; now destroy it
- break;
- }
- }
+ frameBuffer->AttachDepthStencilTexture(texture, mipmapLevel);
}
-void RenderManager::UploadTexture( Render::NewTexture* texture, PixelDataPtr pixelData, const NewTexture::UploadParams& params )
+void RenderManager::AddVertexBuffer(OwnerPointer<Render::VertexBuffer>& vertexBuffer)
{
- texture->Upload( mImpl->context, pixelData, params );
+ mImpl->vertexBufferContainer.PushBack(vertexBuffer.Release());
}
-void RenderManager::GenerateMipmaps( Render::NewTexture* texture )
+void RenderManager::RemoveVertexBuffer(Render::VertexBuffer* vertexBuffer)
{
- texture->GenerateMipmaps( mImpl->context );
+ mImpl->vertexBufferContainer.EraseObject(vertexBuffer);
}
-void RenderManager::SetFilterMode( Render::Sampler* sampler, unsigned int minFilterMode, unsigned int magFilterMode )
+void RenderManager::SetVertexBufferFormat(Render::VertexBuffer* vertexBuffer, OwnerPointer<Render::VertexBuffer::Format>& format)
{
- sampler->mMinificationFilter = static_cast<Dali::FilterMode::Type>(minFilterMode);
- sampler->mMagnificationFilter = static_cast<Dali::FilterMode::Type>(magFilterMode );
+ vertexBuffer->SetFormat(format.Release());
}
-void RenderManager::SetWrapMode( Render::Sampler* sampler, unsigned int rWrapMode, unsigned int sWrapMode, unsigned int tWrapMode )
+void RenderManager::SetVertexBufferData(Render::VertexBuffer* vertexBuffer, OwnerPointer<Vector<uint8_t>>& data, uint32_t size)
{
- sampler->mRWrapMode = static_cast<Dali::WrapMode::Type>(rWrapMode);
- sampler->mSWrapMode = static_cast<Dali::WrapMode::Type>(sWrapMode);
- sampler->mTWrapMode = static_cast<Dali::WrapMode::Type>(tWrapMode);
+ vertexBuffer->SetData(data.Release(), size);
}
-void RenderManager::AddFrameBuffer( Render::FrameBuffer* frameBuffer )
+void RenderManager::SetIndexBuffer(Render::Geometry* geometry, Dali::Vector<uint16_t>& indices)
{
- mImpl->frameBufferContainer.PushBack( frameBuffer );
- frameBuffer->Initialize(mImpl->context);
+ geometry->SetIndexBuffer(indices);
}
-void RenderManager::RemoveFrameBuffer( Render::FrameBuffer* frameBuffer )
+void RenderManager::AddGeometry(OwnerPointer<Render::Geometry>& geometry)
{
- DALI_ASSERT_DEBUG( NULL != frameBuffer );
+ mImpl->geometryContainer.PushBack(geometry.Release());
+}
- FrameBufferOwnerContainer& framebuffers = mImpl->frameBufferContainer;
+void RenderManager::RemoveGeometry(Render::Geometry* geometry)
+{
+ auto iter = std::find(mImpl->geometryContainer.begin(), mImpl->geometryContainer.end(), geometry);
- // Find the sampler
- for ( FrameBufferOwnerIter iter = framebuffers.Begin(); iter != framebuffers.End(); ++iter )
+ if(iter != mImpl->geometryContainer.end())
{
- if ( *iter == frameBuffer )
- {
- frameBuffer->Destroy( mImpl->context );
- framebuffers.Erase( iter ); // frameBuffer found; now destroy it
- break;
- }
+ mImpl->geometryContainer.Erase(iter);
}
}
-void RenderManager::AttachColorTextureToFrameBuffer( Render::FrameBuffer* frameBuffer, Render::NewTexture* texture, unsigned int mipmapLevel, unsigned int layer )
+void RenderManager::AttachVertexBuffer(Render::Geometry* geometry, Render::VertexBuffer* vertexBuffer)
{
- frameBuffer->AttachColorTexture( mImpl->context, texture, mipmapLevel, layer );
-}
+ DALI_ASSERT_DEBUG(nullptr != geometry);
-void RenderManager::AddPropertyBuffer( Render::PropertyBuffer* propertyBuffer )
-{
- mImpl->propertyBufferContainer.PushBack( propertyBuffer );
+ // Find the geometry
+ for(auto&& iter : mImpl->geometryContainer)
+ {
+ if(iter == geometry)
+ {
+ iter->AddVertexBuffer(vertexBuffer);
+ break;
+ }
+ }
}
-void RenderManager::RemovePropertyBuffer( Render::PropertyBuffer* propertyBuffer )
+void RenderManager::RemoveVertexBuffer(Render::Geometry* geometry, Render::VertexBuffer* vertexBuffer)
{
- DALI_ASSERT_DEBUG( NULL != propertyBuffer );
-
- PropertyBufferOwnerContainer& propertyBuffers = mImpl->propertyBufferContainer;
+ DALI_ASSERT_DEBUG(nullptr != geometry);
- // Find the sampler
- for ( PropertyBufferOwnerIter iter = propertyBuffers.Begin(); iter != propertyBuffers.End(); ++iter )
+ // Find the geometry
+ for(auto&& iter : mImpl->geometryContainer)
{
- if ( *iter == propertyBuffer )
+ if(iter == geometry)
{
- propertyBuffers.Erase( iter ); // Property buffer found; now destroy it
+ iter->RemoveVertexBuffer(vertexBuffer);
break;
}
}
}
-void RenderManager::SetPropertyBufferFormat(Render::PropertyBuffer* propertyBuffer, Render::PropertyBuffer::Format* format )
+void RenderManager::SetGeometryType(Render::Geometry* geometry, uint32_t geometryType)
{
- propertyBuffer->SetFormat( format );
+ geometry->SetType(Render::Geometry::Type(geometryType));
}
-void RenderManager::SetPropertyBufferData( Render::PropertyBuffer* propertyBuffer, Dali::Vector<char>* data, size_t size )
+void RenderManager::AddRenderTracker(Render::RenderTracker* renderTracker)
{
- propertyBuffer->SetData( data, size );
+ mImpl->AddRenderTracker(renderTracker);
}
-void RenderManager::SetIndexBuffer( Render::Geometry* geometry, Dali::Vector<unsigned short>& indices )
+void RenderManager::RemoveRenderTracker(Render::RenderTracker* renderTracker)
{
- geometry->SetIndexBuffer( indices );
+ mImpl->RemoveRenderTracker(renderTracker);
}
-void RenderManager::AddGeometry( Render::Geometry* geometry )
+void RenderManager::PreRender(Integration::RenderStatus& status, bool forceClear, bool uploadOnly)
{
- mImpl->geometryContainer.PushBack( geometry );
-}
+ DALI_PRINT_RENDER_START(mImpl->renderBufferIndex);
-void RenderManager::RemoveGeometry( Render::Geometry* geometry )
-{
- DALI_ASSERT_DEBUG( NULL != geometry );
+ // Rollback
+ mImpl->uniformBufferManager->GetUniformBufferViewPool(mImpl->renderBufferIndex)->Rollback();
- GeometryOwnerContainer& geometries = mImpl->geometryContainer;
+ // Increment the frame count at the beginning of each frame
+ ++mImpl->frameCount;
- // Find the geometry
- for ( GeometryOwnerIter iter = geometries.Begin(); iter != geometries.End(); ++iter )
+ // Process messages queued during previous update
+ mImpl->renderQueue.ProcessMessages(mImpl->renderBufferIndex);
+
+ uint32_t count = 0u;
+ for(auto& i : mImpl->sceneContainer)
{
- if ( *iter == geometry )
+ count += i->GetRenderInstructions().Count(mImpl->renderBufferIndex);
+ }
+
+ const bool haveInstructions = count > 0u;
+
+ DALI_LOG_INFO(gLogFilter, Debug::General, "Render: haveInstructions(%s) || mImpl->lastFrameWasRendered(%s) || forceClear(%s)\n", haveInstructions ? "true" : "false", mImpl->lastFrameWasRendered ? "true" : "false", forceClear ? "true" : "false");
+
+ // Only render if we have instructions to render, or the last frame was rendered (and therefore a clear is required).
+ if(haveInstructions || mImpl->lastFrameWasRendered || forceClear)
+ {
+ DALI_LOG_INFO(gLogFilter, Debug::General, "Render: Processing\n");
+
+ // Upload the geometries
+ for(auto&& geom : mImpl->geometryContainer)
{
- geometries.Erase( iter ); // Geometry found; now destroy it
- break;
+ geom->Upload(mImpl->graphicsController);
}
}
}
-void RenderManager::AddVertexBuffer( Render::Geometry* geometry, Render::PropertyBuffer* propertyBuffer )
+void RenderManager::PreRender(Integration::Scene& scene, std::vector<Rect<int>>& damagedRects)
{
- DALI_ASSERT_DEBUG( NULL != geometry );
+ if(mImpl->partialUpdateAvailable != Integration::PartialUpdateAvailable::TRUE)
+ {
+ return;
+ }
- GeometryOwnerContainer& geometries = mImpl->geometryContainer;
+ Internal::Scene& sceneInternal = GetImplementation(scene);
+ SceneGraph::Scene* sceneObject = sceneInternal.GetSceneObject();
+
+ if(sceneObject->IsRenderingSkipped())
+ {
+ // We don't need to calculate dirty rects
+ return;
+ }
- // Find the renderer
- for ( GeometryOwnerIter iter = geometries.Begin(); iter != geometries.End(); ++iter )
+ class DamagedRectsCleaner
{
- if ( *iter == geometry )
+ public:
+ explicit DamagedRectsCleaner(std::vector<Rect<int>>& damagedRects, Rect<int>& surfaceRect)
+ : mDamagedRects(damagedRects),
+ mSurfaceRect(surfaceRect),
+ mCleanOnReturn(true)
{
- (*iter)->AddPropertyBuffer( propertyBuffer );
- break;
}
+
+ void SetCleanOnReturn(bool cleanOnReturn)
+ {
+ mCleanOnReturn = cleanOnReturn;
+ }
+
+ ~DamagedRectsCleaner()
+ {
+ if(mCleanOnReturn)
+ {
+ mDamagedRects.clear();
+ mDamagedRects.push_back(mSurfaceRect);
+ }
+ }
+
+ private:
+ std::vector<Rect<int>>& mDamagedRects;
+ Rect<int> mSurfaceRect;
+ bool mCleanOnReturn;
+ };
+
+ Rect<int32_t> surfaceRect = sceneObject->GetSurfaceRect();
+
+ // Clean collected dirty/damaged rects on exit if 3d layer or 3d node or other conditions.
+ DamagedRectsCleaner damagedRectCleaner(damagedRects, surfaceRect);
+
+ // Mark previous dirty rects in the sorted array. The array is already sorted by node and renderer, frame number.
+ // so you don't need to sort: std::stable_sort(itemsDirtyRects.begin(), itemsDirtyRects.end());
+ std::vector<DirtyRect>& itemsDirtyRects = sceneObject->GetItemsDirtyRects();
+ for(DirtyRect& dirtyRect : itemsDirtyRects)
+ {
+ dirtyRect.visited = false;
}
-}
-void RenderManager::RemoveVertexBuffer( Render::Geometry* geometry, Render::PropertyBuffer* propertyBuffer )
-{
- DALI_ASSERT_DEBUG( NULL != geometry );
+ uint32_t instructionCount = sceneObject->GetRenderInstructions().Count(mImpl->renderBufferIndex);
+ for(uint32_t i = 0; i < instructionCount; ++i)
+ {
+ RenderInstruction& instruction = sceneObject->GetRenderInstructions().At(mImpl->renderBufferIndex, i);
- GeometryOwnerContainer& geometries = mImpl->geometryContainer;
+ if(instruction.mFrameBuffer)
+ {
+ return; // TODO: reset, we don't deal with render tasks with framebuffers (for now)
+ }
- // Find the renderer
- for ( GeometryOwnerIter iter = geometries.Begin(); iter != geometries.End(); ++iter )
+ const Camera* camera = instruction.GetCamera();
+ if(camera->mType == Camera::DEFAULT_TYPE && camera->mTargetPosition == Camera::DEFAULT_TARGET_POSITION)
+ {
+ const Node* node = instruction.GetCamera()->GetNode();
+ if(node)
+ {
+ Vector3 position;
+ Vector3 scale;
+ Quaternion orientation;
+ node->GetWorldMatrix(mImpl->renderBufferIndex).GetTransformComponents(position, orientation, scale);
+
+ Vector3 orientationAxis;
+ Radian orientationAngle;
+ orientation.ToAxisAngle(orientationAxis, orientationAngle);
+
+ if(position.x > Math::MACHINE_EPSILON_10000 ||
+ position.y > Math::MACHINE_EPSILON_10000 ||
+ orientationAxis != Vector3(0.0f, 1.0f, 0.0f) ||
+ orientationAngle != ANGLE_180 ||
+ scale != Vector3(1.0f, 1.0f, 1.0f))
+ {
+ return;
+ }
+ }
+ }
+ else
+ {
+ return;
+ }
+
+ Rect<int32_t> viewportRect;
+ if(instruction.mIsViewportSet)
+ {
+ const int32_t y = (surfaceRect.height - instruction.mViewport.height) - instruction.mViewport.y;
+ viewportRect.Set(instruction.mViewport.x, y, instruction.mViewport.width, instruction.mViewport.height);
+ if(viewportRect.IsEmpty() || !viewportRect.IsValid())
+ {
+ return; // just skip funny use cases for now, empty viewport means it is set somewhere else
+ }
+ }
+ else
+ {
+ viewportRect = surfaceRect;
+ }
+
+ const Matrix* viewMatrix = instruction.GetViewMatrix(mImpl->renderBufferIndex);
+ const Matrix* projectionMatrix = instruction.GetProjectionMatrix(mImpl->renderBufferIndex);
+ if(viewMatrix && projectionMatrix)
+ {
+ const RenderListContainer::SizeType count = instruction.RenderListCount();
+ for(RenderListContainer::SizeType index = 0u; index < count; ++index)
+ {
+ const RenderList* renderList = instruction.GetRenderList(index);
+ if(renderList)
+ {
+ if(!renderList->IsEmpty())
+ {
+ const std::size_t listCount = renderList->Count();
+ for(uint32_t listIndex = 0u; listIndex < listCount; ++listIndex)
+ {
+ RenderItem& item = renderList->GetItem(listIndex);
+ // If the item does 3D transformation, do early exit and clean the damaged rect array
+ if(item.mUpdateSize == Vector3::ZERO)
+ {
+ return;
+ }
+
+ Rect<int> rect;
+ DirtyRect dirtyRect(item.mNode, item.mRenderer, mImpl->frameCount, rect);
+ // If the item refers to updated node or renderer.
+ if(item.mIsUpdated ||
+ (item.mNode &&
+ (item.mNode->Updated() || (item.mRenderer && item.mRenderer->Updated(mImpl->renderBufferIndex, item.mNode)))))
+ {
+ item.mIsUpdated = false;
+
+ rect = RenderItem::CalculateViewportSpaceAABB(item.mModelViewMatrix, item.mUpdateSize, viewportRect.width, viewportRect.height);
+ if(rect.IsValid() && rect.Intersect(viewportRect) && !rect.IsEmpty())
+ {
+ const int left = rect.x;
+ const int top = rect.y;
+ const int right = rect.x + rect.width;
+ const int bottom = rect.y + rect.height;
+ rect.x = (left / 16) * 16;
+ rect.y = (top / 16) * 16;
+ rect.width = ((right + 16) / 16) * 16 - rect.x;
+ rect.height = ((bottom + 16) / 16) * 16 - rect.y;
+
+ // Found valid dirty rect.
+ // 1. Insert it in the sorted array of the dirty rects.
+ // 2. Mark the related dirty rects as visited so they will not be removed below.
+ // 3. Keep only last 3 dirty rects for the same node and renderer (Tizen uses 3 back buffers, Ubuntu 1).
+ dirtyRect.rect = rect;
+ auto dirtyRectPos = std::lower_bound(itemsDirtyRects.begin(), itemsDirtyRects.end(), dirtyRect);
+ dirtyRectPos = itemsDirtyRects.insert(dirtyRectPos, dirtyRect);
+
+ int c = 1;
+ while(++dirtyRectPos != itemsDirtyRects.end())
+ {
+ if(dirtyRectPos->node != item.mNode || dirtyRectPos->renderer != item.mRenderer)
+ {
+ break;
+ }
+
+ dirtyRectPos->visited = true;
+ Rect<int>& dirtRect = dirtyRectPos->rect;
+ rect.Merge(dirtRect);
+
+ c++;
+ if(c > 3) // no more then 3 previous rects
+ {
+ itemsDirtyRects.erase(dirtyRectPos);
+ break;
+ }
+ }
+
+ damagedRects.push_back(rect);
+ }
+ }
+ else
+ {
+ // 1. The item is not dirty, the node and renderer referenced by the item are still exist.
+ // 2. Mark the related dirty rects as visited so they will not be removed below.
+ auto dirtyRectPos = std::lower_bound(itemsDirtyRects.begin(), itemsDirtyRects.end(), dirtyRect);
+ while(dirtyRectPos != itemsDirtyRects.end())
+ {
+ if(dirtyRectPos->node != item.mNode || dirtyRectPos->renderer != item.mRenderer)
+ {
+ break;
+ }
+
+ dirtyRectPos->visited = true;
+ dirtyRectPos++;
+ }
+ }
+ }
+ }
+
+ // Reset updated flag from the root
+ Layer* sourceLayer = renderList->GetSourceLayer();
+ if(sourceLayer)
+ {
+ sourceLayer->SetUpdatedTree(false);
+ }
+ }
+ }
+ }
+ }
+
+ // Check removed nodes or removed renderers dirty rects
+ auto i = itemsDirtyRects.begin();
+ auto j = itemsDirtyRects.begin();
+ while(i != itemsDirtyRects.end())
{
- if ( *iter == geometry )
+ if(i->visited)
{
- (*iter)->RemovePropertyBuffer( propertyBuffer );
- break;
+ *j++ = *i;
+ }
+ else
+ {
+ Rect<int>& dirtRect = i->rect;
+ damagedRects.push_back(dirtRect);
}
+ i++;
}
-}
-void RenderManager::SetGeometryType( Render::Geometry* geometry, unsigned int geometryType )
-{
- geometry->SetType( Render::Geometry::Type(geometryType) );
+ itemsDirtyRects.resize(j - itemsDirtyRects.begin());
+ damagedRectCleaner.SetCleanOnReturn(false);
}
-void RenderManager::AddRenderTracker( Render::RenderTracker* renderTracker )
+void RenderManager::RenderScene(Integration::RenderStatus& status, Integration::Scene& scene, bool renderToFbo)
{
- mImpl->AddRenderTracker(renderTracker);
-}
+ SceneGraph::Scene* sceneObject = GetImplementation(scene).GetSceneObject();
+ Rect<int> clippingRect = sceneObject->GetSurfaceRect();
-void RenderManager::RemoveRenderTracker( Render::RenderTracker* renderTracker )
-{
- mImpl->RemoveRenderTracker(renderTracker);
+ RenderScene(status, scene, renderToFbo, clippingRect);
}
-void RenderManager::SetDefaultShader( Shader* shader )
+void RenderManager::RenderScene(Integration::RenderStatus& status, Integration::Scene& scene, bool renderToFbo, Rect<int>& clippingRect)
{
- mImpl->defaultShader = shader;
-}
+ if(mImpl->partialUpdateAvailable == Integration::PartialUpdateAvailable::TRUE && !renderToFbo && clippingRect.IsEmpty())
+ {
+ // ClippingRect is empty. Skip rendering
+ return;
+ }
-ProgramCache* RenderManager::GetProgramCache()
-{
- return &(mImpl->programController);
-}
+ // Reset main algorithms command buffer
+ mImpl->renderAlgorithms.ResetCommandBuffer();
-bool RenderManager::Render( Integration::RenderStatus& status )
-{
- DALI_PRINT_RENDER_START( mImpl->renderBufferIndex );
+ auto mainCommandBuffer = mImpl->renderAlgorithms.GetMainCommandBuffer();
- // Core::Render documents that GL context must be current before calling Render
- DALI_ASSERT_DEBUG( mImpl->context.IsGlContextCreated() );
+ Internal::Scene& sceneInternal = GetImplementation(scene);
+ SceneGraph::Scene* sceneObject = sceneInternal.GetSceneObject();
- // Increment the frame count at the beginning of each frame
- ++(mImpl->frameCount);
+ uint32_t count = sceneObject->GetRenderInstructions().Count(mImpl->renderBufferIndex);
- // Process messages queued during previous update
- mImpl->renderQueue.ProcessMessages( mImpl->renderBufferIndex );
+ std::vector<Graphics::RenderTarget*> targetstoPresent;
- // No need to make any gl calls if we've done 1st glClear & don't have any renderers to render during startup.
- if( !mImpl->firstRenderCompleted || mImpl->renderersAdded )
+ Rect<int32_t> surfaceRect = sceneObject->GetSurfaceRect();
+ if(clippingRect == surfaceRect)
{
- // switch rendering to adaptor provided (default) buffer
- mImpl->context.BindFramebuffer( GL_FRAMEBUFFER, 0 );
-
- mImpl->context.Viewport( mImpl->defaultSurfaceRect.x,
- mImpl->defaultSurfaceRect.y,
- mImpl->defaultSurfaceRect.width,
- mImpl->defaultSurfaceRect.height );
-
- mImpl->context.ClearColor( mImpl->backgroundColor.r,
- mImpl->backgroundColor.g,
- mImpl->backgroundColor.b,
- mImpl->backgroundColor.a );
-
- mImpl->context.ClearStencil( 0 );
-
- // Clear the entire color, depth and stencil buffers for the default framebuffer.
- // It is important to clear all 3 buffers, for performance on deferred renderers like Mali
- // e.g. previously when the depth & stencil buffers were NOT cleared, it caused the DDK to exceed a "vertex count limit",
- // and then stall. That problem is only noticeable when rendering a large number of vertices per frame.
- mImpl->context.SetScissorTest( false );
- mImpl->context.ColorMask( true );
- mImpl->context.DepthMask( true );
- mImpl->context.StencilMask( 0xFF ); // 8 bit stencil mask, all 1's
- mImpl->context.Clear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, Context::FORCE_CLEAR );
+ // Full rendering case
+ // Make clippingRect empty because we're doing full rendering now if the clippingRect is empty.
+ // To reduce side effects, keep this logic now.
+ clippingRect = Rect<int>();
+ }
- // reset the program matrices for all programs once per frame
- // this ensures we will set view and projection matrix once per program per camera
- mImpl->programController.ResetProgramMatrices();
+ for(uint32_t i = 0; i < count; ++i)
+ {
+ RenderInstruction& instruction = sceneObject->GetRenderInstructions().At(mImpl->renderBufferIndex, i);
- // if we don't have default shader, no point doing the render calls
- if( mImpl->defaultShader )
+ if((renderToFbo && !instruction.mFrameBuffer) || (!renderToFbo && instruction.mFrameBuffer))
{
- size_t count = mImpl->instructions.Count( mImpl->renderBufferIndex );
- for ( size_t i = 0; i < count; ++i )
+ continue; // skip
+ }
+
+ // Mark that we will require a post-render step to be performed (includes swap-buffers).
+ status.SetNeedsPostRender(true);
+
+ Rect<int32_t> viewportRect;
+
+ int32_t surfaceOrientation = sceneObject->GetSurfaceOrientation();
+
+ // @todo Should these be part of scene?
+ Integration::DepthBufferAvailable depthBufferAvailable = mImpl->depthBufferAvailable;
+ Integration::StencilBufferAvailable stencilBufferAvailable = mImpl->stencilBufferAvailable;
+
+ Graphics::RenderTarget* currentRenderTarget = nullptr;
+ Graphics::RenderPass* currentRenderPass = nullptr;
+ std::vector<Graphics::ClearValue> currentClearValues{};
+
+ if(instruction.mFrameBuffer)
+ {
+ // Ensure graphics framebuffer is created, bind attachments and create render passes
+ // Only happens once per framebuffer. If the create fails, e.g. no attachments yet,
+ // then don't render to this framebuffer.
+ if(!instruction.mFrameBuffer->GetGraphicsObject())
{
- RenderInstruction& instruction = mImpl->instructions.At( mImpl->renderBufferIndex, i );
+ const bool created = instruction.mFrameBuffer->CreateGraphicsObjects();
+ if(!created)
+ {
+ continue;
+ }
+ }
- DoRender( instruction, *mImpl->defaultShader );
+ auto& clearValues = instruction.mFrameBuffer->GetGraphicsRenderPassClearValues();
+
+ // Set the clear color for first color attachment
+ if(instruction.mIsClearColorSet && !clearValues.empty())
+ {
+ clearValues[0].color = {
+ instruction.mClearColor.r,
+ instruction.mClearColor.g,
+ instruction.mClearColor.b,
+ instruction.mClearColor.a};
}
- GLenum attachments[] = { GL_DEPTH, GL_STENCIL };
- mImpl->context.InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments);
- mImpl->UpdateTrackers();
+ currentClearValues = clearValues;
- mImpl->firstRenderCompleted = true;
+ auto loadOp = instruction.mIsClearColorSet ? Graphics::AttachmentLoadOp::CLEAR : Graphics::AttachmentLoadOp::LOAD;
+
+ // offscreen buffer
+ currentRenderTarget = instruction.mFrameBuffer->GetGraphicsRenderTarget();
+ currentRenderPass = instruction.mFrameBuffer->GetGraphicsRenderPass(loadOp, Graphics::AttachmentStoreOp::STORE);
}
- }
+ else // no framebuffer
+ {
+ // surface
+ auto& clearValues = sceneObject->GetGraphicsRenderPassClearValues();
- //Notify RenderGeometries that rendering has finished
- for ( GeometryOwnerIter iter = mImpl->geometryContainer.Begin(); iter != mImpl->geometryContainer.End(); ++iter )
- {
- (*iter)->OnRenderFinished();
- }
+ if(instruction.mIsClearColorSet)
+ {
+ clearValues[0].color = {
+ instruction.mClearColor.r,
+ instruction.mClearColor.g,
+ instruction.mClearColor.b,
+ instruction.mClearColor.a};
+ }
- /**
- * The rendering has finished; swap to the next buffer.
- * Ideally the update has just finished using this buffer; otherwise the render thread
- * should block until the update has finished.
- */
- mImpl->renderBufferIndex = (0 != mImpl->renderBufferIndex) ? 0 : 1;
+ currentClearValues = clearValues;
- DALI_PRINT_RENDER_END();
+ // @todo SceneObject should already have the depth clear / stencil clear in the clearValues array.
+ // if the window has a depth/stencil buffer.
+ if((depthBufferAvailable == Integration::DepthBufferAvailable::TRUE ||
+ stencilBufferAvailable == Integration::StencilBufferAvailable::TRUE) &&
+ (currentClearValues.size() <= 1))
+ {
+ currentClearValues.emplace_back();
+ currentClearValues.back().depthStencil.depth = 0;
+ currentClearValues.back().depthStencil.stencil = 0;
+ }
- // check if anything has been posted to the update thread, if IsEmpty then no update required.
- return !mImpl->textureUploadedQueue.IsEmpty();
-}
+ auto loadOp = instruction.mIsClearColorSet ? Graphics::AttachmentLoadOp::CLEAR : Graphics::AttachmentLoadOp::LOAD;
-void RenderManager::DoRender( RenderInstruction& instruction, Shader& defaultShader )
-{
- Rect<int> viewportRect;
- Vector4 clearColor;
+ currentRenderTarget = sceneObject->GetSurfaceRenderTarget();
+ currentRenderPass = sceneObject->GetGraphicsRenderPass(loadOp, Graphics::AttachmentStoreOp::STORE);
+ }
- if ( instruction.mIsClearColorSet )
- {
- clearColor = instruction.mClearColor;
- }
- else
- {
- clearColor = Dali::RenderTask::DEFAULT_CLEAR_COLOR;
- }
+ targetstoPresent.emplace_back(currentRenderTarget);
- FrameBufferTexture* offscreen = NULL;
+ // reset the program matrices for all programs once per frame
+ // this ensures we will set view and projection matrix once per program per camera
+ mImpl->programController.ResetProgramMatrices();
- if ( instruction.mOffscreenTextureId != 0 )
- {
- offscreen = mImpl->textureCache.GetFramebuffer( instruction.mOffscreenTextureId );
- DALI_ASSERT_DEBUG( NULL != offscreen );
+ if(instruction.mFrameBuffer)
+ {
+ // For each offscreen buffer, update the dependency list with the new texture id used by this frame buffer.
+ for(unsigned int i0 = 0, i1 = instruction.mFrameBuffer->GetColorAttachmentCount(); i0 < i1; ++i0)
+ {
+ mImpl->textureDependencyList.PushBack(instruction.mFrameBuffer->GetTexture(i0));
+ }
+ }
- if( NULL != offscreen &&
- offscreen->Prepare() )
+ if(!instruction.mIgnoreRenderToFbo && (instruction.mFrameBuffer != nullptr))
{
- // Check whether a viewport is specified, otherwise the full surface size is used
- if ( instruction.mIsViewportSet )
+ // Offscreen buffer rendering
+ if(instruction.mIsViewportSet)
{
- // For glViewport the lower-left corner is (0,0)
- const int y = ( offscreen->GetHeight() - instruction.mViewport.height ) - instruction.mViewport.y;
- viewportRect.Set( instruction.mViewport.x, y, instruction.mViewport.width, instruction.mViewport.height );
+ // For Viewport the lower-left corner is (0,0)
+ const int32_t y = (instruction.mFrameBuffer->GetHeight() - instruction.mViewport.height) - instruction.mViewport.y;
+ viewportRect.Set(instruction.mViewport.x, y, instruction.mViewport.width, instruction.mViewport.height);
}
else
{
- viewportRect.Set( 0, 0, offscreen->GetWidth(), offscreen->GetHeight() );
+ viewportRect.Set(0, 0, instruction.mFrameBuffer->GetWidth(), instruction.mFrameBuffer->GetHeight());
}
+ surfaceOrientation = 0;
}
- else
+ else // No Offscreen frame buffer rendering
{
- // Offscreen is NULL or could not be prepared.
- return;
+ // Check whether a viewport is specified, otherwise the full surface size is used
+ if(instruction.mIsViewportSet)
+ {
+ // For Viewport the lower-left corner is (0,0)
+ const int32_t y = (surfaceRect.height - instruction.mViewport.height) - instruction.mViewport.y;
+ viewportRect.Set(instruction.mViewport.x, y, instruction.mViewport.width, instruction.mViewport.height);
+ }
+ else
+ {
+ viewportRect = surfaceRect;
+ }
}
- }
- else if( instruction.mFrameBuffer != 0 )
- {
- instruction.mFrameBuffer->Bind( mImpl->context );
- if ( instruction.mIsViewportSet )
+
+ // Set surface orientation
+ // @todo Inform graphics impl by another route.
+ // was: mImpl->currentContext->SetSurfaceOrientation(surfaceOrientation);
+
+ /*** Clear region of framebuffer or surface before drawing ***/
+ bool clearFullFrameRect = (surfaceRect == viewportRect);
+ if(instruction.mFrameBuffer != nullptr)
{
- // For glViewport the lower-left corner is (0,0)
- const int y = ( instruction.mFrameBuffer->GetHeight() - instruction.mViewport.height ) - instruction.mViewport.y;
- viewportRect.Set( instruction.mViewport.x, y, instruction.mViewport.width, instruction.mViewport.height );
+ Viewport frameRect(0, 0, instruction.mFrameBuffer->GetWidth(), instruction.mFrameBuffer->GetHeight());
+ clearFullFrameRect = (frameRect == viewportRect);
}
- else
+
+ if(!clippingRect.IsEmpty())
{
- viewportRect.Set( 0, 0, instruction.mFrameBuffer->GetWidth(), instruction.mFrameBuffer->GetHeight() );
+ if(!clippingRect.Intersect(viewportRect))
+ {
+ DALI_LOG_ERROR("Invalid clipping rect %d %d %d %d\n", clippingRect.x, clippingRect.y, clippingRect.width, clippingRect.height);
+ clippingRect = Rect<int>();
+ }
+ clearFullFrameRect = false;
}
- }
- else // !(instruction.mOffscreenTexture)
- {
- // switch rendering to adaptor provided (default) buffer
- mImpl->context.BindFramebuffer( GL_FRAMEBUFFER, 0 );
- // Check whether a viewport is specified, otherwise the full surface size is used
- if ( instruction.mIsViewportSet )
+ Graphics::Rect2D scissorArea{viewportRect.x, viewportRect.y, uint32_t(viewportRect.width), uint32_t(viewportRect.height)};
+ if(instruction.mIsClearColorSet)
{
- // For glViewport the lower-left corner is (0,0)
- const int y = ( mImpl->defaultSurfaceRect.height - instruction.mViewport.height ) - instruction.mViewport.y;
- viewportRect.Set( instruction.mViewport.x, y, instruction.mViewport.width, instruction.mViewport.height );
+ if(!clearFullFrameRect)
+ {
+ if(!clippingRect.IsEmpty())
+ {
+ scissorArea = {clippingRect.x, clippingRect.y, uint32_t(clippingRect.width), uint32_t(clippingRect.height)};
+ }
+ }
}
- else
+
+ // Scissor's value should be set based on the default system coordinates.
+ // When the surface is rotated, the input values already were set with the rotated angle.
+ // So, re-calculation is needed.
+ scissorArea = RecalculateScissorArea(scissorArea, surfaceOrientation, viewportRect);
+
+ // Begin render pass
+ mainCommandBuffer->BeginRenderPass(
+ currentRenderPass,
+ currentRenderTarget,
+ scissorArea,
+ currentClearValues);
+
+ mainCommandBuffer->SetViewport({float(viewportRect.x),
+ float(viewportRect.y),
+ float(viewportRect.width),
+ float(viewportRect.height)});
+
+ // Clear the list of bound textures
+ mImpl->boundTextures.Clear();
+
+ mImpl->renderAlgorithms.ProcessRenderInstruction(
+ instruction,
+ mImpl->renderBufferIndex,
+ depthBufferAvailable,
+ stencilBufferAvailable,
+ mImpl->boundTextures,
+ viewportRect,
+ clippingRect,
+ surfaceOrientation);
+
+ Graphics::SyncObject* syncObject{nullptr};
+ // If the render instruction has an associated render tracker (owned separately)
+ // and framebuffer, create a one shot sync object, and use it to determine when
+ // the render pass has finished executing on GPU.
+ if(instruction.mRenderTracker && instruction.mFrameBuffer)
{
- viewportRect = mImpl->defaultSurfaceRect;
+ syncObject = instruction.mRenderTracker->CreateSyncObject(mImpl->graphicsController);
+ instruction.mRenderTracker = nullptr;
}
+ mainCommandBuffer->EndRenderPass(syncObject);
}
+ mImpl->renderAlgorithms.SubmitCommandBuffer();
- mImpl->context.Viewport(viewportRect.x, viewportRect.y, viewportRect.width, viewportRect.height);
+ std::sort(targetstoPresent.begin(), targetstoPresent.end());
- if ( instruction.mIsClearColorSet )
+ Graphics::RenderTarget* rt = nullptr;
+ for(auto& target : targetstoPresent)
{
- mImpl->context.ClearColor( clearColor.r,
- clearColor.g,
- clearColor.b,
- clearColor.a );
-
- // Clear the viewport area only
- mImpl->context.SetScissorTest( true );
- mImpl->context.Scissor( viewportRect.x, viewportRect.y, viewportRect.width, viewportRect.height );
- mImpl->context.ColorMask( true );
- mImpl->context.Clear( GL_COLOR_BUFFER_BIT , Context::CHECK_CACHED_VALUES );
- mImpl->context.SetScissorTest( false );
+ if(target != rt)
+ {
+ mImpl->graphicsController.PresentRenderTarget(target);
+ rt = target;
+ }
}
+}
- Render::ProcessRenderInstruction( instruction,
- mImpl->context,
- mImpl->textureCache,
- defaultShader,
- mImpl->geometryBatcher,
- mImpl->renderBufferIndex );
-
- if(instruction.mOffscreenTextureId != 0)
+void RenderManager::PostRender(bool uploadOnly)
+{
+ // Notify RenderGeometries that rendering has finished
+ for(auto&& iter : mImpl->geometryContainer)
{
- GLenum attachments[] = { GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT };
- mImpl->context.InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments);
+ iter->OnRenderFinished();
}
- if( instruction.mRenderTracker && offscreen != NULL )
+ mImpl->UpdateTrackers();
+
+ uint32_t count = 0u;
+ for(auto& scene : mImpl->sceneContainer)
{
- // This will create a sync object every frame this render tracker
- // is alive (though it should be now be created only for
- // render-once render tasks)
- instruction.mRenderTracker->CreateSyncObject( mImpl->glSyncAbstraction );
- instruction.mRenderTracker = NULL; // Only create once.
+ count += scene->GetRenderInstructions().Count(mImpl->renderBufferIndex);
}
+
+ const bool haveInstructions = count > 0u;
+
+ // If this frame was rendered due to instructions existing, we mark this so we know to clear the next frame.
+ mImpl->lastFrameWasRendered = haveInstructions;
+
+ /**
+ * The rendering has finished; swap to the next buffer.
+ * Ideally the update has just finished using this buffer; otherwise the render thread
+ * should block until the update has finished.
+ */
+ mImpl->renderBufferIndex = (0 != mImpl->renderBufferIndex) ? 0 : 1;
+
+ DALI_PRINT_RENDER_END();
}
} // namespace SceneGraph