/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
#include <dali/internal/render/common/render-manager.h>
#include <dali/internal/render/queue/render-queue.h>
+#include <dali/internal/render/renderers/render-vertex-buffer.h>
// Un-comment to enable node tree debug logging
//#define NODE_TREE_LOGGING 1
panGestureProcessor(nullptr),
messageQueue(renderController, sceneGraphBuffers),
frameCallbackProcessor(nullptr),
- keepRenderingSeconds(0.0f),
nodeDirtyFlags(NodePropertyFlags::TRANSFORM), // set to TransformFlag to ensure full update the first time through Update()
frameCounter(0),
renderingBehavior(DevelStage::Rendering::IF_REQUIRED),
(*iter)->OnDestroy();
Node::Delete(*iter);
}
+ nodeIdMap.clear();
for(auto&& scene : scenes)
{
Vector<Node*> nodes; ///< A container of all instantiated nodes
+ std::unordered_map<uint32_t, Node*> nodeIdMap; ///< A container of nodes map by id.
+
Vector<Camera*> cameras; ///< A container of cameras. Note : these cameras are owned by Impl::nodes.
OwnerContainer<PropertyOwner*> customObjects; ///< A container of owned objects (with custom properties)
ResetterContainer<PropertyResetterBase> propertyResetters; ///< A container of property resetters
ResetterContainer<NodeResetter> nodeResetters; ///< A container of node resetters
+ ResetterContainer<RendererResetter> rendererResetters; ///< A container of renderer resetters
OwnerContainer<Animation*> animations; ///< A container of owned animations
OwnerContainer<PropertyNotification*> propertyNotifications; ///< A container of owner property notifications.
DiscardQueue<MemoryPoolKey<Renderer>, OwnerKeyContainer<Renderer>> rendererDiscardQueue;
DiscardQueue<Scene*, OwnerContainer<Scene*>> sceneDiscardQueue;
+ CompleteNotificationInterface::ParameterList notifyRequiredAnimations; ///< A temperal container of complete notify required animations, like animation finished, stopped, or loop completed.
+
OwnerPointer<PanGesture> panGestureProcessor; ///< Owned pan gesture processor; it lives for the lifecycle of UpdateManager
MessageQueue messageQueue; ///< The messages queued from the event-thread
OwnerPointer<FrameCallbackProcessor> frameCallbackProcessor; ///< Owned FrameCallbackProcessor, only created if required.
std::atomic<std::size_t> renderInstructionCapacity{0u};
- float keepRenderingSeconds; ///< Set via Dali::Stage::KeepRendering
- NodePropertyFlags nodeDirtyFlags; ///< cumulative node dirty flags from previous frame
- uint32_t frameCounter; ///< Frame counter used in debugging to choose which frame to debug and which to ignore.
- DevelStage::Rendering renderingBehavior; ///< Set via DevelStage::SetRenderingBehavior
+ NodePropertyFlags nodeDirtyFlags; ///< cumulative node dirty flags from previous frame
+ uint32_t frameCounter; ///< Frame counter used in debugging to choose which frame to debug and which to ignore.
+ DevelStage::Rendering renderingBehavior; ///< Set via DevelStage::SetRenderingBehavior
bool animationFinishedDuringUpdate; ///< Flag whether any animations finished during the Update()
bool previousUpdateScene; ///< True if the scene was updated in the previous frame (otherwise it was optimized out)
rootLayer->CreateTransform(&mImpl->transformManager);
rootLayer->SetRoot(true);
- AddNodeResetter(*rootLayer);
+ rootLayer->AddInitializeResetter(*this);
+
+ // Do not allow to insert duplicated nodes.
+ // It could be happened if node id is overflowed.
+ DALI_ASSERT_ALWAYS(mImpl->nodeIdMap.insert({rootLayer->GetId(), rootLayer}).second);
mImpl->scenes.emplace_back(new Impl::SceneInfo(rootLayer));
}
}
}
+ mImpl->nodeIdMap.erase(layer->GetId());
+
mImpl->nodeDiscardQueue.Add(mSceneGraphBuffers.GetUpdateBufferIndex(), layer);
// Notify the layer about impending destruction
AddCamera(static_cast<Camera*>(rawNode));
}
+ // Do not allow to insert duplicated nodes.
+ // It could be happened if node id is overflowed.
+ DALI_ASSERT_ALWAYS(mImpl->nodeIdMap.insert({rawNode->GetId(), rawNode}).second);
+
mImpl->nodes.PushBack(rawNode);
+
rawNode->CreateTransform(&mImpl->transformManager);
}
DALI_LOG_INFO(gLogFilter, Debug::General, "[%x] ConnectNode\n", node);
+ parent->SetDirtyFlag(NodePropertyFlags::DESCENDENT_HIERARCHY_CHANGED); // make parent dirty so that render items dont get reused
parent->ConnectChild(node);
- AddNodeResetter(*node);
+ node->AddInitializeResetter(*this);
// Inform the frame-callback-processor, if set, about the node-hierarchy changing
if(mImpl->frameCallbackProcessor)
Node* parent = node->GetParent();
DALI_ASSERT_ALWAYS(nullptr != parent);
- parent->SetDirtyFlag(NodePropertyFlags::CHILD_DELETED); // make parent dirty so that render items dont get reused
+ parent->SetDirtyFlag(NodePropertyFlags::CHILD_DELETED | NodePropertyFlags::DESCENDENT_HIERARCHY_CHANGED); // make parent dirty so that render items dont get reused
parent->DisconnectChild(mSceneGraphBuffers.GetUpdateBufferIndex(), *node);
RemoveCamera(static_cast<Camera*>(node));
}
+ mImpl->nodeIdMap.erase(node->GetId());
+
mImpl->nodeDiscardQueue.Add(mSceneGraphBuffers.GetUpdateBufferIndex(), node);
// Notify the Node about impending destruction
void UpdateManager::AddRenderTaskList(OwnerPointer<RenderTaskList>& taskList)
{
RenderTaskList* taskListPointer = taskList.Release();
- taskListPointer->SetRenderMessageDispatcher(&mImpl->renderMessageDispatcher);
+ taskListPointer->Initialize(*this, mImpl->renderMessageDispatcher);
mImpl->scenes.back()->taskList = taskListPointer;
}
bool animationFinished = animation->Stop(mSceneGraphBuffers.GetUpdateBufferIndex());
+ // Queue this animation into notify required animations. Since we need to send Finished signal
+ mImpl->notifyRequiredAnimations.PushBack(animation->GetNotifyId());
+
mImpl->animationFinishedDuringUpdate = mImpl->animationFinishedDuringUpdate || animationFinished;
}
+void UpdateManager::ClearAnimation(Animation* animation)
+{
+ DALI_ASSERT_DEBUG(animation && "NULL animation called to clear");
+
+ animation->Clear(mSceneGraphBuffers.GetUpdateBufferIndex());
+
+ // We should remove all notify lists what we requests before clear.
+ // TODO : Could we do this more faster?
+ Dali::EraseIf(mImpl->notifyRequiredAnimations, [&animation](const NotifierInterface::NotifyId& key) { return key == animation->GetNotifyId(); });
+}
+
void UpdateManager::RemoveAnimation(Animation* animation)
{
DALI_ASSERT_DEBUG(animation && "NULL animation called to remove");
animation->OnDestroy(mSceneGraphBuffers.GetUpdateBufferIndex());
DALI_ASSERT_DEBUG(animation->GetState() == Animation::Destroyed);
+
+ // Do not remove from container now. Destroyed animation will be removed at Animate.
}
bool UpdateManager::IsAnimationRunning() const
mImpl->nodeResetters.PushBack(nodeResetter.Release());
}
+void UpdateManager::AddRendererResetter(const Renderer& renderer)
+{
+ OwnerPointer<SceneGraph::RendererResetter> rendererResetter = SceneGraph::RendererResetter::New(renderer);
+ rendererResetter->Initialize();
+ mImpl->rendererResetters.PushBack(rendererResetter.Release());
+}
+
void UpdateManager::AddPropertyNotification(OwnerPointer<PropertyNotification>& propertyNotification)
{
mImpl->propertyNotifications.PushBack(propertyNotification.Release());
void UpdateManager::RemovePropertyNotification(PropertyNotification* propertyNotification)
{
- mImpl->propertyNotifications.EraseObject(propertyNotification);
+ auto iter = std::find(mImpl->propertyNotifications.Begin(), mImpl->propertyNotifications.End(), propertyNotification);
+ if(iter != mImpl->propertyNotifications.End())
+ {
+ mImpl->propertyNotifications.Erase(iter);
+ }
}
void UpdateManager::PropertyNotificationSetNotify(PropertyNotification* propertyNotification, PropertyNotification::NotifyMode notifyMode)
DALI_LOG_INFO(gLogFilter, Debug::General, "[%x] AddRenderer\n", renderer);
renderer->ConnectToSceneGraph(*mImpl->sceneController, mSceneGraphBuffers.GetUpdateBufferIndex());
+ renderer->AddInitializeResetter(*this);
+
mImpl->renderers.PushBack(rendererKey);
}
void UpdateManager::AddTextureSet(OwnerPointer<TextureSet>& textureSet)
{
+ textureSet->SetRenderMessageDispatcher(&mImpl->renderMessageDispatcher);
mImpl->textureSets.PushBack(textureSet.Release());
}
mImpl->messageQueue.EventProcessingStarted();
}
+void UpdateManager::EventProcessingFinished()
+{
+ mImpl->messageQueue.EventProcessingFinished();
+}
+
bool UpdateManager::FlushQueue()
{
return mImpl->messageQueue.FlushQueue();
// Reset node properties
mImpl->nodeResetters.ResetToBaseValues(bufferIndex);
+ // Reset renderer properties
+ mImpl->rendererResetters.ResetToBaseValues(bufferIndex);
+
// Reset all animating / constrained properties
mImpl->propertyResetters.ResetToBaseValues(bufferIndex);
bool UpdateManager::Animate(BufferIndex bufferIndex, float elapsedSeconds)
{
bool animationActive = false;
+ bool animationLooped = false;
- auto&& iter = mImpl->animations.Begin();
- bool animationLooped = false;
+ auto&& iter = mImpl->animations.Begin();
while(iter != mImpl->animations.End())
{
if(progressMarkerReached)
{
- mImpl->notificationManager.QueueMessage(Internal::NotifyProgressReachedMessage(mImpl->animationPlaylist, animation));
+ mImpl->notificationManager.QueueMessage(Internal::NotifyProgressReachedMessage(mImpl->animationPlaylist, animation->GetNotifyId()));
}
mImpl->animationFinishedDuringUpdate = mImpl->animationFinishedDuringUpdate || finished;
animationLooped = animationLooped || looped;
+ // queue the notification on finished or stoped
+ if(finished)
+ {
+ mImpl->notifyRequiredAnimations.PushBack(animation->GetNotifyId());
+ }
+
// Remove animations that had been destroyed but were still waiting for an update
if(animation->GetState() == Animation::Destroyed)
{
}
}
- // queue the notification on finished or looped (to update loop count)
- if(mImpl->animationFinishedDuringUpdate || animationLooped)
+ // The application should be notified by NotificationManager, in another thread
+ if(!mImpl->notifyRequiredAnimations.Empty())
{
- // The application should be notified by NotificationManager, in another thread
- mImpl->notificationManager.QueueCompleteNotification(&mImpl->animationPlaylist);
+ mImpl->notificationManager.QueueNotification(&mImpl->animationPlaylist, std::move(mImpl->notifyRequiredAnimations));
}
return animationActive;
}
-void UpdateManager::ConstrainCustomObjects(BufferIndex bufferIndex)
+void UpdateManager::ConstrainCustomObjects(PropertyOwnerContainer& postPropertyOwners, BufferIndex bufferIndex)
{
// Constrain custom objects (in construction order)
for(auto&& object : mImpl->customObjects)
{
ConstrainPropertyOwner(*object, bufferIndex);
+ if(!object->GetPostConstraints().Empty())
+ {
+ postPropertyOwners.PushBack(object);
+ }
}
}
-void UpdateManager::ConstrainRenderTasks(BufferIndex bufferIndex)
+void UpdateManager::ConstrainRenderTasks(PropertyOwnerContainer& postPropertyOwners, BufferIndex bufferIndex)
{
// Constrain render-tasks
for(auto&& scene : mImpl->scenes)
for(auto&& task : tasks)
{
ConstrainPropertyOwner(*task, bufferIndex);
+ if(!task->GetPostConstraints().Empty())
+ {
+ postPropertyOwners.PushBack(task);
+ }
}
}
}
}
-void UpdateManager::ConstrainShaders(BufferIndex bufferIndex)
+void UpdateManager::ConstrainShaders(PropertyOwnerContainer& postPropertyOwners, BufferIndex bufferIndex)
{
// constrain shaders... (in construction order)
for(auto&& shader : mImpl->shaders)
{
ConstrainPropertyOwner(*shader, bufferIndex);
+ if(!shader->GetPostConstraints().Empty())
+ {
+ postPropertyOwners.PushBack(shader);
+ }
}
}
bool valid = notification->Check(bufferIndex);
if(valid)
{
- mImpl->notificationManager.QueueMessage(PropertyChangedMessage(mImpl->propertyNotifier, notification, notification->GetValidity()));
+ mImpl->notificationManager.QueueMessage(PropertyChangedMessage(mImpl->propertyNotifier, notification->GetNotifyId(), notification->GetValidity()));
}
}
}
}
}
-void UpdateManager::UpdateRenderers(BufferIndex bufferIndex)
+void UpdateManager::UpdateRenderers(PropertyOwnerContainer& postPropertyOwners, BufferIndex bufferIndex)
{
for(const auto& rendererKey : mImpl->renderers)
{
// Apply constraints
auto renderer = rendererKey.Get();
ConstrainPropertyOwner(*renderer, bufferIndex);
+ if(!renderer->GetPostConstraints().Empty())
+ {
+ postPropertyOwners.PushBack(renderer);
+ }
mImpl->renderingRequired = renderer->PrepareRender(bufferIndex) || mImpl->renderingRequired;
}
}
-void UpdateManager::UpdateNodes(BufferIndex bufferIndex)
+void UpdateManager::UpdateNodes(PropertyOwnerContainer& postPropertyOwners, BufferIndex bufferIndex)
{
mImpl->nodeDirtyFlags = NodePropertyFlags::NOTHING;
// And add the renderers to the sorted layers. Start from root, which is also a layer
mImpl->nodeDirtyFlags |= UpdateNodeTree(*scene->root,
bufferIndex,
- mImpl->renderQueue);
+ mImpl->renderQueue,
+ postPropertyOwners);
}
}
}
mImpl->frameCallbackProcessor || // ..a frame callback processor is existed OR
gestureUpdated; // ..a gesture property was updated
- bool keepRendererRendering = false;
- mImpl->renderingRequired = false;
+ uint32_t keepUpdating = 0;
+ bool keepRendererRendering = false;
+ mImpl->renderingRequired = false;
// Although the scene-graph may not require an update, we still need to synchronize double-buffered
// values if the scene was updated in the previous frame.
// Animate
bool animationActive = Animate(bufferIndex, elapsedSeconds);
+ PropertyOwnerContainer postPropertyOwners;
// Constraint custom objects
- ConstrainCustomObjects(bufferIndex);
+ ConstrainCustomObjects(postPropertyOwners, bufferIndex);
// Clear the lists of renderers from the previous update
for(auto&& scene : mImpl->scenes)
// Call the frame-callback-processor if set
if(mImpl->frameCallbackProcessor)
{
- mImpl->frameCallbackProcessor->Update(bufferIndex, elapsedSeconds);
+ keepRendererRendering |= mImpl->frameCallbackProcessor->Update(bufferIndex, elapsedSeconds);
}
// Update node hierarchy, apply constraints,
- UpdateNodes(bufferIndex);
+ UpdateNodes(postPropertyOwners, bufferIndex);
// Apply constraints to RenderTasks, shaders
- ConstrainRenderTasks(bufferIndex);
- ConstrainShaders(bufferIndex);
+ ConstrainRenderTasks(postPropertyOwners, bufferIndex);
+ ConstrainShaders(postPropertyOwners, bufferIndex);
// Update renderers and apply constraints
- UpdateRenderers(bufferIndex);
+ UpdateRenderers(postPropertyOwners, bufferIndex);
// Update the transformations of all the nodes
if(mImpl->transformManager.Update())
mImpl->nodeDirtyFlags |= NodePropertyFlags::TRANSFORM;
}
+ // Constraint applied after transform manager updated. Only required property owner processed.
+ for(auto&& propertyOwner : postPropertyOwners)
+ {
+ ConstrainPropertyOwner(*propertyOwner, bufferIndex, false);
+ }
+
// Initialise layer renderable reuse
UpdateLayers(bufferIndex);
scene->scene->GetRenderInstructions().ResetAndReserve(bufferIndex,
static_cast<uint32_t>(scene->taskList->GetTasks().Count()));
+ bool sceneKeepUpdating = scene->scene->KeepRenderingCheck(elapsedSeconds);
+ if(sceneKeepUpdating)
+ {
+ keepUpdating |= KeepUpdating::STAGE_KEEP_RENDERING;
+ }
+
// If there are animations running, only add render instruction if at least one animation is currently active (i.e. not delayed)
// or the nodes are dirty
- if(!isAnimationRunning || animationActive || mImpl->renderingRequired || (mImpl->nodeDirtyFlags & RenderableUpdateFlags))
+ // or keep rendering is requested
+ if(!isAnimationRunning || animationActive || mImpl->renderingRequired || (mImpl->nodeDirtyFlags & RenderableUpdateFlags) || sceneKeepUpdating)
{
keepRendererRendering |= mImpl->renderTaskProcessor.Process(bufferIndex,
*scene->taskList,
if(!uploadOnly)
{
+ // check the countdown and notify
+ mImpl->renderTaskWaiting = false;
+
for(auto&& scene : mImpl->scenes)
{
if(scene && scene->root && scene->taskList)
{
RenderTaskList::RenderTaskContainer& tasks = scene->taskList->GetTasks();
- // check the countdown and notify
- bool doRenderOnceNotify = false;
- mImpl->renderTaskWaiting = false;
+ CompleteNotificationInterface::ParameterList notifyRequiredRenderTasks;
+
for(auto&& renderTask : tasks)
{
renderTask->UpdateState();
if(renderTask->HasRendered())
{
- doRenderOnceNotify = true;
+ notifyRequiredRenderTasks.PushBack(renderTask->GetNotifyId());
}
}
- if(doRenderOnceNotify)
+ if(!notifyRequiredRenderTasks.Empty())
{
DALI_LOG_INFO(gRenderTaskLogFilter, Debug::General, "Notify a render task has finished\n");
- mImpl->notificationManager.QueueCompleteNotification(scene->taskList->GetCompleteNotificationInterface());
+ mImpl->notificationManager.QueueNotification(scene->taskList->GetCompleteNotificationInterface(), std::move(notifyRequiredRenderTasks));
}
}
}
mImpl->previousUpdateScene = updateScene;
// Check whether further updates are required
- uint32_t keepUpdating = KeepUpdatingCheck(elapsedSeconds);
+ keepUpdating |= KeepUpdatingCheck(elapsedSeconds);
if(keepRendererRendering)
{
keepUpdating |= KeepUpdating::STAGE_KEEP_RENDERING;
+ }
+ if(keepUpdating & KeepUpdating::STAGE_KEEP_RENDERING)
+ {
// Set dirty flags for next frame to continue rendering
mImpl->nodeDirtyFlags |= RenderableUpdateFlags;
}
// Reset dirty flag
for(auto&& renderer : mImpl->renderers)
{
- renderer->ResetDirtyFlag();
+ renderer->SetUpdated(false);
}
for(auto&& shader : mImpl->shaders)
uint32_t UpdateManager::KeepUpdatingCheck(float elapsedSeconds) const
{
- // Update the duration set via Stage::KeepRendering()
- if(mImpl->keepRenderingSeconds > 0.0f)
- {
- mImpl->keepRenderingSeconds -= elapsedSeconds;
- }
-
uint32_t keepUpdatingRequest = KeepUpdating::NOT_REQUESTED;
// If the rendering behavior is set to continuously render, then continue to render.
- // If Stage::KeepRendering() has been called, then continue until the duration has elapsed.
// Keep updating until no messages are received and no animations are running.
// If an animation has just finished, update at least once more for Discard end-actions.
// No need to check for renderQueue as there is always a render after update and if that
// render needs another update it will tell the adaptor to call update again
- if((mImpl->renderingBehavior == DevelStage::Rendering::CONTINUOUSLY) ||
- (mImpl->keepRenderingSeconds > 0.0f))
+ if(mImpl->renderingBehavior == DevelStage::Rendering::CONTINUOUSLY)
{
keepUpdatingRequest |= KeepUpdating::STAGE_KEEP_RENDERING;
}
void UpdateManager::KeepRendering(float durationSeconds)
{
- mImpl->keepRenderingSeconds = std::max(mImpl->keepRenderingSeconds, durationSeconds);
+ for(auto&& scene : mImpl->scenes)
+ {
+ if(scene->scene)
+ {
+ scene->scene->KeepRendering(durationSeconds);
+ }
+ }
}
void UpdateManager::SetRenderingBehavior(DevelStage::Rendering renderingBehavior)
mImpl->renderingRequired = true;
}
+Node* UpdateManager::GetNodePointerById(uint32_t nodeId) const
+{
+ Node* foundNodePointer = nullptr;
+ auto iter = mImpl->nodeIdMap.find(nodeId);
+ if(iter != mImpl->nodeIdMap.end())
+ {
+ foundNodePointer = iter->second;
+ }
+ return foundNodePointer;
+}
+
void UpdateManager::SetLayerDepths(const SortedLayerPointers& layers, const Layer* rootLayer)
{
for(auto&& scene : mImpl->scenes)
// note, this vector is already in depth order.
// So if we reverse iterate, we can assume that
// my descendant node's depth index are updated.
+
+ // And also, This API is the last flushed message.
+ // We can now setup the DESCENDENT_HIERARCHY_CHANGED flag here.
for(auto rIter = nodeDepths->nodeDepths.rbegin(), rEndIter = nodeDepths->nodeDepths.rend(); rIter != rEndIter; rIter++)
{
auto* node = rIter->node;
+ node->PropagateDescendentFlags();
node->SetDepthIndex(rIter->sortedDepth);
if(node->IsChildrenReorderRequired())
{
mImpl->GetFrameCallbackProcessor(*this).RemoveFrameCallback(frameCallback);
}
+void UpdateManager::NotifyFrameCallback(FrameCallbackInterface* frameCallback, Dali::UpdateProxy::NotifySyncPoint syncPoint)
+{
+ mImpl->GetFrameCallbackProcessor(*this).NotifyFrameCallback(frameCallback, syncPoint);
+}
+
void UpdateManager::AddSampler(OwnerPointer<Render::Sampler>& sampler)
{
// Message has ownership of Sampler while in transit from update to render
new(slot) DerivedType(&mImpl->renderManager, &RenderManager::SetVertexBufferData, vertexBuffer, data, size);
}
+void UpdateManager::SetVertexBufferDivisor(Render::VertexBuffer* vertexBuffer, uint32_t divisor)
+{
+ using LocalType = MessageValue1<Render::VertexBuffer, uint32_t>;
+ uint32_t* slot = mImpl->renderQueue.ReserveMessageSlot(mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof(LocalType));
+ new(slot) LocalType(vertexBuffer, &Render::VertexBuffer::SetDivisor, divisor);
+}
+
+void UpdateManager::SetVertexBufferUpdateCallback(Render::VertexBuffer* vertexBuffer, Dali::VertexBufferUpdateCallback* callback)
+{
+ // Message has ownership of format while in transit from update -> render
+ using DerivedType = MessageValue2<RenderManager, Render::VertexBuffer*, Dali::VertexBufferUpdateCallback*>;
+
+ // Reserve some memory inside the render queue
+ uint32_t* slot = mImpl->renderQueue.ReserveMessageSlot(mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof(DerivedType));
+
+ // Construct message in the render queue memory; note that delete should not be called on the return value
+ new(slot) DerivedType(&mImpl->renderManager, &RenderManager::SetVertexBufferUpdateCallback, vertexBuffer, callback);
+}
+
void UpdateManager::AddGeometry(OwnerPointer<Render::Geometry>& geometry)
{
// Message has ownership of format while in transit from update -> render
new(slot) DerivedType(&mImpl->renderManager, &RenderManager::RemoveTexture, texture);
}
-void UpdateManager::UploadTexture(const Render::TextureKey& texture, PixelDataPtr pixelData, const Texture::UploadParams& params)
+void UpdateManager::UploadTexture(const Render::TextureKey& texture, PixelDataPtr pixelData, const Graphics::UploadParams& params)
{
- using DerivedType = MessageValue3<RenderManager, Render::TextureKey, PixelDataPtr, Texture::UploadParams>;
+ using DerivedType = MessageValue3<RenderManager, Render::TextureKey, PixelDataPtr, Graphics::UploadParams>;
// Reserve some memory inside the message queue
uint32_t* slot = mImpl->renderQueue.ReserveMessageSlot(mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof(DerivedType));
new(slot) DerivedType(&mImpl->renderManager, &RenderManager::GenerateMipmaps, texture);
}
+void UpdateManager::SetTextureSize(const Render::TextureKey& texture, const Dali::ImageDimensions& size)
+{
+ using DerivedType = MessageValue2<RenderManager, Render::TextureKey, Dali::ImageDimensions>;
+
+ // Reserve some memory inside the render queue
+ uint32_t* slot = mImpl->renderQueue.ReserveMessageSlot(mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof(DerivedType));
+
+ // Construct message in the render queue memory; note that delete should not be called on the return value
+ new(slot) DerivedType(&mImpl->renderManager, &RenderManager::SetTextureSize, texture, size);
+}
+
+void UpdateManager::SetTextureFormat(const Render::TextureKey& texture, Dali::Pixel::Format pixelFormat)
+{
+ using DerivedType = MessageValue2<RenderManager, Render::TextureKey, Dali::Pixel::Format>;
+
+ // Reserve some memory inside the render queue
+ uint32_t* slot = mImpl->renderQueue.ReserveMessageSlot(mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof(DerivedType));
+
+ // Construct message in the render queue memory; note that delete should not be called on the return value
+ new(slot) DerivedType(&mImpl->renderManager, &RenderManager::SetTextureFormat, texture, pixelFormat);
+}
+
void UpdateManager::AddFrameBuffer(OwnerPointer<Render::FrameBuffer>& frameBuffer)
{
using DerivedType = MessageValue1<RenderManager, OwnerPointer<Render::FrameBuffer>>;