From 4781749e3da496d4bbbe6ffd9fa883c5d6c940f5 Mon Sep 17 00:00:00 2001 From: Jay Shen Date: Wed, 7 Jan 2026 01:59:32 +0800 Subject: [PATCH] [NOT FOR MERGE] Combine GL context example and platform cleanup - Add context example to verify GL context switching - Remove support for macOS and X11 - Normalize EXAMPLE_DIR on Windows for Meson example build [NOT FOR MERGE] Add Meson GL backend option Introduce meson_options.txt to select GL vs GLES. Wire option in examples build to pull gl/gles+egl deps and set TVGEXAMPLE_GLES_SUPPORTED for GLES builds. Update GL context setup to use the new GLES define and prioritize EGL context handling when enabled. --- meson_options.txt | 5 ++ src/Example.h | 22 +++++++- src/MultiCanvas.cpp | 20 ++++++- src/context.cpp | 130 ++++++++++++++++++++++++++++++++++++++++++++ src/meson.build | 25 ++++++--- 5 files changed, 190 insertions(+), 12 deletions(-) create mode 100644 meson_options.txt create mode 100644 src/context.cpp diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000..6966579 --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,5 @@ +option('gl_backend', + type: 'combo', + choices: ['gl', 'gles'], + value: 'gl', + description: 'Select GL backend for examples (gl, gles)') diff --git a/src/Example.h b/src/Example.h index 2e692e7..2feacf4 100644 --- a/src/Example.h +++ b/src/Example.h @@ -30,6 +30,9 @@ #include #include #include +#ifdef TVGEXAMPLE_GLES_SUPPORTED + #include +#endif #ifdef _WIN32 #include #ifndef PATH_MAX @@ -395,8 +398,23 @@ struct GlWindow : Window void resize() override { - //Set the canvas target and draw on it. - verify(static_cast(canvas)->target(context, 0, width, height, tvg::ColorSpace::ABGR8888S)); + // Set the canvas target and draw on it. + SDL_GL_MakeCurrent(window, context); + +#if defined(TVGEXAMPLE_GLES_SUPPORTED) + // OpenGL ES via EGL + auto eglDisplay = eglGetCurrentDisplay(); + auto eglSurface = eglGetCurrentSurface(EGL_DRAW); + verify(static_cast(canvas)->target(eglDisplay, eglSurface, context, 0, width, height, tvg::ColorSpace::ABGR8888S)); +#elif defined(_WIN32) + SDL_SysWMinfo wmInfo; + SDL_VERSION(&wmInfo.version); + SDL_GetWindowWMInfo(window, &wmInfo); + auto hdc = GetDC(wmInfo.info.win.window); + verify(static_cast(canvas)->target(hdc, wmInfo.info.win.window, context, 0, width, height, tvg::ColorSpace::ABGR8888S)); +#else + verify(static_cast(canvas)->target(nullptr, nullptr, context, 0, width, height, tvg::ColorSpace::ABGR8888S)); +#endif } void refresh() override diff --git a/src/MultiCanvas.cpp b/src/MultiCanvas.cpp index 61e9142..7e9f52d 100644 --- a/src/MultiCanvas.cpp +++ b/src/MultiCanvas.cpp @@ -175,7 +175,8 @@ void runGl() { #ifdef THORVG_GL_RASTER_SUPPORT -#ifdef THORVG_GL_TARGET_GLES +#ifdef TVGEXAMPLE_GLES_SUPPORTED + SDL_SetHint(SDL_HINT_OPENGL_ES_DRIVER, "1"); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); @@ -187,6 +188,7 @@ void runGl() auto window = SDL_CreateWindow("ThorVG Example (OpenGL)", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WIDTH, HEIGHT, SDL_WINDOW_OPENGL | SDL_WINDOW_HIDDEN); auto context = SDL_GL_CreateContext(window); + SDL_GL_MakeCurrent(window, context); fglBindTexture = (PFNGLBINDTEXTUREEXTPROC)SDL_GL_GetProcAddress("glBindTexture"); fglDeleteTextures = (PFNGLDELETETEXTURESEXTPROC)SDL_GL_GetProcAddress("glDeleteTextures"); @@ -208,7 +210,19 @@ void runGl() auto canvas = unique_ptr(tvg::GlCanvas::gen()); // Pass the framebuffer id to the GlCanvas - tvgexam::verify(canvas->target(context, glFbo.fbo, SIZE, SIZE, tvg::ColorSpace::ABGR8888S)); +#if defined(TVGEXAMPLE_GLES_SUPPORTED) + auto eglDisplay = eglGetCurrentDisplay(); + auto eglSurface = eglGetCurrentSurface(EGL_DRAW); + tvgexam::verify(canvas->target(eglDisplay, eglSurface, context, glFbo.fbo, SIZE, SIZE, tvg::ColorSpace::ABGR8888S)); +#elif defined(_WIN32) + SDL_SysWMinfo wmInfo; + SDL_VERSION(&wmInfo.version); + SDL_GetWindowWMInfo(window, &wmInfo); + auto hdc = GetDC(wmInfo.info.win.window); + tvgexam::verify(canvas->target(hdc, wmInfo.info.win.window, context, glFbo.fbo, SIZE, SIZE, tvg::ColorSpace::ABGR8888S)); +#else + tvgexam::verify(canvas->target(nullptr, nullptr, context, glFbo.fbo, SIZE, SIZE, tvg::ColorSpace::ABGR8888S)); +#endif content(canvas.get()); if (tvgexam::verify(canvas->draw())) { @@ -416,4 +430,4 @@ int main(int argc, char **argv) } return 0; -} \ No newline at end of file +} diff --git a/src/context.cpp b/src/context.cpp new file mode 100644 index 0000000..6c77aa9 --- /dev/null +++ b/src/context.cpp @@ -0,0 +1,130 @@ +#include "Example.h" +#ifdef TVGEXAMPLE_GLES_SUPPORTED +#include +#else +#include +#endif +#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) +#include +static HDC gHdc = nullptr; +#endif + +static SDL_GLContext getCurrentContext() { +#if defined(TVGEXAMPLE_GLES_SUPPORTED) + auto fn = (SDL_GLContext(*)())SDL_GL_GetProcAddress("eglGetCurrentContext"); + return fn ? fn() : SDL_GL_GetCurrentContext(); +#elif defined(_WIN32) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) + return (SDL_GLContext)wglGetCurrentContext(); +#else + return SDL_GL_GetCurrentContext(); +#endif +} + +static bool makeCurrent(SDL_Window* win, SDL_GLContext ctx) { +#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) && !defined(TVGEXAMPLE_GLES_SUPPORTED) + if (!gHdc) { + SDL_SysWMinfo info; SDL_VERSION(&info.version); + if (SDL_GetWindowWMInfo(win, &info)) gHdc = GetDC(info.info.win.window); + } + return wglMakeCurrent(gHdc, (HGLRC)ctx); +#else + return SDL_GL_MakeCurrent(win, ctx) == 0; +#endif +} + +int main(int argc, char** argv) { + (void)argc; (void)argv; + if (!tvgexam::verify(tvg::Initializer::init(0))) return 0; + if (SDL_Init(SDL_INIT_VIDEO) != 0) { tvg::Initializer::term(); return 0; } + + uint32_t w = 800, h = 800; +#ifdef TVGEXAMPLE_GLES_SUPPORTED + SDL_SetHint(SDL_HINT_OPENGL_ES_DRIVER, "1"); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); +#else + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); +#endif + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + + auto window = SDL_CreateWindow("Context", SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, w, h, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN); + auto tvgCtx = window ? SDL_GL_CreateContext(window) : nullptr; + auto otherCtx = tvgCtx ? SDL_GL_CreateContext(window) : nullptr; + if (!otherCtx || !makeCurrent(window, tvgCtx)) { + if (otherCtx) SDL_GL_DeleteContext(otherCtx); + if (tvgCtx) SDL_GL_DeleteContext(tvgCtx); + if (window) SDL_DestroyWindow(window); + SDL_Quit(); tvg::Initializer::term(); + return 0; + } + +#if defined(TVGEXAMPLE_GLES_SUPPORTED) + auto targetCtx = getCurrentContext(); + void* display = eglGetCurrentDisplay(); + void* surface = eglGetCurrentSurface(EGL_DRAW); +#elif defined(_WIN32) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) + auto targetCtx = getCurrentContext(); + void* display = nullptr; + void* surface = gHdc; +#else + auto targetCtx = getCurrentContext(); + void* display = nullptr; + void* surface = nullptr; +#endif + auto canvas = tvg::GlCanvas::gen(); + if (!canvas || !tvgexam::verify(canvas->target(display, surface, targetCtx, 0, w, h, tvg::ColorSpace::ABGR8888S))) { + delete canvas; + SDL_GL_DeleteContext(otherCtx); SDL_GL_DeleteContext(tvgCtx); + SDL_DestroyWindow(window); SDL_Quit(); tvg::Initializer::term(); + return 0; + } + + auto ring = tvg::Shape::gen(); + ring->appendCircle(0, 0, 260, 260); + ring->fill(0, 0, 0, 0); + ring->strokeFill(255, 255, 255, 255); + ring->strokeWidth(8); + ring->translate(w * 0.5f, h * 0.5f); + canvas->push(ring); + + auto needle = tvg::Shape::gen(); + needle->appendRect(-8, -200, 16, 140); + needle->fill(255, 140, 0, 220); + needle->translate(w * 0.5f, h * 0.5f); + canvas->push(needle); + + canvas->draw(); canvas->sync(); + SDL_GL_SwapWindow(window); + makeCurrent(window, otherCtx); + + SDL_Event ev; + bool running = true; + auto t0 = SDL_GetTicks(); + while (running) { + while (SDL_PollEvent(&ev)) { + if (ev.type == SDL_QUIT) running = false; + if (ev.type == SDL_KEYUP && ev.key.keysym.sym == SDLK_ESCAPE) running = false; + } + makeCurrent(window, otherCtx); + float t = (SDL_GetTicks() - t0) * 0.001f; + glViewport(0, 0, w, h); + glDisable(GL_SCISSOR_TEST); + glClearColor(0.15f + 0.1f*sinf(t*0.9f), 0.18f + 0.1f*sinf(t*1.1f+2), 0.22f + 0.1f*sinf(t*1.3f+4), 1); + glClear(GL_COLOR_BUFFER_BIT); + + needle->rotate(t * 90); + canvas->update(); canvas->draw(false); canvas->sync(); + + if (getCurrentContext() != targetCtx) break; + SDL_GL_SwapWindow(window); + } + + delete canvas; + SDL_GL_DeleteContext(otherCtx); SDL_GL_DeleteContext(tvgCtx); + SDL_DestroyWindow(window); SDL_Quit(); tvg::Initializer::term(); + return 0; +} diff --git a/src/meson.build b/src/meson.build index 55e6242..f300651 100644 --- a/src/meson.build +++ b/src/meson.build @@ -4,16 +4,26 @@ examples_dep = [thorvg_dep, dependency('sdl2', required: true)] compiler_flags = ['-DSDL_MAIN_HANDLED'] # GL or GLES +gl_backend = get_option('gl_backend') gl_dep = dependency('gl', required: false) gles_dep = dependency('glesv2', required: false) +egl_dep = dependency('egl', required: false) -if gl_dep.found() - examples_dep += gl_dep -elif gles_dep.found() - examples_dep += gles_dep - compiler_flags += ['-DTVGEXAMPLE_GLES_SUPPORTED'] -else - message('Neither OpenGL nor OpenGL ES was found. Skipping GL examples.') +if gl_backend == 'gl' + if gl_dep.found() + examples_dep += gl_dep + compiler_flags += ['-DTHORVG_GL_RASTER_SUPPORT'] + else + message('Requested OpenGL but it was not found. Skipping GL examples.') + endif +elif gl_backend == 'gles' + if gles_dep.found() and egl_dep.found() + examples_dep += [gles_dep, egl_dep] + compiler_flags += ['-DTHORVG_GL_RASTER_SUPPORT'] + compiler_flags += ['-DTVGEXAMPLE_GLES_SUPPORTED'] + else + message('Requested OpenGL ES but it was not found. Skipping GL examples.') + endif endif # WebGPU @@ -37,6 +47,7 @@ source_file = [ 'Blending.cpp', 'BoundingBox.cpp', 'Clipping.cpp', + 'context.cpp', 'CustomTransform.cpp', 'DataLoad.cpp', 'DirectUpdate.cpp',