From: Seungho Baek Date: Fri, 15 Nov 2024 06:55:34 +0000 (+0900) Subject: [Tizen] Keep rendered buffer in framebuffer X-Git-Tag: accepted/tizen/9.0/unified/20241207.044225^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c94e5a5872d337d578abdb34d3a64e31b54eb834;p=platform%2Fcore%2Fuifw%2Fdali-core.git [Tizen] Keep rendered buffer in framebuffer - Users can use RenderTask API to request and to use the buffer. Change-Id: Iaf63a60f246df8dc48f152bc8a4b4c0b68cd1e1b Signed-off-by: Seungho Baek --- diff --git a/automated-tests/src/dali/dali-test-suite-utils/test-graphics-command-buffer.h b/automated-tests/src/dali/dali-test-suite-utils/test-graphics-command-buffer.h index 9df2d0faf..147246f44 100644 --- a/automated-tests/src/dali/dali-test-suite-utils/test-graphics-command-buffer.h +++ b/automated-tests/src/dali/dali-test-suite-utils/test-graphics-command-buffer.h @@ -834,6 +834,10 @@ public: mCallStack.PushCall("EndRenderPass", namedParams.str(), namedParams); } + void ReadPixels(uint8_t* buffer) override + { + } + void ExecuteCommandBuffers(std::vector&& commandBuffers) override { mCommands.emplace_back(); diff --git a/automated-tests/src/dali/utc-Dali-RenderTask.cpp b/automated-tests/src/dali/utc-Dali-RenderTask.cpp index db59e4257..401ffbfd4 100644 --- a/automated-tests/src/dali/utc-Dali-RenderTask.cpp +++ b/automated-tests/src/dali/utc-Dali-RenderTask.cpp @@ -5319,3 +5319,59 @@ int UtcDaliRenderTaskDestructWorkerThreadN(void) END_TEST; } + +int UtcDaliRenderTaskKeepRenderResult(void) +{ + TestApplication application; + + tet_infoline("Testing RenderTask::SignalFinished()"); + + CameraActor offscreenCameraActor = CameraActor::New(); + + application.GetScene().Add(offscreenCameraActor); + + Texture image = CreateTexture(TextureType::TEXTURE_2D, Pixel::RGBA8888, 10, 10); + Actor rootActor = CreateRenderableActor(image); + rootActor.SetProperty(Actor::Property::SIZE, Vector2(10.0f, 10.0f)); + application.GetScene().Add(rootActor); + + RenderTaskList taskList = application.GetScene().GetRenderTaskList(); + Texture frameBufferTexture = Texture::New(TextureType::TEXTURE_2D, Pixel::Format::RGBA8888, 10, 10); + FrameBuffer frameBuffer = FrameBuffer::New(frameBufferTexture.GetWidth(), frameBufferTexture.GetHeight()); + frameBuffer.AttachColorTexture(frameBufferTexture); + + RenderTask newTask = taskList.CreateTask(); + newTask.SetCameraActor(offscreenCameraActor); + newTask.SetSourceActor(rootActor); + newTask.SetInputEnabled(false); + newTask.SetClearColor(Vector4(0.f, 0.f, 0.f, 0.f)); + newTask.SetClearEnabled(true); + newTask.SetExclusive(true); + newTask.SetRefreshRate(RenderTask::REFRESH_ONCE); + newTask.SetFrameBuffer(frameBuffer); + newTask.KeepRenderResult(); + + bool finished = false; + RenderTaskFinished renderTaskFinished(finished); + newTask.FinishedSignal().Connect(&application, renderTaskFinished); + + DALI_TEST_CHECK(!newTask.GetRenderResult()); + + // Flush the queue and render. + application.SendNotification(); + application.Render(); + application.Render(); + application.SendNotification(); + DALI_TEST_CHECK(finished); + DALI_TEST_CHECK(newTask.GetRenderResult()); + + newTask.ClearRenderResult(); + + DALI_TEST_CHECK(newTask.GetRenderResult()); + + application.SendNotification(); + application.Render(); + DALI_TEST_CHECK(!newTask.GetRenderResult()); + + END_TEST; +} diff --git a/dali/graphics-api/graphics-command-buffer.h b/dali/graphics-api/graphics-command-buffer.h index 34eec9a36..a85db34dd 100644 --- a/dali/graphics-api/graphics-command-buffer.h +++ b/dali/graphics-api/graphics-command-buffer.h @@ -290,6 +290,12 @@ public: */ virtual void EndRenderPass(Graphics::SyncObject* syncObject) = 0; + /** + * @brief Request to read pixels + * @param[out] buffer to load pixel data. + */ + virtual void ReadPixels(uint8_t* buffer) = 0; + /** * @brief Executes a list of secondary command buffers * diff --git a/dali/graphics-api/graphics-types.h b/dali/graphics-api/graphics-types.h index 9922ead00..acb86e849 100644 --- a/dali/graphics-api/graphics-types.h +++ b/dali/graphics-api/graphics-types.h @@ -1081,10 +1081,11 @@ enum class TextureTiling */ struct ColorAttachment { - uint32_t attachmentId; - Texture* texture; - uint32_t layerId; - uint32_t levelId; + uint32_t attachmentId; + Texture* texture; + uint32_t layerId; + uint32_t levelId; + Dali::Pixel::Format pixelFormat; }; /** diff --git a/dali/internal/event/render-tasks/render-task-impl.cpp b/dali/internal/event/render-tasks/render-task-impl.cpp index f1a2f9ec9..c894cf75e 100644 --- a/dali/internal/event/render-tasks/render-task-impl.cpp +++ b/dali/internal/event/render-tasks/render-task-impl.cpp @@ -184,11 +184,21 @@ CameraActor* RenderTask::GetCameraActor() const void RenderTask::SetFrameBuffer(FrameBufferPtr frameBuffer) { + if(mFrameBuffer) + { + mFrameBuffer->ClearRenderResult(); + } + mFrameBuffer = frameBuffer; Render::FrameBuffer* renderFrameBufferPtr(nullptr); if(frameBuffer) { - renderFrameBufferPtr = mFrameBuffer->GetRenderObject(); + renderFrameBufferPtr = frameBuffer->GetRenderObject(); + } + + if(frameBuffer && mIsRequestedToKeepRenderResult) + { + frameBuffer->KeepRenderResult(); } if(GetRenderTaskSceneObject()) @@ -443,6 +453,10 @@ void RenderTask::SetRefreshRate(uint32_t refreshRate) DALI_LOG_INFO(gLogRender, Debug::General, "RenderTask::SetRefreshRate(this:%p, %d)\n", this, refreshRate); mRefreshRate = refreshRate; // cached for GetRefreshRate() + if(mRefreshRate == Dali::RenderTask::REFRESH_ONCE) + { + ClearRenderResult(); + } // Note - even when refreshRate is the same as mRefreshRate, a message should be sent @@ -672,6 +686,40 @@ void RenderTask::RenderUntil(Actor* stopperActor) } } +void RenderTask::KeepRenderResult() +{ + if(mRefreshRate == Dali::RenderTask::REFRESH_ONCE) + { + if(!mIsRequestedToKeepRenderResult) + { + mIsRequestedToKeepRenderResult = true; + if(mFrameBuffer) + { + mFrameBuffer->KeepRenderResult(); + } + } + } +} + +void RenderTask::ClearRenderResult() +{ + mIsRequestedToKeepRenderResult = false; + if(mFrameBuffer) + { + mFrameBuffer->ClearRenderResult(); + } +} + +Dali::PixelData RenderTask::GetRenderResult() +{ + Dali::PixelData pixelData; + if(mFrameBuffer) + { + pixelData = mFrameBuffer->GetRenderResult(); + } + return pixelData; +} + const SceneGraph::RenderTask* RenderTask::GetRenderTaskSceneObject() const { return static_cast(mUpdateObject); @@ -936,6 +984,7 @@ void RenderTask::EmitSignalFinish() { DALI_LOG_INFO(gLogRender, Debug::General, "RenderTask::EmitSignalFinish(this:%p)\n", this); + mIsRequestedToKeepRenderResult = false; if(!mSignalFinished.Empty()) { Dali::RenderTask handle(this); @@ -979,6 +1028,7 @@ RenderTask::RenderTask(const SceneGraph::RenderTask* sceneObject, RenderTaskList mRefreshRate(Dali::RenderTask::DEFAULT_REFRESH_RATE), mRefreshOnceCounter(0u), mScreenToFrameBufferFunction(Dali::RenderTask::DEFAULT_SCREEN_TO_FRAMEBUFFER_FUNCTION), + mIsRequestedToKeepRenderResult(false), mExclusive(Dali::RenderTask::DEFAULT_EXCLUSIVE), mInputEnabled(Dali::RenderTask::DEFAULT_INPUT_ENABLED), mClearEnabled(Dali::RenderTask::DEFAULT_CLEAR_ENABLED), @@ -1002,6 +1052,8 @@ RenderTask::~RenderTask() DALI_LOG_INFO(gLogRender, Debug::General, "RenderTask::~RenderTask(this:%p)\n", this); // scene object deletion is handled by our parent // scene object handles observation of source and camera + + ClearRenderResult(); } } // namespace Internal diff --git a/dali/internal/event/render-tasks/render-task-impl.h b/dali/internal/event/render-tasks/render-task-impl.h index efed82f39..d9855412f 100644 --- a/dali/internal/event/render-tasks/render-task-impl.h +++ b/dali/internal/event/render-tasks/render-task-impl.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -294,6 +295,21 @@ public: */ void RenderUntil(Actor* stopperActor); + /** + * @copydoc Dali::RenderTask::KeepRenderResult + */ + void KeepRenderResult(); + + /** + * @copydoc Dali::RenderTask::ClearRenderResult + */ + void ClearRenderResult(); + + /** + * @copydoc Dali::RenderTask::GetRenderResult + */ + Dali::PixelData GetRenderResult(); + public: // Used by RenderTaskList, which owns the SceneGraph::RenderTasks /** * Retrieve the scene-graph RenderTask object. @@ -420,6 +436,7 @@ private: uint32_t mRenderTaskId{0u}; + bool mIsRequestedToKeepRenderResult : 1; bool mExclusive : 1; ///< True if the render-task has exclusive access to the source Nodes. bool mInputEnabled : 1; ///< True if the render-task should be considered for input handling. bool mClearEnabled : 1; ///< True if the render-task should be clear the color buffer. diff --git a/dali/internal/event/rendering/frame-buffer-impl.cpp b/dali/internal/event/rendering/frame-buffer-impl.cpp index 317ffd4cc..1136b1c40 100644 --- a/dali/internal/event/rendering/frame-buffer-impl.cpp +++ b/dali/internal/event/rendering/frame-buffer-impl.cpp @@ -133,6 +133,24 @@ void FrameBuffer::SetSize(uint32_t width, uint32_t height) mHeight = height; } +void FrameBuffer::KeepRenderResult() +{ + KeepRenderResultToFrameBuffer(GetEventThreadServices().GetUpdateManager(), *mRenderObject); +} + +void FrameBuffer::ClearRenderResult() +{ + if(DALI_LIKELY(EventThreadServices::IsCoreRunning() && mRenderObject)) + { + ClearRenderResultToFrameBuffer(GetEventThreadServices().GetUpdateManager(), *mRenderObject); + } +} + +Dali::PixelData FrameBuffer::GetRenderResult() +{ + return mRenderObject->GetRenderResult(); +} + FrameBuffer::~FrameBuffer() { if(DALI_UNLIKELY(!Dali::Stage::IsCoreThread())) diff --git a/dali/internal/event/rendering/frame-buffer-impl.h b/dali/internal/event/rendering/frame-buffer-impl.h index 341e9de05..6a3f7c858 100644 --- a/dali/internal/event/rendering/frame-buffer-impl.h +++ b/dali/internal/event/rendering/frame-buffer-impl.h @@ -111,6 +111,24 @@ public: */ void SetSize(uint32_t width, uint32_t height); + /** + * @brief Requests to Keep rendering result. + */ + void KeepRenderResult(); + + /** + * @brief Requests to Clear the rendered result. + * @note Since the rendered result is kept in the render thread resource, this method asynchronously clears the result. + */ + void ClearRenderResult(); + + /** + * @brief Retrieves the rendered result as PixelData. + * @return Dali::PixelData that contains rendered result. + * If the frame is not yet rendered, empty handle is returned. + */ + Dali::PixelData GetRenderResult(); + private: // implementation /** * Constructor diff --git a/dali/internal/render/common/render-manager.cpp b/dali/internal/render/common/render-manager.cpp index 9caf165fd..f4dc289ea 100644 --- a/dali/internal/render/common/render-manager.cpp +++ b/dali/internal/render/common/render-manager.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include @@ -269,6 +270,7 @@ struct RenderManager::Impl sceneContainer.clear(); renderAlgorithms.DestroyCommandBuffer(); + renderedFrameBufferContainer.clear(); samplerContainer.Clear(); frameBufferContainer.Clear(); vertexBufferContainer.Clear(); @@ -296,12 +298,13 @@ struct RenderManager::Impl std::vector sceneContainer; ///< List of pointers to the scene graph objects of the scenes Render::RenderAlgorithms renderAlgorithms; ///< The RenderAlgorithms object is used to action the renders required by a RenderInstruction - Integration::OrderedSet samplerContainer; ///< List of owned samplers - Integration::OrderedSet frameBufferContainer; ///< List of owned framebuffers - Integration::OrderedSet vertexBufferContainer; ///< List of owned vertex buffers - Integration::OrderedSet geometryContainer; ///< List of owned Geometries - OwnerKeyContainer rendererContainer; ///< List of owned renderers - OwnerKeyContainer textureContainer; ///< List of owned textures + std::vector renderedFrameBufferContainer; ///< List of rendered frame buffer + Integration::OrderedSet samplerContainer; ///< List of owned samplers + Integration::OrderedSet frameBufferContainer; ///< List of owned framebuffers + Integration::OrderedSet vertexBufferContainer; ///< List of owned vertex buffers + Integration::OrderedSet geometryContainer; ///< List of owned Geometries + OwnerKeyContainer rendererContainer; ///< List of owned renderers + OwnerKeyContainer textureContainer; ///< List of owned textures Integration::OrderedSet mRenderTrackers; ///< List of owned render trackers @@ -1299,6 +1302,12 @@ void RenderManager::RenderScene(Integration::RenderStatus& status, Integration:: instruction.mRenderTracker = nullptr; } mainCommandBuffer->EndRenderPass(syncObject); + + if(instruction.mFrameBuffer && instruction.mFrameBuffer->IsKeepingRenderResultRequested()) + { + mainCommandBuffer->ReadPixels(instruction.mFrameBuffer->GetRenderResultBuffer()); + mImpl->renderedFrameBufferContainer.push_back(instruction.mFrameBuffer); + } } if(targetsToPresent.size() > 0u) @@ -1373,6 +1382,12 @@ void RenderManager::PostRender() mImpl->ClearUnusedProgramCacheIfNeed(); + for(auto& framebuffer : mImpl->renderedFrameBufferContainer) + { + framebuffer->SetRenderResultDrawn(); + } + mImpl->renderedFrameBufferContainer.clear(); + #if defined(LOW_SPEC_MEMORY_MANAGEMENT_ENABLED) // Shrink relevant containers if required. if(mImpl->containerRemovedFlags & ContainerRemovedFlagBits::RENDERER) diff --git a/dali/internal/render/renderers/render-frame-buffer.cpp b/dali/internal/render/renderers/render-frame-buffer.cpp index 965d28b9a..af0029bf7 100644 --- a/dali/internal/render/renderers/render-frame-buffer.cpp +++ b/dali/internal/render/renderers/render-frame-buffer.cpp @@ -28,7 +28,8 @@ namespace Internal namespace Render { FrameBuffer::FrameBuffer(uint32_t width, uint32_t height, Mask attachments) -: mWidth(width), +: mRenderResult(nullptr), + mWidth(width), mHeight(height), mDepthBuffer(attachments & Dali::FrameBuffer::Attachment::DEPTH), mStencilBuffer(attachments & Dali::FrameBuffer::Attachment::STENCIL) @@ -45,7 +46,10 @@ FrameBuffer::FrameBuffer(uint32_t width, uint32_t height, Mask attachments) } } -FrameBuffer::~FrameBuffer() = default; +FrameBuffer::~FrameBuffer() +{ + ClearRenderResult(); +} void FrameBuffer::Destroy() { @@ -67,7 +71,7 @@ void FrameBuffer::AttachColorTexture(Render::Texture* texture, uint32_t mipmapLe } uint32_t attachmentId = mCreateInfo.colorAttachments.size(); - Graphics::ColorAttachment colorAttachment{attachmentId, texture->GetGraphicsObject(), layer, mipmapLevel}; + Graphics::ColorAttachment colorAttachment{attachmentId, texture->GetGraphicsObject(), layer, mipmapLevel, texture->GetPixelFormat()}; mCreateInfo.colorAttachments.push_back(colorAttachment); } } @@ -106,6 +110,66 @@ void FrameBuffer::SetMultiSamplingLevel(uint8_t multiSamplingLevel) mCreateInfo.multiSamplingLevel = multiSamplingLevel; } +void FrameBuffer::KeepRenderResult() +{ + mIsKeepingRenderResultRequested = true; +} + +void FrameBuffer::ClearRenderResult() +{ + if(mIsKeepingRenderResultRequested) + { + mIsKeepingRenderResultRequested = false; + delete[] mRenderResult; + } + + Dali::Mutex::ScopedLock lock(mPixelDataMutex); + if(mRenderedPixelData) + { + mRenderedPixelData.Reset(); + } +} + +bool FrameBuffer::IsKeepingRenderResultRequested() const +{ + return mIsKeepingRenderResultRequested; +} + +uint8_t* FrameBuffer::GetRenderResultBuffer() +{ + uint8_t* buffer = nullptr; + if(mIsKeepingRenderResultRequested) + { + if(mRenderResult) + { + delete[] mRenderResult; + } + mRenderResult = new uint8_t[mWidth * mHeight * Dali::Pixel::GetBytesPerPixel(mCreateInfo.colorAttachments.begin()->pixelFormat)]; + buffer = mRenderResult; + } + return buffer; +} + +void FrameBuffer::SetRenderResultDrawn() +{ + Dali::Mutex::ScopedLock lock(mPixelDataMutex); + mRenderedPixelData = Dali::PixelData::New(mRenderResult, mWidth * mHeight * Dali::Pixel::GetBytesPerPixel(mCreateInfo.colorAttachments.begin()->pixelFormat), mWidth, mHeight, mCreateInfo.colorAttachments.begin()->pixelFormat, Dali::PixelData::DELETE_ARRAY); + mRenderResult = nullptr; + mIsKeepingRenderResultRequested = false; +} + +// Called from Main thread. +Dali::PixelData FrameBuffer::GetRenderResult() +{ + Dali::Mutex::ScopedLock lock(mPixelDataMutex); + Dali::PixelData pixelData; + if(!mIsKeepingRenderResultRequested && mRenderedPixelData) + { + pixelData = mRenderedPixelData; + } + return pixelData; +} + bool FrameBuffer::CreateGraphicsObjects() { bool created = false; diff --git a/dali/internal/render/renderers/render-frame-buffer.h b/dali/internal/render/renderers/render-frame-buffer.h index e1eb65769..2020d2dd8 100644 --- a/dali/internal/render/renderers/render-frame-buffer.h +++ b/dali/internal/render/renderers/render-frame-buffer.h @@ -21,6 +21,9 @@ #include #include #include +#include + +#include namespace Dali { @@ -110,6 +113,41 @@ public: */ void SetMultiSamplingLevel(uint8_t multiSamplingLevel); + /** + * @brief Requests to Keep rendering result. + */ + void KeepRenderResult(); + + /** + * @brief Requests to Clear the rendered result. + * @note Since the rendered result is kept in the render thread resource, this method asynchronously clears the result. + */ + void ClearRenderResult(); + + /** + * @brief Retrieves the rendered result as PixelData. + * @return Dali::PixelData that contains rendered result. + * If the frame is not yet rendered, empty handle is returned. + */ + Dali::PixelData GetRenderResult(); + + /** + * @brief Retrieves whether keeping render result is requested or not. + * @return True if keeping render result is requested. + */ + bool IsKeepingRenderResultRequested() const; + + /** + * @brief Retrieves buffer pointer that the render result is stored. + * @return Buffer pointer of the render result buffer. + */ + uint8_t* GetRenderResultBuffer(); + + /** + * @brief Notifies the drawing call of the frame is finished. + */ + void SetRenderResultDrawn(); + /** * @brief Get the number of textures bound to this frame buffer as color attachments. * @return The number of color attachments. @@ -172,6 +210,12 @@ private: // clear colors std::vector mClearValues{}; + bool mIsKeepingRenderResultRequested{false}; + bool mIsRenderResultDrawn{false}; + uint8_t* mRenderResult; + Dali::PixelData mRenderedPixelData; + Dali::Mutex mPixelDataMutex; + uint32_t mWidth; uint32_t mHeight; diff --git a/dali/internal/update/manager/update-manager.cpp b/dali/internal/update/manager/update-manager.cpp index 2e329faa7..a7c5c31bb 100644 --- a/dali/internal/update/manager/update-manager.cpp +++ b/dali/internal/update/manager/update-manager.cpp @@ -1602,6 +1602,16 @@ void UpdateManager::NotifyFrameCallback(FrameCallbackInterface* frameCallback, D mImpl->GetFrameCallbackProcessor(*this).NotifyFrameCallback(frameCallback, syncPoint); } +void UpdateManager::KeepRenderResultToFrameBuffer(Render::FrameBuffer* frameBuffer) +{ + frameBuffer->KeepRenderResult(); +} + +void UpdateManager::ClearRenderResultToFrameBuffer(Render::FrameBuffer* frameBuffer) +{ + frameBuffer->ClearRenderResult(); +} + void UpdateManager::AddSampler(OwnerPointer& sampler) { // Message has ownership of Sampler while in transit from update to render diff --git a/dali/internal/update/manager/update-manager.h b/dali/internal/update/manager/update-manager.h index 241a75ae2..dc23eaf61 100644 --- a/dali/internal/update/manager/update-manager.h +++ b/dali/internal/update/manager/update-manager.h @@ -739,6 +739,18 @@ public: */ void NotifyFrameCallback(FrameCallbackInterface* frameCallback, Dali::UpdateProxy::NotifySyncPoint syncPoint); + /** + * Requests to keep render result of the framebuffer. + * @param[in] frameBuffer The FrameBuffer + */ + void KeepRenderResultToFrameBuffer(Render::FrameBuffer* frameBuffer); + + /** + * Requests to clear kept render result of the framebuffer. + * @param[in] frameBuffer The FrameBuffer + */ + void ClearRenderResultToFrameBuffer(Render::FrameBuffer* frameBuffer); + /** * Get the update message queue capacity (mutex locked) */ @@ -1613,6 +1625,28 @@ inline void SetMultiSamplingLevelToFrameBuffer(UpdateManager& manager, Render::F new(slot) LocalType(&manager, &UpdateManager::SetMultiSamplingLevelToFrameBuffer, &frameBuffer, multiSamplingLevel); } +inline void KeepRenderResultToFrameBuffer(UpdateManager& manager, Render::FrameBuffer& frameBuffer) +{ + using LocalType = MessageValue1; + + // Reserve some memory inside the render queue + uint32_t* slot = manager.ReserveMessageSlot(sizeof(LocalType)); + + // Construct message in the render queue memory; note that delete should not be called on the return value + new(slot) LocalType(&manager, &UpdateManager::KeepRenderResultToFrameBuffer, &frameBuffer); +} + +inline void ClearRenderResultToFrameBuffer(UpdateManager& manager, Render::FrameBuffer& frameBuffer) +{ + using LocalType = MessageValue1; + + // Reserve some memory inside the render queue + uint32_t* slot = manager.ReserveMessageSlot(sizeof(LocalType)); + + // Construct message in the render queue memory; note that delete should not be called on the return value + new(slot) LocalType(&manager, &UpdateManager::ClearRenderResultToFrameBuffer, &frameBuffer); +} + inline void SetDepthIndicesMessage(UpdateManager& manager, OwnerPointer& nodeDepths) { using LocalType = MessageValue1>; diff --git a/dali/public-api/render-tasks/render-task.cpp b/dali/public-api/render-tasks/render-task.cpp index a30f97110..da224365c 100644 --- a/dali/public-api/render-tasks/render-task.cpp +++ b/dali/public-api/render-tasks/render-task.cpp @@ -323,6 +323,21 @@ void RenderTask::RenderUntil(Actor stopperActor) return GetImplementation(*this).RenderUntil(actorImpl); } +void RenderTask::KeepRenderResult() +{ + GetImplementation(*this).KeepRenderResult(); +} + +void RenderTask::ClearRenderResult() +{ + GetImplementation(*this).ClearRenderResult(); +} + +PixelData RenderTask::GetRenderResult() +{ + return GetImplementation(*this).GetRenderResult(); +} + RenderTask::RenderTask(Internal::RenderTask* internal) : Handle(internal) { diff --git a/dali/public-api/render-tasks/render-task.h b/dali/public-api/render-tasks/render-task.h index 1835d0623..f9a0a08ac 100644 --- a/dali/public-api/render-tasks/render-task.h +++ b/dali/public-api/render-tasks/render-task.h @@ -22,6 +22,7 @@ #include // uint32_t // INTERNAL INCLUDES +#include #include #include #include @@ -594,6 +595,30 @@ public: */ void RenderUntil(Actor stopperActor); + /** + * @brief Requests to Keep rendering result of this frame. + * @SINCE_2_3.51 + * @note This mothod is only available when the refresh rate is REFRESH_ONCE. + * @note The result can be used after the FinishedSignal is emitted. + */ + void KeepRenderResult(); + + /** + * @brief Requests to Clear the rendered result. + * @SINCE_2_3.51 + * @note Since the rendered result is kept in the render thread resource, this method asynchronously clears the result. + */ + void ClearRenderResult(); + + /** + * @brief Retrieves the rendered result as PixelData. + * @SINCE_2_3.51 + * @return Dali::PixelData that contains rendered result. + * @note This method is only available after the FinishedSignal is emitted. + * If this method is called before the Finishedsignal is emitted, empty handle is returned. + */ + Dali::PixelData GetRenderResult(); + public: // Signals /** * @brief If the refresh rate is REFRESH_ONCE, connect to this signal to be notified when a RenderTask has finished.