Wayland platform.: complete support of gl_start/gl_finish.

This commit is contained in:
ManoloFLTK 2022-07-04 11:44:03 +02:00
parent 8a2559e1af
commit 844d3d6d5c
5 changed files with 66 additions and 17 deletions

View File

@ -200,9 +200,8 @@ and OpenGL under macOS (see \ref osissues_retina)
\section opengl_normal Using OpenGL in Normal FLTK Windows
\note Drawing both with OpenGL and Quartz in a normal FLTK window is not possible
with the macOS platform. Similarly, the Wayland platform doesn't allow to draw with
both Cairo and OpenGL to the same window. This technique is therefore not useful under
macOS or Wayland because it permits nothing more than what is possible with class Fl_Gl_Window.
with the macOS platform. This technique is therefore not useful under macOS because
it permits nothing more than what is possible with class Fl_Gl_Window.
You can put OpenGL code into the \p draw() method, as described in
\ref subclassing_drawing

View File

@ -50,8 +50,8 @@ class Fl_Wayland_Gl_Window_Driver : public Fl_Gl_Window_Driver {
virtual void delete_gl_context(GLContext);
virtual void make_overlay_current();
virtual void redraw_overlay();
virtual void waitGL();
virtual void gl_start();
virtual void gl_visual(Fl_Gl_Choice *c);
virtual Fl_RGB_Image* capture_gl_rectangle(int x, int y, int w, int h);
char *alpha_mask_for_string(const char *str, int n, int w, int h, Fl_Fontsize fs);
static EGLDisplay egl_display;

View File

@ -46,6 +46,15 @@ public:
}
};
struct gl_start_support { // to support use of gl_start / gl_finish
struct wl_surface *surface;
struct wl_subsurface *subsurface;
struct wl_egl_window *egl_window;
EGLSurface egl_surface;
};
static EGLConfig wld_egl_conf = NULL;
EGLDisplay Fl_Wayland_Gl_Window_Driver::egl_display = EGL_NO_DISPLAY;
EGLint Fl_Wayland_Gl_Window_Driver::configs_count = 0;
struct wl_event_queue *Fl_Wayland_Gl_Window_Driver::gl_event_queue = NULL;
@ -172,23 +181,36 @@ GLContext Fl_Wayland_Gl_Window_Driver::create_gl_context(Fl_Window* window, cons
//fprintf(stderr, "eglCreateContext=%p shared_ctx=%p\n", ctx, shared_ctx);
if (ctx)
add_context(ctx);
if (!egl_surface) { // useful for gl_start()
struct wld_window *xid = fl_xid(window);
float s = Fl::screen_scale(window->screen_num());
egl_window = wl_egl_window_create(xid->wl_surface, window->w() * s, window->h() * s);
egl_surface = eglCreateWindowSurface(egl_display, ((Fl_Wayland_Gl_Choice*)g)->egl_conf, egl_window, NULL);
}
return ctx;
}
void Fl_Wayland_Gl_Window_Driver::set_gl_context(Fl_Window* w, GLContext context) {
struct wld_window *win = fl_xid(w);
if (!win || !egl_surface) return;
if (!win) return;
Fl_Wayland_Window_Driver *dr = (Fl_Wayland_Window_Driver*)Fl_Window_Driver::driver(w);
EGLSurface target_egl_surface = NULL;
if (egl_surface) target_egl_surface = egl_surface;
else if (dr->gl_start_support_) target_egl_surface = dr->gl_start_support_->egl_surface;
if (!target_egl_surface) { // useful for gl_start()
dr->gl_start_support_ = new struct gl_start_support;
float s = Fl::screen_scale(w->screen_num());
Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
// the GL scene will be a transparent subsurface above the cairo-drawn surface
dr->gl_start_support_->surface = wl_compositor_create_surface(scr_driver->wl_compositor);
dr->gl_start_support_->subsurface = wl_subcompositor_get_subsurface(
scr_driver->wl_subcompositor, dr->gl_start_support_->surface, win->wl_surface);
wl_subsurface_set_position(dr->gl_start_support_->subsurface, w->x() * s, w->y() * s);
wl_subsurface_place_above(dr->gl_start_support_->subsurface, win->wl_surface);
dr->gl_start_support_->egl_window = wl_egl_window_create(
dr->gl_start_support_->surface, w->w() * s, w->h() * s);
target_egl_surface = dr->gl_start_support_->egl_surface = eglCreateWindowSurface(
egl_display, wld_egl_conf, dr->gl_start_support_->egl_window, NULL);
}
if (context != cached_context || w != cached_window) {
cached_context = context;
cached_window = w;
if (eglMakeCurrent(egl_display, egl_surface, egl_surface, (EGLContext)context)) {
if (eglMakeCurrent(egl_display, target_egl_surface, target_egl_surface, (EGLContext)context)) {
//fprintf(stderr, "EGLContext %p made current\n", context);
} else {
Fl::error("eglMakeCurrent() failed\n");
@ -333,6 +355,13 @@ public:
eglTerminate(Fl_Wayland_Gl_Window_Driver::egl_display);
}
}
virtual void destroy(struct gl_start_support *gl_start_support_) {
eglDestroySurface(Fl_Wayland_Gl_Window_Driver::egl_display, gl_start_support_->egl_surface);
wl_egl_window_destroy(gl_start_support_->egl_window);
wl_subsurface_destroy(gl_start_support_->subsurface);
wl_surface_destroy(gl_start_support_->surface);
delete gl_start_support_;
}
};
static Fl_Wayland_Gl_Plugin Gl_Overlay_Plugin;
@ -358,11 +387,14 @@ char Fl_Wayland_Gl_Window_Driver::swap_type() {
}
void Fl_Wayland_Gl_Window_Driver::waitGL() {
struct wld_window *window = fl_xid(Fl_Window::current());
window->buffer->draw_buffer_needs_commit = false;
void Fl_Wayland_Gl_Window_Driver::gl_visual(Fl_Gl_Choice *c) {
Fl_Gl_Window_Driver::gl_visual(c);
wld_egl_conf = ((Fl_Wayland_Gl_Choice*)c)->egl_conf;
}
static void delayed_redraw(Fl_Window *win) {
win->redraw();
}
void Fl_Wayland_Gl_Window_Driver::gl_start() {
struct wld_window *win = fl_xid(Fl_Window::current());
@ -370,8 +402,12 @@ void Fl_Wayland_Gl_Window_Driver::gl_start() {
int W = Fl_Window::current()->w() * f;
int H = Fl_Window::current()->h() * f;
int W2, H2;
wl_egl_window_get_attached_size(egl_window, &W2, &H2);
if (W2 != W || H2 != H) wl_egl_window_resize(egl_window, W, H, 0, 0);
Fl_Wayland_Window_Driver *dr = (Fl_Wayland_Window_Driver*)Fl_Window_Driver::driver(Fl_Window::current());
wl_egl_window_get_attached_size(dr->gl_start_support_->egl_window, &W2, &H2);
if (W2 != W || H2 != H) {
wl_egl_window_resize(dr->gl_start_support_->egl_window, W, H, 0, 0);
Fl::add_timeout(0.01, (Fl_Timeout_Handler)delayed_redraw, Fl_Window::current());
}
glClearColor(0., 0., 0., 0.);
glClear(GL_COLOR_BUFFER_BIT);
}

View File

@ -46,6 +46,7 @@ typedef struct _cairo_pattern cairo_pattern_t;
class FL_EXPORT Fl_Wayland_Window_Driver : public Fl_Window_Driver
{
friend class Fl_X;
friend class Fl_Wayland_Gl_Window_Driver;
private:
struct shape_data_type {
int lw_; ///< width of shape image
@ -56,6 +57,7 @@ private:
static bool in_flush; // useful for progressive window drawing
struct wl_cursor *cursor_;
void delete_cursor_();
struct gl_start_support *gl_start_support_; // for support of gl_start/gl_finish
public:
struct wl_cursor *cursor() { return cursor_; };
bool in_handle_configure; // distinguish OS and user window resize
@ -156,6 +158,7 @@ public:
virtual void do_swap(Fl_Window*) = 0;
virtual void invalidate(Fl_Window*) = 0;
virtual void terminate() = 0;
virtual void destroy(struct gl_start_support *) = 0;
};
#endif // FL_WAYLAND_WINDOW_DRIVER_H

View File

@ -67,6 +67,7 @@ Fl_Wayland_Window_Driver::Fl_Wayland_Window_Driver(Fl_Window *win) : Fl_Window_D
cursor_ = NULL;
in_handle_configure = false;
screen_num_ = -1;
gl_start_support_ = NULL;
}
void Fl_Wayland_Window_Driver::delete_cursor_() {
@ -98,6 +99,16 @@ Fl_Wayland_Window_Driver::~Fl_Wayland_Window_Driver()
delete shape_data_;
}
delete_cursor_();
if (gl_start_support_) { // occurs only if gl_start/gl_finish was used
static Fl_Wayland_Plugin *plugin = NULL;
if (!plugin) {
Fl_Plugin_Manager pm("wayland.fltk.org");
plugin = (Fl_Wayland_Plugin*)pm.plugin("gl.wayland.fltk.org");
}
if (plugin) {
plugin->destroy(gl_start_support_);
}
}
}