Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
51cdf69
Initial support of CGL.
najlkin May 28, 2025
f451a7b
Fixed compilation on Mac.
najlkin May 28, 2025
12808dd
Fixed a typo.
najlkin May 28, 2025
3c930dc
Silenced deprecation warning for CGL.
najlkin May 28, 2025
3e8637b
Added CGL build to CI on Mac.
najlkin May 28, 2025
1c8ddef
Merge branch 'egl-headless' into cgl-headless
najlkin May 28, 2025
152ff7c
Improved pixel format setup.
najlkin May 28, 2025
6142110
Fixed insertion of legacy flag.
najlkin May 28, 2025
3f18f22
Setup config
camierjs Oct 3, 2025
c1f5a0e
Fix CGL macos
camierjs Oct 5, 2025
1a998bb
Meld back to EGL fused with CGL
camierjs Oct 5, 2025
cf0af34
Remove CGL sub directory
camierjs Oct 5, 2025
938fbab
Cleanup
camierjs Oct 5, 2025
ace4319
Simplify
camierjs Oct 5, 2025
4701ced
Cleanup
camierjs Oct 5, 2025
c34e758
Revert cerr use
camierjs Oct 5, 2025
844e336
Cleanup and remove cmake user settings
camierjs Oct 5, 2025
fef7e06
Add GL_SILENCE_DEPRECATION and update INSTALL
camierjs Oct 5, 2025
7421750
Avoid unused variable 'status'
camierjs Oct 5, 2025
e873d0c
Address reviewers comments
camierjs Oct 6, 2025
e29e622
Merge pull request #345 from GLVis/cgl-headless-dbg
najlkin Oct 7, 2025
4977af2
Added error check to initGLEW().
najlkin Oct 7, 2025
0bf5c63
Fixed error reporting.
najlkin Oct 7, 2025
27263da
if GLEW_KHR_debug, enable GL_DEBUG_OUTPUT
camierjs Oct 7, 2025
8bbc29c
Made the GLEW_KHR_debug condition Mac specific.
najlkin Oct 7, 2025
a497eb0
Made CGL default on Mac.
najlkin Oct 7, 2025
5b54075
Updated INSTALL.
najlkin Oct 7, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .github/workflows/builds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,9 @@ jobs:
[[ ${{ matrix.target }} == "dbg" ]] && glvis_target="debug";
use_egl="NO"
[[ ${{ matrix.os }} == "ubuntu-latest" ]] && use_egl="YES"
cd glvis && make ${glvis_target} -j3 GLVIS_USE_EGL=${use_egl}
use_cgl="NO"
[[ ${{ matrix.os }} == "macos-latest" ]] && use_cgl="YES"
cd glvis && make ${glvis_target} -j3 GLVIS_USE_EGL=${use_egl} GLVIS_USE_CGL=${use_cgl}

- name: build GLVis (cmake)
if: matrix.build-system == 'cmake'
Expand All @@ -214,12 +216,15 @@ jobs:
&& toolchain_file="${VCPKG_INSTALLATION_ROOT}\\scripts\\buildsystems\\vcpkg.cmake"
use_egl="OFF"
[[ ${{ matrix.os }} == "ubuntu-latest" ]] && use_egl="ON"
use_cgl="NO"
[[ ${{ matrix.os }} == "macos-latest" ]] && use_cgl="YES"
cd glvis && mkdir build && cd build
cmake \
-D CMAKE_TOOLCHAIN_FILE:STRING=${toolchain_file} \
-D CMAKE_BUILD_TYPE:STRING=${build_type} \
-D ENABLE_TESTS:BOOL=TRUE \
-D GLVIS_USE_EGL:BOOL=${use_egl} \
-D GLVIS_USE_CGL:BOOL=${use_cgl} \
-D mfem_DIR:PATH=${GITHUB_WORKSPACE}/${MFEM_TOP_DIR}/build \
-D GLVIS_BASELINE_SYS=${{ matrix.os }} \
..
Expand Down
9 changes: 9 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ option(GLVIS_USE_EGL
"Use EGL for headless rendering"
OFF)

option(GLVIS_USE_CGL
"Use CGL for headless rendering"
APPLE)

#
# Handle a few other definitions
#
Expand Down Expand Up @@ -243,6 +247,11 @@ if (NOT EMSCRIPTEN)
endif (OpenGL_EGL_FOUND)
endif (GLVIS_USE_EGL)

# Find CGL
if (GLVIS_USE_CGL)
list(APPEND _glvis_compile_defs "GLVIS_USE_CGL")
endif (GLVIS_USE_CGL)

# Find threading library
find_package(Threads REQUIRED)
list(APPEND _glvis_libraries "${CMAKE_THREAD_LIBS_INIT}")
Expand Down
3 changes: 3 additions & 0 deletions INSTALL
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ Some important variables for CMake are:

- GLVIS_USE_EGL: Use EGL for headless rendering. Default is "OFF".

- GLVIS_USE_CGL: Use CGL for headless rendering on Mac OS X. Default is "ON" on
this platform, "OFF" otherwise.

- GLVIS_MULTISAMPLE and GLVIS_MS_LINEWIDTH: See building considerations below
for more information on these variables.

Expand Down
25 changes: 13 additions & 12 deletions lib/aux_vis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

#include <iostream>
#include <sstream>
#include <fstream>
#include <cmath>
#include <chrono>
#include <regex>
Expand Down Expand Up @@ -59,13 +58,12 @@ static bool wndUseHiDPI = true;

MainThread& GetMainThread(bool headless)
{
#ifdef GLVIS_USE_EGL
#if defined(GLVIS_USE_EGL) or defined(GLVIS_USE_CGL)
if (headless)
{
return EglMainThread::Get();
}
#endif

return GetSdlMainThread();
}

Expand Down Expand Up @@ -116,13 +114,16 @@ GLWindow* InitVisualization(const char name[], int x, int y, int w, int h,
bool headless)
{
#ifdef GLVIS_DEBUG
if (!headless)
{
cout << "OpenGL Visualization" << endl;
}
if (!headless) { cout << "OpenGL Visualization" << endl; }
else
{
#if defined(GLVIS_USE_EGL)
cout << "OpenGL+EGL Visualization" << endl;
#elif defined(GLVIS_USE_CGL)
cout << "OpenGL+CGL Visualization" << endl;
#else
cout << "Headless rendering requires EGL or CGL!" << endl;
#endif
}
#endif

Expand All @@ -145,7 +146,7 @@ GLWindow* InitVisualization(const char name[], int x, int y, int w, int h,
}
else
{
#ifdef GLVIS_USE_EGL
#if defined(GLVIS_USE_EGL) or defined(GLVIS_USE_CGL)
sdl_wnd = nullptr;
if (!wnd)
{
Expand All @@ -161,10 +162,10 @@ GLWindow* InitVisualization(const char name[], int x, int y, int w, int h,
{
wnd->clearEvents();
}
#else //GLVIS_USE_EGL
cerr << "EGL is required for headless rendering!" << endl;
#else // GLVIS_USE_EGL || GLVIS_USE_CGL
cerr << "EGL or CGL are required for headless rendering!" << endl;
return NULL;
#endif //GLVIS_USE_EGL
#endif // GLVIS_USE_EGL || GLVIS_USE_CGL
}

#ifdef GLVIS_DEBUG
Expand Down Expand Up @@ -1029,7 +1030,7 @@ int SaveAsPNG(const char *fname, int w, int h, bool is_hidpi, bool with_alpha,
}

png_uint_32 ppi = is_hidpi ? 144 : 72; // pixels/inch
png_uint_32 ppm = ppi/0.0254 + 0.5; // pixels/meter
auto ppm = static_cast<png_uint_32>(ppi/0.0254 + 0.5); // pixels/meter
png_set_pHYs(png_ptr, info_ptr, ppm, ppm, PNG_RESOLUTION_METER);

png_init_io(png_ptr, fp);
Expand Down
39 changes: 29 additions & 10 deletions lib/egl/egl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#ifdef GLVIS_USE_EGL
#if defined(GLVIS_USE_EGL) || defined(GLVIS_USE_CGL)

#include <cassert>
#include <iostream>
#include <vector>

#include "egl.hpp"
#include "egl_main.hpp"
#include "../aux_vis.hpp"
#include <iostream>
#include <vector>
#include <future>

#ifdef GLVIS_DEBUG
#define PRINT_DEBUG(s) std::cerr << s
Expand All @@ -25,10 +27,6 @@

using namespace std;

EglWindow::EglWindow()
{
}

EglWindow::~EglWindow()
{
EglMainThread::Get().DeleteWindow(this, handle);
Expand All @@ -43,6 +41,10 @@ bool EglWindow::createWindow(const char *, int, int, int w, int h,
return false;
}

#ifdef GLVIS_USE_CGL
return true; // CGL already called initGLEW() during CreateWindow()
#endif

#ifndef __EMSCRIPTEN__
glEnable(GL_DEBUG_OUTPUT);
#endif
Expand Down Expand Up @@ -156,13 +158,30 @@ void EglWindow::signalLoop()

void EglWindow::getGLDrawSize(int& w, int& h) const
{
#ifdef GLVIS_USE_EGL
EGLint egl_w, egl_h;

EGLDisplay disp = EglMainThread::Get().GetDisplay();
eglQuerySurface(disp, handle.surf, EGL_WIDTH, &egl_w);
eglQuerySurface(disp, handle.surf, EGL_HEIGHT, &egl_h);
w = egl_w;
h = egl_h;
#endif
#ifdef GLVIS_USE_CGL
GLint cgl_w, cgl_h;
// Bind the color renderbuffer
glBindRenderbuffer(GL_RENDERBUFFER, handle.buf_color);
assert(glGetError() == GL_NO_ERROR);
// Query width and height
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &cgl_w);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &cgl_h);
assert(glGetError() == GL_NO_ERROR);
// Unbind to restore state
glBindRenderbuffer(GL_RENDERBUFFER, 0);
assert(glGetError() == GL_NO_ERROR);
w = cgl_w;
h = cgl_h;
#endif
}

bool EglWindow::isHighDpi() const
Expand All @@ -184,7 +203,7 @@ void EglWindow::signalKeyDown(SDL_Keycode k, SDL_Keymod m)

void EglWindow::signalQuit()
{
queueEvents({{EventType::Quit}});
queueEvents({{EventType::Quit, {}}});
}

void EglWindow::screenshot(string filename, bool convert)
Expand All @@ -197,4 +216,4 @@ void EglWindow::screenshot(string filename, bool convert)
signalExpose();
}

#endif //GLVIS_USE_EGL
#endif // GLVIS_USE_EGL || GLVIS_USE_CGL
49 changes: 38 additions & 11 deletions lib/egl/egl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,46 +11,69 @@

#ifndef GLVIS_EGL_HPP
#define GLVIS_EGL_HPP
#ifdef GLVIS_USE_EGL

#if defined(GLVIS_USE_EGL) || defined(GLVIS_USE_CGL)

#include "../glwindow.hpp"

#ifdef GLVIS_USE_EGL
#include <EGL/egl.h>
#endif

#ifdef GLVIS_USE_CGL
#define GL_SILENCE_DEPRECATION // CGL has been deprecated since MacOS 10.14
#include <OpenGL/OpenGL.h>
#endif

#include <condition_variable>
#include <memory>
#include <mutex>
#include <deque>
#include <list>

class EglWindow : public GLWindow
{
public:
struct Handle
{
EGLSurface surf{EGL_NO_SURFACE};
#ifdef GLVIS_USE_EGL
EGLSurface surf {EGL_NO_SURFACE};
EGLContext ctx{EGL_NO_CONTEXT};
EGLConfig eglCfg{};
#endif
#ifdef GLVIS_USE_CGL
GLuint buf_frame {}, buf_color {}, buf_depth {};
CGLPixelFormatObj pix {};

using CGLContextDeleter = void(*)(CGLContextObj);
std::unique_ptr<_CGLContextObject, CGLContextDeleter> ctx
{nullptr, [](CGLContextObj ctx) { CGLDestroyContext(ctx); }};
#endif

bool isInitialized()
{
#ifdef GLVIS_USE_EGL
return surf != EGL_NO_SURFACE && ctx != EGL_NO_CONTEXT;
#endif
#ifdef GLVIS_USE_CGL
return ctx != nullptr;
#endif
}
};

private:
Handle handle;

bool running{false};

bool is_multithreaded{true};
bool call_idle_func{false};
bool running {false};
bool is_multithreaded {true};
bool call_idle_func {false};

enum class EventType
{
Keydown,
Screenshot,
Quit,
};

struct Event
{
EventType type;
Expand All @@ -72,15 +95,14 @@ class EglWindow : public GLWindow
};

std::string screenshot_filename;

std::condition_variable events_available;
std::mutex event_mutex;
std::deque<Event> waiting_events;

void queueEvents(std::vector<Event> events);

public:
EglWindow();
EglWindow() = default;
~EglWindow();

/** @brief Creates a new OpenGL window. Returns false if EGL or OpenGL
Expand All @@ -103,8 +125,13 @@ class EglWindow : public GLWindow

void setWindowSize(int w, int h) override;

#if defined(GLVIS_USE_EGL)
bool isWindowInitialized() const override { return handle.surf != EGL_NO_SURFACE; }
bool isGlInitialized() const override { return handle.ctx != EGL_NO_CONTEXT; }
#elif defined(GLVIS_USE_CGL)
bool isWindowInitialized() const override { return isGlInitialized(); }
bool isGlInitialized() const override { return handle.ctx != nullptr; }
#endif

void signalKeyDown(SDL_Keycode k, SDL_Keymod m = KMOD_NONE) override;
void signalQuit() override;
Expand All @@ -118,5 +145,5 @@ class EglWindow : public GLWindow
void screenshot(std::string filename, bool convert = false) override;
};

#endif //GLVIS_USE_EGL
#endif //GLVIS_EGL_HPP
#endif // GLVIS_USE_EGL || GLVIS_USE_CGL
#endif // GLVIS_EGL_HPP
Loading
Loading