From 0e25879d1285e748b1e94d89ab7b0c8e4dad28d4 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 18 Jun 2020 18:44:52 +0900 Subject: [PATCH 01/16] correct unmatched files permission. Please keep file permission 664. Change-Id: I90bdfa76b4f94a06d3b560df42509f30e59111a4 --- src/lib/gl_engine/meson.build | 0 src/lib/gl_engine/tvgGlCommon.h | 0 src/lib/gl_engine/tvgGlGeometry.cpp | 0 src/lib/gl_engine/tvgGlGeometry.h | 0 src/lib/gl_engine/tvgGlGpuBuffer.cpp | 0 src/lib/gl_engine/tvgGlGpuBuffer.h | 0 src/lib/gl_engine/tvgGlProgram.cpp | 0 src/lib/gl_engine/tvgGlProgram.h | 0 src/lib/gl_engine/tvgGlRenderer.cpp | 0 src/lib/gl_engine/tvgGlRenderer.h | 0 src/lib/gl_engine/tvgGlShader.cpp | 0 src/lib/gl_engine/tvgGlShader.h | 0 src/lib/gl_engine/tvgGlShaderSrc.cpp | 0 src/lib/gl_engine/tvgGlShaderSrc.h | 0 src/lib/tvgGlCanvas.cpp | 0 src/lib/tvgRenderCommon.h | 0 src/lib/tvgShape.cpp | 0 test/testGlShape.cpp | 0 18 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 src/lib/gl_engine/meson.build mode change 100755 => 100644 src/lib/gl_engine/tvgGlCommon.h mode change 100755 => 100644 src/lib/gl_engine/tvgGlGeometry.cpp mode change 100755 => 100644 src/lib/gl_engine/tvgGlGeometry.h mode change 100755 => 100644 src/lib/gl_engine/tvgGlGpuBuffer.cpp mode change 100755 => 100644 src/lib/gl_engine/tvgGlGpuBuffer.h mode change 100755 => 100644 src/lib/gl_engine/tvgGlProgram.cpp mode change 100755 => 100644 src/lib/gl_engine/tvgGlProgram.h mode change 100755 => 100644 src/lib/gl_engine/tvgGlRenderer.cpp mode change 100755 => 100644 src/lib/gl_engine/tvgGlRenderer.h mode change 100755 => 100644 src/lib/gl_engine/tvgGlShader.cpp mode change 100755 => 100644 src/lib/gl_engine/tvgGlShader.h mode change 100755 => 100644 src/lib/gl_engine/tvgGlShaderSrc.cpp mode change 100755 => 100644 src/lib/gl_engine/tvgGlShaderSrc.h mode change 100755 => 100644 src/lib/tvgGlCanvas.cpp mode change 100755 => 100644 src/lib/tvgRenderCommon.h mode change 100755 => 100644 src/lib/tvgShape.cpp mode change 100755 => 100644 test/testGlShape.cpp diff --git a/src/lib/gl_engine/meson.build b/src/lib/gl_engine/meson.build old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlCommon.h b/src/lib/gl_engine/tvgGlCommon.h old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlGeometry.cpp b/src/lib/gl_engine/tvgGlGeometry.cpp old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlGeometry.h b/src/lib/gl_engine/tvgGlGeometry.h old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlGpuBuffer.cpp b/src/lib/gl_engine/tvgGlGpuBuffer.cpp old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlGpuBuffer.h b/src/lib/gl_engine/tvgGlGpuBuffer.h old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlProgram.cpp b/src/lib/gl_engine/tvgGlProgram.cpp old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlProgram.h b/src/lib/gl_engine/tvgGlProgram.h old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlShader.cpp b/src/lib/gl_engine/tvgGlShader.cpp old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlShader.h b/src/lib/gl_engine/tvgGlShader.h old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlShaderSrc.cpp b/src/lib/gl_engine/tvgGlShaderSrc.cpp old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlShaderSrc.h b/src/lib/gl_engine/tvgGlShaderSrc.h old mode 100755 new mode 100644 diff --git a/src/lib/tvgGlCanvas.cpp b/src/lib/tvgGlCanvas.cpp old mode 100755 new mode 100644 diff --git a/src/lib/tvgRenderCommon.h b/src/lib/tvgRenderCommon.h old mode 100755 new mode 100644 diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp old mode 100755 new mode 100644 diff --git a/test/testGlShape.cpp b/test/testGlShape.cpp old mode 100755 new mode 100644 -- 2.7.4 From 01e52c7c7aaeeeb4018022023ff53673d7a2114d Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 19 Jun 2020 14:49:07 +0900 Subject: [PATCH 02/16] common loader: build up loader infrastructure. Change-Id: I62aaed43015301ec39e414833f37d6c5485d8043 --- .gitignore | 1 - inc/tizenvg.h | 5 +-- src/lib/gl_engine/meson.build | 2 +- src/lib/meson.build | 3 ++ src/lib/sw_engine/meson.build | 2 +- src/lib/tvgCommon.h | 2 + src/lib/tvgInitializer.cpp | 7 +-- src/lib/tvgLoader.h | 36 +++++++++++++++ src/lib/tvgLoaderMgr.cpp | 52 +++++++++++++++++++++ src/lib/tvgLoaderMgr.h | 27 +++++++++++ src/lib/tvgScene.cpp | 16 +------ src/lib/tvgSceneImpl.h | 21 ++++++--- src/loaders/meson.build | 1 + src/loaders/svg_loader/meson.build | 9 ++++ src/loaders/svg_loader/tvgSvgLoader.cpp | 80 +++++++++++++++++++++++++++++++++ src/loaders/svg_loader/tvgSvgLoader.h | 38 ++++++++++++++++ src/meson.build | 6 ++- test/makefile | 3 +- test/testSvg.cpp | 4 +- test/testSvg2.cpp | 67 --------------------------- 20 files changed, 279 insertions(+), 103 deletions(-) create mode 100644 src/lib/tvgLoader.h create mode 100644 src/lib/tvgLoaderMgr.cpp create mode 100644 src/lib/tvgLoaderMgr.h create mode 100644 src/loaders/meson.build create mode 100644 src/loaders/svg_loader/meson.build create mode 100644 src/loaders/svg_loader/tvgSvgLoader.cpp create mode 100644 src/loaders/svg_loader/tvgSvgLoader.h delete mode 100644 test/testSvg2.cpp diff --git a/.gitignore b/.gitignore index af30a22..7aa8bd7 100644 --- a/.gitignore +++ b/.gitignore @@ -18,5 +18,4 @@ testLinearGradient testRadialGradient testGradientTransform testSvg -testSvg2 testGlShape diff --git a/inc/tizenvg.h b/inc/tizenvg.h index c62dda2..bc541b3 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -64,7 +64,7 @@ class Scene; class Canvas; -enum class TVG_EXPORT Result { Success = 0, InvalidArguments, InsufficientCondition, FailedAllocation, MemoryCorruption, Unknown }; +enum class TVG_EXPORT Result { Success = 0, InvalidArguments, InsufficientCondition, FailedAllocation, MemoryCorruption, NonSupport, Unknown }; enum class TVG_EXPORT PathCommand { Close = 0, MoveTo, LineTo, CubicTo }; enum class TVG_EXPORT StrokeCap { Square = 0, Round, Butt }; enum class TVG_EXPORT StrokeJoin { Bevel = 0, Round, Miter }; @@ -283,8 +283,7 @@ public: Result push(std::unique_ptr paint) noexcept; Result reserve(uint32_t size) noexcept; - Result load(const std::string& path, float w, float h, bool lazy = false) noexcept; - Result save(const std::string& path) noexcept; + Result load(const std::string& path) noexcept; Result rotate(float degree) noexcept override; Result scale(float factor) noexcept override; diff --git a/src/lib/gl_engine/meson.build b/src/lib/gl_engine/meson.build index a5409a7..943fb06 100644 --- a/src/lib/gl_engine/meson.build +++ b/src/lib/gl_engine/meson.build @@ -14,7 +14,7 @@ source_file = [ 'tvgGlShaderSrc.cpp', ] -glraster_dep = declare_dependency( +glengine_dep = declare_dependency( include_directories : include_directories('.'), sources : source_file ) diff --git a/src/lib/meson.build b/src/lib/meson.build index c936501..32db5f1 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -4,6 +4,8 @@ subdir('gl_engine') source_file = [ 'tvgCanvasImpl.h', 'tvgCommon.h', + 'tvgLoader.h', + 'tvgLoaderMgr.h', 'tvgRenderCommon.h', 'tvgSceneImpl.h', 'tvgShapePath.h', @@ -13,6 +15,7 @@ source_file = [ 'tvgGlCanvas.cpp', 'tvgInitializer.cpp', 'tvgLinearGradient.cpp', + 'tvgLoaderMgr.cpp', 'tvgRadialGradient.cpp', 'tvgScene.cpp', 'tvgShape.cpp', diff --git a/src/lib/sw_engine/meson.build b/src/lib/sw_engine/meson.build index f96fe97..8b06258 100644 --- a/src/lib/sw_engine/meson.build +++ b/src/lib/sw_engine/meson.build @@ -10,7 +10,7 @@ source_file = [ 'tvgSwStroke.cpp', ] -swraster_dep = declare_dependency( +swengine_dep = declare_dependency( include_directories : include_directories('.'), sources : source_file ) diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index 49c3f96..d147521 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -37,6 +37,8 @@ using namespace tvg; #define FILL_ID_LINEAR 0 #define FILL_ID_RADIAL 1 +#include "tvgLoader.h" +#include "tvgLoaderMgr.h" #include "tvgRenderCommon.h" #include "tvgShapePath.h" #include "tvgShapeImpl.h" diff --git a/src/lib/tvgInitializer.cpp b/src/lib/tvgInitializer.cpp index ac6ce3a..857698d 100644 --- a/src/lib/tvgInitializer.cpp +++ b/src/lib/tvgInitializer.cpp @@ -20,6 +20,7 @@ #include "tvgCommon.h" #include "tvgSwRenderer.h" #include "tvgGlRenderer.h" +#include "tvgLoaderMgr.h" /************************************************************************/ /* Internal Class Implementation */ @@ -39,9 +40,7 @@ Result Initializer::init(CanvasEngine engine) noexcept return Result::InvalidArguments; } - //TODO: check modules then enable them - //1. TVG - //2. SVG + if (!LoaderMgr::init()) return Result::Unknown; return Result::Success; } @@ -59,6 +58,8 @@ Result Initializer::term(CanvasEngine engine) noexcept return Result::InvalidArguments; } + if (!LoaderMgr::term()) return Result::Unknown; + return Result::Success; } diff --git a/src/lib/tvgLoader.h b/src/lib/tvgLoader.h new file mode 100644 index 0000000..8a1c918 --- /dev/null +++ b/src/lib/tvgLoader.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef _TVG_LOADER_H_ +#define _TVG_LOADER_H_ + +namespace tvg +{ + +class Loader +{ +public: + virtual ~Loader() {} + + virtual bool open(const char* path) = 0; + virtual bool read() = 0; + virtual bool close() = 0; + virtual unique_ptr data() = 0; +}; + +} + +#endif //_TVG_LOADER_H_ \ No newline at end of file diff --git a/src/lib/tvgLoaderMgr.cpp b/src/lib/tvgLoaderMgr.cpp new file mode 100644 index 0000000..a99838b --- /dev/null +++ b/src/lib/tvgLoaderMgr.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef _TVG_LOADER_MGR_CPP_ +#define _TVG_LOADER_MGR_CPP_ + +#include "tvgCommon.h" +#include "tvgSvgLoader.h" + + +static int initCnt = 0; + +bool LoaderMgr::init() +{ + if (initCnt > 0) return true; + ++initCnt; + + //TODO: + + return true; +} + +bool LoaderMgr::term() +{ + --initCnt; + if (initCnt > 0) return true; + + //TODO: + + return true; +} + +unique_ptr LoaderMgr::loader(const char* path) +{ + //TODO: + return unique_ptr(new SvgLoader); +} + +#endif //_TVG_LOADER_MGR_CPP_ \ No newline at end of file diff --git a/src/lib/tvgLoaderMgr.h b/src/lib/tvgLoaderMgr.h new file mode 100644 index 0000000..0d37012 --- /dev/null +++ b/src/lib/tvgLoaderMgr.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef _TVG_LOADER_MGR_H_ +#define _TVG_LOADER_MGR_H_ + +struct LoaderMgr +{ + static bool init(); + static bool term(); + static unique_ptr loader(const char* path); +}; + +#endif //_TVG_LOADER_MGR_H_ \ No newline at end of file diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index c093933..41620a0 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -108,26 +108,14 @@ Result Scene::bounds(float* x, float* y, float* w, float* h) const noexcept } -Result Scene::load(const std::string& path, float w, float h, bool lazy) noexcept +Result Scene::load(const std::string& path) noexcept { if (path.empty()) return Result::InvalidArguments; auto impl = pImpl.get(); if (!impl) return Result::MemoryCorruption; - return impl->load(path, w, h, lazy); + return impl->load(path); } - -Result Scene::save(const std::string& path) noexcept -{ - if (path.empty()) return Result::InvalidArguments; - - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - return impl->save(path); -} - - #endif /* _TVG_SCENE_CPP_ */ \ No newline at end of file diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index 5ba8d51..5e67a66 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -28,6 +28,7 @@ struct Scene::Impl vector paints; RenderTransform *transform = nullptr; uint32_t flag = RenderUpdateFlag::None; + unique_ptr loader = nullptr; ~Impl() { @@ -71,6 +72,15 @@ struct Scene::Impl bool update(RenderMethod &renderer, const RenderTransform* pTransform = nullptr, uint32_t pFlag = 0) { + if (loader) { + auto scene = loader->data(); + auto p = scene.release(); + if (!p) return false; + paints.push_back(p); + loader->close(); + loader.reset(nullptr); + } + if (flag & RenderUpdateFlag::Transform) { if (!transform) return false; if (!transform->update()) { @@ -192,13 +202,12 @@ struct Scene::Impl return true; } - Result load(const string& path, float w, float h, bool lazy) - { - return Result::Success; - } - - Result save(const string& path) + Result load(const string& path) { + if (loader) loader->close(); + loader = LoaderMgr::loader(path.c_str()); + if (!loader || !loader->open(path.c_str())) return Result::NonSupport; + if (!loader->read()) return Result::Unknown; return Result::Success; } }; diff --git a/src/loaders/meson.build b/src/loaders/meson.build new file mode 100644 index 0000000..53186dd --- /dev/null +++ b/src/loaders/meson.build @@ -0,0 +1 @@ +subdir('svg_loader') diff --git a/src/loaders/svg_loader/meson.build b/src/loaders/svg_loader/meson.build new file mode 100644 index 0000000..1bd40c1 --- /dev/null +++ b/src/loaders/svg_loader/meson.build @@ -0,0 +1,9 @@ +source_file = [ + 'tvgSvgLoader.h', + 'tvgSvgLoader.cpp', +] + +svgloader_dep = declare_dependency( + include_directories : include_directories('.'), + sources : source_file +) diff --git a/src/loaders/svg_loader/tvgSvgLoader.cpp b/src/loaders/svg_loader/tvgSvgLoader.cpp new file mode 100644 index 0000000..f4b8f43 --- /dev/null +++ b/src/loaders/svg_loader/tvgSvgLoader.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef _TVG_SVG_LOADER_CPP_ +#define _TVG_SVG_LOADER_CPP_ + +#include "tvgSvgLoader.h" + + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +SvgLoader::SvgLoader() +{ + cout << "SvgLoader()" << endl; +} + + +SvgLoader::~SvgLoader() +{ + cout << "~SvgLoader()" << endl; +} + + +bool SvgLoader::open(const char* path) +{ + //TODO: + cout << "SvgLoader::open()" << endl; + + return false; +} + + +bool SvgLoader::read() +{ + //TODO: + cout << "SvgLoader::read()" << endl; + + return false; +} + + +bool SvgLoader::close() +{ + //TODO: + cout << "SvgLoader::close()" << endl; + + return false; +} + + +unique_ptr SvgLoader::data() +{ + //TODO: + cout << "SvgLoader::data()" << endl; + + return nullptr; +} + +#endif //_TVG_SVG_LOADER_CPP_ \ No newline at end of file diff --git a/src/loaders/svg_loader/tvgSvgLoader.h b/src/loaders/svg_loader/tvgSvgLoader.h new file mode 100644 index 0000000..2b4d8b1 --- /dev/null +++ b/src/loaders/svg_loader/tvgSvgLoader.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef _TVG_SVG_LOADER_H_ +#define _TVG_SVG_LOADER_H_ + +#include "tvgCommon.h" + +class SvgLoader : public Loader +{ +private: + //TODO: + +public: + SvgLoader(); + ~SvgLoader(); + + bool open(const char* path) override; + bool read() override; + bool close() override; + unique_ptr data() override; +}; + + +#endif //_TVG_SVG_LOADER_H_ \ No newline at end of file diff --git a/src/meson.build b/src/meson.build index a0ef37d..e49c9a0 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,12 +1,14 @@ compiler_flags = ['-DTVG_BUILD'] subdir('lib') +subdir('loaders') subdir('examples') + m_dep = meson.get_compiler('cpp').find_library('m') egl_dep = meson.get_compiler('cpp').find_library('EGL') -gl_dep = meson.get_compiler('cpp').find_library('GLESv2') +gles_dep = meson.get_compiler('cpp').find_library('GLESv2') -tizenvg_lib_dep = [ src_dep, swraster_dep, glraster_dep, m_dep, egl_dep, gl_dep] +tizenvg_lib_dep = [ src_dep, swengine_dep, glengine_dep, m_dep, egl_dep, gles_dep, svgloader_dep] tizenvg_lib = library( diff --git a/test/makefile b/test/makefile index aca250b..501eef5 100755 --- a/test/makefile +++ b/test/makefile @@ -15,6 +15,5 @@ all: gcc -o testLinearGradient testLinearGradient.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testRadialGradient testRadialGradient.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testGradientTransform testGradientTransform.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` -# gcc -o testSvg testSvg.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` -# gcc -o testSvg2 testSvg2.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` + gcc -o testSvg testSvg.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testGlShape testGlShape.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` diff --git a/test/testSvg.cpp b/test/testSvg.cpp index dea96a2..e918902 100644 --- a/test/testSvg.cpp +++ b/test/testSvg.cpp @@ -17,9 +17,7 @@ void tvgtest() auto canvas = tvg::SwCanvas::gen(); canvas->target(buffer, WIDTH, WIDTH, HEIGHT); - /* Create a SVG scene, keep original size, - You can pass 0 x 0 size for lazying loading in this case. - scene->load("sample.svg", 0, 0, true); */ + // Create a SVG scene, request the original size, auto scene = tvg::Scene::gen(); scene->load("sample.svg"); canvas->push(move(scene)); diff --git a/test/testSvg2.cpp b/test/testSvg2.cpp deleted file mode 100644 index 4714db6..0000000 --- a/test/testSvg2.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include -#include - -using namespace std; - -#define WIDTH 800 -#define HEIGHT 800 - -static uint32_t buffer[WIDTH * HEIGHT]; - -void tvgtest() -{ - //Initialize TizenVG Engine - tvg::Initializer::init(tvg::CanvasEngine::Sw); - - //Create a Canvas - auto canvas = tvg::SwCanvas::gen(); - canvas->target(buffer, WIDTH, WIDTH, HEIGHT); - - //Create a SVG scene, keep aspect ratio to width/2 with lazy loading - auto scene = tvg::Scene::gen(); - scene->load("sample.svg", WIDTH/2, 0, true); - canvas->push(move(scene)); - - //Create a SVG scene, keep aspect ratio to height/2 with lazy loading - auto scene2 = tvg::Scene::gen(); - scene2->load("sample.svg", 0, HEIGHT/2, true); - scene2->translate(WIDTH/2, HEIGHT/2); - canvas->push(move(scene2)); - - canvas->draw(); - canvas->sync(); - - //Terminate TizenVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); -} - -void -win_del(void *data, Evas_Object *o, void *ev) -{ - elm_exit(); -} - - -int main(int argc, char **argv) -{ - tvgtest(); - - //Show the result using EFL... - elm_init(argc, argv); - - Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); - evas_object_smart_callback_add(win, "delete,request", win_del, 0); - - Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); - evas_object_image_size_set(img, WIDTH, HEIGHT); - evas_object_image_data_set(img, buffer); - evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_show(img); - - elm_win_resize_object_add(win, img); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); - - elm_run(); - elm_shutdown(); -} -- 2.7.4 From 538254a32d83a49e65565ab50c5af5eaeb3dd812 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 22 Jun 2020 16:30:18 +0900 Subject: [PATCH 03/16] common render: code refactoring. just replace the filename. Change-Id: I6b18520d33c7db3ac9d6c44b10dd693b204495e5 --- src/lib/{tvgRenderCommon.h => tvgRender.h} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/lib/{tvgRenderCommon.h => tvgRender.h} (100%) diff --git a/src/lib/tvgRenderCommon.h b/src/lib/tvgRender.h similarity index 100% rename from src/lib/tvgRenderCommon.h rename to src/lib/tvgRender.h -- 2.7.4 From f56a3b791c0f8a229c84fba232b4f35975abc36c Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 22 Jun 2020 16:44:11 +0900 Subject: [PATCH 04/16] comon render: split declaration and body. Change-Id: I39eb1dfb929b7811fab82956aedbb15f001390e7 --- src/lib/meson.build | 3 +- src/lib/tvgCommon.h | 2 +- src/lib/tvgRender.cpp | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib/tvgRender.h | 81 +++---------------------------------- 4 files changed, 118 insertions(+), 77 deletions(-) create mode 100644 src/lib/tvgRender.cpp diff --git a/src/lib/meson.build b/src/lib/meson.build index 32db5f1..9675206 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -6,7 +6,7 @@ source_file = [ 'tvgCommon.h', 'tvgLoader.h', 'tvgLoaderMgr.h', - 'tvgRenderCommon.h', + 'tvgRender.h', 'tvgSceneImpl.h', 'tvgShapePath.h', 'tvgShapeImpl.h', @@ -17,6 +17,7 @@ source_file = [ 'tvgLinearGradient.cpp', 'tvgLoaderMgr.cpp', 'tvgRadialGradient.cpp', + 'tvgRender.cpp', 'tvgScene.cpp', 'tvgShape.cpp', 'tvgSwCanvas.cpp', diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index d147521..2b0e9c1 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -39,7 +39,7 @@ using namespace tvg; #include "tvgLoader.h" #include "tvgLoaderMgr.h" -#include "tvgRenderCommon.h" +#include "tvgRender.h" #include "tvgShapePath.h" #include "tvgShapeImpl.h" #include "tvgSceneImpl.h" diff --git a/src/lib/tvgRender.cpp b/src/lib/tvgRender.cpp new file mode 100644 index 0000000..4b4afc3 --- /dev/null +++ b/src/lib/tvgRender.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef _TVG_RENDER_CPP_ +#define _TVG_RENDER_CPP_ + +#include "tvgCommon.h" +#include "tvgRender.h" + + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +bool RenderTransform::update() +{ + constexpr auto PI = 3.141592f; + + //Init Status + if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON && + fabsf(degree) <= FLT_EPSILON && fabsf(factor - 1) <= FLT_EPSILON) { + return false; + } + + //identity + e11 = 1.0f; + e12 = 0.0f; + e13 = 0.0f; + e21 = 0.0f; + e22 = 1.0f; + e23 = 0.0f; + e31 = 0.0f; + e32 = 0.0f; + e33 = 1.0f; + + //scale + e11 *= factor; + e22 *= factor; + e33 *= factor; + + //rotation + if (fabsf(degree) > FLT_EPSILON) { + auto radian = degree / 180.0f * PI; + auto cosVal = cosf(radian); + auto sinVal = sinf(radian); + + auto t11 = e11 * cosVal + e12 * sinVal; + auto t12 = e11 * -sinVal + e12 * cosVal; + auto t21 = e21 * cosVal + e22 * sinVal; + auto t22 = e21 * -sinVal + e22 * cosVal; + auto t31 = e31 * cosVal + e32 * sinVal; + auto t32 = e31 * -sinVal + e32 * cosVal; + + e11 = t11; + e12 = t12; + e21 = t21; + e22 = t22; + e31 = t31; + e32 = t32; + } + + e31 += x; + e32 += y; + + return true; +} + + +RenderTransform::RenderTransform() +{ +} + + +RenderTransform::RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs) +{ + assert(lhs && rhs); + + auto dx = rhs->x * lhs->factor; + auto dy = rhs->y * lhs->factor; + auto tx = dx * lhs->e11 + dy * lhs->e12 + lhs->e13; + auto ty = dx * lhs->e21 + dy * lhs->e22 + lhs->e23; + + x = lhs->x + tx; + y = lhs->y + ty; + degree = lhs->degree + rhs->degree; + factor = lhs->factor * rhs->factor; + + update(); +} + +#endif //_TVG_RENDER_CPP_ diff --git a/src/lib/tvgRender.h b/src/lib/tvgRender.h index a581067..74feb77 100644 --- a/src/lib/tvgRender.h +++ b/src/lib/tvgRender.h @@ -14,8 +14,8 @@ * limitations under the License. * */ -#ifndef _TVG_RENDER_COMMON_H_ -#define _TVG_RENDER_COMMON_H_ +#ifndef _TVG_RENDER_H_ +#define _TVG_RENDER_H_ namespace tvg { @@ -42,79 +42,10 @@ struct RenderTransform float degree = 0.0f; //rotation degree float factor = 1.0f; //scale factor - bool update() - { - constexpr auto PI = 3.141592f; - - //Init Status - if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON && - fabsf(degree) <= FLT_EPSILON && fabsf(factor - 1) <= FLT_EPSILON) { - return false; - } - - //identity - e11 = 1.0f; - e12 = 0.0f; - e13 = 0.0f; - e21 = 0.0f; - e22 = 1.0f; - e23 = 0.0f; - e31 = 0.0f; - e32 = 0.0f; - e33 = 1.0f; - - //scale - e11 *= factor; - e22 *= factor; - e33 *= factor; - - //rotation - if (fabsf(degree) > FLT_EPSILON) { - auto radian = degree / 180.0f * PI; - auto cosVal = cosf(radian); - auto sinVal = sinf(radian); - - auto t11 = e11 * cosVal + e12 * sinVal; - auto t12 = e11 * -sinVal + e12 * cosVal; - auto t21 = e21 * cosVal + e22 * sinVal; - auto t22 = e21 * -sinVal + e22 * cosVal; - auto t31 = e31 * cosVal + e32 * sinVal; - auto t32 = e31 * -sinVal + e32 * cosVal; - - e11 = t11; - e12 = t12; - e21 = t21; - e22 = t22; - e31 = t31; - e32 = t32; - } - - e31 += x; - e32 += y; - - return true; - } + bool update(); - RenderTransform() - { - } - - RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs) - { - assert(lhs && rhs); - - auto dx = rhs->x * lhs->factor; - auto dy = rhs->y * lhs->factor; - auto tx = dx * lhs->e11 + dy * lhs->e12 + lhs->e13; - auto ty = dx * lhs->e21 + dy * lhs->e22 + lhs->e23; - - x = lhs->x + tx; - y = lhs->y + ty; - degree = lhs->degree + rhs->degree; - factor = lhs->factor * rhs->factor; - - update(); - } + RenderTransform(); + RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs); }; @@ -190,4 +121,4 @@ struct RenderInitializer } -#endif //_TVG_RENDER_COMMON_H_ +#endif //_TVG_RENDER_H_ \ No newline at end of file -- 2.7.4 From ab5c1bc44180a256c6b9f02f26fcff40e7f0bf16 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 22 Jun 2020 17:06:53 +0900 Subject: [PATCH 05/16] common bezier: code refactoring. Organize bezier functions for internal share. this bezier can be used in svg loader. Change-Id: I78acd3273c0528688ca46ff7c29d78607bd729bd --- src/lib/meson.build | 2 + src/lib/sw_engine/tvgSwShape.cpp | 109 +---------------------------- src/lib/tvgBezier.cpp | 144 +++++++++++++++++++++++++++++++++++++++ src/lib/tvgBezier.h | 39 +++++++++++ src/lib/tvgCommon.h | 1 + src/lib/tvgRender.cpp | 2 - 6 files changed, 188 insertions(+), 109 deletions(-) create mode 100644 src/lib/tvgBezier.cpp create mode 100644 src/lib/tvgBezier.h diff --git a/src/lib/meson.build b/src/lib/meson.build index 9675206..53c9a19 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -4,12 +4,14 @@ subdir('gl_engine') source_file = [ 'tvgCanvasImpl.h', 'tvgCommon.h', + 'tvgBezier.h', 'tvgLoader.h', 'tvgLoaderMgr.h', 'tvgRender.h', 'tvgSceneImpl.h', 'tvgShapePath.h', 'tvgShapeImpl.h', + 'tvgBezier.cpp', 'tvgCanvas.cpp', 'tvgFill.cpp', 'tvgGlCanvas.cpp', diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 4d3c44e..ee599df 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -30,15 +30,6 @@ struct Line }; -struct Bezier -{ - Point start; - Point ctrl1; - Point ctrl2; - Point end; -}; - - static float _lineLength(const Point& pt1, const Point& pt2) { /* approximate sqrt(x*x + y*y) using alpha max plus beta min algorithm. @@ -64,102 +55,6 @@ static void _lineSplitAt(const Line& cur, float at, Line& left, Line& right) } -static void _bezSplit(const Bezier&cur, Bezier& left, Bezier& right) -{ - auto c = (cur.ctrl1.x + cur.ctrl2.x) * 0.5f; - left.ctrl1.x = (cur.start.x + cur.ctrl1.x) * 0.5f; - right.ctrl2.x = (cur.ctrl2.x + cur.end.x) * 0.5f; - left.start.x = cur.start.x; - right.end.x = cur.end.x; - left.ctrl2.x = (left.ctrl1.x + c) * 0.5f; - right.ctrl1.x = (right.ctrl2.x + c) * 0.5f; - left.end.x = right.start.x = (left.ctrl2.x + right.ctrl1.x) * 0.5f; - - c = (cur.ctrl1.y + cur.ctrl2.y) * 0.5f; - left.ctrl1.y = (cur.start.y + cur.ctrl1.y) * 0.5f; - right.ctrl2.y = (cur.ctrl2.y + cur.end.y) * 0.5f; - left.start.y = cur.start.y; - right.end.y = cur.end.y; - left.ctrl2.y = (left.ctrl1.y + c) * 0.5f; - right.ctrl1.y = (right.ctrl2.y + c) * 0.5f; - left.end.y = right.start.y = (left.ctrl2.y + right.ctrl1.y) * 0.5f; -} - - -static float _bezLength(const Bezier& cur) -{ - Bezier left, right; - auto len = _lineLength(cur.start, cur.ctrl1) + _lineLength(cur.ctrl1, cur.ctrl2) + _lineLength(cur.ctrl2, cur.end); - auto chord = _lineLength(cur.start, cur.end); - - if (fabs(len - chord) > FLT_EPSILON) { - _bezSplit(cur, left, right); - return _bezLength(left) + _bezLength(right); - } - return len; -} - - -static void _bezSplitLeft(Bezier& cur, float at, Bezier& left) -{ - left.start = cur.start; - - left.ctrl1.x = cur.start.x + at * (cur.ctrl1.x - cur.start.x); - left.ctrl1.y = cur.start.y + at * (cur.ctrl1.y - cur.start.y); - - left.ctrl2.x = cur.ctrl1.x + at * (cur.ctrl2.x - cur.ctrl1.x); // temporary holding spot - left.ctrl2.y = cur.ctrl1.y + at * (cur.ctrl2.y - cur.ctrl1.y); // temporary holding spot - - cur.ctrl2.x = cur.ctrl2.x + at * (cur.end.x - cur.ctrl2.x); - cur.ctrl2.y = cur.ctrl2.y + at * (cur.end.y - cur.ctrl2.y); - - cur.ctrl1.x = left.ctrl2.x + at * (cur.ctrl2.x - left.ctrl2.x); - cur.ctrl1.y = left.ctrl2.y + at * (cur.ctrl2.y - left.ctrl2.y); - - left.ctrl2.x = left.ctrl1.x + at * (left.ctrl2.x - left.ctrl1.x); - left.ctrl2.y = left.ctrl1.y + at * (left.ctrl2.y - left.ctrl1.y); - - left.end.x = cur.start.x = left.ctrl2.x + at * (cur.ctrl1.x - left.ctrl2.x); - left.end.y = cur.start.y = left.ctrl2.y + at * (cur.ctrl1.y - left.ctrl2.y); -} - - -static float _bezAt(const Bezier& bz, float at) -{ - auto len = _bezLength(bz); - auto biggest = 1.0f; - - if (at >= len) return 1.0f; - - at *= 0.5f; - - while (true) { - auto right = bz; - Bezier left; - _bezSplitLeft(right, at, left); - auto len2 = _bezLength(left); - - if (fabs(len2 - len) < FLT_EPSILON) break; - - if (len2 < len) { - at += (biggest - at) * 0.5f; - } else { - biggest = at; - at -= (at * 0.5f); - } - } - return at; -} - - -static void _bezSplitAt(const Bezier& cur, float at, Bezier& left, Bezier& right) -{ - right = cur; - auto t = _bezAt(right, at); - _bezSplitLeft(right, t, left); -} - - static void _growOutlineContour(SwOutline& outline, uint32_t n) { if (outline.reservedCntrsCnt >= outline.cntrsCnt + n) return; @@ -407,7 +302,7 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct _growOutlineContour(*dash.outline, dash.outline->cntrsCnt >> 1); Bezier cur = { dash.ptCur, *ctrl1, *ctrl2, *to}; - auto len = _bezLength(cur); + auto len = bezLength(cur); if (len < dash.curLen) { dash.curLen -= len; @@ -419,7 +314,7 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct while (len > dash.curLen) { Bezier left, right; len -= dash.curLen; - _bezSplitAt(cur, dash.curLen, left, right); + bezSplitAt(cur, dash.curLen, left, right); dash.curIdx = (dash.curIdx + 1) % dash.cnt; if (!dash.curOpGap) { _outlineMoveTo(*dash.outline, &left.start); diff --git a/src/lib/tvgBezier.cpp b/src/lib/tvgBezier.cpp new file mode 100644 index 0000000..1aa2dab --- /dev/null +++ b/src/lib/tvgBezier.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef _TVG_BEZIER_CPP_ +#define _TVG_BEZIER_CPP_ + +#include "tvgCommon.h" + + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +static float _lineLength(const Point& pt1, const Point& pt2) +{ + /* approximate sqrt(x*x + y*y) using alpha max plus beta min algorithm. + With alpha = 1, beta = 3/8, giving results with the largest error less + than 7% compared to the exact value. */ + Point diff = {pt2.x - pt1.x, pt2.y - pt1.y}; + if (diff.x < 0) diff.x = -diff.x; + if (diff.y < 0) diff.y = -diff.y; + return (diff.x > diff.y) ? (diff.x + diff.y * 0.375f) : (diff.y + diff.x * 0.375f); +} + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +namespace tvg +{ + +void bezSplit(const Bezier&cur, Bezier& left, Bezier& right) +{ + auto c = (cur.ctrl1.x + cur.ctrl2.x) * 0.5f; + left.ctrl1.x = (cur.start.x + cur.ctrl1.x) * 0.5f; + right.ctrl2.x = (cur.ctrl2.x + cur.end.x) * 0.5f; + left.start.x = cur.start.x; + right.end.x = cur.end.x; + left.ctrl2.x = (left.ctrl1.x + c) * 0.5f; + right.ctrl1.x = (right.ctrl2.x + c) * 0.5f; + left.end.x = right.start.x = (left.ctrl2.x + right.ctrl1.x) * 0.5f; + + c = (cur.ctrl1.y + cur.ctrl2.y) * 0.5f; + left.ctrl1.y = (cur.start.y + cur.ctrl1.y) * 0.5f; + right.ctrl2.y = (cur.ctrl2.y + cur.end.y) * 0.5f; + left.start.y = cur.start.y; + right.end.y = cur.end.y; + left.ctrl2.y = (left.ctrl1.y + c) * 0.5f; + right.ctrl1.y = (right.ctrl2.y + c) * 0.5f; + left.end.y = right.start.y = (left.ctrl2.y + right.ctrl1.y) * 0.5f; +} + + +float bezLength(const Bezier& cur) +{ + Bezier left, right; + auto len = _lineLength(cur.start, cur.ctrl1) + _lineLength(cur.ctrl1, cur.ctrl2) + _lineLength(cur.ctrl2, cur.end); + auto chord = _lineLength(cur.start, cur.end); + + if (fabs(len - chord) > FLT_EPSILON) { + bezSplit(cur, left, right); + return bezLength(left) + bezLength(right); + } + return len; +} + + +void bezSplitLeft(Bezier& cur, float at, Bezier& left) +{ + left.start = cur.start; + + left.ctrl1.x = cur.start.x + at * (cur.ctrl1.x - cur.start.x); + left.ctrl1.y = cur.start.y + at * (cur.ctrl1.y - cur.start.y); + + left.ctrl2.x = cur.ctrl1.x + at * (cur.ctrl2.x - cur.ctrl1.x); // temporary holding spot + left.ctrl2.y = cur.ctrl1.y + at * (cur.ctrl2.y - cur.ctrl1.y); // temporary holding spot + + cur.ctrl2.x = cur.ctrl2.x + at * (cur.end.x - cur.ctrl2.x); + cur.ctrl2.y = cur.ctrl2.y + at * (cur.end.y - cur.ctrl2.y); + + cur.ctrl1.x = left.ctrl2.x + at * (cur.ctrl2.x - left.ctrl2.x); + cur.ctrl1.y = left.ctrl2.y + at * (cur.ctrl2.y - left.ctrl2.y); + + left.ctrl2.x = left.ctrl1.x + at * (left.ctrl2.x - left.ctrl1.x); + left.ctrl2.y = left.ctrl1.y + at * (left.ctrl2.y - left.ctrl1.y); + + left.end.x = cur.start.x = left.ctrl2.x + at * (cur.ctrl1.x - left.ctrl2.x); + left.end.y = cur.start.y = left.ctrl2.y + at * (cur.ctrl1.y - left.ctrl2.y); +} + + +float bezAt(const Bezier& bz, float at) +{ + auto len = bezLength(bz); + auto biggest = 1.0f; + + if (at >= len) return 1.0f; + + at *= 0.5f; + + while (true) { + auto right = bz; + Bezier left; + bezSplitLeft(right, at, left); + auto len2 = bezLength(left); + + if (fabs(len2 - len) < FLT_EPSILON) break; + + if (len2 < len) { + at += (biggest - at) * 0.5f; + } else { + biggest = at; + at -= (at * 0.5f); + } + } + return at; +} + + +void bezSplitAt(const Bezier& cur, float at, Bezier& left, Bezier& right) +{ + right = cur; + auto t = bezAt(right, at); + bezSplitLeft(right, t, left); +} + + +} + +#endif //_TVG_BEZIER_CPP_ diff --git a/src/lib/tvgBezier.h b/src/lib/tvgBezier.h new file mode 100644 index 0000000..aa7d77f --- /dev/null +++ b/src/lib/tvgBezier.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef _TVG_BEZIER_H_ +#define _TVG_BEZIER_H_ + +namespace tvg +{ + +struct Bezier +{ + Point start; + Point ctrl1; + Point ctrl2; + Point end; +}; + +void bezSplit(const Bezier&cur, Bezier& left, Bezier& right); +float bezLength(const Bezier& cur); +void bezSplitLeft(Bezier& cur, float at, Bezier& left); +float bezAt(const Bezier& bz, float at); +void bezSplitAt(const Bezier& cur, float at, Bezier& left, Bezier& right); + +} + +#endif //_TVG_BEZIER_H_ \ No newline at end of file diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index 2b0e9c1..302f4e9 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -37,6 +37,7 @@ using namespace tvg; #define FILL_ID_LINEAR 0 #define FILL_ID_RADIAL 1 +#include "tvgBezier.h" #include "tvgLoader.h" #include "tvgLoaderMgr.h" #include "tvgRender.h" diff --git a/src/lib/tvgRender.cpp b/src/lib/tvgRender.cpp index 4b4afc3..bffbe40 100644 --- a/src/lib/tvgRender.cpp +++ b/src/lib/tvgRender.cpp @@ -18,8 +18,6 @@ #define _TVG_RENDER_CPP_ #include "tvgCommon.h" -#include "tvgRender.h" - /************************************************************************/ /* Internal Class Implementation */ -- 2.7.4 From c6742e9590ba243cd7f2eefed511e4adf72d68e4 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 22 Jun 2020 20:53:52 +0900 Subject: [PATCH 06/16] common transform: support matrix transform interface. this interface is designed for user-defined arbitrary affine-transform paints. required by svg loader. Change-Id: I7f08023605d224e36cef3770098d3757aee81848 --- .gitignore | 1 + inc/tizenvg.h | 33 ++++----- src/lib/sw_engine/tvgSwFill.cpp | 14 ++-- src/lib/sw_engine/tvgSwShape.cpp | 4 +- src/lib/tvgRender.cpp | 72 ++++++++++++-------- src/lib/tvgRender.h | 8 +-- src/lib/tvgScene.cpp | 11 +++ src/lib/tvgSceneImpl.h | 64 +++++++++++------- src/lib/tvgShape.cpp | 13 +++- src/lib/tvgShapeImpl.h | 68 +++++++++++-------- test/makefile | 1 + test/testCustomTransform.cpp | 140 +++++++++++++++++++++++++++++++++++++++ 12 files changed, 318 insertions(+), 111 deletions(-) create mode 100644 test/testCustomTransform.cpp diff --git a/.gitignore b/.gitignore index 7aa8bd7..c2b9a6c 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ testUpdate testDirectUpdate testScene testTransform +testCustomTransform testSceneTransform testStroke testStrokeLine diff --git a/inc/tizenvg.h b/inc/tizenvg.h index bc541b3..a7eede4 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -78,6 +78,14 @@ struct Point }; +struct Matrix +{ + float e11, e12, e13; + float e21, e22, e23; + float e31, e32, e33; +}; + + /** * @class Paint * @@ -91,12 +99,6 @@ class TVG_EXPORT Paint public: virtual ~Paint() {} - virtual Result rotate(float degree) = 0; - virtual Result scale(float factor) = 0; - virtual Result translate(float x, float y) = 0; - - virtual Result bounds(float* x, float* y, float* w, float* h) const = 0; - _TVG_DECALRE_IDENTIFIER(); }; @@ -242,16 +244,17 @@ public: Result fill(std::unique_ptr f) noexcept; //Transform - Result rotate(float degree) noexcept override; - Result scale(float factor) noexcept override; - Result translate(float x, float y) noexcept override; + Result rotate(float degree) noexcept; + Result scale(float factor) noexcept; + Result translate(float x, float y) noexcept; + Result transform(const Matrix& m) noexcept; //Getters uint32_t pathCommands(const PathCommand** cmds) const noexcept; uint32_t pathCoords(const Point** pts) const noexcept; Result fill(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept; const Fill* fill() const noexcept; - Result bounds(float* x, float* y, float* w, float* h) const noexcept override; + Result bounds(float* x, float* y, float* w, float* h) const noexcept; float strokeWidth() const noexcept; Result strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept; @@ -282,14 +285,14 @@ public: Result push(std::unique_ptr paint) noexcept; Result reserve(uint32_t size) noexcept; - Result load(const std::string& path) noexcept; - Result rotate(float degree) noexcept override; - Result scale(float factor) noexcept override; - Result translate(float x, float y) noexcept override; + Result rotate(float degree) noexcept; + Result scale(float factor) noexcept; + Result translate(float x, float y) noexcept; + Result transform(const Matrix& m) noexcept; - Result bounds(float* x, float* y, float* w, float* h) const noexcept override; + Result bounds(float* x, float* y, float* w, float* h) const noexcept; static std::unique_ptr gen() noexcept; diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp index f609183..0bf3024 100644 --- a/src/lib/sw_engine/tvgSwFill.cpp +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -100,12 +100,12 @@ bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const RenderTran auto cy = (y2 - y1) * 0.5f + y1; auto dx = x1 - cx; auto dy = y1 - cy; - x1 = dx * transform->e11 + dy * transform->e12 + transform->e31; - y1 = dx * transform->e21 + dy * transform->e22 + transform->e32; + x1 = dx * transform->m.e11 + dy * transform->m.e12 + transform->m.e31; + y1 = dx * transform->m.e21 + dy * transform->m.e22 + transform->m.e32; dx = x2 - cx; dy = y2 - cy; - x2 = dx * transform->e11 + dy * transform->e12 + transform->e31; - y2 = dx * transform->e21 + dy * transform->e22 + transform->e32; + x2 = dx * transform->m.e11 + dy * transform->m.e12 + transform->m.e31; + y2 = dx * transform->m.e21 + dy * transform->m.e22 + transform->m.e32; } fill->linear.dx = x2 - x1; @@ -131,11 +131,11 @@ bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const RenderTran if (radius < FLT_EPSILON) return true; if (transform) { - auto tx = fill->radial.cx * transform->e11 + fill->radial.cy * transform->e12 + transform->e31; - auto ty = fill->radial.cx * transform->e21 + fill->radial.cy * transform->e22 + transform->e32; + auto tx = fill->radial.cx * transform->m.e11 + fill->radial.cy * transform->m.e12 + transform->m.e31; + auto ty = fill->radial.cx * transform->m.e21 + fill->radial.cy * transform->m.e22 + transform->m.e32; fill->radial.cx = tx; fill->radial.cy = ty; - radius *= transform->e33; + radius *= transform->m.e33; } fill->radial.a = radius * radius; diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 4d3c44e..6d8c9f2 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -347,8 +347,8 @@ static void _transformOutline(SwOutline* outline, const RenderTransform* transfo for(uint32_t i = 0; i < outline->ptsCnt; ++i) { auto dx = static_cast(outline->pts[i].x >> 6); auto dy = static_cast(outline->pts[i].y >> 6); - auto tx = dx * transform->e11 + dy * transform->e12 + transform->e31; - auto ty = dx * transform->e21 + dy * transform->e22 + transform->e32; + auto tx = dx * transform->m.e11 + dy * transform->m.e12 + transform->m.e31; + auto ty = dx * transform->m.e21 + dy * transform->m.e22 + transform->m.e32; auto pt = Point{tx, ty}; outline->pts[i] = TO_SWPOINT(&pt); } diff --git a/src/lib/tvgRender.cpp b/src/lib/tvgRender.cpp index 4b4afc3..cd9dff2 100644 --- a/src/lib/tvgRender.cpp +++ b/src/lib/tvgRender.cpp @@ -30,10 +30,24 @@ /* External Class Implementation */ /************************************************************************/ +void RenderTransform::override(const Matrix& m) +{ + this->m = m; + + if (m.e11 == 0.0f && m.e12 == 0.0f && m.e13 == 0.0f && + m.e21 == 0.0f && m.e22 == 0.0f && m.e23 == 0.0f && + m.e31 == 0.0f && m.e32 == 0.0f && m.e33 == 0.0f) { + overriding = false; + } else overriding = true; +} + + bool RenderTransform::update() { constexpr auto PI = 3.141592f; + if (overriding) return true; + //Init Status if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON && fabsf(degree) <= FLT_EPSILON && fabsf(factor - 1) <= FLT_EPSILON) { @@ -41,20 +55,20 @@ bool RenderTransform::update() } //identity - e11 = 1.0f; - e12 = 0.0f; - e13 = 0.0f; - e21 = 0.0f; - e22 = 1.0f; - e23 = 0.0f; - e31 = 0.0f; - e32 = 0.0f; - e33 = 1.0f; + m.e11 = 1.0f; + m.e12 = 0.0f; + m.e13 = 0.0f; + m.e21 = 0.0f; + m.e22 = 1.0f; + m.e23 = 0.0f; + m.e31 = 0.0f; + m.e32 = 0.0f; + m.e33 = 1.0f; //scale - e11 *= factor; - e22 *= factor; - e33 *= factor; + m.e11 *= factor; + m.e22 *= factor; + m.e33 *= factor; //rotation if (fabsf(degree) > FLT_EPSILON) { @@ -62,23 +76,23 @@ bool RenderTransform::update() auto cosVal = cosf(radian); auto sinVal = sinf(radian); - auto t11 = e11 * cosVal + e12 * sinVal; - auto t12 = e11 * -sinVal + e12 * cosVal; - auto t21 = e21 * cosVal + e22 * sinVal; - auto t22 = e21 * -sinVal + e22 * cosVal; - auto t31 = e31 * cosVal + e32 * sinVal; - auto t32 = e31 * -sinVal + e32 * cosVal; - - e11 = t11; - e12 = t12; - e21 = t21; - e22 = t22; - e31 = t31; - e32 = t32; + auto t11 = m.e11 * cosVal + m.e12 * sinVal; + auto t12 = m.e11 * -sinVal + m.e12 * cosVal; + auto t21 = m.e21 * cosVal + m.e22 * sinVal; + auto t22 = m.e21 * -sinVal + m.e22 * cosVal; + auto t31 = m.e31 * cosVal + m.e32 * sinVal; + auto t32 = m.e31 * -sinVal + m.e32 * cosVal; + + m.e11 = t11; + m.e12 = t12; + m.e21 = t21; + m.e22 = t22; + m.e31 = t31; + m.e32 = t32; } - e31 += x; - e32 += y; + m.e31 += x; + m.e32 += y; return true; } @@ -95,8 +109,8 @@ RenderTransform::RenderTransform(const RenderTransform* lhs, const RenderTransfo auto dx = rhs->x * lhs->factor; auto dy = rhs->y * lhs->factor; - auto tx = dx * lhs->e11 + dy * lhs->e12 + lhs->e13; - auto ty = dx * lhs->e21 + dy * lhs->e22 + lhs->e23; + auto tx = dx * lhs->m.e11 + dy * lhs->m.e12 + lhs->m.e13; + auto ty = dx * lhs->m.e21 + dy * lhs->m.e22 + lhs->m.e23; x = lhs->x + tx; y = lhs->y + ty; diff --git a/src/lib/tvgRender.h b/src/lib/tvgRender.h index 74feb77..8e9a50f 100644 --- a/src/lib/tvgRender.h +++ b/src/lib/tvgRender.h @@ -32,17 +32,15 @@ enum RenderUpdateFlag {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, struct RenderTransform { - //3x3 Matrix Elements - float e11, e12, e13; - float e21, e22, e23; - float e31, e32, e33; - + Matrix m; //3x3 Matrix Elements float x = 0.0f; float y = 0.0f; float degree = 0.0f; //rotation degree float factor = 1.0f; //scale factor + bool overriding = false; //user transform? bool update(); + void override(const Matrix& m); RenderTransform(); RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs); diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index 41620a0..1980d96 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -97,6 +97,17 @@ Result Scene::translate(float x, float y) noexcept } +Result Scene::transform(const Matrix& m) noexcept +{ + auto impl = pImpl.get(); + if (!impl) return Result::MemoryCorruption; + + if (!impl->transform(m)) return Result::FailedAllocation; + + return Result::Success; +} + + Result Scene::bounds(float* x, float* y, float* w, float* h) const noexcept { auto impl = pImpl.get(); diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index 5e67a66..4e412d4 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -26,7 +26,7 @@ struct Scene::Impl { vector paints; - RenderTransform *transform = nullptr; + RenderTransform *rTransform = nullptr; uint32_t flag = RenderUpdateFlag::None; unique_ptr loader = nullptr; @@ -34,7 +34,7 @@ struct Scene::Impl { //Are you sure clear() prior to this? assert(paints.empty()); - if (transform) delete(transform); + if (rTransform) delete(rTransform); } bool clear(RenderMethod& renderer) @@ -82,20 +82,20 @@ struct Scene::Impl } if (flag & RenderUpdateFlag::Transform) { - if (!transform) return false; - if (!transform->update()) { - delete(transform); - transform = nullptr; + if (!rTransform) return false; + if (!rTransform->update()) { + delete(rTransform); + rTransform = nullptr; } } auto ret = true; - if (transform && pTransform) { - RenderTransform outTransform(pTransform, transform); + if (rTransform && pTransform) { + RenderTransform outTransform(pTransform, rTransform); ret = updateInternal(renderer, &outTransform, pFlag | flag); } else { - auto outTransform = pTransform ? pTransform : transform; + auto outTransform = pTransform ? pTransform : rTransform; ret = updateInternal(renderer, outTransform, pFlag | flag); } @@ -158,14 +158,14 @@ struct Scene::Impl bool scale(float factor) { - if (transform) { - if (fabsf(factor - transform->factor) <= FLT_EPSILON) return true; + if (rTransform) { + if (fabsf(factor - rTransform->factor) <= FLT_EPSILON) return true; } else { if (fabsf(factor) <= FLT_EPSILON) return true; - transform = new RenderTransform(); - if (!transform) return false; + rTransform = new RenderTransform(); + if (!rTransform) return false; } - transform->factor = factor; + rTransform->factor = factor; flag |= RenderUpdateFlag::Transform; return true; @@ -173,14 +173,14 @@ struct Scene::Impl bool rotate(float degree) { - if (transform) { - if (fabsf(degree - transform->degree) <= FLT_EPSILON) return true; + if (rTransform) { + if (fabsf(degree - rTransform->degree) <= FLT_EPSILON) return true; } else { if (fabsf(degree) <= FLT_EPSILON) return true; - transform = new RenderTransform(); - if (!transform) return false; + rTransform = new RenderTransform(); + if (!rTransform) return false; } - transform->degree = degree; + rTransform->degree = degree; flag |= RenderUpdateFlag::Transform; return true; @@ -188,20 +188,34 @@ struct Scene::Impl bool translate(float x, float y) { - if (transform) { - if (fabsf(x - transform->x) <= FLT_EPSILON && fabsf(y - transform->y) <= FLT_EPSILON) return true; + if (rTransform) { + if (fabsf(x - rTransform->x) <= FLT_EPSILON && fabsf(y - rTransform->y) <= FLT_EPSILON) return true; } else { if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON) return true; - transform = new RenderTransform(); - if (!transform) return false; + rTransform = new RenderTransform(); + if (!rTransform) return false; } - transform->x = x; - transform->y = y; + rTransform->x = x; + rTransform->y = y; flag |= RenderUpdateFlag::Transform; return true; } + + bool transform(const Matrix& m) + { + if (!rTransform) { + rTransform = new RenderTransform(); + if (!rTransform) return false; + } + rTransform->override(m); + flag |= RenderUpdateFlag::Transform; + + return true; + } + + Result load(const string& path) { if (loader) loader->close(); diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index aabd5bd..f7699b4 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -303,7 +303,18 @@ Result Shape::translate(float x, float y) noexcept auto impl = pImpl.get(); if (!impl) return Result::MemoryCorruption; - impl->translate(x, y); + if (!impl->translate(x, y)) return Result::FailedAllocation; + + return Result::Success; +} + + +Result Shape::transform(const Matrix& m) noexcept +{ + auto impl = pImpl.get(); + if (!impl) return Result::MemoryCorruption; + + if (!impl->transform(m)) return Result::FailedAllocation; return Result::Success; } diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index 4cce022..fa670f0 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -44,7 +44,7 @@ struct Shape::Impl ShapePath *path = nullptr; Fill *fill = nullptr; ShapeStroke *stroke = nullptr; - RenderTransform *transform = nullptr; + RenderTransform *rTransform = nullptr; uint8_t color[4] = {0, 0, 0, 0}; //r, g, b, a uint32_t flag = RenderUpdateFlag::None; void *edata = nullptr; //engine data @@ -59,7 +59,7 @@ struct Shape::Impl if (path) delete(path); if (fill) delete(fill); if (stroke) delete(stroke); - if (transform) delete(transform); + if (rTransform) delete(rTransform); } bool dispose(Shape& shape, RenderMethod& renderer) @@ -75,18 +75,18 @@ struct Shape::Impl bool update(Shape& shape, RenderMethod& renderer, const RenderTransform* pTransform = nullptr, uint32_t pFlag = 0) { if (flag & RenderUpdateFlag::Transform) { - if (!transform) return false; - if (!transform->update()) { - delete(transform); - transform = nullptr; + if (!rTransform) return false; + if (!rTransform->update()) { + delete(rTransform); + rTransform = nullptr; } } - if (transform && pTransform) { - RenderTransform outTransform(pTransform, transform); + if (rTransform && pTransform) { + RenderTransform outTransform(pTransform, rTransform); edata = renderer.prepare(shape, edata, &outTransform, static_cast(pFlag | flag)); } else { - auto outTransform = pTransform ? pTransform : transform; + auto outTransform = pTransform ? pTransform : rTransform; edata = renderer.prepare(shape, edata, outTransform, static_cast(pFlag | flag)); } @@ -104,50 +104,64 @@ struct Shape::Impl bool scale(float factor) { - if (transform) { - if (fabsf(factor - transform->factor) <= FLT_EPSILON) return true; + if (rTransform) { + if (fabsf(factor - rTransform->factor) <= FLT_EPSILON) return true; } else { if (fabsf(factor) <= FLT_EPSILON) return true; - transform = new RenderTransform(); - if (!transform) return false; + rTransform = new RenderTransform(); + if (!rTransform) return false; } - transform->factor = factor; - flag |= RenderUpdateFlag::Transform; + rTransform->factor = factor; + if (!rTransform->overriding) flag |= RenderUpdateFlag::Transform; return true; } bool rotate(float degree) { - if (transform) { - if (fabsf(degree - transform->degree) <= FLT_EPSILON) return true; + if (rTransform) { + if (fabsf(degree - rTransform->degree) <= FLT_EPSILON) return true; } else { if (fabsf(degree) <= FLT_EPSILON) return true; - transform = new RenderTransform(); - if (!transform) return false; + rTransform = new RenderTransform(); + if (!rTransform) return false; } - transform->degree = degree; - flag |= RenderUpdateFlag::Transform; + rTransform->degree = degree; + if (!rTransform->overriding) flag |= RenderUpdateFlag::Transform; return true; } bool translate(float x, float y) { - if (transform) { - if (fabsf(x - transform->x) <= FLT_EPSILON && fabsf(y - transform->y) <= FLT_EPSILON) return true; + if (rTransform) { + if (fabsf(x - rTransform->x) <= FLT_EPSILON && fabsf(y - rTransform->y) <= FLT_EPSILON) return true; } else { if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON) return true; - transform = new RenderTransform(); - if (!transform) return false; + rTransform = new RenderTransform(); + if (!rTransform) return false; + } + rTransform->x = x; + rTransform->y = y; + if (!rTransform->overriding) flag |= RenderUpdateFlag::Transform; + + return true; + } + + + bool transform(const Matrix& m) + { + if (!rTransform) { + rTransform = new RenderTransform(); + if (!rTransform) return false; } - transform->x = x; - transform->y = y; + rTransform->override(m); flag |= RenderUpdateFlag::Transform; return true; } + bool strokeWidth(float width) { //TODO: Size Exception? diff --git a/test/makefile b/test/makefile index 501eef5..f6624fc 100755 --- a/test/makefile +++ b/test/makefile @@ -9,6 +9,7 @@ all: gcc -o testDirectUpdate testDirectUpdate.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testScene testScene.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testTransform testTransform.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` + gcc -o testCustomTransform testCustomTransform.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testSceneTransform testSceneTransform.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testStroke testStroke.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testStrokeLine testStrokeLine.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` diff --git a/test/testCustomTransform.cpp b/test/testCustomTransform.cpp new file mode 100644 index 0000000..ae3d7c8 --- /dev/null +++ b/test/testCustomTransform.cpp @@ -0,0 +1,140 @@ +#include +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 + +static uint32_t buffer[WIDTH * HEIGHT]; +unique_ptr canvas = nullptr; +tvg::Shape* pShape = nullptr; + +void tvgtest() +{ + //Create a Canvas + canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); + + //Shape1 + auto shape = tvg::Shape::gen(); + + /* Acquire shape pointer to access it again. + instead, you should consider not to interrupt this pointer life-cycle. */ + pShape = shape.get(); + + shape->moveTo(0, -114.5); + shape->lineTo(54, -5.5); + shape->lineTo(175, 11.5); + shape->lineTo(88, 95.5); + shape->lineTo(108, 216.5); + shape->lineTo(0, 160.5); + shape->lineTo(-102, 216.5); + shape->lineTo(-87, 96.5); + shape->lineTo(-173, 12.5); + shape->lineTo(-53, -5.5); + shape->close(); + shape->fill(0, 0, 255, 255); + canvas->push(move(shape)); + + //Draw first frame + canvas->draw(); + canvas->sync(); +} + +void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) +{ + /* Update shape directly. + You can update only necessary properties of this shape, + while retaining other properties. */ + + //Transform Matrix + tvg::Matrix m = {1, 0, 0, 0, 1, 0, 0, 0, 1}; + + //scale x + m.e11 = 1 - (progress * 0.5f); + + //scale y + m.e22 = 1 + (progress * 2.0f); + + //rotation + constexpr auto PI = 3.141592f; + auto degree = 45.0f; + auto radian = degree / 180.0f * PI; + auto cosVal = cosf(radian); + auto sinVal = sinf(radian); + + auto t11 = m.e11 * cosVal + m.e12 * sinVal; + auto t12 = m.e11 * -sinVal + m.e12 * cosVal; + auto t21 = m.e21 * cosVal + m.e22 * sinVal; + auto t22 = m.e21 * -sinVal + m.e22 * cosVal; + auto t31 = m.e31 * cosVal + m.e32 * sinVal; + auto t32 = m.e31 * -sinVal + m.e32 * cosVal; + + m.e11 = t11; + m.e12 = t12; + m.e21 = t21; + m.e22 = t22; + m.e31 = t31; + m.e32 = t32; + + //translate + m.e31 = progress * 300.0f + 300.0f; + m.e32 = progress * -100.0f + 300.0f; + + pShape->transform(m); + + //Update shape for drawing (this may work asynchronously) + canvas->update(pShape); + + //Draw Next frames + canvas->draw(); + canvas->sync(); + + //Update Efl Canvas + Eo* img = (Eo*) effect; + evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); +} + +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + +int main(int argc, char **argv) +{ + //Initialize TizenVG Engine + tvg::Initializer::init(tvg::CanvasEngine::Sw); + + tvgtest(); + + //Show the result using EFL... + elm_init(argc, argv); + + Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + evas_object_smart_callback_add(win, "delete,request", win_del, 0); + + Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); + evas_object_image_size_set(img, WIDTH, HEIGHT); + evas_object_image_data_set(img, buffer); + evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(img); + + elm_win_resize_object_add(win, img); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + Elm_Transit *transit = elm_transit_add(); + elm_transit_effect_add(transit, transit_cb, img, nullptr); + elm_transit_duration_set(transit, 2); + elm_transit_repeat_times_set(transit, -1); + elm_transit_auto_reverse_set(transit, EINA_TRUE); + elm_transit_go(transit); + + elm_run(); + elm_shutdown(); + + //Terminate TizenVG Engine + tvg::Initializer::term(tvg::CanvasEngine::Sw); +} -- 2.7.4 From 4f48c856f6f965390e198c2a6c52cdb99e287bf7 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 23 Jun 2020 14:14:47 +0900 Subject: [PATCH 07/16] sw_engie: fix wrong boundary check. this bounding box max indicates absolute positions, not width/height size. because of this, shape couldn't rendered properly, when it's clipped out. Change-Id: I0afb0d6e63d1b511b83716c55f55e3fd5370fdb8 --- src/lib/sw_engine/tvgSwShape.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 723650b..22fed2c 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -225,9 +225,7 @@ static bool _checkValid(const SwOutline* outline, const SwBBox& bbox, const SwSi if (outline->ptsCnt == 0 || outline->cntrsCnt <= 0) return false; //Check boundary - if ((bbox.min.x > clip.w || bbox.min.y > clip.h) || - (bbox.min.x + bbox.max.x < 0) || - (bbox.min.y + bbox.max.y < 0)) return false; + if (bbox.min.x >= clip.w || bbox.min.y >= clip.h || bbox.max.x <= 0 || bbox.max.y <= 0) return false; return true; } -- 2.7.4 From 86300c5fc05a9e0b269f2f1a624c7c1f77fd5913 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 23 Jun 2020 14:41:57 +0900 Subject: [PATCH 08/16] sw_engine: optimize raster. memset() is more than 10x faster than manual loop. Thus we replace it to manipulate buffer pixels. Change-Id: If0f255578f7d49ff6704c4f15e2eefe435cc3c15 --- meson.build | 2 +- src/lib/sw_engine/tvgSwCommon.h | 17 +++++++++++++++++ src/lib/sw_engine/tvgSwFill.cpp | 25 +------------------------ src/lib/sw_engine/tvgSwRaster.cpp | 33 +++++++++++++++++++++++++-------- src/lib/sw_engine/tvgSwRenderer.cpp | 13 ++----------- test/makefile | 0 6 files changed, 46 insertions(+), 44 deletions(-) mode change 100755 => 100644 test/makefile diff --git a/meson.build b/meson.build index 5692fbc..6693650 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project('tizenvg', 'cpp', - default_options : ['buildtype=debug', 'werror=false', 'cpp_std=c++14'], + default_options : ['buildtype=debugoptimized', 'werror=false', 'cpp_std=c++14', 'optimization=s'], version : '0.1.0', license : 'Apache-2.0') diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index eedaf9d..076cccd 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -19,6 +19,16 @@ #include "tvgCommon.h" +#if 1 +#include +static double timeStamp() +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return (tv.tv_sec + tv.tv_usec / 1000000.0); +} +#endif + using namespace tvg; #define SW_CURVE_TYPE_POINT 0 @@ -230,6 +240,12 @@ static inline uint32_t COLOR_ARGB_JOIN(uint8_t r, uint8_t g, uint8_t b, uint8_t } +static inline void COLOR_SET(uint32_t *dst, uint32_t val, uint32_t len) +{ + while (len--) *dst++ = val; +} + + int64_t mathMultiply(int64_t a, int64_t b); int64_t mathDivide(int64_t a, int64_t b); int64_t mathMulDiv(int64_t a, int64_t b, int64_t c); @@ -273,5 +289,6 @@ void rleFree(SwRleData* rle); bool rasterGradientShape(Surface& surface, SwShape& shape, unsigned id); bool rasterSolidShape(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a); bool rasterStroke(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a); +bool rasterClear(Surface& surface); #endif /* _TVG_SW_COMMON_H_ */ diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp index 0bf3024..bd7f81e 100644 --- a/src/lib/sw_engine/tvgSwFill.cpp +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -181,29 +181,6 @@ static inline uint32_t _pixel(const SwFill* fill, float pos) } -static inline void _write(uint32_t *dst, uint32_t val, uint32_t len) -{ - if (len <= 0) return; - - // Cute hack to align future memcopy operation - // and do unroll the loop a bit. Not sure it is - // the most efficient, but will do for now. - auto n = (len + 7) / 8; - - switch (len & 0x07) { - case 0: do { *dst++ = val; - case 7: *dst++ = val; - case 6: *dst++ = val; - case 5: *dst++ = val; - case 4: *dst++ = val; - case 3: *dst++ = val; - case 2: *dst++ = val; - case 1: *dst++ = val; - } while (--n > 0); - } -} - - /************************************************************************/ /* External Class Implementation */ /************************************************************************/ @@ -244,7 +221,7 @@ void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, if (fabsf(inc) < FLT_EPSILON) { auto color = _fixedPixel(fill, static_cast(t * FIXPT_SIZE)); - _write(dst, color, len); + COLOR_SET(dst, color, len); return; } diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 05f23e6..05429f3 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -24,20 +24,22 @@ /* Internal Class Implementation */ /************************************************************************/ + static bool _rasterTranslucentRle(Surface& surface, SwRleData* rle, uint32_t color) { if (!rle) return false; auto span = rle->spans; auto stride = surface.stride; - uint32_t tmp; + uint32_t src; for (uint32_t i = 0; i < rle->size; ++i) { auto dst = &surface.buffer[span->y * stride + span->x]; - if (span->coverage < 255) tmp = COLOR_ALPHA_BLEND(color, span->coverage); - else tmp = color; + if (span->coverage < 255) src = COLOR_ALPHA_BLEND(color, span->coverage); + else src = color; + auto ialpha = 255 - COLOR_ALPHA(src); for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = tmp + COLOR_ALPHA_BLEND(dst[i], 255 - COLOR_ALPHA(tmp)); + dst[i] = src + COLOR_ALPHA_BLEND(dst[i], ialpha); } ++span; } @@ -55,12 +57,12 @@ static bool _rasterSolidRle(Surface& surface, SwRleData* rle, uint32_t color) for (uint32_t i = 0; i < rle->size; ++i) { auto dst = &surface.buffer[span->y * stride + span->x]; if (span->coverage == 255) { - for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = color; - } + COLOR_SET(dst, color, span->len); } else { + auto src = COLOR_ALPHA_BLEND(color, span->coverage); + auto ialpha = 255 - span->coverage; for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = COLOR_ALPHA_BLEND(color, span->coverage) + COLOR_ALPHA_BLEND(dst[i], 255 - span->coverage); + dst[i] = src + COLOR_ALPHA_BLEND(dst[i], ialpha); } } ++span; @@ -188,4 +190,19 @@ bool rasterStroke(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, uint8_ } +bool rasterClear(Surface& surface) +{ + if (!surface.buffer || surface.stride <= 0 || surface.w <= 0 || surface.h <= 0) return false; + + if (surface.w == surface.stride) { + COLOR_SET(surface.buffer, 0xff000000, surface.w * surface.h); + } else { + for (uint32_t i = 0; i < surface.h; i++) { + COLOR_SET(surface.buffer + surface.stride * i, 0xff000000, surface.w); + } + } + return true; +} + + #endif /* _TVG_SW_RASTER_CPP_ */ \ No newline at end of file diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index adeb738..9a5db51 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -20,6 +20,7 @@ #include "tvgSwCommon.h" #include "tvgSwRenderer.h" + /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ @@ -32,17 +33,7 @@ static RenderInitializer renderInit; bool SwRenderer::clear() { - if (!surface.buffer) return false; - - assert(surface.stride > 0 && surface.w > 0 && surface.h > 0); - - //OPTIMIZE ME: SIMD! - for (uint32_t i = 0; i < surface.h; i++) { - for (uint32_t j = 0; j < surface.w; j++) - surface.buffer[surface.stride * i + j] = 0xff000000; //Solid Black - } - - return true; + return rasterClear(surface); } bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) diff --git a/test/makefile b/test/makefile old mode 100755 new mode 100644 -- 2.7.4 From 55e215e6ea50c35dbaeb720cec2c75b7877cc3a2 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 23 Jun 2020 17:29:28 +0900 Subject: [PATCH 09/16] sw_engine: optimize span generation. there are unnecessary partial spans generated in orthogonal rectangle. we can merge those partial spans to others if they are on the same scanline... Change-Id: I35a437a4f2eec106bd50f46f0390c652e617311d --- src/lib/sw_engine/tvgSwCommon.h | 2 +- src/lib/sw_engine/tvgSwFill.cpp | 9 ++++----- src/lib/sw_engine/tvgSwRle.cpp | 10 ++++++---- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 076cccd..71af7df 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -19,7 +19,7 @@ #include "tvgCommon.h" -#if 1 +#if 0 #include static double timeStamp() { diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp index bd7f81e..2a9ba69 100644 --- a/src/lib/sw_engine/tvgSwFill.cpp +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -189,7 +189,7 @@ void fillFetchRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, { if (fill->radial.a < FLT_EPSILON) return; - //TODO: Rotation??? + //Rotation auto rx = x + 0.5f - fill->radial.cx; auto ry = y + 0.5f - fill->radial.cy; auto inv2a = fill->radial.inv2a; @@ -199,13 +199,12 @@ void fillFetchRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, auto detDelta = (4 * fill->radial.a * (rxryPlus + 1.0f)) * inv2a; auto detDelta2 = (4 * fill->radial.a * 2.0f) * inv2a; - for (uint32_t i = 0 ; i < len ; ++i) - { + for (uint32_t i = 0 ; i < len ; ++i) { *dst = _pixel(fill, sqrt(det)); ++dst; det += detDelta; detDelta += detDelta2; - } + } } @@ -213,7 +212,7 @@ void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, { if (fill->linear.len < FLT_EPSILON) return; - //TODO: Rotation??? + //Rotation auto rx = x + 0.5f; auto ry = y + 0.5f; auto t = (fill->linear.dx * rx + fill->linear.dy * ry + fill->linear.offset) * (GRADIENT_STOP_SIZE - 1); diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index cab5463..5d7d5a7 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -195,7 +195,7 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor y = SHRT_MAX; } - if (coverage) { + if (coverage > 0) { auto count = rw.spansCnt; auto span = rw.spans + count - 1; assert(span); @@ -209,13 +209,15 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor if (x + acount >= rw.clip.w) xOver -= (x + acount - rw.clip.w); if (x < 0) xOver += x; - span->len += (acount + xOver) - 1; + //span->len += (acount + xOver) - 1; + span->len += (acount + xOver); return; } if (count >= MAX_SPANS) { _genSpan(rw.rle, rw.spans, count); rw.spansCnt = 0; + rw.ySpan = 0; span = rw.spans; assert(span); } else { @@ -240,6 +242,7 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor span->len = (acount + xOver); span->coverage = coverage; ++rw.spansCnt; + rw.ySpan = y; } } @@ -249,6 +252,7 @@ static void _sweep(RleWorker& rw) if (rw.cellsCnt == 0) return; rw.spansCnt = 0; + rw.ySpan = 0; for (int y = 0; y < rw.yCnt; ++y) { auto cover = 0; @@ -775,6 +779,4 @@ void rleFree(SwRleData* rle) free(rle); } - - #endif /* _TVG_SW_RLE_H_ */ -- 2.7.4 From b212df1061a96232035e6e6de650e001ead17258 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 23 Jun 2020 17:38:59 +0900 Subject: [PATCH 10/16] sw_engine stroke: initialize a missing variable. Change-Id: I1c3d83d56045f592ff89a5462d4de494e50c9d34 --- src/lib/sw_engine/tvgSwStroke.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index 8b6f1ce..94a2537 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -297,13 +297,11 @@ static void _inside(SwStroke& stroke, int32_t side, SwFixed lineLength) auto border = stroke.borders + side; auto theta = mathDiff(stroke.angleIn, stroke.angleOut) / 2; SwPoint delta; - bool intersect; + bool intersect = false; /* Only intersect borders if between two line_to's and both lines are long enough (line length is zero fur curves). */ - if (!border->movable || lineLength == 0) { - intersect = false; - } else { + if (border->movable && lineLength > 0) { //compute minimum required length of lines SwFixed minLength = abs(mathMultiply(stroke.width, mathTan(theta))); if (stroke.lineLength >= minLength && lineLength >= minLength) intersect = true; -- 2.7.4 From 9ffc1d40f6f9f1ffd439c5b25cfb3918ac96fc77 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 23 Jun 2020 18:59:12 +0900 Subject: [PATCH 11/16] sw_engine: optimize memory allocation. there are a logical wrong that memory increase size, it correct that also tune the number to reduce memory allocation time. Now scene transform test works smoothly. Change-Id: If0674e33426d794546801a96ad9de711b5de0dcd --- src/lib/sw_engine/tvgSwRle.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index 5d7d5a7..5bb3a31 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -147,9 +147,9 @@ static void _genSpan(SwRleData* rle, SwSpan* spans, uint32_t count) /* alloc is required to prevent free and reallocation */ /* when the rle needs to be regenerated because of attribute change. */ if (rle->alloc < newSize) { - rle->spans = static_cast(realloc(rle->spans, (count + rle->size) << 2 * sizeof(SwSpan))); + rle->alloc = (newSize * 2); + rle->spans = static_cast(realloc(rle->spans, rle->alloc * sizeof(SwSpan))); assert(rle->spans); - rle->alloc = rle->size + (count << 2); } //copy the new spans to the allocated memory -- 2.7.4 From 35803e9c2b145bdfe19d50f1ab99edf3cdd7efa8 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 24 Jun 2020 13:31:09 +0900 Subject: [PATCH 12/16] test: add stress test for performance profiling. Change-Id: I4a1556c107ba59b7c972375ab8bfd22c777a5503 --- .gitignore | 1 + test/makefile | 1 + test/testStress.cpp | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+) create mode 100644 test/testStress.cpp diff --git a/.gitignore b/.gitignore index c2b9a6c..c8da1b2 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ testRadialGradient testGradientTransform testSvg testGlShape +testStress diff --git a/test/makefile b/test/makefile index f6624fc..9f77648 100644 --- a/test/makefile +++ b/test/makefile @@ -18,3 +18,4 @@ all: gcc -o testGradientTransform testGradientTransform.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testSvg testSvg.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testGlShape testGlShape.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` + gcc -o testStress testStress.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` diff --git a/test/testStress.cpp b/test/testStress.cpp new file mode 100644 index 0000000..2c1020e --- /dev/null +++ b/test/testStress.cpp @@ -0,0 +1,117 @@ +#include +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 +#define COUNT 50 + +static uint32_t buffer[WIDTH * HEIGHT]; +unique_ptr canvas = nullptr; + +void tvgtest() +{ + //Create a Canvas + canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); +} + +Eina_Bool anim_cb(void *data) +{ + static unsigned cnt = 0; + + //Explicitly clear all retained paint nodes. + double t1 = ecore_time_get(); + canvas->clear(); + double t2 = ecore_time_get(); + + for (int i = 0; i < COUNT; i++) { + auto shape = tvg::Shape::gen(); + + float x = rand() % 400; + float y = rand() % 400; + float w = 1 + rand() % 600; + float h = 1 + rand() % 600; + + shape->appendRect(x, y, w, h, rand() % 400); + + if (rand() % 2) { + //LinearGradient + auto fill = tvg::LinearGradient::gen(); + fill->linear(x, y, x + w, y + h); + + //Gradient Color Stops + tvg::Fill::ColorStop colorStops[3]; + colorStops[0] = {0, uint8_t(rand() % 255), uint8_t(rand() % 255), uint8_t(rand() % 255), 255}; + colorStops[1] = {1, uint8_t(rand() % 255), uint8_t(rand() % 255), uint8_t(rand() % 255), 255}; + colorStops[2] = {2, uint8_t(rand() % 255), uint8_t(rand() % 255), uint8_t(rand() % 255), 255}; + + fill->colorStops(colorStops, 3); + shape->fill(move(fill)); + } else { + shape->fill(uint8_t(rand() % 255), uint8_t(rand() % 255), uint8_t(rand() % 255), 255); + } +#if 0 + if (rand() % 2) { + shape->stroke(float(rand() % 10)); + shape->stroke(uint8_t(rand() % 255), uint8_t(rand() % 255), uint8_t(rand() % 255), 255); + } +#endif + canvas->push(move(shape)); + } + + double t3 = ecore_time_get(); + + //Draw Next frames + canvas->draw(); + canvas->sync(); + + double t4 = ecore_time_get(); + + printf("[%5d]: total[%fms] = clear[%fms] + update[%fms] + render[%fms]\n", ++cnt, t4 - t1, t2 - t1, t3 - t2, t4 - t3); + + //Update Efl Canvas + Eo* img = (Eo*) data; + evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); + + return ECORE_CALLBACK_RENEW; +} + +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + +int main(int argc, char **argv) +{ + //Initialize TizenVG Engine + tvg::Initializer::init(tvg::CanvasEngine::Sw); + + tvgtest(); + + //Show the result using EFL... + elm_init(argc, argv); + + Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + evas_object_smart_callback_add(win, "delete,request", win_del, 0); + + Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); + evas_object_image_size_set(img, WIDTH, HEIGHT); + evas_object_image_data_set(img, buffer); + evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(img); + + elm_win_resize_object_add(win, img); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + ecore_animator_add(anim_cb, img); + + elm_run(); + elm_shutdown(); + + //Terminate TizenVG Engine + tvg::Initializer::term(tvg::CanvasEngine::Sw); +} -- 2.7.4 From 36c76ca73ca4791ee1d42d14dde16dda3f4f4b9f Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 23 Jun 2020 20:12:39 +0900 Subject: [PATCH 13/16] sw_engine: threading optimization make it prepare step asynchronously. Change-Id: Ifb85f01d579cf1c111558842496b93fcaef74cd9 --- src/lib/sw_engine/tvgSwCommon.h | 32 +++++++---- src/lib/sw_engine/tvgSwFill.cpp | 22 ++++---- src/lib/sw_engine/tvgSwRenderer.cpp | 109 ++++++++++++++++++++---------------- src/lib/sw_engine/tvgSwShape.cpp | 67 +++++++++++----------- src/lib/sw_engine/tvgSwStroke.cpp | 10 ++-- src/lib/tvgCanvasImpl.h | 10 ++-- src/meson.build | 3 +- test/testBlending.cpp | 3 +- test/testBoundary.cpp | 3 +- test/testCustomTransform.cpp | 3 +- test/testGlShape.cpp | 15 ++--- test/testGradientTransform.cpp | 3 +- test/testLinearGradient.cpp | 3 +- test/testMultiShapes.cpp | 3 +- test/testPath.cpp | 3 +- test/testPathCopy.cpp | 3 +- test/testRadialGradient.cpp | 3 +- test/testScene.cpp | 3 +- test/testSceneTransform.cpp | 3 +- test/testShape.cpp | 3 +- test/testStress.cpp | 46 ++++++++------- test/testStroke.cpp | 4 +- test/testStrokeLine.cpp | 3 +- test/testSvg.cpp | 3 +- test/testTransform.cpp | 3 +- test/testUpdate.cpp | 3 +- 26 files changed, 185 insertions(+), 181 deletions(-) diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 71af7df..9c54088 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -17,6 +17,8 @@ #ifndef _TVG_SW_COMMON_H_ #define _TVG_SW_COMMON_H_ +#include +#include #include "tvgCommon.h" #if 0 @@ -201,6 +203,16 @@ struct SwShape }; +struct SwTask +{ + SwShape shape; + const Shape* sdata; + SwSize clip; + const Matrix* transform; + RenderUpdateFlag flags; + future prepared; +}; + static inline SwPoint TO_SWPOINT(const Point* pt) { return {SwCoord(pt->x * 64), SwCoord(pt->y * 64)}; @@ -261,24 +273,24 @@ bool mathSmallCubic(SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& SwFixed mathMean(SwFixed angle1, SwFixed angle2); void shapeReset(SwShape& shape); -bool shapeGenOutline(SwShape& shape, const Shape& sdata); -bool shapeGenRle(SwShape& shape, const Shape& sdata, const SwSize& clip, const RenderTransform* transform); +bool shapeGenOutline(SwShape& shape, const Shape* sdata); +bool shapeGenRle(SwShape& shape, const Shape* sdata, const SwSize& clip, const Matrix* transform); void shapeDelOutline(SwShape& shape); -void shapeResetStroke(SwShape& shape, const Shape& sdata); -bool shapeGenStrokeRle(SwShape& shape, const Shape& sdata, const SwSize& clip); -void shapeFree(SwShape* shape); +void shapeResetStroke(SwShape& shape, const Shape* sdata); +bool shapeGenStrokeRle(SwShape& shape, const Shape* sdata, const SwSize& clip); +void shapeFree(SwShape& shape); void shapeDelStroke(SwShape& shape); -bool shapeGenFillColors(SwShape& shape, const Fill* fill, const RenderTransform* transform, bool ctable); -void shapeResetFill(SwShape& shape, const Fill* fill); +bool shapeGenFillColors(SwShape& shape, const Fill* fill, const Matrix* transform, bool ctable); +void shapeResetFill(SwShape& shape); void shapeDelFill(SwShape& shape); -void strokeReset(SwStroke& stroke, const Shape& shape); +void strokeReset(SwStroke& stroke, const Shape* shape); bool strokeParseOutline(SwStroke& stroke, const SwOutline& outline); SwOutline* strokeExportOutline(SwStroke& stroke); void strokeFree(SwStroke* stroke); -bool fillGenColorTable(SwFill* fill, const Fill* fdata, const RenderTransform* transform, bool ctable); -void fillReset(SwFill* fill, const Fill* fdata); +bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, bool ctable); +void fillReset(SwFill* fill); void fillFree(SwFill* fill); void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len); void fillFetchRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len); diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp index 2a9ba69..5992bca 100644 --- a/src/lib/sw_engine/tvgSwFill.cpp +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -88,7 +88,7 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata) } -bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const RenderTransform* transform) +bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const Matrix* transform) { assert(fill && linear); @@ -100,12 +100,12 @@ bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const RenderTran auto cy = (y2 - y1) * 0.5f + y1; auto dx = x1 - cx; auto dy = y1 - cy; - x1 = dx * transform->m.e11 + dy * transform->m.e12 + transform->m.e31; - y1 = dx * transform->m.e21 + dy * transform->m.e22 + transform->m.e32; + x1 = dx * transform->e11 + dy * transform->e12 + transform->e31; + y1 = dx * transform->e21 + dy * transform->e22 + transform->e32; dx = x2 - cx; dy = y2 - cy; - x2 = dx * transform->m.e11 + dy * transform->m.e12 + transform->m.e31; - y2 = dx * transform->m.e21 + dy * transform->m.e22 + transform->m.e32; + x2 = dx * transform->e11 + dy * transform->e12 + transform->e31; + y2 = dx * transform->e21 + dy * transform->e22 + transform->e32; } fill->linear.dx = x2 - x1; @@ -122,7 +122,7 @@ bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const RenderTran } -bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const RenderTransform* transform) +bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const Matrix* transform) { assert(fill && radial); @@ -131,11 +131,11 @@ bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const RenderTran if (radius < FLT_EPSILON) return true; if (transform) { - auto tx = fill->radial.cx * transform->m.e11 + fill->radial.cy * transform->m.e12 + transform->m.e31; - auto ty = fill->radial.cx * transform->m.e21 + fill->radial.cy * transform->m.e22 + transform->m.e32; + auto tx = fill->radial.cx * transform->e11 + fill->radial.cy * transform->e12 + transform->e31; + auto ty = fill->radial.cx * transform->e21 + fill->radial.cy * transform->e22 + transform->e32; fill->radial.cx = tx; fill->radial.cy = ty; - radius *= transform->m.e33; + radius *= transform->e33; } fill->radial.a = radius * radius; @@ -248,7 +248,7 @@ void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, } -bool fillGenColorTable(SwFill* fill, const Fill* fdata, const RenderTransform* transform, bool ctable) +bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, bool ctable) { if (!fill) return false; @@ -272,7 +272,7 @@ bool fillGenColorTable(SwFill* fill, const Fill* fdata, const RenderTransform* t } -void fillReset(SwFill* fill, const Fill* fdata) +void fillReset(SwFill* fill) { if (fill->ctable) { free(fill->ctable); diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 9a5db51..8c59029 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -36,6 +36,7 @@ bool SwRenderer::clear() return rasterClear(surface); } + bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) { if (!buffer || stride == 0 || w == 0 || h == 0) return false; @@ -48,22 +49,25 @@ bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t return true; } + bool SwRenderer::render(const Shape& sdata, void *data) { - SwShape* shape = static_cast(data); - if (!shape) return false; + auto task = static_cast(data); + if (!task) return false; + + if (task->prepared.valid()) task->prepared.get(); uint8_t r, g, b, a; if (auto fill = sdata.fill()) { - rasterGradientShape(surface, *shape, fill->id()); + rasterGradientShape(surface, task->shape, fill->id()); } else { sdata.fill(&r, &g, &b, &a); - if (a > 0) rasterSolidShape(surface, *shape, r, g, b, a); + if (a > 0) rasterSolidShape(surface, task->shape, r, g, b, a); } sdata.strokeColor(&r, &g, &b, &a); - if (a > 0) rasterStroke(surface, *shape, r, g, b, a); + if (a > 0) rasterStroke(surface, task->shape, r, g, b, a); return true; } @@ -71,67 +75,74 @@ bool SwRenderer::render(const Shape& sdata, void *data) bool SwRenderer::dispose(const Shape& sdata, void *data) { - auto shape = static_cast(data); - if (!shape) return true; - shapeFree(shape); + auto task = static_cast(data); + if (!task) return true; + if (task->prepared.valid()) task->prepared.wait(); + shapeFree(task->shape); + free(task); return true; } void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* transform, RenderUpdateFlag flags) { - //prepare shape data - auto shape = static_cast(data); - if (!shape) { - shape = static_cast(calloc(1, sizeof(SwShape))); - assert(shape); + //prepare task + auto task = static_cast(data); + if (!task) { + task = static_cast(calloc(1, sizeof(SwTask))); + if (!task) return nullptr; } - if (flags == RenderUpdateFlag::None) return shape; + if (flags == RenderUpdateFlag::None || task->prepared.valid()) return task; - //TODO: Threading + task->sdata = &sdata; + task->clip = {static_cast(surface.w), static_cast(surface.h)}; - SwSize clip = {static_cast(surface.w), static_cast(surface.h)}; + if (transform) task->transform = &transform->m; + else task->transform = nullptr; - //Shape - if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Transform)) { - shapeReset(*shape); - uint8_t alpha = 0; - sdata.fill(nullptr, nullptr, nullptr, &alpha); - if (alpha > 0 || sdata.fill()) { - if (!shapeGenRle(*shape, sdata, clip, transform)) return shape; - } - } + task->flags = flags; - //Fill - if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform)) { - auto fill = sdata.fill(); - if (fill) { - auto ctable = (flags & RenderUpdateFlag::Gradient) ? true : false; - if (ctable) shapeResetFill(*shape, fill); - if (!shapeGenFillColors(*shape, fill, transform, ctable)) return shape; - } else { - shapeDelFill(*shape); - } - } - - //Stroke - if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) { - if (sdata.strokeWidth() > FLT_EPSILON) { - shapeResetStroke(*shape, sdata); + auto asyncTask = [](SwTask* task) { + //Shape + if (task->flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Transform)) { + shapeReset(task->shape); uint8_t alpha = 0; - sdata.strokeColor(nullptr, nullptr, nullptr, &alpha); - if (alpha > 0) { - if (!shapeGenStrokeRle(*shape, sdata, clip)) return shape; + task->sdata->fill(nullptr, nullptr, nullptr, &alpha); + if (alpha > 0 || task->sdata->fill()) { + if (!shapeGenRle(task->shape, task->sdata, task->clip, task->transform)) return; } - } else { - shapeDelStroke(*shape); } - } + //Fill + if (task->flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform)) { + auto fill = task->sdata->fill(); + if (fill) { + auto ctable = (task->flags & RenderUpdateFlag::Gradient) ? true : false; + if (ctable) shapeResetFill(task->shape); + if (!shapeGenFillColors(task->shape, fill, task->transform, ctable)) return; + } else { + shapeDelFill(task->shape); + } + } + //Stroke + if (task->flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) { + if (task->sdata->strokeWidth() > FLT_EPSILON) { + shapeResetStroke(task->shape, task->sdata); + uint8_t alpha = 0; + task->sdata->strokeColor(nullptr, nullptr, nullptr, &alpha); + if (alpha > 0) { + if (!shapeGenStrokeRle(task->shape, task->sdata, task->clip)) return; + } + } else { + shapeDelStroke(task->shape); + } + } + shapeDelOutline(task->shape); + }; - shapeDelOutline(*shape); + task->prepared = async((launch::async | launch::deferred), asyncTask, task); - return shape; + return task; } diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 22fed2c..d9a4e81 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -231,17 +231,17 @@ static bool _checkValid(const SwOutline* outline, const SwBBox& bbox, const SwSi } -static void _transformOutline(SwOutline* outline, const RenderTransform* transform) +static void _transformOutline(SwOutline* outline, const Matrix* transform) { - assert(outline); - if (!transform) return; + assert(outline); + for(uint32_t i = 0; i < outline->ptsCnt; ++i) { auto dx = static_cast(outline->pts[i].x >> 6); auto dy = static_cast(outline->pts[i].y >> 6); - auto tx = dx * transform->m.e11 + dy * transform->m.e12 + transform->m.e31; - auto ty = dx * transform->m.e21 + dy * transform->m.e22 + transform->m.e32; + auto tx = dx * transform->e11 + dy * transform->e12 + transform->e31; + auto ty = dx * transform->e21 + dy * transform->e22 + transform->e32; auto pt = Point{tx, ty}; outline->pts[i] = TO_SWPOINT(&pt); } @@ -340,13 +340,15 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct } -SwOutline* _genDashOutline(const Shape& shape) +SwOutline* _genDashOutline(const Shape* sdata) { + assert(sdata); + const PathCommand* cmds = nullptr; - auto cmdCnt = shape.pathCommands(&cmds); + auto cmdCnt = sdata->pathCommands(&cmds); const Point* pts = nullptr; - auto ptsCnt = shape.pathCoords(&pts); + auto ptsCnt = sdata->pathCoords(&pts); //No actual shape data if (cmdCnt == 0 || ptsCnt == 0) return nullptr; @@ -359,7 +361,7 @@ SwOutline* _genDashOutline(const Shape& shape) dash.curOpGap = false; const float* pattern; - dash.cnt = shape.strokeDash(&pattern); + dash.cnt = sdata->strokeDash(&pattern); assert(dash.cnt > 0 && pattern); //Is it safe to mutual exclusive? @@ -440,7 +442,7 @@ SwOutline* _genDashOutline(const Shape& shape) /* External Class Implementation */ /************************************************************************/ -bool shapeGenRle(SwShape& shape, const Shape& sdata, const SwSize& clip, const RenderTransform* transform) +bool shapeGenRle(SwShape& shape, const Shape* sdata, const SwSize& clip, const Matrix* transform) { if (!shapeGenOutline(shape, sdata)) return false; @@ -474,13 +476,15 @@ void shapeReset(SwShape& shape) } -bool shapeGenOutline(SwShape& shape, const Shape& sdata) +bool shapeGenOutline(SwShape& shape, const Shape* sdata) { + assert(sdata); + const PathCommand* cmds = nullptr; - auto cmdCnt = sdata.pathCommands(&cmds); + auto cmdCnt = sdata->pathCommands(&cmds); const Point* pts = nullptr; - auto ptsCnt = sdata.pathCoords(&pts); + auto ptsCnt = sdata->pathCoords(&pts); //No actual shape data if (cmdCnt == 0 || ptsCnt == 0) return false; @@ -559,19 +563,15 @@ bool shapeGenOutline(SwShape& shape, const Shape& sdata) } -void shapeFree(SwShape* shape) +void shapeFree(SwShape& shape) { - assert(shape); - - shapeDelOutline(*shape); - rleFree(shape->rle); + shapeDelOutline(shape); + rleFree(shape.rle); - if (shape->stroke) { - rleFree(shape->strokeRle); - strokeFree(shape->stroke); + if (shape.stroke) { + rleFree(shape.strokeRle); + strokeFree(shape.stroke); } - - free(shape); } @@ -585,7 +585,7 @@ void shapeDelStroke(SwShape& shape) } -void shapeResetStroke(SwShape& shape, const Shape& sdata) +void shapeResetStroke(SwShape& shape, const Shape* sdata) { if (!shape.stroke) shape.stroke = static_cast(calloc(1, sizeof(SwStroke))); auto stroke = shape.stroke; @@ -598,12 +598,14 @@ void shapeResetStroke(SwShape& shape, const Shape& sdata) } -bool shapeGenStrokeRle(SwShape& shape, const Shape& sdata, const SwSize& clip) +bool shapeGenStrokeRle(SwShape& shape, const Shape* sdata, const SwSize& clip) { + assert(sdata); + SwOutline* shapeOutline = nullptr; //Dash Style Stroke - if (sdata.strokeDash(nullptr) > 0) { + if (sdata->strokeDash(nullptr) > 0) { shapeOutline = _genDashOutline(sdata); if (!shapeOutline) return false; @@ -633,23 +635,18 @@ bool shapeGenStrokeRle(SwShape& shape, const Shape& sdata, const SwSize& clip) } -bool shapeGenFillColors(SwShape& shape, const Fill* fill, const RenderTransform* transform, bool ctable) +bool shapeGenFillColors(SwShape& shape, const Fill* fill, const Matrix* transform, bool ctable) { - assert(fill); - - fillGenColorTable(shape.fill, fill, transform, ctable); - return true; + return fillGenColorTable(shape.fill, fill, transform, ctable); } -void shapeResetFill(SwShape& shape, const Fill* fill) +void shapeResetFill(SwShape& shape) { - assert(fill); - if (!shape.fill) shape.fill = static_cast(calloc(1, sizeof(SwFill))); assert(shape.fill); - fillReset(shape.fill, fill); + fillReset(shape.fill); } diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index 94a2537..6ccfb7d 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -816,13 +816,15 @@ void strokeFree(SwStroke* stroke) } -void strokeReset(SwStroke& stroke, const Shape& shape) +void strokeReset(SwStroke& stroke, const Shape* sdata) { - stroke.width = TO_SWCOORD(shape.strokeWidth() * 0.5); - stroke.cap = shape.strokeCap(); + assert(sdata); + + stroke.width = TO_SWCOORD(sdata->strokeWidth() * 0.5); + stroke.cap = sdata->strokeCap(); //Save line join: it can be temporarily changed when stroking curves... - stroke.joinSaved = stroke.join = shape.strokeJoin(); + stroke.joinSaved = stroke.join = sdata->strokeJoin(); stroke.borders[0].ptsCnt = 0; stroke.borders[0].start = -1; diff --git a/src/lib/tvgCanvasImpl.h b/src/lib/tvgCanvasImpl.h index 42cf470..ae0ce3c 100644 --- a/src/lib/tvgCanvasImpl.h +++ b/src/lib/tvgCanvasImpl.h @@ -42,7 +42,7 @@ struct Canvas::Impl Result push(unique_ptr paint) { auto p = paint.release(); - assert(p); + if (!p) return Result::MemoryCorruption; paints.push_back(p); return update(p); @@ -50,7 +50,7 @@ struct Canvas::Impl Result clear() { - assert(renderer); + if (!renderer) return Result::InsufficientCondition; for (auto paint : paints) { if (paint->id() == PAINT_ID_SCENE) { @@ -70,7 +70,7 @@ struct Canvas::Impl Result update() { - assert(renderer); + if (!renderer) return Result::InsufficientCondition; for(auto paint: paints) { if (paint->id() == PAINT_ID_SCENE) { @@ -87,7 +87,7 @@ struct Canvas::Impl Result update(Paint* paint) { - assert(renderer); + if (!renderer) return Result::InsufficientCondition; if (paint->id() == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. @@ -102,7 +102,7 @@ struct Canvas::Impl Result draw() { - assert(renderer); + if (!renderer) return Result::InsufficientCondition; //Clear render target before drawing if (!renderer->clear()) return Result::InsufficientCondition; diff --git a/src/meson.build b/src/meson.build index e49c9a0..b5000bc 100644 --- a/src/meson.build +++ b/src/meson.build @@ -5,10 +5,11 @@ subdir('loaders') subdir('examples') m_dep = meson.get_compiler('cpp').find_library('m') +thread_dep = meson.get_compiler('cpp').find_library('pthread') egl_dep = meson.get_compiler('cpp').find_library('EGL') gles_dep = meson.get_compiler('cpp').find_library('GLESv2') -tizenvg_lib_dep = [ src_dep, swengine_dep, glengine_dep, m_dep, egl_dep, gles_dep, svgloader_dep] +tizenvg_lib_dep = [ src_dep, swengine_dep, glengine_dep, m_dep, egl_dep, gles_dep, svgloader_dep, thread_dep] tizenvg_lib = library( diff --git a/test/testBlending.cpp b/test/testBlending.cpp index a5559d4..ebb3e67 100644 --- a/test/testBlending.cpp +++ b/test/testBlending.cpp @@ -66,8 +66,7 @@ void tvgtest() tvg::Initializer::term(tvg::CanvasEngine::Sw); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } diff --git a/test/testBoundary.cpp b/test/testBoundary.cpp index 701bb84..a71374a 100644 --- a/test/testBoundary.cpp +++ b/test/testBoundary.cpp @@ -56,8 +56,7 @@ void tvgtest() tvg::Initializer::term(tvg::CanvasEngine::Sw); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } diff --git a/test/testCustomTransform.cpp b/test/testCustomTransform.cpp index ae3d7c8..cc0c8bb 100644 --- a/test/testCustomTransform.cpp +++ b/test/testCustomTransform.cpp @@ -96,8 +96,7 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } diff --git a/test/testGlShape.cpp b/test/testGlShape.cpp index 3ff4a33..8ad43ae 100644 --- a/test/testGlShape.cpp +++ b/test/testGlShape.cpp @@ -9,8 +9,7 @@ using namespace std; static Evas_GL_API *glapi; static unique_ptr canvas; -static void -tvgtest() +void tvgtest() { //Create a Canvas canvas = tvg::GlCanvas::gen(); @@ -33,8 +32,7 @@ tvgtest() canvas->push(move(shape1)); } -static void -init_gl(Evas_Object *obj) +void init_gl(Evas_Object *obj) { //Initialize TizenVG Engine tvg::Initializer::init(tvg::CanvasEngine::Gl); @@ -42,15 +40,13 @@ init_gl(Evas_Object *obj) tvgtest(); } -static void -del_gl(Evas_Object *obj) +void del_gl(Evas_Object *obj) { //Terminate TizenVG Engine tvg::Initializer::term(tvg::CanvasEngine::Gl); } -static void -draw_gl(Evas_Object *obj) +void draw_gl(Evas_Object *obj) { Evas_GL_API *gl = elm_glview_gl_api_get(obj); int w, h; @@ -66,8 +62,7 @@ draw_gl(Evas_Object *obj) canvas->sync(); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } diff --git a/test/testGradientTransform.cpp b/test/testGradientTransform.cpp index 90fab16..428acc5 100644 --- a/test/testGradientTransform.cpp +++ b/test/testGradientTransform.cpp @@ -126,8 +126,7 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } diff --git a/test/testLinearGradient.cpp b/test/testLinearGradient.cpp index decf263..8016a45 100644 --- a/test/testLinearGradient.cpp +++ b/test/testLinearGradient.cpp @@ -84,8 +84,7 @@ void tvgtest() tvg::Initializer::term(tvg::CanvasEngine::Sw); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } diff --git a/test/testMultiShapes.cpp b/test/testMultiShapes.cpp index e6db3bb..9fff6f0 100644 --- a/test/testMultiShapes.cpp +++ b/test/testMultiShapes.cpp @@ -44,8 +44,7 @@ void tvgtest() tvg::Initializer::term(tvg::CanvasEngine::Sw); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } diff --git a/test/testPath.cpp b/test/testPath.cpp index 3d52003..efb784f 100644 --- a/test/testPath.cpp +++ b/test/testPath.cpp @@ -59,8 +59,7 @@ void tvgtest() tvg::Initializer::term(tvg::CanvasEngine::Sw); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } diff --git a/test/testPathCopy.cpp b/test/testPathCopy.cpp index 8ce33c3..4ba5941 100644 --- a/test/testPathCopy.cpp +++ b/test/testPathCopy.cpp @@ -99,8 +99,7 @@ void tvgtest() tvg::Initializer::term(tvg::CanvasEngine::Sw); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } diff --git a/test/testRadialGradient.cpp b/test/testRadialGradient.cpp index b50204b..e10be47 100644 --- a/test/testRadialGradient.cpp +++ b/test/testRadialGradient.cpp @@ -84,8 +84,7 @@ void tvgtest() tvg::Initializer::term(tvg::CanvasEngine::Sw); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } diff --git a/test/testScene.cpp b/test/testScene.cpp index e134237..db6fd53 100644 --- a/test/testScene.cpp +++ b/test/testScene.cpp @@ -90,8 +90,7 @@ void tvgtest() tvg::Initializer::term(tvg::CanvasEngine::Sw); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } diff --git a/test/testSceneTransform.cpp b/test/testSceneTransform.cpp index 11dade0..1e411fe 100644 --- a/test/testSceneTransform.cpp +++ b/test/testSceneTransform.cpp @@ -120,8 +120,7 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } diff --git a/test/testShape.cpp b/test/testShape.cpp index 16fc1a0..4cc1f7f 100644 --- a/test/testShape.cpp +++ b/test/testShape.cpp @@ -38,8 +38,7 @@ void tvgtest() tvg::Initializer::term(tvg::CanvasEngine::Sw); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } diff --git a/test/testStress.cpp b/test/testStress.cpp index 2c1020e..870742e 100644 --- a/test/testStress.cpp +++ b/test/testStress.cpp @@ -3,12 +3,14 @@ using namespace std; -#define WIDTH 800 -#define HEIGHT 800 +#define WIDTH 1920 +#define HEIGHT 1080 #define COUNT 50 static uint32_t buffer[WIDTH * HEIGHT]; unique_ptr canvas = nullptr; +static double t1, t2, t3, t4; +static unsigned cnt = 0; void tvgtest() { @@ -19,20 +21,18 @@ void tvgtest() Eina_Bool anim_cb(void *data) { - static unsigned cnt = 0; - //Explicitly clear all retained paint nodes. - double t1 = ecore_time_get(); + t1 = ecore_time_get(); canvas->clear(); - double t2 = ecore_time_get(); + t2 = ecore_time_get(); for (int i = 0; i < COUNT; i++) { auto shape = tvg::Shape::gen(); - float x = rand() % 400; - float y = rand() % 400; - float w = 1 + rand() % 600; - float h = 1 + rand() % 600; + float x = rand() % (WIDTH/2); + float y = rand() % (HEIGHT/2); + float w = 1 + rand() % 1200; + float h = 1 + rand() % 800; shape->appendRect(x, y, w, h, rand() % 400); @@ -61,25 +61,28 @@ Eina_Bool anim_cb(void *data) canvas->push(move(shape)); } - double t3 = ecore_time_get(); + //Update Efl Canvas + Eo* img = (Eo*) data; + evas_object_image_pixels_dirty_set(img, EINA_TRUE); + evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); + + return ECORE_CALLBACK_RENEW; +} + +void render_cb(void* data, Eo* obj) +{ + t3 = ecore_time_get(); //Draw Next frames canvas->draw(); canvas->sync(); - double t4 = ecore_time_get(); - - printf("[%5d]: total[%fms] = clear[%fms] + update[%fms] + render[%fms]\n", ++cnt, t4 - t1, t2 - t1, t3 - t2, t4 - t3); + t4 = ecore_time_get(); - //Update Efl Canvas - Eo* img = (Eo*) data; - evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); - - return ECORE_CALLBACK_RENEW; + printf("[%5d]: total[%fms] = clear[%fms], update[%fms], render[%fms]\n", ++cnt, t4 - t1, t2 - t1, t3 - t2, t4 - t3); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } @@ -100,6 +103,7 @@ int main(int argc, char **argv) Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); evas_object_image_size_set(img, WIDTH, HEIGHT); evas_object_image_data_set(img, buffer); + evas_object_image_pixels_get_callback_set(img, render_cb, nullptr); evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_show(img); diff --git a/test/testStroke.cpp b/test/testStroke.cpp index a7ae5d0..68bffa2 100644 --- a/test/testStroke.cpp +++ b/test/testStroke.cpp @@ -83,13 +83,11 @@ void tvgtest() tvg::Initializer::term(tvg::CanvasEngine::Sw); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } - int main(int argc, char **argv) { tvgtest(); diff --git a/test/testStrokeLine.cpp b/test/testStrokeLine.cpp index 61e035e..3b6cc9d 100644 --- a/test/testStrokeLine.cpp +++ b/test/testStrokeLine.cpp @@ -119,8 +119,7 @@ void tvgtest() tvg::Initializer::term(tvg::CanvasEngine::Sw); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } diff --git a/test/testSvg.cpp b/test/testSvg.cpp index e918902..cad2f1b 100644 --- a/test/testSvg.cpp +++ b/test/testSvg.cpp @@ -29,8 +29,7 @@ void tvgtest() tvg::Initializer::term(tvg::CanvasEngine::Sw); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } diff --git a/test/testTransform.cpp b/test/testTransform.cpp index a99708d..5222743 100644 --- a/test/testTransform.cpp +++ b/test/testTransform.cpp @@ -89,8 +89,7 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } diff --git a/test/testUpdate.cpp b/test/testUpdate.cpp index 0ee9412..7111b21 100644 --- a/test/testUpdate.cpp +++ b/test/testUpdate.cpp @@ -50,8 +50,7 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); } -void -win_del(void *data, Evas_Object *o, void *ev) +void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } -- 2.7.4 From 4156de72f1cedc5aa01d41f5a9a5686ec5dcd662 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 24 Jun 2020 17:10:50 +0900 Subject: [PATCH 14/16] sw_engine: optimize rasterizey by threading it. Also, newly introduced render interfaces: preRender(), postRender(), flush() Change-Id: If506fa27e3c7dbd89f6734cad4774c1d151b88aa --- inc/tizenvg.h | 5 +- src/lib/gl_engine/tvgGlRenderer.cpp | 20 +++++++- src/lib/gl_engine/tvgGlRenderer.h | 4 +- src/lib/sw_engine/tvgSwCommon.h | 12 ----- src/lib/sw_engine/tvgSwRenderer.cpp | 95 ++++++++++++++++++++++++++++++------- src/lib/sw_engine/tvgSwRenderer.h | 25 ++++++++-- src/lib/sw_engine/tvgSwShape.cpp | 2 + src/lib/tvgCanvas.cpp | 11 +++++ src/lib/tvgCanvasImpl.h | 9 +++- src/lib/tvgGlCanvas.cpp | 10 ---- src/lib/tvgRender.h | 3 ++ src/lib/tvgSwCanvas.cpp | 7 +-- test/testStress.cpp | 21 +++++--- 13 files changed, 162 insertions(+), 62 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index a7eede4..a9e797f 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -153,7 +153,7 @@ public: virtual Result update() noexcept; virtual Result update(Paint* paint) noexcept; virtual Result draw(bool async = true) noexcept; - virtual Result sync() = 0; + virtual Result sync() noexcept; _TVG_DECLARE_ACCESSOR(Scene); _TVG_DECLARE_PRIVATE(Canvas); @@ -315,7 +315,6 @@ public: ~SwCanvas(); Result target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept; - Result sync() noexcept override; static std::unique_ptr gen() noexcept; @@ -337,9 +336,7 @@ public: ~GlCanvas(); //TODO: Gl Specific methods. Need gl backend configuration methods as well. - Result target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept; - Result sync() noexcept override; static std::unique_ptr gen() noexcept; diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index ecabf6a..bef3871 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -53,10 +53,28 @@ bool GlRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t } -void GlRenderer::flush() +bool GlRenderer::flush() { GL_CHECK(glFinish()); mColorProgram->unload(); + + return true; +} + + +bool GlRenderer::preRender() +{ + //TODO: called just before render() + + return true; +} + + +bool GlRenderer::postRender() +{ + //TODO: called just after render() + + return true; } diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h index 5214a63..7d0972a 100644 --- a/src/lib/gl_engine/tvgGlRenderer.h +++ b/src/lib/gl_engine/tvgGlRenderer.h @@ -28,9 +28,11 @@ public: void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) override; bool dispose(const Shape& shape, void *data) override; + bool preRender() override; bool render(const Shape& shape, void *data) override; + bool postRender() override; bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h); - void flush(); + bool flush() override; bool clear() override; uint32_t ref() override; uint32_t unref() override; diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 9c54088..72fa700 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -17,8 +17,6 @@ #ifndef _TVG_SW_COMMON_H_ #define _TVG_SW_COMMON_H_ -#include -#include #include "tvgCommon.h" #if 0 @@ -203,16 +201,6 @@ struct SwShape }; -struct SwTask -{ - SwShape shape; - const Shape* sdata; - SwSize clip; - const Matrix* transform; - RenderUpdateFlag flags; - future prepared; -}; - static inline SwPoint TO_SWPOINT(const Point* pt) { return {SwCoord(pt->x * 64), SwCoord(pt->y * 64)}; diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 8c59029..2458cdb 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -17,6 +17,8 @@ #ifndef _TVG_SW_RENDERER_CPP_ #define _TVG_SW_RENDERER_CPP_ +using namespace std; + #include "tvgSwCommon.h" #include "tvgSwRenderer.h" @@ -24,19 +26,37 @@ /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ +namespace tvg { + struct SwTask + { + SwShape shape; + const Shape* sdata; + SwSize clip; + const Matrix* transform; + RenderUpdateFlag flags; + future progress; + }; +} static RenderInitializer renderInit; + /************************************************************************/ /* External Class Implementation */ /************************************************************************/ -bool SwRenderer::clear() +SwRenderer::~SwRenderer() { - return rasterClear(surface); + if (progress.valid()) progress.get(); } +bool SwRenderer::clear() +{ + if (progress.valid()) return false; + return true; +} + bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) { if (!buffer || stride == 0 || w == 0 || h == 0) return false; @@ -50,24 +70,64 @@ bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t } -bool SwRenderer::render(const Shape& sdata, void *data) +bool SwRenderer::preRender() { - auto task = static_cast(data); - if (!task) return false; + //before we start rendering, we should finish all preparing tasks + while (prepareTasks.size() > 0) { + auto task = prepareTasks.front(); + if (task->progress.valid()) task->progress.get(); + prepareTasks.pop(); + renderTasks.push(task); + } + return true; +} - if (task->prepared.valid()) task->prepared.get(); - uint8_t r, g, b, a; +bool SwRenderer::postRender() +{ + auto asyncTask = [](SwRenderer* renderer) { + renderer->doRender(); + }; - if (auto fill = sdata.fill()) { - rasterGradientShape(surface, task->shape, fill->id()); - } else { - sdata.fill(&r, &g, &b, &a); - if (a > 0) rasterSolidShape(surface, task->shape, r, g, b, a); + progress = async(launch::async, asyncTask, this); + + return true; +} + + +void SwRenderer::doRender() +{ + rasterClear(surface); + + while (renderTasks.size() > 0) { + auto task = renderTasks.front(); + uint8_t r, g, b, a; + if (auto fill = task->sdata->fill()) { + rasterGradientShape(surface, task->shape, fill->id()); + } else{ + task->sdata->fill(&r, &g, &b, &a); + if (a > 0) rasterSolidShape(surface, task->shape, r, g, b, a); + } + task->sdata->strokeColor(&r, &g, &b, &a); + if (a > 0) rasterStroke(surface, task->shape, r, g, b, a); + renderTasks.pop(); + } +} + + +bool SwRenderer::flush() +{ + if (progress.valid()) { + progress.get(); + return true; } + return false; +} + - sdata.strokeColor(&r, &g, &b, &a); - if (a > 0) rasterStroke(surface, task->shape, r, g, b, a); +bool SwRenderer::render(const Shape& sdata, void *data) +{ + //Do Nothing return true; } @@ -77,7 +137,7 @@ bool SwRenderer::dispose(const Shape& sdata, void *data) { auto task = static_cast(data); if (!task) return true; - if (task->prepared.valid()) task->prepared.wait(); + if (task->progress.valid()) task->progress.get(); shapeFree(task->shape); free(task); return true; @@ -93,7 +153,7 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* if (!task) return nullptr; } - if (flags == RenderUpdateFlag::None || task->prepared.valid()) return task; + if (flags == RenderUpdateFlag::None || task->progress.valid()) return task; task->sdata = &sdata; task->clip = {static_cast(surface.w), static_cast(surface.h)}; @@ -140,7 +200,8 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* shapeDelOutline(task->shape); }; - task->prepared = async((launch::async | launch::deferred), asyncTask, task); + prepareTasks.push(task); + task->progress = async((launch::async | launch::deferred), asyncTask, task); return task; } diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index 4a4fafd..3669d03 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -17,16 +17,26 @@ #ifndef _TVG_SW_RENDERER_H_ #define _TVG_SW_RENDERER_H_ +#include +#include +#include + +namespace tvg +{ + +struct SwTask; + class SwRenderer : public RenderMethod { public: - Surface surface; - void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) override; bool dispose(const Shape& shape, void *data) override; + bool preRender() override; bool render(const Shape& shape, void *data) override; + bool postRender() override; bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h); bool clear() override; + bool flush() override; uint32_t ref() override; uint32_t unref() override; @@ -34,9 +44,18 @@ public: static int init(); static int term(); + void doRender(); //Internally used for threading + private: + Surface surface; + future progress; + queue prepareTasks; + queue renderTasks; + SwRenderer(){}; - ~SwRenderer(){}; + ~SwRenderer(); }; +} + #endif /* _TVG_SW_RENDERER_H_ */ diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index d9a4e81..9a79c6e 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -568,6 +568,8 @@ void shapeFree(SwShape& shape) shapeDelOutline(shape); rleFree(shape.rle); + shapeDelFill(shape); + if (shape.stroke) { rleFree(shape.strokeRle); strokeFree(shape.stroke); diff --git a/src/lib/tvgCanvas.cpp b/src/lib/tvgCanvas.cpp index dc05d66..01fcae1 100644 --- a/src/lib/tvgCanvas.cpp +++ b/src/lib/tvgCanvas.cpp @@ -82,4 +82,15 @@ Result Canvas::update(Paint* paint) noexcept return impl->update(paint); } + +Result Canvas::sync() noexcept +{ + auto impl = pImpl.get(); + if (!impl) return Result::MemoryCorruption; + + if (impl->renderer->flush()) return Result::Success; + + return Result::InsufficientCondition; +} + #endif /* _TVG_CANVAS_CPP_ */ diff --git a/src/lib/tvgCanvasImpl.h b/src/lib/tvgCanvasImpl.h index ae0ce3c..94737c9 100644 --- a/src/lib/tvgCanvasImpl.h +++ b/src/lib/tvgCanvasImpl.h @@ -52,6 +52,9 @@ struct Canvas::Impl { if (!renderer) return Result::InsufficientCondition; + //Clear render target before drawing + if (!renderer->clear()) return Result::InsufficientCondition; + for (auto paint : paints) { if (paint->id() == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. @@ -104,8 +107,7 @@ struct Canvas::Impl { if (!renderer) return Result::InsufficientCondition; - //Clear render target before drawing - if (!renderer->clear()) return Result::InsufficientCondition; + if (!renderer->preRender()) return Result::InsufficientCondition; for(auto paint: paints) { if (paint->id() == PAINT_ID_SCENE) { @@ -117,6 +119,9 @@ struct Canvas::Impl if(!SHAPE_IMPL->render(*shape, *renderer)) return Result::InsufficientCondition; } } + + if (!renderer->postRender()) return Result::InsufficientCondition; + return Result::Success; } }; diff --git a/src/lib/tvgGlCanvas.cpp b/src/lib/tvgGlCanvas.cpp index 80a0017..1af7eac 100644 --- a/src/lib/tvgGlCanvas.cpp +++ b/src/lib/tvgGlCanvas.cpp @@ -57,16 +57,6 @@ Result GlCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t } -Result GlCanvas::sync() noexcept -{ - auto renderer = dynamic_cast(Canvas::pImpl.get()->renderer); - assert(renderer); - - renderer->flush(); - return Result::Success; -} - - unique_ptr GlCanvas::gen() noexcept { auto canvas = unique_ptr(new GlCanvas); diff --git a/src/lib/tvgRender.h b/src/lib/tvgRender.h index 8e9a50f..b0a3c84 100644 --- a/src/lib/tvgRender.h +++ b/src/lib/tvgRender.h @@ -53,8 +53,11 @@ public: virtual ~RenderMethod() {} virtual void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) = 0; virtual bool dispose(const Shape& shape, void *data) = 0; + virtual bool preRender() = 0; virtual bool render(const Shape& shape, void *data) = 0; + virtual bool postRender() = 0; virtual bool clear() = 0; + virtual bool flush() = 0; virtual uint32_t ref() = 0; virtual uint32_t unref() = 0; }; diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index 780e463..a0bfdd0 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -45,6 +45,7 @@ SwCanvas::~SwCanvas() { } + Result SwCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept { //We know renderer type, avoid dynamic_cast for performance. @@ -57,12 +58,6 @@ Result SwCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t } -Result SwCanvas::sync() noexcept -{ - return Result::Success; -} - - unique_ptr SwCanvas::gen() noexcept { auto canvas = unique_ptr(new SwCanvas); diff --git a/test/testStress.cpp b/test/testStress.cpp index 870742e..f500078 100644 --- a/test/testStress.cpp +++ b/test/testStress.cpp @@ -21,9 +21,17 @@ void tvgtest() Eina_Bool anim_cb(void *data) { + auto t = ecore_time_get(); + //Explicitly clear all retained paint nodes. - t1 = ecore_time_get(); - canvas->clear(); + if (canvas->clear() != tvg::Result::Success) + { + //Probably, you missed sync() call before. + return ECORE_CALLBACK_RENEW; + } + + t1 = t; + t2 = ecore_time_get(); for (int i = 0; i < COUNT; i++) { @@ -61,6 +69,11 @@ Eina_Bool anim_cb(void *data) canvas->push(move(shape)); } + t3 = ecore_time_get(); + + //Draw Next frames + canvas->draw(); + //Update Efl Canvas Eo* img = (Eo*) data; evas_object_image_pixels_dirty_set(img, EINA_TRUE); @@ -71,10 +84,6 @@ Eina_Bool anim_cb(void *data) void render_cb(void* data, Eo* obj) { - t3 = ecore_time_get(); - - //Draw Next frames - canvas->draw(); canvas->sync(); t4 = ecore_time_get(); -- 2.7.4 From 28485d4b9c8eb0891b592f06c51abafc22e96ac0 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 24 Jun 2020 20:14:46 +0900 Subject: [PATCH 15/16] test: revise async(stress) test code. Change-Id: I2005f12cc9552b4a98101ba53f48b04c9a6c5732 --- .gitignore | 2 +- test/makefile | 2 +- test/{testStress.cpp => testAsync.cpp} | 41 +++++++++++++--------------------- 3 files changed, 18 insertions(+), 27 deletions(-) rename test/{testStress.cpp => testAsync.cpp} (70%) diff --git a/.gitignore b/.gitignore index c8da1b2..f6c52c5 100644 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,4 @@ testRadialGradient testGradientTransform testSvg testGlShape -testStress +testAsync diff --git a/test/makefile b/test/makefile index 9f77648..870c3bb 100644 --- a/test/makefile +++ b/test/makefile @@ -18,4 +18,4 @@ all: gcc -o testGradientTransform testGradientTransform.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testSvg testSvg.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testGlShape testGlShape.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` - gcc -o testStress testStress.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` + gcc -o testAsync testAsync.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` diff --git a/test/testStress.cpp b/test/testAsync.cpp similarity index 70% rename from test/testStress.cpp rename to test/testAsync.cpp index f500078..4d042dc 100644 --- a/test/testStress.cpp +++ b/test/testAsync.cpp @@ -26,12 +26,11 @@ Eina_Bool anim_cb(void *data) //Explicitly clear all retained paint nodes. if (canvas->clear() != tvg::Result::Success) { - //Probably, you missed sync() call before. + //Logically wrong! Probably, you missed to call sync() before. return ECORE_CALLBACK_RENEW; } t1 = t; - t2 = ecore_time_get(); for (int i = 0; i < COUNT; i++) { @@ -44,34 +43,25 @@ Eina_Bool anim_cb(void *data) shape->appendRect(x, y, w, h, rand() % 400); - if (rand() % 2) { - //LinearGradient - auto fill = tvg::LinearGradient::gen(); - fill->linear(x, y, x + w, y + h); - - //Gradient Color Stops - tvg::Fill::ColorStop colorStops[3]; - colorStops[0] = {0, uint8_t(rand() % 255), uint8_t(rand() % 255), uint8_t(rand() % 255), 255}; - colorStops[1] = {1, uint8_t(rand() % 255), uint8_t(rand() % 255), uint8_t(rand() % 255), 255}; - colorStops[2] = {2, uint8_t(rand() % 255), uint8_t(rand() % 255), uint8_t(rand() % 255), 255}; - - fill->colorStops(colorStops, 3); - shape->fill(move(fill)); - } else { - shape->fill(uint8_t(rand() % 255), uint8_t(rand() % 255), uint8_t(rand() % 255), 255); - } -#if 0 - if (rand() % 2) { - shape->stroke(float(rand() % 10)); - shape->stroke(uint8_t(rand() % 255), uint8_t(rand() % 255), uint8_t(rand() % 255), 255); - } -#endif + //LinearGradient + auto fill = tvg::LinearGradient::gen(); + fill->linear(x, y, x + w, y + h); + + //Gradient Color Stops + tvg::Fill::ColorStop colorStops[3]; + colorStops[0] = {0, uint8_t(rand() % 255), uint8_t(rand() % 255), uint8_t(rand() % 255), 255}; + colorStops[1] = {1, uint8_t(rand() % 255), uint8_t(rand() % 255), uint8_t(rand() % 255), 255}; + colorStops[2] = {2, uint8_t(rand() % 255), uint8_t(rand() % 255), uint8_t(rand() % 255), 255}; + + fill->colorStops(colorStops, 3); + shape->fill(move(fill)); + canvas->push(move(shape)); } t3 = ecore_time_get(); - //Draw Next frames + //Drawing task can be performed asynchronously. canvas->draw(); //Update Efl Canvas @@ -84,6 +74,7 @@ Eina_Bool anim_cb(void *data) void render_cb(void* data, Eo* obj) { + //Make it guarantee finishing drawing task. canvas->sync(); t4 = ecore_time_get(); -- 2.7.4 From ad5f147c747a2e737d7502b89d484dd87c4c1a40 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 24 Jun 2020 21:00:43 +0900 Subject: [PATCH 16/16] sw_engine: fix a regression bug. this matrix data is volatile since it's coming from stack memory. thus engine should record its own memory space for keeping it. Change-Id: I664dd56412f4d236ad04c312220c67da226274e5 --- src/lib/sw_engine/tvgSwRenderer.cpp | 13 ++++++++++--- src/lib/sw_engine/tvgSwShape.cpp | 2 -- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 2458cdb..ac5464e 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -32,7 +32,7 @@ namespace tvg { SwShape shape; const Shape* sdata; SwSize clip; - const Matrix* transform; + Matrix* transform; RenderUpdateFlag flags; future progress; }; @@ -139,6 +139,7 @@ bool SwRenderer::dispose(const Shape& sdata, void *data) if (!task) return true; if (task->progress.valid()) task->progress.get(); shapeFree(task->shape); + if (task->transform) free(task->transform); free(task); return true; } @@ -158,8 +159,14 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* task->sdata = &sdata; task->clip = {static_cast(surface.w), static_cast(surface.h)}; - if (transform) task->transform = &transform->m; - else task->transform = nullptr; + if (transform) { + if (!task->transform) task->transform = static_cast(malloc(sizeof(Matrix))); + assert(task->transform); + *task->transform = transform->m; + } else { + if (task->transform) free(task->transform); + task->transform = nullptr; + } task->flags = flags; diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 9a79c6e..29ecf27 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -201,7 +201,6 @@ static bool _updateBBox(SwOutline* outline, SwBBox& bbox) ++pt; for(uint32_t i = 1; i < outline->ptsCnt; ++i, ++pt) { - assert(pt); if (xMin > pt->x) xMin = pt->x; if (xMax < pt->x) xMax = pt->x; if (yMin > pt->y) yMin = pt->y; @@ -567,7 +566,6 @@ void shapeFree(SwShape& shape) { shapeDelOutline(shape); rleFree(shape.rle); - shapeDelFill(shape); if (shape.stroke) { -- 2.7.4