File 0001-replace-osmesa-with-EGL_PLATFORM_SURFACELESS_MESA.patch of Package horizon
From 1e4923283e5b99b2442bf494f9d1bc2683d40f1f Mon Sep 17 00:00:00 2001
From: "Lukas K." <lu@0x83.eu>
Date: Mon, 9 Jun 2025 12:50:26 +0200
Subject: [PATCH 1/2] replace osmesa with EGL_PLATFORM_SURFACELESS_MESA
fixes #809
---
.github/workflows/all.yml | 4 +-
meson.build | 9 ++-
src/export_3d_image/export_3d_image.cpp | 82 ++++++++++++++++++-------
src/export_3d_image/export_3d_image.hpp | 5 +-
src/util/gl_inc.h | 6 --
5 files changed, 68 insertions(+), 38 deletions(-)
diff --git a/.github/workflows/all.yml b/.github/workflows/all.yml
index 3888de2c..9b1fb324 100644
--- a/.github/workflows/all.yml
+++ b/.github/workflows/all.yml
@@ -37,7 +37,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Install dependencies
- run: apt-get update -y && apt-get install git build-essential libsqlite3-dev util-linux librsvg2-dev libcairomm-1.0-dev libepoxy-dev libgtkmm-3.0-dev uuid-dev libzmq5 libzmq3-dev libglm-dev libgit2-dev libcurl4-gnutls-dev libocct-data-exchange-dev libocct-draw-dev occt-misc libpodofo-dev python3-dev libarchive-dev git libosmesa6-dev cmake meson -y
+ run: apt-get update -y && apt-get install git build-essential libsqlite3-dev util-linux librsvg2-dev libcairomm-1.0-dev libepoxy-dev libgtkmm-3.0-dev uuid-dev libzmq5 libzmq3-dev libglm-dev libgit2-dev libcurl4-gnutls-dev libocct-data-exchange-dev libocct-draw-dev occt-misc libpodofo-dev python3-dev libarchive-dev git cmake meson -y
- name: Build
run: |
mkdir ../build
@@ -90,7 +90,7 @@ jobs:
run: apt-get install git build-essential ${{ matrix.os.cxx }} libsqlite3-dev util-linux librsvg2-dev libcairomm-1.0-dev libepoxy-dev libgtkmm-3.0-dev uuid-dev libzmq5 libzmq3-dev libglm-dev libgit2-dev libcurl4-gnutls-dev libpodofo-dev python3-dev libarchive-dev git libspnav-dev meson cmake libocct-data-exchange-dev libocct-draw-dev occt-misc -y
- name: Install python dependencies
if: ${{ matrix.target == 'horizon.so' }}
- run: apt-get install python3-cairo-dev libosmesa6-dev python3-yaml -y
+ run: apt-get install python3-cairo-dev python3-yaml -y
- name: Build
run: |
mkdir ../build
diff --git a/meson.build b/meson.build
index c438f9c8..9fec796f 100644
--- a/meson.build
+++ b/meson.build
@@ -48,7 +48,6 @@ endif
libpython = dependency('python3', required: false, disabler:true)
py3cairo = dependency('py3cairo', required: false, disabler:true)
-osmesa = dependency('osmesa', required: false, disabler:true)
glm = dependency('glm')
cpp_args_router = ['-D_USE_MATH_DEFINES']
@@ -105,7 +104,7 @@ endif
build_dependencies_libhorizon = [libm, pthread, gtkmm, sqlite3, png] + stdlibs
-build_dependencies_horizonmodule = [libm, gtkmm, sqlite3, png, py3cairo, podofo, libpython, osmesa, opencascade, libarchive]
+build_dependencies_horizonmodule = [libm, gtkmm, sqlite3, png, py3cairo, podofo, libpython, epoxy, opencascade, libarchive]
if not is_windows
uuid = dependency('uuid')
build_dependencies_libhorizon += uuid
@@ -116,7 +115,7 @@ endif
build_dependencies_libhorizonui = build_dependencies_libhorizon + [epoxy, zeromq, cppzmq, curl, glm]
build_dependencies_gen_pkg = build_dependencies_libhorizon
-build_dependencies_pr_review = build_dependencies_libhorizon + [podofo, osmesa, opencascade, libgit2]
+build_dependencies_pr_review = build_dependencies_libhorizon + [podofo, epoxy, opencascade, libgit2]
build_dependencies_pool_prj_mgr = build_dependencies_libhorizonui + [libgit2]
build_dependencies_imp = build_dependencies_libhorizonui +[rsvg, podofo, libarchive, opencascade, spnav]
@@ -1002,7 +1001,7 @@ horizon_py = shared_module('horizon',
dependencies: build_dependencies_horizonmodule,
link_with: [clipper_pic, delaunator_pic, polypartition_pic, poly2tri_pic],
include_directories: include_directories,
- cpp_args: cpp_args + ['-DOFFSCREEN=1'],
+ cpp_args: cpp_args,
build_by_default: false,
name_prefix: ''
)
@@ -1012,7 +1011,7 @@ horizon_pr_review = executable('horizon-pr-review',
dependencies: build_dependencies_pr_review,
link_with: [clipper_nopic, delaunator_nopic, polypartition_nopic, poly2tri_nopic, libhorizon],
include_directories: include_directories,
- cpp_args: cpp_args + ['-DOFFSCREEN=1'],
+ cpp_args: cpp_args,
build_by_default: false,
)
diff --git a/src/export_3d_image/export_3d_image.cpp b/src/export_3d_image/export_3d_image.cpp
index 8f307980..7410ed81 100644
--- a/src/export_3d_image/export_3d_image.cpp
+++ b/src/export_3d_image/export_3d_image.cpp
@@ -1,7 +1,7 @@
#include "export_3d_image.hpp"
#include "canvas3d/canvas3d_base.hpp"
-#include "GL/osmesa.h"
#include <cairomm/cairomm.h>
+#include <epoxy/egl.h>
namespace horizon {
@@ -11,28 +11,59 @@ Image3DExporter::Image3DExporter(const class Board &abrd, class IPool &apool, un
width = awidth;
height = aheight;
- {
- std::vector<int> attribs;
- attribs.push_back(OSMESA_DEPTH_BITS);
- attribs.push_back(16);
+ // based on
+ // https://code.videolan.org/videolan/libplacebo/-/blob/00a1009a78434bbc43a1efc54f5915dd466706a4/src/tests/opengl_surfaceless.c#L98
+ const char *extstr = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
+ if (!extstr || !strstr(extstr, "EGL_MESA_platform_surfaceless"))
+ throw std::runtime_error("no EGL_MESA_platform_surfaceless");
- attribs.push_back(OSMESA_PROFILE);
- attribs.push_back(OSMESA_CORE_PROFILE);
+ dpy = eglGetPlatformDisplayEXT(EGL_PLATFORM_SURFACELESS_MESA, (void *)EGL_DEFAULT_DISPLAY, NULL);
+ if (!dpy)
+ throw std::runtime_error("no dpy");
- attribs.push_back(OSMESA_CONTEXT_MAJOR_VERSION);
- attribs.push_back(3);
+ EGLint major, minor;
+ if (!eglInitialize(dpy, &major, &minor))
+ throw std::runtime_error("error in eglInitialize");
+
+ // clang-format off
+ const int cfg_attribs[] = {
+ EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
+ EGL_ALPHA_SIZE, 8,
+ EGL_NONE
+ };
+ // clang-format on
+
+ EGLConfig config = 0;
+ EGLint num_configs = 0;
+ bool ok = eglChooseConfig(dpy, cfg_attribs, &config, 1, &num_configs);
+ if (!ok || !num_configs)
+ throw std::runtime_error("error in eglChooseConfig");
+
+ if (!eglBindAPI(EGL_OPENGL_API))
+ throw std::runtime_error("error in eglBindAPI");
+
+ // clang-format off
+ const int egl_attribs[] = {
+ EGL_CONTEXT_MAJOR_VERSION, 4,
+ EGL_CONTEXT_MINOR_VERSION, 6,
+ EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
+ EGL_NONE
+ };
+ // clang-format on
+
+ egl = eglCreateContext(dpy, config, EGL_NO_CONTEXT, egl_attribs);
+ if (!egl)
+ throw std::runtime_error("no context");
+
+
+ const EGLint pbuffer_attribs[] = {EGL_WIDTH, width, EGL_HEIGHT, height, EGL_NONE};
+
+ surf = eglCreatePbufferSurface(dpy, config, pbuffer_attribs);
+
+ if (!eglMakeCurrent(dpy, surf, surf, egl))
+ throw std::runtime_error("error in eglMakeCurrent");
- attribs.push_back(0);
- attribs.push_back(0);
- ctx = OSMesaCreateContextAttribs(attribs.data(), NULL);
- }
- if (!ctx) {
- throw std::runtime_error("couldn't create context");
- }
- buffer.resize(width * height * 4);
- if (!OSMesaMakeCurrent(static_cast<OSMesaContext>(ctx), buffer.data(), GL_UNSIGNED_BYTE, width, height)) {
- throw std::runtime_error("couldn't make current");
- }
a_realize();
brd = &abrd;
@@ -43,7 +74,7 @@ Image3DExporter::Image3DExporter(const class Board &abrd, class IPool &apool, un
void Image3DExporter::check_ctx()
{
- if (ctx != OSMesaGetCurrentContext()) {
+ if (egl != eglGetCurrentContext()) {
throw std::runtime_error("lost context");
}
}
@@ -68,7 +99,10 @@ Cairo::RefPtr<Cairo::Surface> Image3DExporter::render_to_surface()
render(render_background ? RenderBackground::YES : RenderBackground::NO);
glFinish();
- auto buf = buffer.data();
+ glReadBuffer(GL_COLOR_ATTACHMENT0);
+ std::vector<uint8_t> buf(width * height * 4);
+ glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buf.data());
+
unsigned int iwidth = width;
unsigned int iheight = height;
auto surf = Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, iwidth, iheight);
@@ -90,6 +124,8 @@ Cairo::RefPtr<Cairo::Surface> Image3DExporter::render_to_surface()
Image3DExporter::~Image3DExporter()
{
- OSMesaDestroyContext(static_cast<OSMesaContext>(ctx));
+ eglDestroySurface(dpy, surf);
+ eglDestroyContext(dpy, egl);
+ eglTerminate(dpy);
}
} // namespace horizon
diff --git a/src/export_3d_image/export_3d_image.hpp b/src/export_3d_image/export_3d_image.hpp
index 69910a1d..9ab4269c 100644
--- a/src/export_3d_image/export_3d_image.hpp
+++ b/src/export_3d_image/export_3d_image.hpp
@@ -25,8 +25,9 @@ public:
private:
class IPool &pool;
- void *ctx = nullptr; // to get around including osmesa here
- std::vector<unsigned char> buffer;
+ void *egl = nullptr; // to get around including epoxy here
+ void *dpy = nullptr; // to get around including epoxy here
+ void *surf = nullptr; // to get around including epoxy here
void check_ctx();
bool render_background = false;
};
diff --git a/src/util/gl_inc.h b/src/util/gl_inc.h
index 9a98f746..ffe72303 100644
--- a/src/util/gl_inc.h
+++ b/src/util/gl_inc.h
@@ -1,9 +1,3 @@
#pragma once
-#ifndef OFFSCREEN
#include <epoxy/gl.h>
-#else
-#define GL_GLEXT_PROTOTYPES 1
-#include <GL/gl.h>
-#include <GL/glcorearb.h>
-#endif
--
2.49.0