mirror of
				https://gitlab.freedesktop.org/wayland/wayland.git
				synced 2025-11-03 09:01:42 -05:00 
			
		
		
		
	Fall back to cairo image backend and shm surface if we don't have cairo gl
This commit is contained in:
		
							parent
							
								
									6866856dfd
								
							
						
					
					
						commit
						d0c3b9da22
					
				
					 4 changed files with 331 additions and 100 deletions
				
			
		
							
								
								
									
										406
									
								
								clients/window.c
									
										
									
									
									
								
							
							
						
						
									
										406
									
								
								clients/window.c
									
										
									
									
									
								
							| 
						 | 
					@ -20,6 +20,8 @@
 | 
				
			||||||
 * OF THIS SOFTWARE.
 | 
					 * OF THIS SOFTWARE.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "../config.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
| 
						 | 
					@ -33,13 +35,17 @@
 | 
				
			||||||
#include <glib-object.h>
 | 
					#include <glib-object.h>
 | 
				
			||||||
#include <gdk-pixbuf/gdk-pixbuf.h>
 | 
					#include <gdk-pixbuf/gdk-pixbuf.h>
 | 
				
			||||||
#include <xf86drm.h>
 | 
					#include <xf86drm.h>
 | 
				
			||||||
 | 
					#include <sys/mman.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define EGL_EGLEXT_PROTOTYPES 1
 | 
					#define EGL_EGLEXT_PROTOTYPES 1
 | 
				
			||||||
#define GL_GLEXT_PROTOTYPES 1
 | 
					#define GL_GLEXT_PROTOTYPES 1
 | 
				
			||||||
#include <GL/gl.h>
 | 
					#include <GL/gl.h>
 | 
				
			||||||
#include <EGL/egl.h>
 | 
					#include <EGL/egl.h>
 | 
				
			||||||
#include <EGL/eglext.h>
 | 
					#include <EGL/eglext.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef HAVE_CAIRO_GL
 | 
				
			||||||
#include <cairo-gl.h>
 | 
					#include <cairo-gl.h>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <X11/extensions/XKBcommon.h>
 | 
					#include <X11/extensions/XKBcommon.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -56,6 +62,7 @@ struct display {
 | 
				
			||||||
	struct wl_compositor *compositor;
 | 
						struct wl_compositor *compositor;
 | 
				
			||||||
	struct wl_shell *shell;
 | 
						struct wl_shell *shell;
 | 
				
			||||||
	struct wl_drm *drm;
 | 
						struct wl_drm *drm;
 | 
				
			||||||
 | 
						struct wl_shm *shm;
 | 
				
			||||||
	struct wl_output *output;
 | 
						struct wl_output *output;
 | 
				
			||||||
	struct rectangle screen_allocation;
 | 
						struct rectangle screen_allocation;
 | 
				
			||||||
	int authenticated;
 | 
						int authenticated;
 | 
				
			||||||
| 
						 | 
					@ -89,6 +96,7 @@ struct window {
 | 
				
			||||||
	struct input *grab_device;
 | 
						struct input *grab_device;
 | 
				
			||||||
	struct input *keyboard_device;
 | 
						struct input *keyboard_device;
 | 
				
			||||||
	uint32_t name;
 | 
						uint32_t name;
 | 
				
			||||||
 | 
						enum window_buffer_type buffer_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	EGLImageKHR *image;
 | 
						EGLImageKHR *image;
 | 
				
			||||||
	cairo_surface_t *cairo_surface, *pending_surface;
 | 
						cairo_surface_t *cairo_surface, *pending_surface;
 | 
				
			||||||
| 
						 | 
					@ -148,33 +156,110 @@ rounded_rect(cairo_t *cr, int x0, int y0, int x1, int y1, int radius)
 | 
				
			||||||
	cairo_close_path(cr);
 | 
						cairo_close_path(cr);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static const cairo_user_data_key_t surface_data_key;
 | 
				
			||||||
texture_from_png(const char *filename, int width, int height)
 | 
					struct surface_data {
 | 
				
			||||||
 | 
						struct wl_buffer *buffer;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef HAVE_CAIRO_GL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct drm_surface_data {
 | 
				
			||||||
 | 
						struct surface_data data;
 | 
				
			||||||
 | 
						EGLImageKHR image;
 | 
				
			||||||
 | 
						GLuint texture;
 | 
				
			||||||
 | 
						EGLDisplay dpy;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					drm_surface_data_destroy(void *p)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct drm_surface_data *data = p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						glDeleteTextures(1, &data->texture);
 | 
				
			||||||
 | 
						eglDestroyImageKHR(data->dpy, data->image);
 | 
				
			||||||
 | 
						wl_buffer_destroy(data->data.buffer);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cairo_surface_t *
 | 
				
			||||||
 | 
					display_create_drm_surface(struct display *display,
 | 
				
			||||||
 | 
								   struct rectangle *rectangle)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct drm_surface_data *data;
 | 
				
			||||||
 | 
						EGLDisplay dpy = display->dpy;
 | 
				
			||||||
 | 
						cairo_surface_t *surface;
 | 
				
			||||||
 | 
						struct wl_visual *visual;
 | 
				
			||||||
 | 
						struct wl_buffer *buffer;
 | 
				
			||||||
 | 
						EGLint name, stride;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						EGLint image_attribs[] = {
 | 
				
			||||||
 | 
							EGL_WIDTH,		0,
 | 
				
			||||||
 | 
							EGL_HEIGHT,		0,
 | 
				
			||||||
 | 
							EGL_DRM_BUFFER_FORMAT_MESA,	EGL_DRM_BUFFER_FORMAT_ARGB32_MESA,
 | 
				
			||||||
 | 
							EGL_DRM_BUFFER_USE_MESA,	EGL_DRM_BUFFER_USE_SCANOUT_MESA,
 | 
				
			||||||
 | 
							EGL_NONE
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						data = malloc(sizeof *data);
 | 
				
			||||||
 | 
						if (data == NULL)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						image_attribs[1] = rectangle->width;
 | 
				
			||||||
 | 
						image_attribs[3] = rectangle->height;
 | 
				
			||||||
 | 
						data->image = eglCreateDRMImageMESA(dpy, image_attribs);
 | 
				
			||||||
 | 
						glGenTextures(1, &data->texture);
 | 
				
			||||||
 | 
						data->dpy = dpy;
 | 
				
			||||||
 | 
						glBindTexture(GL_TEXTURE_2D, data->texture);
 | 
				
			||||||
 | 
						glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, data->image);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						eglExportDRMImageMESA(display->dpy, data->image, &name, NULL, &stride);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						visual = wl_display_get_premultiplied_argb_visual(display->display);
 | 
				
			||||||
 | 
						data->data.buffer =
 | 
				
			||||||
 | 
							wl_drm_create_buffer(display->drm, name, rectangle->width,
 | 
				
			||||||
 | 
									     rectangle->height, stride, visual);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						surface = cairo_gl_surface_create_for_texture(display->device,
 | 
				
			||||||
 | 
											      CAIRO_CONTENT_COLOR_ALPHA,
 | 
				
			||||||
 | 
											      data->texture,
 | 
				
			||||||
 | 
											      rectangle->width,
 | 
				
			||||||
 | 
											      rectangle->height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cairo_surface_set_user_data (surface, &surface_data_key,
 | 
				
			||||||
 | 
									     data, drm_surface_data_destroy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return surface;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cairo_surface_t *
 | 
				
			||||||
 | 
					display_create_drm_surface_from_file(struct display *display,
 | 
				
			||||||
 | 
									     const char *filename,
 | 
				
			||||||
 | 
									     struct rectangle *rect)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						cairo_surface_t *surface;
 | 
				
			||||||
	GdkPixbuf *pixbuf;
 | 
						GdkPixbuf *pixbuf;
 | 
				
			||||||
	GError *error = NULL;
 | 
						GError *error = NULL;
 | 
				
			||||||
	int stride, i;
 | 
						int stride, i;
 | 
				
			||||||
	unsigned char *pixels, *p, *end;
 | 
						unsigned char *pixels, *p, *end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pixbuf = gdk_pixbuf_new_from_file_at_scale(filename,
 | 
						pixbuf = gdk_pixbuf_new_from_file_at_scale(filename,
 | 
				
			||||||
						   width, height,
 | 
											   rect->width, rect->height,
 | 
				
			||||||
						   FALSE, &error);
 | 
											   FALSE, &error);
 | 
				
			||||||
	if (error != NULL)
 | 
						if (error != NULL)
 | 
				
			||||||
		return -1;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!gdk_pixbuf_get_has_alpha(pixbuf) ||
 | 
						if (!gdk_pixbuf_get_has_alpha(pixbuf) ||
 | 
				
			||||||
	    gdk_pixbuf_get_n_channels(pixbuf) != 4) {
 | 
						    gdk_pixbuf_get_n_channels(pixbuf) != 4) {
 | 
				
			||||||
		gdk_pixbuf_unref(pixbuf);
 | 
							gdk_pixbuf_unref(pixbuf);
 | 
				
			||||||
		return -1;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	stride = gdk_pixbuf_get_rowstride(pixbuf);
 | 
						stride = gdk_pixbuf_get_rowstride(pixbuf);
 | 
				
			||||||
	pixels = gdk_pixbuf_get_pixels(pixbuf);
 | 
						pixels = gdk_pixbuf_get_pixels(pixbuf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < height; i++) {
 | 
						for (i = 0; i < rect->height; i++) {
 | 
				
			||||||
		p = pixels + i * stride;
 | 
							p = pixels + i * stride;
 | 
				
			||||||
		end = p + width * 4;
 | 
							end = p + rect->width * 4;
 | 
				
			||||||
		while (p < end) {
 | 
							while (p < end) {
 | 
				
			||||||
			unsigned int t;
 | 
								unsigned int t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -189,12 +274,181 @@ texture_from_png(const char *filename, int width, int height)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						surface = display_create_drm_surface(display, rect);
 | 
				
			||||||
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
 | 
						glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
 | 
				
			||||||
		     width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
 | 
							     rect->width, rect->height,
 | 
				
			||||||
 | 
							     0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	gdk_pixbuf_unref(pixbuf);
 | 
						gdk_pixbuf_unref(pixbuf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return surface;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wl_buffer *
 | 
				
			||||||
 | 
					display_get_buffer_for_surface(struct display *display,
 | 
				
			||||||
 | 
								       cairo_surface_t *surface)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct surface_data *data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						data = cairo_surface_get_user_data (surface, &surface_data_key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return data->buffer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct shm_surface_data {
 | 
				
			||||||
 | 
						struct surface_data data;
 | 
				
			||||||
 | 
						void *map;
 | 
				
			||||||
 | 
						size_t length;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					shm_surface_data_destroy(void *p)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct shm_surface_data *data = p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wl_buffer_destroy(data->data.buffer);
 | 
				
			||||||
 | 
						munmap(data->map, data->length);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cairo_surface_t *
 | 
				
			||||||
 | 
					display_create_shm_surface(struct display *display,
 | 
				
			||||||
 | 
								   struct rectangle *rectangle)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct shm_surface_data *data;
 | 
				
			||||||
 | 
						cairo_surface_t *surface;
 | 
				
			||||||
 | 
						struct wl_visual *visual;
 | 
				
			||||||
 | 
						int stride, alloc, fd;
 | 
				
			||||||
 | 
						char filename[] = "/tmp/wayland-shm-XXXXXX";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						data = malloc(sizeof *data);
 | 
				
			||||||
 | 
						if (data == NULL)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32,
 | 
				
			||||||
 | 
											rectangle->width);
 | 
				
			||||||
 | 
						data->length = stride * rectangle->height;
 | 
				
			||||||
 | 
						fd = mkstemp(filename);
 | 
				
			||||||
 | 
						if (fd < 0) {
 | 
				
			||||||
 | 
							fprintf(stderr, "open %s failed: %m", filename);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (ftruncate(fd, data->length) < 0) {
 | 
				
			||||||
 | 
							fprintf(stderr, "ftruncate failed: %m");
 | 
				
			||||||
 | 
							close(fd);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						data->map = mmap(NULL, data->length,
 | 
				
			||||||
 | 
								 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
 | 
				
			||||||
 | 
						unlink(filename);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (data->map == MAP_FAILED) {
 | 
				
			||||||
 | 
							fprintf(stderr, "mmap failed: %m");
 | 
				
			||||||
 | 
							close(fd);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						surface = cairo_image_surface_create_for_data (data->map,
 | 
				
			||||||
 | 
											       CAIRO_FORMAT_ARGB32,
 | 
				
			||||||
 | 
											       rectangle->width,
 | 
				
			||||||
 | 
											       rectangle->height,
 | 
				
			||||||
 | 
											       stride);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cairo_surface_set_user_data (surface, &surface_data_key,
 | 
				
			||||||
 | 
									     data, shm_surface_data_destroy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						visual = wl_display_get_premultiplied_argb_visual(display->display);
 | 
				
			||||||
 | 
						data->data.buffer = wl_shm_create_buffer(display->shm,
 | 
				
			||||||
 | 
											 fd,
 | 
				
			||||||
 | 
											 rectangle->width,
 | 
				
			||||||
 | 
											 rectangle->height,
 | 
				
			||||||
 | 
											 stride, visual);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						close(fd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return surface;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cairo_surface_t *
 | 
				
			||||||
 | 
					display_create_shm_surface_from_file(struct display *display,
 | 
				
			||||||
 | 
									     const char *filename,
 | 
				
			||||||
 | 
									     struct rectangle *rect)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						cairo_surface_t *surface;
 | 
				
			||||||
 | 
						GdkPixbuf *pixbuf;
 | 
				
			||||||
 | 
						GError *error = NULL;
 | 
				
			||||||
 | 
						int stride, i;
 | 
				
			||||||
 | 
						unsigned char *pixels, *p, *end, *dest_data;
 | 
				
			||||||
 | 
						int dest_stride;
 | 
				
			||||||
 | 
						uint32_t *d;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pixbuf = gdk_pixbuf_new_from_file_at_scale(filename,
 | 
				
			||||||
 | 
											   rect->width, rect->height,
 | 
				
			||||||
 | 
											   FALSE, &error);
 | 
				
			||||||
 | 
						if (error != NULL)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!gdk_pixbuf_get_has_alpha(pixbuf) ||
 | 
				
			||||||
 | 
						    gdk_pixbuf_get_n_channels(pixbuf) != 4) {
 | 
				
			||||||
 | 
							gdk_pixbuf_unref(pixbuf);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						stride = gdk_pixbuf_get_rowstride(pixbuf);
 | 
				
			||||||
 | 
						pixels = gdk_pixbuf_get_pixels(pixbuf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						surface = display_create_shm_surface(display, rect);
 | 
				
			||||||
 | 
						dest_data = cairo_image_surface_get_data (surface);
 | 
				
			||||||
 | 
						dest_stride = cairo_image_surface_get_stride (surface);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < rect->height; i++) {
 | 
				
			||||||
 | 
							d = (uint32_t *) (dest_data + i * dest_stride);
 | 
				
			||||||
 | 
							p = pixels + i * stride;
 | 
				
			||||||
 | 
							end = p + rect->width * 4;
 | 
				
			||||||
 | 
							while (p < end) {
 | 
				
			||||||
 | 
								unsigned int t;
 | 
				
			||||||
 | 
								unsigned char a, r, g, b;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MULT(_d,c,a,t) \
 | 
				
			||||||
 | 
						do { t = c * a + 0x7f; _d = ((t >> 8) + t) >> 8; } while (0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								a = p[3];
 | 
				
			||||||
 | 
								MULT(r, p[0], a, t);
 | 
				
			||||||
 | 
								MULT(g, p[1], a, t);
 | 
				
			||||||
 | 
								MULT(b, p[2], a, t);
 | 
				
			||||||
 | 
								p += 4;
 | 
				
			||||||
 | 
								*d++ = (a << 24) | (r << 16) | (g << 8) | b;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gdk_pixbuf_unref(pixbuf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return surface;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cairo_surface_t *
 | 
				
			||||||
 | 
					display_create_surface(struct display *display,
 | 
				
			||||||
 | 
							       struct rectangle *rectangle)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#ifdef HAVE_CAIRO_GL
 | 
				
			||||||
 | 
						display_create_drm_surface(display, rectangle);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						display_create_shm_surface(display, rectangle);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cairo_surface_t *
 | 
				
			||||||
 | 
					display_create_surface_from_file(struct display *display,
 | 
				
			||||||
 | 
									 const char *filename,
 | 
				
			||||||
 | 
									 struct rectangle *rectangle)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#ifdef HAVE_CAIRO_GL
 | 
				
			||||||
 | 
						display_create_drm_surface_from_file(display, filename, rectangle);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						display_create_shm_surface_from_file(display, filename, rectangle);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct {
 | 
					static const struct {
 | 
				
			||||||
| 
						 | 
					@ -229,96 +483,13 @@ create_pointer_surfaces(struct display *display)
 | 
				
			||||||
	rect.height = height;
 | 
						rect.height = height;
 | 
				
			||||||
	for (i = 0; i < count; i++) {
 | 
						for (i = 0; i < count; i++) {
 | 
				
			||||||
		display->pointer_surfaces[i] =
 | 
							display->pointer_surfaces[i] =
 | 
				
			||||||
			display_create_surface(display, &rect);
 | 
								display_create_surface_from_file(display,
 | 
				
			||||||
		texture_from_png(pointer_images[i].filename, width, height);
 | 
												 pointer_images[i].filename,
 | 
				
			||||||
 | 
												 &rect);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const cairo_user_data_key_t surface_data_key;
 | 
					 | 
				
			||||||
struct surface_data {
 | 
					 | 
				
			||||||
	EGLImageKHR image;
 | 
					 | 
				
			||||||
	GLuint texture;
 | 
					 | 
				
			||||||
	EGLDisplay dpy;
 | 
					 | 
				
			||||||
	struct wl_buffer *buffer;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
surface_data_destroy(void *p)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct surface_data *data = p;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	glDeleteTextures(1, &data->texture);
 | 
					 | 
				
			||||||
	eglDestroyImageKHR(data->dpy, data->image);
 | 
					 | 
				
			||||||
	if (data->buffer)
 | 
					 | 
				
			||||||
		wl_buffer_destroy(data->buffer);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
cairo_surface_t *
 | 
					 | 
				
			||||||
display_create_surface(struct display *display,
 | 
					 | 
				
			||||||
		       struct rectangle *rectangle)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct surface_data *data;
 | 
					 | 
				
			||||||
	EGLDisplay dpy = display->dpy;
 | 
					 | 
				
			||||||
	cairo_surface_t *surface;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	EGLint image_attribs[] = {
 | 
					 | 
				
			||||||
		EGL_WIDTH,		0,
 | 
					 | 
				
			||||||
		EGL_HEIGHT,		0,
 | 
					 | 
				
			||||||
		EGL_DRM_BUFFER_FORMAT_MESA,	EGL_DRM_BUFFER_FORMAT_ARGB32_MESA,
 | 
					 | 
				
			||||||
		EGL_DRM_BUFFER_USE_MESA,	EGL_DRM_BUFFER_USE_SCANOUT_MESA,
 | 
					 | 
				
			||||||
		EGL_NONE
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	data = malloc(sizeof *data);
 | 
					 | 
				
			||||||
	image_attribs[1] = rectangle->width;
 | 
					 | 
				
			||||||
	image_attribs[3] = rectangle->height;
 | 
					 | 
				
			||||||
	data->image = eglCreateDRMImageMESA(dpy, image_attribs);
 | 
					 | 
				
			||||||
	glGenTextures(1, &data->texture);
 | 
					 | 
				
			||||||
	data->dpy = dpy;
 | 
					 | 
				
			||||||
	glBindTexture(GL_TEXTURE_2D, data->texture);
 | 
					 | 
				
			||||||
	glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, data->image);
 | 
					 | 
				
			||||||
	data->buffer = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	surface = cairo_gl_surface_create_for_texture(display->device,
 | 
					 | 
				
			||||||
						      CAIRO_CONTENT_COLOR_ALPHA,
 | 
					 | 
				
			||||||
						      data->texture,
 | 
					 | 
				
			||||||
						      rectangle->width,
 | 
					 | 
				
			||||||
						      rectangle->height);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cairo_surface_set_user_data (surface, &surface_data_key,
 | 
					 | 
				
			||||||
				     data, surface_data_destroy);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return surface;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct wl_buffer *
 | 
					 | 
				
			||||||
display_get_buffer_for_surface(struct display *display,
 | 
					 | 
				
			||||||
			       cairo_surface_t *surface)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct surface_data *data;
 | 
					 | 
				
			||||||
	struct wl_visual *visual;
 | 
					 | 
				
			||||||
	struct wl_buffer *buffer;
 | 
					 | 
				
			||||||
	EGLint name, stride;
 | 
					 | 
				
			||||||
	int width, height;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	data = cairo_surface_get_user_data (surface, &surface_data_key);
 | 
					 | 
				
			||||||
	if (data->buffer)
 | 
					 | 
				
			||||||
		return data->buffer;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	width = cairo_gl_surface_get_width (surface);
 | 
					 | 
				
			||||||
	height = cairo_gl_surface_get_height (surface);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	eglExportDRMImageMESA(display->dpy, data->image, &name, NULL, &stride);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	visual = wl_display_get_premultiplied_argb_visual(display->display);
 | 
					 | 
				
			||||||
	buffer = wl_drm_create_buffer(display->drm,
 | 
					 | 
				
			||||||
				      name, width, height, stride, visual);
 | 
					 | 
				
			||||||
	data->buffer = buffer;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return buffer;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
cairo_surface_t *
 | 
					cairo_surface_t *
 | 
				
			||||||
display_get_pointer_surface(struct display *display, int pointer,
 | 
					display_get_pointer_surface(struct display *display, int pointer,
 | 
				
			||||||
			    int *width, int *height,
 | 
								    int *width, int *height,
 | 
				
			||||||
| 
						 | 
					@ -382,6 +553,23 @@ window_flush(struct window *window)
 | 
				
			||||||
	       window_attach_surface(window);
 | 
						       window_attach_surface(window);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					window_create_surface(struct window *window, struct rectangle *allocation)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						switch (window->buffer_type) {
 | 
				
			||||||
 | 
					#ifdef HAVE_CAIRO_GL
 | 
				
			||||||
 | 
						case WINDOW_BUFFER_TYPE_DRM:
 | 
				
			||||||
 | 
							window->cairo_surface =
 | 
				
			||||||
 | 
								display_create_surface(window->display, allocation);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						case WINDOW_BUFFER_TYPE_SHM:
 | 
				
			||||||
 | 
							window->cairo_surface =
 | 
				
			||||||
 | 
								display_create_shm_surface(window->display, allocation);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
window_draw_decorations(struct window *window)
 | 
					window_draw_decorations(struct window *window)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -391,8 +579,8 @@ window_draw_decorations(struct window *window)
 | 
				
			||||||
	cairo_surface_t *frame;
 | 
						cairo_surface_t *frame;
 | 
				
			||||||
	int width, height, shadow_dx = 3, shadow_dy = 3;
 | 
						int width, height, shadow_dx = 3, shadow_dy = 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	window->cairo_surface =
 | 
						window_create_surface(window, &window->allocation);
 | 
				
			||||||
		display_create_surface(window->display, &window->allocation);
 | 
					
 | 
				
			||||||
	width = window->allocation.width;
 | 
						width = window->allocation.width;
 | 
				
			||||||
	height = window->allocation.height;
 | 
						height = window->allocation.height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -447,8 +635,7 @@ display_flush_cairo_device(struct display *display)
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
window_draw_fullscreen(struct window *window)
 | 
					window_draw_fullscreen(struct window *window)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	window->cairo_surface =
 | 
						window_create_surface(window, &window->allocation);
 | 
				
			||||||
		display_create_surface(window->display, &window->allocation);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
| 
						 | 
					@ -985,6 +1172,13 @@ window_move(struct window *window, int32_t x, int32_t y)
 | 
				
			||||||
		       window->allocation.height);
 | 
							       window->allocation.height);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					window_damage(struct window *window, int32_t x, int32_t y,
 | 
				
			||||||
 | 
						      int32_t width, int32_t height)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						wl_surface_damage(window->surface, x, y, width, height);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct window *
 | 
					struct window *
 | 
				
			||||||
window_create(struct display *display, const char *title,
 | 
					window_create(struct display *display, const char *title,
 | 
				
			||||||
	      int32_t x, int32_t y, int32_t width, int32_t height)
 | 
						      int32_t x, int32_t y, int32_t width, int32_t height)
 | 
				
			||||||
| 
						 | 
					@ -1007,12 +1201,24 @@ window_create(struct display *display, const char *title,
 | 
				
			||||||
	window->margin = 16;
 | 
						window->margin = 16;
 | 
				
			||||||
	window->decoration = 1;
 | 
						window->decoration = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef HAVE_CAIRO_GL
 | 
				
			||||||
 | 
						window->buffer_type = WINDOW_BUFFER_TYPE_DRM;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						window->buffer_type = WINDOW_BUFFER_TYPE_SHM;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl_surface_set_user_data(window->surface, window);
 | 
						wl_surface_set_user_data(window->surface, window);
 | 
				
			||||||
	wl_list_insert(display->window_list.prev, &window->link);
 | 
						wl_list_insert(display->window_list.prev, &window->link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return window;
 | 
						return window;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					window_set_buffer_type(struct window *window, enum window_buffer_type type)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						window->buffer_type = type;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
drm_handle_device(void *data, struct wl_drm *drm, const char *device)
 | 
					drm_handle_device(void *data, struct wl_drm *drm, const char *device)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -1091,6 +1297,8 @@ display_handle_global(struct wl_display *display, uint32_t id,
 | 
				
			||||||
	} else if (strcmp(interface, "drm") == 0) {
 | 
						} else if (strcmp(interface, "drm") == 0) {
 | 
				
			||||||
		d->drm = wl_drm_create(display, id);
 | 
							d->drm = wl_drm_create(display, id);
 | 
				
			||||||
		wl_drm_add_listener(d->drm, &drm_listener, d);
 | 
							wl_drm_add_listener(d->drm, &drm_listener, d);
 | 
				
			||||||
 | 
						} else if (strcmp(interface, "shm") == 0) {
 | 
				
			||||||
 | 
							d->shm = wl_shm_create(display, id);
 | 
				
			||||||
	} else if (strcmp(interface, "drag_offer") == 0) {
 | 
						} else if (strcmp(interface, "drag_offer") == 0) {
 | 
				
			||||||
		offer = wl_drag_offer_create(display, id);
 | 
							offer = wl_drag_offer_create(display, id);
 | 
				
			||||||
		d->drag_offer_handler(offer, d);
 | 
							d->drag_offer_handler(offer, d);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -138,6 +138,10 @@ window_schedule_redraw(struct window *window);
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
window_move(struct window *window, int32_t x, int32_t y);
 | 
					window_move(struct window *window, int32_t x, int32_t y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					window_damage(struct window *window, int32_t x, int32_t y,
 | 
				
			||||||
 | 
						      int32_t width, int32_t height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cairo_surface_t *
 | 
					cairo_surface_t *
 | 
				
			||||||
window_get_surface(struct window *window);
 | 
					window_get_surface(struct window *window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -149,6 +153,14 @@ window_copy_surface(struct window *window,
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
window_flush(struct window *window);
 | 
					window_flush(struct window *window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum window_buffer_type {
 | 
				
			||||||
 | 
						WINDOW_BUFFER_TYPE_DRM,
 | 
				
			||||||
 | 
						WINDOW_BUFFER_TYPE_SHM,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					window_set_buffer_type(struct window *window, enum window_buffer_type type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
window_set_fullscreen(struct window *window, int fullscreen);
 | 
					window_set_fullscreen(struct window *window, int fullscreen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -52,6 +52,12 @@ shm_buffer_attach(struct wl_buffer *buffer_base, struct wl_surface *surface)
 | 
				
			||||||
		(struct wlsc_shm_buffer *) buffer_base;
 | 
							(struct wlsc_shm_buffer *) buffer_base;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	glBindTexture(GL_TEXTURE_2D, es->texture);
 | 
						glBindTexture(GL_TEXTURE_2D, es->texture);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Unbind any EGLImage texture that may be bound, so we don't
 | 
				
			||||||
 | 
						 * overwrite it.*/
 | 
				
			||||||
 | 
						glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
 | 
				
			||||||
 | 
							     0, 0, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
 | 
						glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
 | 
				
			||||||
		     buffer->base.width, buffer->base.height, 0,
 | 
							     buffer->base.width, buffer->base.height, 0,
 | 
				
			||||||
		     GL_BGRA_EXT, GL_UNSIGNED_BYTE, buffer->data);
 | 
							     GL_BGRA_EXT, GL_UNSIGNED_BYTE, buffer->data);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,7 @@ AM_INIT_AUTOMAKE([foreign dist-bzip2])
 | 
				
			||||||
AC_PROG_CC
 | 
					AC_PROG_CC
 | 
				
			||||||
AC_PROG_LIBTOOL
 | 
					AC_PROG_LIBTOOL
 | 
				
			||||||
AC_CONFIG_MACRO_DIR([m4])
 | 
					AC_CONFIG_MACRO_DIR([m4])
 | 
				
			||||||
 | 
					AC_CONFIG_HEADERS([config.h])
 | 
				
			||||||
AM_SILENT_RULES([yes])
 | 
					AM_SILENT_RULES([yes])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PKG_PROG_PKG_CONFIG()
 | 
					PKG_PROG_PKG_CONFIG()
 | 
				
			||||||
| 
						 | 
					@ -10,8 +11,12 @@ PKG_CHECK_MODULES(FFI, [libffi])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PKG_CHECK_MODULES(COMPOSITOR,
 | 
					PKG_CHECK_MODULES(COMPOSITOR,
 | 
				
			||||||
		  [egl glesv2 gdk-pixbuf-2.0 libudev >= 136 libdrm >= 2.4.17] xcb-dri2 xcb-xfixes)
 | 
							  [egl glesv2 gdk-pixbuf-2.0 libudev >= 136 libdrm >= 2.4.17] xcb-dri2 xcb-xfixes)
 | 
				
			||||||
PKG_CHECK_MODULES(CLIENT, [egl gl cairo-gl gdk-pixbuf-2.0 glib-2.0 gobject-2.0 xkbcommon libdrm])
 | 
					PKG_CHECK_MODULES(CLIENT, [egl gl cairo gdk-pixbuf-2.0 glib-2.0 gobject-2.0 xkbcommon libdrm])
 | 
				
			||||||
PKG_CHECK_MODULES(POPPLER, [poppler-glib gdk-2.0])
 | 
					PKG_CHECK_MODULES(POPPLER, [poppler-glib gdk-2.0])
 | 
				
			||||||
 | 
					PKG_CHECK_MODULES(CAIRO_GL, [cairo-gl],
 | 
				
			||||||
 | 
							  [have_cairo_gl=yes], [have_cairo_gl=no])
 | 
				
			||||||
 | 
					AS_IF([test "x$have_cairo_gl" = "xyes"],
 | 
				
			||||||
 | 
					      [AC_DEFINE([HAVE_CAIRO_GL], [1], [Have cairo-gl])])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if test $CC = gcc; then
 | 
					if test $CC = gcc; then
 | 
				
			||||||
	GCC_CFLAGS="-Wall -g -Wstrict-prototypes -Wmissing-prototypes -fvisibility=hidden"
 | 
						GCC_CFLAGS="-Wall -g -Wstrict-prototypes -Wmissing-prototypes -fvisibility=hidden"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue