mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 13:43:43 +00:00
apis/engines: Revise the clear() buffer behavior.
ThorVG has offered an option to clear the buffer since version 1.0. This is essential when users utilize the canvas target buffer with the main render target. They share the buffer and need to draw contents onto the existing contents. API: Result Canvas::clear(bool free = true) -> Result Canvas::clear(bool paints = true, bool buffer = true) Tvg_Result tvg_canvas_clear(Tvg_Canvas* canvas, bool free); -> Tvg_Result tvg_canvas_clear(Tvg_Canvas* canvas, bool paints, bool buffer); Issue: https://github.com/thorvg/thorvg/issues/1779 Co-Authored-By: Hermet Park <hermet@lottiefiles.com>
This commit is contained in:
parent
5374155048
commit
548962f5f8
15 changed files with 57 additions and 38 deletions
|
@ -603,14 +603,15 @@ public:
|
||||||
* Depending on the value of the @p free argument, the paints are either freed or retained.
|
* Depending on the value of the @p free argument, the paints are either freed or retained.
|
||||||
* So if you need to update paint properties while maintaining the existing scene structure, you can set @p free = false.
|
* So if you need to update paint properties while maintaining the existing scene structure, you can set @p free = false.
|
||||||
*
|
*
|
||||||
* @param[in] free If @c true, the memory occupied by paints is deallocated, otherwise it is not.
|
* @param[in] paints If @c true, The memory occupied by paints is deallocated; otherwise, the paints will be retained on the canvas.
|
||||||
|
* @param[in] buffer If @c true, the canvas target buffer is cleared with a zero value.
|
||||||
*
|
*
|
||||||
* @return Result::Success when succeed, Result::InsufficientCondition otherwise.
|
* @return Result::Success when succeed, Result::InsufficientCondition otherwise.
|
||||||
*
|
*
|
||||||
* @see Canvas::push()
|
* @see Canvas::push()
|
||||||
* @see Canvas::paints()
|
* @see Canvas::paints()
|
||||||
*/
|
*/
|
||||||
virtual Result clear(bool free = true) noexcept;
|
virtual Result clear(bool paints = true, bool buffer = true) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Request the canvas to update the paint objects.
|
* @brief Request the canvas to update the paint objects.
|
||||||
|
|
|
@ -614,18 +614,17 @@ TVG_DEPRECATED TVG_API Tvg_Result tvg_canvas_reserve(Tvg_Canvas* canvas, uint32_
|
||||||
* all paints should be released manually in order to avoid memory leaks.
|
* all paints should be released manually in order to avoid memory leaks.
|
||||||
*
|
*
|
||||||
* \param[in] canvas The Tvg_Canvas object to be cleared.
|
* \param[in] canvas The Tvg_Canvas object to be cleared.
|
||||||
* \param[in] free If @c true the memory occupied by paints is deallocated, otherwise it is not.
|
* \param[in] paints If @c true, The memory occupied by paints is deallocated; otherwise, the paints will be retained on the canvas.
|
||||||
|
* \param[in] buffer If @c true the canvas target buffer is cleared with a zero value.
|
||||||
*
|
*
|
||||||
* \return Tvg_Result enumeration.
|
* \return Tvg_Result enumeration.
|
||||||
* \retval TVG_RESULT_SUCCESS Succeed.
|
* \retval TVG_RESULT_SUCCESS Succeed.
|
||||||
* \retval TVG_RESULT_INVALID_ARGUMENT An invalid Tvg_Canvas pointer.
|
* \retval TVG_RESULT_INVALID_ARGUMENT An invalid Tvg_Canvas pointer.
|
||||||
* \retval TVG_RESULT_INSUFFICIENT_CONDITION An internal error.
|
* \retval TVG_RESULT_INSUFFICIENT_CONDITION An internal error.
|
||||||
*
|
*
|
||||||
* \warning Please use the @p free argument only when you know how it works, otherwise it's not recommended.
|
|
||||||
*
|
|
||||||
* \see tvg_canvas_destroy()
|
* \see tvg_canvas_destroy()
|
||||||
*/
|
*/
|
||||||
TVG_API Tvg_Result tvg_canvas_clear(Tvg_Canvas* canvas, bool free);
|
TVG_API Tvg_Result tvg_canvas_clear(Tvg_Canvas* canvas, bool paints, bool buffer);
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -93,10 +93,10 @@ TVG_API Tvg_Result tvg_canvas_reserve(Tvg_Canvas* canvas, uint32_t n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TVG_API Tvg_Result tvg_canvas_clear(Tvg_Canvas* canvas, bool free)
|
TVG_API Tvg_Result tvg_canvas_clear(Tvg_Canvas* canvas, bool paints, bool buffer)
|
||||||
{
|
{
|
||||||
if (!canvas) return TVG_RESULT_INVALID_ARGUMENT;
|
if (!canvas) return TVG_RESULT_INVALID_ARGUMENT;
|
||||||
return (Tvg_Result) reinterpret_cast<Canvas*>(canvas)->clear(free);
|
return (Tvg_Result) reinterpret_cast<Canvas*>(canvas)->clear(paints, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -246,6 +246,7 @@ void transitCb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress
|
||||||
}
|
}
|
||||||
|
|
||||||
//Draw the canvas
|
//Draw the canvas
|
||||||
|
tvg_canvas_clear(canvas, false, true);
|
||||||
tvg_canvas_draw(canvas);
|
tvg_canvas_draw(canvas);
|
||||||
tvg_canvas_sync(canvas);
|
tvg_canvas_sync(canvas);
|
||||||
|
|
||||||
|
|
|
@ -111,11 +111,10 @@ void GlComposeTask::run()
|
||||||
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, getSelfFbo()));
|
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, getSelfFbo()));
|
||||||
|
|
||||||
// clear this fbo
|
// clear this fbo
|
||||||
GLenum color_buffer = GL_COLOR_ATTACHMENT0;
|
if (mClearBuffer) {
|
||||||
const float transparent[] = {0.f, 0.f, 0.f, 0.f};
|
const float transparent[] = {0.f, 0.f, 0.f, 0.f};
|
||||||
|
GL_CHECK(glClearBufferfv(GL_COLOR, 0, transparent));
|
||||||
GL_CHECK(glDrawBuffers(1, &color_buffer));
|
}
|
||||||
GL_CHECK(glClearBufferfv(GL_COLOR, 0, transparent));
|
|
||||||
|
|
||||||
for(uint32_t i = 0; i < mTasks.count; i++) {
|
for(uint32_t i = 0; i < mTasks.count; i++) {
|
||||||
mTasks[i]->run();
|
mTasks[i]->run();
|
||||||
|
|
|
@ -103,6 +103,8 @@ public:
|
||||||
|
|
||||||
void run() override;
|
void run() override;
|
||||||
|
|
||||||
|
bool mClearBuffer = true;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
GLuint getTargetFbo() { return mTargetFbo; }
|
GLuint getTargetFbo() { return mTargetFbo; }
|
||||||
|
|
||||||
|
|
|
@ -49,8 +49,7 @@ static void _termEngine()
|
||||||
|
|
||||||
bool GlRenderer::clear()
|
bool GlRenderer::clear()
|
||||||
{
|
{
|
||||||
//TODO: (Request) to clear target
|
mClearBuffer = true;
|
||||||
// Will be adding glClearColor for input buffer
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,15 +97,17 @@ bool GlRenderer::sync()
|
||||||
|
|
||||||
task->setSize(surface.w, surface.h);
|
task->setSize(surface.w, surface.h);
|
||||||
|
|
||||||
|
task->mClearBuffer = mClearBuffer;
|
||||||
|
|
||||||
task->run();
|
task->run();
|
||||||
|
|
||||||
mGpuBuffer->unbind();
|
mGpuBuffer->unbind();
|
||||||
|
|
||||||
|
|
||||||
GL_CHECK(glDisable(GL_SCISSOR_TEST));
|
GL_CHECK(glDisable(GL_SCISSOR_TEST));
|
||||||
|
|
||||||
mRenderPassStack.clear();
|
mRenderPassStack.clear();
|
||||||
mPoolIndex = 0;
|
mPoolIndex = 0;
|
||||||
|
mClearBuffer = false;
|
||||||
|
|
||||||
delete task;
|
delete task;
|
||||||
|
|
||||||
|
|
|
@ -86,13 +86,16 @@ private:
|
||||||
|
|
||||||
GLint mTargetFboId = 0;
|
GLint mTargetFboId = 0;
|
||||||
RenderRegion mViewport;
|
RenderRegion mViewport;
|
||||||
std::unique_ptr<GlStageBuffer> mGpuBuffer;
|
//TODO: remove all unique_ptr / replace the vector with tvg::Array
|
||||||
|
unique_ptr<GlStageBuffer> mGpuBuffer;
|
||||||
vector<std::unique_ptr<GlProgram>> mPrograms;
|
vector<std::unique_ptr<GlProgram>> mPrograms;
|
||||||
unique_ptr<GlRenderTarget> mRootTarget = {};
|
unique_ptr<GlRenderTarget> mRootTarget = {};
|
||||||
vector<unique_ptr<GlRenderTarget>> mComposePool = {};
|
vector<unique_ptr<GlRenderTarget>> mComposePool = {};
|
||||||
size_t mPoolIndex = 0;
|
size_t mPoolIndex = 0;
|
||||||
vector<GlRenderPass> mRenderPassStack = {};
|
vector<GlRenderPass> mRenderPassStack = {};
|
||||||
vector<unique_ptr<Compositor>> mComposeStack = {};
|
vector<unique_ptr<Compositor>> mComposeStack = {};
|
||||||
|
|
||||||
|
bool mClearBuffer = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _TVG_GL_RENDERER_H_ */
|
#endif /* _TVG_GL_RENDERER_H_ */
|
||||||
|
|
|
@ -49,9 +49,9 @@ Result Canvas::push(unique_ptr<Paint> paint) noexcept
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Result Canvas::clear(bool free) noexcept
|
Result Canvas::clear(bool paints, bool buffer) noexcept
|
||||||
{
|
{
|
||||||
return pImpl->clear(free);
|
return pImpl->clear(paints, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -45,22 +45,19 @@ struct Canvas::Impl
|
||||||
//make it sure any deffered jobs
|
//make it sure any deffered jobs
|
||||||
if (renderer) renderer->sync();
|
if (renderer) renderer->sync();
|
||||||
|
|
||||||
clearPaints(true);
|
clearPaints();
|
||||||
delete(renderer);
|
delete(renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearPaints(bool free)
|
void clearPaints()
|
||||||
{
|
{
|
||||||
if (free) {
|
for (auto paint : paints) {
|
||||||
for (auto paint : paints) {
|
P(paint)->unref();
|
||||||
P(paint)->unref();
|
if (paint->pImpl->dispose(*renderer) && P(paint)->refCnt == 0) {
|
||||||
if (paint->pImpl->dispose(*renderer) && P(paint)->refCnt == 0) {
|
delete(paint);
|
||||||
delete(paint);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
paints.clear();
|
|
||||||
}
|
}
|
||||||
drawing = false;
|
paints.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result push(unique_ptr<Paint> paint)
|
Result push(unique_ptr<Paint> paint)
|
||||||
|
@ -76,12 +73,16 @@ struct Canvas::Impl
|
||||||
return update(p, true);
|
return update(p, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result clear(bool free)
|
Result clear(bool paints, bool buffer)
|
||||||
{
|
{
|
||||||
//Clear render target
|
if (drawing) return Result::InsufficientCondition;
|
||||||
if (!renderer || !renderer->clear()) return Result::InsufficientCondition;
|
|
||||||
|
|
||||||
clearPaints(free);
|
//Clear render target
|
||||||
|
if (buffer) {
|
||||||
|
if (!renderer || !renderer->clear()) return Result::InsufficientCondition;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (paints) clearPaints();
|
||||||
|
|
||||||
return Result::Success;
|
return Result::Success;
|
||||||
}
|
}
|
||||||
|
|
|
@ -242,6 +242,7 @@ ColorSpace WgRenderer::colorSpace() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WgRenderer::clear() {
|
bool WgRenderer::clear() {
|
||||||
|
mClearBuffer = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,9 +275,13 @@ bool WgRenderer::sync() {
|
||||||
WGPURenderPassColorAttachment colorAttachment{};
|
WGPURenderPassColorAttachment colorAttachment{};
|
||||||
colorAttachment.view = backBufferView;
|
colorAttachment.view = backBufferView;
|
||||||
colorAttachment.resolveTarget = nullptr;
|
colorAttachment.resolveTarget = nullptr;
|
||||||
colorAttachment.loadOp = WGPULoadOp_Clear;
|
if (mClearBuffer) {
|
||||||
|
colorAttachment.loadOp = WGPULoadOp_Clear
|
||||||
|
colorAttachment.clearValue = {0, 0, 0, 0};
|
||||||
|
} else {
|
||||||
|
colorAttachment.loadOp = WGPULoadOp_Load;
|
||||||
|
}
|
||||||
colorAttachment.storeOp = WGPUStoreOp_Store;
|
colorAttachment.storeOp = WGPUStoreOp_Store;
|
||||||
colorAttachment.clearValue = { 0.0f, 0.0f, 0.0f, 1.0 };
|
|
||||||
// render pass descriptor
|
// render pass descriptor
|
||||||
WGPURenderPassDescriptor renderPassDesc{};
|
WGPURenderPassDescriptor renderPassDesc{};
|
||||||
renderPassDesc.nextInChain = nullptr;
|
renderPassDesc.nextInChain = nullptr;
|
||||||
|
@ -351,6 +356,9 @@ bool WgRenderer::sync() {
|
||||||
wgpuSwapChainPresent(mSwapChain);
|
wgpuSwapChainPresent(mSwapChain);
|
||||||
|
|
||||||
mRenderDatas.clear();
|
mRenderDatas.clear();
|
||||||
|
|
||||||
|
mClearBuffer = false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,6 +87,8 @@ private:
|
||||||
WgGeometryData mGeometryDataWindow;
|
WgGeometryData mGeometryDataWindow;
|
||||||
WgPipelineBindGroupEmpty mPipelineBindGroupEmpty;
|
WgPipelineBindGroupEmpty mPipelineBindGroupEmpty;
|
||||||
WgPipelineBindGroupStroke mPipelineBindGroupStroke;
|
WgPipelineBindGroupStroke mPipelineBindGroupStroke;
|
||||||
|
|
||||||
|
bool mClearBuffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _TVG_WG_RENDERER_H_ */
|
#endif /* _TVG_WG_RENDERER_H_ */
|
||||||
|
|
|
@ -94,7 +94,7 @@ TEST_CASE("Canvas draw", "[capiSwCanvas]")
|
||||||
|
|
||||||
REQUIRE(tvg_canvas_draw(canvas) == TVG_RESULT_SUCCESS);
|
REQUIRE(tvg_canvas_draw(canvas) == TVG_RESULT_SUCCESS);
|
||||||
REQUIRE(tvg_canvas_sync(canvas) == TVG_RESULT_SUCCESS);
|
REQUIRE(tvg_canvas_sync(canvas) == TVG_RESULT_SUCCESS);
|
||||||
REQUIRE(tvg_canvas_clear(canvas, true) == TVG_RESULT_SUCCESS);
|
REQUIRE(tvg_canvas_clear(canvas, true, true) == TVG_RESULT_SUCCESS);
|
||||||
|
|
||||||
Tvg_Paint* paint2 = tvg_shape_new();
|
Tvg_Paint* paint2 = tvg_shape_new();
|
||||||
REQUIRE(paint);
|
REQUIRE(paint);
|
||||||
|
@ -129,11 +129,11 @@ TEST_CASE("Canvas update, clear and reuse", "[capiSwCanvas]")
|
||||||
REQUIRE(tvg_canvas_update_paint(canvas, paint) == TVG_RESULT_SUCCESS);
|
REQUIRE(tvg_canvas_update_paint(canvas, paint) == TVG_RESULT_SUCCESS);
|
||||||
|
|
||||||
//negative
|
//negative
|
||||||
REQUIRE(tvg_canvas_clear(canvas, false) == TVG_RESULT_INSUFFICIENT_CONDITION);
|
REQUIRE(tvg_canvas_clear(canvas, false, true) == TVG_RESULT_INSUFFICIENT_CONDITION);
|
||||||
|
|
||||||
uint32_t buffer[25];
|
uint32_t buffer[25];
|
||||||
REQUIRE(tvg_swcanvas_set_target(canvas, buffer, 5, 5, 5, TVG_COLORSPACE_ARGB8888) == TVG_RESULT_SUCCESS);
|
REQUIRE(tvg_swcanvas_set_target(canvas, buffer, 5, 5, 5, TVG_COLORSPACE_ARGB8888) == TVG_RESULT_SUCCESS);
|
||||||
REQUIRE(tvg_canvas_clear(canvas, false) == TVG_RESULT_SUCCESS);
|
REQUIRE(tvg_canvas_clear(canvas, false, true) == TVG_RESULT_SUCCESS);
|
||||||
|
|
||||||
REQUIRE(tvg_canvas_destroy(canvas) == TVG_RESULT_SUCCESS);
|
REQUIRE(tvg_canvas_destroy(canvas) == TVG_RESULT_SUCCESS);
|
||||||
|
|
||||||
|
|
Binary file not shown.
|
@ -169,6 +169,8 @@ TEST_CASE("Update", "[tvgSwCanvasBase]")
|
||||||
REQUIRE(canvas->update() == Result::Success);
|
REQUIRE(canvas->update() == Result::Success);
|
||||||
REQUIRE(canvas->draw() == Result::Success);
|
REQUIRE(canvas->draw() == Result::Success);
|
||||||
REQUIRE(canvas->update() == Result::InsufficientCondition);
|
REQUIRE(canvas->update() == Result::InsufficientCondition);
|
||||||
|
REQUIRE(canvas->clear() == Result::InsufficientCondition);
|
||||||
|
REQUIRE(canvas->sync() == Result::Success);
|
||||||
|
|
||||||
REQUIRE(canvas->clear() == Result::Success);
|
REQUIRE(canvas->clear() == Result::Success);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue