From 9fb8a49d52c497ebe38a5958aff5ebde55104b7e Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sun, 23 Jun 2024 18:40:29 +0900 Subject: [PATCH] renderer/canvas: ++exceptional handling. do not allow change the target if the condition is not satisfied. --- inc/thorvg.h | 14 +++++++++++--- src/bindings/capi/thorvg_capi.h | 1 + src/renderer/tvgCanvas.h | 4 ++-- src/renderer/tvgGlCanvas.cpp | 2 ++ src/renderer/tvgSwCanvas.cpp | 2 ++ src/renderer/tvgWgCanvas.cpp | 6 +++--- test/capi/capiSwCanvas.cpp | 3 +++ 7 files changed, 24 insertions(+), 8 deletions(-) diff --git a/inc/thorvg.h b/inc/thorvg.h index a2ef6c80..a79a50b5 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -1685,11 +1685,13 @@ public: * @retval Result::Success When succeed. * @retval Result::MemoryCorruption When casting in the internal function implementation failed. * @retval Result::InvalidArguments In case no valid pointer is provided or the width, or the height or the stride is zero. + * @retval Result::InsufficientCondition if the canvas is performing rendering. Please ensure the canvas is synced. * @retval Result::NonSupport In case the software engine is not supported. * * @warning Do not access @p buffer during Canvas::push() - Canvas::sync(). It should not be accessed while the engine is writing on it. * * @see Canvas::viewport() + * @see Canvas::sync() */ Result target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, Colorspace cs) noexcept; @@ -1752,10 +1754,13 @@ public: * @param[in] w The width (in pixels) of the raster image. * @param[in] h The height (in pixels) of the raster image. * - * @warning This API is experimental and not officially supported. It may be modified or removed in future versions. - * @warning Drawing on the main surface is currently not permitted. If the identifier (@p id) is set to @c 0, the operation will be aborted. + * @retval Result::Success When succeed. + * @retval Result::MemoryCorruption When casting in the internal function implementation failed. + * @retval Result::InsufficientCondition if the canvas is performing rendering. Please ensure the canvas is synced. + * @retval Result::NonSupport In case the gl engine is not supported. * * @see Canvas::viewport() + * @see Canvas::sync() * * @note Currently, this only allows the GL_RGBA8 color space format. * @note Experimental API @@ -1795,10 +1800,13 @@ public: * @param[in] instance WGPUInstance, context for all other wgpu objects. * @param[in] surace WGPUSurface, handle to a presentable surface. * - * @warning Please do not use it, this API is not official one. It could be modified in the next version. + * @retval Result::InsufficientCondition if the canvas is performing rendering. Please ensure the canvas is synced. + * @retval Result::NonSupport In case the wg engine is not supported. * * @note Experimental API + * * @see Canvas::viewport() + * @see Canvas::sync() */ Result target(void* instance, void* surface, uint32_t w, uint32_t h) noexcept; diff --git a/src/bindings/capi/thorvg_capi.h b/src/bindings/capi/thorvg_capi.h index 22e9f6ec..b8b1801b 100644 --- a/src/bindings/capi/thorvg_capi.h +++ b/src/bindings/capi/thorvg_capi.h @@ -452,6 +452,7 @@ TVG_API Tvg_Canvas* tvg_swcanvas_create(void); * \retval TVG_RESULT_SUCCESS Succeed. * \retval TVG_RESULT_MEMORY_CORRUPTION Casting in the internal function implementation failed. * \retval TVG_RESULT_INVALID_ARGUMENTS An invalid canvas or buffer pointer passed or one of the @p stride, @p w or @p h being zero. +* \retval TVG_RESULT_INSUFFICIENT_CONDITION if the canvas is performing rendering. Please ensure the canvas is synced. * \retval TVG_RESULT_NOT_SUPPORTED The software engine is not supported. * * \warning Do not access @p buffer during tvg_canvas_draw() - tvg_canvas_sync(). It should not be accessed while the engine is writing on it. diff --git a/src/renderer/tvgCanvas.h b/src/renderer/tvgCanvas.h index 7c9e9e52..3a11f20f 100644 --- a/src/renderer/tvgCanvas.h +++ b/src/renderer/tvgCanvas.h @@ -26,10 +26,10 @@ #include "tvgPaint.h" +enum Status : uint8_t {Synced = 0, Updating, Drawing}; + struct Canvas::Impl { - enum Status : uint8_t {Synced = 0, Updating, Drawing}; - list paints; RenderMethod* renderer; RenderRegion vport = {0, 0, INT32_MAX, INT32_MAX}; diff --git a/src/renderer/tvgGlCanvas.cpp b/src/renderer/tvgGlCanvas.cpp index 64b68577..fdf28d53 100644 --- a/src/renderer/tvgGlCanvas.cpp +++ b/src/renderer/tvgGlCanvas.cpp @@ -62,6 +62,8 @@ GlCanvas::~GlCanvas() Result GlCanvas::target(int32_t id, uint32_t w, uint32_t h) noexcept { #ifdef THORVG_GL_RASTER_SUPPORT + if (Canvas::pImpl->status != Status::Synced) return Result::InsufficientCondition; + //We know renderer type, avoid dynamic_cast for performance. auto renderer = static_cast(Canvas::pImpl->renderer); if (!renderer) return Result::MemoryCorruption; diff --git a/src/renderer/tvgSwCanvas.cpp b/src/renderer/tvgSwCanvas.cpp index 32c608f8..7a95167b 100644 --- a/src/renderer/tvgSwCanvas.cpp +++ b/src/renderer/tvgSwCanvas.cpp @@ -82,6 +82,8 @@ Result SwCanvas::mempool(MempoolPolicy policy) noexcept Result SwCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, Colorspace cs) noexcept { #ifdef THORVG_SW_RASTER_SUPPORT + if (Canvas::pImpl->status != Status::Synced) return Result::InsufficientCondition; + //We know renderer type, avoid dynamic_cast for performance. auto renderer = static_cast(Canvas::pImpl->renderer); if (!renderer) return Result::MemoryCorruption; diff --git a/src/renderer/tvgWgCanvas.cpp b/src/renderer/tvgWgCanvas.cpp index 7e7a6ceb..fbc6fd30 100644 --- a/src/renderer/tvgWgCanvas.cpp +++ b/src/renderer/tvgWgCanvas.cpp @@ -57,9 +57,9 @@ WgCanvas::~WgCanvas() Result WgCanvas::target(void* instance, void* surface, uint32_t w, uint32_t h) noexcept { #ifdef THORVG_WG_RASTER_SUPPORT - if (!instance) return Result::InvalidArguments; - if (!surface) return Result::InvalidArguments; - if ((w == 0) || (h == 0)) return Result::InvalidArguments; + if (Canvas::pImpl->status != Status::Synced) return Result::InsufficientCondition; + + if (!instance || !surface || (w == 0) || (h == 0)) return Result::InvalidArguments; //We know renderer type, avoid dynamic_cast for performance. auto renderer = static_cast(Canvas::pImpl->renderer); diff --git a/test/capi/capiSwCanvas.cpp b/test/capi/capiSwCanvas.cpp index 774a8750..9e2c9ddb 100644 --- a/test/capi/capiSwCanvas.cpp +++ b/test/capi/capiSwCanvas.cpp @@ -131,6 +131,9 @@ TEST_CASE("Canvas update, clear and reuse", "[capiSwCanvas]") //negative REQUIRE(tvg_canvas_clear(canvas, false, true) == TVG_RESULT_INSUFFICIENT_CONDITION); + //make it sure sync before changing the target + REQUIRE(tvg_canvas_sync(canvas) == TVG_RESULT_SUCCESS); + 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, true) == TVG_RESULT_SUCCESS);