diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index 516b815..167785a 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -162,6 +162,7 @@ MWDECL void (*MwLLDestroy)(MwLL handle); MWDECL void (*MwLLPolygon)(MwLL handle, MwPoint* points, int points_count, MwLLColor color); MWDECL void (*MwLLLine)(MwLL handle, MwPoint* points, MwLLColor color); +MWDECL void (*MwLLBeginDraw)(MwLL handle); MWDECL void (*MwLLEndDraw)(MwLL handle); MWDECL MwLLColor (*MwLLAllocColor)(MwLL handle, int r, int g, int b); diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index f443c52..75f208b 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -13,34 +13,13 @@ #include #include -#include +#include +#include +#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "Mw/BaseTypes.h" -#include "Mw/LowLevel.h" - -#include -#include -#include - -/* TODO: find out what FreeBSD and such wants us to include */ -#include - MWDECL int MwLLWaylandCallInit(void); #ifndef WL_PROTOCOLS_DEFINED @@ -110,19 +89,18 @@ struct _MwLLWayland { MwU32 x, y, ww, wh; MwPoint cur_mouse_pos; - cairo_surface_t* cairo_surface; - void* mapped_buffer; + int last_serial; MwLL parent; - // GLuint fbo; - // unsigned int fbo_texture; + GLuint fbo; + unsigned int fbo_texture; - // EGLNativeWindowType egl_window_native; - // EGLDisplay egl_display; - // EGLContext egl_context; - // EGLSurface egl_surface; - // EGLConfig egl_config; + EGLNativeWindowType egl_window_native; + EGLDisplay egl_display; + EGLContext egl_context; + EGLSurface egl_surface; + EGLConfig egl_config; }; struct _MwLLWaylandColor { @@ -131,7 +109,7 @@ struct _MwLLWaylandColor { struct _MwLLWaylandPixmap { struct _MwLLCommonPixmap common; - // GLuint texture; + GLuint texture; }; #endif diff --git a/pl/rules.pl b/pl/rules.pl index 7d4de16..8ba2206 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -29,7 +29,7 @@ if (grep(/^gdi$/, @backends)) { if (grep(/^wayland$/, @backends)) { add_cflags("-DUSE_WAYLAND"); new_object("src/backend/wayland.c"); - add_libs("-lcairo -lwayland-client -lxkbcommon"); + add_libs("-lGL -lEGL -lwayland-egl -lwayland-client -lxkbcommon"); scan_wayland_protocol("stable", "xdg-shell",""); scan_wayland_protocol("stable", "tablet","-v2"); diff --git a/src/backend/call.c b/src/backend/call.c index e97e28b..e2ce934 100644 --- a/src/backend/call.c +++ b/src/backend/call.c @@ -8,9 +8,10 @@ MwLLCreate = MwLLCreateImpl; \ MwLLDestroy = MwLLDestroyImpl; \ \ - MwLLPolygon = MwLLPolygonImpl; \ - MwLLLine = MwLLLineImpl; \ - MwLLEndDraw = MwLLEndDrawImpl; \ + MwLLPolygon = MwLLPolygonImpl; \ + MwLLLine = MwLLLineImpl; \ + MwLLBeginDraw = MwLLBeginDrawImpl; \ + MwLLEndDraw = MwLLEndDrawImpl; \ \ MwLLAllocColor = MwLLAllocColorImpl; \ MwLLColorUpdate = MwLLColorUpdateImpl; \ diff --git a/src/backend/gdi.c b/src/backend/gdi.c index 9d25fae..a527e09 100644 --- a/src/backend/gdi.c +++ b/src/backend/gdi.c @@ -277,6 +277,7 @@ static void MwLLDestroyImpl(MwLL handle) { free(handle); } +static void MwLLBeginDrawImpl(MwLL handle) {} static void MwLLEndDrawImpl(MwLL handle) {} static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 1c232fe..cfd30f2 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1,7 +1,37 @@ #include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include "../../external/stb_ds.h" +#include "Mw/BaseTypes.h" #include "Mw/LowLevel.h" +#include +#include +#include + +/* TODO: find out what FreeBSD and such wants us to include */ +#include + +PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers; +PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D; +PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers; +PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer; +PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer; +PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer; +PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatus; + /* callback todo: void (*up)(MwLL handle, void* data); @@ -48,7 +78,6 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, uint32_t t self->wayland.cur_mouse_pos.y = wl_fixed_to_double(surface_y); p.point = self->wayland.cur_mouse_pos; MwLLDispatch(self, move, &p); - MwLLForceRender(self); }; static void pointer_button(void* data, struct wl_pointer* wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { MwLL self = data; @@ -75,8 +104,6 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, uint32_t s break; } } - printf("what\n"); - MwLLForceRender(self); }; static void pointer_axis(void* data, struct wl_pointer* wl_pointer, uint32_t time, uint32_t axis, wl_fixed_t value) {}; @@ -113,62 +140,6 @@ void xdg_wm_base_ping(void* data, xdg_wm_base_pong(xdg_wm_base, serial); }; -static wayland_protocol_t* wl_shm_setup(MwU32 name, struct _MwLLWayland* wayland) { - wayland->shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1); - return NULL; -} -static void buffer_setup(struct _MwLLWayland* wayland) { - struct wl_shm_pool* pool; - struct wl_buffer* buffer; - int x, y; - int stride = wayland->ww * 4; - - int fd; - MwU32 size = wayland->ww * wayland->wh * 4; - char temp_name[] = "/tmp/milsko-wl-shm-XXXXXX"; - - fd = mkstemp(temp_name); - - unlink(temp_name); - - if(posix_fallocate(fd, 0, size) != 0) { - printf("failure setting up wl_shm: could not fallocate. %s.\n", strerror(errno)); - close(fd); - return; - } - if(ftruncate(fd, size) != 0) { - printf("failure setting up wl_shm: could not truncate. %s.\n", strerror(errno)); - close(fd); - return; - } - - wayland->mapped_buffer = mmap(NULL, size, PROT_WRITE, MAP_SHARED, fd, 0); - memset(wayland->mapped_buffer, 0xFF, size); - // wayland->mapped_buffer_size = size; - - wayland->cairo_surface = cairo_image_surface_create_for_data(wayland->mapped_buffer, - CAIRO_FORMAT_ARGB32, - wayland->ww, - wayland->wh, - stride); - - fsync(fd); - - if(!(pool = wl_shm_create_pool(wayland->shm, fd, size))) { - printf("failure setting up wl_shm: could not create pool.\n"); - } - - buffer = wl_shm_pool_create_buffer(pool, 0, wayland->ww, wayland->wh, stride, WL_SHM_FORMAT_ARGB8888); - - if(wayland->configured) { - wl_surface_attach(wayland->surface, buffer, 0, 0); - wl_surface_commit(wayland->surface); - } - wl_buffer_destroy(buffer); - wl_shm_pool_destroy(pool); - close(fd); -} - static wayland_protocol_t* wl_seat_setup(MwU32 name, MwLL ll) { wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); proto->listener = malloc(sizeof(struct wl_seat_listener)); @@ -234,6 +205,163 @@ static wayland_protocol_t* zxdg_decoration_manager_v1_setup(MwU32 name, struct _ return proto; } +static MwBool egl_setup(MwLL self, int width, int height) { + int err; + EGLint numConfigs; + EGLint majorVersion; + EGLint minorVersion; + EGLContext context; + EGLSurface surface; + EGLint fbAttribs[] = + { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, + EGL_NONE}; + EGLint contextAttribs[] = { + EGL_CONTEXT_CLIENT_VERSION, 1, + EGL_CONTEXT_MAJOR_VERSION, 1, + EGL_CONTEXT_MINOR_VERSION, 1, + EGL_NONE}; + + EGLDisplay display = eglGetDisplay(self->wayland.display); + if(display == EGL_NO_DISPLAY) { + printf("ERROR: eglGetDisplay, %0X\n", eglGetError()); + return MwFALSE; + } + + // Initialize EGL + if(!eglInitialize(display, &majorVersion, &minorVersion)) { + printf("ERROR: eglInitialize, %0X\n", eglGetError()); + return MwFALSE; + } + + // Get configs + if((eglGetConfigs(display, NULL, 0, &numConfigs) != EGL_TRUE) || (numConfigs == 0)) { + printf("ERROR: eglGetConfigs, %0X\n", eglGetError()); + return MwFALSE; + } + + // Choose config + if((eglChooseConfig(display, fbAttribs, &self->wayland.egl_config, 1, &numConfigs) != EGL_TRUE) || (numConfigs != 1)) { + printf("ERROR: eglChooseConfig, %0X\n", eglGetError()); + return MwFALSE; + } + + self->wayland.egl_window_native = + wl_egl_window_create(self->wayland.surface, width, height); + if(self->wayland.egl_window_native == EGL_NO_SURFACE) { + printf("ERROR: wl_egl_window_create, EGL_NO_SURFACE\n"); + return MwFALSE; + } + + // Create a surface + surface = eglCreateWindowSurface(display, self->wayland.egl_config, self->wayland.egl_window_native, NULL); + if(surface == EGL_NO_SURFACE) { + printf("ERROR: eglCreateWindowSurface, %0X\n", eglGetError()); + return MwFALSE; + } + + eglBindAPI(EGL_OPENGL_API); + + // Create a GL context + context = eglCreateContext(display, self->wayland.egl_config, EGL_NO_CONTEXT, contextAttribs); + if(context == EGL_NO_CONTEXT) { + printf("ERROR: eglCreateContext, %0X\n", eglGetError()); + return MwFALSE; + } + + glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)eglGetProcAddress("glGenFramebuffers"); + glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)eglGetProcAddress("glFramebufferTexture2D"); + glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)eglGetProcAddress("glGenRenderbuffers"); + // glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)eglGetProcAddress("glRenderbufferStorage"); + glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)eglGetProcAddress("glFramebufferRenderbuffer"); + glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)eglGetProcAddress("glBindRenderbuffer"); + glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)eglGetProcAddress("glBindFramebuffer"); + glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)eglGetProcAddress("glCheckFramebufferStatus"); + + glGenTextures(1, &self->wayland.fbo_texture); + glBindTexture(GL_TEXTURE_2D, self->wayland.fbo_texture); + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + + glBindTexture(GL_TEXTURE_2D, 0); + + glGenFramebuffers(1, &self->wayland.fbo); + glBindFramebuffer(GL_FRAMEBUFFER_BINDING, self->wayland.fbo); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self->wayland.fbo_texture, 0); + + if((err = glCheckFramebufferStatus(GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE) { + printf("Error binding framebuffer: %0X\n", err); + // return MwFALSE; + } + + glBindFramebuffer(GL_FRAMEBUFFER_BINDING, 0); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, width, height, 0, -1, 1); + glEnable(GL_TEXTURE_2D); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + + self->wayland.egl_display = display; + self->wayland.egl_surface = surface; + self->wayland.egl_context = context; + return MwTRUE; +} + +static void egl_resetup(MwLL handle) { + int err; + + glDeleteTextures(1, &handle->wayland.fbo_texture); + glGenTextures(1, &handle->wayland.fbo_texture); + glBindTexture(GL_TEXTURE_2D, handle->wayland.fbo_texture); + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, handle->wayland.ww, handle->wayland.wh, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + + glGenFramebuffers(1, &handle->wayland.fbo); + glBindFramebuffer(GL_FRAMEBUFFER_BINDING, handle->wayland.fbo); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, handle->wayland.fbo_texture, 0); + + if((err = glCheckFramebufferStatus(GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE) { + printf("Error binding framebuffer: %0X\n", err); + return; + } + + glBindFramebuffer(GL_FRAMEBUFFER_BINDING, 0); + + glBindTexture(GL_TEXTURE_2D, 0); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, handle->wayland.ww, handle->wayland.wh, 0, -1, 1); + glViewport(0, 0, handle->wayland.ww, handle->wayland.wh); + + handle->wayland.egl_do_resetup = MwFALSE; +} + +static void recursive_draw(MwLL handle) { + int i; + if(handle->wayland.subwidgets != NULL) { + for(i = 0; i < arrlen(handle->wayland.subwidgets); i++) { + MwLLDispatch(handle->wayland.subwidgets[i], draw, NULL); + recursive_draw(handle->wayland.subwidgets[i]); + } + } +} + static void recursive_resize(MwLL handle) { int i; if(handle->wayland.subwidgets != NULL) { @@ -248,7 +376,8 @@ static void xdg_toplevel_configure(void* data, struct xdg_toplevel* xdg_toplevel, MwI32 width, MwI32 height, struct wl_array* states) { - MwLL self = data; + MwLL self = data; + PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)eglGetProcAddress("glFramebufferTexture2D"); if(width == 0 || height == 0) { width = self->wayland.ww; @@ -266,6 +395,15 @@ static void xdg_toplevel_configure(void* data, MwLLDispatch(self, resize, NULL); recursive_resize(self); + if(!self->wayland.egl_setup) { + self->wayland.egl_setup = egl_setup(self, width, height); + MwLLForceRender(self); + } else { + wl_egl_window_resize(self->wayland.egl_window_native, width, height, 0, 0); + self->wayland.egl_do_resetup = MwTRUE; + egl_resetup(self); + } + return; }; @@ -298,20 +436,69 @@ static void xdg_surface_configure( self->wayland.configured = MwTRUE; } -static MwBool flush_display(struct wl_display* display) { - while(wl_display_flush(display) == -1) { +static int event_loop(MwLL handle) { + enum { + DISPLAY_FD, + KEYREPEAT_FD, + CURSOR_FD + }; + struct pollfd fd; + int timeout = 100; + struct _MwLLWayland* wayland = &handle->wayland; + MwLL topmost_parent = handle->wayland.parent; + + if(wayland->display == NULL) { + return 0; + } + fd.fd = wl_display_get_fd(wayland->display); + fd.events = POLLIN; + + /* If an error other than EAGAIN happens, we have likely been disconnected from the Wayland session */ + while(wl_display_flush(wayland->display) == -1) { if(errno != EAGAIN) { return MwFALSE; } - struct pollfd fd = {wl_display_get_fd(display), POLL_OUT}; - while(poll(&fd, 1, -1) == -1) { - if(errno != EINTR && errno != EAGAIN) - return MwFALSE; + if(errno != EINTR && errno != EAGAIN) { + wl_display_cancel_read(wayland->display); + + MwLLDispatch(handle, close, NULL); + return 0; + } } } - return MwTRUE; + + /* + IOI: + I took this from ioilib which I in turn adapted from SDL. I think this is meant to be required? + But doing this on my main machine causes the decorations manager to be null...? This doesn't show up on the project currently using ioilib. + Race condition? Random KDE bug? Who knows, but it seems that not polling for this works anyways (possibly because we already flush events above and then cancel reads when we actually need to close). + */ + /* + + // Condition where no events are being sent. + if(!poll(&fd, 1, timeout)) { + wl_display_cancel_read(wayland->display); + // In this case, we need to commit the surface for any animations, etc. + wl_surface_commit(wayland->surface); + return 0; + } + + */ + + if(fd.revents & POLLIN) { + wl_display_read_events(wayland->display); + if(wl_display_dispatch_pending(wayland->display) > 0) { + } + } else { + if(wl_display_dispatch_pending(wayland->display) == 0) { + MwLLDispatch(handle, draw, NULL); + recursive_draw(handle); + } + } + + return 0; } #define WL_INTERFACE(interface) \ @@ -326,7 +513,6 @@ static void setup_callbacks(struct _MwLLWayland* wayland) { WL_INTERFACE(wl_compositor); WL_INTERFACE(wl_subcompositor); WL_INTERFACE(wl_seat); - WL_INTERFACE(wl_shm); if(wayland->type == MWLL_WAYLAND_TOPLEVEL) { WL_INTERFACE(xdg_wm_base); WL_INTERFACE(zxdg_decoration_manager_v1); @@ -396,8 +582,7 @@ static void setup_toplevel(MwLL r, int x, int y) { // Perform the initial commit and wait for the first configure event wl_surface_commit(r->wayland.surface); - while(wl_display_dispatch(r->wayland.display) != -1 && !r->wayland.configured) { - } + event_loop(r); // setup decorations if we can if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL) { @@ -415,9 +600,6 @@ static void setup_toplevel(MwLL r, int x, int y) { // buffer_setup(&r->wayland); // glGenBuffers(1, &vertex_buffer); - // - buffer_setup(&r->wayland); - wl_surface_commit(r->wayland.surface); } static void setup_subsurface(MwLL parent, MwLL r, int x, int y) { @@ -441,6 +623,7 @@ static void setup_subsurface(MwLL parent, MwLL r, int x, int y) { wl_region_add(region, 0, 0, r->wayland.ww, r->wayland.wh); wl_surface_set_opaque_region(r->wayland.surface, region); wl_surface_commit(r->wayland.surface); + event_loop(r); wl_region_destroy(region); r->wayland.subsurface = wl_subcompositor_get_subsurface(subcompositor, r->wayland.surface, parent_surface); @@ -464,14 +647,22 @@ static void setup_subsurface(MwLL parent, MwLL r, int x, int y) { // arrpush(parent->wayland.subsurfaces, r); r->wayland.configured = MwTRUE; + if(!r->wayland.egl_setup) { + r->wayland.egl_setup = egl_setup(r, r->wayland.ww, r->wayland.wh); + MwLLForceRender(r); + }; arrpush(parent->wayland.subwidgets, r); } static void framebuffer_action_begin(MwLL handle) { + glBindFramebuffer(GL_FRAMEBUFFER, handle->wayland.fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, handle->wayland.fbo_texture, 0); } static void framebuffer_action_end(MwLL handle) { + glFinish(); + glBindFramebuffer(GL_FRAMEBUFFER, 0); } static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { @@ -507,9 +698,6 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { setup_subsurface(parent, r, x, y); } - buffer_setup(&r->wayland); - - printf("test\n"); return r; } @@ -552,43 +740,130 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) { } static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { - int i = 0; + int i, n; + float maxX = 0, maxY = 0; + float centerX, centerY; + int doLoopback = MwFALSE; - cairo_t* cairo = cairo_create(handle->wayland.cairo_surface); - cairo_set_source_rgb(cairo, color->common.red / 255., color->common.green / 255., color->common.blue / 255.); - cairo_set_line_width(cairo, 0.1); - cairo_set_fill_rule(cairo, CAIRO_FILL_RULE_EVEN_ODD); + if(points_count > 3) { + /* To avoid having to do a real triangulation algorithim: + 1.) loop through the points once to determine the bounds of the polygon + 2.) calculate the center of the polygon - cairo_new_path(cairo); - for(; i < points_count; i++) { - cairo_line_to(cairo, points[i].x, points[i].y); + */ + for(i = 0; i < points_count; i++) { + float x = round(handle->wayland.x) + round(points[i].x); + float y = round(handle->wayland.y) + round(points[i].y); + if(x >= maxX) { + maxX = x; + } + if(y >= maxY) { + maxY = y; + } + } } - cairo_close_path(cairo); + centerX = (handle->wayland.x + maxX / 2); + centerY = (handle->wayland.y + maxY / 2); - // cairo_paint(cairo); - cairo_stroke_preserve(cairo); - cairo_fill(cairo); - cairo_destroy(cairo); + /* Efficient? No. But at the end of the day it's still not that many polygons, and if a computer can't handle 12 polygons over 6 then it should not be using Wayland anyways */ + + framebuffer_action_begin(handle); + + if(points_count == 3) { + glBegin(GL_TRIANGLES); + } else if((points_count % 3) == 0) { + glBegin(GL_POLYGON); + } else { + glBegin(GL_TRIANGLE_FAN); + doLoopback = MwTRUE; + } + + for(i = 0; i < points_count; i++) { + float x = round(handle->wayland.x) + round(points[i].x); + float y = round(handle->wayland.y) + round(points[i].y); + + glColor3f(color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0); + + glVertex2f(x, y); + if(doLoopback) { + glVertex2f(maxX, maxY); + glVertex2f(x, y); + } + } + glEnd(); + glColor3f(0, 0, 0); + + framebuffer_action_end(handle); } static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { - MwPoint p1 = points[0]; - MwPoint p2 = points[1]; - int i; + int i; - cairo_t* cairo = cairo_create(handle->wayland.cairo_surface); - cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); - cairo_set_line_width(cairo, 1); - cairo_set_source_rgb(cairo, color->common.red / 255., color->common.green / 255., color->common.blue / 255.); - cairo_paint(cairo); + glLineWidth(1); - cairo_move_to(cairo, p1.x, p1.y); - cairo_line_to(cairo, p2.x, p2.y); - cairo_fill(cairo); - cairo_destroy(cairo); + framebuffer_action_begin(handle); + glBegin(GL_LINES); + for(i = 0; i < 2; i++) { + float x = round(handle->wayland.x) + round(points[i].x); + float y = round(handle->wayland.y) + round(points[i].y); + + glColor3f(color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0); + + glVertex2f(x, y); + } + + glEnd(); + glColor3f(0, 0, 0); + + framebuffer_action_end(handle); +} + +static void MwLLBeginDrawImpl(MwLL handle) { + if(!eglMakeCurrent(handle->wayland.egl_display, handle->wayland.egl_surface, handle->wayland.egl_surface, handle->wayland.egl_context)) { + printf("ERROR: eglMakeCurrent, %0X\n", eglGetError()); + return; + } } static void MwLLEndDrawImpl(MwLL handle) { + int w, h; + + if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { + w = handle->wayland.ww; + h = handle->wayland.wh; + } else { + MwLL parent = handle->wayland.parent; + w = parent->wayland.ww; + h = parent->wayland.wh; + } + + recursive_draw(handle); + + glBindTexture(GL_TEXTURE_2D, handle->wayland.fbo_texture); + // glClear(GL_COLOR_BUFFER_BIT); + // glClearColor(1.0, 0, 0, 1); + + glColor3f(1.0, 1.0, 1.0); + + glBegin(GL_QUADS); + glTexCoord2f(0.0f, 1); + glVertex2f(0, 0); + glTexCoord2f(1, 1); + glVertex2f(w, 0); + glTexCoord2f(1, 0.0f); + glVertex2f(w, h); + glTexCoord2f(0.0f, 0.0f); + glVertex2f(0, h); + glEnd(); + glFinish(); + + wl_surface_damage(handle->wayland.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); + + if(!eglSwapBuffers(handle->wayland.egl_display, handle->wayland.egl_surface)) { + printf("error swapping buffers! %0X\n", eglGetError()); + } else { + wl_surface_commit(handle->wayland.surface); + } } static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { @@ -612,71 +887,15 @@ static void MwLLFreeColorImpl(MwLLColor color) { } static int MwLLPendingImpl(MwLL handle) { - enum { - DISPLAY_FD, - KEYREPEAT_FD, - CURSOR_FD - }; - struct pollfd fd; - int timeout = 1; - - if(handle->wayland.force_redraw) { - return 1; + if(wl_display_dispatch_pending(handle->wayland.display) == 0) { } - - if(handle->wayland.display == NULL) { - return 0; - } - fd.fd = wl_display_get_fd(handle->wayland.display); - fd.events = POLLIN; - - while(wl_display_prepare_read(handle->wayland.display) != 0) { - if(wl_display_dispatch_pending(handle->wayland.display) > 0) { - return 0; - } - } - - // If an error other than EAGAIN happens, we have likely been disconnected - // from the Wayland session - if(!flush_display(handle->wayland.display)) { - wl_display_cancel_read(handle->wayland.display); - - MwLLDispatch(handle, close, NULL); - // handle->wayland.toplevel->running = MwFALSE; - return 0; - } - - // Condition where no events are being sent. - if(!poll(&fd, 1, timeout)) { - wl_display_cancel_read(handle->wayland.display); - // In this case, we need to commit the surface for any animations, etc. - wl_surface_commit(handle->wayland.surface); - return 0; - } - - if(fd.revents & POLLIN) { - wl_display_read_events(handle->wayland.display); - if(wl_display_dispatch_pending(handle->wayland.display) > 0) { - } - } else { - wl_display_cancel_read(handle->wayland.display); - } - - return 1; + return event_loop(handle) || handle->wayland.force_redraw; } static void MwLLNextEventImpl(MwLL handle) { - MwBool render; - - render = handle->wayland.force_redraw; + MwBool render = handle->wayland.force_redraw; if(render) { - int x, y; - unsigned int w, h; - - MwLLGetXYWH(handle, &x, &y, &w, &h); - - MwLLDispatch(handle, draw, NULL); handle->wayland.force_redraw = MwFALSE; } } @@ -690,23 +909,59 @@ static void MwLLSetTitleImpl(MwLL handle, const char* title) { static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int width, int height) { MwLLPixmap r = malloc(sizeof(*r)); - r->common.width = width; - r->common.height = height; - r->common.raw = data; - // r->wayland.texture = 0; + r->common.width = width; + r->common.height = height; + r->common.raw = data; + r->wayland.texture = 0; + + glGenTextures(1, &r->wayland.texture); + + glBindTexture(GL_TEXTURE_2D, r->wayland.texture); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glBindTexture(GL_TEXTURE_2D, 0); + + MwLLPixmapUpdate(r); return r; } static void MwLLPixmapUpdateImpl(MwLLPixmap r) { + glBindTexture(GL_TEXTURE_2D, r->wayland.texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, r->common.width, r->common.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, r->common.raw); + glBindTexture(GL_TEXTURE_2D, 0); } static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { + glDeleteTextures(1, &pixmap->wayland.texture); free(pixmap); } static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { int x, y; + glColor3f(1.0, 1.0, 1.0); + + x = handle->wayland.x + rect->x; + y = handle->wayland.y + rect->y; + + glBindTexture(GL_TEXTURE_2D, pixmap->wayland.texture); + glActiveTexture(pixmap->wayland.texture); + + framebuffer_action_begin(handle); + glBegin(GL_QUADS); + glTexCoord2f(0.0f, 0); + glVertex2f(x, y); + glTexCoord2f(1, 0); + glVertex2f(x + rect->width, y); + glTexCoord2f(1, 1); + glVertex2f(x + rect->width, y + rect->height); + glTexCoord2f(0.0f, 1); + glVertex2f(x, y + rect->height); + glEnd(); + glFinish(); + framebuffer_action_end(handle); } static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { diff --git a/src/backend/x11.c b/src/backend/x11.c index 44da549..3c54155 100644 --- a/src/backend/x11.c +++ b/src/backend/x11.c @@ -148,14 +148,14 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { if(height < 2) height = 2; if(parent == NULL) { - r->x11.display = XOpenDisplay(NULL); - p = XRootWindow(r->x11.display, XDefaultScreen(r->x11.display)); - r->x11.top = 1; + r->x11.display = XOpenDisplay(NULL); + p = XRootWindow(r->x11.display, XDefaultScreen(r->x11.display)); + r->x11.top = 1; r->x11.toplevel = 1; } else { - r->x11.display = parent->x11.display; - p = parent->x11.window; - r->x11.top = 0; + r->x11.display = parent->x11.display; + p = parent->x11.window; + r->x11.top = 0; r->x11.toplevel = 0; } r->x11.window = XCreateSimpleWindow(r->x11.display, p, px, py, width, height, 0, 0, WhitePixel(r->x11.display, DefaultScreen(r->x11.display))); @@ -259,6 +259,7 @@ static void MwLLDestroyImpl(MwLL handle) { free(handle); } +static void MwLLBeginDrawImpl(MwLL handle) {} static void MwLLEndDrawImpl(MwLL handle) {} static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { diff --git a/src/core.c b/src/core.c index 696ed42..a734655 100644 --- a/src/core.c +++ b/src/core.c @@ -9,15 +9,16 @@ static void lldrawhandler(MwLL handle, void* data) { int ind; (void)data; + if(handle->wayland.parent == NULL) + MwLLBeginDraw(handle); h->bgcolor = NULL; MwDispatch(h, draw); if(h->draw_inject != NULL) h->draw_inject(h); MwDispatchUserHandler(h, MwNdrawHandler, NULL); - if(handle->wayland.parent == NULL) { + if(handle->wayland.parent == NULL) MwLLEndDraw(handle); - } } static void lluphandler(MwLL handle, void* data) { diff --git a/src/lowlevel.c b/src/lowlevel.c index 8e94790..96f6196 100644 --- a/src/lowlevel.c +++ b/src/lowlevel.c @@ -6,6 +6,7 @@ void (*MwLLDestroy)(MwLL handle); void (*MwLLPolygon)(MwLL handle, MwPoint* points, int points_count, MwLLColor color); void (*MwLLLine)(MwLL handle, MwPoint* points, MwLLColor color); +void (*MwLLBeginDraw)(MwLL handle); void (*MwLLEndDraw)(MwLL handle); MwLLColor (*MwLLAllocColor)(MwLL handle, int r, int g, int b);