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:
Sergii Liebodkin 2023-11-20 10:59:38 +09:00 committed by Hermet Park
parent 5374155048
commit 548962f5f8
15 changed files with 57 additions and 38 deletions

View file

@ -603,14 +603,15 @@ public:
* 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.
*
* @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.
*
* @see Canvas::push()
* @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.

View file

@ -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.
*
* \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.
* \retval TVG_RESULT_SUCCESS Succeed.
* \retval TVG_RESULT_INVALID_ARGUMENT An invalid Tvg_Canvas pointer.
* \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()
*/
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);
/*!

View file

@ -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;
return (Tvg_Result) reinterpret_cast<Canvas*>(canvas)->clear(free);
return (Tvg_Result) reinterpret_cast<Canvas*>(canvas)->clear(paints, buffer);
}

View file

@ -246,6 +246,7 @@ void transitCb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress
}
//Draw the canvas
tvg_canvas_clear(canvas, false, true);
tvg_canvas_draw(canvas);
tvg_canvas_sync(canvas);

View file

@ -111,11 +111,10 @@ void GlComposeTask::run()
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, getSelfFbo()));
// clear this fbo
GLenum color_buffer = GL_COLOR_ATTACHMENT0;
if (mClearBuffer) {
const float transparent[] = {0.f, 0.f, 0.f, 0.f};
GL_CHECK(glDrawBuffers(1, &color_buffer));
GL_CHECK(glClearBufferfv(GL_COLOR, 0, transparent));
}
for(uint32_t i = 0; i < mTasks.count; i++) {
mTasks[i]->run();

View file

@ -103,6 +103,8 @@ public:
void run() override;
bool mClearBuffer = true;
protected:
GLuint getTargetFbo() { return mTargetFbo; }

View file

@ -49,8 +49,7 @@ static void _termEngine()
bool GlRenderer::clear()
{
//TODO: (Request) to clear target
// Will be adding glClearColor for input buffer
mClearBuffer = true;
return true;
}
@ -98,15 +97,17 @@ bool GlRenderer::sync()
task->setSize(surface.w, surface.h);
task->mClearBuffer = mClearBuffer;
task->run();
mGpuBuffer->unbind();
GL_CHECK(glDisable(GL_SCISSOR_TEST));
mRenderPassStack.clear();
mPoolIndex = 0;
mClearBuffer = false;
delete task;

View file

@ -86,13 +86,16 @@ private:
GLint mTargetFboId = 0;
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;
unique_ptr<GlRenderTarget> mRootTarget = {};
vector<unique_ptr<GlRenderTarget>> mComposePool = {};
size_t mPoolIndex = 0;
vector<GlRenderPass> mRenderPassStack = {};
vector<unique_ptr<Compositor>> mComposeStack = {};
bool mClearBuffer = true;
};
#endif /* _TVG_GL_RENDERER_H_ */

View file

@ -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);
}

View file

@ -45,13 +45,12 @@ struct Canvas::Impl
//make it sure any deffered jobs
if (renderer) renderer->sync();
clearPaints(true);
clearPaints();
delete(renderer);
}
void clearPaints(bool free)
void clearPaints()
{
if (free) {
for (auto paint : paints) {
P(paint)->unref();
if (paint->pImpl->dispose(*renderer) && P(paint)->refCnt == 0) {
@ -60,8 +59,6 @@ struct Canvas::Impl
}
paints.clear();
}
drawing = false;
}
Result push(unique_ptr<Paint> paint)
{
@ -76,12 +73,16 @@ struct Canvas::Impl
return update(p, true);
}
Result clear(bool free)
Result clear(bool paints, bool buffer)
{
//Clear render target
if (!renderer || !renderer->clear()) return Result::InsufficientCondition;
if (drawing) return Result::InsufficientCondition;
clearPaints(free);
//Clear render target
if (buffer) {
if (!renderer || !renderer->clear()) return Result::InsufficientCondition;
}
if (paints) clearPaints();
return Result::Success;
}

View file

@ -242,6 +242,7 @@ ColorSpace WgRenderer::colorSpace() {
}
bool WgRenderer::clear() {
mClearBuffer = true;
return true;
}
@ -274,9 +275,13 @@ bool WgRenderer::sync() {
WGPURenderPassColorAttachment colorAttachment{};
colorAttachment.view = backBufferView;
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.clearValue = { 0.0f, 0.0f, 0.0f, 1.0 };
// render pass descriptor
WGPURenderPassDescriptor renderPassDesc{};
renderPassDesc.nextInChain = nullptr;
@ -351,6 +356,9 @@ bool WgRenderer::sync() {
wgpuSwapChainPresent(mSwapChain);
mRenderDatas.clear();
mClearBuffer = false;
return true;
}

View file

@ -87,6 +87,8 @@ private:
WgGeometryData mGeometryDataWindow;
WgPipelineBindGroupEmpty mPipelineBindGroupEmpty;
WgPipelineBindGroupStroke mPipelineBindGroupStroke;
bool mClearBuffer;
};
#endif /* _TVG_WG_RENDERER_H_ */

View file

@ -94,7 +94,7 @@ TEST_CASE("Canvas draw", "[capiSwCanvas]")
REQUIRE(tvg_canvas_draw(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();
REQUIRE(paint);
@ -129,11 +129,11 @@ TEST_CASE("Canvas update, clear and reuse", "[capiSwCanvas]")
REQUIRE(tvg_canvas_update_paint(canvas, paint) == TVG_RESULT_SUCCESS);
//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];
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);

Binary file not shown.

View file

@ -169,6 +169,8 @@ TEST_CASE("Update", "[tvgSwCanvasBase]")
REQUIRE(canvas->update() == Result::Success);
REQUIRE(canvas->draw() == Result::Success);
REQUIRE(canvas->update() == Result::InsufficientCondition);
REQUIRE(canvas->clear() == Result::InsufficientCondition);
REQUIRE(canvas->sync() == Result::Success);
REQUIRE(canvas->clear() == Result::Success);