Commit graph

46 commits

Author SHA1 Message Date
Sergii Liebodkin
47b9866f8b wg_engine: cross-platform support
it provide changes public API for webgpu canvas interface to provide nessessary handles to native window for different platforms:

API Change:
- Result target(void *instance, void *surface, uint32_t w, uint32_t h) noexcept;
2024-06-24 14:50:28 +09:00
Hermet Park
7e83590ec5 wg_engine: resolve gcc compiler warnings.
virtual functions and accessible non-virtual destructor [-Wnon-virtual-dtor]
2024-06-24 14:45:26 +09:00
Hermet Park
4b4514a8b0 wg_engine: add the wgpu_native library dependency.
about the wgpu-native please visit:
https://github.com/gfx-rs/wgpu-native/releases
2024-06-24 14:45:19 +09:00
Sergii Liebodkin
eadf66e178 wg_engine: fix color buffer corruption with wgpu-opengl wrapper (linux)
In a case of usage stencil buffer only we need to turn off an color target writes. In other case color buffer fill be filled by unxepcted color if fragment shader did not return any value.
It happens in a case on OpenGL realization of webgpu, that used in linux

Befire:

After:
2024-06-24 14:37:15 +09:00
Sergii Liebodkin
9c8b10603e wg_engine: Fill Rule winding optimization
[issues 1479: Fill Rule](#1479)

In this solution we dont need to find silhouette, that is not a cheep operation (decreasing performance in 2 times)

For winding, you can select separate operations for front and back faces (increment for front, decrement for back)
After rendering the fan, the value in the stencil buffer will be the winding number. You can fill the appropriate portion by rendering a screen-sized quad with stencil testing enabled and the stencil function set according to which winding rule you wish to use.

For even-odd, you don't need to distinguish front and back faces; you can just use INVERT as the operation.
2024-06-24 14:30:39 +09:00
Hermet Park
5b3a045f15 renderer/engines: added mainSurface() interface.
This interface expects the main surface of the raster engine.
2024-06-24 14:19:43 +09:00
Sergii Liebodkin
09751f63cd wg_engine: Text support
[issues 1479: Text](#1479)

EvenOdd fill rule reorganized: using global bbox of whole path for fill
2024-06-24 14:19:34 +09:00
Hermet Park
a3fe9c25f2 wg_engine: code refactoring
Use the override specifier so that
a compiler could warn any human mistake.
2024-06-24 14:14:02 +09:00
Sergii Liebodkin
ddc6fc7f0b wg_engine: blending and composition optimization
[issues 1479: Masking, InvMasking, LumaMasking, InvLumaMasking](#1479)

Computes composition and blending using simgle pass istead of two full screen passes
2024-06-24 12:24:53 +09:00
Sergii Liebodkin
642fd77a3a wg_engine: update mesh generations and render mechanics
[issues 1479: lottie](#1479)

- optimaze stroking algorithm by prevent vector normalizations
- using render meshes heaps to reduce webgpu instances re-creations
- using single instance of pilylines for standard operations such as trim and split
- "on-the-fly" strokes generations with dash pattern
- "on-the-fly" mesh objects generation in a process of path decoding
- merge strokes into single mesh by each shape
2024-06-24 12:21:10 +09:00
Sergii Liebodkin
f73f3c8b53 wg_engine: added preallocated index buffers for triangle fans
[issues 1479: lottie](#1479)
2024-06-24 12:21:10 +09:00
Sergii Liebodkin
cebf723076 wg_engine: added math and polyline structures for geometry generating optimizations
[issues 1479: lottie](#1479)
2024-06-24 12:21:10 +09:00
Sergii Liebodkin
366c1be6bd wg_engine: vertex, index and unifroms buffers, render objects caching
[issues 1479: lottie](#1479)

Vertex, Index and uniform buffers now updates instead of recreate.
Implemented pools form mesh objects and render shapes data

it increase performance in 30-40% in massive animations scenes
2024-04-07 15:15:59 +09:00
Sergii Liebodkin
7d8a261a83 wg_engine: Blending optimization
[issues 1479: lottie](#1479)

To optimize bled operations hardware pipeline blend stage are used for some blend methods:
	BlendMethod::SrcOver
    BlendMethod::Normal
    BlendMethod::Add
    BlendMethod::Multiply
    BlendMethod::Darken
    BlendMethod::Lighten

Other types compute shaders used
2024-04-06 12:48:30 +09:00
Sergii Liebodkin
4f204b5e13 wg_engine: Lottie extensions
[issues 1479: LottieExtensions](#1479)

LottieExtensions example supports
Supports multiple color stops for gradient fill (redial and linear)
2024-04-06 12:48:30 +09:00
Sergii Liebodkin
fafec9fa46 wg_engine: render buffers usage refactorings
[issues 1479: strokes](#1479)

- update buffers via memory mapping
- refactoring of winding fill rule computation
2024-04-06 12:08:23 +09:00
Sergii Liebodkin
98b30c72ef wg_engine: stroke trim
[issues 1479: strokes](#1479)

Introduced stroke trim setting

left: (0, 0.95)
middle: (0.15, 1)
right: (0.15, 0.95)
2024-04-06 12:08:23 +09:00
vtorri
3640724b99 [common] code clean up
use MATH_PI and MATH_PI2 instead of M_PI and M_PI_2
2024-04-06 12:08:23 +09:00
Sergii Liebodkin
4d2440cc70 wg_engine: stroke first
[issues 1479: strokes](#1479)

Introduced order setting

    auto star = tvg::Shape::gen();
    star->fill(80, 80, 80);
    star->moveTo(599, 34);
    star->lineTo(653, 143);
    star->lineTo(774, 160);
    star->lineTo(687, 244);
    star->lineTo(707, 365);
    star->lineTo(599, 309);
    star->lineTo(497, 365);
    star->lineTo(512, 245);
    star->lineTo(426, 161);
    star->lineTo(546, 143);
    star->close();
    star->strokeWidth(10);
    star->strokeJoin(tvg::StrokeJoin::Round);
    star->strokeFill(255, 255, 255);
    star->order(true); // stroke first
    if (canvas->push(std::move(star)) != tvg::Result::Success) return;
2024-04-06 12:08:22 +09:00
Sergii Liebodkin
203cd4cd60 wg_engine: winding fill rule
[issues 1479: FillRule](#1479)

Introduced fill rule winding
This rule makes sense only if path have some self intersections.
In all other cases shapes are filled by even-odd behavor.
2024-04-06 12:08:21 +09:00
Sergii Liebodkin
80d454e2d6 wg_engine: fill spread
[issues 1479: LinearGradient, RadialGradient](#1479)

Introduced fill spreads: Pad, Reflect, Repeat

Pad:

Reflect:

Repeat:
2024-04-06 12:08:21 +09:00
Sergii Liebodkin
850e6ef466 wg_engine: antialiasing
[issues 1479: antialiasing](#1479)

Anti-aliasing implementation
Implements antialiasing as a post process on cimpute shaders and original render target with scale of 2x.
Can be modified as an external settings
2024-04-06 12:08:21 +09:00
Sergii Liebodkin
345753a397 wg_engine: meson script fixed
[issues 1991: Basic steps to compile for linux (wg_beta, examples)](#1991)
2024-04-06 12:08:21 +09:00
Sergii Liebodkin
081f276f21 wg_engine: animation optimizations (part 1)
[issues 1479: update](#1479)

gpu vertex buffer reallocations optimization
2024-04-06 12:08:21 +09:00
Sergii Liebodkin
8f3b822f18 wg_engine: clenup shader sources
Remove unused composition/blending shader sources
2024-04-05 17:48:22 +09:00
Hermet Park
6df111bc23 renderer: code refactoring.
removed unnused return value.
2024-04-05 17:46:54 +09:00
Sergii Liebodkin
9e0cc0298c wg_engine: introduced blending
[issues 1479: blending](#1479)

Supported blend settings:

    Normal
    Add
    Screen
    Multiply
    Overlay
    Difference
    Exclusion
    SrcOver
    Darken
    Lighten
    ColorDodge
    ColorBurn
    HardLight
    SoftLight
2024-04-05 17:41:44 +09:00
Sergii Liebodkin
84d3ef7184 wg_engine: introduced compute pipeline entities
introduces posibility to create compute pipelines
does not affect functionality
2024-04-05 17:37:49 +09:00
Sergii Liebodkin
96e0794a67 wg_engine: introduced scene opacity
[issues 1479: opacity](#1479)

Supported opacity value for scene

Usage example:

    //Create a Scene
    auto scene = tvg::Scene::gen();
    scene->opacity(100);

    //Prepare Circle
    auto shape1 = tvg::Shape::gen();
    shape1->appendCircle(400, 400, 250, 250);
    shape1->fill(255, 255, 0);
    shape1->opacity(100);
    scene->push(std::move(shape1));

    //Round rectangle
    auto shape2 = tvg::Shape::gen();
    shape2->appendRect(450, 100, 200, 200, 50, 50);
    shape2->fill(0, 255, 0);
    shape2->strokeWidth(10);
    shape2->strokeFill(255, 255, 255);
    scene->push(std::move(shape2));

    canvas->push(std::move(scene));
2024-04-05 17:28:34 +09:00
Sergii Liebodkin
af6969e15e wg_engine: introduced composition ability
[issues 1479: Masking](#1479)

Supported composition methods:

    AlphaMask
    InvAlphaMask
    LumaMask
    InvLumaMask
    AddMask
    SubtractMask
    IntersectMask
    DifferenceMask

Usage example:

    //Solid Rectangle
    auto shape = tvg::Shape::gen();
    shape->appendRect(0, 0, 400, 400);
    shape->fill(0, 0, 255);

    //Mask
    auto mask = tvg::Shape::gen();
    mask->appendCircle(200, 200, 125, 125);
    mask->fill(255, 255, 255);        //AlphaMask RGB channels are unused.

    //Nested Mask
    auto nMask = tvg::Shape::gen();
    nMask->appendCircle(220, 220, 125, 125);
    nMask->fill(255, 255, 255);       //AlphaMask RGB channels are unused.

    mask->composite(std::move(nMask), tvg::CompositeMethod::AlphaMask);
    shape->composite(std::move(mask), tvg::CompositeMethod::AlphaMask);
    canvas->push(std::move(shape));

    //Star
    auto star = tvg::Shape::gen();
    star->fill(80, 80, 80);
    star->moveTo(599, 34);
    star->lineTo(653, 143);
    star->lineTo(774, 160);
    star->lineTo(687, 244);
    star->lineTo(707, 365);
    star->lineTo(599, 309);
    star->lineTo(497, 365);
    star->lineTo(512, 245);
    star->lineTo(426, 161);
    star->lineTo(546, 143);
    star->close();
    star->strokeWidth(30);
    star->strokeJoin(tvg::StrokeJoin::Miter);
    star->strokeFill(255, 255, 255);

    //Mask3
    auto mask3 = tvg::Shape::gen();
    mask3->appendCircle(600, 200, 125, 125);
    mask3->fill(255, 255, 255);       //AlphaMask RGB channels are unused.
    mask3->opacity(200);
    star->composite(std::move(mask3), tvg::CompositeMethod::AlphaMask);
    if (canvas->push(std::move(star)) != tvg::Result::Success) return;
2024-04-05 17:28:08 +09:00
Hermet Park
38c625d070 renderer: enhanced shared surface handling with mutex implementation
Introduced a dedicated mutex for each surface instance
to ensure safe sharing between the loader, renderer, and engine.

This enhancement allows for secure modification and access to bitmap data,
addressing potential concurrency issues.

Multiple Picture instances can now safely share a single loader instance,
optimizing performance.

This change builds upon the previous Loader Cache improvements:
ff6ea4b6c4
2024-01-02 20:34:12 +09:00
Jinny You
92288c8291 updated copyright date (#1866) 2024-01-02 20:34:12 +09:00
Sergii Liebodkin
5ba19a8a7f wg_engine: shape bbox based rendering (optimization)
Before the current changes, all surfaces were painted using a full-screen overlay, no matter how large the object was rendered. This approach is redundant and required reorganization. At the moment, all objects are rendered using an overlay equal to the box of the object itself, which reduces the cost of filling the surface.
Also surfaces and images were divided into different entities, which reduces the pressure on memory.
Also geometry data for rendering and geometry data for calculations in system memory were logically separated.
2024-01-02 20:34:11 +09:00
Sergii Liebodkin
4164b36c8a wg_engine: Added shape opacity value usage
[issues 1479: Opacity](#1479)

Usage example:

    // prepare a shape (Rectangle + Rectangle + Circle + Circle) with opacity
    auto shape1 = tvg::Shape::gen();
    shape1->appendRect(0, 0, 200, 200);                //x, y, w, h
    shape1->appendRect(100, 100, 300, 300, 100, 100);  //x, y, w, h, rx, ry
    shape1->appendCircle(400, 400, 100, 100);          //cx, cy, radiusW, radiusH
    shape1->appendCircle(400, 500, 170, 100);          //cx, cy, radiusW, radiusH
    shape1->fill(255, 255, 0);                         //r, g, b
    shape1->opacity(128)                               //opacity
    canvas->push(std::move(shape1));
2024-01-02 20:34:11 +09:00
Sergii Liebodkin
003464b7e5 wg_engine: refactor context handles
New approach provide:
- instance, adaptor, device and default queue
- device capabilitieas
- command buffer executor
- error handling
2024-01-02 20:34:11 +09:00
Sergii Liebodkin
e797cf63f4 wg_engine: refactor render targets handling
For further development of features, we need to create off-screen buffers that will allow us to implement functionality related to composition and blending, as well as for loading data to system memory from the framebuffer. Separating the framebuffer into a separate entity allows you to create several instances of them, switch between them, and blend them according to given rules.

For current time we have only a single render target instance, that have a handle to drawing into surface surface, like a native window.

New approach allows:
- offscreen rendering
- render pass handling
- switching between render targets
- ability to render images, strokes and shapes into independent render targets
2024-01-02 20:34:11 +09:00
Hermet Park
a6378fc673 wg_engine: apply tvg coding style. 2024-01-02 20:34:11 +09:00
Sergii Liebodkin
9742cfe293 wg_engine: pipelines and bind groups refactoring
- shader and system types synchronized
- pipelens and bind groups description separated
- pipelines description simplified
2024-01-02 20:34:11 +09:00
Sergii Liebodkin
51e98eebdb Add support for textures color space formats
[Issues 1479: pictures](https://github.com/thorvg/thorvg/issues/1479)

Formats supported:
    ABGR8888
    ARGB8888
    ABGR8888S
    ARGB8888S
2024-01-02 20:34:10 +09:00
Sergii Liebodkin
c5b642e3e7 wg_engine: introduced images drawing support
[issues 1479: pictures](https://github.com/thorvg/thorvg/issues/1479)

    auto picture = tvg::Picture::gen();
    picture->load("images/test.png");
    picture->translate(0, 0);
    picture->size(100, 100);
    picture->opacity(255);
    canvas->push(std::move(picture));
2023-12-26 18:36:45 +09:00
Sergii Liebodkin
bad02c7de0 Added ability to draw solid strokes with dashes
[issues 1479: Shape](https://github.com/thorvg/thorvg/issues/1479)

In order to build you need third party libraries. Before you start please read this: [LearnWebGPU](https://eliemichel.github.io/LearnWebGPU/getting-started/hello-webgpu.html)

Usage example:

    // init glfw
    glfwInit();

    // create a windowed mode window and its opengl context
    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
    GLFWwindow* window = glfwCreateWindow(800, 800, "WebGPU base app", nullptr, nullptr);

    // get window size
    int width{}, height{};
    glfwGetWindowSize(window, &width, &height);

    // init engine webgpu
    tvg::Initializer::init(tvg::CanvasEngine::Wg, 0);

    // create wg canvas
    auto canvasWg = tvg::WgCanvas::gen();
    canvas_wg->target(glfwGetWin32Window(window), width, height);

    //Test for Stroke Dash for Arc, Circle, Rect
    auto shape = tvg::Shape::gen();
    shape->appendArc(70, 600, 160, 10, 30, true);
    shape->appendCircle(70, 700, 20, 60);
    shape->appendRect(130, 710, 100, 40);
    shape->strokeFill(255, 0, 0);
    shape->strokeWidth(5);
    shape->strokeJoin(tvg::StrokeJoin::Round);
    shape->strokeCap(tvg::StrokeCap::Round);
    float dashPattern[2] = {20, 10};
    shape->strokeDash(dashPattern, 2);
    if (canvas_wg->push(std::move(shape)) != tvg::Result::Success) return;

    while (!glfwWindowShouldClose(window)) {
        // webgpu
        canvas_wg->draw();
        canvas_wg->sync();

        // pull events
        glfwPollEvents();
    }

    // terminate engine and window
    tvg::Initializer::term(tvg::CanvasEngine::Wg);
    glfwDestroyWindow(window);
    glfwTerminate();
2023-12-26 18:18:48 +09:00
Sergii Liebodkin
41ea198a5e Added ability to draw solid strokes
[issues 1479: Shape](https://github.com/thorvg/thorvg/issues/1479)

In order to build you need third party libraries. Before you start please read this: [LearnWebGPU](https://eliemichel.github.io/LearnWebGPU/getting-started/hello-webgpu.html)

Usage example:

    // init glfw
    glfwInit();

    // create a windowed mode window and its opengl context
    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
    GLFWwindow* window = glfwCreateWindow(800, 800, "WebGPU base app", nullptr, nullptr);

    // get window size
    int width{}, height{};
    glfwGetWindowSize(window, &width, &height);

    // init engine webgpu
    tvg::Initializer::init(tvg::CanvasEngine::Wg, 0);

    // create wg canvas
    auto canvasWg = tvg::WgCanvas::gen();
    canvas_wg->target(glfwGetWin32Window(window), width, height);

    //Test for Stroke Dash for Arc, Circle, Rect
    auto shape = tvg::Shape::gen();
    shape->appendArc(70, 600, 160, 10, 30, true);
    shape->appendCircle(70, 700, 20, 60);
    shape->appendRect(130, 710, 100, 40);
    shape->strokeFill(255, 0, 0);
    shape->strokeWidth(5);
    shape->strokeJoin(tvg::StrokeJoin::Round);
    shape->strokeCap(tvg::StrokeCap::Round);
    if (canvas_wg->push(std::move(shape)) != tvg::Result::Success) return;

    while (!glfwWindowShouldClose(window)) {
        // webgpu
        canvas_wg->draw();
        canvas_wg->sync();

        // pull events
        glfwPollEvents();
    }

    // terminate engine and window
    tvg::Initializer::term(tvg::CanvasEngine::Wg);
    glfwDestroyWindow(window);
    glfwTerminate();
2023-12-26 18:18:42 +09:00
SergeyLebedkin
4f0fbc459c wg_engine: Added a feature to draw multiple radial gradient filled shapes 2023-12-26 17:51:59 +09:00
Sergii Liebodkin
db1f171d2a wg_engine: Added ability to draw multiple linear gradient filled shapes
[issues 1479: LinearGradient](thorvg#1479)

In order to build you need third party libraries. Before you start please read this: [LearnWebGPU](https://eliemichel.github.io/LearnWebGPU/getting-started/hello-webgpu.html)

Usage example:

    // init glfw
    glfwInit();

    // create a windowed mode window and its opengl context
    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
    GLFWwindow* window = glfwCreateWindow(800, 800, "WebGPU base app", nullptr, nullptr);

    // get window size
    int width{}, height{};
    glfwGetWindowSize(window, &width, &height);

    // init engine webgpu
    tvg::Initializer::init(tvg::CanvasEngine::Wg, 0);

    // create wg canvas
    auto canvasWg = tvg::WgCanvas::gen();
    canvas_wg->target(glfwGetWin32Window(window), width, height);

    // gradient color stops
    tvg::Fill::ColorStop colorStops[2];
    colorStops[0] = {0, 0, 0, 0, 255};
    colorStops[1] = {1, 255, 255, 255, 255};
    // linear gradient
    auto fill = tvg::LinearGradient::gen();
    fill->linear(0, 0, 400, 400);
    fill->colorStops(colorStops, 2);
    // prepare rectangle
    auto shape1 = tvg::Shape::gen();
    shape1->appendRect(0, 0, 400, 400); //x, y, w, h
    shape1->fill(std::move(fill));
    canvas_wg->push(std::move(shape1));

    // gradient color stops
    tvg::Fill::ColorStop colorStops2[3];
    colorStops2[0] = { 0, 255, 0, 0, 255 };
    colorStops2[1] = { 0.5, 255, 255, 0, 255 };
    colorStops2[2] = { 1, 255, 255, 255, 255 };
    // linear gradient
    auto fill2 = tvg::LinearGradient::gen();
    fill2->linear(400, 200, 400, 600);
    fill2->colorStops(colorStops2, 3);
    // prepare circle
    auto shape2 = tvg::Shape::gen();
    shape2->appendCircle(400, 400, 200, 200); //cx, cy, radiusW, radiusH
    shape2->fill(std::move(fill2));
    canvas_wg->push(std::move(shape2));

    // gradient color stops
    tvg::Fill::ColorStop colorStops3[4];
    colorStops3[0] = { 0, 0, 127, 0, 127 };
    colorStops3[1] = { 0.25, 0, 170, 170, 170 };
    colorStops3[2] = { 0.5, 200, 0, 200, 200 };
    colorStops3[3] = { 1, 255, 255, 255, 255 };
    // linear gradient
    auto fill3 = tvg::LinearGradient::gen();
    fill3->linear(450, 600, 750, 600);
    fill3->colorStops(colorStops3, 4);
    // prepare ellipse
    auto shape3 = tvg::Shape::gen();
    shape3->appendCircle(600, 600, 150, 100); //cx, cy, radiusW, radiusH
    shape3->fill(std::move(fill3));
    canvas_wg->push(std::move(shape3));

    while (!glfwWindowShouldClose(window)) {
        // webgpu
        canvas_wg->draw();
        canvas_wg->sync();

        // pull events
        glfwPollEvents();
    }

    // terminate engine and window
    tvg::Initializer::term(tvg::CanvasEngine::Wg);
    glfwDestroyWindow(window);
    glfwTerminate();
2023-12-26 17:51:39 +09:00
Sergii Liebodkin
938b69688d wg_engine: Added ability to draw multiple solid color filled shapes
[issues 1479: Shape](https://github.com/thorvg/thorvg/issues/1479)

In order to build you need third party libraries. Before you start please read this: [LearnWebGPU](https://eliemichel.github.io/LearnWebGPU/getting-started/hello-webgpu.html)

Usage example:

    // init glfw
    glfwInit();

    // create a windowed mode window and its opengl context
    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
    GLFWwindow* window = glfwCreateWindow(800, 800, "WebGPU base app", nullptr, nullptr);

    // get window size
    int width{}, height{};
    glfwGetWindowSize(window, &width, &height);

    // init engine webgpu
    tvg::Initializer::init(tvg::CanvasEngine::Wg, 0);

    // create wg canvas
    auto canvasWg = tvg::WgCanvas::gen();
    canvas_wg->target(glfwGetWin32Window(window), width, height);

    // prepare a shape (Rectangle + Rectangle + Circle + Circle)
    auto shape1 = tvg::Shape::gen();
    shape1->appendRect(0, 0, 200, 200);                //x, y, w, h
    shape1->appendRect(100, 100, 300, 300, 100, 100);  //x, y, w, h, rx, ry
    shape1->appendCircle(400, 400, 100, 100);          //cx, cy, radiusW, radiusH
    shape1->appendCircle(400, 500, 170, 100);          //cx, cy, radiusW, radiusH
    shape1->fill(255, 255, 0);                         //r, g, b

    canvas_wg->push(std::move(shape1));

    while (!glfwWindowShouldClose(window)) {
        // webgpu
        canvas_wg->draw();
        canvas_wg->sync();

        // pull events
        glfwPollEvents();
    }

    // terminate engine and window
    tvg::Initializer::term(tvg::CanvasEngine::Wg);
    glfwDestroyWindow(window);
    glfwTerminate();
2023-12-26 17:51:17 +09:00
SergeyLebedkin
35b03c826e wg_engine: introduce a webgpu canvas(engine)
WebGPU is a Render Hardware Interface built on top of the various APIs 
provided by the driver/OS depending on your platform. 

WebGPU exposes an API for performing operations, 
such as rendering and computation, on a Graphics Processing Unit.

WebGPU official documentation: https://www.w3.org/TR/webgpu/

The new engine type introduced: tvg::CanvasEngine::Wg

The new canvas type introduced: tvg::WgCanvas

Example:
$meson setup build -Dengines=wg_beta

`
    // init engine webgpu
    tvg::Initializer::init(tvg::CanvasEngine::Wg, 0);

    // create wg canvas
    auto canvasWg = tvg::WgCanvas::gen();
    canvas_wg->target(glfwGetWin32Window(window), width, height);

    // ...

    // terminate engine and window
    tvg::Initializer::term(tvg::CanvasEngine::Wg);
`
Still this feature is under the beta

Issue: https://github.com/thorvg/thorvg/issues/1479
2023-12-26 17:49:16 +09:00