From 53e5e783b7e0691cec95631de5f34d4e2c31a386 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 23 Apr 2025 14:01:31 +0900 Subject: [PATCH] api: revise engine initialization and termination Simplified parameters and ensured proper backend engine initialization by using reference checking through canvas instances. C++ API Modification: - Result Initializer::init(uint32_t threads, CanvasEngine engine) -> Result Initializer::init(uint32_t threads) - Result Initializer::term(CanvasEngine engine) -> Result Initializer::term() C API Modification: - Tvg_Result tvg_engine_init(Tvg_Engine engine_method, unsigned threads) -> Tvg_Result tvg_engine_init(unsigned threads); - Tvg_Result tvg_engine_term(Tvg_Engine engine_method) -> Tvg_Result tvg_engine_term() issue: https://github.com/thorvg/thorvg/issues/3116 --- examples/Capi.cpp | 4 +- examples/Example.h | 25 ++-- examples/MultiCanvas.cpp | 14 +-- inc/thorvg.h | 44 +++---- src/bindings/capi/thorvg_capi.h | 47 +++----- src/bindings/capi/tvgCapi.cpp | 8 +- src/renderer/gl_engine/tvgGlRenderer.cpp | 61 ++++------ src/renderer/gl_engine/tvgGlRenderer.h | 4 +- src/renderer/sw_engine/tvgSwPostEffect.cpp | 10 +- src/renderer/sw_engine/tvgSwRaster.cpp | 12 +- src/renderer/sw_engine/tvgSwRenderer.cpp | 94 ++++++--------- src/renderer/sw_engine/tvgSwRenderer.h | 4 +- src/renderer/tvgCommon.h | 2 + src/renderer/tvgGlCanvas.cpp | 24 ++-- src/renderer/tvgInitializer.cpp | 76 +++--------- src/renderer/tvgSwCanvas.cpp | 23 ++-- src/renderer/tvgWgCanvas.cpp | 21 ++-- src/renderer/wg_engine/tvgWgRenderer.cpp | 47 ++------ src/renderer/wg_engine/tvgWgRenderer.h | 4 +- test/testAccessor.cpp | 72 +++++------ test/testInitializer.cpp | 7 +- test/testPicture.cpp | 131 +++++++++++---------- test/testScene.cpp | 34 +++--- tools/lottie2gif/lottie2gif.cpp | 2 +- tools/svg2png/svg2png.cpp | 2 +- 25 files changed, 313 insertions(+), 459 deletions(-) diff --git a/examples/Capi.cpp b/examples/Capi.cpp index d15d2b52..230afdb1 100644 --- a/examples/Capi.cpp +++ b/examples/Capi.cpp @@ -268,7 +268,7 @@ float progress(uint32_t elapsed, float durationInSec) int main(int argc, char **argv) { - tvg_engine_init(Tvg_Engine(TVG_ENGINE_SW), 0); + tvg_engine_init(4); SDL_Init(SDL_INIT_VIDEO); @@ -333,7 +333,7 @@ int main(int argc, char **argv) SDL_Quit(); - tvg_engine_term(Tvg_Engine(TVG_ENGINE_SW)); + tvg_engine_term(); return 0; } diff --git a/examples/Example.h b/examples/Example.h index 13a47831..9ea003f7 100644 --- a/examples/Example.h +++ b/examples/Example.h @@ -148,10 +148,9 @@ struct Window bool clearBuffer = false; bool print = false; - Window(tvg::CanvasEngine engine, Example* example, uint32_t width, uint32_t height, uint32_t threadsCnt) + Window(Example* example, uint32_t width, uint32_t height, uint32_t threadsCnt) { - //Initialize ThorVG Engine (engine: raster method) - if (!verify(tvg::Initializer::init(threadsCnt, engine), "Failed to init ThorVG engine!")) return; + if (!verify(tvg::Initializer::init(threadsCnt), "Failed to init ThorVG engine!")) return; //Initialize the SDL SDL_Init(SDL_INIT_VIDEO); @@ -284,7 +283,7 @@ struct Window struct SwWindow : Window { - SwWindow(Example* example, uint32_t width, uint32_t height, uint32_t threadsCnt) : Window(tvg::CanvasEngine::Sw, example, width, height, threadsCnt) + SwWindow(Example* example, uint32_t width, uint32_t height, uint32_t threadsCnt) : Window(example, width, height, threadsCnt) { if (!initialized) return; @@ -323,7 +322,7 @@ struct GlWindow : Window { SDL_GLContext context; - GlWindow(Example* example, uint32_t width, uint32_t height, uint32_t threadsCnt) : Window(tvg::CanvasEngine::Gl, example, width, height, threadsCnt) + GlWindow(Example* example, uint32_t width, uint32_t height, uint32_t threadsCnt) : Window(example, width, height, threadsCnt) { if (!initialized) return; @@ -383,7 +382,7 @@ struct WgWindow : Window WGPUAdapter adapter; WGPUDevice device; - WgWindow(Example* example, uint32_t width, uint32_t height, uint32_t threadsCnt) : Window(tvg::CanvasEngine::Wg, example, width, height, threadsCnt) + WgWindow(Example* example, uint32_t width, uint32_t height, uint32_t threadsCnt) : Window(example, width, height, threadsCnt) { if (!initialized) return; @@ -484,7 +483,7 @@ struct WgWindow : Window #else struct WgWindow : Window { - WgWindow(Example* example, uint32_t width, uint32_t height, uint32_t threadsCnt) : Window(tvg::CanvasEngine::Wg, example, width, height, threadsCnt) + WgWindow(Example* example, uint32_t width, uint32_t height, uint32_t threadsCnt) : Window(example, width, height, threadsCnt) { cout << "webgpu driver is not detected!" << endl; } @@ -540,20 +539,20 @@ bool verify(tvg::Result result, string failMsg) int main(Example* example, int argc, char **argv, bool clearBuffer = false, uint32_t width = 800, uint32_t height = 800, uint32_t threadsCnt = 4, bool print = false) { - auto engine = tvg::CanvasEngine::Sw; + auto engine = 0; //0: sw, 1: gl, 2: wg if (argc > 1) { - if (!strcmp(argv[1], "gl")) engine = tvg::CanvasEngine::Gl; - if (!strcmp(argv[1], "wg")) engine = tvg::CanvasEngine::Wg; + if (!strcmp(argv[1], "gl")) engine = 1; + if (!strcmp(argv[1], "wg")) engine = 2; } unique_ptr window; - if (engine == tvg::CanvasEngine::Sw) { + if (engine == 0) { window = unique_ptr(new SwWindow(example, width, height, threadsCnt)); - } else if (engine == tvg::CanvasEngine::Gl) { + } else if (engine == 1) { window = unique_ptr(new GlWindow(example, width, height, threadsCnt)); - } else if (engine == tvg::CanvasEngine::Wg) { + } else if (engine == 2) { window = unique_ptr(new WgWindow(example, width, height, threadsCnt)); } diff --git a/examples/MultiCanvas.cpp b/examples/MultiCanvas.cpp index 502e8f80..c7052bac 100644 --- a/examples/MultiCanvas.cpp +++ b/examples/MultiCanvas.cpp @@ -401,20 +401,20 @@ void runWg() int main(int argc, char **argv) { - auto engine = tvg::CanvasEngine::Sw; + auto engine = 0; //0: sw, 1: gl, 2: wg if (argc > 1) { - if (!strcmp(argv[1], "gl")) engine = tvg::CanvasEngine::Gl; - if (!strcmp(argv[1], "wg")) engine = tvg::CanvasEngine::Wg; + if (!strcmp(argv[1], "gl")) engine = 1; + if (!strcmp(argv[1], "wg")) engine = 2; } - if (tvgexam::verify(tvg::Initializer::init(4, engine))) { + if (tvgexam::verify(tvg::Initializer::init(4))) { SDL_Init(SDL_INIT_VIDEO); - if (engine == tvg::CanvasEngine::Sw) runSw(); - else if (engine == tvg::CanvasEngine::Gl) runGl(); - else if (engine == tvg::CanvasEngine::Wg) runWg(); + if (engine == 0) runSw(); + else if (engine == 1) runGl(); + else if (engine == 2) runWg(); SDL_Quit(); diff --git a/inc/thorvg.h b/inc/thorvg.h index 9a029eb0..0c13414e 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -237,18 +237,6 @@ enum class SceneEffect : uint8_t }; -/** - * @brief Enumeration specifying the engine type used for the graphics backend. For multiple backends bitwise operation is allowed. - */ -enum class CanvasEngine : uint8_t -{ - All = 0, ///< All feasible rasterizers. @since 1.0 - Sw = (1 << 1), ///< CPU rasterizer. - Gl = (1 << 2), ///< OpenGL rasterizer. - Wg = (1 << 3), ///< WebGPU rasterizer. @since 0.15 -}; - - /** * @brief Enumeration specifying the ThorVG class type value. * @@ -1850,35 +1838,33 @@ class TVG_API Initializer final { public: /** - * @brief Initializes TVG engines. + * @brief Initializes the ThorVG engine. * - * TVG requires the running-engine environment. - * TVG runs its own task-scheduler for parallelizing rendering tasks efficiently. - * You can indicate the number of threads, the count of which is designated @p threads. - * In the initialization step, TVG will generate/spawn the threads as set by @p threads count. + * ThorVG requires an active runtime environment to operate. + * Internally, it utilizes a task scheduler to efficiently parallelize rendering operations. + * You can specify the number of worker threads using the @p threads parameter. + * During initialization, ThorVG will spawn the specified number of threads. * - * @param[in] threads The number of additional threads. Zero indicates only the main thread is to be used. - * @param[in] engine The engine types to initialize. This is relative to the Canvas types, in which it will be used. For multiple backends bitwise operation is allowed. + * @param[in] threads The number of worker threads to create. A value of zero indicates that only the main thread will be used. * - * @retval Result::NonSupport In case the engine type is not supported on the system. - * - * @note The Initializer keeps track of the number of times it was called. Threads count is fixed at the first init() call. + * @note The initializer uses internal reference counting to track multiple calls. + * The number of threads is fixed on the first call to init() and cannot be changed in subsequent calls. * @see Initializer::term() */ - static Result init(uint32_t threads, CanvasEngine engine = tvg::CanvasEngine::All) noexcept; + static Result init(uint32_t threads) noexcept; /** - * @brief Terminates TVG engines. + * @brief Terminates the ThorVG engine. * - * @param[in] engine The engine types to terminate. This is relative to the Canvas types, in which it will be used. For multiple backends bitwise operation is allowed + * Cleans up resources and stops any internal threads initialized by init(). * - * @retval Result::InsufficientCondition In case there is nothing to be terminated. - * @retval Result::NonSupport In case the engine type is not supported on the system. + * @retval Result::InsufficientCondition Returned if there is nothing to terminate (e.g., init() was not called). * - * @note Initializer does own reference counting for multiple calls. + * @note The initializer maintains a reference count for safe repeated use. + * Only the final call to term() will fully shut down the engine. * @see Initializer::init() */ - static Result term(CanvasEngine engine = tvg::CanvasEngine::All) noexcept; + static Result term() noexcept; /** * @brief Retrieves the version of the TVG engine. diff --git a/src/bindings/capi/thorvg_capi.h b/src/bindings/capi/thorvg_capi.h index 7aca0a36..ee4e6d2d 100644 --- a/src/bindings/capi/thorvg_capi.h +++ b/src/bindings/capi/thorvg_capi.h @@ -107,18 +107,6 @@ typedef struct _Tvg_Animation Tvg_Animation; typedef struct _Tvg_Accessor Tvg_Accessor; -/** -* @brief Enumeration specifying the engine type used for the graphics backend. For multiple backends bitwise operation is allowed. -* -* @ingroup ThorVGCapi_Initializer -*/ -typedef enum { - TVG_ENGINE_SW = (1 << 1), ///< CPU rasterizer - TVG_ENGINE_GL = (1 << 2), ///< OpenGL rasterizer - TVG_ENGINE_WG = (1 << 3) ///< WebGPU rasterizer -} Tvg_Engine; - - /** * @brief Enumeration specifying the result from the APIs. * @@ -342,43 +330,36 @@ typedef struct /* Engine API */ /************************************************************************/ /*! -* @brief Initializes TVG engines. +* @brief Initializes the ThorVG engine. * -* TVG requires the running-engine environment. -* TVG runs its own task-scheduler for parallelizing rendering tasks efficiently. -* You can indicate the number of threads, the count of which is designated @p threads. -* In the initialization step, TVG will generate/spawn the threads as set by @p threads count. +* ThorVG requires an active runtime environment to operate. +* Internally, it utilizes a task scheduler to efficiently parallelize rendering operations. +* You can specify the number of worker threads using the @p threads parameter. +* During initialization, ThorVG will spawn the specified number of threads. * -* @param[in] engine_method The engine types to initialize. This is relative to the Canvas types, in which it will be used. For multiple backends bitwise operation is allowed. -* @param[in] threads The number of additional threads used to perform rendering. Zero indicates only the main thread is to be used. +* @param[in] threads The number of worker threads to create. A value of zero indicates that only the main thread will be used. * * @return Tvg_Result enumeration. -* @retval TVG_RESULT_INVALID_ARGUMENT Unknown engine type. -* @retval TVG_RESULT_NOT_SUPPORTED Unsupported engine type. * -* @note The Initializer keeps track of the number of times it was called. Threads count is fixed at the first init() call. +* @note The initializer uses internal reference counting to track multiple calls. +* The number of threads is fixed on the first call to tvg_engine_init() and cannot be changed in subsequent calls. * @see tvg_engine_term() -* @see Tvg_Engine */ -TVG_API Tvg_Result tvg_engine_init(Tvg_Engine engine_method, unsigned threads); +TVG_API Tvg_Result tvg_engine_init(unsigned threads); /*! -* @brief Terminates TVG engines. +* @brief Terminates the ThorVG engine. * -* It should be called in case of termination of the TVG client with the same engine types as were passed when tvg_engine_init() was called. -* -* @param engine_method The engine types to terminate. This is relative to the Canvas types, in which it will be used. For multiple backends bitwise operation is allowed +* Cleans up resources and stops any internal threads initialized by tvg_engine_init(). * * @return Tvg_Result enumeration. -* @retval TVG_RESULT_INSUFFICIENT_CONDITION Nothing to be terminated. -* @retval TVG_RESULT_INVALID_ARGUMENT Unknown engine type. -* @retval TVG_RESULT_NOT_SUPPORTED Unsupported engine type. +* @retval TVG_RESULT_INSUFFICIENT_CONDITION Returned if there is nothing to terminate (e.g., tvg_engine_init() was not called). * +* @note The initializer maintains a reference count for safe repeated use. Only the final call to tvg_engine_term() will fully shut down the engine. * @see tvg_engine_init() -* @see Tvg_Engine */ -TVG_API Tvg_Result tvg_engine_term(Tvg_Engine engine_method); +TVG_API Tvg_Result tvg_engine_term(); /** diff --git a/src/bindings/capi/tvgCapi.cpp b/src/bindings/capi/tvgCapi.cpp index cd1c7905..1194eb04 100644 --- a/src/bindings/capi/tvgCapi.cpp +++ b/src/bindings/capi/tvgCapi.cpp @@ -40,15 +40,15 @@ extern "C" { /* Engine API */ /************************************************************************/ -TVG_API Tvg_Result tvg_engine_init(Tvg_Engine engine_method, unsigned threads) +TVG_API Tvg_Result tvg_engine_init(unsigned threads) { - return (Tvg_Result) Initializer::init(threads, CanvasEngine(engine_method)); + return (Tvg_Result) Initializer::init(threads); } -TVG_API Tvg_Result tvg_engine_term(Tvg_Engine engine_method) +TVG_API Tvg_Result tvg_engine_term() { - return (Tvg_Result) Initializer::term(CanvasEngine(engine_method)); + return (Tvg_Result) Initializer::term(); } diff --git a/src/renderer/gl_engine/tvgGlRenderer.cpp b/src/renderer/gl_engine/tvgGlRenderer.cpp index 9064feb2..21323d49 100644 --- a/src/renderer/gl_engine/tvgGlRenderer.cpp +++ b/src/renderer/gl_engine/tvgGlRenderer.cpp @@ -34,17 +34,7 @@ #define NOISE_LEVEL 0.5f -static atomic initEngineCnt{}; -static atomic rendererCnt{}; - - -static void _termEngine() -{ - if (rendererCnt > 0) return; - - //TODO: Clean up global resources -} - +static atomic rendererCnt{-1}; void GlRenderer::clearDisposes() { @@ -88,6 +78,7 @@ void GlRenderer::currentContext() GlRenderer::GlRenderer() { + ++rendererCnt; } @@ -99,7 +90,7 @@ GlRenderer::~GlRenderer() ARRAY_FOREACH(p, mPrograms) delete(*p); - if (rendererCnt == 0 && initEngineCnt == 0) _termEngine(); + } @@ -1520,45 +1511,33 @@ bool GlRenderer::postUpdate() } -bool GlRenderer::init(uint32_t threads) -{ - if ((initEngineCnt++) > 0) return true; - - //TODO: runtime linking? - - return true; -} - - -int32_t GlRenderer::init() -{ - return initEngineCnt; -} - - bool GlRenderer::term() { - if ((--initEngineCnt) > 0) return true; + if (rendererCnt > 0) return false; - initEngineCnt = 0; + //TODO: clean up global resources - _termEngine(); + rendererCnt = -1; return true; } -GlRenderer* GlRenderer::gen() +GlRenderer* GlRenderer::gen(TVG_UNUSED uint32_t threads) { - //TODO: GL minimum version check, should be replaced with the runtime linking in GlRenderer::init() - GLint vMajor, vMinor; - glGetIntegerv(GL_MAJOR_VERSION, &vMajor); - glGetIntegerv(GL_MINOR_VERSION, &vMinor); - if (vMajor < TVG_REQUIRE_GL_MAJOR_VER || (vMajor == TVG_REQUIRE_GL_MAJOR_VER && vMinor < TVG_REQUIRE_GL_MINOR_VER)) { - TVGERR("GL_ENGINE", "OpenGL/ES version is not satisfied. Current: v%d.%d, Required: v%d.%d", vMajor, vMinor, TVG_REQUIRE_GL_MAJOR_VER, TVG_REQUIRE_GL_MINOR_VER); - return nullptr; + //initialize engine + if (rendererCnt == -1) { + //TODO: GL minimum version check, should be replaced with the runtime linking in GlRenderer::init() + GLint vMajor, vMinor; + glGetIntegerv(GL_MAJOR_VERSION, &vMajor); + glGetIntegerv(GL_MINOR_VERSION, &vMinor); + if (vMajor < TVG_REQUIRE_GL_MAJOR_VER || (vMajor == TVG_REQUIRE_GL_MAJOR_VER && vMinor < TVG_REQUIRE_GL_MINOR_VER)) { + TVGERR("GL_ENGINE", "OpenGL/ES version is not satisfied. Current: v%d.%d, Required: v%d.%d", vMajor, vMinor, TVG_REQUIRE_GL_MAJOR_VER, TVG_REQUIRE_GL_MINOR_VER); + return nullptr; + } + TVGLOG("GL_ENGINE", "OpenGL/ES version = v%d.%d", vMajor, vMinor); + rendererCnt = 0; } - TVGLOG("GL_ENGINE", "OpenGL/ES version = v%d.%d", vMajor, vMinor); - return new GlRenderer(); + return new GlRenderer; } \ No newline at end of file diff --git a/src/renderer/gl_engine/tvgGlRenderer.h b/src/renderer/gl_engine/tvgGlRenderer.h index 7ec1650d..7ab1e901 100644 --- a/src/renderer/gl_engine/tvgGlRenderer.h +++ b/src/renderer/gl_engine/tvgGlRenderer.h @@ -99,9 +99,7 @@ public: bool render(RenderCompositor* cmp, const RenderEffect* effect, bool direct) override; void dispose(RenderEffect* effect) override; - static GlRenderer* gen(); - static bool init(TVG_UNUSED uint32_t threads); - static int32_t init(); + static GlRenderer* gen(uint32_t threads); static bool term(); private: diff --git a/src/renderer/sw_engine/tvgSwPostEffect.cpp b/src/renderer/sw_engine/tvgSwPostEffect.cpp index 2bdab334..32debffb 100644 --- a/src/renderer/sw_engine/tvgSwPostEffect.cpp +++ b/src/renderer/sw_engine/tvgSwPostEffect.cpp @@ -184,7 +184,7 @@ bool effectGaussianBlur(SwCompositor* cmp, SwSurface* surface, const RenderEffec auto back = buffer.buf32; auto swapped = false; - TVGLOG("SW_ENGINE", "GaussianFilter region(%ld, %ld, %ld, %ld) params(%f %d %d), level(%d)", bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y, params->sigma, params->direction, params->border, data->level); + TVGLOG("SW_ENGINE", "GaussianFilter region(%d, %d, %d, %d) params(%f %d %d), level(%d)", bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y, params->sigma, params->direction, params->border, data->level); /* It is best to take advantage of the Gaussian blur’s separable property by dividing the process into two passes. horizontal and vertical. @@ -363,7 +363,7 @@ bool effectDropShadow(SwCompositor* cmp, SwSurface* surface[2], const RenderEffe auto opacity = direct ? MULTIPLY(params->color[3], cmp->opacity) : params->color[3]; - TVGLOG("SW_ENGINE", "DropShadow region(%ld, %ld, %ld, %ld) params(%f %f %f), level(%d)", bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y, params->angle, params->distance, params->sigma, data->level); + TVGLOG("SW_ENGINE", "DropShadow region(%d, %d, %d, %d) params(%f %f %f), level(%d)", bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y, params->angle, params->distance, params->sigma, data->level); //saving the original image in order to overlay it into the filtered image. _dropShadowFilter(back, front, stride, w, h, bbox, data->kernel[0], color, false); @@ -433,7 +433,7 @@ bool effectFill(SwCompositor* cmp, const RenderEffectFill* params, bool direct) auto h = size_t(bbox.max.y - bbox.min.y); auto color = cmp->recoverSfc->join(params->color[0], params->color[1], params->color[2], 255); - TVGLOG("SW_ENGINE", "Fill region(%ld, %ld, %ld, %ld), param(%d %d %d %d)", bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y, params->color[0], params->color[1], params->color[2], params->color[3]); + TVGLOG("SW_ENGINE", "Fill region(%d, %d, %d, %d), param(%d %d %d %d)", bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y, params->color[0], params->color[1], params->color[2], params->color[3]); if (direct) { auto dbuffer = cmp->recoverSfc->buf32 + (bbox.min.y * cmp->recoverSfc->stride + bbox.min.x); @@ -484,7 +484,7 @@ bool effectTint(SwCompositor* cmp, const RenderEffectTint* params, bool direct) auto opacity = cmp->opacity; auto luma = cmp->recoverSfc->alphas[2]; //luma function - TVGLOG("SW_ENGINE", "Tint region(%ld, %ld, %ld, %ld), param(%d %d %d, %d %d %d, %d)", bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y, params->black[0], params->black[1], params->black[2], params->white[0], params->white[1], params->white[2], params->intensity); + TVGLOG("SW_ENGINE", "Tint region(%d, %d, %d, %d), param(%d %d %d, %d %d %d, %d)", bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y, params->black[0], params->black[1], params->black[2], params->white[0], params->white[1], params->white[2], params->intensity); /* Tint Formula: (1 - L) * Black + L * White, where the L is Luminance. */ @@ -558,7 +558,7 @@ bool effectTritone(SwCompositor* cmp, const RenderEffectTritone* params, bool di auto opacity = cmp->opacity; auto luma = cmp->recoverSfc->alphas[2]; //luma function - TVGLOG("SW_ENGINE", "Tritone region(%ld, %ld, %ld, %ld), param(%d %d %d, %d %d %d, %d %d %d)", bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y, params->shadow[0], params->shadow[1], params->shadow[2], params->midtone[0], params->midtone[1], params->midtone[2], params->highlight[0], params->highlight[1], params->highlight[2]); + TVGLOG("SW_ENGINE", "Tritone region(%d, %d, %d, %d), param(%d %d %d, %d %d %d, %d %d %d)", bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y, params->shadow[0], params->shadow[1], params->shadow[2], params->midtone[0], params->midtone[1], params->midtone[2], params->highlight[0], params->highlight[1], params->highlight[2]); if (direct) { auto dbuffer = cmp->recoverSfc->buf32 + (bbox.min.y * cmp->recoverSfc->stride + bbox.min.x); diff --git a/src/renderer/sw_engine/tvgSwRaster.cpp b/src/renderer/sw_engine/tvgSwRaster.cpp index 32452b3c..26114bce 100644 --- a/src/renderer/sw_engine/tvgSwRaster.cpp +++ b/src/renderer/sw_engine/tvgSwRaster.cpp @@ -362,7 +362,7 @@ static bool _rasterMaskedRect(SwSurface* surface, const SwBBox& region, const Re //8bit masking channels composition if (surface->channelSize != sizeof(uint8_t)) return false; - TVGLOG("SW_ENGINE", "Masked(%d) Rect [Region: %lu %lu %lu %lu]", (int)surface->compositor->method, region.min.x, region.min.y, region.max.x - region.min.x, region.max.y - region.min.y); + TVGLOG("SW_ENGINE", "Masked(%d) Rect [Region: %d %d %d %d]", (int)surface->compositor->method, region.min.x, region.min.y, region.max.x - region.min.x, region.max.y - region.min.y); auto maskOp = _getMaskOp(surface->compositor->method); if (_direct(surface->compositor->method)) return _rasterDirectMaskedRect(surface, region, maskOp, c.a); @@ -379,7 +379,7 @@ static bool _rasterMattedRect(SwSurface* surface, const SwBBox& region, const Re auto cbuffer = surface->compositor->image.buf8 + ((region.min.y * surface->compositor->image.stride + region.min.x) * csize); //compositor buffer auto alpha = surface->alpha(surface->compositor->method); - TVGLOG("SW_ENGINE", "Matted(%d) Rect [Region: %lu %lu %u %u]", (int)surface->compositor->method, region.min.x, region.min.y, w, h); + TVGLOG("SW_ENGINE", "Matted(%d) Rect [Region: %d %d %u %u]", (int)surface->compositor->method, region.min.x, region.min.y, w, h); //32bits channels if (surface->channelSize == sizeof(uint32_t)) { @@ -917,7 +917,7 @@ static bool _rasterScaledMattedImage(SwSurface* surface, const SwImage* image, c auto cbuffer = surface->compositor->image.buf8 + (region.min.y * surface->compositor->image.stride + region.min.x) * csize; auto alpha = surface->alpha(surface->compositor->method); - TVGLOG("SW_ENGINE", "Scaled Matted(%d) Image [Region: %lu %lu %lu %lu]", (int)surface->compositor->method, region.min.x, region.min.y, region.max.x - region.min.x, region.max.y - region.min.y); + TVGLOG("SW_ENGINE", "Scaled Matted(%d) Image [Region: %d %d %d %d]", (int)surface->compositor->method, region.min.x, region.min.y, region.max.x - region.min.x, region.max.y - region.min.y); auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler; auto sampleSize = _sampleSize(image->scale); @@ -1039,7 +1039,7 @@ static bool _rasterDirectMattedImage(SwSurface* surface, const SwImage* image, c auto sbuffer = image->buf32 + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox); auto cbuffer = surface->compositor->image.buf8 + (region.min.y * surface->compositor->image.stride + region.min.x) * csize; //compositor buffer - TVGLOG("SW_ENGINE", "Direct Matted(%d) Image [Region: %lu %lu %u %u]", (int)surface->compositor->method, region.min.x, region.min.y, w, h); + TVGLOG("SW_ENGINE", "Direct Matted(%d) Image [Region: %d %d %u %u]", (int)surface->compositor->method, region.min.x, region.min.y, w, h); //32 bits if (surface->channelSize == sizeof(uint32_t)) { @@ -1269,7 +1269,7 @@ static bool _rasterGradientMaskedRect(SwSurface* surface, const SwBBox& region, { auto method = surface->compositor->method; - TVGLOG("SW_ENGINE", "Masked(%d) Gradient [Region: %lu %lu %lu %lu]", (int)method, region.min.x, region.min.y, region.max.x - region.min.x, region.max.y - region.min.y); + TVGLOG("SW_ENGINE", "Masked(%d) Gradient [Region: %d %d %d %d]", (int)method, region.min.x, region.min.y, region.max.x - region.min.x, region.max.y - region.min.y); auto maskOp = _getMaskOp(method); @@ -1290,7 +1290,7 @@ static bool _rasterGradientMattedRect(SwSurface* surface, const SwBBox& region, auto cbuffer = surface->compositor->image.buf8 + (region.min.y * surface->compositor->image.stride + region.min.x) * csize; auto alpha = surface->alpha(surface->compositor->method); - TVGLOG("SW_ENGINE", "Matted(%d) Gradient [Region: %lu %lu %u %u]", (int)surface->compositor->method, region.min.x, region.min.y, w, h); + TVGLOG("SW_ENGINE", "Matted(%d) Gradient [Region: %d %d %u %u]", (int)surface->compositor->method, region.min.x, region.min.y, w, h); for (uint32_t y = 0; y < h; ++y) { fillMethod()(fill, buffer, region.min.y + y, region.min.x, w, cbuffer, alpha, csize, 255); diff --git a/src/renderer/sw_engine/tvgSwRenderer.cpp b/src/renderer/sw_engine/tvgSwRenderer.cpp index 8b199414..3bbea0bc 100644 --- a/src/renderer/sw_engine/tvgSwRenderer.cpp +++ b/src/renderer/sw_engine/tvgSwRenderer.cpp @@ -32,8 +32,7 @@ /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ -static atomic initEngineCnt{}; -static atomic rendererCnt{}; +static atomic rendererCnt{-1}; static SwMpool* globalMpool = nullptr; static uint32_t threadsCnt = 0; @@ -242,15 +241,6 @@ struct SwImageTask : SwTask }; -static void _termEngine() -{ - if (rendererCnt > 0) return; - - mpoolTerm(globalMpool); - globalMpool = nullptr; -} - - static void _renderFill(SwShapeTask* task, SwSurface* surface, uint8_t opacity) { if (auto fill = task->rshape->fill) { @@ -280,6 +270,21 @@ static void _renderStroke(SwShapeTask* task, SwSurface* surface, uint8_t opacity /* External Class Implementation */ /************************************************************************/ +SwRenderer::SwRenderer() +{ + if (TaskScheduler::onthread()) { + TVGLOG("SW_RENDERER", "Running on a non-dominant thread!, Renderer(%p)", this); + mpool = mpoolInit(threadsCnt); + sharedMpool = false; + } else { + mpool = globalMpool; + sharedMpool = true; + } + + ++rendererCnt; +} + + SwRenderer::~SwRenderer() { clearCompositors(); @@ -289,8 +294,6 @@ SwRenderer::~SwRenderer() if (!sharedMpool) mpoolTerm(mpool); --rendererCnt; - - if (rendererCnt == 0 && initEngineCnt == 0) _termEngine(); } @@ -777,59 +780,30 @@ RenderData SwRenderer::prepare(const RenderShape& rshape, RenderData data, const } -SwRenderer::SwRenderer() -{ - if (TaskScheduler::onthread()) { - TVGLOG("SW_RENDERER", "Running on a non-dominant thread!, Renderer(%p)", this); - mpool = mpoolInit(threadsCnt); - sharedMpool = false; - } else { - mpool = globalMpool; - sharedMpool = true; - } -} - - -bool SwRenderer::init(uint32_t threads) -{ - if ((initEngineCnt++) > 0) return true; - - threadsCnt = threads; - - //Share the memory pool among the renderer - globalMpool = mpoolInit(threads); - if (!globalMpool) { - --initEngineCnt; - return false; - } - - return true; -} - - -int32_t SwRenderer::init() -{ -#ifdef THORVG_SW_OPENMP_SUPPORT - omp_set_num_threads(TaskScheduler::threads()); -#endif - - return initEngineCnt; -} - - bool SwRenderer::term() { - if ((--initEngineCnt) > 0) return true; + if (rendererCnt > 0) return false; - initEngineCnt = 0; - - _termEngine(); + mpoolTerm(globalMpool); + globalMpool = nullptr; + rendererCnt = -1; return true; } -SwRenderer* SwRenderer::gen() + +SwRenderer* SwRenderer::gen(uint32_t threads) { - ++rendererCnt; - return new SwRenderer(); + //initialize engine + if (rendererCnt == -1) { +#ifdef THORVG_SW_OPENMP_SUPPORT + omp_set_num_threads(threads); +#endif + //Share the memory pool among the renderer + globalMpool = mpoolInit(threads); + threadsCnt = threads; + rendererCnt = 0; + } + + return new SwRenderer; } diff --git a/src/renderer/sw_engine/tvgSwRenderer.h b/src/renderer/sw_engine/tvgSwRenderer.h index edb56813..dc7673df 100644 --- a/src/renderer/sw_engine/tvgSwRenderer.h +++ b/src/renderer/sw_engine/tvgSwRenderer.h @@ -66,9 +66,7 @@ public: bool render(RenderCompositor* cmp, const RenderEffect* effect, bool direct) override; void dispose(RenderEffect* effect) override; - static SwRenderer* gen(); - static bool init(uint32_t threads); - static int32_t init(); + static SwRenderer* gen(uint32_t threads); static bool term(); private: diff --git a/src/renderer/tvgCommon.h b/src/renderer/tvgCommon.h index b9071c44..ec112de7 100644 --- a/src/renderer/tvgCommon.h +++ b/src/renderer/tvgCommon.h @@ -116,6 +116,8 @@ namespace tvg { { std::free(ptr); } + + extern int engineInit; } #endif //_TVG_COMMON_H_ diff --git a/src/renderer/tvgGlCanvas.cpp b/src/renderer/tvgGlCanvas.cpp index c476b0fb..d66af6ad 100644 --- a/src/renderer/tvgGlCanvas.cpp +++ b/src/renderer/tvgGlCanvas.cpp @@ -21,23 +21,19 @@ */ #include "tvgCanvas.h" +#include "tvgTaskScheduler.h" #ifdef THORVG_GL_RASTER_SUPPORT #include "tvgGlRenderer.h" #endif -GlCanvas::GlCanvas() -{ -#ifdef THORVG_GL_RASTER_SUPPORT - pImpl->renderer = GlRenderer::gen(); - pImpl->renderer->ref(); -#endif -} - +GlCanvas::GlCanvas() = default; GlCanvas::~GlCanvas() { - //TODO: +#ifdef THORVG_GL_RASTER_SUPPORT + GlRenderer::term(); +#endif } @@ -70,8 +66,14 @@ Result GlCanvas::target(void* context, int32_t id, uint32_t w, uint32_t h, Color GlCanvas* GlCanvas::gen() noexcept { #ifdef THORVG_GL_RASTER_SUPPORT - if (GlRenderer::init() <= 0) return nullptr; - return new GlCanvas; + if (engineInit > 0) { + auto renderer = GlRenderer::gen(TaskScheduler::threads()); + if (!renderer) return nullptr; + renderer->ref(); + auto ret = new GlCanvas; + ret->pImpl->renderer = renderer; + return ret; + } #endif return nullptr; } diff --git a/src/renderer/tvgInitializer.cpp b/src/renderer/tvgInitializer.cpp index ef8e8bed..fb667555 100644 --- a/src/renderer/tvgInitializer.cpp +++ b/src/renderer/tvgInitializer.cpp @@ -41,14 +41,12 @@ /* Internal Class Implementation */ /************************************************************************/ -static int _initCnt = 0; +namespace tvg { + int engineInit = 0; +} + static uint16_t _version = 0; -//enum class operation helper -static constexpr bool operator &(CanvasEngine a, CanvasEngine b) -{ - return int(a) & int(b); -} static bool _buildVersionInfo(uint32_t* major, uint32_t* minor, uint32_t* micro) { @@ -82,34 +80,9 @@ static bool _buildVersionInfo(uint32_t* major, uint32_t* minor, uint32_t* micro) /* External Class Implementation */ /************************************************************************/ -Result Initializer::init(uint32_t threads, CanvasEngine engine) noexcept +Result Initializer::init(uint32_t threads) noexcept { - auto nonSupport = true; - - if (engine == CanvasEngine::All || engine & CanvasEngine::Sw) { - #ifdef THORVG_SW_RASTER_SUPPORT - if (!SwRenderer::init(threads)) return Result::FailedAllocation; - nonSupport = false; - #endif - } - - if (engine == CanvasEngine::All || engine & CanvasEngine::Gl) { - #ifdef THORVG_GL_RASTER_SUPPORT - if (!GlRenderer::init(threads)) return Result::FailedAllocation; - nonSupport = false; - #endif - } - - if (engine == CanvasEngine::All || engine & CanvasEngine::Wg) { - #ifdef THORVG_WG_RASTER_SUPPORT - if (!WgRenderer::init(threads)) return Result::FailedAllocation; - nonSupport = false; - #endif - } - - if (nonSupport) return Result::NonSupport; - - if (_initCnt++ > 0) return Result::Success; + if (engineInit++ > 0) return Result::Success; if (!_buildVersionInfo(nullptr, nullptr, nullptr)) return Result::Unknown; @@ -121,36 +94,23 @@ Result Initializer::init(uint32_t threads, CanvasEngine engine) noexcept } -Result Initializer::term(CanvasEngine engine) noexcept +Result Initializer::term() noexcept { - if (_initCnt == 0) return Result::InsufficientCondition; + if (engineInit == 0) return Result::InsufficientCondition; - auto nonSupport = true; + if (--engineInit > 0) return Result::Success; - if (engine == CanvasEngine::All || engine & CanvasEngine::Sw) { - #ifdef THORVG_SW_RASTER_SUPPORT - if (!SwRenderer::term()) return Result::InsufficientCondition; - nonSupport = false; - #endif - } + #ifdef THORVG_SW_RASTER_SUPPORT + if (!SwRenderer::term()) return Result::InsufficientCondition; + #endif - if (engine == CanvasEngine::All || engine & CanvasEngine::Gl) { - #ifdef THORVG_GL_RASTER_SUPPORT - if (!GlRenderer::term()) return Result::InsufficientCondition; - nonSupport = false; - #endif - } + #ifdef THORVG_GL_RASTER_SUPPORT + if (!GlRenderer::term()) return Result::InsufficientCondition; + #endif - if (engine == CanvasEngine::All || engine & CanvasEngine::Wg) { - #ifdef THORVG_WG_RASTER_SUPPORT - if (!WgRenderer::term()) return Result::InsufficientCondition; - nonSupport = false; - #endif - } - - if (nonSupport) return Result::NonSupport; - - if (--_initCnt > 0) return Result::Success; + #ifdef THORVG_WG_RASTER_SUPPORT + if (!WgRenderer::term()) return Result::InsufficientCondition; + #endif TaskScheduler::term(); diff --git a/src/renderer/tvgSwCanvas.cpp b/src/renderer/tvgSwCanvas.cpp index 027c9e14..9e64bfce 100644 --- a/src/renderer/tvgSwCanvas.cpp +++ b/src/renderer/tvgSwCanvas.cpp @@ -21,6 +21,7 @@ */ #include "tvgCanvas.h" +#include "tvgTaskScheduler.h" #include "tvgLoadModule.h" #ifdef THORVG_SW_RASTER_SUPPORT @@ -28,18 +29,13 @@ #endif -SwCanvas::SwCanvas() -{ -#ifdef THORVG_SW_RASTER_SUPPORT - pImpl->renderer = SwRenderer::gen(); - pImpl->renderer->ref(); -#endif -} - +SwCanvas::SwCanvas() = default; SwCanvas::~SwCanvas() { - //TODO: +#ifdef THORVG_SW_RASTER_SUPPORT + SwRenderer::term(); +#endif } @@ -76,8 +72,13 @@ Result SwCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t SwCanvas* SwCanvas::gen() noexcept { #ifdef THORVG_SW_RASTER_SUPPORT - if (SwRenderer::init() <= 0) return nullptr; - return new SwCanvas; + if (engineInit > 0) { + auto renderer = SwRenderer::gen(TaskScheduler::threads()); + renderer->ref(); + auto ret = new SwCanvas; + ret->pImpl->renderer = renderer; + return ret; + } #endif return nullptr; } diff --git a/src/renderer/tvgWgCanvas.cpp b/src/renderer/tvgWgCanvas.cpp index 18a30ba7..5d074199 100644 --- a/src/renderer/tvgWgCanvas.cpp +++ b/src/renderer/tvgWgCanvas.cpp @@ -21,26 +21,22 @@ */ #include "tvgCanvas.h" +#include "tvgTaskScheduler.h" #ifdef THORVG_WG_RASTER_SUPPORT #include "tvgWgRenderer.h" #endif -WgCanvas::WgCanvas() -{ -#ifdef THORVG_WG_RASTER_SUPPORT - pImpl->renderer = WgRenderer::gen(); - pImpl->renderer->ref(); -#endif -} - +WgCanvas::WgCanvas() = default; WgCanvas::~WgCanvas() { #ifdef THORVG_WG_RASTER_SUPPORT auto renderer = static_cast(pImpl->renderer); renderer->target(nullptr, nullptr, nullptr, 0, 0); + + WgRenderer::term(); #endif } @@ -74,8 +70,13 @@ Result WgCanvas::target(void* device, void* instance, void* target, uint32_t w, WgCanvas* WgCanvas::gen() noexcept { #ifdef THORVG_WG_RASTER_SUPPORT - if (WgRenderer::init() <= 0) return nullptr; - return new WgCanvas; + if (engineInit > 0) { + auto renderer = WgRenderer::gen(TaskScheduler::threads()); + renderer->ref(); + auto ret = new WgCanvas; + ret->pImpl->renderer = renderer; + return ret; + } #endif return nullptr; } diff --git a/src/renderer/wg_engine/tvgWgRenderer.cpp b/src/renderer/wg_engine/tvgWgRenderer.cpp index cafa418f..9ab2fea3 100644 --- a/src/renderer/wg_engine/tvgWgRenderer.cpp +++ b/src/renderer/wg_engine/tvgWgRenderer.cpp @@ -29,16 +29,7 @@ /* Internal Class Implementation */ /************************************************************************/ -static atomic initEngineCnt{}; -static atomic rendererCnt{}; - - -static void _termEngine() -{ - if (rendererCnt > 0) return; - - //TODO: -} +static atomic rendererCnt{-1}; void WgRenderer::release() @@ -426,6 +417,8 @@ WgRenderer::WgRenderer() } else { mBufferPool.pool = WgGeometryBufferPool::instance(); } + + ++rendererCnt; } @@ -436,8 +429,6 @@ WgRenderer::~WgRenderer() if (mBufferPool.individual) delete(mBufferPool.pool); --rendererCnt; - - if (rendererCnt == 0 && initEngineCnt == 0) _termEngine(); } @@ -648,36 +639,24 @@ bool WgRenderer::postUpdate() } -bool WgRenderer::init(TVG_UNUSED uint32_t threads) -{ - if ((initEngineCnt++) > 0) return true; - - //TODO: global engine init - - return true; -} - - -int32_t WgRenderer::init() -{ - return initEngineCnt; -} - - bool WgRenderer::term() { - if ((--initEngineCnt) > 0) return true; + if (rendererCnt > 0) return false; - initEngineCnt = 0; + //TODO: clean up global resources - _termEngine(); + rendererCnt = -1; return true; } -WgRenderer* WgRenderer::gen() +WgRenderer* WgRenderer::gen(TVG_UNUSED uint32_t threads) { - ++rendererCnt; - return new WgRenderer(); + //initialize engine + if (rendererCnt == -1) { + //TODO: + } + + return new WgRenderer; } \ No newline at end of file diff --git a/src/renderer/wg_engine/tvgWgRenderer.h b/src/renderer/wg_engine/tvgWgRenderer.h index 01f1e17f..d82c9322 100644 --- a/src/renderer/wg_engine/tvgWgRenderer.h +++ b/src/renderer/wg_engine/tvgWgRenderer.h @@ -58,9 +58,7 @@ public: bool render(RenderCompositor* cmp, const RenderEffect* effect, bool direct) override; void dispose(RenderEffect* effect) override; - static WgRenderer* gen(); - static bool init(uint32_t threads); - static int32_t init(); + static WgRenderer* gen(uint32_t threads); static bool term(); private: diff --git a/test/testAccessor.cpp b/test/testAccessor.cpp index f57e7da5..7cd54ffc 100644 --- a/test/testAccessor.cpp +++ b/test/testAccessor.cpp @@ -41,46 +41,46 @@ TEST_CASE("Accessor Creation", "[tvgAccessor]") TEST_CASE("Set", "[tvgAccessor]") { REQUIRE(Initializer::init(0) == Result::Success); - - auto canvas = unique_ptr(SwCanvas::gen()); - REQUIRE(canvas); - - uint32_t buffer[100*100]; - REQUIRE(canvas->target(buffer, 100, 100, 100, ColorSpace::ABGR8888) == Result::Success); - - auto picture = unique_ptr(Picture::gen()); - REQUIRE(picture); - REQUIRE(picture->load(TEST_DIR"/logo.svg") == Result::Success); - - auto accessor = unique_ptr(Accessor::gen()); - REQUIRE(accessor); - - //Case 1 - REQUIRE(accessor->set(picture.get(), nullptr, nullptr) == Result::InvalidArguments); - - //Case 2 - Shape* ret = nullptr; - - auto f = [](const tvg::Paint* paint, void* data) -> bool { - if (paint->type() == Type::Shape) { - auto shape = (tvg::Shape*) paint; - uint8_t r, g, b; - shape->fill(&r, &g, &b); - if (r == 37 && g == 47 && b == 53) { - shape->fill(0, 0, 255); - shape->id = Accessor::id("TestAccessor"); - *static_cast(data) = shape; - return false; + auto canvas = unique_ptr(SwCanvas::gen()); + REQUIRE(canvas); + + uint32_t buffer[100*100]; + REQUIRE(canvas->target(buffer, 100, 100, 100, ColorSpace::ABGR8888) == Result::Success); + + auto picture = unique_ptr(Picture::gen()); + REQUIRE(picture); + REQUIRE(picture->load(TEST_DIR"/logo.svg") == Result::Success); + + auto accessor = unique_ptr(Accessor::gen()); + REQUIRE(accessor); + + //Case 1 + REQUIRE(accessor->set(picture.get(), nullptr, nullptr) == Result::InvalidArguments); + + //Case 2 + Shape* ret = nullptr; + + auto f = [](const tvg::Paint* paint, void* data) -> bool + { + if (paint->type() == Type::Shape) { + auto shape = (tvg::Shape*) paint; + uint8_t r, g, b; + shape->fill(&r, &g, &b); + if (r == 37 && g == 47 && b == 53) { + shape->fill(0, 0, 255); + shape->id = Accessor::id("TestAccessor"); + *static_cast(data) = shape; + return false; + } } - } - return true; - }; + return true; + }; - REQUIRE(accessor->set(picture.get(), f, &ret) == Result::Success); - - REQUIRE((ret && ret->id == Accessor::id("TestAccessor"))); + REQUIRE(accessor->set(picture.get(), f, &ret) == Result::Success); + REQUIRE((ret && ret->id == Accessor::id("TestAccessor"))); + } REQUIRE(Initializer::term() == Result::Success); } diff --git a/test/testInitializer.cpp b/test/testInitializer.cpp index 396b91d1..fed6559f 100644 --- a/test/testInitializer.cpp +++ b/test/testInitializer.cpp @@ -58,9 +58,4 @@ TEST_CASE("Version", "[tvgInitializer]") TEST_CASE("Negative termination", "[tvgInitializer]") { REQUIRE(Initializer::term() == Result::InsufficientCondition); -} - -TEST_CASE("Invalid engine", "[tvgInitializer]") -{ - REQUIRE(Initializer::init(0, CanvasEngine(64)) == Result::NonSupport); -} +} \ No newline at end of file diff --git a/test/testPicture.cpp b/test/testPicture.cpp index 18c33e4d..fc7fbd95 100644 --- a/test/testPicture.cpp +++ b/test/testPicture.cpp @@ -71,30 +71,30 @@ TEST_CASE("Load RAW Data", "[tvgPicture]") TEST_CASE("Load RAW file and render", "[tvgPicture]") { REQUIRE(Initializer::init(0) == Result::Success); + { + auto canvas = unique_ptr(SwCanvas::gen()); + REQUIRE(canvas); - auto canvas = unique_ptr(SwCanvas::gen()); - REQUIRE(canvas); + uint32_t buffer[100*100]; + REQUIRE(canvas->target(buffer, 100, 100, 100, ColorSpace::ABGR8888) == Result::Success); - uint32_t buffer[100*100]; - REQUIRE(canvas->target(buffer, 100, 100, 100, ColorSpace::ABGR8888) == Result::Success); + ifstream file(TEST_DIR"/rawimage_200x300.raw"); + if (!file.is_open()) return; + auto data = (uint32_t*)malloc(sizeof(uint32_t) * (200*300)); + file.read(reinterpret_cast(data), sizeof (uint32_t) * 200 * 300); + file.close(); - ifstream file(TEST_DIR"/rawimage_200x300.raw"); - if (!file.is_open()) return; - auto data = (uint32_t*)malloc(sizeof(uint32_t) * (200*300)); - file.read(reinterpret_cast(data), sizeof (uint32_t) * 200 * 300); - file.close(); + auto picture = Picture::gen(); + REQUIRE(picture); - auto picture = Picture::gen(); - REQUIRE(picture); + REQUIRE(picture->load(data, 200, 300, ColorSpace::ARGB8888, false) == Result::Success); + REQUIRE(picture->size(100, 150) == Result::Success); - REQUIRE(picture->load(data, 200, 300, ColorSpace::ARGB8888, false) == Result::Success); - REQUIRE(picture->size(100, 150) == Result::Success); - - REQUIRE(canvas->push(picture) == Result::Success); + REQUIRE(canvas->push(picture) == Result::Success); + free(data); + } REQUIRE(Initializer::term() == Result::Success); - - free(data); } TEST_CASE("Picture Size", "[tvgPicture]") @@ -203,28 +203,28 @@ TEST_CASE("Load SVG Data", "[tvgPicture]") TEST_CASE("Load SVG file and render", "[tvgPicture]") { REQUIRE(Initializer::init(0) == Result::Success); + { + auto canvas = unique_ptr(SwCanvas::gen()); + REQUIRE(canvas); - auto canvas = unique_ptr(SwCanvas::gen()); - REQUIRE(canvas); + auto buffer = new uint32_t[1000*1000]; + if (!buffer) return; - auto buffer = new uint32_t[1000*1000]; - if (!buffer) return; + REQUIRE(canvas->target(buffer, 1000, 1000, 1000, ColorSpace::ABGR8888) == Result::Success); - REQUIRE(canvas->target(buffer, 1000, 1000, 1000, ColorSpace::ABGR8888) == Result::Success); + auto picture = Picture::gen(); + REQUIRE(picture); - auto picture = Picture::gen(); - REQUIRE(picture); + REQUIRE(picture->load(TEST_DIR"/tag.svg") == Result::Success); + REQUIRE(picture->size(100, 100) == Result::Success); - REQUIRE(picture->load(TEST_DIR"/tag.svg") == Result::Success); - REQUIRE(picture->size(100, 100) == Result::Success); - - REQUIRE(canvas->push(picture) == Result::Success); - REQUIRE(canvas->draw() == Result::Success); - REQUIRE(canvas->sync() == Result::Success); + REQUIRE(canvas->push(picture) == Result::Success); + REQUIRE(canvas->draw() == Result::Success); + REQUIRE(canvas->sync() == Result::Success); + delete[] buffer; + } REQUIRE(Initializer::term() == Result::Success); - - delete[] buffer; } #endif @@ -275,22 +275,22 @@ TEST_CASE("Load PNG file from data", "[tvgPicture]") TEST_CASE("Load PNG file and render", "[tvgPicture]") { REQUIRE(Initializer::init(0) == Result::Success); + { + auto canvas = unique_ptr(SwCanvas::gen()); + REQUIRE(canvas); - auto canvas = unique_ptr(SwCanvas::gen()); - REQUIRE(canvas); + uint32_t buffer[100*100]; + REQUIRE(canvas->target(buffer, 100, 100, 100, ColorSpace::ABGR8888) == Result::Success); - uint32_t buffer[100*100]; - REQUIRE(canvas->target(buffer, 100, 100, 100, ColorSpace::ABGR8888) == Result::Success); + auto picture = Picture::gen(); + REQUIRE(picture); - auto picture = Picture::gen(); - REQUIRE(picture); - - REQUIRE(picture->load(TEST_DIR"/test.png") == Result::Success); - REQUIRE(picture->opacity(192) == Result::Success); - REQUIRE(picture->scale(5.0) == Result::Success); - - REQUIRE(canvas->push(picture) == Result::Success); + REQUIRE(picture->load(TEST_DIR"/test.png") == Result::Success); + REQUIRE(picture->opacity(192) == Result::Success); + REQUIRE(picture->scale(5.0) == Result::Success); + REQUIRE(canvas->push(picture) == Result::Success); + } REQUIRE(Initializer::term() == Result::Success); } @@ -345,20 +345,21 @@ TEST_CASE("Load JPG file from data", "[tvgPicture]") TEST_CASE("Load JPG file and render", "[tvgPicture]") { REQUIRE(Initializer::init(0) == Result::Success); + { - auto canvas = unique_ptr(SwCanvas::gen()); - REQUIRE(canvas); + auto canvas = unique_ptr(SwCanvas::gen()); + REQUIRE(canvas); - uint32_t buffer[100*100]; - REQUIRE(canvas->target(buffer, 100, 100, 100, ColorSpace::ABGR8888) == Result::Success); + uint32_t buffer[100*100]; + REQUIRE(canvas->target(buffer, 100, 100, 100, ColorSpace::ABGR8888) == Result::Success); - auto picture = Picture::gen(); - REQUIRE(picture); + auto picture = Picture::gen(); + REQUIRE(picture); - REQUIRE(picture->load(TEST_DIR"/test.jpg") == Result::Success); - - REQUIRE(canvas->push(picture) == Result::Success); + REQUIRE(picture->load(TEST_DIR"/test.jpg") == Result::Success); + REQUIRE(canvas->push(picture) == Result::Success); + } REQUIRE(Initializer::term() == Result::Success); } @@ -410,22 +411,22 @@ TEST_CASE("Load WEBP file from data", "[tvgPicture]") TEST_CASE("Load WEBP file and render", "[tvgPicture]") { REQUIRE(Initializer::init(0) == Result::Success); + { + auto canvas = unique_ptr(SwCanvas::gen()); + REQUIRE(canvas); - auto canvas = unique_ptr(SwCanvas::gen()); - REQUIRE(canvas); + uint32_t buffer[100*100]; + REQUIRE(canvas->target(buffer, 100, 100, 100, ColorSpace::ABGR8888) == Result::Success); - uint32_t buffer[100*100]; - REQUIRE(canvas->target(buffer, 100, 100, 100, ColorSpace::ABGR8888) == Result::Success); + auto picture = Picture::gen(); + REQUIRE(picture); - auto picture = Picture::gen(); - REQUIRE(picture); - - REQUIRE(picture->load(TEST_DIR"/test.webp") == Result::Success); - REQUIRE(picture->opacity(192) == Result::Success); - REQUIRE(picture->scale(5.0) == Result::Success); - - REQUIRE(canvas->push(picture) == Result::Success); + REQUIRE(picture->load(TEST_DIR"/test.webp") == Result::Success); + REQUIRE(picture->opacity(192) == Result::Success); + REQUIRE(picture->scale(5.0) == Result::Success); + REQUIRE(canvas->push(picture) == Result::Success); + } REQUIRE(Initializer::term() == Result::Success); } diff --git a/test/testScene.cpp b/test/testScene.cpp index 7320e3f8..77f127bf 100644 --- a/test/testScene.cpp +++ b/test/testScene.cpp @@ -78,27 +78,27 @@ TEST_CASE("Scene Clear", "[tvgScene]") TEST_CASE("Scene Clear And Reuse Shape", "[tvgScene]") { REQUIRE(Initializer::init(0) == Result::Success); + { + auto canvas = unique_ptr(SwCanvas::gen()); + REQUIRE(canvas); - auto canvas = unique_ptr(SwCanvas::gen()); - REQUIRE(canvas); + auto scene = Scene::gen(); + REQUIRE(scene); - auto scene = Scene::gen(); - REQUIRE(scene); + auto shape = Shape::gen(); + REQUIRE(shape); + REQUIRE(shape->ref() == 1); - auto shape = Shape::gen(); - REQUIRE(shape); - REQUIRE(shape->ref() == 1); + REQUIRE(scene->push(shape) == Result::Success); + REQUIRE(canvas->push(scene) == Result::Success); + REQUIRE(canvas->update() == Result::Success); - REQUIRE(scene->push(shape) == Result::Success); - REQUIRE(canvas->push(scene) == Result::Success); - REQUIRE(canvas->update() == Result::Success); - - //No deallocate shape. - REQUIRE(scene->remove() == Result::Success); - - //Reuse shape. - REQUIRE(scene->push(shape) == Result::Success); - REQUIRE(shape->unref() == 1); //The scene still holds 1. + //No deallocate shape. + REQUIRE(scene->remove() == Result::Success); + //Reuse shape. + REQUIRE(scene->push(shape) == Result::Success); + REQUIRE(shape->unref() == 1); //The scene still holds 1. + } REQUIRE(Initializer::term() == Result::Success); } diff --git a/tools/lottie2gif/lottie2gif.cpp b/tools/lottie2gif/lottie2gif.cpp index 785065ff..a729fc03 100644 --- a/tools/lottie2gif/lottie2gif.cpp +++ b/tools/lottie2gif/lottie2gif.cpp @@ -70,7 +70,7 @@ private: bool convert(string& in, string& out) { - if (Initializer::init(0, CanvasEngine::Sw) != Result::Success) return false; + if (Initializer::init(0) != Result::Success) return false; auto animation = Animation::gen(); auto picture = animation->picture(); diff --git a/tools/svg2png/svg2png.cpp b/tools/svg2png/svg2png.cpp index 655a2437..c17b679c 100644 --- a/tools/svg2png/svg2png.cpp +++ b/tools/svg2png/svg2png.cpp @@ -172,7 +172,7 @@ private: if (threads > 0) --threads; //Initialize ThorVG Engine - if (tvg::Initializer::init(threads, tvg::CanvasEngine::Sw) != tvg::Result::Success) { + if (tvg::Initializer::init(threads) != tvg::Result::Success) { cout << "Error: Engine is not supported" << endl; }