diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 63e6fc79..6dddba34 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -125,10 +125,12 @@ jobs: CIBW_BEFORE_ALL: bash scripts/build_${{ runner.os }}.sh CIBW_BEFORE_BUILD: pip install pybind11 numpy CIBW_TEST_REQUIRES: pytest pillow glfw + CIBW_TEST_REQUIRES_LINUX: pytest pillow glfw moderngl CIBW_TEST_REQUIRES_MACOS: pytest pillow pyopengl CIBW_TEST_COMMAND: python -m pytest {project}/tests CIBW_TEST_COMMAND_LINUX: > xvfb-run -s "-screen 0 640x480x24" python -m pytest {project}/tests + CIBW_REPAIR_WHEEL_COMMAND_LINUX: "auditwheel repair --exclude libEGL.so.1 -w {dest_dir} {wheel}" CIBW_TEST_SKIP: "*-macosx_arm64" - uses: actions/upload-artifact@v4 @@ -190,10 +192,12 @@ jobs: CIBW_BEFORE_ALL: bash scripts/build_${{ runner.os }}.sh CIBW_BEFORE_BUILD: pip install pybind11 numpy CIBW_TEST_REQUIRES: pytest pillow glfw + CIBW_TEST_REQUIRES_LINUX: pytest pillow glfw moderngl CIBW_TEST_REQUIRES_MACOS: pytest pillow pyopengl CIBW_TEST_COMMAND: python -m pytest {project}/tests CIBW_TEST_COMMAND_LINUX: > xvfb-run -s "-screen 0 640x480x24" python -m pytest {project}/tests + CIBW_REPAIR_WHEEL_COMMAND_LINUX: "auditwheel repair --exclude libEGL.so.1 -w {dest_dir} {wheel}" CIBW_TEST_SKIP: "*-macosx_arm64" - uses: actions/upload-artifact@v4 @@ -248,3 +252,27 @@ jobs: path: dist - uses: pypa/gh-action-pypi-publish@release/v1 + + build_and_test_on_Fedora: + runs-on: ubuntu-24.04 + container: fedora:41 + permissions: write-all + steps: + - run: dnf install -y dnf-utils git gcc-c++ libstdc++-devel libstdc++-static + - run: dnf install -y python3-build python3-devel python3-pytest python3-pillow python3-glfw + - run: dnf install -y egl-utils glx-utils + - run: dnf install -y patch + - run: dnf install -y expat-devel fontconfig-devel + - run: dnf install -y libxml2-devel vulkan-headers + - uses: actions/checkout@v4 + with: + submodules: recursive + - run: bash scripts/build_Linux.sh + - run: python -m build --wheel + - run: python -m pip install dist/*.whl + - run: python -m pip install moderngl + - run: python -c 'import moderngl; moderngl_context = moderngl.create_standalone_context(backend="egl"); import skia; interface = skia.GrGLInterface.MakeEGL() ; assert isinstance(skia.GrDirectContext.MakeGL(interface), skia.GrContext) ; print("Success3")' + - run: eglinfo || /bin/true + - run: xvfb-run -s "-screen 0 640x480x24" glxinfo + # The below also run that 3 lines above but under X, but allows it to fail there. + - run: xvfb-run -s "-screen 0 640x480x24" pytest diff --git a/patch/0001-Fix-for-Werror-redundant-move-for-newer-g.patch b/patch/0001-Fix-for-Werror-redundant-move-for-newer-g.patch new file mode 100644 index 00000000..4c6d703b --- /dev/null +++ b/patch/0001-Fix-for-Werror-redundant-move-for-newer-g.patch @@ -0,0 +1,35 @@ +From b34a4e2f812e916f806f61412dc3f70f31a32fd0 Mon Sep 17 00:00:00 2001 +From: Hin-Tak Leung +Date: Fri, 27 Dec 2024 02:08:12 +0000 +Subject: [PATCH] Fix for -Werror=redundant-move for newer g++ + +Signed-off-by: Hin-Tak Leung +--- + src/gn/desc_builder.cc | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/gn/desc_builder.cc b/src/gn/desc_builder.cc +index 444a5e02..3ef170c3 100644 +--- a/src/gn/desc_builder.cc ++++ b/src/gn/desc_builder.cc +@@ -167,7 +167,7 @@ class BaseDescBuilder { + base::ListValue res; + for (const auto& v : vector) + res.GetList().emplace_back(ToBaseValue(v)); +- return std::move(res); ++ return res; + } + + base::Value ToBaseValue(const Scope* scope) { +@@ -176,7 +176,7 @@ class BaseDescBuilder { + scope->GetCurrentScopeValues(&map); + for (const auto& v : map) + res.SetKey(v.first, ToBaseValue(v.second)); +- return std::move(res); ++ return res; + } + + base::Value ToBaseValue(const Value& val) { +-- +2.47.1 + diff --git a/patch/skia-m132-egl-runtime.diff b/patch/skia-m132-egl-runtime.diff new file mode 100644 index 00000000..3f7c7b66 --- /dev/null +++ b/patch/skia-m132-egl-runtime.diff @@ -0,0 +1,42 @@ +If you use cibuildwheel (which uses auditwheel repair to bundle libraries) to build, +you must NOT use the bundled "libEGL-xxxxxxxx.so.A.B.C". Look at ldd's output: + + $ ldd skia.cpython-313-x86_64-linux-gnu.so | grep GL + libEGL-48f73270.so.1.1.0 => .../skia_python.libs/libEGL-48f73270.so.1.1.0 (0x00007fd03fd31000) + libGL.so.1 => /lib64/libGL.so.1 (0x00007fd03fc71000) + libGLdispatch-64b28464.so.0.0.0 => .../skia_python.libs/libGLdispatch-64b28464.so.0.0.0 (0x00007fd03fa69000) + libGLX.so.0 => /lib64/libGLX.so.0 (0x00007fd03f369000) + libGLdispatch.so.0 => /lib64/libGLdispatch.so.0 (0x00007fd03f189000) + +(The duplicate GLdispatch entry is indirect from libEGL) + +You need to undo the effect of "auditwheel repair ..." with something like this: + + patchelf --replace-needed libEGL-e42ac8e3.so.1.1.0 libEGL.so.1.1.0 ~/.local/lib/python3.13/site-packages/skia.*.so + +Then check that libEGL.so (and libGLdispatch.so) is looked up from system locations, +and not from python3.13/site-packages/skia_python.libs/ again: + + $ ldd ~/.local/lib/python3.13/site-packages/skia.cpython-313-x86_64-linux-gnu.so | grep GL + libEGL.so.1.1.0 => /lib64/libEGL.so.1.1.0 (0x00007f8d1ea39000) + libGL.so.1 => /lib64/libGL.so.1 (0x00007f8d1e9c1000) + libGLdispatch.so.0 => /lib64/libGLdispatch.so.0 (0x00007f8d1ca69000) + libGLX.so.0 => /lib64/libGLX.so.0 (0x00007f8d1c369000) + +diff --git a/BUILD.gn b/BUILD.gn +index 20f308b..ceac00c 100644 +--- a/BUILD.gn ++++ b/BUILD.gn +@@ -1003,10 +1003,11 @@ optional("gpu") { + sources += [ "src/gpu/ganesh/gl/webgl/GrGLMakeNativeInterface_webgl.cpp" ] + } else if (is_linux && skia_use_x11) { + sources += [ ++ "src/gpu/ganesh/gl/egl/GrGLMakeEGLInterface.cpp", + "src/gpu/ganesh/gl/glx/GrGLMakeGLXInterface.cpp", + "src/gpu/ganesh/gl/glx/GrGLMakeNativeInterface_glx.cpp", + ] +- libs += [ "GL" ] ++ libs += [ "EGL", "GL" ] + } else if (is_mac) { + sources += [ "src/gpu/ganesh/gl/mac/GrGLMakeNativeInterface_mac.cpp" ] + } else if (is_ios) { diff --git a/scripts/build_Linux.sh b/scripts/build_Linux.sh index dbc468fe..17fb54e6 100644 --- a/scripts/build_Linux.sh +++ b/scripts/build_Linux.sh @@ -16,6 +16,7 @@ if [[ $EUID -eq 0 ]]; then python3 \ fontconfig-devel \ mesa-libGL-devel \ + mesa-libEGL-devel libglvnd-devel mesa-libGLES-devel libglvnd mesa-libGLES mesa-libEGL libglvnd-egl \ xorg-x11-server-Xvfb \ mesa-dri-drivers && \ yum clean all && \ @@ -53,6 +54,7 @@ fi git clone https://gn.googlesource.com/gn && \ cd gn && \ git checkout fe330c0ae1ec29db30b6f830e50771a335e071fb && \ + if [[ -e "/etc/fedora-release" ]] ; then patch -p1 -i ../patch/0001-Fix-for-Werror-redundant-move-for-newer-g.patch ; fi && \ python3 build/gen.py && \ ninja -C out gn && \ cd .. @@ -61,6 +63,7 @@ git clone https://gn.googlesource.com/gn && \ cd skia && \ patch -p1 < ../patch/skia-m134-minimize-download.patch && \ patch -p1 < ../patch/skia-m132-colrv1-freetype.diff && \ + patch -p1 < ../patch/skia-m132-egl-runtime.diff && \ python3 tools/git-sync-deps && \ cp -f ../gn/out/gn bin/gn && \ bin/gn gen out/Release --args=" diff --git a/setup.py b/setup.py index b6329b8d..71b99473 100644 --- a/setup.py +++ b/setup.py @@ -97,6 +97,7 @@ LIBRARIES = [ 'dl', 'fontconfig', + 'EGL', 'GL', 'expat', ] diff --git a/src/skia/GrContext_gl.cpp b/src/skia/GrContext_gl.cpp index b0413997..8d20a2ca 100644 --- a/src/skia/GrContext_gl.cpp +++ b/src/skia/GrContext_gl.cpp @@ -1,6 +1,10 @@ #include "common.h" #include #include +#ifdef __linux__ +#include +#include +#endif void initGrContext_gl(py::module &m) { @@ -58,6 +62,12 @@ py::class_, SkRefCnt>( throw std::runtime_error("null pointer exception."); const GrGLInterface* ptr = interface.release(); return const_cast(ptr); - })); + })) + .def("validate", &GrGLInterface::validate) +#ifdef __linux__ + .def_static("MakeEGL", &GrGLInterfaces::MakeEGL) + .def_static("MakeGLX", &GrGLInterfaces::MakeGLX) +#endif + ; } diff --git a/tests/test_grcontext.py b/tests/test_grcontext.py index 107342c5..8784a6b9 100644 --- a/tests/test_grcontext.py +++ b/tests/test_grcontext.py @@ -540,10 +540,32 @@ def test_GrContext_ComputeImageSize(image): int) +# We want this to be followed by something that re-obtain the context +# as this one can fail, but making a broken context current. +def test_GrDirectContext_MakeGL_EGL(): + if not sys.platform.startswith("linux"): + pytest.skip("API on Linux only") + import moderngl + moderngl_context = moderngl.create_standalone_context(backend="egl") + interface = skia.GrGLInterface.MakeEGL() + import os + # The interface non-Null and validate tests don't fail under X! + if ((interface is None) or (not interface.validate())) and (os.getenv("DISPLAY") == True): + pytest.skip("Software-only X (Xvfb)") + assert isinstance(skia.GrDirectContext.MakeGL(interface), skia.GrContext) + + def test_GrDirectContext_MakeGL(context): assert isinstance(context, skia.GrContext) +# inherits the context from the last call +def test_GrDirectContext_MakeGL_GLX(): + if not sys.platform.startswith("linux"): + pytest.skip("API on Linux only") + assert isinstance(skia.GrDirectContext.MakeGL(skia.GrGLInterface.MakeGLX()), skia.GrContext) + + def test_GrDirectContext_MakeVulkan(): context = skia.GrVkBackendContext() options = skia.GrContextOptions()