mirror of
				https://gitlab.freedesktop.org/wlroots/wlroots.git
				synced 2025-11-03 09:01:40 -05:00 
			
		
		
		
	Merge branch 'master' into xdg-positioner
This commit is contained in:
		
						commit
						30b8fb5572
					
				
					 75 changed files with 3011 additions and 1897 deletions
				
			
		| 
						 | 
					@ -173,7 +173,7 @@ struct wlr_backend *wlr_drm_backend_create(struct wl_display *display,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!wlr_egl_bind_display(&drm->renderer.egl, display)) {
 | 
						if (!wlr_egl_bind_display(&drm->renderer.egl, display)) {
 | 
				
			||||||
		wlr_log(L_INFO, "Failed to bind egl/wl display: %s", egl_error());
 | 
							wlr_log(L_INFO, "Failed to bind egl/wl display");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	drm->display_destroy.notify = handle_display_destroy;
 | 
						drm->display_destroy.notify = handle_display_destroy;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,9 +15,9 @@
 | 
				
			||||||
#include <wayland-util.h>
 | 
					#include <wayland-util.h>
 | 
				
			||||||
#include <wlr/backend/interface.h>
 | 
					#include <wlr/backend/interface.h>
 | 
				
			||||||
#include <wlr/interfaces/wlr_output.h>
 | 
					#include <wlr/interfaces/wlr_output.h>
 | 
				
			||||||
#include <wlr/render.h>
 | 
					 | 
				
			||||||
#include <wlr/render/gles2.h>
 | 
					#include <wlr/render/gles2.h>
 | 
				
			||||||
#include <wlr/render/matrix.h>
 | 
					#include <wlr/render/wlr_renderer.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_matrix.h>
 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					#include <wlr/util/log.h>
 | 
				
			||||||
#include <xf86drm.h>
 | 
					#include <xf86drm.h>
 | 
				
			||||||
#include <xf86drmMode.h>
 | 
					#include <xf86drmMode.h>
 | 
				
			||||||
| 
						 | 
					@ -582,13 +582,10 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output,
 | 
				
			||||||
			return false;
 | 
								return false;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// OpenGL will read the pixels out upside down,
 | 
							enum wl_output_transform transform =
 | 
				
			||||||
		// so we need to flip the image vertically
 | 
								wlr_output_transform_invert(output->transform);
 | 
				
			||||||
		enum wl_output_transform transform = wlr_output_transform_compose(
 | 
							wlr_matrix_projection(plane->matrix, plane->surf.width,
 | 
				
			||||||
			wlr_output_transform_invert(output->transform),
 | 
								plane->surf.height, transform);
 | 
				
			||||||
			WL_OUTPUT_TRANSFORM_FLIPPED_180);
 | 
					 | 
				
			||||||
		wlr_matrix_texture(plane->matrix, plane->surf.width, plane->surf.height,
 | 
					 | 
				
			||||||
			transform);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		plane->wlr_tex =
 | 
							plane->wlr_tex =
 | 
				
			||||||
			wlr_render_texture_create(plane->surf.renderer->wlr_rend);
 | 
								wlr_render_texture_create(plane->surf.renderer->wlr_rend);
 | 
				
			||||||
| 
						 | 
					@ -643,20 +640,14 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output,
 | 
				
			||||||
		wlr_texture_upload_pixels(plane->wlr_tex, WL_SHM_FORMAT_ARGB8888,
 | 
							wlr_texture_upload_pixels(plane->wlr_tex, WL_SHM_FORMAT_ARGB8888,
 | 
				
			||||||
			stride, width, height, buf);
 | 
								stride, width, height, buf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		glViewport(0, 0, plane->surf.width, plane->surf.height);
 | 
							struct wlr_renderer *rend = plane->surf.renderer->wlr_rend;
 | 
				
			||||||
		glClearColor(0.0, 0.0, 0.0, 0.0);
 | 
							wlr_renderer_begin(rend, plane->surf.width, plane->surf.height);
 | 
				
			||||||
		glClear(GL_COLOR_BUFFER_BIT);
 | 
							wlr_renderer_clear(rend, (float[]){ 0.0, 0.0, 0.0, 0.0 });
 | 
				
			||||||
 | 
							wlr_render_texture(rend, plane->wlr_tex, plane->matrix, 0, 0, 1.0f);
 | 
				
			||||||
 | 
							wlr_renderer_end(rend);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		float matrix[16];
 | 
							wlr_renderer_read_pixels(rend, WL_SHM_FORMAT_ARGB8888, bo_stride,
 | 
				
			||||||
		wlr_texture_get_matrix(plane->wlr_tex, &matrix, &plane->matrix, 0, 0);
 | 
								plane->surf.width, plane->surf.height, 0, 0, 0, 0, bo_data);
 | 
				
			||||||
		wlr_render_with_matrix(plane->surf.renderer->wlr_rend, plane->wlr_tex,
 | 
					 | 
				
			||||||
			&matrix, 1.0f);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		glFinish();
 | 
					 | 
				
			||||||
		glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, bo_stride);
 | 
					 | 
				
			||||||
		glReadPixels(0, 0, plane->surf.width, plane->surf.height, GL_BGRA_EXT,
 | 
					 | 
				
			||||||
			GL_UNSIGNED_BYTE, bo_data);
 | 
					 | 
				
			||||||
		glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		wlr_drm_surface_swap_buffers(&plane->surf, NULL);
 | 
							wlr_drm_surface_swap_buffers(&plane->surf, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,15 +1,15 @@
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
#include <EGL/egl.h>
 | 
					#include <EGL/egl.h>
 | 
				
			||||||
#include <EGL/eglext.h>
 | 
					#include <EGL/eglext.h>
 | 
				
			||||||
#include <gbm.h>
 | 
					#include <gbm.h>
 | 
				
			||||||
#include <GLES2/gl2.h>
 | 
					 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <unistd.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
#include <wayland-util.h>
 | 
					#include <wayland-util.h>
 | 
				
			||||||
#include <wlr/render.h>
 | 
					 | 
				
			||||||
#include <wlr/render/egl.h>
 | 
					#include <wlr/render/egl.h>
 | 
				
			||||||
#include <wlr/render/gles2.h>
 | 
					#include <wlr/render/gles2.h>
 | 
				
			||||||
#include <wlr/render/matrix.h>
 | 
					#include <wlr/render/wlr_renderer.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_matrix.h>
 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					#include <wlr/util/log.h>
 | 
				
			||||||
#include "backend/drm/drm.h"
 | 
					#include "backend/drm/drm.h"
 | 
				
			||||||
#include "glapi.h"
 | 
					#include "glapi.h"
 | 
				
			||||||
| 
						 | 
					@ -106,9 +106,6 @@ void wlr_drm_surface_finish(struct wlr_drm_surface *surf) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	eglMakeCurrent(surf->renderer->egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE,
 | 
					 | 
				
			||||||
		EGL_NO_CONTEXT);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (surf->front) {
 | 
						if (surf->front) {
 | 
				
			||||||
		gbm_surface_release_buffer(surf->gbm, surf->front);
 | 
							gbm_surface_release_buffer(surf->gbm, surf->front);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -150,9 +147,10 @@ struct gbm_bo *wlr_drm_surface_get_front(struct wlr_drm_surface *surf) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_drm_surface_make_current(surf, NULL);
 | 
						wlr_drm_surface_make_current(surf, NULL);
 | 
				
			||||||
	glViewport(0, 0, surf->width, surf->height);
 | 
						struct wlr_renderer *renderer = surf->renderer->wlr_rend;
 | 
				
			||||||
	glClearColor(0.0, 0.0, 0.0, 1.0);
 | 
						wlr_renderer_begin(renderer, surf->width, surf->height);
 | 
				
			||||||
	glClear(GL_COLOR_BUFFER_BIT);
 | 
						wlr_renderer_clear(renderer, (float[]){ 0.0, 0.0, 0.0, 1.0 });
 | 
				
			||||||
 | 
						wlr_renderer_end(renderer);
 | 
				
			||||||
	return wlr_drm_surface_swap_buffers(surf, NULL);
 | 
						return wlr_drm_surface_swap_buffers(surf, NULL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -177,12 +175,15 @@ static void free_eglimage(struct gbm_bo *bo, void *data) {
 | 
				
			||||||
	free(tex);
 | 
						free(tex);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct wlr_texture *get_tex_for_bo(struct wlr_drm_renderer *renderer, struct gbm_bo *bo) {
 | 
					static struct wlr_texture *get_tex_for_bo(struct wlr_drm_renderer *renderer,
 | 
				
			||||||
 | 
							struct gbm_bo *bo) {
 | 
				
			||||||
	struct tex *tex = gbm_bo_get_user_data(bo);
 | 
						struct tex *tex = gbm_bo_get_user_data(bo);
 | 
				
			||||||
	if (tex) {
 | 
						if (tex) {
 | 
				
			||||||
		return tex->tex;
 | 
							return tex->tex;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO: use wlr_texture_upload_dmabuf instead
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tex = malloc(sizeof(*tex));
 | 
						tex = malloc(sizeof(*tex));
 | 
				
			||||||
	if (!tex) {
 | 
						if (!tex) {
 | 
				
			||||||
		wlr_log_errno(L_ERROR, "Allocation failed");
 | 
							wlr_log_errno(L_ERROR, "Allocation failed");
 | 
				
			||||||
| 
						 | 
					@ -209,7 +210,7 @@ static struct wlr_texture *get_tex_for_bo(struct wlr_drm_renderer *renderer, str
 | 
				
			||||||
	tex->img = eglCreateImageKHR(renderer->egl.display, EGL_NO_CONTEXT,
 | 
						tex->img = eglCreateImageKHR(renderer->egl.display, EGL_NO_CONTEXT,
 | 
				
			||||||
		EGL_LINUX_DMA_BUF_EXT, NULL, attribs);
 | 
							EGL_LINUX_DMA_BUF_EXT, NULL, attribs);
 | 
				
			||||||
	if (!tex->img) {
 | 
						if (!tex->img) {
 | 
				
			||||||
		wlr_log(L_ERROR, "Failed to create EGL image: %s", egl_error());
 | 
							wlr_log(L_ERROR, "Failed to create EGL image");
 | 
				
			||||||
		abort();
 | 
							abort();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -226,26 +227,23 @@ struct gbm_bo *wlr_drm_surface_mgpu_copy(struct wlr_drm_surface *dest,
 | 
				
			||||||
	wlr_drm_surface_make_current(dest, NULL);
 | 
						wlr_drm_surface_make_current(dest, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_texture *tex = get_tex_for_bo(dest->renderer, src);
 | 
						struct wlr_texture *tex = get_tex_for_bo(dest->renderer, src);
 | 
				
			||||||
 | 
						assert(tex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static const float matrix[16] = {
 | 
						float mat[9];
 | 
				
			||||||
		[0] = 2.0f,
 | 
						wlr_matrix_projection(mat, 1, 1, WL_OUTPUT_TRANSFORM_FLIPPED_180);
 | 
				
			||||||
		[3] = -1.0f,
 | 
					 | 
				
			||||||
		[5] = 2.0f,
 | 
					 | 
				
			||||||
		[7] = -1.0f,
 | 
					 | 
				
			||||||
		[10] = 1.0f,
 | 
					 | 
				
			||||||
		[15] = 1.0f,
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	glViewport(0, 0, dest->width, dest->height);
 | 
						struct wlr_renderer *renderer = dest->renderer->wlr_rend;
 | 
				
			||||||
	glClearColor(0.0, 0.0, 0.0, 1.0);
 | 
						wlr_renderer_begin(renderer, dest->width, dest->height);
 | 
				
			||||||
	glClear(GL_COLOR_BUFFER_BIT);
 | 
						wlr_renderer_clear(renderer, (float[]){ 0.0, 0.0, 0.0, 1.0 });
 | 
				
			||||||
	wlr_render_with_matrix(dest->renderer->wlr_rend, tex, &matrix, 1.0f);
 | 
						wlr_render_texture_with_matrix(renderer, tex, mat, 1.0f);
 | 
				
			||||||
 | 
						wlr_renderer_end(renderer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return wlr_drm_surface_swap_buffers(dest, NULL);
 | 
						return wlr_drm_surface_swap_buffers(dest, NULL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool wlr_drm_plane_surfaces_init(struct wlr_drm_plane *plane, struct wlr_drm_backend *drm,
 | 
					bool wlr_drm_plane_surfaces_init(struct wlr_drm_plane *plane,
 | 
				
			||||||
		int32_t width, uint32_t height, uint32_t format) {
 | 
							struct wlr_drm_backend *drm, int32_t width, uint32_t height,
 | 
				
			||||||
 | 
							uint32_t format) {
 | 
				
			||||||
	if (!drm->parent) {
 | 
						if (!drm->parent) {
 | 
				
			||||||
		return wlr_drm_surface_init(&plane->surf, &drm->renderer, width, height,
 | 
							return wlr_drm_surface_init(&plane->surf, &drm->renderer, width, height,
 | 
				
			||||||
			format, GBM_BO_USE_SCANOUT);
 | 
								format, GBM_BO_USE_SCANOUT);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,8 +1,8 @@
 | 
				
			||||||
#include <EGL/egl.h>
 | 
					#include <EGL/egl.h>
 | 
				
			||||||
#include <EGL/eglext.h>
 | 
					#include <EGL/eglext.h>
 | 
				
			||||||
#include <GLES2/gl2.h>
 | 
					 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <wlr/interfaces/wlr_output.h>
 | 
					#include <wlr/interfaces/wlr_output.h>
 | 
				
			||||||
 | 
					#include <wlr/render/wlr_renderer.h>
 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					#include <wlr/util/log.h>
 | 
				
			||||||
#include "backend/headless.h"
 | 
					#include "backend/headless.h"
 | 
				
			||||||
#include "util/signal.h"
 | 
					#include "util/signal.h"
 | 
				
			||||||
| 
						 | 
					@ -13,7 +13,7 @@ static EGLSurface egl_create_surface(struct wlr_egl *egl, unsigned int width,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	EGLSurface surf = eglCreatePbufferSurface(egl->display, egl->config, attribs);
 | 
						EGLSurface surf = eglCreatePbufferSurface(egl->display, egl->config, attribs);
 | 
				
			||||||
	if (surf == EGL_NO_SURFACE) {
 | 
						if (surf == EGL_NO_SURFACE) {
 | 
				
			||||||
		wlr_log(L_ERROR, "Failed to create EGL surface: %s", egl_error());
 | 
							wlr_log(L_ERROR, "Failed to create EGL surface");
 | 
				
			||||||
		return EGL_NO_SURFACE;
 | 
							return EGL_NO_SURFACE;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return surf;
 | 
						return surf;
 | 
				
			||||||
| 
						 | 
					@ -120,16 +120,14 @@ struct wlr_output *wlr_headless_add_output(struct wlr_backend *wlr_backend,
 | 
				
			||||||
	snprintf(wlr_output->name, sizeof(wlr_output->name), "HEADLESS-%d",
 | 
						snprintf(wlr_output->name, sizeof(wlr_output->name), "HEADLESS-%d",
 | 
				
			||||||
		wl_list_length(&backend->outputs) + 1);
 | 
							wl_list_length(&backend->outputs) + 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!eglMakeCurrent(output->backend->egl.display,
 | 
						if (!wlr_egl_make_current(&output->backend->egl, output->egl_surface,
 | 
				
			||||||
			output->egl_surface, output->egl_surface,
 | 
								NULL)) {
 | 
				
			||||||
			output->backend->egl.context)) {
 | 
					 | 
				
			||||||
		wlr_log(L_ERROR, "eglMakeCurrent failed: %s", egl_error());
 | 
					 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	glViewport(0, 0, wlr_output->width, wlr_output->height);
 | 
						wlr_renderer_begin(backend->renderer, wlr_output->width, wlr_output->height);
 | 
				
			||||||
	glClearColor(1.0, 1.0, 1.0, 1.0);
 | 
						wlr_renderer_clear(backend->renderer, (float[]){ 1.0, 1.0, 1.0, 1.0 });
 | 
				
			||||||
	glClear(GL_COLOR_BUFFER_BIT);
 | 
						wlr_renderer_end(backend->renderer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_event_loop *ev = wl_display_get_event_loop(backend->display);
 | 
						struct wl_event_loop *ev = wl_display_get_event_loop(backend->display);
 | 
				
			||||||
	output->frame_timer = wl_event_loop_add_timer(ev, signal_frame, output);
 | 
						output->frame_timer = wl_event_loop_add_timer(ev, signal_frame, output);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,4 @@
 | 
				
			||||||
#include <assert.h>
 | 
					#include <assert.h>
 | 
				
			||||||
#include <GLES2/gl2.h>
 | 
					 | 
				
			||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
| 
						 | 
					@ -9,6 +8,7 @@
 | 
				
			||||||
#include <unistd.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
#include <wayland-client.h>
 | 
					#include <wayland-client.h>
 | 
				
			||||||
#include <wlr/interfaces/wlr_output.h>
 | 
					#include <wlr/interfaces/wlr_output.h>
 | 
				
			||||||
 | 
					#include <wlr/render/wlr_renderer.h>
 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					#include <wlr/util/log.h>
 | 
				
			||||||
#include "backend/wayland.h"
 | 
					#include "backend/wayland.h"
 | 
				
			||||||
#include "util/signal.h"
 | 
					#include "util/signal.h"
 | 
				
			||||||
| 
						 | 
					@ -313,27 +313,26 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *_backend) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	output->egl_window = wl_egl_window_create(output->surface,
 | 
						output->egl_window = wl_egl_window_create(output->surface,
 | 
				
			||||||
			wlr_output->width, wlr_output->height);
 | 
								wlr_output->width, wlr_output->height);
 | 
				
			||||||
	output->egl_surface = wlr_egl_create_surface(&backend->egl, output->egl_window);
 | 
						output->egl_surface = wlr_egl_create_surface(&backend->egl,
 | 
				
			||||||
 | 
							output->egl_window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl_display_roundtrip(output->backend->remote_display);
 | 
						wl_display_roundtrip(output->backend->remote_display);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// start rendering loop per callbacks by rendering first frame
 | 
						// start rendering loop per callbacks by rendering first frame
 | 
				
			||||||
	if (!eglMakeCurrent(output->backend->egl.display,
 | 
						if (!wlr_egl_make_current(&output->backend->egl, output->egl_surface,
 | 
				
			||||||
		output->egl_surface, output->egl_surface,
 | 
								NULL)) {
 | 
				
			||||||
		output->backend->egl.context)) {
 | 
					 | 
				
			||||||
		wlr_log(L_ERROR, "eglMakeCurrent failed: %s", egl_error());
 | 
					 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	glViewport(0, 0, wlr_output->width, wlr_output->height);
 | 
						wlr_renderer_begin(backend->renderer, wlr_output->width, wlr_output->height);
 | 
				
			||||||
	glClearColor(1.0, 1.0, 1.0, 1.0);
 | 
						wlr_renderer_clear(backend->renderer, (float[]){ 1.0, 1.0, 1.0, 1.0 });
 | 
				
			||||||
	glClear(GL_COLOR_BUFFER_BIT);
 | 
						wlr_renderer_end(backend->renderer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	output->frame_callback = wl_surface_frame(output->surface);
 | 
						output->frame_callback = wl_surface_frame(output->surface);
 | 
				
			||||||
	wl_callback_add_listener(output->frame_callback, &frame_listener, output);
 | 
						wl_callback_add_listener(output->frame_callback, &frame_listener, output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!eglSwapBuffers(output->backend->egl.display, output->egl_surface)) {
 | 
						if (!wlr_egl_swap_buffers(&output->backend->egl, output->egl_surface,
 | 
				
			||||||
		wlr_log(L_ERROR, "eglSwapBuffers failed: %s", egl_error());
 | 
								NULL)) {
 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,6 +26,11 @@ static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer,
 | 
				
			||||||
		// GNOME sends a pointer enter when the surface is being destroyed
 | 
							// GNOME sends a pointer enter when the surface is being destroyed
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (wlr_wl_pointer->current_output) {
 | 
				
			||||||
 | 
							wl_list_remove(&wlr_wl_pointer->output_destroy_listener.link);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						wl_signal_add(&output->wlr_output.events.destroy,
 | 
				
			||||||
 | 
							&wlr_wl_pointer->output_destroy_listener);
 | 
				
			||||||
	wlr_wl_pointer->current_output = output;
 | 
						wlr_wl_pointer->current_output = output;
 | 
				
			||||||
	output->enter_serial = serial;
 | 
						output->enter_serial = serial;
 | 
				
			||||||
	wlr_wl_output_update_cursor(output);
 | 
						wlr_wl_output_update_cursor(output);
 | 
				
			||||||
| 
						 | 
					@ -49,7 +54,7 @@ static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer,
 | 
				
			||||||
	struct wlr_wl_pointer *wlr_wl_pointer =
 | 
						struct wlr_wl_pointer *wlr_wl_pointer =
 | 
				
			||||||
		(struct wlr_wl_pointer *)dev->pointer;
 | 
							(struct wlr_wl_pointer *)dev->pointer;
 | 
				
			||||||
	if (!wlr_wl_pointer->current_output) {
 | 
						if (!wlr_wl_pointer->current_output) {
 | 
				
			||||||
		wlr_log(L_ERROR, "pointer motion event without current output");
 | 
							wlr_log(L_DEBUG, "pointer motion event without current output");
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -231,6 +236,14 @@ static struct wlr_input_device *allocate_device(struct wlr_wl_backend *backend,
 | 
				
			||||||
	return wlr_device;
 | 
						return wlr_device;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void wlr_wl_pointer_handle_output_destroy(struct wl_listener *listener,
 | 
				
			||||||
 | 
							void *data) {
 | 
				
			||||||
 | 
						struct wlr_wl_pointer *wlr_wl_pointer =
 | 
				
			||||||
 | 
							wl_container_of(listener, wlr_wl_pointer, output_destroy_listener);
 | 
				
			||||||
 | 
						wlr_wl_pointer->current_output = NULL;
 | 
				
			||||||
 | 
						wl_list_remove(&wlr_wl_pointer->output_destroy_listener.link);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
 | 
					static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
 | 
				
			||||||
		enum wl_seat_capability caps) {
 | 
							enum wl_seat_capability caps) {
 | 
				
			||||||
	struct wlr_wl_backend *backend = data;
 | 
						struct wlr_wl_backend *backend = data;
 | 
				
			||||||
| 
						 | 
					@ -243,6 +256,8 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
 | 
				
			||||||
			wlr_log(L_ERROR, "Unable to allocate wlr_wl_pointer");
 | 
								wlr_log(L_ERROR, "Unable to allocate wlr_wl_pointer");
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							wlr_wl_pointer->output_destroy_listener.notify =
 | 
				
			||||||
 | 
								wlr_wl_pointer_handle_output_destroy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		struct wlr_input_device *wlr_device;
 | 
							struct wlr_input_device *wlr_device;
 | 
				
			||||||
		if (!(wlr_device = allocate_device(backend, WLR_INPUT_DEVICE_POINTER))) {
 | 
							if (!(wlr_device = allocate_device(backend, WLR_INPUT_DEVICE_POINTER))) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -143,6 +143,7 @@ static bool handle_x11_event(struct wlr_x11_backend *x11, xcb_generic_event_t *e
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		wlr_signal_emit_safe(&x11->pointer.events.motion_absolute, &abs);
 | 
							wlr_signal_emit_safe(&x11->pointer.events.motion_absolute, &abs);
 | 
				
			||||||
 | 
							free(pointer);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	case XCB_CLIENT_MESSAGE: {
 | 
						case XCB_CLIENT_MESSAGE: {
 | 
				
			||||||
| 
						 | 
					@ -317,12 +318,20 @@ static void wlr_x11_backend_destroy(struct wlr_backend *backend) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_signal_emit_safe(&backend->events.destroy, backend);
 | 
						wlr_signal_emit_safe(&backend->events.destroy, backend);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (x11->event_source) {
 | 
				
			||||||
 | 
							wl_event_source_remove(x11->event_source);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	wl_list_remove(&x11->display_destroy.link);
 | 
						wl_list_remove(&x11->display_destroy.link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl_event_source_remove(x11->frame_timer);
 | 
						wl_event_source_remove(x11->frame_timer);
 | 
				
			||||||
	wlr_egl_finish(&x11->egl);
 | 
						wlr_egl_finish(&x11->egl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (x11->xcb_conn) {
 | 
				
			||||||
		xcb_disconnect(x11->xcb_conn);
 | 
							xcb_disconnect(x11->xcb_conn);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (x11->xlib_conn) {
 | 
				
			||||||
 | 
							XCloseDisplay(x11->xlib_conn);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	free(x11);
 | 
						free(x11);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,8 +5,8 @@
 | 
				
			||||||
#include <wayland-client.h>
 | 
					#include <wayland-client.h>
 | 
				
			||||||
#include <wayland-egl.h>
 | 
					#include <wayland-egl.h>
 | 
				
			||||||
#include <wlr/render/egl.h>
 | 
					#include <wlr/render/egl.h>
 | 
				
			||||||
#include "xdg-shell-client-protocol.h"
 | 
					 | 
				
			||||||
#include "idle-inhibit-unstable-v1-client-protocol.h"
 | 
					#include "idle-inhibit-unstable-v1-client-protocol.h"
 | 
				
			||||||
 | 
					#include "xdg-shell-client-protocol.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/input-event-codes.h>
 | 
					#include <linux/input-event-codes.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,11 +1,11 @@
 | 
				
			||||||
 | 
					#include <getopt.h>
 | 
				
			||||||
 | 
					#include <pthread.h>
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
#include <unistd.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
#include <getopt.h>
 | 
					 | 
				
			||||||
#include <pthread.h>
 | 
					 | 
				
			||||||
#include <wayland-client.h>
 | 
					 | 
				
			||||||
#include <wayland-client-protocol.h>
 | 
					#include <wayland-client-protocol.h>
 | 
				
			||||||
 | 
					#include <wayland-client.h>
 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					#include <wlr/util/log.h>
 | 
				
			||||||
#include "idle-client-protocol.h"
 | 
					#include "idle-client-protocol.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,30 +1,30 @@
 | 
				
			||||||
#define _POSIX_C_SOURCE 199309L
 | 
					#define _POSIX_C_SOURCE 199309L
 | 
				
			||||||
#define _XOPEN_SOURCE 500
 | 
					#define _XOPEN_SOURCE 500
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					#include <GLES2/gl2.h>
 | 
				
			||||||
 | 
					#include <math.h>
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <time.h>
 | 
					 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <time.h>
 | 
				
			||||||
#include <unistd.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
#include <math.h>
 | 
					 | 
				
			||||||
#include <assert.h>
 | 
					 | 
				
			||||||
#include <wayland-server.h>
 | 
					 | 
				
			||||||
#include <wayland-server-protocol.h>
 | 
					#include <wayland-server-protocol.h>
 | 
				
			||||||
#include <xkbcommon/xkbcommon.h>
 | 
					#include <wayland-server.h>
 | 
				
			||||||
#include <GLES2/gl2.h>
 | 
					 | 
				
			||||||
#include <wlr/render/matrix.h>
 | 
					 | 
				
			||||||
#include <wlr/render/gles2.h>
 | 
					 | 
				
			||||||
#include <wlr/render.h>
 | 
					 | 
				
			||||||
#include <wlr/backend.h>
 | 
					#include <wlr/backend.h>
 | 
				
			||||||
#include <wlr/backend/session.h>
 | 
					#include <wlr/backend/session.h>
 | 
				
			||||||
#include <wlr/types/wlr_keyboard.h>
 | 
					#include <wlr/render/gles2.h>
 | 
				
			||||||
#include <wlr/types/wlr_output_layout.h>
 | 
					#include <wlr/render/wlr_renderer.h>
 | 
				
			||||||
#include <wlr/xcursor.h>
 | 
					 | 
				
			||||||
#include <wlr/types/wlr_cursor.h>
 | 
					#include <wlr/types/wlr_cursor.h>
 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					#include <wlr/types/wlr_keyboard.h>
 | 
				
			||||||
#include <wlr/types/wlr_list.h>
 | 
					#include <wlr/types/wlr_list.h>
 | 
				
			||||||
#include "support/shared.h"
 | 
					#include <wlr/types/wlr_matrix.h>
 | 
				
			||||||
#include "support/config.h"
 | 
					#include <wlr/types/wlr_output_layout.h>
 | 
				
			||||||
 | 
					#include <wlr/util/log.h>
 | 
				
			||||||
 | 
					#include <wlr/xcursor.h>
 | 
				
			||||||
 | 
					#include <xkbcommon/xkbcommon.h>
 | 
				
			||||||
#include "support/cat.h"
 | 
					#include "support/cat.h"
 | 
				
			||||||
 | 
					#include "support/config.h"
 | 
				
			||||||
 | 
					#include "support/shared.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sample_state;
 | 
					struct sample_state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,29 +1,29 @@
 | 
				
			||||||
#define _POSIX_C_SOURCE 199309L
 | 
					#define _POSIX_C_SOURCE 199309L
 | 
				
			||||||
#define _XOPEN_SOURCE 700
 | 
					#define _XOPEN_SOURCE 700
 | 
				
			||||||
 | 
					#include <GLES2/gl2.h>
 | 
				
			||||||
 | 
					#include <limits.h>
 | 
				
			||||||
 | 
					#include <math.h>
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <time.h>
 | 
					 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
#include <strings.h>
 | 
					#include <strings.h>
 | 
				
			||||||
 | 
					#include <time.h>
 | 
				
			||||||
#include <unistd.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
#include <limits.h>
 | 
					 | 
				
			||||||
#include <wayland-server.h>
 | 
					 | 
				
			||||||
#include <wayland-server-protocol.h>
 | 
					#include <wayland-server-protocol.h>
 | 
				
			||||||
#include <xkbcommon/xkbcommon.h>
 | 
					#include <wayland-server.h>
 | 
				
			||||||
#include <GLES2/gl2.h>
 | 
					 | 
				
			||||||
#include <wlr/render/matrix.h>
 | 
					 | 
				
			||||||
#include <wlr/render/gles2.h>
 | 
					 | 
				
			||||||
#include <wlr/render.h>
 | 
					 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					 | 
				
			||||||
#include <wlr/backend.h>
 | 
					#include <wlr/backend.h>
 | 
				
			||||||
#include <wlr/backend/session.h>
 | 
					#include <wlr/backend/session.h>
 | 
				
			||||||
 | 
					#include <wlr/render/gles2.h>
 | 
				
			||||||
 | 
					#include <wlr/render/wlr_renderer.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_keyboard.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_matrix.h>
 | 
				
			||||||
#include <wlr/types/wlr_output_layout.h>
 | 
					#include <wlr/types/wlr_output_layout.h>
 | 
				
			||||||
#include <wlr/types/wlr_output.h>
 | 
					#include <wlr/types/wlr_output.h>
 | 
				
			||||||
#include <wlr/types/wlr_keyboard.h>
 | 
					#include <wlr/util/log.h>
 | 
				
			||||||
#include <math.h>
 | 
					#include <xkbcommon/xkbcommon.h>
 | 
				
			||||||
#include "support/shared.h"
 | 
					 | 
				
			||||||
#include "support/config.h"
 | 
					 | 
				
			||||||
#include "support/cat.h"
 | 
					#include "support/cat.h"
 | 
				
			||||||
 | 
					#include "support/config.h"
 | 
				
			||||||
 | 
					#include "support/shared.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sample_state {
 | 
					struct sample_state {
 | 
				
			||||||
	struct example_config *config;
 | 
						struct example_config *config;
 | 
				
			||||||
| 
						 | 
					@ -101,8 +101,8 @@ static void handle_output_frame(struct output_state *output,
 | 
				
			||||||
	struct wlr_output *wlr_output = output->output;
 | 
						struct wlr_output *wlr_output = output->output;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_output_make_current(wlr_output, NULL);
 | 
						wlr_output_make_current(wlr_output, NULL);
 | 
				
			||||||
	wlr_renderer_begin(sample->renderer, wlr_output);
 | 
						wlr_renderer_begin(sample->renderer, wlr_output->width, wlr_output->height);
 | 
				
			||||||
	wlr_renderer_clear(sample->renderer, &(float[]){0.25f, 0.25f, 0.25f, 1});
 | 
						wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	animate_cat(sample, output->output);
 | 
						animate_cat(sample, output->output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -111,18 +111,14 @@ static void handle_output_frame(struct output_state *output,
 | 
				
			||||||
		.width = 128, .height = 128,
 | 
							.width = 128, .height = 128,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	if (wlr_output_layout_intersects(sample->layout, output->output, &box)) {
 | 
						if (wlr_output_layout_intersects(sample->layout, output->output, &box)) {
 | 
				
			||||||
		float matrix[16];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// transform global coordinates to local coordinates
 | 
							// transform global coordinates to local coordinates
 | 
				
			||||||
		double local_x = sample->x_offs;
 | 
							double local_x = sample->x_offs;
 | 
				
			||||||
		double local_y = sample->y_offs;
 | 
							double local_y = sample->y_offs;
 | 
				
			||||||
		wlr_output_layout_output_coords(sample->layout, output->output,
 | 
							wlr_output_layout_output_coords(sample->layout, output->output,
 | 
				
			||||||
			&local_x, &local_y);
 | 
								&local_x, &local_y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		wlr_texture_get_matrix(sample->cat_texture, &matrix,
 | 
							wlr_render_texture(sample->renderer, sample->cat_texture,
 | 
				
			||||||
			&wlr_output->transform_matrix, local_x, local_y);
 | 
								wlr_output->transform_matrix, local_x, local_y, 1.0f);
 | 
				
			||||||
		wlr_render_with_matrix(sample->renderer,
 | 
					 | 
				
			||||||
			sample->cat_texture, &matrix, 1.0f);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_renderer_end(sample->renderer);
 | 
						wlr_renderer_end(sample->renderer);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,30 +1,30 @@
 | 
				
			||||||
#define _POSIX_C_SOURCE 199309L
 | 
					#define _POSIX_C_SOURCE 199309L
 | 
				
			||||||
#define _XOPEN_SOURCE 500
 | 
					#define _XOPEN_SOURCE 500
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					#include <GLES2/gl2.h>
 | 
				
			||||||
 | 
					#include <math.h>
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <time.h>
 | 
					 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <time.h>
 | 
				
			||||||
#include <unistd.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
#include <math.h>
 | 
					 | 
				
			||||||
#include <assert.h>
 | 
					 | 
				
			||||||
#include <wayland-server.h>
 | 
					 | 
				
			||||||
#include <wayland-server-protocol.h>
 | 
					#include <wayland-server-protocol.h>
 | 
				
			||||||
#include <xkbcommon/xkbcommon.h>
 | 
					#include <wayland-server.h>
 | 
				
			||||||
#include <GLES2/gl2.h>
 | 
					 | 
				
			||||||
#include <wlr/render/matrix.h>
 | 
					 | 
				
			||||||
#include <wlr/render/gles2.h>
 | 
					 | 
				
			||||||
#include <wlr/render.h>
 | 
					 | 
				
			||||||
#include <wlr/backend.h>
 | 
					#include <wlr/backend.h>
 | 
				
			||||||
#include <wlr/backend/session.h>
 | 
					#include <wlr/backend/session.h>
 | 
				
			||||||
#include <wlr/types/wlr_keyboard.h>
 | 
					#include <wlr/render/gles2.h>
 | 
				
			||||||
#include <wlr/types/wlr_output_layout.h>
 | 
					#include <wlr/render/wlr_renderer.h>
 | 
				
			||||||
#include <wlr/xcursor.h>
 | 
					 | 
				
			||||||
#include <wlr/types/wlr_cursor.h>
 | 
					#include <wlr/types/wlr_cursor.h>
 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					#include <wlr/types/wlr_keyboard.h>
 | 
				
			||||||
#include <wlr/types/wlr_list.h>
 | 
					#include <wlr/types/wlr_list.h>
 | 
				
			||||||
#include "support/shared.h"
 | 
					#include <wlr/types/wlr_matrix.h>
 | 
				
			||||||
#include "support/config.h"
 | 
					#include <wlr/types/wlr_output_layout.h>
 | 
				
			||||||
 | 
					#include <wlr/util/log.h>
 | 
				
			||||||
 | 
					#include <wlr/xcursor.h>
 | 
				
			||||||
 | 
					#include <xkbcommon/xkbcommon.h>
 | 
				
			||||||
#include "support/cat.h"
 | 
					#include "support/cat.h"
 | 
				
			||||||
 | 
					#include "support/config.h"
 | 
				
			||||||
 | 
					#include "support/shared.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sample_state {
 | 
					struct sample_state {
 | 
				
			||||||
	struct compositor_state *compositor;
 | 
						struct compositor_state *compositor;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,23 +1,23 @@
 | 
				
			||||||
#define _POSIX_C_SOURCE 199309L
 | 
					#define _POSIX_C_SOURCE 199309L
 | 
				
			||||||
#define _XOPEN_SOURCE 500
 | 
					#define _XOPEN_SOURCE 500
 | 
				
			||||||
 | 
					#include <GLES2/gl2.h>
 | 
				
			||||||
 | 
					#include <math.h>
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <time.h>
 | 
					 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
#include <strings.h>
 | 
					#include <strings.h>
 | 
				
			||||||
 | 
					#include <time.h>
 | 
				
			||||||
#include <unistd.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
#include <wayland-server.h>
 | 
					 | 
				
			||||||
#include <wayland-server-protocol.h>
 | 
					#include <wayland-server-protocol.h>
 | 
				
			||||||
#include <xkbcommon/xkbcommon.h>
 | 
					#include <wayland-server.h>
 | 
				
			||||||
#include <GLES2/gl2.h>
 | 
					 | 
				
			||||||
#include <wlr/render/matrix.h>
 | 
					 | 
				
			||||||
#include <wlr/render/gles2.h>
 | 
					 | 
				
			||||||
#include <wlr/render.h>
 | 
					 | 
				
			||||||
#include <wlr/backend.h>
 | 
					#include <wlr/backend.h>
 | 
				
			||||||
#include <wlr/backend/session.h>
 | 
					#include <wlr/backend/session.h>
 | 
				
			||||||
 | 
					#include <wlr/render/wlr_renderer.h>
 | 
				
			||||||
 | 
					#include <wlr/render/gles2.h>
 | 
				
			||||||
#include <wlr/types/wlr_keyboard.h>
 | 
					#include <wlr/types/wlr_keyboard.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_matrix.h>
 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					#include <wlr/util/log.h>
 | 
				
			||||||
#include <math.h>
 | 
					#include <xkbcommon/xkbcommon.h>
 | 
				
			||||||
#include "support/shared.h"
 | 
					#include "support/shared.h"
 | 
				
			||||||
#include "support/config.h"
 | 
					#include "support/config.h"
 | 
				
			||||||
#include "support/cat.h"
 | 
					#include "support/cat.h"
 | 
				
			||||||
| 
						 | 
					@ -43,16 +43,13 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts
 | 
				
			||||||
	wlr_output_effective_resolution(wlr_output, &width, &height);
 | 
						wlr_output_effective_resolution(wlr_output, &width, &height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_output_make_current(wlr_output, NULL);
 | 
						wlr_output_make_current(wlr_output, NULL);
 | 
				
			||||||
	wlr_renderer_begin(sample->renderer, wlr_output);
 | 
						wlr_renderer_begin(sample->renderer, wlr_output->width, wlr_output->height);
 | 
				
			||||||
	wlr_renderer_clear(sample->renderer, &(float[]){0.25f, 0.25f, 0.25f, 1});
 | 
						wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	float matrix[16];
 | 
					 | 
				
			||||||
	for (int y = -128 + (int)odata->y_offs; y < height; y += 128) {
 | 
						for (int y = -128 + (int)odata->y_offs; y < height; y += 128) {
 | 
				
			||||||
		for (int x = -128 + (int)odata->x_offs; x < width; x += 128) {
 | 
							for (int x = -128 + (int)odata->x_offs; x < width; x += 128) {
 | 
				
			||||||
			wlr_texture_get_matrix(sample->cat_texture, &matrix,
 | 
								wlr_render_texture(sample->renderer, sample->cat_texture,
 | 
				
			||||||
				&wlr_output->transform_matrix, x, y);
 | 
									wlr_output->transform_matrix, x, y, 1.0f);
 | 
				
			||||||
			wlr_render_with_matrix(sample->renderer,
 | 
					 | 
				
			||||||
					sample->cat_texture, &matrix, 1.0f);
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,6 +26,7 @@
 | 
				
			||||||
#include <errno.h>
 | 
					#include <errno.h>
 | 
				
			||||||
#include <fcntl.h>
 | 
					#include <fcntl.h>
 | 
				
			||||||
#include <limits.h>
 | 
					#include <limits.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
| 
						 | 
					@ -36,33 +37,22 @@
 | 
				
			||||||
#include <wayland-client.h>
 | 
					#include <wayland-client.h>
 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					#include <wlr/util/log.h>
 | 
				
			||||||
#include "screenshooter-client-protocol.h"
 | 
					#include "screenshooter-client-protocol.h"
 | 
				
			||||||
#include "util/os-compatibility.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct wl_shm *shm = NULL;
 | 
					static struct wl_shm *shm = NULL;
 | 
				
			||||||
static struct orbital_screenshooter *screenshooter = NULL;
 | 
					static struct orbital_screenshooter *screenshooter = NULL;
 | 
				
			||||||
static struct wl_list output_list;
 | 
					static struct wl_list output_list;
 | 
				
			||||||
int min_x, min_y, max_x, max_y;
 | 
					static bool buffer_copy_done;
 | 
				
			||||||
int buffer_copy_done;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct screenshooter_output {
 | 
					struct screenshooter_output {
 | 
				
			||||||
	struct wl_output *output;
 | 
						struct wl_output *output;
 | 
				
			||||||
	struct wl_buffer *buffer;
 | 
						int width, height;
 | 
				
			||||||
	int width, height, offset_x, offset_y;
 | 
					 | 
				
			||||||
	enum wl_output_transform transform;
 | 
					 | 
				
			||||||
	void *data;
 | 
					 | 
				
			||||||
	struct wl_list link;
 | 
						struct wl_list link;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void output_handle_geometry(void *data, struct wl_output *wl_output,
 | 
					static void output_handle_geometry(void *data, struct wl_output *wl_output,
 | 
				
			||||||
		int x, int y, int physical_width, int physical_height, int subpixel,
 | 
							int x, int y, int physical_width, int physical_height, int subpixel,
 | 
				
			||||||
		const char *make, const char *model, int transform) {
 | 
							const char *make, const char *model, int transform) {
 | 
				
			||||||
	struct screenshooter_output *output = wl_output_get_user_data(wl_output);
 | 
						// No-op
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (wl_output == output->output) {
 | 
					 | 
				
			||||||
		output->offset_x = x;
 | 
					 | 
				
			||||||
		output->offset_y = y;
 | 
					 | 
				
			||||||
		output->transform = transform;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void output_handle_mode(void *data, struct wl_output *wl_output,
 | 
					static void output_handle_mode(void *data, struct wl_output *wl_output,
 | 
				
			||||||
| 
						 | 
					@ -86,7 +76,7 @@ static const struct wl_output_listener output_listener = {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void screenshot_done(void *data, struct orbital_screenshot *screenshot) {
 | 
					static void screenshot_done(void *data, struct orbital_screenshot *screenshot) {
 | 
				
			||||||
	buffer_copy_done = 1;
 | 
						buffer_copy_done = true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct orbital_screenshot_listener screenshot_listener = {
 | 
					static const struct orbital_screenshot_listener screenshot_listener = {
 | 
				
			||||||
| 
						 | 
					@ -113,7 +103,7 @@ static void handle_global(void *data, struct wl_registry *registry,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_global_remove(void *data, struct wl_registry *registry,
 | 
					static void handle_global_remove(void *data, struct wl_registry *registry,
 | 
				
			||||||
		uint32_t name) {
 | 
							uint32_t name) {
 | 
				
			||||||
	// Unimplemented
 | 
						// Who cares?
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct wl_registry_listener registry_listener = {
 | 
					static const struct wl_registry_listener registry_listener = {
 | 
				
			||||||
| 
						 | 
					@ -123,14 +113,15 @@ static const struct wl_registry_listener registry_listener = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int backingfile(off_t size) {
 | 
					static int backingfile(off_t size) {
 | 
				
			||||||
	char template[] = "/tmp/wlroots-shared-XXXXXX";
 | 
						char template[] = "/tmp/wlroots-shared-XXXXXX";
 | 
				
			||||||
	int fd, ret;
 | 
						int fd = mkstemp(template);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	fd = mkstemp(template);
 | 
					 | 
				
			||||||
	if (fd < 0) {
 | 
						if (fd < 0) {
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while ((ret = ftruncate(fd, size)) == EINTR) {}
 | 
						int ret;
 | 
				
			||||||
 | 
						while ((ret = ftruncate(fd, size)) == EINTR) {
 | 
				
			||||||
 | 
							// No-op
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if (ret < 0) {
 | 
						if (ret < 0) {
 | 
				
			||||||
		close(fd);
 | 
							close(fd);
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
| 
						 | 
					@ -140,7 +131,6 @@ static int backingfile(off_t size) {
 | 
				
			||||||
	return fd;
 | 
						return fd;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
static struct wl_buffer *create_shm_buffer(int width, int height,
 | 
					static struct wl_buffer *create_shm_buffer(int width, int height,
 | 
				
			||||||
		void **data_out) {
 | 
							void **data_out) {
 | 
				
			||||||
	int stride = width * 4;
 | 
						int stride = width * 4;
 | 
				
			||||||
| 
						 | 
					@ -170,91 +160,8 @@ static struct wl_buffer *create_shm_buffer(int width, int height,
 | 
				
			||||||
	return buffer;
 | 
						return buffer;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void write_image(const char *filename, int width, int height) {
 | 
					static void write_image(const char *filename, int width, int height,
 | 
				
			||||||
	int buffer_stride = width * 4;
 | 
							void *data) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
	void *data = calloc(1, buffer_stride * height);
 | 
					 | 
				
			||||||
	if (!data) {
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct screenshooter_output *output, *next;
 | 
					 | 
				
			||||||
	wl_list_for_each_safe(output, next, &output_list, link) {
 | 
					 | 
				
			||||||
		int output_stride = output->width * 4;
 | 
					 | 
				
			||||||
		uint32_t *src = (uint32_t *)output->data;
 | 
					 | 
				
			||||||
		uint32_t *dst = (uint32_t *)(data +
 | 
					 | 
				
			||||||
			(output->offset_y - min_y) * buffer_stride +
 | 
					 | 
				
			||||||
			(output->offset_x - min_x) * 4);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		switch (output->transform) {
 | 
					 | 
				
			||||||
		case WL_OUTPUT_TRANSFORM_NORMAL:
 | 
					 | 
				
			||||||
			for (int i = 0; i < output->height; i++) {
 | 
					 | 
				
			||||||
				memcpy(dst, src, output_stride);
 | 
					 | 
				
			||||||
				dst += width;
 | 
					 | 
				
			||||||
				src += output->width;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		case WL_OUTPUT_TRANSFORM_FLIPPED:
 | 
					 | 
				
			||||||
			for (int i = 0; i < output->height; ++i) {
 | 
					 | 
				
			||||||
				for (int j = 0; j < output->width; ++j) {
 | 
					 | 
				
			||||||
					dst[i * width + j] =
 | 
					 | 
				
			||||||
						src[i * output->width + output->width - 1 - j];
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		case WL_OUTPUT_TRANSFORM_90:
 | 
					 | 
				
			||||||
			for (int i = 0; i < output->width; ++i) {
 | 
					 | 
				
			||||||
				for (int j = 0; j < output->height; ++j) {
 | 
					 | 
				
			||||||
					dst[i * width + j] =
 | 
					 | 
				
			||||||
						src[j * output->width + output->width - 1 - i];
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		case WL_OUTPUT_TRANSFORM_FLIPPED_90:
 | 
					 | 
				
			||||||
			for (int i = 0; i < output->width; ++i) {
 | 
					 | 
				
			||||||
				for (int j = 0; j < output->height; ++j) {
 | 
					 | 
				
			||||||
					dst[i * width + j] =
 | 
					 | 
				
			||||||
						src[(output->height - 1 - j) * output->width + output->width - 1 - i];
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		case WL_OUTPUT_TRANSFORM_180:
 | 
					 | 
				
			||||||
			for (int i = 0; i < output->height; ++i) {
 | 
					 | 
				
			||||||
				for (int j = 0; j < output->width; ++j) {
 | 
					 | 
				
			||||||
					dst[i * width + j] =
 | 
					 | 
				
			||||||
						src[(output->height - 1 - i) * output->width + output->width - 1 - j];
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		case WL_OUTPUT_TRANSFORM_FLIPPED_180:
 | 
					 | 
				
			||||||
			for (int i = 0; i < output->height; ++i) {
 | 
					 | 
				
			||||||
				for (int j = 0; j < output->width; ++j) {
 | 
					 | 
				
			||||||
					dst[i * width + j] =
 | 
					 | 
				
			||||||
						src[(output->height - 1 - i) * output->width + j];
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		case WL_OUTPUT_TRANSFORM_270:
 | 
					 | 
				
			||||||
			for (int i = 0; i < output->width; ++i) {
 | 
					 | 
				
			||||||
				for (int j = 0; j < output->height; ++j) {
 | 
					 | 
				
			||||||
					dst[i * width + j] =
 | 
					 | 
				
			||||||
						src[(output->height - 1 - j) * output->width + i];
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		case WL_OUTPUT_TRANSFORM_FLIPPED_270:
 | 
					 | 
				
			||||||
			for (int i = 0; i < output->width; ++i) {
 | 
					 | 
				
			||||||
				for (int j = 0; j < output->height; ++j) {
 | 
					 | 
				
			||||||
					dst[i * width + j] =
 | 
					 | 
				
			||||||
						src[j * output->width + i];
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		free(output);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	char size[10 + 1 + 10 + 2 + 1]; // int32_t are max 10 digits
 | 
						char size[10 + 1 + 10 + 2 + 1]; // int32_t are max 10 digits
 | 
				
			||||||
	sprintf(size, "%dx%d+0", width, height);
 | 
						sprintf(size, "%dx%d+0", width, height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -270,12 +177,11 @@ static void write_image(const char *filename, int width, int height) {
 | 
				
			||||||
		exit(EXIT_FAILURE);
 | 
							exit(EXIT_FAILURE);
 | 
				
			||||||
	} else if (child != 0) {
 | 
						} else if (child != 0) {
 | 
				
			||||||
		close(fd[0]);
 | 
							close(fd[0]);
 | 
				
			||||||
		if (write(fd[1], data, buffer_stride * height) < 0) {
 | 
							if (write(fd[1], data, 4 * width * height) < 0) {
 | 
				
			||||||
			fprintf(stderr, "write() failed: %s\n", strerror(errno));
 | 
								fprintf(stderr, "write() failed: %s\n", strerror(errno));
 | 
				
			||||||
			exit(EXIT_FAILURE);
 | 
								exit(EXIT_FAILURE);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		close(fd[1]);
 | 
							close(fd[1]);
 | 
				
			||||||
		free(data);
 | 
					 | 
				
			||||||
		waitpid(child, NULL, 0);
 | 
							waitpid(child, NULL, 0);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		close(fd[1]);
 | 
							close(fd[1]);
 | 
				
			||||||
| 
						 | 
					@ -293,38 +199,9 @@ static void write_image(const char *filename, int width, int height) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int set_buffer_size(int *width, int *height) {
 | 
					 | 
				
			||||||
	int owidth, oheight;
 | 
					 | 
				
			||||||
	min_x = min_y = INT_MAX;
 | 
					 | 
				
			||||||
	max_x = max_y = INT_MIN;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct screenshooter_output *output;
 | 
					 | 
				
			||||||
	wl_list_for_each(output, &output_list, link) {
 | 
					 | 
				
			||||||
		if (output->transform & 0x1) {
 | 
					 | 
				
			||||||
			owidth = output->height;
 | 
					 | 
				
			||||||
			oheight = output->width;
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			owidth = output->width;
 | 
					 | 
				
			||||||
			oheight = output->height;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		min_x = MIN(min_x, output->offset_x);
 | 
					 | 
				
			||||||
		min_y = MIN(min_y, output->offset_y);
 | 
					 | 
				
			||||||
		max_x = MAX(max_x, output->offset_x + owidth);
 | 
					 | 
				
			||||||
		max_y = MAX(max_y, output->offset_y + oheight);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (max_x <= min_x || max_y <= min_y) {
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	*width = max_x - min_x;
 | 
					 | 
				
			||||||
	*height = max_y - min_y;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main(int argc, char *argv[]) {
 | 
					int main(int argc, char *argv[]) {
 | 
				
			||||||
	wlr_log_init(L_DEBUG, NULL);
 | 
						wlr_log_init(L_DEBUG, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_display * display = wl_display_connect(NULL);
 | 
						struct wl_display * display = wl_display_connect(NULL);
 | 
				
			||||||
	if (display == NULL) {
 | 
						if (display == NULL) {
 | 
				
			||||||
		fprintf(stderr, "failed to create display: %m\n");
 | 
							fprintf(stderr, "failed to create display: %m\n");
 | 
				
			||||||
| 
						 | 
					@ -342,27 +219,31 @@ int main(int argc, char *argv[]) {
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int width, height;
 | 
						int i = 0;
 | 
				
			||||||
	if (set_buffer_size(&width, &height)) {
 | 
					 | 
				
			||||||
		fprintf(stderr, "cannot set buffer size\n");
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct screenshooter_output *output;
 | 
						struct screenshooter_output *output;
 | 
				
			||||||
	wl_list_for_each(output, &output_list, link) {
 | 
						wl_list_for_each(output, &output_list, link) {
 | 
				
			||||||
		output->buffer = create_shm_buffer(output->width, output->height, &output->data);
 | 
							void *data = NULL;
 | 
				
			||||||
		if (output->buffer == NULL) {
 | 
							struct wl_buffer *buffer =
 | 
				
			||||||
 | 
								create_shm_buffer(output->width, output->height, &data);
 | 
				
			||||||
 | 
							if (buffer == NULL) {
 | 
				
			||||||
			return -1;
 | 
								return -1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		struct orbital_screenshot *screenshot = orbital_screenshooter_shoot(
 | 
							struct orbital_screenshot *screenshot = orbital_screenshooter_shoot(
 | 
				
			||||||
			screenshooter, output->output, output->buffer);
 | 
								screenshooter, output->output, buffer);
 | 
				
			||||||
		orbital_screenshot_add_listener(screenshot, &screenshot_listener, screenshot);
 | 
							orbital_screenshot_add_listener(screenshot, &screenshot_listener,
 | 
				
			||||||
		buffer_copy_done = 0;
 | 
								screenshot);
 | 
				
			||||||
 | 
							buffer_copy_done = false;
 | 
				
			||||||
		while (!buffer_copy_done) {
 | 
							while (!buffer_copy_done) {
 | 
				
			||||||
			wl_display_roundtrip(display);
 | 
								wl_display_roundtrip(display);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							char filename[24 + 10]; // int32_t are max 10 digits
 | 
				
			||||||
 | 
							snprintf(filename, sizeof(filename), "wayland-screenshot-%d.png", i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							write_image(filename, output->width, output->height, data);
 | 
				
			||||||
 | 
							wl_buffer_destroy(buffer);
 | 
				
			||||||
 | 
							++i;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	write_image("wayland-screenshot.png", width, height);
 | 
					 | 
				
			||||||
	return EXIT_SUCCESS;
 | 
						return EXIT_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,11 +1,11 @@
 | 
				
			||||||
#define _POSIX_C_SOURCE 199309L
 | 
					#define _POSIX_C_SOURCE 199309L
 | 
				
			||||||
#include <string.h>
 | 
					#include <GLES2/gl2.h>
 | 
				
			||||||
 | 
					#include <inttypes.h>
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
#include <time.h>
 | 
					#include <time.h>
 | 
				
			||||||
#include <inttypes.h>
 | 
					 | 
				
			||||||
#include <wayland-server.h>
 | 
					#include <wayland-server.h>
 | 
				
			||||||
#include <GLES2/gl2.h>
 | 
					 | 
				
			||||||
#include <wlr/backend.h>
 | 
					#include <wlr/backend.h>
 | 
				
			||||||
#include <wlr/backend/session.h>
 | 
					#include <wlr/backend/session.h>
 | 
				
			||||||
#include <wlr/types/wlr_output.h>
 | 
					#include <wlr/types/wlr_output.h>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,27 +1,27 @@
 | 
				
			||||||
#define _POSIX_C_SOURCE 199309L
 | 
					#define _POSIX_C_SOURCE 199309L
 | 
				
			||||||
#define _XOPEN_SOURCE 500
 | 
					#define _XOPEN_SOURCE 500
 | 
				
			||||||
 | 
					#include <GLES2/gl2.h>
 | 
				
			||||||
 | 
					#include <math.h>
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <time.h>
 | 
					 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <time.h>
 | 
				
			||||||
#include <unistd.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
#include <wayland-server.h>
 | 
					 | 
				
			||||||
#include <wayland-server-protocol.h>
 | 
					#include <wayland-server-protocol.h>
 | 
				
			||||||
#include <xkbcommon/xkbcommon.h>
 | 
					#include <wayland-server.h>
 | 
				
			||||||
#include <GLES2/gl2.h>
 | 
					 | 
				
			||||||
#include <wlr/render/matrix.h>
 | 
					 | 
				
			||||||
#include <wlr/render/gles2.h>
 | 
					 | 
				
			||||||
#include <wlr/render.h>
 | 
					 | 
				
			||||||
#include <wlr/backend.h>
 | 
					#include <wlr/backend.h>
 | 
				
			||||||
#include <wlr/backend/session.h>
 | 
					#include <wlr/backend/session.h>
 | 
				
			||||||
 | 
					#include <wlr/render/gles2.h>
 | 
				
			||||||
 | 
					#include <wlr/render/wlr_renderer.h>
 | 
				
			||||||
#include <wlr/types/wlr_box.h>
 | 
					#include <wlr/types/wlr_box.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_matrix.h>
 | 
				
			||||||
#include <wlr/types/wlr_output.h>
 | 
					#include <wlr/types/wlr_output.h>
 | 
				
			||||||
#include <wlr/types/wlr_tablet_tool.h>
 | 
					 | 
				
			||||||
#include <wlr/types/wlr_tablet_pad.h>
 | 
					#include <wlr/types/wlr_tablet_pad.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_tablet_tool.h>
 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					#include <wlr/util/log.h>
 | 
				
			||||||
#include <math.h>
 | 
					#include <xkbcommon/xkbcommon.h>
 | 
				
			||||||
#include "support/shared.h"
 | 
					 | 
				
			||||||
#include "support/cat.h"
 | 
					#include "support/cat.h"
 | 
				
			||||||
 | 
					#include "support/shared.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sample_state {
 | 
					struct sample_state {
 | 
				
			||||||
	struct wlr_renderer *renderer;
 | 
						struct wlr_renderer *renderer;
 | 
				
			||||||
| 
						 | 
					@ -46,10 +46,10 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts
 | 
				
			||||||
	wlr_output_effective_resolution(wlr_output, &width, &height);
 | 
						wlr_output_effective_resolution(wlr_output, &width, &height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_output_make_current(wlr_output, NULL);
 | 
						wlr_output_make_current(wlr_output, NULL);
 | 
				
			||||||
	wlr_renderer_begin(sample->renderer, wlr_output);
 | 
						wlr_renderer_begin(sample->renderer, wlr_output->width, wlr_output->height);
 | 
				
			||||||
	wlr_renderer_clear(sample->renderer, &(float[]){0.25f, 0.25f, 0.25f, 1});
 | 
						wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	float matrix[16];
 | 
						float matrix[9];
 | 
				
			||||||
	float distance = 0.8f * (1 - sample->distance);
 | 
						float distance = 0.8f * (1 - sample->distance);
 | 
				
			||||||
	float tool_color[4] = { distance, distance, distance, 1 };
 | 
						float tool_color[4] = { distance, distance, distance, 1 };
 | 
				
			||||||
	for (size_t i = 0; sample->button && i < 4; ++i) {
 | 
						for (size_t i = 0; sample->button && i < 4; ++i) {
 | 
				
			||||||
| 
						 | 
					@ -65,9 +65,8 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts
 | 
				
			||||||
		.x = left, .y = top,
 | 
							.x = left, .y = top,
 | 
				
			||||||
		.width = pad_width, .height = pad_height,
 | 
							.width = pad_width, .height = pad_height,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	wlr_matrix_project_box(&matrix, &box, 0, 0,
 | 
						wlr_matrix_project_box(matrix, &box, 0, 0, wlr_output->transform_matrix);
 | 
				
			||||||
			&wlr_output->transform_matrix);
 | 
						wlr_render_colored_quad(sample->renderer, sample->pad_color, matrix);
 | 
				
			||||||
	wlr_render_colored_quad(sample->renderer, &sample->pad_color, &matrix);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (sample->proximity) {
 | 
						if (sample->proximity) {
 | 
				
			||||||
		struct wlr_box box = {
 | 
							struct wlr_box box = {
 | 
				
			||||||
| 
						 | 
					@ -76,16 +75,16 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts
 | 
				
			||||||
			.width = 16 * (sample->pressure + 1),
 | 
								.width = 16 * (sample->pressure + 1),
 | 
				
			||||||
			.height = 16 * (sample->pressure + 1),
 | 
								.height = 16 * (sample->pressure + 1),
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
		wlr_matrix_project_box(&matrix, &box, 0, sample->ring,
 | 
							wlr_matrix_project_box(matrix, &box, 0, sample->ring,
 | 
				
			||||||
				&wlr_output->transform_matrix);
 | 
								wlr_output->transform_matrix);
 | 
				
			||||||
		wlr_render_colored_quad(sample->renderer, &tool_color, &matrix);
 | 
							wlr_render_colored_quad(sample->renderer, tool_color, matrix);
 | 
				
			||||||
		box.x += sample->x_tilt;
 | 
							box.x += sample->x_tilt;
 | 
				
			||||||
		box.y += sample->y_tilt;
 | 
							box.y += sample->y_tilt;
 | 
				
			||||||
		box.width /= 2;
 | 
							box.width /= 2;
 | 
				
			||||||
		box.height /= 2;
 | 
							box.height /= 2;
 | 
				
			||||||
		wlr_matrix_project_box(&matrix, &box, 0, 0,
 | 
							wlr_matrix_project_box(matrix, &box, 0, 0,
 | 
				
			||||||
				&wlr_output->transform_matrix);
 | 
								wlr_output->transform_matrix);
 | 
				
			||||||
		wlr_render_colored_quad(sample->renderer, &tool_color, &matrix);
 | 
							wlr_render_colored_quad(sample->renderer, tool_color, matrix);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_renderer_end(sample->renderer);
 | 
						wlr_renderer_end(sample->renderer);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,25 +1,25 @@
 | 
				
			||||||
#define _POSIX_C_SOURCE 199309L
 | 
					#define _POSIX_C_SOURCE 199309L
 | 
				
			||||||
#define _XOPEN_SOURCE 500
 | 
					#define _XOPEN_SOURCE 500
 | 
				
			||||||
 | 
					#include <GLES2/gl2.h>
 | 
				
			||||||
 | 
					#include <math.h>
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <time.h>
 | 
					 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <time.h>
 | 
				
			||||||
#include <unistd.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
#include <stdint.h>
 | 
					 | 
				
			||||||
#include <math.h>
 | 
					 | 
				
			||||||
#include <wayland-server.h>
 | 
					 | 
				
			||||||
#include <wayland-server-protocol.h>
 | 
					#include <wayland-server-protocol.h>
 | 
				
			||||||
#include <xkbcommon/xkbcommon.h>
 | 
					#include <wayland-server.h>
 | 
				
			||||||
#include <GLES2/gl2.h>
 | 
					 | 
				
			||||||
#include <wlr/render/matrix.h>
 | 
					 | 
				
			||||||
#include <wlr/render/gles2.h>
 | 
					 | 
				
			||||||
#include <wlr/render.h>
 | 
					 | 
				
			||||||
#include <wlr/backend.h>
 | 
					#include <wlr/backend.h>
 | 
				
			||||||
#include <wlr/backend/session.h>
 | 
					#include <wlr/backend/session.h>
 | 
				
			||||||
 | 
					#include <wlr/render/gles2.h>
 | 
				
			||||||
 | 
					#include <wlr/render/wlr_renderer.h>
 | 
				
			||||||
#include <wlr/types/wlr_list.h>
 | 
					#include <wlr/types/wlr_list.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_matrix.h>
 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					#include <wlr/util/log.h>
 | 
				
			||||||
#include "support/shared.h"
 | 
					#include <xkbcommon/xkbcommon.h>
 | 
				
			||||||
#include "support/cat.h"
 | 
					#include "support/cat.h"
 | 
				
			||||||
 | 
					#include "support/shared.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sample_state {
 | 
					struct sample_state {
 | 
				
			||||||
	struct wlr_renderer *renderer;
 | 
						struct wlr_renderer *renderer;
 | 
				
			||||||
| 
						 | 
					@ -42,18 +42,15 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts
 | 
				
			||||||
	wlr_output_effective_resolution(wlr_output, &width, &height);
 | 
						wlr_output_effective_resolution(wlr_output, &width, &height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_output_make_current(wlr_output, NULL);
 | 
						wlr_output_make_current(wlr_output, NULL);
 | 
				
			||||||
	wlr_renderer_begin(sample->renderer, wlr_output);
 | 
						wlr_renderer_begin(sample->renderer, wlr_output->width, wlr_output->height);
 | 
				
			||||||
	wlr_renderer_clear(sample->renderer, &(float[]){0.25f, 0.25f, 0.25f, 1});
 | 
						wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	float matrix[16];
 | 
					 | 
				
			||||||
	struct touch_point *p;
 | 
						struct touch_point *p;
 | 
				
			||||||
	wl_list_for_each(p, &sample->touch_points, link) {
 | 
						wl_list_for_each(p, &sample->touch_points, link) {
 | 
				
			||||||
		wlr_texture_get_matrix(sample->cat_texture, &matrix,
 | 
							int x = (int)(p->x * width) - sample->cat_texture->width / 2;
 | 
				
			||||||
			&wlr_output->transform_matrix,
 | 
							int y = (int)(p->y * height) - sample->cat_texture->height / 2;
 | 
				
			||||||
			(int)(p->x * width) - sample->cat_texture->width / 2,
 | 
							wlr_render_texture(sample->renderer, sample->cat_texture,
 | 
				
			||||||
			(int)(p->y * height) - sample->cat_texture->height / 2);
 | 
								wlr_output->transform_matrix, x, y, 1.0f);
 | 
				
			||||||
		wlr_render_with_matrix(sample->renderer,
 | 
					 | 
				
			||||||
			sample->cat_texture, &matrix, 1.0f);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_renderer_end(sample->renderer);
 | 
						wlr_renderer_end(sample->renderer);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,7 +26,7 @@ struct wlr_drm_plane {
 | 
				
			||||||
	struct wlr_drm_surface mgpu_surf;
 | 
						struct wlr_drm_surface mgpu_surf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Only used by cursor
 | 
						// Only used by cursor
 | 
				
			||||||
	float matrix[16];
 | 
						float matrix[9];
 | 
				
			||||||
	struct wlr_texture *wlr_tex;
 | 
						struct wlr_texture *wlr_tex;
 | 
				
			||||||
	struct gbm_bo *cursor_bo;
 | 
						struct gbm_bo *cursor_bo;
 | 
				
			||||||
	bool cursor_enabled;
 | 
						bool cursor_enabled;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,7 +5,7 @@
 | 
				
			||||||
#include <gbm.h>
 | 
					#include <gbm.h>
 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
#include <wlr/render.h>
 | 
					#include <wlr/render/wlr_renderer.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_drm_backend;
 | 
					struct wlr_drm_backend;
 | 
				
			||||||
struct wlr_drm_plane;
 | 
					struct wlr_drm_plane;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,8 +7,8 @@
 | 
				
			||||||
#include <wayland-server.h>
 | 
					#include <wayland-server.h>
 | 
				
			||||||
#include <wayland-util.h>
 | 
					#include <wayland-util.h>
 | 
				
			||||||
#include <wlr/backend/wayland.h>
 | 
					#include <wlr/backend/wayland.h>
 | 
				
			||||||
#include <wlr/render.h>
 | 
					 | 
				
			||||||
#include <wlr/render/egl.h>
 | 
					#include <wlr/render/egl.h>
 | 
				
			||||||
 | 
					#include <wlr/render/wlr_renderer.h>
 | 
				
			||||||
#include <wlr/types/wlr_box.h>
 | 
					#include <wlr/types/wlr_box.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_wl_backend {
 | 
					struct wlr_wl_backend {
 | 
				
			||||||
| 
						 | 
					@ -71,6 +71,7 @@ struct wlr_wl_pointer {
 | 
				
			||||||
	struct wlr_pointer wlr_pointer;
 | 
						struct wlr_pointer wlr_pointer;
 | 
				
			||||||
	enum wlr_axis_source axis_source;
 | 
						enum wlr_axis_source axis_source;
 | 
				
			||||||
	struct wlr_wl_backend_output *current_output;
 | 
						struct wlr_wl_backend_output *current_output;
 | 
				
			||||||
 | 
						struct wl_listener output_destroy_listener;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void wlr_wl_registry_poll(struct wlr_wl_backend *backend);
 | 
					void wlr_wl_registry_poll(struct wlr_wl_backend *backend);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,24 +9,33 @@
 | 
				
			||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
#include <wlr/backend.h>
 | 
					#include <wlr/backend.h>
 | 
				
			||||||
#include <wlr/render.h>
 | 
					 | 
				
			||||||
#include <wlr/render/egl.h>
 | 
					#include <wlr/render/egl.h>
 | 
				
			||||||
#include <wlr/render/interface.h>
 | 
					#include <wlr/render/interface.h>
 | 
				
			||||||
 | 
					#include <wlr/render/wlr_renderer.h>
 | 
				
			||||||
 | 
					#include <wlr/render/wlr_texture.h>
 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					#include <wlr/util/log.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
 | 
					extern PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct pixel_format {
 | 
					struct gles2_pixel_format {
 | 
				
			||||||
	uint32_t wl_format;
 | 
						uint32_t wl_format;
 | 
				
			||||||
	GLint gl_format, gl_type;
 | 
						GLint gl_format, gl_type;
 | 
				
			||||||
	int depth, bpp;
 | 
						int depth, bpp;
 | 
				
			||||||
	GLuint *shader;
 | 
						bool has_alpha;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_gles2_renderer {
 | 
					struct wlr_gles2_renderer {
 | 
				
			||||||
	struct wlr_renderer wlr_renderer;
 | 
						struct wlr_renderer wlr_renderer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_egl *egl;
 | 
						struct wlr_egl *egl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							GLuint quad;
 | 
				
			||||||
 | 
							GLuint ellipse;
 | 
				
			||||||
 | 
							GLuint tex_rgba;
 | 
				
			||||||
 | 
							GLuint tex_rgbx;
 | 
				
			||||||
 | 
							GLuint tex_ext;
 | 
				
			||||||
 | 
						} shaders;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_gles2_texture {
 | 
					struct wlr_gles2_texture {
 | 
				
			||||||
| 
						 | 
					@ -34,36 +43,20 @@ struct wlr_gles2_texture {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_egl *egl;
 | 
						struct wlr_egl *egl;
 | 
				
			||||||
	GLuint tex_id;
 | 
						GLuint tex_id;
 | 
				
			||||||
	const struct pixel_format *pixel_format;
 | 
						const struct gles2_pixel_format *pixel_format;
 | 
				
			||||||
	EGLImageKHR image;
 | 
						EGLImageKHR image;
 | 
				
			||||||
 | 
						GLenum target;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct shaders {
 | 
					const struct gles2_pixel_format *gles2_format_from_wl(enum wl_shm_format fmt);
 | 
				
			||||||
	bool initialized;
 | 
					const enum wl_shm_format *gles2_formats(size_t *len);
 | 
				
			||||||
	GLuint rgba, rgbx;
 | 
					 | 
				
			||||||
	GLuint quad;
 | 
					 | 
				
			||||||
	GLuint ellipse;
 | 
					 | 
				
			||||||
	GLuint external;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
extern struct shaders shaders;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const struct pixel_format *gl_format_for_wl_format(enum wl_shm_format fmt);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_texture *gles2_texture_create();
 | 
					struct wlr_texture *gles2_texture_create();
 | 
				
			||||||
 | 
					struct wlr_gles2_texture *gles2_get_texture(struct wlr_texture *wlr_texture);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern const GLchar quad_vertex_src[];
 | 
					void gles2_push_marker(const char *file, const char *func);
 | 
				
			||||||
extern const GLchar quad_fragment_src[];
 | 
					void gles2_pop_marker(void);
 | 
				
			||||||
extern const GLchar ellipse_fragment_src[];
 | 
					#define GLES2_DEBUG_PUSH gles2_push_marker(wlr_strip_path(__FILE__), __func__)
 | 
				
			||||||
extern const GLchar vertex_src[];
 | 
					#define GLES2_DEBUG_POP gles2_pop_marker()
 | 
				
			||||||
extern const GLchar fragment_src_rgba[];
 | 
					 | 
				
			||||||
extern const GLchar fragment_src_rgbx[];
 | 
					 | 
				
			||||||
extern const GLchar fragment_src_external[];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool _gles2_flush_errors(const char *file, int line);
 | 
					 | 
				
			||||||
#define gles2_flush_errors(...) \
 | 
					 | 
				
			||||||
	_gles2_flush_errors(wlr_strip_path(__FILE__), __LINE__)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define GL_CALL(func) func; gles2_flush_errors()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,6 +7,7 @@
 | 
				
			||||||
#include <wlr/types/wlr_compositor.h>
 | 
					#include <wlr/types/wlr_compositor.h>
 | 
				
			||||||
#include <wlr/types/wlr_gamma_control.h>
 | 
					#include <wlr/types/wlr_gamma_control.h>
 | 
				
			||||||
#include <wlr/types/wlr_idle.h>
 | 
					#include <wlr/types/wlr_idle.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_linux_dmabuf.h>
 | 
				
			||||||
#include <wlr/types/wlr_list.h>
 | 
					#include <wlr/types/wlr_list.h>
 | 
				
			||||||
#include <wlr/types/wlr_output_layout.h>
 | 
					#include <wlr/types/wlr_output_layout.h>
 | 
				
			||||||
#include <wlr/types/wlr_output.h>
 | 
					#include <wlr/types/wlr_output.h>
 | 
				
			||||||
| 
						 | 
					@ -46,6 +47,7 @@ struct roots_desktop {
 | 
				
			||||||
	struct wlr_primary_selection_device_manager *primary_selection_device_manager;
 | 
						struct wlr_primary_selection_device_manager *primary_selection_device_manager;
 | 
				
			||||||
	struct wlr_idle *idle;
 | 
						struct wlr_idle *idle;
 | 
				
			||||||
	struct wlr_idle_inhibit_manager_v1 *idle_inhibit;
 | 
						struct wlr_idle_inhibit_manager_v1 *idle_inhibit;
 | 
				
			||||||
 | 
						struct wlr_linux_dmabuf *linux_dmabuf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_listener new_output;
 | 
						struct wl_listener new_output;
 | 
				
			||||||
	struct wl_listener layout_change;
 | 
						struct wl_listener layout_change;
 | 
				
			||||||
| 
						 | 
					@ -71,14 +73,16 @@ struct roots_output *desktop_output_from_wlr_output(
 | 
				
			||||||
struct roots_view *desktop_view_at(struct roots_desktop *desktop, double lx,
 | 
					struct roots_view *desktop_view_at(struct roots_desktop *desktop, double lx,
 | 
				
			||||||
	double ly, struct wlr_surface **surface, double *sx, double *sy);
 | 
						double ly, struct wlr_surface **surface, double *sx, double *sy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void view_init(struct roots_view *view, struct roots_desktop *desktop);
 | 
					struct roots_view *view_create(struct roots_desktop *desktop);
 | 
				
			||||||
void view_finish(struct roots_view *view);
 | 
					void view_destroy(struct roots_view *view);
 | 
				
			||||||
void view_activate(struct roots_view *view, bool activate);
 | 
					void view_activate(struct roots_view *view, bool activate);
 | 
				
			||||||
void view_apply_damage(struct roots_view *view);
 | 
					void view_apply_damage(struct roots_view *view);
 | 
				
			||||||
void view_damage_whole(struct roots_view *view);
 | 
					void view_damage_whole(struct roots_view *view);
 | 
				
			||||||
void view_update_position(struct roots_view *view, double x, double y);
 | 
					void view_update_position(struct roots_view *view, double x, double y);
 | 
				
			||||||
void view_update_size(struct roots_view *view, uint32_t width, uint32_t height);
 | 
					void view_update_size(struct roots_view *view, uint32_t width, uint32_t height);
 | 
				
			||||||
void view_initial_focus(struct roots_view *view);
 | 
					void view_initial_focus(struct roots_view *view);
 | 
				
			||||||
 | 
					void view_map(struct roots_view *view, struct wlr_surface *surface);
 | 
				
			||||||
 | 
					void view_unmap(struct roots_view *view);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data);
 | 
					void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data);
 | 
				
			||||||
void handle_xdg_shell_surface(struct wl_listener *listener, void *data);
 | 
					void handle_xdg_shell_surface(struct wl_listener *listener, void *data);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,6 +39,7 @@ struct roots_seat_view {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_list link; // roots_seat::views
 | 
						struct wl_list link; // roots_seat::views
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wl_listener view_unmap;
 | 
				
			||||||
	struct wl_listener view_destroy;
 | 
						struct wl_listener view_destroy;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,7 +5,7 @@
 | 
				
			||||||
#include <wlr/backend.h>
 | 
					#include <wlr/backend.h>
 | 
				
			||||||
#include <wlr/backend/session.h>
 | 
					#include <wlr/backend/session.h>
 | 
				
			||||||
#include <wlr/config.h>
 | 
					#include <wlr/config.h>
 | 
				
			||||||
#include <wlr/render.h>
 | 
					#include <wlr/render/wlr_renderer.h>
 | 
				
			||||||
#include <wlr/types/wlr_data_device.h>
 | 
					#include <wlr/types/wlr_data_device.h>
 | 
				
			||||||
#ifdef WLR_HAS_XWAYLAND
 | 
					#ifdef WLR_HAS_XWAYLAND
 | 
				
			||||||
#include <wlr/xwayland.h>
 | 
					#include <wlr/xwayland.h>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,6 +27,8 @@ struct roots_xdg_surface_v6 {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_listener destroy;
 | 
						struct wl_listener destroy;
 | 
				
			||||||
	struct wl_listener new_popup;
 | 
						struct wl_listener new_popup;
 | 
				
			||||||
 | 
						struct wl_listener map;
 | 
				
			||||||
 | 
						struct wl_listener unmap;
 | 
				
			||||||
	struct wl_listener request_move;
 | 
						struct wl_listener request_move;
 | 
				
			||||||
	struct wl_listener request_resize;
 | 
						struct wl_listener request_resize;
 | 
				
			||||||
	struct wl_listener request_maximize;
 | 
						struct wl_listener request_maximize;
 | 
				
			||||||
| 
						 | 
					@ -42,6 +44,8 @@ struct roots_xdg_surface {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_listener destroy;
 | 
						struct wl_listener destroy;
 | 
				
			||||||
	struct wl_listener new_popup;
 | 
						struct wl_listener new_popup;
 | 
				
			||||||
 | 
						struct wl_listener map;
 | 
				
			||||||
 | 
						struct wl_listener unmap;
 | 
				
			||||||
	struct wl_listener request_move;
 | 
						struct wl_listener request_move;
 | 
				
			||||||
	struct wl_listener request_resize;
 | 
						struct wl_listener request_resize;
 | 
				
			||||||
	struct wl_listener request_maximize;
 | 
						struct wl_listener request_maximize;
 | 
				
			||||||
| 
						 | 
					@ -128,6 +132,7 @@ struct roots_view {
 | 
				
			||||||
	struct wl_listener new_subsurface;
 | 
						struct wl_listener new_subsurface;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct {
 | 
						struct {
 | 
				
			||||||
 | 
							struct wl_signal unmap;
 | 
				
			||||||
		struct wl_signal destroy;
 | 
							struct wl_signal destroy;
 | 
				
			||||||
	} events;
 | 
						} events;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -140,6 +145,7 @@ struct roots_view {
 | 
				
			||||||
	void (*maximize)(struct roots_view *view, bool maximized);
 | 
						void (*maximize)(struct roots_view *view, bool maximized);
 | 
				
			||||||
	void (*set_fullscreen)(struct roots_view *view, bool fullscreen);
 | 
						void (*set_fullscreen)(struct roots_view *view, bool fullscreen);
 | 
				
			||||||
	void (*close)(struct roots_view *view);
 | 
						void (*close)(struct roots_view *view);
 | 
				
			||||||
 | 
						void (*destroy)(struct roots_view *view);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct roots_view_child {
 | 
					struct roots_view_child {
 | 
				
			||||||
| 
						 | 
					@ -181,7 +187,6 @@ struct roots_xdg_popup {
 | 
				
			||||||
	struct wl_listener new_popup;
 | 
						struct wl_listener new_popup;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct roots_view *view_create();
 | 
					 | 
				
			||||||
void view_get_box(const struct roots_view *view, struct wlr_box *box);
 | 
					void view_get_box(const struct roots_view *view, struct wlr_box *box);
 | 
				
			||||||
void view_activate(struct roots_view *view, bool active);
 | 
					void view_activate(struct roots_view *view, bool active);
 | 
				
			||||||
void view_move(struct roots_view *view, double x, double y);
 | 
					void view_move(struct roots_view *view, double x, double y);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,16 +11,39 @@ struct wlr_backend {
 | 
				
			||||||
	const struct wlr_backend_impl *impl;
 | 
						const struct wlr_backend_impl *impl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct {
 | 
						struct {
 | 
				
			||||||
 | 
							/** Raised when destroyed, passed the wlr_backend reference */
 | 
				
			||||||
		struct wl_signal destroy;
 | 
							struct wl_signal destroy;
 | 
				
			||||||
 | 
							/** Raised when new inputs are added, passed the wlr_input_device */
 | 
				
			||||||
		struct wl_signal new_input;
 | 
							struct wl_signal new_input;
 | 
				
			||||||
 | 
							/** Raised when new outputs are added, passed the wlr_output */
 | 
				
			||||||
		struct wl_signal new_output;
 | 
							struct wl_signal new_output;
 | 
				
			||||||
	} events;
 | 
						} events;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Automatically initializes the most suitable backend given the environment.
 | 
				
			||||||
 | 
					 * Will always return a multibackend. The backend is created but not started.
 | 
				
			||||||
 | 
					 * Returns NULL on failure.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
struct wlr_backend *wlr_backend_autocreate(struct wl_display *display);
 | 
					struct wlr_backend *wlr_backend_autocreate(struct wl_display *display);
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Start the backend. This may signal new_input or new_output immediately, but
 | 
				
			||||||
 | 
					 * may also wait until the display's event loop begins. Returns false on
 | 
				
			||||||
 | 
					 * failure.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
bool wlr_backend_start(struct wlr_backend *backend);
 | 
					bool wlr_backend_start(struct wlr_backend *backend);
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Destroy the backend and clean up all of its resources. Normally called
 | 
				
			||||||
 | 
					 * automatically when the wl_display is destroyed.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
void wlr_backend_destroy(struct wlr_backend *backend);
 | 
					void wlr_backend_destroy(struct wlr_backend *backend);
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Obtains the wlr_egl reference this backend is using.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
struct wlr_egl *wlr_backend_get_egl(struct wlr_backend *backend);
 | 
					struct wlr_egl *wlr_backend_get_egl(struct wlr_backend *backend);
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Obtains the wlr_renderer reference this backend is using.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
struct wlr_renderer *wlr_backend_get_renderer(struct wlr_backend *backend);
 | 
					struct wlr_renderer *wlr_backend_get_renderer(struct wlr_backend *backend);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint32_t usec_to_msec(uint64_t usec);
 | 
					uint32_t usec_to_msec(uint64_t usec);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,6 +6,13 @@
 | 
				
			||||||
#include <wlr/backend/session.h>
 | 
					#include <wlr/backend/session.h>
 | 
				
			||||||
#include <wlr/types/wlr_output.h>
 | 
					#include <wlr/types/wlr_output.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Creates a DRM backend using the specified GPU file descriptor (typically from
 | 
				
			||||||
 | 
					 * a device node in /dev/dri).
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * To slave this to another DRM backend, pass it as the parent (which _must_ be
 | 
				
			||||||
 | 
					 * a DRM backend, other kinds of backends raise SIGABRT).
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
struct wlr_backend *wlr_drm_backend_create(struct wl_display *display,
 | 
					struct wlr_backend *wlr_drm_backend_create(struct wl_display *display,
 | 
				
			||||||
	struct wlr_session *session, int gpu_fd, struct wlr_backend *parent);
 | 
						struct wlr_session *session, int gpu_fd, struct wlr_backend *parent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,9 +5,23 @@
 | 
				
			||||||
#include <wlr/types/wlr_input_device.h>
 | 
					#include <wlr/types/wlr_input_device.h>
 | 
				
			||||||
#include <wlr/types/wlr_output.h>
 | 
					#include <wlr/types/wlr_output.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Creates a headless backend. A headless backend has no outputs or inputs by
 | 
				
			||||||
 | 
					 * default.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
struct wlr_backend *wlr_headless_backend_create(struct wl_display *display);
 | 
					struct wlr_backend *wlr_headless_backend_create(struct wl_display *display);
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Create a new headless output backed by an in-memory EGL framebuffer. You can
 | 
				
			||||||
 | 
					 * read pixels from this framebuffer via wlr_renderer_read_pixels but it is
 | 
				
			||||||
 | 
					 * otherwise not displayed.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
struct wlr_output *wlr_headless_add_output(struct wlr_backend *backend,
 | 
					struct wlr_output *wlr_headless_add_output(struct wlr_backend *backend,
 | 
				
			||||||
	unsigned int width, unsigned int height);
 | 
						unsigned int width, unsigned int height);
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Creates a new input device. The caller is responsible for manually raising
 | 
				
			||||||
 | 
					 * any event signals on the new input device if it wants to simulate input
 | 
				
			||||||
 | 
					 * events.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
struct wlr_input_device *wlr_headless_add_input_device(
 | 
					struct wlr_input_device *wlr_headless_add_input_device(
 | 
				
			||||||
	struct wlr_backend *backend, enum wlr_input_device_type type);
 | 
						struct wlr_backend *backend, enum wlr_input_device_type type);
 | 
				
			||||||
bool wlr_backend_is_headless(struct wlr_backend *backend);
 | 
					bool wlr_backend_is_headless(struct wlr_backend *backend);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,6 +12,10 @@ struct wlr_backend_impl {
 | 
				
			||||||
	struct wlr_renderer *(*get_renderer)(struct wlr_backend *backend);
 | 
						struct wlr_renderer *(*get_renderer)(struct wlr_backend *backend);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Initializes common state on a wlr_backend and sets the implementation to the
 | 
				
			||||||
 | 
					 * provided wlr_backend_impl reference.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
void wlr_backend_init(struct wlr_backend *backend,
 | 
					void wlr_backend_init(struct wlr_backend *backend,
 | 
				
			||||||
		const struct wlr_backend_impl *impl);
 | 
							const struct wlr_backend_impl *impl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,7 +9,9 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_backend *wlr_libinput_backend_create(struct wl_display *display,
 | 
					struct wlr_backend *wlr_libinput_backend_create(struct wl_display *display,
 | 
				
			||||||
		struct wlr_session *session);
 | 
							struct wlr_session *session);
 | 
				
			||||||
struct libinput_device *wlr_libinput_get_device_handle(struct wlr_input_device *dev);
 | 
					/** Gets the underlying libinput_device handle for the given wlr_input_device */
 | 
				
			||||||
 | 
					struct libinput_device *wlr_libinput_get_device_handle(
 | 
				
			||||||
 | 
							struct wlr_input_device *dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool wlr_backend_is_libinput(struct wlr_backend *backend);
 | 
					bool wlr_backend_is_libinput(struct wlr_backend *backend);
 | 
				
			||||||
bool wlr_input_device_is_libinput(struct wlr_input_device *device);
 | 
					bool wlr_input_device_is_libinput(struct wlr_input_device *device);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,11 +4,21 @@
 | 
				
			||||||
#include <wlr/backend.h>
 | 
					#include <wlr/backend.h>
 | 
				
			||||||
#include <wlr/backend/session.h>
 | 
					#include <wlr/backend/session.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Creates a multi-backend. Multi-backends wrap an arbitrary number of backends
 | 
				
			||||||
 | 
					 * and aggregate their new_output/new_input signals.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
struct wlr_backend *wlr_multi_backend_create(struct wl_display *display);
 | 
					struct wlr_backend *wlr_multi_backend_create(struct wl_display *display);
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Adds the given backend to the multi backend. This should be done before the
 | 
				
			||||||
 | 
					 * new backend is started.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
void wlr_multi_backend_add(struct wlr_backend *multi,
 | 
					void wlr_multi_backend_add(struct wlr_backend *multi,
 | 
				
			||||||
	struct wlr_backend *backend);
 | 
						struct wlr_backend *backend);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void wlr_multi_backend_remove(struct wlr_backend *multi,
 | 
					void wlr_multi_backend_remove(struct wlr_backend *multi,
 | 
				
			||||||
	struct wlr_backend *backend);
 | 
						struct wlr_backend *backend);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool wlr_backend_is_multi(struct wlr_backend *backend);
 | 
					bool wlr_backend_is_multi(struct wlr_backend *backend);
 | 
				
			||||||
struct wlr_session *wlr_multi_get_session(struct wlr_backend *base);
 | 
					struct wlr_session *wlr_multi_get_session(struct wlr_backend *base);
 | 
				
			||||||
bool wlr_multi_is_empty(struct wlr_backend *backend);
 | 
					bool wlr_multi_is_empty(struct wlr_backend *backend);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,149 +0,0 @@
 | 
				
			||||||
#ifndef WLR_RENDER_H
 | 
					 | 
				
			||||||
#define WLR_RENDER_H
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <EGL/egl.h>
 | 
					 | 
				
			||||||
#include <EGL/eglext.h>
 | 
					 | 
				
			||||||
#include <stdint.h>
 | 
					 | 
				
			||||||
#include <wayland-server-protocol.h>
 | 
					 | 
				
			||||||
#include <wlr/types/wlr_box.h>
 | 
					 | 
				
			||||||
#include <wlr/types/wlr_output.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct wlr_texture;
 | 
					 | 
				
			||||||
struct wlr_renderer;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void wlr_renderer_begin(struct wlr_renderer *r, struct wlr_output *output);
 | 
					 | 
				
			||||||
void wlr_renderer_end(struct wlr_renderer *r);
 | 
					 | 
				
			||||||
void wlr_renderer_clear(struct wlr_renderer *r, const float (*color)[4]);
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Defines a scissor box. Only pixels that lie within the scissor box can be
 | 
					 | 
				
			||||||
 * modified by drawing functions. Providing a NULL `box` disables the scissor
 | 
					 | 
				
			||||||
 * box.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
void wlr_renderer_scissor(struct wlr_renderer *r, struct wlr_box *box);
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Requests a texture handle from this renderer.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
struct wlr_texture *wlr_render_texture_create(struct wlr_renderer *r);
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Renders the requested texture using the provided matrix. A typical texture
 | 
					 | 
				
			||||||
 * rendering goes like so:
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * 	struct wlr_renderer *renderer;
 | 
					 | 
				
			||||||
 * 	struct wlr_texture *texture;
 | 
					 | 
				
			||||||
 * 	float projection[16];
 | 
					 | 
				
			||||||
 * 	float matrix[16];
 | 
					 | 
				
			||||||
 * 	wlr_texture_get_matrix(texture, &matrix, &projection, 123, 321);
 | 
					 | 
				
			||||||
 * 	wlr_render_with_matrix(renderer, texture, &matrix, 0.5f);
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * This will render the texture at <123, 321> with an alpha channel of 0.5.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
bool wlr_render_with_matrix(struct wlr_renderer *r,
 | 
					 | 
				
			||||||
	struct wlr_texture *texture, const float (*matrix)[16], float alpha);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Renders a solid quad in the specified color.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
void wlr_render_colored_quad(struct wlr_renderer *r,
 | 
					 | 
				
			||||||
	const float (*color)[4], const float (*matrix)[16]);
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Renders a solid ellipse in the specified color.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
void wlr_render_colored_ellipse(struct wlr_renderer *r,
 | 
					 | 
				
			||||||
	const float (*color)[4], const float (*matrix)[16]);
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Returns a list of pixel formats supported by this renderer.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
const enum wl_shm_format *wlr_renderer_get_formats(
 | 
					 | 
				
			||||||
	struct wlr_renderer *r, size_t *len);
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Returns true if this wl_buffer is a DRM buffer.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
bool wlr_renderer_buffer_is_drm(struct wlr_renderer *renderer,
 | 
					 | 
				
			||||||
	struct wl_resource *buffer);
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Reads out of pixels of the currently bound surface into data. `stride` is in
 | 
					 | 
				
			||||||
 * bytes.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
bool wlr_renderer_read_pixels(struct wlr_renderer *r, enum wl_shm_format fmt,
 | 
					 | 
				
			||||||
	uint32_t stride, uint32_t width, uint32_t height,
 | 
					 | 
				
			||||||
	uint32_t src_x, uint32_t src_y, uint32_t dst_x, uint32_t dst_y, void *data);
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Checks if a format is supported.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
bool wlr_renderer_format_supported(struct wlr_renderer *r,
 | 
					 | 
				
			||||||
	enum wl_shm_format fmt);
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Destroys this wlr_renderer. Textures must be destroyed separately.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
void wlr_renderer_destroy(struct wlr_renderer *renderer);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct wlr_texture_impl;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct wlr_texture {
 | 
					 | 
				
			||||||
	struct wlr_texture_impl *impl;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	bool valid;
 | 
					 | 
				
			||||||
	uint32_t format;
 | 
					 | 
				
			||||||
	int width, height;
 | 
					 | 
				
			||||||
	struct wl_signal destroy_signal;
 | 
					 | 
				
			||||||
	struct wl_resource *resource;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Copies pixels to this texture. The buffer is not accessed after this function
 | 
					 | 
				
			||||||
 * returns.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
bool wlr_texture_upload_pixels(struct wlr_texture *tex,
 | 
					 | 
				
			||||||
		enum wl_shm_format format, int stride, int width, int height,
 | 
					 | 
				
			||||||
		const unsigned char *pixels);
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Copies pixels to this texture. The buffer is not accessed after this function
 | 
					 | 
				
			||||||
 * returns. Under some circumstances, this function may re-upload the entire
 | 
					 | 
				
			||||||
 * buffer - therefore, the entire buffer must be valid.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
bool wlr_texture_update_pixels(struct wlr_texture *surf,
 | 
					 | 
				
			||||||
		enum wl_shm_format format, int stride, int x, int y,
 | 
					 | 
				
			||||||
		int width, int height, const unsigned char *pixels);
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Copies pixels from a wl_shm_buffer into this texture. The buffer is not
 | 
					 | 
				
			||||||
 * accessed after this function returns.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
bool wlr_texture_upload_shm(struct wlr_texture *tex, uint32_t format,
 | 
					 | 
				
			||||||
		struct wl_shm_buffer *shm);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Attaches the contents from the given wl_drm wl_buffer resource onto the
 | 
					 | 
				
			||||||
 * texture. The wl_resource is not used after this call.
 | 
					 | 
				
			||||||
 * Will fail (return false) if the given resource is no drm buffer.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
bool wlr_texture_upload_drm(struct wlr_texture *tex,
 | 
					 | 
				
			||||||
	struct wl_resource *drm_buffer);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool wlr_texture_upload_eglimage(struct wlr_texture *tex,
 | 
					 | 
				
			||||||
	EGLImageKHR image, uint32_t width, uint32_t height);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Copies a rectangle of pixels from a wl_shm_buffer onto the texture. The
 | 
					 | 
				
			||||||
 * buffer is not accessed after this function returns. Under some circumstances,
 | 
					 | 
				
			||||||
 * this function may re-upload the entire buffer - therefore, the entire buffer
 | 
					 | 
				
			||||||
 * must be valid.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
bool wlr_texture_update_shm(struct wlr_texture *surf, uint32_t format,
 | 
					 | 
				
			||||||
		int x, int y, int width, int height, struct wl_shm_buffer *shm);
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Prepares a matrix with the appropriate scale for the given texture and
 | 
					 | 
				
			||||||
 * multiplies it with the projection, producing a matrix that the shader can
 | 
					 | 
				
			||||||
 * muptlipy vertex coordinates with to get final screen coordinates.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * The projection matrix is assumed to be an orthographic projection of [0,
 | 
					 | 
				
			||||||
 * width) and [0, height], and the x and y coordinates provided are used as
 | 
					 | 
				
			||||||
 * such.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
void wlr_texture_get_matrix(struct wlr_texture *texture,
 | 
					 | 
				
			||||||
		float (*matrix)[16], const float (*projection)[16], int x, int y);
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Destroys this wlr_texture.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
void wlr_texture_destroy(struct wlr_texture *texture);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
| 
						 | 
					@ -6,6 +6,7 @@
 | 
				
			||||||
#include <pixman.h>
 | 
					#include <pixman.h>
 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
#include <wayland-server.h>
 | 
					#include <wayland-server.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_linux_dmabuf.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_egl {
 | 
					struct wlr_egl {
 | 
				
			||||||
	EGLDisplay display;
 | 
						EGLDisplay display;
 | 
				
			||||||
| 
						 | 
					@ -18,6 +19,8 @@ struct wlr_egl {
 | 
				
			||||||
	struct {
 | 
						struct {
 | 
				
			||||||
		bool buffer_age;
 | 
							bool buffer_age;
 | 
				
			||||||
		bool swap_buffers_with_damage;
 | 
							bool swap_buffers_with_damage;
 | 
				
			||||||
 | 
							bool dmabuf_import;
 | 
				
			||||||
 | 
							bool dmabuf_import_modifiers;
 | 
				
			||||||
	} egl_exts;
 | 
						} egl_exts;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_display *wl_display;
 | 
						struct wl_display *wl_display;
 | 
				
			||||||
| 
						 | 
					@ -61,16 +64,36 @@ EGLSurface wlr_egl_create_surface(struct wlr_egl *egl, void *window);
 | 
				
			||||||
EGLImageKHR wlr_egl_create_image(struct wlr_egl *egl,
 | 
					EGLImageKHR wlr_egl_create_image(struct wlr_egl *egl,
 | 
				
			||||||
		EGLenum target, EGLClientBuffer buffer, const EGLint *attribs);
 | 
							EGLenum target, EGLClientBuffer buffer, const EGLint *attribs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Creates an egl image from the given dmabuf attributes. Check usability
 | 
				
			||||||
 | 
					 * of the dmabuf with wlr_egl_check_import_dmabuf once first.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl,
 | 
				
			||||||
 | 
							struct wlr_dmabuf_buffer_attribs *attributes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Try to import the given dmabuf. On success return true false otherwise.
 | 
				
			||||||
 | 
					 * If this succeeds the dmabuf can be used for rendering on a texture
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool wlr_egl_check_import_dmabuf(struct wlr_egl *egl,
 | 
				
			||||||
 | 
							struct wlr_dmabuf_buffer *dmabuf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Get the available dmabuf formats
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int wlr_egl_get_dmabuf_formats(struct wlr_egl *egl, int **formats);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Get the available dmabuf modifiers for a given format
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int wlr_egl_get_dmabuf_modifiers(struct wlr_egl *egl, int format,
 | 
				
			||||||
 | 
							uint64_t **modifiers);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Destroys an egl image created with the given wlr_egl.
 | 
					 * Destroys an egl image created with the given wlr_egl.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
bool wlr_egl_destroy_image(struct wlr_egl *egl, EGLImageKHR image);
 | 
					bool wlr_egl_destroy_image(struct wlr_egl *egl, EGLImageKHR image);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Returns a string for the last error ocurred with egl.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
const char *egl_error(void);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool wlr_egl_make_current(struct wlr_egl *egl, EGLSurface surface,
 | 
					bool wlr_egl_make_current(struct wlr_egl *egl, EGLSurface surface,
 | 
				
			||||||
	int *buffer_age);
 | 
						int *buffer_age);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,7 @@
 | 
				
			||||||
#define WLR_RENDER_GLES2_H
 | 
					#define WLR_RENDER_GLES2_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <wlr/backend.h>
 | 
					#include <wlr/backend.h>
 | 
				
			||||||
#include <wlr/render.h>
 | 
					#include <wlr/render/wlr_renderer.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_egl;
 | 
					struct wlr_egl;
 | 
				
			||||||
struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_backend *backend);
 | 
					struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_backend *backend);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,28 +5,32 @@
 | 
				
			||||||
#include <EGL/eglext.h>
 | 
					#include <EGL/eglext.h>
 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
#include <wayland-server-protocol.h>
 | 
					#include <wayland-server-protocol.h>
 | 
				
			||||||
#include <wlr/render.h>
 | 
					#include <wlr/render/wlr_renderer.h>
 | 
				
			||||||
 | 
					#include <wlr/render/wlr_texture.h>
 | 
				
			||||||
#include <wlr/types/wlr_box.h>
 | 
					#include <wlr/types/wlr_box.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_linux_dmabuf.h>
 | 
				
			||||||
#include <wlr/types/wlr_output.h>
 | 
					#include <wlr/types/wlr_output.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_renderer_impl;
 | 
					struct wlr_renderer_impl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_renderer {
 | 
					struct wlr_renderer {
 | 
				
			||||||
	struct wlr_renderer_impl *impl;
 | 
						const struct wlr_renderer_impl *impl;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_renderer_impl {
 | 
					struct wlr_renderer_impl {
 | 
				
			||||||
	void (*begin)(struct wlr_renderer *renderer, struct wlr_output *output);
 | 
						void (*begin)(struct wlr_renderer *renderer, uint32_t width,
 | 
				
			||||||
 | 
							uint32_t height);
 | 
				
			||||||
	void (*end)(struct wlr_renderer *renderer);
 | 
						void (*end)(struct wlr_renderer *renderer);
 | 
				
			||||||
	void (*clear)(struct wlr_renderer *renderer, const float (*color)[4]);
 | 
						void (*clear)(struct wlr_renderer *renderer, const float color[static 4]);
 | 
				
			||||||
	void (*scissor)(struct wlr_renderer *renderer, struct wlr_box *box);
 | 
						void (*scissor)(struct wlr_renderer *renderer, struct wlr_box *box);
 | 
				
			||||||
	struct wlr_texture *(*texture_create)(struct wlr_renderer *renderer);
 | 
						struct wlr_texture *(*texture_create)(struct wlr_renderer *renderer);
 | 
				
			||||||
	bool (*render_with_matrix)(struct wlr_renderer *renderer,
 | 
						bool (*render_texture_with_matrix)(struct wlr_renderer *renderer,
 | 
				
			||||||
		struct wlr_texture *texture, const float (*matrix)[16], float alpha);
 | 
							struct wlr_texture *texture, const float matrix[static 9],
 | 
				
			||||||
 | 
							float alpha);
 | 
				
			||||||
	void (*render_quad)(struct wlr_renderer *renderer,
 | 
						void (*render_quad)(struct wlr_renderer *renderer,
 | 
				
			||||||
		const float (*color)[4], const float (*matrix)[16]);
 | 
							const float color[static 4], const float matrix[static 9]);
 | 
				
			||||||
	void (*render_ellipse)(struct wlr_renderer *renderer,
 | 
						void (*render_ellipse)(struct wlr_renderer *renderer,
 | 
				
			||||||
		const float (*color)[4], const float (*matrix)[16]);
 | 
							const float color[static 4], const float matrix[static 9]);
 | 
				
			||||||
	const enum wl_shm_format *(*formats)(
 | 
						const enum wl_shm_format *(*formats)(
 | 
				
			||||||
		struct wlr_renderer *renderer, size_t *len);
 | 
							struct wlr_renderer *renderer, size_t *len);
 | 
				
			||||||
	bool (*buffer_is_drm)(struct wlr_renderer *renderer,
 | 
						bool (*buffer_is_drm)(struct wlr_renderer *renderer,
 | 
				
			||||||
| 
						 | 
					@ -41,7 +45,7 @@ struct wlr_renderer_impl {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void wlr_renderer_init(struct wlr_renderer *renderer,
 | 
					void wlr_renderer_init(struct wlr_renderer *renderer,
 | 
				
			||||||
		struct wlr_renderer_impl *impl);
 | 
							const struct wlr_renderer_impl *impl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_texture_impl {
 | 
					struct wlr_texture_impl {
 | 
				
			||||||
	bool (*upload_pixels)(struct wlr_texture *texture,
 | 
						bool (*upload_pixels)(struct wlr_texture *texture,
 | 
				
			||||||
| 
						 | 
					@ -58,17 +62,15 @@ struct wlr_texture_impl {
 | 
				
			||||||
		struct wl_resource *drm_buf);
 | 
							struct wl_resource *drm_buf);
 | 
				
			||||||
	bool (*upload_eglimage)(struct wlr_texture *texture, EGLImageKHR image,
 | 
						bool (*upload_eglimage)(struct wlr_texture *texture, EGLImageKHR image,
 | 
				
			||||||
		uint32_t width, uint32_t height);
 | 
							uint32_t width, uint32_t height);
 | 
				
			||||||
	void (*get_matrix)(struct wlr_texture *state,
 | 
						bool (*upload_dmabuf)(struct wlr_texture *texture,
 | 
				
			||||||
		float (*matrix)[16], const float (*projection)[16], int x, int y);
 | 
							struct wl_resource *dmabuf_resource);
 | 
				
			||||||
	void (*get_buffer_size)(struct wlr_texture *texture,
 | 
						void (*get_buffer_size)(struct wlr_texture *texture,
 | 
				
			||||||
		struct wl_resource *resource, int *width, int *height);
 | 
							struct wl_resource *resource, int *width, int *height);
 | 
				
			||||||
	void (*bind)(struct wlr_texture *texture);
 | 
					 | 
				
			||||||
	void (*destroy)(struct wlr_texture *texture);
 | 
						void (*destroy)(struct wlr_texture *texture);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void wlr_texture_init(struct wlr_texture *texture,
 | 
					void wlr_texture_init(struct wlr_texture *texture,
 | 
				
			||||||
		struct wlr_texture_impl *impl);
 | 
						const struct wlr_texture_impl *impl);
 | 
				
			||||||
void wlr_texture_bind(struct wlr_texture *texture);
 | 
					 | 
				
			||||||
void wlr_texture_get_buffer_size(struct wlr_texture *texture,
 | 
					void wlr_texture_get_buffer_size(struct wlr_texture *texture,
 | 
				
			||||||
	struct wl_resource *resource, int *width, int *height);
 | 
						struct wl_resource *resource, int *width, int *height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,22 +0,0 @@
 | 
				
			||||||
#ifndef WLR_RENDER_MATRIX_H
 | 
					 | 
				
			||||||
#define WLR_RENDER_MATRIX_H
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <stdint.h>
 | 
					 | 
				
			||||||
#include <wlr/types/wlr_box.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void wlr_matrix_identity(float (*output)[16]);
 | 
					 | 
				
			||||||
void wlr_matrix_translate(float (*output)[16], float x, float y, float z);
 | 
					 | 
				
			||||||
void wlr_matrix_scale(float (*output)[16], float x, float y, float z);
 | 
					 | 
				
			||||||
void wlr_matrix_rotate(float (*output)[16], float radians);
 | 
					 | 
				
			||||||
void wlr_matrix_mul(const float (*x)[16], const float (*y)[16], float (*product)[16]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enum wl_output_transform;
 | 
					 | 
				
			||||||
void wlr_matrix_transform(float mat[static 16],
 | 
					 | 
				
			||||||
		enum wl_output_transform transform);
 | 
					 | 
				
			||||||
void wlr_matrix_texture(float mat[static 16], int32_t width, int32_t height,
 | 
					 | 
				
			||||||
		enum wl_output_transform transform);
 | 
					 | 
				
			||||||
void wlr_matrix_project_box(float (*mat)[16], struct wlr_box *box,
 | 
					 | 
				
			||||||
		enum wl_output_transform transform, float rotation, float
 | 
					 | 
				
			||||||
		(*projection)[16]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
							
								
								
									
										75
									
								
								include/wlr/render/wlr_renderer.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								include/wlr/render/wlr_renderer.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,75 @@
 | 
				
			||||||
 | 
					#ifndef WLR_RENDER_WLR_RENDERER_H
 | 
				
			||||||
 | 
					#define WLR_RENDER_WLR_RENDERER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <EGL/egl.h>
 | 
				
			||||||
 | 
					#include <EGL/eglext.h>
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <wayland-server-protocol.h>
 | 
				
			||||||
 | 
					#include <wlr/render/wlr_texture.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_box.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_output;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_renderer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void wlr_renderer_begin(struct wlr_renderer *r, int width, int height);
 | 
				
			||||||
 | 
					void wlr_renderer_end(struct wlr_renderer *r);
 | 
				
			||||||
 | 
					void wlr_renderer_clear(struct wlr_renderer *r, const float color[static 4]);
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Defines a scissor box. Only pixels that lie within the scissor box can be
 | 
				
			||||||
 | 
					 * modified by drawing functions. Providing a NULL `box` disables the scissor
 | 
				
			||||||
 | 
					 * box.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void wlr_renderer_scissor(struct wlr_renderer *r, struct wlr_box *box);
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Requests a texture handle from this renderer.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct wlr_texture *wlr_render_texture_create(struct wlr_renderer *r);
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Renders the requested texture.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool wlr_render_texture(struct wlr_renderer *r, struct wlr_texture *texture,
 | 
				
			||||||
 | 
						const float projection[static 9], int x, int y, float alpha);
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Renders the requested texture using the provided matrix.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool wlr_render_texture_with_matrix(struct wlr_renderer *r,
 | 
				
			||||||
 | 
						struct wlr_texture *texture, const float matrix[static 9], float alpha);
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Renders a solid quad in the specified color.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void wlr_render_colored_quad(struct wlr_renderer *r,
 | 
				
			||||||
 | 
						const float color[static 4], const float matrix[static 9]);
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Renders a solid ellipse in the specified color.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void wlr_render_colored_ellipse(struct wlr_renderer *r,
 | 
				
			||||||
 | 
						const float color[static 4], const float matrix[static 9]);
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Returns a list of pixel formats supported by this renderer.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const enum wl_shm_format *wlr_renderer_get_formats(struct wlr_renderer *r,
 | 
				
			||||||
 | 
						size_t *len);
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Returns true if this wl_buffer is a DRM buffer.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool wlr_renderer_buffer_is_drm(struct wlr_renderer *renderer,
 | 
				
			||||||
 | 
						struct wl_resource *buffer);
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Reads out of pixels of the currently bound surface into data. `stride` is in
 | 
				
			||||||
 | 
					 * bytes.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool wlr_renderer_read_pixels(struct wlr_renderer *r, enum wl_shm_format fmt,
 | 
				
			||||||
 | 
						uint32_t stride, uint32_t width, uint32_t height,
 | 
				
			||||||
 | 
						uint32_t src_x, uint32_t src_y, uint32_t dst_x, uint32_t dst_y, void *data);
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Checks if a format is supported.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool wlr_renderer_format_supported(struct wlr_renderer *r,
 | 
				
			||||||
 | 
						enum wl_shm_format fmt);
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Destroys this wlr_renderer. Textures must be destroyed separately.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void wlr_renderer_destroy(struct wlr_renderer *renderer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										69
									
								
								include/wlr/render/wlr_texture.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								include/wlr/render/wlr_texture.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,69 @@
 | 
				
			||||||
 | 
					#ifndef WLR_RENDER_WLR_TEXTURE_H
 | 
				
			||||||
 | 
					#define WLR_RENDER_WLR_TEXTURE_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <EGL/egl.h>
 | 
				
			||||||
 | 
					#include <EGL/eglext.h>
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <wayland-server-protocol.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_texture_impl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_texture {
 | 
				
			||||||
 | 
						const struct wlr_texture_impl *impl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool valid;
 | 
				
			||||||
 | 
						uint32_t format;
 | 
				
			||||||
 | 
						int width, height;
 | 
				
			||||||
 | 
						bool inverted_y;
 | 
				
			||||||
 | 
						struct wl_signal destroy_signal;
 | 
				
			||||||
 | 
						struct wl_resource *resource;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Copies pixels to this texture. The buffer is not accessed after this function
 | 
				
			||||||
 | 
					 * returns.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool wlr_texture_upload_pixels(struct wlr_texture *tex,
 | 
				
			||||||
 | 
						enum wl_shm_format format, int stride, int width, int height,
 | 
				
			||||||
 | 
						const unsigned char *pixels);
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Copies pixels to this texture. The buffer is not accessed after this function
 | 
				
			||||||
 | 
					 * returns. Under some circumstances, this function may re-upload the entire
 | 
				
			||||||
 | 
					 * buffer - therefore, the entire buffer must be valid.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool wlr_texture_update_pixels(struct wlr_texture *surf,
 | 
				
			||||||
 | 
						enum wl_shm_format format, int stride, int x, int y,
 | 
				
			||||||
 | 
						int width, int height, const unsigned char *pixels);
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Copies pixels from a wl_shm_buffer into this texture. The buffer is not
 | 
				
			||||||
 | 
					 * accessed after this function returns.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool wlr_texture_upload_shm(struct wlr_texture *tex, uint32_t format,
 | 
				
			||||||
 | 
						struct wl_shm_buffer *shm);
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Attaches the contents from the given wl_drm wl_buffer resource onto the
 | 
				
			||||||
 | 
					 * texture. The wl_resource is not used after this call.
 | 
				
			||||||
 | 
					 * Will fail (return false) if the given resource is no drm buffer.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool wlr_texture_upload_drm(struct wlr_texture *tex,
 | 
				
			||||||
 | 
						struct wl_resource *drm_buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool wlr_texture_upload_eglimage(struct wlr_texture *tex,
 | 
				
			||||||
 | 
						EGLImageKHR image, uint32_t width, uint32_t height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool wlr_texture_upload_dmabuf(struct wlr_texture *tex,
 | 
				
			||||||
 | 
						struct wl_resource *dmabuf_resource);
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Copies a rectangle of pixels from a wl_shm_buffer onto the texture. The
 | 
				
			||||||
 | 
					 * buffer is not accessed after this function returns. Under some circumstances,
 | 
				
			||||||
 | 
					 * this function may re-upload the entire buffer - therefore, the entire buffer
 | 
				
			||||||
 | 
					 * must be valid.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool wlr_texture_update_shm(struct wlr_texture *surf, uint32_t format,
 | 
				
			||||||
 | 
						int x, int y, int width, int height, struct wl_shm_buffer *shm);
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Destroys this wlr_texture.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void wlr_texture_destroy(struct wlr_texture *texture);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,7 @@
 | 
				
			||||||
#define WLR_TYPES_WLR_COMPOSITOR_H
 | 
					#define WLR_TYPES_WLR_COMPOSITOR_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <wayland-server.h>
 | 
					#include <wayland-server.h>
 | 
				
			||||||
#include <wlr/render.h>
 | 
					#include <wlr/render/wlr_renderer.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_compositor {
 | 
					struct wlr_compositor {
 | 
				
			||||||
	struct wl_global *wl_global;
 | 
						struct wl_global *wl_global;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										84
									
								
								include/wlr/types/wlr_linux_dmabuf.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								include/wlr/types/wlr_linux_dmabuf.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,84 @@
 | 
				
			||||||
 | 
					#ifndef WLR_TYPES_WLR_LINUX_DMABUF_H
 | 
				
			||||||
 | 
					#define WLR_TYPES_WLR_LINUX_DMABUF_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define WLR_LINUX_DMABUF_MAX_PLANES 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <wayland-server-protocol.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* So we don't have to pull in linux specific drm headers */
 | 
				
			||||||
 | 
					#ifndef DRM_FORMAT_MOD_INVALID
 | 
				
			||||||
 | 
					#define DRM_FORMAT_MOD_INVALID ((1ULL<<56) - 1)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_dmabuf_buffer_attribs {
 | 
				
			||||||
 | 
						/* set via params_add */
 | 
				
			||||||
 | 
						int n_planes;
 | 
				
			||||||
 | 
						uint32_t offset[WLR_LINUX_DMABUF_MAX_PLANES];
 | 
				
			||||||
 | 
						uint32_t stride[WLR_LINUX_DMABUF_MAX_PLANES];
 | 
				
			||||||
 | 
						uint64_t modifier[WLR_LINUX_DMABUF_MAX_PLANES];
 | 
				
			||||||
 | 
						int fd[WLR_LINUX_DMABUF_MAX_PLANES];
 | 
				
			||||||
 | 
						/* set via params_create */
 | 
				
			||||||
 | 
						int32_t width;
 | 
				
			||||||
 | 
						int32_t height;
 | 
				
			||||||
 | 
						uint32_t format;
 | 
				
			||||||
 | 
						uint32_t flags; /* enum zlinux_buffer_params_flags */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_dmabuf_buffer {
 | 
				
			||||||
 | 
						struct wlr_egl *egl;
 | 
				
			||||||
 | 
						struct wl_resource *buffer_resource;
 | 
				
			||||||
 | 
						struct wl_resource *params_resource;
 | 
				
			||||||
 | 
						struct wlr_dmabuf_buffer_attribs attributes;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Returns true if the given resource was created via the linux-dmabuf
 | 
				
			||||||
 | 
					 * buffer protocol, false otherwise
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool wlr_dmabuf_resource_is_buffer(struct wl_resource *buffer_resource);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Returns the wlr_dmabuf_buffer if the given resource was created
 | 
				
			||||||
 | 
					 * via the linux-dmabuf buffer protocol
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct wlr_dmabuf_buffer *wlr_dmabuf_buffer_from_buffer_resource(
 | 
				
			||||||
 | 
						struct wl_resource *buffer_resource);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Returns the wlr_dmabuf_buffer if the given resource was created
 | 
				
			||||||
 | 
					 * via the linux-dmabuf params protocol
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct wlr_dmabuf_buffer *wlr_dmabuf_buffer_from_params_resource(
 | 
				
			||||||
 | 
						struct wl_resource *params_resource);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Returns true if the given dmabuf has y-axis inverted, false otherwise
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool wlr_dmabuf_buffer_has_inverted_y(struct wlr_dmabuf_buffer *dmabuf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* the protocol interface */
 | 
				
			||||||
 | 
					struct wlr_linux_dmabuf {
 | 
				
			||||||
 | 
						struct wl_global *wl_global;
 | 
				
			||||||
 | 
						struct wl_listener display_destroy;
 | 
				
			||||||
 | 
						struct wlr_egl *egl;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Create linux-dmabuf interface
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct wlr_linux_dmabuf *wlr_linux_dmabuf_create(struct wl_display *display,
 | 
				
			||||||
 | 
						struct wlr_egl *egl);
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Destroy the linux-dmabuf interface
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void wlr_linux_dmabuf_destroy(struct wlr_linux_dmabuf *linux_dmabuf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Returns the wlr_linux_dmabuf if the given resource was created
 | 
				
			||||||
 | 
					 * via the linux_dmabuf protocol
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct wlr_linux_dmabuf *wlr_linux_dmabuf_from_resource(
 | 
				
			||||||
 | 
						struct wl_resource *resource);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										22
									
								
								include/wlr/types/wlr_matrix.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								include/wlr/types/wlr_matrix.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,22 @@
 | 
				
			||||||
 | 
					#ifndef WLR_TYPES_WLR_MATRIX_H
 | 
				
			||||||
 | 
					#define WLR_TYPES_WLR_MATRIX_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <wayland-server.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_box.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void wlr_matrix_identity(float mat[static 9]);
 | 
				
			||||||
 | 
					void wlr_matrix_multiply(float mat[static 9], const float a[static 9],
 | 
				
			||||||
 | 
						const float b[static 9]);
 | 
				
			||||||
 | 
					void wlr_matrix_transpose(float mat[static 9], const float a[static 9]);
 | 
				
			||||||
 | 
					void wlr_matrix_translate(float mat[static 9], float x, float y);
 | 
				
			||||||
 | 
					void wlr_matrix_scale(float mat[static 9], float x, float y);
 | 
				
			||||||
 | 
					void wlr_matrix_rotate(float mat[static 9], float rad);
 | 
				
			||||||
 | 
					void wlr_matrix_transform(float mat[static 9],
 | 
				
			||||||
 | 
						enum wl_output_transform transform);
 | 
				
			||||||
 | 
					void wlr_matrix_projection(float mat[static 9], int width, int height,
 | 
				
			||||||
 | 
						enum wl_output_transform transform);
 | 
				
			||||||
 | 
					void wlr_matrix_project_box(float mat[static 9], const struct wlr_box *box,
 | 
				
			||||||
 | 
						enum wl_output_transform transform, float rotation,
 | 
				
			||||||
 | 
						const float projection[static 9]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -76,7 +76,7 @@ struct wlr_output {
 | 
				
			||||||
	// damage for cursors and fullscreen surface, in output-local coordinates
 | 
						// damage for cursors and fullscreen surface, in output-local coordinates
 | 
				
			||||||
	pixman_region32_t damage;
 | 
						pixman_region32_t damage;
 | 
				
			||||||
	bool frame_pending;
 | 
						bool frame_pending;
 | 
				
			||||||
	float transform_matrix[16];
 | 
						float transform_matrix[9];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct {
 | 
						struct {
 | 
				
			||||||
		struct wl_signal frame;
 | 
							struct wl_signal frame;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -70,8 +70,8 @@ struct wlr_surface {
 | 
				
			||||||
	struct wlr_surface_state *current, *pending;
 | 
						struct wlr_surface_state *current, *pending;
 | 
				
			||||||
	const char *role; // the lifetime-bound role or null
 | 
						const char *role; // the lifetime-bound role or null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	float buffer_to_surface_matrix[16];
 | 
						float buffer_to_surface_matrix[9];
 | 
				
			||||||
	float surface_to_buffer_matrix[16];
 | 
						float surface_to_buffer_matrix[9];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct {
 | 
						struct {
 | 
				
			||||||
		struct wl_signal commit;
 | 
							struct wl_signal commit;
 | 
				
			||||||
| 
						 | 
					@ -99,19 +99,6 @@ struct wlr_surface {
 | 
				
			||||||
struct wlr_renderer;
 | 
					struct wlr_renderer;
 | 
				
			||||||
struct wlr_surface *wlr_surface_create(struct wl_resource *res,
 | 
					struct wlr_surface *wlr_surface_create(struct wl_resource *res,
 | 
				
			||||||
		struct wlr_renderer *renderer);
 | 
							struct wlr_renderer *renderer);
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Gets a matrix you can pass into wlr_render_with_matrix to display this
 | 
					 | 
				
			||||||
 * surface. `matrix` is the output matrix, `projection` is the wlr_output
 | 
					 | 
				
			||||||
 * projection matrix, and `transform` is any additional transformations you want
 | 
					 | 
				
			||||||
 * to perform on the surface (or NULL/the identity matrix if you don't).
 | 
					 | 
				
			||||||
 * `transform` is used before the surface is scaled, so its geometry extends
 | 
					 | 
				
			||||||
 * from 0 to 1 in both dimensions.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
void wlr_surface_get_matrix(struct wlr_surface *surface,
 | 
					 | 
				
			||||||
		float (*matrix)[16],
 | 
					 | 
				
			||||||
		const float (*projection)[16],
 | 
					 | 
				
			||||||
		const float (*transform)[16]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Set the lifetime role for this surface. Returns 0 on success or -1 if the
 | 
					 * Set the lifetime role for this surface. Returns 0 on success or -1 if the
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -53,6 +53,7 @@ struct wlr_xdg_popup_grab {
 | 
				
			||||||
	struct wlr_seat *seat;
 | 
						struct wlr_seat *seat;
 | 
				
			||||||
	struct wl_list popups;
 | 
						struct wl_list popups;
 | 
				
			||||||
	struct wl_list link; // wlr_xdg_shell::popup_grabs
 | 
						struct wl_list link; // wlr_xdg_shell::popup_grabs
 | 
				
			||||||
 | 
						struct wl_listener seat_destroy;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum wlr_xdg_surface_role {
 | 
					enum wlr_xdg_surface_role {
 | 
				
			||||||
| 
						 | 
					@ -62,19 +63,10 @@ enum wlr_xdg_surface_role {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_xdg_toplevel_state {
 | 
					struct wlr_xdg_toplevel_state {
 | 
				
			||||||
	bool maximized;
 | 
						bool maximized, fullscreen, resizing, activated;
 | 
				
			||||||
	bool fullscreen;
 | 
						uint32_t width, height;
 | 
				
			||||||
	bool resizing;
 | 
						uint32_t max_width, max_height;
 | 
				
			||||||
	bool activated;
 | 
						uint32_t min_width, min_height;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	uint32_t width;
 | 
					 | 
				
			||||||
	uint32_t height;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	uint32_t max_width;
 | 
					 | 
				
			||||||
	uint32_t max_height;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	uint32_t min_width;
 | 
					 | 
				
			||||||
	uint32_t min_height;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_xdg_toplevel {
 | 
					struct wlr_xdg_toplevel {
 | 
				
			||||||
| 
						 | 
					@ -90,7 +82,8 @@ struct wlr_xdg_toplevel {
 | 
				
			||||||
struct wlr_xdg_surface_configure {
 | 
					struct wlr_xdg_surface_configure {
 | 
				
			||||||
	struct wl_list link; // wlr_xdg_surface::configure_list
 | 
						struct wl_list link; // wlr_xdg_surface::configure_list
 | 
				
			||||||
	uint32_t serial;
 | 
						uint32_t serial;
 | 
				
			||||||
	struct wlr_xdg_toplevel_state state;
 | 
					
 | 
				
			||||||
 | 
						struct wlr_xdg_toplevel_state *toplevel_state;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_xdg_surface {
 | 
					struct wlr_xdg_surface {
 | 
				
			||||||
| 
						 | 
					@ -101,14 +94,13 @@ struct wlr_xdg_surface {
 | 
				
			||||||
	enum wlr_xdg_surface_role role;
 | 
						enum wlr_xdg_surface_role role;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	union {
 | 
						union {
 | 
				
			||||||
		struct wlr_xdg_toplevel *toplevel_state;
 | 
							struct wlr_xdg_toplevel *toplevel;
 | 
				
			||||||
		struct wlr_xdg_popup *popup_state;
 | 
							struct wlr_xdg_popup *popup;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_list popups; // wlr_xdg_popup::link
 | 
						struct wl_list popups; // wlr_xdg_popup::link
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool configured;
 | 
						bool added, configured, mapped;
 | 
				
			||||||
	bool added;
 | 
					 | 
				
			||||||
	uint32_t configure_serial;
 | 
						uint32_t configure_serial;
 | 
				
			||||||
	struct wl_event_source *configure_idle;
 | 
						struct wl_event_source *configure_idle;
 | 
				
			||||||
	uint32_t configure_next_serial;
 | 
						uint32_t configure_next_serial;
 | 
				
			||||||
| 
						 | 
					@ -118,8 +110,8 @@ struct wlr_xdg_surface {
 | 
				
			||||||
	char *app_id;
 | 
						char *app_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool has_next_geometry;
 | 
						bool has_next_geometry;
 | 
				
			||||||
	struct wlr_box *next_geometry;
 | 
						struct wlr_box next_geometry;
 | 
				
			||||||
	struct wlr_box *geometry;
 | 
						struct wlr_box geometry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_listener surface_destroy_listener;
 | 
						struct wl_listener surface_destroy_listener;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -127,6 +119,8 @@ struct wlr_xdg_surface {
 | 
				
			||||||
		struct wl_signal destroy;
 | 
							struct wl_signal destroy;
 | 
				
			||||||
		struct wl_signal ping_timeout;
 | 
							struct wl_signal ping_timeout;
 | 
				
			||||||
		struct wl_signal new_popup;
 | 
							struct wl_signal new_popup;
 | 
				
			||||||
 | 
							struct wl_signal map;
 | 
				
			||||||
 | 
							struct wl_signal unmap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		struct wl_signal request_maximize;
 | 
							struct wl_signal request_maximize;
 | 
				
			||||||
		struct wl_signal request_fullscreen;
 | 
							struct wl_signal request_fullscreen;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -113,6 +113,7 @@ struct wlr_xdg_popup_grab_v6 {
 | 
				
			||||||
	struct wlr_seat *seat;
 | 
						struct wlr_seat *seat;
 | 
				
			||||||
	struct wl_list popups;
 | 
						struct wl_list popups;
 | 
				
			||||||
	struct wl_list link; // wlr_xdg_shell_v6::popup_grabs
 | 
						struct wl_list link; // wlr_xdg_shell_v6::popup_grabs
 | 
				
			||||||
 | 
						struct wl_listener seat_destroy;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum wlr_xdg_surface_v6_role {
 | 
					enum wlr_xdg_surface_v6_role {
 | 
				
			||||||
| 
						 | 
					@ -122,19 +123,10 @@ enum wlr_xdg_surface_v6_role {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_xdg_toplevel_v6_state {
 | 
					struct wlr_xdg_toplevel_v6_state {
 | 
				
			||||||
	bool maximized;
 | 
						bool maximized, fullscreen, resizing, activated;
 | 
				
			||||||
	bool fullscreen;
 | 
						uint32_t width, height;
 | 
				
			||||||
	bool resizing;
 | 
						uint32_t max_width, max_height;
 | 
				
			||||||
	bool activated;
 | 
						uint32_t min_width, min_height;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	uint32_t width;
 | 
					 | 
				
			||||||
	uint32_t height;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	uint32_t max_width;
 | 
					 | 
				
			||||||
	uint32_t max_height;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	uint32_t min_width;
 | 
					 | 
				
			||||||
	uint32_t min_height;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_xdg_toplevel_v6 {
 | 
					struct wlr_xdg_toplevel_v6 {
 | 
				
			||||||
| 
						 | 
					@ -150,7 +142,8 @@ struct wlr_xdg_toplevel_v6 {
 | 
				
			||||||
struct wlr_xdg_surface_v6_configure {
 | 
					struct wlr_xdg_surface_v6_configure {
 | 
				
			||||||
	struct wl_list link; // wlr_xdg_surface_v6::configure_list
 | 
						struct wl_list link; // wlr_xdg_surface_v6::configure_list
 | 
				
			||||||
	uint32_t serial;
 | 
						uint32_t serial;
 | 
				
			||||||
	struct wlr_xdg_toplevel_v6_state state;
 | 
					
 | 
				
			||||||
 | 
						struct wlr_xdg_toplevel_v6_state *toplevel_state;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_xdg_surface_v6 {
 | 
					struct wlr_xdg_surface_v6 {
 | 
				
			||||||
| 
						 | 
					@ -161,14 +154,13 @@ struct wlr_xdg_surface_v6 {
 | 
				
			||||||
	enum wlr_xdg_surface_v6_role role;
 | 
						enum wlr_xdg_surface_v6_role role;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	union {
 | 
						union {
 | 
				
			||||||
		struct wlr_xdg_toplevel_v6 *toplevel_state;
 | 
							struct wlr_xdg_toplevel_v6 *toplevel;
 | 
				
			||||||
		struct wlr_xdg_popup_v6 *popup_state;
 | 
							struct wlr_xdg_popup_v6 *popup;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_list popups; // wlr_xdg_popup_v6::link
 | 
						struct wl_list popups; // wlr_xdg_popup_v6::link
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool configured;
 | 
						bool added, configured, mapped;
 | 
				
			||||||
	bool added;
 | 
					 | 
				
			||||||
	uint32_t configure_serial;
 | 
						uint32_t configure_serial;
 | 
				
			||||||
	struct wl_event_source *configure_idle;
 | 
						struct wl_event_source *configure_idle;
 | 
				
			||||||
	uint32_t configure_next_serial;
 | 
						uint32_t configure_next_serial;
 | 
				
			||||||
| 
						 | 
					@ -178,8 +170,8 @@ struct wlr_xdg_surface_v6 {
 | 
				
			||||||
	char *app_id;
 | 
						char *app_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool has_next_geometry;
 | 
						bool has_next_geometry;
 | 
				
			||||||
	struct wlr_box *next_geometry;
 | 
						struct wlr_box next_geometry;
 | 
				
			||||||
	struct wlr_box *geometry;
 | 
						struct wlr_box geometry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_listener surface_destroy_listener;
 | 
						struct wl_listener surface_destroy_listener;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -187,6 +179,8 @@ struct wlr_xdg_surface_v6 {
 | 
				
			||||||
		struct wl_signal destroy;
 | 
							struct wl_signal destroy;
 | 
				
			||||||
		struct wl_signal ping_timeout;
 | 
							struct wl_signal ping_timeout;
 | 
				
			||||||
		struct wl_signal new_popup;
 | 
							struct wl_signal new_popup;
 | 
				
			||||||
 | 
							struct wl_signal map;
 | 
				
			||||||
 | 
							struct wl_signal unmap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		struct wl_signal request_maximize;
 | 
							struct wl_signal request_maximize;
 | 
				
			||||||
		struct wl_signal request_fullscreen;
 | 
							struct wl_signal request_fullscreen;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,9 +21,10 @@ wayland_scanner_client = generator(
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
protocols = [
 | 
					protocols = [
 | 
				
			||||||
	[wl_protocol_dir, 'unstable/xdg-shell/xdg-shell-unstable-v6.xml'],
 | 
					 | 
				
			||||||
	[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
 | 
						[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
 | 
				
			||||||
	[wl_protocol_dir, 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml'],
 | 
						[wl_protocol_dir, 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml'],
 | 
				
			||||||
 | 
						[wl_protocol_dir, 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml'],
 | 
				
			||||||
 | 
						[wl_protocol_dir, 'unstable/xdg-shell/xdg-shell-unstable-v6.xml'],
 | 
				
			||||||
	'gamma-control.xml',
 | 
						'gamma-control.xml',
 | 
				
			||||||
	'gtk-primary-selection.xml',
 | 
						'gtk-primary-selection.xml',
 | 
				
			||||||
	'idle.xml',
 | 
						'idle.xml',
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										242
									
								
								render/egl.c
									
										
									
									
									
								
							
							
						
						
									
										242
									
								
								render/egl.c
									
										
									
									
									
								
							| 
						 | 
					@ -1,4 +1,5 @@
 | 
				
			||||||
#include <assert.h>
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
#include <EGL/egl.h>
 | 
					#include <EGL/egl.h>
 | 
				
			||||||
#include <EGL/eglext.h>
 | 
					#include <EGL/eglext.h>
 | 
				
			||||||
#include <GLES2/gl2.h>
 | 
					#include <GLES2/gl2.h>
 | 
				
			||||||
| 
						 | 
					@ -11,43 +12,6 @@
 | 
				
			||||||
// https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_image_base.txt.
 | 
					// https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_image_base.txt.
 | 
				
			||||||
// https://cgit.freedesktop.org/mesa/mesa/tree/docs/specs/WL_bind_wayland_display.spec
 | 
					// https://cgit.freedesktop.org/mesa/mesa/tree/docs/specs/WL_bind_wayland_display.spec
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const char *egl_error(void) {
 | 
					 | 
				
			||||||
	switch (eglGetError()) {
 | 
					 | 
				
			||||||
	case EGL_SUCCESS:
 | 
					 | 
				
			||||||
		return "Success";
 | 
					 | 
				
			||||||
	case EGL_NOT_INITIALIZED:
 | 
					 | 
				
			||||||
		return "Not initialized";
 | 
					 | 
				
			||||||
	case EGL_BAD_ACCESS:
 | 
					 | 
				
			||||||
		return "Bad access";
 | 
					 | 
				
			||||||
	case EGL_BAD_ALLOC:
 | 
					 | 
				
			||||||
		return "Bad alloc";
 | 
					 | 
				
			||||||
	case EGL_BAD_ATTRIBUTE:
 | 
					 | 
				
			||||||
		return "Bad attribute";
 | 
					 | 
				
			||||||
	case EGL_BAD_CONTEXT:
 | 
					 | 
				
			||||||
		return "Bad Context";
 | 
					 | 
				
			||||||
	case EGL_BAD_CONFIG:
 | 
					 | 
				
			||||||
		return "Bad Config";
 | 
					 | 
				
			||||||
	case EGL_BAD_CURRENT_SURFACE:
 | 
					 | 
				
			||||||
		return "Bad current surface";
 | 
					 | 
				
			||||||
	case EGL_BAD_DISPLAY:
 | 
					 | 
				
			||||||
		return "Bad display";
 | 
					 | 
				
			||||||
	case EGL_BAD_SURFACE:
 | 
					 | 
				
			||||||
		return "Bad surface";
 | 
					 | 
				
			||||||
	case EGL_BAD_MATCH:
 | 
					 | 
				
			||||||
		return "Bad match";
 | 
					 | 
				
			||||||
	case EGL_BAD_PARAMETER:
 | 
					 | 
				
			||||||
		return "Bad parameter";
 | 
					 | 
				
			||||||
	case EGL_BAD_NATIVE_PIXMAP:
 | 
					 | 
				
			||||||
		return "Bad native pixmap";
 | 
					 | 
				
			||||||
	case EGL_BAD_NATIVE_WINDOW:
 | 
					 | 
				
			||||||
		return "Bad native window";
 | 
					 | 
				
			||||||
	case EGL_CONTEXT_LOST:
 | 
					 | 
				
			||||||
		return "Context lost";
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		return "Unknown";
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static bool egl_get_config(EGLDisplay disp, EGLint *attribs, EGLConfig *out,
 | 
					static bool egl_get_config(EGLDisplay disp, EGLint *attribs, EGLConfig *out,
 | 
				
			||||||
		EGLint visual_id) {
 | 
							EGLint visual_id) {
 | 
				
			||||||
	EGLint count = 0, matched = 0, ret;
 | 
						EGLint count = 0, matched = 0, ret;
 | 
				
			||||||
| 
						 | 
					@ -83,6 +47,21 @@ static bool egl_get_config(EGLDisplay disp, EGLint *attribs, EGLConfig *out,
 | 
				
			||||||
	return false;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static log_importance_t egl_log_importance_to_wlr(EGLint type) {
 | 
				
			||||||
 | 
						switch (type) {
 | 
				
			||||||
 | 
						case EGL_DEBUG_MSG_CRITICAL_KHR: return L_ERROR;
 | 
				
			||||||
 | 
						case EGL_DEBUG_MSG_ERROR_KHR:    return L_ERROR;
 | 
				
			||||||
 | 
						case EGL_DEBUG_MSG_WARN_KHR:     return L_ERROR;
 | 
				
			||||||
 | 
						case EGL_DEBUG_MSG_INFO_KHR:     return L_INFO;
 | 
				
			||||||
 | 
						default:                         return L_INFO;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void egl_log(EGLenum error, const char *command, EGLint msg_type,
 | 
				
			||||||
 | 
							EGLLabelKHR thread, EGLLabelKHR obj, const char *msg) {
 | 
				
			||||||
 | 
						_wlr_log(egl_log_importance_to_wlr(msg_type), "[EGL] %s: %s", command, msg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool check_egl_ext(const char *egl_exts, const char *ext) {
 | 
					static bool check_egl_ext(const char *egl_exts, const char *ext) {
 | 
				
			||||||
	size_t extlen = strlen(ext);
 | 
						size_t extlen = strlen(ext);
 | 
				
			||||||
	const char *end = egl_exts + strlen(egl_exts);
 | 
						const char *end = egl_exts + strlen(egl_exts);
 | 
				
			||||||
| 
						 | 
					@ -101,14 +80,45 @@ static bool check_egl_ext(const char *egl_exts, const char *ext) {
 | 
				
			||||||
	return false;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void print_dmabuf_formats(struct wlr_egl *egl) {
 | 
				
			||||||
 | 
						/* Avoid log msg if extension is not present */
 | 
				
			||||||
 | 
						if (!egl->egl_exts.dmabuf_import_modifiers) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int *formats;
 | 
				
			||||||
 | 
						int num = wlr_egl_get_dmabuf_formats(egl, &formats);
 | 
				
			||||||
 | 
						if (num < 0) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						char str_formats[num * 5 + 1];
 | 
				
			||||||
 | 
						for (int i = 0; i < num; i++) {
 | 
				
			||||||
 | 
							snprintf(&str_formats[i*5], (num - i) * 5 + 1, "%.4s ", (char*)&formats[i]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						wlr_log(L_INFO, "Supported dmabuf buffer formats: %s", str_formats);
 | 
				
			||||||
 | 
						free(formats);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display,
 | 
					bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display,
 | 
				
			||||||
		EGLint *config_attribs, EGLint visual_id) {
 | 
							EGLint *config_attribs, EGLint visual_id) {
 | 
				
			||||||
	if (!load_glapi()) {
 | 
						if (!load_glapi()) {
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (eglDebugMessageControlKHR) {
 | 
				
			||||||
 | 
							static const EGLAttrib debug_attribs[] = {
 | 
				
			||||||
 | 
								EGL_DEBUG_MSG_CRITICAL_KHR, EGL_TRUE,
 | 
				
			||||||
 | 
								EGL_DEBUG_MSG_ERROR_KHR, EGL_TRUE,
 | 
				
			||||||
 | 
								EGL_DEBUG_MSG_WARN_KHR, EGL_TRUE,
 | 
				
			||||||
 | 
								EGL_DEBUG_MSG_INFO_KHR, EGL_TRUE,
 | 
				
			||||||
 | 
								EGL_NONE,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							eglDebugMessageControlKHR(egl_log, debug_attribs);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (eglBindAPI(EGL_OPENGL_ES_API) == EGL_FALSE) {
 | 
						if (eglBindAPI(EGL_OPENGL_ES_API) == EGL_FALSE) {
 | 
				
			||||||
		wlr_log(L_ERROR, "Failed to bind to the OpenGL ES API: %s", egl_error());
 | 
							wlr_log(L_ERROR, "Failed to bind to the OpenGL ES API");
 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -119,13 +129,13 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display,
 | 
				
			||||||
		egl->display = eglGetPlatformDisplayEXT(platform, remote_display, NULL);
 | 
							egl->display = eglGetPlatformDisplayEXT(platform, remote_display, NULL);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (egl->display == EGL_NO_DISPLAY) {
 | 
						if (egl->display == EGL_NO_DISPLAY) {
 | 
				
			||||||
		wlr_log(L_ERROR, "Failed to create EGL display: %s", egl_error());
 | 
							wlr_log(L_ERROR, "Failed to create EGL display");
 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	EGLint major, minor;
 | 
						EGLint major, minor;
 | 
				
			||||||
	if (eglInitialize(egl->display, &major, &minor) == EGL_FALSE) {
 | 
						if (eglInitialize(egl->display, &major, &minor) == EGL_FALSE) {
 | 
				
			||||||
		wlr_log(L_ERROR, "Failed to initialize EGL: %s", egl_error());
 | 
							wlr_log(L_ERROR, "Failed to initialize EGL");
 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -140,7 +150,7 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display,
 | 
				
			||||||
		EGL_NO_CONTEXT, attribs);
 | 
							EGL_NO_CONTEXT, attribs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (egl->context == EGL_NO_CONTEXT) {
 | 
						if (egl->context == EGL_NO_CONTEXT) {
 | 
				
			||||||
		wlr_log(L_ERROR, "Failed to create EGL context: %s", egl_error());
 | 
							wlr_log(L_ERROR, "Failed to create EGL context");
 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -167,16 +177,29 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display,
 | 
				
			||||||
		check_egl_ext(egl->egl_exts_str, "EGL_EXT_swap_buffers_with_damage") ||
 | 
							check_egl_ext(egl->egl_exts_str, "EGL_EXT_swap_buffers_with_damage") ||
 | 
				
			||||||
		check_egl_ext(egl->egl_exts_str, "EGL_KHR_swap_buffers_with_damage");
 | 
							check_egl_ext(egl->egl_exts_str, "EGL_KHR_swap_buffers_with_damage");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						egl->egl_exts.dmabuf_import =
 | 
				
			||||||
 | 
							check_egl_ext(egl->egl_exts_str, "EGL_EXT_image_dma_buf_import");
 | 
				
			||||||
 | 
						egl->egl_exts.dmabuf_import_modifiers =
 | 
				
			||||||
 | 
							check_egl_ext(egl->egl_exts_str, "EGL_EXT_image_dma_buf_import_modifiers")
 | 
				
			||||||
 | 
							&& eglQueryDmaBufFormatsEXT && eglQueryDmaBufModifiersEXT;
 | 
				
			||||||
 | 
						print_dmabuf_formats(egl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
error:
 | 
					error:
 | 
				
			||||||
	eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
 | 
						eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
 | 
				
			||||||
 | 
						if (egl->display) {
 | 
				
			||||||
		eglTerminate(egl->display);
 | 
							eglTerminate(egl->display);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	eglReleaseThread();
 | 
						eglReleaseThread();
 | 
				
			||||||
	return false;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void wlr_egl_finish(struct wlr_egl *egl) {
 | 
					void wlr_egl_finish(struct wlr_egl *egl) {
 | 
				
			||||||
 | 
						if (egl == NULL) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
 | 
						eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
 | 
				
			||||||
	if (egl->wl_display && eglUnbindWaylandDisplayWL) {
 | 
						if (egl->wl_display && eglUnbindWaylandDisplayWL) {
 | 
				
			||||||
		eglUnbindWaylandDisplayWL(egl->display, egl->wl_display);
 | 
							eglUnbindWaylandDisplayWL(egl->display, egl->wl_display);
 | 
				
			||||||
| 
						 | 
					@ -231,7 +254,7 @@ EGLSurface wlr_egl_create_surface(struct wlr_egl *egl, void *window) {
 | 
				
			||||||
	EGLSurface surf = eglCreatePlatformWindowSurfaceEXT(egl->display, egl->config,
 | 
						EGLSurface surf = eglCreatePlatformWindowSurfaceEXT(egl->display, egl->config,
 | 
				
			||||||
		window, NULL);
 | 
							window, NULL);
 | 
				
			||||||
	if (surf == EGL_NO_SURFACE) {
 | 
						if (surf == EGL_NO_SURFACE) {
 | 
				
			||||||
		wlr_log(L_ERROR, "Failed to create EGL surface: %s", egl_error());
 | 
							wlr_log(L_ERROR, "Failed to create EGL surface");
 | 
				
			||||||
		return EGL_NO_SURFACE;
 | 
							return EGL_NO_SURFACE;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return surf;
 | 
						return surf;
 | 
				
			||||||
| 
						 | 
					@ -246,7 +269,7 @@ int wlr_egl_get_buffer_age(struct wlr_egl *egl, EGLSurface surface) {
 | 
				
			||||||
	EGLBoolean ok = eglQuerySurface(egl->display, surface,
 | 
						EGLBoolean ok = eglQuerySurface(egl->display, surface,
 | 
				
			||||||
		EGL_BUFFER_AGE_EXT, &buffer_age);
 | 
							EGL_BUFFER_AGE_EXT, &buffer_age);
 | 
				
			||||||
	if (!ok) {
 | 
						if (!ok) {
 | 
				
			||||||
		wlr_log(L_ERROR, "Failed to get EGL surface buffer age: %s", egl_error());
 | 
							wlr_log(L_ERROR, "Failed to get EGL surface buffer age");
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -256,7 +279,7 @@ int wlr_egl_get_buffer_age(struct wlr_egl *egl, EGLSurface surface) {
 | 
				
			||||||
bool wlr_egl_make_current(struct wlr_egl *egl, EGLSurface surface,
 | 
					bool wlr_egl_make_current(struct wlr_egl *egl, EGLSurface surface,
 | 
				
			||||||
		int *buffer_age) {
 | 
							int *buffer_age) {
 | 
				
			||||||
	if (!eglMakeCurrent(egl->display, surface, surface, egl->context)) {
 | 
						if (!eglMakeCurrent(egl->display, surface, surface, egl->context)) {
 | 
				
			||||||
		wlr_log(L_ERROR, "eglMakeCurrent failed: %s", egl_error());
 | 
							wlr_log(L_ERROR, "eglMakeCurrent failed");
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -294,8 +317,137 @@ bool wlr_egl_swap_buffers(struct wlr_egl *egl, EGLSurface surface,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!ret) {
 | 
						if (!ret) {
 | 
				
			||||||
		wlr_log(L_ERROR, "eglSwapBuffers failed: %s", egl_error());
 | 
							wlr_log(L_ERROR, "eglSwapBuffers failed");
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EGLImage wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl,
 | 
				
			||||||
 | 
							struct wlr_dmabuf_buffer_attribs *attributes) {
 | 
				
			||||||
 | 
						int atti = 0;
 | 
				
			||||||
 | 
						EGLint attribs[20];
 | 
				
			||||||
 | 
						attribs[atti++] = EGL_WIDTH;
 | 
				
			||||||
 | 
						attribs[atti++] = attributes->width;
 | 
				
			||||||
 | 
						attribs[atti++] = EGL_HEIGHT;
 | 
				
			||||||
 | 
						attribs[atti++] = attributes->height;
 | 
				
			||||||
 | 
						attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT;
 | 
				
			||||||
 | 
						attribs[atti++] = attributes->format;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool has_modifier = false;
 | 
				
			||||||
 | 
						if (attributes->modifier[0] != DRM_FORMAT_MOD_INVALID) {
 | 
				
			||||||
 | 
							if (!egl->egl_exts.dmabuf_import_modifiers) {
 | 
				
			||||||
 | 
								return NULL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							has_modifier = true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* TODO: YUV planes have up four planes but we only support a
 | 
				
			||||||
 | 
						   single EGLImage for now */
 | 
				
			||||||
 | 
						if (attributes->n_planes > 1) {
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						attribs[atti++] = EGL_DMA_BUF_PLANE0_FD_EXT;
 | 
				
			||||||
 | 
						attribs[atti++] = attributes->fd[0];
 | 
				
			||||||
 | 
						attribs[atti++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT;
 | 
				
			||||||
 | 
						attribs[atti++] = attributes->offset[0];
 | 
				
			||||||
 | 
						attribs[atti++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
 | 
				
			||||||
 | 
						attribs[atti++] = attributes->stride[0];
 | 
				
			||||||
 | 
						if (has_modifier) {
 | 
				
			||||||
 | 
							attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT;
 | 
				
			||||||
 | 
							attribs[atti++] = attributes->modifier[0] & 0xFFFFFFFF;
 | 
				
			||||||
 | 
							attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT;
 | 
				
			||||||
 | 
							attribs[atti++] = attributes->modifier[0] >> 32;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						attribs[atti++] = EGL_NONE;
 | 
				
			||||||
 | 
						return eglCreateImageKHR(egl->display, EGL_NO_CONTEXT,
 | 
				
			||||||
 | 
							EGL_LINUX_DMA_BUF_EXT, NULL, attribs);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef DRM_FORMAT_BIG_ENDIAN
 | 
				
			||||||
 | 
					# define DRM_FORMAT_BIG_ENDIAN 0x80000000
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					bool wlr_egl_check_import_dmabuf(struct wlr_egl *egl,
 | 
				
			||||||
 | 
							struct wlr_dmabuf_buffer *dmabuf) {
 | 
				
			||||||
 | 
						switch (dmabuf->attributes.format & ~DRM_FORMAT_BIG_ENDIAN) {
 | 
				
			||||||
 | 
							/* YUV based formats not yet supported */
 | 
				
			||||||
 | 
						case WL_SHM_FORMAT_YUYV:
 | 
				
			||||||
 | 
						case WL_SHM_FORMAT_YVYU:
 | 
				
			||||||
 | 
						case WL_SHM_FORMAT_UYVY:
 | 
				
			||||||
 | 
						case WL_SHM_FORMAT_VYUY:
 | 
				
			||||||
 | 
						case WL_SHM_FORMAT_AYUV:
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						EGLImage egl_image = wlr_egl_create_image_from_dmabuf(egl,
 | 
				
			||||||
 | 
							&dmabuf->attributes);
 | 
				
			||||||
 | 
						if (egl_image) {
 | 
				
			||||||
 | 
							/* We can import the image, good. No need to keep it
 | 
				
			||||||
 | 
							   since wlr_texture_upload_dmabuf will import it again */
 | 
				
			||||||
 | 
							wlr_egl_destroy_image(egl, egl_image);
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						/* TODO: import yuv dmabufs */
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int wlr_egl_get_dmabuf_formats(struct wlr_egl *egl,
 | 
				
			||||||
 | 
							int **formats) {
 | 
				
			||||||
 | 
						if (!egl->egl_exts.dmabuf_import ||
 | 
				
			||||||
 | 
							!egl->egl_exts.dmabuf_import_modifiers) {
 | 
				
			||||||
 | 
							wlr_log(L_ERROR, "dmabuf extension not present");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						EGLint num;
 | 
				
			||||||
 | 
						if (!eglQueryDmaBufFormatsEXT(egl->display, 0, NULL, &num)) {
 | 
				
			||||||
 | 
							wlr_log(L_ERROR, "failed to query number of dmabuf formats");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*formats = calloc(num, sizeof(int));
 | 
				
			||||||
 | 
						if (*formats == NULL) {
 | 
				
			||||||
 | 
							wlr_log(L_ERROR, "Allocation failed: %s", strerror(errno));
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!eglQueryDmaBufFormatsEXT(egl->display, num, *formats, &num)) {
 | 
				
			||||||
 | 
							wlr_log(L_ERROR, "failed to query dmabuf format");
 | 
				
			||||||
 | 
							free(*formats);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return num;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int wlr_egl_get_dmabuf_modifiers(struct wlr_egl *egl,
 | 
				
			||||||
 | 
							int format, uint64_t **modifiers) {
 | 
				
			||||||
 | 
						if (!egl->egl_exts.dmabuf_import ||
 | 
				
			||||||
 | 
							!egl->egl_exts.dmabuf_import_modifiers) {
 | 
				
			||||||
 | 
							wlr_log(L_ERROR, "dmabuf extension not present");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						EGLint num;
 | 
				
			||||||
 | 
						if (!eglQueryDmaBufModifiersEXT(egl->display, format, 0,
 | 
				
			||||||
 | 
								NULL, NULL, &num)) {
 | 
				
			||||||
 | 
							wlr_log(L_ERROR, "failed to query dmabuf number of modifiers");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*modifiers = calloc(num, sizeof(uint64_t));
 | 
				
			||||||
 | 
						if (*modifiers == NULL) {
 | 
				
			||||||
 | 
							wlr_log(L_ERROR, "Allocation failed: %s", strerror(errno));
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!eglQueryDmaBufModifiersEXT(egl->display, format, num,
 | 
				
			||||||
 | 
							*modifiers, NULL, &num)) {
 | 
				
			||||||
 | 
							wlr_log(L_ERROR, "failed to query dmabuf modifiers");
 | 
				
			||||||
 | 
							free(*modifiers);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return num;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,3 +8,10 @@ eglCreatePlatformWindowSurfaceEXT
 | 
				
			||||||
-glEGLImageTargetTexture2DOES
 | 
					-glEGLImageTargetTexture2DOES
 | 
				
			||||||
-eglSwapBuffersWithDamageEXT
 | 
					-eglSwapBuffersWithDamageEXT
 | 
				
			||||||
-eglSwapBuffersWithDamageKHR
 | 
					-eglSwapBuffersWithDamageKHR
 | 
				
			||||||
 | 
					-eglQueryDmaBufFormatsEXT
 | 
				
			||||||
 | 
					-eglQueryDmaBufModifiersEXT
 | 
				
			||||||
 | 
					-eglDebugMessageControlKHR
 | 
				
			||||||
 | 
					-glDebugMessageCallbackKHR
 | 
				
			||||||
 | 
					-glDebugMessageControlKHR
 | 
				
			||||||
 | 
					-glPopDebugGroupKHR
 | 
				
			||||||
 | 
					-glPushDebugGroupKHR
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,14 +6,14 @@
 | 
				
			||||||
* The wayland formats are little endian while the GL formats are big endian,
 | 
					* The wayland formats are little endian while the GL formats are big endian,
 | 
				
			||||||
* so WL_SHM_FORMAT_ARGB8888 is actually compatible with GL_BGRA_EXT.
 | 
					* so WL_SHM_FORMAT_ARGB8888 is actually compatible with GL_BGRA_EXT.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
struct pixel_format formats[] = {
 | 
					static const struct gles2_pixel_format formats[] = {
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		.wl_format = WL_SHM_FORMAT_ARGB8888,
 | 
							.wl_format = WL_SHM_FORMAT_ARGB8888,
 | 
				
			||||||
		.depth = 32,
 | 
							.depth = 32,
 | 
				
			||||||
		.bpp = 32,
 | 
							.bpp = 32,
 | 
				
			||||||
		.gl_format = GL_BGRA_EXT,
 | 
							.gl_format = GL_BGRA_EXT,
 | 
				
			||||||
		.gl_type = GL_UNSIGNED_BYTE,
 | 
							.gl_type = GL_UNSIGNED_BYTE,
 | 
				
			||||||
		.shader = &shaders.rgba
 | 
							.has_alpha = true,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		.wl_format = WL_SHM_FORMAT_XRGB8888,
 | 
							.wl_format = WL_SHM_FORMAT_XRGB8888,
 | 
				
			||||||
| 
						 | 
					@ -21,7 +21,7 @@ struct pixel_format formats[] = {
 | 
				
			||||||
		.bpp = 32,
 | 
							.bpp = 32,
 | 
				
			||||||
		.gl_format = GL_BGRA_EXT,
 | 
							.gl_format = GL_BGRA_EXT,
 | 
				
			||||||
		.gl_type = GL_UNSIGNED_BYTE,
 | 
							.gl_type = GL_UNSIGNED_BYTE,
 | 
				
			||||||
		.shader = &shaders.rgbx
 | 
							.has_alpha = false,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		.wl_format = WL_SHM_FORMAT_XBGR8888,
 | 
							.wl_format = WL_SHM_FORMAT_XBGR8888,
 | 
				
			||||||
| 
						 | 
					@ -29,7 +29,7 @@ struct pixel_format formats[] = {
 | 
				
			||||||
		.bpp = 32,
 | 
							.bpp = 32,
 | 
				
			||||||
		.gl_format = GL_RGBA,
 | 
							.gl_format = GL_RGBA,
 | 
				
			||||||
		.gl_type = GL_UNSIGNED_BYTE,
 | 
							.gl_type = GL_UNSIGNED_BYTE,
 | 
				
			||||||
		.shader = &shaders.rgbx
 | 
							.has_alpha = false,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		.wl_format = WL_SHM_FORMAT_ABGR8888,
 | 
							.wl_format = WL_SHM_FORMAT_ABGR8888,
 | 
				
			||||||
| 
						 | 
					@ -37,12 +37,20 @@ struct pixel_format formats[] = {
 | 
				
			||||||
		.bpp = 32,
 | 
							.bpp = 32,
 | 
				
			||||||
		.gl_format = GL_RGBA,
 | 
							.gl_format = GL_RGBA,
 | 
				
			||||||
		.gl_type = GL_UNSIGNED_BYTE,
 | 
							.gl_type = GL_UNSIGNED_BYTE,
 | 
				
			||||||
		.shader = &shaders.rgba
 | 
							.has_alpha = true,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const enum wl_shm_format wl_formats[] = {
 | 
				
			||||||
 | 
						WL_SHM_FORMAT_ARGB8888,
 | 
				
			||||||
 | 
						WL_SHM_FORMAT_XRGB8888,
 | 
				
			||||||
 | 
						WL_SHM_FORMAT_ABGR8888,
 | 
				
			||||||
 | 
						WL_SHM_FORMAT_XBGR8888,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO: more pixel formats
 | 
					// TODO: more pixel formats
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const struct pixel_format *gl_format_for_wl_format(enum wl_shm_format fmt) {
 | 
					const struct gles2_pixel_format *gles2_format_from_wl(enum wl_shm_format fmt) {
 | 
				
			||||||
	for (size_t i = 0; i < sizeof(formats) / sizeof(*formats); ++i) {
 | 
						for (size_t i = 0; i < sizeof(formats) / sizeof(*formats); ++i) {
 | 
				
			||||||
		if (formats[i].wl_format == fmt) {
 | 
							if (formats[i].wl_format == fmt) {
 | 
				
			||||||
			return &formats[i];
 | 
								return &formats[i];
 | 
				
			||||||
| 
						 | 
					@ -50,3 +58,8 @@ const struct pixel_format *gl_format_for_wl_format(enum wl_shm_format fmt) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const enum wl_shm_format *gles2_formats(size_t *len) {
 | 
				
			||||||
 | 
						*len = sizeof(wl_formats) / sizeof(wl_formats[0]);
 | 
				
			||||||
 | 
						return wl_formats;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,143 +2,80 @@
 | 
				
			||||||
#include <GLES2/gl2.h>
 | 
					#include <GLES2/gl2.h>
 | 
				
			||||||
#include <GLES2/gl2ext.h>
 | 
					#include <GLES2/gl2ext.h>
 | 
				
			||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <wayland-server-protocol.h>
 | 
					#include <wayland-server-protocol.h>
 | 
				
			||||||
#include <wayland-util.h>
 | 
					#include <wayland-util.h>
 | 
				
			||||||
#include <wlr/backend.h>
 | 
					#include <wlr/backend.h>
 | 
				
			||||||
#include <wlr/render.h>
 | 
					 | 
				
			||||||
#include <wlr/render/egl.h>
 | 
					#include <wlr/render/egl.h>
 | 
				
			||||||
#include <wlr/render/interface.h>
 | 
					#include <wlr/render/interface.h>
 | 
				
			||||||
#include <wlr/render/matrix.h>
 | 
					#include <wlr/render/wlr_renderer.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_matrix.h>
 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					#include <wlr/util/log.h>
 | 
				
			||||||
#include "render/gles2.h"
 | 
					#include "render/gles2.h"
 | 
				
			||||||
#include "glapi.h"
 | 
					#include "glapi.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct shaders shaders;
 | 
					static const struct wlr_renderer_impl renderer_impl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool compile_shader(GLuint type, const GLchar *src, GLuint *shader) {
 | 
					static struct wlr_gles2_renderer *gles2_get_renderer(
 | 
				
			||||||
	*shader = GL_CALL(glCreateShader(type));
 | 
							struct wlr_renderer *wlr_renderer) {
 | 
				
			||||||
	int len = strlen(src);
 | 
						assert(wlr_renderer->impl == &renderer_impl);
 | 
				
			||||||
	GL_CALL(glShaderSource(*shader, 1, &src, &len));
 | 
						struct wlr_gles2_renderer *renderer =
 | 
				
			||||||
	GL_CALL(glCompileShader(*shader));
 | 
							(struct wlr_gles2_renderer *)wlr_renderer;
 | 
				
			||||||
	GLint success;
 | 
						assert(eglGetCurrentContext() == renderer->egl->context);
 | 
				
			||||||
	GL_CALL(glGetShaderiv(*shader, GL_COMPILE_STATUS, &success));
 | 
						return renderer;
 | 
				
			||||||
	if (success == GL_FALSE) {
 | 
					 | 
				
			||||||
		GLint loglen;
 | 
					 | 
				
			||||||
		GL_CALL(glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &loglen));
 | 
					 | 
				
			||||||
		GLchar msg[loglen];
 | 
					 | 
				
			||||||
		GL_CALL(glGetShaderInfoLog(*shader, loglen, &loglen, msg));
 | 
					 | 
				
			||||||
		wlr_log(L_ERROR, "Shader compilation failed");
 | 
					 | 
				
			||||||
		wlr_log(L_ERROR, "%s", msg);
 | 
					 | 
				
			||||||
		glDeleteShader(*shader);
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return true;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool compile_program(const GLchar *vert_src,
 | 
					static void gles2_begin(struct wlr_renderer *wlr_renderer, uint32_t width,
 | 
				
			||||||
		const GLchar *frag_src, GLuint *program) {
 | 
							uint32_t height) {
 | 
				
			||||||
	GLuint vertex, fragment;
 | 
						gles2_get_renderer(wlr_renderer);
 | 
				
			||||||
	if (!compile_shader(GL_VERTEX_SHADER, vert_src, &vertex)) {
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (!compile_shader(GL_FRAGMENT_SHADER, frag_src, &fragment)) {
 | 
					 | 
				
			||||||
		glDeleteShader(vertex);
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	*program = GL_CALL(glCreateProgram());
 | 
					 | 
				
			||||||
	GL_CALL(glAttachShader(*program, vertex));
 | 
					 | 
				
			||||||
	GL_CALL(glAttachShader(*program, fragment));
 | 
					 | 
				
			||||||
	GL_CALL(glLinkProgram(*program));
 | 
					 | 
				
			||||||
	GLint success;
 | 
					 | 
				
			||||||
	GL_CALL(glGetProgramiv(*program, GL_LINK_STATUS, &success));
 | 
					 | 
				
			||||||
	if (success == GL_FALSE) {
 | 
					 | 
				
			||||||
		GLint loglen;
 | 
					 | 
				
			||||||
		GL_CALL(glGetProgramiv(*program, GL_INFO_LOG_LENGTH, &loglen));
 | 
					 | 
				
			||||||
		GLchar msg[loglen];
 | 
					 | 
				
			||||||
		GL_CALL(glGetProgramInfoLog(*program, loglen, &loglen, msg));
 | 
					 | 
				
			||||||
		wlr_log(L_ERROR, "Program link failed");
 | 
					 | 
				
			||||||
		wlr_log(L_ERROR, "%s", msg);
 | 
					 | 
				
			||||||
		glDeleteProgram(*program);
 | 
					 | 
				
			||||||
		glDeleteShader(vertex);
 | 
					 | 
				
			||||||
		glDeleteShader(fragment);
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	glDetachShader(*program, vertex);
 | 
					 | 
				
			||||||
	glDetachShader(*program, fragment);
 | 
					 | 
				
			||||||
	glDeleteShader(vertex);
 | 
					 | 
				
			||||||
	glDeleteShader(fragment);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return true;
 | 
						GLES2_DEBUG_PUSH;
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void init_default_shaders() {
 | 
						glViewport(0, 0, width, height);
 | 
				
			||||||
	if (shaders.initialized) {
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (!compile_program(vertex_src, fragment_src_rgba, &shaders.rgba)) {
 | 
					 | 
				
			||||||
		goto error;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (!compile_program(vertex_src, fragment_src_rgbx, &shaders.rgbx)) {
 | 
					 | 
				
			||||||
		goto error;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (!compile_program(quad_vertex_src, quad_fragment_src, &shaders.quad)) {
 | 
					 | 
				
			||||||
		goto error;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (!compile_program(quad_vertex_src, ellipse_fragment_src, &shaders.ellipse)) {
 | 
					 | 
				
			||||||
		goto error;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (glEGLImageTargetTexture2DOES) {
 | 
					 | 
				
			||||||
		if (!compile_program(quad_vertex_src, fragment_src_external, &shaders.external)) {
 | 
					 | 
				
			||||||
			goto error;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wlr_log(L_DEBUG, "Compiled default shaders");
 | 
					 | 
				
			||||||
	shaders.initialized = true;
 | 
					 | 
				
			||||||
	return;
 | 
					 | 
				
			||||||
error:
 | 
					 | 
				
			||||||
	wlr_log(L_ERROR, "Failed to set up default shaders!");
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void init_globals() {
 | 
					 | 
				
			||||||
	init_default_shaders();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void wlr_gles2_begin(struct wlr_renderer *wlr_renderer,
 | 
					 | 
				
			||||||
		struct wlr_output *output) {
 | 
					 | 
				
			||||||
	GL_CALL(glViewport(0, 0, output->width, output->height));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// enable transparency
 | 
						// enable transparency
 | 
				
			||||||
	GL_CALL(glEnable(GL_BLEND));
 | 
						glEnable(GL_BLEND);
 | 
				
			||||||
	GL_CALL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
 | 
						glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Note: maybe we should save output projection and remove some of the need
 | 
						// XXX: maybe we should save output projection and remove some of the need
 | 
				
			||||||
	// for users to sling matricies themselves
 | 
						// for users to sling matricies themselves
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GLES2_DEBUG_POP;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void wlr_gles2_end(struct wlr_renderer *wlr_renderer) {
 | 
					static void gles2_end(struct wlr_renderer *wlr_renderer) {
 | 
				
			||||||
 | 
						gles2_get_renderer(wlr_renderer);
 | 
				
			||||||
	// no-op
 | 
						// no-op
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void wlr_gles2_clear(struct wlr_renderer *wlr_renderer,
 | 
					static void gles2_clear(struct wlr_renderer *wlr_renderer,
 | 
				
			||||||
		const float (*color)[4]) {
 | 
							const float color[static 4]) {
 | 
				
			||||||
	glClearColor((*color)[0], (*color)[1], (*color)[2], (*color)[3]);
 | 
						gles2_get_renderer(wlr_renderer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GLES2_DEBUG_PUSH;
 | 
				
			||||||
 | 
						glClearColor(color[0], color[1], color[2], color[3]);
 | 
				
			||||||
	glClear(GL_COLOR_BUFFER_BIT);
 | 
						glClear(GL_COLOR_BUFFER_BIT);
 | 
				
			||||||
 | 
						GLES2_DEBUG_POP;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void wlr_gles2_scissor(struct wlr_renderer *wlr_renderer,
 | 
					static void gles2_scissor(struct wlr_renderer *wlr_renderer,
 | 
				
			||||||
		struct wlr_box *box) {
 | 
							struct wlr_box *box) {
 | 
				
			||||||
 | 
						gles2_get_renderer(wlr_renderer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GLES2_DEBUG_PUSH;
 | 
				
			||||||
	if (box != NULL) {
 | 
						if (box != NULL) {
 | 
				
			||||||
		glScissor(box->x, box->y, box->width, box->height);
 | 
							glScissor(box->x, box->y, box->width, box->height);
 | 
				
			||||||
		glEnable(GL_SCISSOR_TEST);
 | 
							glEnable(GL_SCISSOR_TEST);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		glDisable(GL_SCISSOR_TEST);
 | 
							glDisable(GL_SCISSOR_TEST);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						GLES2_DEBUG_POP;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct wlr_texture *wlr_gles2_texture_create(
 | 
					static struct wlr_texture *gles2_renderer_texture_create(
 | 
				
			||||||
		struct wlr_renderer *wlr_renderer) {
 | 
							struct wlr_renderer *wlr_renderer) {
 | 
				
			||||||
 | 
						assert(wlr_renderer->impl == &renderer_impl);
 | 
				
			||||||
	struct wlr_gles2_renderer *renderer =
 | 
						struct wlr_gles2_renderer *renderer =
 | 
				
			||||||
		(struct wlr_gles2_renderer *)wlr_renderer;
 | 
							(struct wlr_gles2_renderer *)wlr_renderer;
 | 
				
			||||||
	return gles2_texture_create(renderer->egl);
 | 
						return gles2_texture_create(renderer->egl);
 | 
				
			||||||
| 
						 | 
					@ -158,80 +95,117 @@ static void draw_quad() {
 | 
				
			||||||
		0, 1, // bottom left
 | 
							0, 1, // bottom left
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	GL_CALL(glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, verts));
 | 
						glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, verts);
 | 
				
			||||||
	GL_CALL(glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, texcoord));
 | 
						glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, texcoord);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	GL_CALL(glEnableVertexAttribArray(0));
 | 
						glEnableVertexAttribArray(0);
 | 
				
			||||||
	GL_CALL(glEnableVertexAttribArray(1));
 | 
						glEnableVertexAttribArray(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	GL_CALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
 | 
						glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	GL_CALL(glDisableVertexAttribArray(0));
 | 
						glDisableVertexAttribArray(0);
 | 
				
			||||||
	GL_CALL(glDisableVertexAttribArray(1));
 | 
						glDisableVertexAttribArray(1);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool wlr_gles2_render_texture(struct wlr_renderer *wlr_renderer,
 | 
					static bool gles2_render_texture_with_matrix(
 | 
				
			||||||
		struct wlr_texture *texture, const float (*matrix)[16], float alpha) {
 | 
							struct wlr_renderer *wlr_renderer, struct wlr_texture *wlr_texture,
 | 
				
			||||||
	if (!texture || !texture->valid) {
 | 
							const float matrix[static 9], float alpha) {
 | 
				
			||||||
 | 
						struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
 | 
				
			||||||
 | 
						struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
 | 
				
			||||||
 | 
						if (!wlr_texture->valid) {
 | 
				
			||||||
		wlr_log(L_ERROR, "attempt to render invalid texture");
 | 
							wlr_log(L_ERROR, "attempt to render invalid texture");
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_texture_bind(texture);
 | 
						GLuint prog = renderer->shaders.tex_rgba;
 | 
				
			||||||
	GL_CALL(glUniformMatrix4fv(0, 1, GL_FALSE, *matrix));
 | 
						if (texture->target == GL_TEXTURE_EXTERNAL_OES) {
 | 
				
			||||||
	GL_CALL(glUniform1f(2, alpha));
 | 
							prog = renderer->shaders.tex_ext;
 | 
				
			||||||
 | 
						} else if (!texture->pixel_format->has_alpha) {
 | 
				
			||||||
 | 
							prog = renderer->shaders.tex_rgbx;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set
 | 
				
			||||||
 | 
						// to GL_FALSE
 | 
				
			||||||
 | 
						float transposition[9];
 | 
				
			||||||
 | 
						wlr_matrix_transpose(transposition, matrix);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GLES2_DEBUG_PUSH;
 | 
				
			||||||
 | 
						glBindTexture(texture->target, texture->tex_id);
 | 
				
			||||||
 | 
						glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 | 
				
			||||||
 | 
						glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 | 
				
			||||||
 | 
						glUseProgram(prog);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						glUniformMatrix3fv(0, 1, GL_FALSE, transposition);
 | 
				
			||||||
 | 
						glUniform1i(1, wlr_texture->inverted_y);
 | 
				
			||||||
 | 
						glUniform1f(3, alpha);
 | 
				
			||||||
	draw_quad();
 | 
						draw_quad();
 | 
				
			||||||
 | 
						GLES2_DEBUG_POP;
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void wlr_gles2_render_quad(struct wlr_renderer *wlr_renderer,
 | 
					static void gles2_render_quad(struct wlr_renderer *wlr_renderer,
 | 
				
			||||||
		const float (*color)[4], const float (*matrix)[16]) {
 | 
							const float color[static 4], const float matrix[static 9]) {
 | 
				
			||||||
	GL_CALL(glUseProgram(shaders.quad));
 | 
						struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
 | 
				
			||||||
	GL_CALL(glUniformMatrix4fv(0, 1, GL_FALSE, *matrix));
 | 
					
 | 
				
			||||||
	GL_CALL(glUniform4f(1, (*color)[0], (*color)[1], (*color)[2], (*color)[3]));
 | 
						// OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set
 | 
				
			||||||
 | 
						// to GL_FALSE
 | 
				
			||||||
 | 
						float transposition[9];
 | 
				
			||||||
 | 
						wlr_matrix_transpose(transposition, matrix);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GLES2_DEBUG_PUSH;
 | 
				
			||||||
 | 
						glUseProgram(renderer->shaders.quad);
 | 
				
			||||||
 | 
						glUniformMatrix3fv(0, 1, GL_FALSE, transposition);
 | 
				
			||||||
 | 
						glUniform4f(1, color[0], color[1], color[2], color[3]);
 | 
				
			||||||
	draw_quad();
 | 
						draw_quad();
 | 
				
			||||||
 | 
						GLES2_DEBUG_POP;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void wlr_gles2_render_ellipse(struct wlr_renderer *wlr_renderer,
 | 
					static void gles2_render_ellipse(struct wlr_renderer *wlr_renderer,
 | 
				
			||||||
		const float (*color)[4], const float (*matrix)[16]) {
 | 
							const float color[static 4], const float matrix[static 9]) {
 | 
				
			||||||
	GL_CALL(glUseProgram(shaders.ellipse));
 | 
						struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
 | 
				
			||||||
	GL_CALL(glUniformMatrix4fv(0, 1, GL_TRUE, *matrix));
 | 
					
 | 
				
			||||||
	GL_CALL(glUniform4f(1, (*color)[0], (*color)[1], (*color)[2], (*color)[3]));
 | 
						// OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set
 | 
				
			||||||
 | 
						// to GL_FALSE
 | 
				
			||||||
 | 
						float transposition[9];
 | 
				
			||||||
 | 
						wlr_matrix_transpose(transposition, matrix);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GLES2_DEBUG_PUSH;
 | 
				
			||||||
 | 
						glUseProgram(renderer->shaders.ellipse);
 | 
				
			||||||
 | 
						glUniformMatrix3fv(0, 1, GL_FALSE, transposition);
 | 
				
			||||||
 | 
						glUniform4f(1, color[0], color[1], color[2], color[3]);
 | 
				
			||||||
	draw_quad();
 | 
						draw_quad();
 | 
				
			||||||
 | 
						GLES2_DEBUG_POP;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const enum wl_shm_format *wlr_gles2_formats(
 | 
					static const enum wl_shm_format *gles2_renderer_formats(
 | 
				
			||||||
		struct wlr_renderer *renderer, size_t *len) {
 | 
							struct wlr_renderer *wlr_renderer, size_t *len) {
 | 
				
			||||||
	static enum wl_shm_format formats[] = {
 | 
						return gles2_formats(len);
 | 
				
			||||||
		WL_SHM_FORMAT_ARGB8888,
 | 
					 | 
				
			||||||
		WL_SHM_FORMAT_XRGB8888,
 | 
					 | 
				
			||||||
		WL_SHM_FORMAT_ABGR8888,
 | 
					 | 
				
			||||||
		WL_SHM_FORMAT_XBGR8888,
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
	*len = sizeof(formats) / sizeof(formats[0]);
 | 
					 | 
				
			||||||
	return formats;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool wlr_gles2_buffer_is_drm(struct wlr_renderer *wlr_renderer,
 | 
					static bool gles2_buffer_is_drm(struct wlr_renderer *wlr_renderer,
 | 
				
			||||||
		struct wl_resource *buffer) {
 | 
							struct wl_resource *buffer) {
 | 
				
			||||||
	struct wlr_gles2_renderer *renderer =
 | 
						struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
 | 
				
			||||||
		(struct wlr_gles2_renderer *)wlr_renderer;
 | 
					
 | 
				
			||||||
	EGLint format;
 | 
						EGLint format;
 | 
				
			||||||
	return wlr_egl_query_buffer(renderer->egl, buffer,
 | 
						return wlr_egl_query_buffer(renderer->egl, buffer, EGL_TEXTURE_FORMAT,
 | 
				
			||||||
		EGL_TEXTURE_FORMAT, &format);
 | 
							&format);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool wlr_gles2_read_pixels(struct wlr_renderer *renderer,
 | 
					static bool gles2_read_pixels(struct wlr_renderer *wlr_renderer,
 | 
				
			||||||
		enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width,
 | 
							enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width,
 | 
				
			||||||
		uint32_t height, uint32_t src_x, uint32_t src_y, uint32_t dst_x,
 | 
							uint32_t height, uint32_t src_x, uint32_t src_y, uint32_t dst_x,
 | 
				
			||||||
		uint32_t dst_y, void *data) {
 | 
							uint32_t dst_y, void *data) {
 | 
				
			||||||
	const struct pixel_format *fmt = gl_format_for_wl_format(wl_fmt);
 | 
						gles2_get_renderer(wlr_renderer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const struct gles2_pixel_format *fmt = gles2_format_from_wl(wl_fmt);
 | 
				
			||||||
	if (fmt == NULL) {
 | 
						if (fmt == NULL) {
 | 
				
			||||||
		wlr_log(L_ERROR, "Cannot read pixels: unsupported pixel format");
 | 
							wlr_log(L_ERROR, "Cannot read pixels: unsupported pixel format");
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GLES2_DEBUG_PUSH;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Make sure any pending drawing is finished before we try to read it
 | 
						// Make sure any pending drawing is finished before we try to read it
 | 
				
			||||||
	glFinish();
 | 
						glFinish();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -243,38 +217,225 @@ static bool wlr_gles2_read_pixels(struct wlr_renderer *renderer,
 | 
				
			||||||
			fmt->gl_type, p + i * stride + dst_x * fmt->bpp / 8);
 | 
								fmt->gl_type, p + i * stride + dst_x * fmt->bpp / 8);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GLES2_DEBUG_POP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool wlr_gles2_format_supported(struct wlr_renderer *r,
 | 
					static bool gles2_format_supported(struct wlr_renderer *r,
 | 
				
			||||||
		enum wl_shm_format wl_fmt) {
 | 
							enum wl_shm_format wl_fmt) {
 | 
				
			||||||
	return gl_format_for_wl_format(wl_fmt);
 | 
						return gles2_format_from_wl(wl_fmt) != NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct wlr_renderer_impl wlr_renderer_impl = {
 | 
					static void gles2_destroy(struct wlr_renderer *wlr_renderer) {
 | 
				
			||||||
	.begin = wlr_gles2_begin,
 | 
						struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
 | 
				
			||||||
	.end = wlr_gles2_end,
 | 
					
 | 
				
			||||||
	.clear = wlr_gles2_clear,
 | 
						wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL);
 | 
				
			||||||
	.scissor = wlr_gles2_scissor,
 | 
					
 | 
				
			||||||
	.texture_create = wlr_gles2_texture_create,
 | 
						GLES2_DEBUG_PUSH;
 | 
				
			||||||
	.render_with_matrix = wlr_gles2_render_texture,
 | 
						glDeleteProgram(renderer->shaders.quad);
 | 
				
			||||||
	.render_quad = wlr_gles2_render_quad,
 | 
						glDeleteProgram(renderer->shaders.ellipse);
 | 
				
			||||||
	.render_ellipse = wlr_gles2_render_ellipse,
 | 
						glDeleteProgram(renderer->shaders.tex_rgba);
 | 
				
			||||||
	.formats = wlr_gles2_formats,
 | 
						glDeleteProgram(renderer->shaders.tex_rgbx);
 | 
				
			||||||
	.buffer_is_drm = wlr_gles2_buffer_is_drm,
 | 
						glDeleteProgram(renderer->shaders.tex_ext);
 | 
				
			||||||
	.read_pixels = wlr_gles2_read_pixels,
 | 
						GLES2_DEBUG_POP;
 | 
				
			||||||
	.format_supported = wlr_gles2_format_supported,
 | 
					
 | 
				
			||||||
 | 
						if (glDebugMessageCallbackKHR) {
 | 
				
			||||||
 | 
							glDisable(GL_DEBUG_OUTPUT_KHR);
 | 
				
			||||||
 | 
							glDebugMessageCallbackKHR(NULL, NULL);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						free(renderer);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct wlr_renderer_impl renderer_impl = {
 | 
				
			||||||
 | 
						.destroy = gles2_destroy,
 | 
				
			||||||
 | 
						.begin = gles2_begin,
 | 
				
			||||||
 | 
						.end = gles2_end,
 | 
				
			||||||
 | 
						.clear = gles2_clear,
 | 
				
			||||||
 | 
						.scissor = gles2_scissor,
 | 
				
			||||||
 | 
						.texture_create = gles2_renderer_texture_create,
 | 
				
			||||||
 | 
						.render_texture_with_matrix = gles2_render_texture_with_matrix,
 | 
				
			||||||
 | 
						.render_quad = gles2_render_quad,
 | 
				
			||||||
 | 
						.render_ellipse = gles2_render_ellipse,
 | 
				
			||||||
 | 
						.formats = gles2_renderer_formats,
 | 
				
			||||||
 | 
						.buffer_is_drm = gles2_buffer_is_drm,
 | 
				
			||||||
 | 
						.read_pixels = gles2_read_pixels,
 | 
				
			||||||
 | 
						.format_supported = gles2_format_supported,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void gles2_push_marker(const char *file, const char *func) {
 | 
				
			||||||
 | 
						if (!glPushDebugGroupKHR) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int len = snprintf(NULL, 0, "%s:%s", file, func) + 1;
 | 
				
			||||||
 | 
						char str[len];
 | 
				
			||||||
 | 
						snprintf(str, len, "%s:%s", file, func);
 | 
				
			||||||
 | 
						glPushDebugGroupKHR(GL_DEBUG_SOURCE_APPLICATION_KHR, 1, -1, str);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void gles2_pop_marker(void) {
 | 
				
			||||||
 | 
						if (glPopDebugGroupKHR) {
 | 
				
			||||||
 | 
							glPopDebugGroupKHR();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static log_importance_t gles2_log_importance_to_wlr(GLenum type) {
 | 
				
			||||||
 | 
						switch (type) {
 | 
				
			||||||
 | 
						case GL_DEBUG_TYPE_ERROR_KHR:               return L_ERROR;
 | 
				
			||||||
 | 
						case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_KHR: return L_DEBUG;
 | 
				
			||||||
 | 
						case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_KHR:  return L_ERROR;
 | 
				
			||||||
 | 
						case GL_DEBUG_TYPE_PORTABILITY_KHR:         return L_DEBUG;
 | 
				
			||||||
 | 
						case GL_DEBUG_TYPE_PERFORMANCE_KHR:         return L_DEBUG;
 | 
				
			||||||
 | 
						case GL_DEBUG_TYPE_OTHER_KHR:               return L_INFO;
 | 
				
			||||||
 | 
						case GL_DEBUG_TYPE_MARKER_KHR:              return L_DEBUG;
 | 
				
			||||||
 | 
						case GL_DEBUG_TYPE_PUSH_GROUP_KHR:          return L_DEBUG;
 | 
				
			||||||
 | 
						case GL_DEBUG_TYPE_POP_GROUP_KHR:           return L_DEBUG;
 | 
				
			||||||
 | 
						default:                                    return L_INFO;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void gles2_log(GLenum src, GLenum type, GLuint id, GLenum severity,
 | 
				
			||||||
 | 
							GLsizei len, const GLchar *msg, const void *user) {
 | 
				
			||||||
 | 
						_wlr_log(gles2_log_importance_to_wlr(type), "[GLES2] %s", msg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static GLuint compile_shader(GLuint type, const GLchar *src) {
 | 
				
			||||||
 | 
						GLES2_DEBUG_PUSH;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GLuint shader = glCreateShader(type);
 | 
				
			||||||
 | 
						glShaderSource(shader, 1, &src, NULL);
 | 
				
			||||||
 | 
						glCompileShader(shader);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GLint ok;
 | 
				
			||||||
 | 
						glGetShaderiv(shader, GL_COMPILE_STATUS, &ok);
 | 
				
			||||||
 | 
						if (ok == GL_FALSE) {
 | 
				
			||||||
 | 
							glDeleteShader(shader);
 | 
				
			||||||
 | 
							shader = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GLES2_DEBUG_POP;
 | 
				
			||||||
 | 
						return shader;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static GLuint link_program(const GLchar *vert_src, const GLchar *frag_src) {
 | 
				
			||||||
 | 
						GLES2_DEBUG_PUSH;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GLuint vert = compile_shader(GL_VERTEX_SHADER, vert_src);
 | 
				
			||||||
 | 
						if (!vert) {
 | 
				
			||||||
 | 
							goto error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GLuint frag = compile_shader(GL_FRAGMENT_SHADER, frag_src);
 | 
				
			||||||
 | 
						if (!frag) {
 | 
				
			||||||
 | 
							glDeleteShader(vert);
 | 
				
			||||||
 | 
							goto error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GLuint prog = glCreateProgram();
 | 
				
			||||||
 | 
						glAttachShader(prog, vert);
 | 
				
			||||||
 | 
						glAttachShader(prog, frag);
 | 
				
			||||||
 | 
						glLinkProgram(prog);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						glDetachShader(prog, vert);
 | 
				
			||||||
 | 
						glDetachShader(prog, frag);
 | 
				
			||||||
 | 
						glDeleteShader(vert);
 | 
				
			||||||
 | 
						glDeleteShader(frag);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GLint ok;
 | 
				
			||||||
 | 
						glGetProgramiv(prog, GL_LINK_STATUS, &ok);
 | 
				
			||||||
 | 
						if (ok == GL_FALSE) {
 | 
				
			||||||
 | 
							glDeleteProgram(prog);
 | 
				
			||||||
 | 
							goto error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GLES2_DEBUG_POP;
 | 
				
			||||||
 | 
						return prog;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					error:
 | 
				
			||||||
 | 
						GLES2_DEBUG_POP;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern const GLchar quad_vertex_src[];
 | 
				
			||||||
 | 
					extern const GLchar quad_fragment_src[];
 | 
				
			||||||
 | 
					extern const GLchar ellipse_fragment_src[];
 | 
				
			||||||
 | 
					extern const GLchar tex_vertex_src[];
 | 
				
			||||||
 | 
					extern const GLchar tex_fragment_src_rgba[];
 | 
				
			||||||
 | 
					extern const GLchar tex_fragment_src_rgbx[];
 | 
				
			||||||
 | 
					extern const GLchar tex_fragment_src_external[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_backend *backend) {
 | 
					struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_backend *backend) {
 | 
				
			||||||
	init_globals();
 | 
						struct wlr_gles2_renderer *renderer =
 | 
				
			||||||
	struct wlr_gles2_renderer *renderer;
 | 
							calloc(1, sizeof(struct wlr_gles2_renderer));
 | 
				
			||||||
	if (!(renderer = calloc(1, sizeof(struct wlr_gles2_renderer)))) {
 | 
						if (renderer == NULL) {
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	wlr_renderer_init(&renderer->wlr_renderer, &wlr_renderer_impl);
 | 
						wlr_renderer_init(&renderer->wlr_renderer, &renderer_impl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	renderer->egl = wlr_backend_get_egl(backend);
 | 
						renderer->egl = wlr_backend_get_egl(backend);
 | 
				
			||||||
 | 
						wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (glDebugMessageCallbackKHR && glDebugMessageControlKHR) {
 | 
				
			||||||
 | 
							glEnable(GL_DEBUG_OUTPUT_KHR);
 | 
				
			||||||
 | 
							glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR);
 | 
				
			||||||
 | 
							glDebugMessageCallbackKHR(gles2_log, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Silence unwanted message types
 | 
				
			||||||
 | 
							glDebugMessageControlKHR(GL_DONT_CARE, GL_DEBUG_TYPE_POP_GROUP_KHR,
 | 
				
			||||||
 | 
								GL_DONT_CARE, 0, NULL, GL_FALSE);
 | 
				
			||||||
 | 
							glDebugMessageControlKHR(GL_DONT_CARE, GL_DEBUG_TYPE_PUSH_GROUP_KHR,
 | 
				
			||||||
 | 
								GL_DONT_CARE, 0, NULL, GL_FALSE);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GLES2_DEBUG_PUSH;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						renderer->shaders.quad = link_program(quad_vertex_src, quad_fragment_src);
 | 
				
			||||||
 | 
						if (!renderer->shaders.quad) {
 | 
				
			||||||
 | 
							goto error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						renderer->shaders.ellipse =
 | 
				
			||||||
 | 
							link_program(quad_vertex_src, ellipse_fragment_src);
 | 
				
			||||||
 | 
						if (!renderer->shaders.ellipse) {
 | 
				
			||||||
 | 
							goto error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						renderer->shaders.tex_rgba =
 | 
				
			||||||
 | 
							link_program(tex_vertex_src, tex_fragment_src_rgba);
 | 
				
			||||||
 | 
						if (!renderer->shaders.tex_rgba) {
 | 
				
			||||||
 | 
							goto error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						renderer->shaders.tex_rgbx =
 | 
				
			||||||
 | 
							link_program(tex_vertex_src, tex_fragment_src_rgbx);
 | 
				
			||||||
 | 
						if (!renderer->shaders.tex_rgbx) {
 | 
				
			||||||
 | 
							goto error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (glEGLImageTargetTexture2DOES) {
 | 
				
			||||||
 | 
							renderer->shaders.tex_ext =
 | 
				
			||||||
 | 
								link_program(tex_vertex_src, tex_fragment_src_external);
 | 
				
			||||||
 | 
							if (!renderer->shaders.tex_ext) {
 | 
				
			||||||
 | 
								goto error;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GLES2_DEBUG_POP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return &renderer->wlr_renderer;
 | 
						return &renderer->wlr_renderer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					error:
 | 
				
			||||||
 | 
						glDeleteProgram(renderer->shaders.quad);
 | 
				
			||||||
 | 
						glDeleteProgram(renderer->shaders.ellipse);
 | 
				
			||||||
 | 
						glDeleteProgram(renderer->shaders.tex_rgba);
 | 
				
			||||||
 | 
						glDeleteProgram(renderer->shaders.tex_rgbx);
 | 
				
			||||||
 | 
						glDeleteProgram(renderer->shaders.tex_ext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GLES2_DEBUG_POP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (glDebugMessageCallbackKHR) {
 | 
				
			||||||
 | 
							glDisable(GL_DEBUG_OUTPUT_KHR);
 | 
				
			||||||
 | 
							glDebugMessageCallbackKHR(NULL, NULL);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						free(renderer);
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,100 +3,88 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Colored quads
 | 
					// Colored quads
 | 
				
			||||||
const GLchar quad_vertex_src[] =
 | 
					const GLchar quad_vertex_src[] =
 | 
				
			||||||
"uniform mat4 proj;"
 | 
					"uniform mat3 proj;\n"
 | 
				
			||||||
"uniform vec4 color;"
 | 
					"uniform vec4 color;\n"
 | 
				
			||||||
"attribute vec2 pos;"
 | 
					"attribute vec2 pos;\n"
 | 
				
			||||||
"attribute vec2 texcoord;"
 | 
					"attribute vec2 texcoord;\n"
 | 
				
			||||||
"varying vec4 v_color;"
 | 
					"varying vec4 v_color;\n"
 | 
				
			||||||
"varying vec2 v_texcoord;"
 | 
					"varying vec2 v_texcoord;\n"
 | 
				
			||||||
"mat4 transpose(in mat4 inMatrix) {"
 | 
					"\n"
 | 
				
			||||||
"    vec4 i0 = inMatrix[0];"
 | 
					"void main() {\n"
 | 
				
			||||||
"    vec4 i1 = inMatrix[1];"
 | 
					"	gl_Position = vec4(proj * vec3(pos, 1.0), 1.0);\n"
 | 
				
			||||||
"    vec4 i2 = inMatrix[2];"
 | 
					"	v_color = color;\n"
 | 
				
			||||||
"    vec4 i3 = inMatrix[3];"
 | 
					"	v_texcoord = texcoord;\n"
 | 
				
			||||||
"    mat4 outMatrix = mat4("
 | 
					"}\n";
 | 
				
			||||||
"                 vec4(i0.x, i1.x, i2.x, i3.x),"
 | 
					 | 
				
			||||||
"                 vec4(i0.y, i1.y, i2.y, i3.y),"
 | 
					 | 
				
			||||||
"                 vec4(i0.z, i1.z, i2.z, i3.z),"
 | 
					 | 
				
			||||||
"                 vec4(i0.w, i1.w, i2.w, i3.w)"
 | 
					 | 
				
			||||||
"                 );"
 | 
					 | 
				
			||||||
"    return outMatrix;"
 | 
					 | 
				
			||||||
"}"
 | 
					 | 
				
			||||||
"void main() {"
 | 
					 | 
				
			||||||
"  gl_Position = transpose(proj) * vec4(pos, 0.0, 1.0);"
 | 
					 | 
				
			||||||
"  v_color = color;"
 | 
					 | 
				
			||||||
"  v_texcoord = texcoord;"
 | 
					 | 
				
			||||||
"}";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const GLchar quad_fragment_src[] =
 | 
					const GLchar quad_fragment_src[] =
 | 
				
			||||||
"precision mediump float;"
 | 
					"precision mediump float;\n"
 | 
				
			||||||
"varying vec4 v_color;"
 | 
					"varying vec4 v_color;\n"
 | 
				
			||||||
"varying vec2 v_texcoord;"
 | 
					"varying vec2 v_texcoord;\n"
 | 
				
			||||||
"void main() {"
 | 
					"\n"
 | 
				
			||||||
"  gl_FragColor = v_color;"
 | 
					"void main() {\n"
 | 
				
			||||||
"}";
 | 
					"	gl_FragColor = v_color;\n"
 | 
				
			||||||
 | 
					"}\n";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Colored ellipses
 | 
					// Colored ellipses
 | 
				
			||||||
const GLchar ellipse_fragment_src[] =
 | 
					const GLchar ellipse_fragment_src[] =
 | 
				
			||||||
"precision mediump float;"
 | 
					"precision mediump float;\n"
 | 
				
			||||||
"varying vec4 v_color;"
 | 
					"varying vec4 v_color;\n"
 | 
				
			||||||
"varying vec2 v_texcoord;"
 | 
					"varying vec2 v_texcoord;\n"
 | 
				
			||||||
"void main() {"
 | 
					"\n"
 | 
				
			||||||
"  float l = length(v_texcoord - vec2(0.5, 0.5));"
 | 
					"void main() {\n"
 | 
				
			||||||
"  if (l > 0.5) discard;"
 | 
					"	float l = length(v_texcoord - vec2(0.5, 0.5));\n"
 | 
				
			||||||
"  gl_FragColor = v_color;"
 | 
					"	if (l > 0.5) {\n"
 | 
				
			||||||
"}";
 | 
					"		discard;\n"
 | 
				
			||||||
 | 
					"	}\n"
 | 
				
			||||||
 | 
					"	gl_FragColor = v_color;\n"
 | 
				
			||||||
 | 
					"}\n";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Textured quads
 | 
					// Textured quads
 | 
				
			||||||
const GLchar vertex_src[] =
 | 
					const GLchar tex_vertex_src[] =
 | 
				
			||||||
"uniform mat4 proj;"
 | 
					"uniform mat3 proj;\n"
 | 
				
			||||||
"attribute vec2 pos;"
 | 
					"uniform bool invert_y;\n"
 | 
				
			||||||
"attribute vec2 texcoord;"
 | 
					"attribute vec2 pos;\n"
 | 
				
			||||||
"varying vec2 v_texcoord;"
 | 
					"attribute vec2 texcoord;\n"
 | 
				
			||||||
"mat4 transpose(in mat4 inMatrix) {"
 | 
					"varying vec2 v_texcoord;\n"
 | 
				
			||||||
"    vec4 i0 = inMatrix[0];"
 | 
					"\n"
 | 
				
			||||||
"    vec4 i1 = inMatrix[1];"
 | 
					"void main() {\n"
 | 
				
			||||||
"    vec4 i2 = inMatrix[2];"
 | 
					"	gl_Position = vec4(proj * vec3(pos, 1.0), 1.0);\n"
 | 
				
			||||||
"    vec4 i3 = inMatrix[3];"
 | 
					"	if (invert_y) {\n"
 | 
				
			||||||
"    mat4 outMatrix = mat4("
 | 
					"		v_texcoord = vec2(texcoord.s, 1.0 - texcoord.t);\n"
 | 
				
			||||||
"                 vec4(i0.x, i1.x, i2.x, i3.x),"
 | 
					"	} else {\n"
 | 
				
			||||||
"                 vec4(i0.y, i1.y, i2.y, i3.y),"
 | 
					"		v_texcoord = texcoord;\n"
 | 
				
			||||||
"                 vec4(i0.z, i1.z, i2.z, i3.z),"
 | 
					"	}\n"
 | 
				
			||||||
"                 vec4(i0.w, i1.w, i2.w, i3.w)"
 | 
					"}\n";
 | 
				
			||||||
"                 );"
 | 
					 | 
				
			||||||
""
 | 
					 | 
				
			||||||
"    return outMatrix;"
 | 
					 | 
				
			||||||
"}"
 | 
					 | 
				
			||||||
"void main() {"
 | 
					 | 
				
			||||||
"	gl_Position = transpose(proj) * vec4(pos, 0.0, 1.0);"
 | 
					 | 
				
			||||||
"	v_texcoord = texcoord;"
 | 
					 | 
				
			||||||
"}";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const GLchar fragment_src_rgba[] =
 | 
					const GLchar tex_fragment_src_rgba[] =
 | 
				
			||||||
"precision mediump float;"
 | 
					"precision mediump float;\n"
 | 
				
			||||||
"varying vec2 v_texcoord;"
 | 
					"varying vec2 v_texcoord;\n"
 | 
				
			||||||
"uniform sampler2D tex;"
 | 
					"uniform sampler2D tex;\n"
 | 
				
			||||||
"uniform float alpha;"
 | 
					"uniform float alpha;\n"
 | 
				
			||||||
"void main() {"
 | 
					"\n"
 | 
				
			||||||
"	gl_FragColor = alpha * texture2D(tex, v_texcoord);"
 | 
					"void main() {\n"
 | 
				
			||||||
"}";
 | 
					"	gl_FragColor = alpha * texture2D(tex, v_texcoord);\n"
 | 
				
			||||||
 | 
					"}\n";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const GLchar fragment_src_rgbx[] =
 | 
					const GLchar tex_fragment_src_rgbx[] =
 | 
				
			||||||
"precision mediump float;"
 | 
					"precision mediump float;\n"
 | 
				
			||||||
"varying vec2 v_texcoord;"
 | 
					"varying vec2 v_texcoord;\n"
 | 
				
			||||||
"uniform sampler2D tex;"
 | 
					"uniform sampler2D tex;\n"
 | 
				
			||||||
"uniform float alpha;"
 | 
					"uniform float alpha;\n"
 | 
				
			||||||
"void main() {"
 | 
					"\n"
 | 
				
			||||||
"   gl_FragColor.rgb = alpha * texture2D(tex, v_texcoord).rgb;"
 | 
					"void main() {\n"
 | 
				
			||||||
"   gl_FragColor.a = alpha;"
 | 
					"	gl_FragColor.rgb = alpha * texture2D(tex, v_texcoord).rgb;\n"
 | 
				
			||||||
"}";
 | 
					"	gl_FragColor.a = alpha;\n"
 | 
				
			||||||
 | 
					"}\n";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const GLchar fragment_src_external[] =
 | 
					const GLchar tex_fragment_src_external[] =
 | 
				
			||||||
"#extension GL_OES_EGL_image_external : require\n"
 | 
					"#extension GL_OES_EGL_image_external : require\n\n"
 | 
				
			||||||
"precision mediump float;"
 | 
					"precision mediump float;\n"
 | 
				
			||||||
"varying vec2 v_texcoord;"
 | 
					"varying vec2 v_texcoord;\n"
 | 
				
			||||||
"uniform samplerExternalOES texture0;"
 | 
					"uniform samplerExternalOES texture0;\n"
 | 
				
			||||||
"void main() {"
 | 
					"uniform float alpha;\n"
 | 
				
			||||||
"  vec4 col = texture2D(texture0, v_texcoord);"
 | 
					"\n"
 | 
				
			||||||
"  gl_FragColor = vec4(col.rgb, col.a);"
 | 
					"void main() {\n"
 | 
				
			||||||
"}";
 | 
					"	vec4 col = texture2D(texture0, v_texcoord);\n"
 | 
				
			||||||
 | 
					"	gl_FragColor = vec4(col.rgb, col.a * alpha);\n"
 | 
				
			||||||
 | 
					"}\n";
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,39 +5,47 @@
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <wayland-server-protocol.h>
 | 
					#include <wayland-server-protocol.h>
 | 
				
			||||||
#include <wayland-util.h>
 | 
					#include <wayland-util.h>
 | 
				
			||||||
#include <wlr/render.h>
 | 
					#include <wlr/render/wlr_texture.h>
 | 
				
			||||||
#include <wlr/render/egl.h>
 | 
					#include <wlr/render/egl.h>
 | 
				
			||||||
#include <wlr/render/interface.h>
 | 
					#include <wlr/render/interface.h>
 | 
				
			||||||
#include <wlr/render/matrix.h>
 | 
					#include <wlr/types/wlr_matrix.h>
 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					#include <wlr/util/log.h>
 | 
				
			||||||
#include "render/gles2.h"
 | 
					#include "render/gles2.h"
 | 
				
			||||||
#include "util/signal.h"
 | 
					#include "util/signal.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct pixel_format external_pixel_format = {
 | 
					static struct gles2_pixel_format external_pixel_format = {
 | 
				
			||||||
	.wl_format = 0,
 | 
						.wl_format = 0,
 | 
				
			||||||
	.depth = 0,
 | 
						.depth = 0,
 | 
				
			||||||
	.bpp = 0,
 | 
						.bpp = 0,
 | 
				
			||||||
	.gl_format = 0,
 | 
						.gl_format = 0,
 | 
				
			||||||
	.gl_type = 0,
 | 
						.gl_type = 0,
 | 
				
			||||||
	.shader = &shaders.external
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void gles2_texture_ensure_texture(struct wlr_gles2_texture *texture) {
 | 
					static void gles2_texture_ensure(struct wlr_gles2_texture *texture,
 | 
				
			||||||
 | 
							GLenum target) {
 | 
				
			||||||
	if (texture->tex_id) {
 | 
						if (texture->tex_id) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	GL_CALL(glGenTextures(1, &texture->tex_id));
 | 
						texture->target = target;
 | 
				
			||||||
	GL_CALL(glBindTexture(GL_TEXTURE_2D, texture->tex_id));
 | 
						glGenTextures(1, &texture->tex_id);
 | 
				
			||||||
	GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
 | 
						glBindTexture(target, texture->tex_id);
 | 
				
			||||||
	GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
 | 
						glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 | 
				
			||||||
 | 
						glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool gles2_texture_upload_pixels(struct wlr_texture *_texture,
 | 
					static const struct wlr_texture_impl texture_impl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_gles2_texture *gles2_get_texture(struct wlr_texture *wlr_texture) {
 | 
				
			||||||
 | 
						assert(wlr_texture->impl == &texture_impl);
 | 
				
			||||||
 | 
						return (struct wlr_gles2_texture *)wlr_texture;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool gles2_texture_upload_pixels(struct wlr_texture *wlr_texture,
 | 
				
			||||||
		enum wl_shm_format format, int stride, int width, int height,
 | 
							enum wl_shm_format format, int stride, int width, int height,
 | 
				
			||||||
		const unsigned char *pixels) {
 | 
							const unsigned char *pixels) {
 | 
				
			||||||
	struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture;
 | 
						struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
 | 
				
			||||||
	assert(texture);
 | 
					
 | 
				
			||||||
	const struct pixel_format *fmt = gl_format_for_wl_format(format);
 | 
						const struct gles2_pixel_format *fmt = gles2_format_from_wl(format);
 | 
				
			||||||
	if (!fmt || !fmt->gl_format) {
 | 
						if (!fmt || !fmt->gl_format) {
 | 
				
			||||||
		wlr_log(L_ERROR, "No supported pixel format for this texture");
 | 
							wlr_log(L_ERROR, "No supported pixel format for this texture");
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
| 
						 | 
					@ -47,44 +55,50 @@ static bool gles2_texture_upload_pixels(struct wlr_texture *_texture,
 | 
				
			||||||
	texture->wlr_texture.format = format;
 | 
						texture->wlr_texture.format = format;
 | 
				
			||||||
	texture->pixel_format = fmt;
 | 
						texture->pixel_format = fmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	gles2_texture_ensure_texture(texture);
 | 
						GLES2_DEBUG_PUSH;
 | 
				
			||||||
	GL_CALL(glBindTexture(GL_TEXTURE_2D, texture->tex_id));
 | 
						gles2_texture_ensure(texture, GL_TEXTURE_2D);
 | 
				
			||||||
	GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride));
 | 
						glBindTexture(GL_TEXTURE_2D, texture->tex_id);
 | 
				
			||||||
	GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, fmt->gl_format, width, height, 0,
 | 
						glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride);
 | 
				
			||||||
			fmt->gl_format, fmt->gl_type, pixels));
 | 
						glTexImage2D(GL_TEXTURE_2D, 0, fmt->gl_format, width, height, 0,
 | 
				
			||||||
 | 
							fmt->gl_format, fmt->gl_type, pixels);
 | 
				
			||||||
 | 
						GLES2_DEBUG_POP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	texture->wlr_texture.valid = true;
 | 
						texture->wlr_texture.valid = true;
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool gles2_texture_update_pixels(struct wlr_texture *_texture,
 | 
					static bool gles2_texture_update_pixels(struct wlr_texture *wlr_texture,
 | 
				
			||||||
		enum wl_shm_format format, int stride, int x, int y,
 | 
							enum wl_shm_format format, int stride, int x, int y,
 | 
				
			||||||
		int width, int height, const unsigned char *pixels) {
 | 
							int width, int height, const unsigned char *pixels) {
 | 
				
			||||||
	struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture;
 | 
						struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
 | 
				
			||||||
	assert(texture);
 | 
					
 | 
				
			||||||
	// TODO: Test if the unpack subimage extension is supported and adjust the
 | 
						// TODO: Test if the unpack subimage extension is supported and adjust the
 | 
				
			||||||
	// upload strategy if not
 | 
						// upload strategy if not
 | 
				
			||||||
	if (!texture->wlr_texture.valid
 | 
						if (!texture->wlr_texture.valid
 | 
				
			||||||
			|| texture->wlr_texture.format != format
 | 
								|| texture->wlr_texture.format != format
 | 
				
			||||||
		/*	|| unpack not supported */) {
 | 
							/*	|| unpack not supported */) {
 | 
				
			||||||
		return gles2_texture_upload_pixels(&texture->wlr_texture,
 | 
							return gles2_texture_upload_pixels(&texture->wlr_texture, format,
 | 
				
			||||||
				format, stride, width, height, pixels);
 | 
								stride, width, height, pixels);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	const struct pixel_format *fmt = texture->pixel_format;
 | 
						const struct gles2_pixel_format *fmt = texture->pixel_format;
 | 
				
			||||||
	GL_CALL(glBindTexture(GL_TEXTURE_2D, texture->tex_id));
 | 
						GLES2_DEBUG_PUSH;
 | 
				
			||||||
	GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride));
 | 
						glBindTexture(GL_TEXTURE_2D, texture->tex_id);
 | 
				
			||||||
	GL_CALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, x));
 | 
						glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride);
 | 
				
			||||||
	GL_CALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, y));
 | 
						glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, x);
 | 
				
			||||||
	GL_CALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height,
 | 
						glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, y);
 | 
				
			||||||
			fmt->gl_format, fmt->gl_type, pixels));
 | 
						glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, fmt->gl_format,
 | 
				
			||||||
	GL_CALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0));
 | 
							fmt->gl_type, pixels);
 | 
				
			||||||
	GL_CALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0));
 | 
						glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0);
 | 
				
			||||||
 | 
						glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0);
 | 
				
			||||||
 | 
						GLES2_DEBUG_POP;
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool gles2_texture_upload_shm(struct wlr_texture *_texture,
 | 
					static bool gles2_texture_upload_shm(struct wlr_texture *wlr_texture,
 | 
				
			||||||
		uint32_t format, struct wl_shm_buffer *buffer) {
 | 
							uint32_t format, struct wl_shm_buffer *buffer) {
 | 
				
			||||||
	struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture;
 | 
						struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
 | 
				
			||||||
	const struct pixel_format *fmt = gl_format_for_wl_format(format);
 | 
					
 | 
				
			||||||
 | 
						const struct gles2_pixel_format *fmt = gles2_format_from_wl(format);
 | 
				
			||||||
	if (!fmt || !fmt->gl_format) {
 | 
						if (!fmt || !fmt->gl_format) {
 | 
				
			||||||
		wlr_log(L_ERROR, "Unsupported pixel format %"PRIu32" for this texture",
 | 
							wlr_log(L_ERROR, "Unsupported pixel format %"PRIu32" for this texture",
 | 
				
			||||||
				format);
 | 
									format);
 | 
				
			||||||
| 
						 | 
					@ -100,23 +114,26 @@ static bool gles2_texture_upload_shm(struct wlr_texture *_texture,
 | 
				
			||||||
	texture->wlr_texture.format = format;
 | 
						texture->wlr_texture.format = format;
 | 
				
			||||||
	texture->pixel_format = fmt;
 | 
						texture->pixel_format = fmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	gles2_texture_ensure_texture(texture);
 | 
						GLES2_DEBUG_PUSH;
 | 
				
			||||||
	GL_CALL(glBindTexture(GL_TEXTURE_2D, texture->tex_id));
 | 
						gles2_texture_ensure(texture, GL_TEXTURE_2D);
 | 
				
			||||||
	GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, pitch));
 | 
						glBindTexture(GL_TEXTURE_2D, texture->tex_id);
 | 
				
			||||||
	GL_CALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0));
 | 
						glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, pitch);
 | 
				
			||||||
	GL_CALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0));
 | 
						glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0);
 | 
				
			||||||
	GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, fmt->gl_format, width, height, 0,
 | 
						glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0);
 | 
				
			||||||
				fmt->gl_format, fmt->gl_type, pixels));
 | 
						glTexImage2D(GL_TEXTURE_2D, 0, fmt->gl_format, width, height, 0,
 | 
				
			||||||
 | 
							fmt->gl_format, fmt->gl_type, pixels);
 | 
				
			||||||
 | 
						GLES2_DEBUG_POP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	texture->wlr_texture.valid = true;
 | 
						texture->wlr_texture.valid = true;
 | 
				
			||||||
	wl_shm_buffer_end_access(buffer);
 | 
						wl_shm_buffer_end_access(buffer);
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool gles2_texture_update_shm(struct wlr_texture *_texture,
 | 
					static bool gles2_texture_update_shm(struct wlr_texture *wlr_texture,
 | 
				
			||||||
		uint32_t format, int x, int y, int width, int height,
 | 
							uint32_t format, int x, int y, int width, int height,
 | 
				
			||||||
		struct wl_shm_buffer *buffer) {
 | 
							struct wl_shm_buffer *buffer) {
 | 
				
			||||||
	struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture;
 | 
						struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// TODO: Test if the unpack subimage extension is supported and adjust the
 | 
						// TODO: Test if the unpack subimage extension is supported and adjust the
 | 
				
			||||||
	// upload strategy if not
 | 
						// upload strategy if not
 | 
				
			||||||
	assert(texture);
 | 
						assert(texture);
 | 
				
			||||||
| 
						 | 
					@ -125,28 +142,30 @@ static bool gles2_texture_update_shm(struct wlr_texture *_texture,
 | 
				
			||||||
		/*	|| unpack not supported */) {
 | 
							/*	|| unpack not supported */) {
 | 
				
			||||||
		return gles2_texture_upload_shm(&texture->wlr_texture, format, buffer);
 | 
							return gles2_texture_upload_shm(&texture->wlr_texture, format, buffer);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	const struct pixel_format *fmt = texture->pixel_format;
 | 
						const struct gles2_pixel_format *fmt = texture->pixel_format;
 | 
				
			||||||
	wl_shm_buffer_begin_access(buffer);
 | 
						wl_shm_buffer_begin_access(buffer);
 | 
				
			||||||
	uint8_t *pixels = wl_shm_buffer_get_data(buffer);
 | 
						uint8_t *pixels = wl_shm_buffer_get_data(buffer);
 | 
				
			||||||
	int pitch = wl_shm_buffer_get_stride(buffer) / (fmt->bpp / 8);
 | 
						int pitch = wl_shm_buffer_get_stride(buffer) / (fmt->bpp / 8);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	GL_CALL(glBindTexture(GL_TEXTURE_2D, texture->tex_id));
 | 
						GLES2_DEBUG_PUSH;
 | 
				
			||||||
	GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, pitch));
 | 
						glBindTexture(GL_TEXTURE_2D, texture->tex_id);
 | 
				
			||||||
	GL_CALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, x));
 | 
						glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, pitch);
 | 
				
			||||||
	GL_CALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, y));
 | 
						glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, x);
 | 
				
			||||||
	GL_CALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height,
 | 
						glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, y);
 | 
				
			||||||
			fmt->gl_format, fmt->gl_type, pixels));
 | 
						glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height,
 | 
				
			||||||
	GL_CALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0));
 | 
								fmt->gl_format, fmt->gl_type, pixels);
 | 
				
			||||||
	GL_CALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0));
 | 
						glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0);
 | 
				
			||||||
 | 
						glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0);
 | 
				
			||||||
 | 
						GLES2_DEBUG_POP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl_shm_buffer_end_access(buffer);
 | 
						wl_shm_buffer_end_access(buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool gles2_texture_upload_drm(struct wlr_texture *_tex,
 | 
					static bool gles2_texture_upload_drm(struct wlr_texture *wlr_texture,
 | 
				
			||||||
		struct wl_resource *buf) {
 | 
							struct wl_resource *buf) {
 | 
				
			||||||
	struct wlr_gles2_texture *tex = (struct wlr_gles2_texture *)_tex;
 | 
						struct wlr_gles2_texture *tex = gles2_get_texture(wlr_texture);
 | 
				
			||||||
	if (!glEGLImageTargetTexture2DOES) {
 | 
						if (!glEGLImageTargetTexture2DOES) {
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -163,15 +182,18 @@ static bool gles2_texture_upload_drm(struct wlr_texture *_tex,
 | 
				
			||||||
		(EGLint*)&tex->wlr_texture.height);
 | 
							(EGLint*)&tex->wlr_texture.height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	EGLint inverted_y;
 | 
						EGLint inverted_y;
 | 
				
			||||||
	wlr_egl_query_buffer(tex->egl, buf, EGL_WAYLAND_Y_INVERTED_WL, &inverted_y);
 | 
						if (wlr_egl_query_buffer(tex->egl, buf, EGL_WAYLAND_Y_INVERTED_WL,
 | 
				
			||||||
 | 
								&inverted_y)) {
 | 
				
			||||||
 | 
							tex->wlr_texture.inverted_y = !!inverted_y;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	GLenum target;
 | 
						GLenum target;
 | 
				
			||||||
	const struct pixel_format *pf;
 | 
						const struct gles2_pixel_format *pf;
 | 
				
			||||||
	switch (format) {
 | 
						switch (format) {
 | 
				
			||||||
	case EGL_TEXTURE_RGB:
 | 
						case EGL_TEXTURE_RGB:
 | 
				
			||||||
	case EGL_TEXTURE_RGBA:
 | 
						case EGL_TEXTURE_RGBA:
 | 
				
			||||||
		target = GL_TEXTURE_2D;
 | 
							target = GL_TEXTURE_2D;
 | 
				
			||||||
		pf = gl_format_for_wl_format(WL_SHM_FORMAT_ARGB8888);
 | 
							pf = gles2_format_from_wl(WL_SHM_FORMAT_ARGB8888);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case EGL_TEXTURE_EXTERNAL_WL:
 | 
						case EGL_TEXTURE_EXTERNAL_WL:
 | 
				
			||||||
		target = GL_TEXTURE_EXTERNAL_OES;
 | 
							target = GL_TEXTURE_EXTERNAL_OES;
 | 
				
			||||||
| 
						 | 
					@ -182,8 +204,10 @@ static bool gles2_texture_upload_drm(struct wlr_texture *_tex,
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	gles2_texture_ensure_texture(tex);
 | 
						GLES2_DEBUG_PUSH;
 | 
				
			||||||
	GL_CALL(glBindTexture(GL_TEXTURE_2D, tex->tex_id));
 | 
						gles2_texture_ensure(tex, target);
 | 
				
			||||||
 | 
						glBindTexture(GL_TEXTURE_2D, tex->tex_id);
 | 
				
			||||||
 | 
						GLES2_DEBUG_POP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	EGLint attribs[] = { EGL_WAYLAND_PLANE_WL, 0, EGL_NONE };
 | 
						EGLint attribs[] = { EGL_WAYLAND_PLANE_WL, 0, EGL_NONE };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -194,22 +218,24 @@ static bool gles2_texture_upload_drm(struct wlr_texture *_tex,
 | 
				
			||||||
	tex->image = wlr_egl_create_image(tex->egl, EGL_WAYLAND_BUFFER_WL,
 | 
						tex->image = wlr_egl_create_image(tex->egl, EGL_WAYLAND_BUFFER_WL,
 | 
				
			||||||
		(EGLClientBuffer*) buf, attribs);
 | 
							(EGLClientBuffer*) buf, attribs);
 | 
				
			||||||
	if (!tex->image) {
 | 
						if (!tex->image) {
 | 
				
			||||||
		wlr_log(L_ERROR, "failed to create egl image: %s", egl_error());
 | 
							wlr_log(L_ERROR, "failed to create EGL image");
 | 
				
			||||||
 		return false;
 | 
					 		return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	GL_CALL(glActiveTexture(GL_TEXTURE0));
 | 
						GLES2_DEBUG_PUSH;
 | 
				
			||||||
	GL_CALL(glBindTexture(target, tex->tex_id));
 | 
						glActiveTexture(GL_TEXTURE0);
 | 
				
			||||||
	GL_CALL(glEGLImageTargetTexture2DOES(target, tex->image));
 | 
						glBindTexture(target, tex->tex_id);
 | 
				
			||||||
 | 
						glEGLImageTargetTexture2DOES(target, tex->image);
 | 
				
			||||||
 | 
						GLES2_DEBUG_POP;
 | 
				
			||||||
	tex->wlr_texture.valid = true;
 | 
						tex->wlr_texture.valid = true;
 | 
				
			||||||
	tex->pixel_format = pf;
 | 
						tex->pixel_format = pf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool gles2_texture_upload_eglimage(struct wlr_texture *wlr_tex,
 | 
					static bool gles2_texture_upload_eglimage(struct wlr_texture *wlr_texture,
 | 
				
			||||||
		EGLImageKHR image, uint32_t width, uint32_t height) {
 | 
							EGLImageKHR image, uint32_t width, uint32_t height) {
 | 
				
			||||||
	struct wlr_gles2_texture *tex = (struct wlr_gles2_texture *)wlr_tex;
 | 
						struct wlr_gles2_texture *tex = gles2_get_texture(wlr_texture);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tex->image = image;
 | 
						tex->image = image;
 | 
				
			||||||
	tex->pixel_format = &external_pixel_format;
 | 
						tex->pixel_format = &external_pixel_format;
 | 
				
			||||||
| 
						 | 
					@ -217,30 +243,68 @@ static bool gles2_texture_upload_eglimage(struct wlr_texture *wlr_tex,
 | 
				
			||||||
	tex->wlr_texture.width = width;
 | 
						tex->wlr_texture.width = width;
 | 
				
			||||||
	tex->wlr_texture.height = height;
 | 
						tex->wlr_texture.height = height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	gles2_texture_ensure_texture(tex);
 | 
						GLES2_DEBUG_PUSH;
 | 
				
			||||||
 | 
						gles2_texture_ensure(tex, GL_TEXTURE_2D);
 | 
				
			||||||
	GL_CALL(glActiveTexture(GL_TEXTURE0));
 | 
						glActiveTexture(GL_TEXTURE0);
 | 
				
			||||||
	GL_CALL(glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex->tex_id));
 | 
						glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex->tex_id);
 | 
				
			||||||
	GL_CALL(glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, tex->image));
 | 
						glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, tex->image);
 | 
				
			||||||
 | 
						GLES2_DEBUG_POP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void gles2_texture_get_matrix(struct wlr_texture *_texture,
 | 
					static bool gles2_texture_upload_dmabuf(struct wlr_texture *wlr_texture,
 | 
				
			||||||
		float (*matrix)[16], const float (*projection)[16], int x, int y) {
 | 
							struct wl_resource *dmabuf_resource) {
 | 
				
			||||||
	struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture;
 | 
						struct wlr_gles2_texture *tex = gles2_get_texture(wlr_texture);
 | 
				
			||||||
	float world[16];
 | 
						struct wlr_dmabuf_buffer *dmabuf =
 | 
				
			||||||
	wlr_matrix_identity(matrix);
 | 
							wlr_dmabuf_buffer_from_buffer_resource(dmabuf_resource);
 | 
				
			||||||
	wlr_matrix_translate(&world, x, y, 0);
 | 
					
 | 
				
			||||||
	wlr_matrix_mul(matrix, &world, matrix);
 | 
						if (!tex->egl->egl_exts.dmabuf_import) {
 | 
				
			||||||
	wlr_matrix_scale(&world,
 | 
							wlr_log(L_ERROR, "Want dmabuf but extension not present");
 | 
				
			||||||
			texture->wlr_texture.width, texture->wlr_texture.height, 1);
 | 
							return false;
 | 
				
			||||||
	wlr_matrix_mul(matrix, &world, matrix);
 | 
						}
 | 
				
			||||||
	wlr_matrix_mul(projection, matrix, matrix);
 | 
					
 | 
				
			||||||
 | 
						tex->wlr_texture.width = dmabuf->attributes.width;
 | 
				
			||||||
 | 
						tex->wlr_texture.height = dmabuf->attributes.height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (tex->image) {
 | 
				
			||||||
 | 
							wlr_egl_destroy_image(tex->egl, tex->image);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (wlr_dmabuf_buffer_has_inverted_y(dmabuf)) {
 | 
				
			||||||
 | 
							wlr_texture->inverted_y = true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						GLenum target = GL_TEXTURE_2D;
 | 
				
			||||||
 | 
						const struct gles2_pixel_format *pf =
 | 
				
			||||||
 | 
							gles2_format_from_wl(WL_SHM_FORMAT_ARGB8888);
 | 
				
			||||||
 | 
						GLES2_DEBUG_PUSH;
 | 
				
			||||||
 | 
						gles2_texture_ensure(tex, target);
 | 
				
			||||||
 | 
						glBindTexture(target, tex->tex_id);
 | 
				
			||||||
 | 
						tex->image = wlr_egl_create_image_from_dmabuf(tex->egl, &dmabuf->attributes);
 | 
				
			||||||
 | 
						glActiveTexture(GL_TEXTURE0);
 | 
				
			||||||
 | 
						glEGLImageTargetTexture2DOES(target, tex->image);
 | 
				
			||||||
 | 
						GLES2_DEBUG_POP;
 | 
				
			||||||
 | 
						tex->pixel_format = pf;
 | 
				
			||||||
 | 
						tex->wlr_texture.valid = true;
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void gles2_texture_get_buffer_size(struct wlr_texture *texture, struct
 | 
					static bool gles2_texture_get_dmabuf_size(struct wlr_texture *texture, struct
 | 
				
			||||||
		wl_resource *resource, int *width, int *height) {
 | 
							wl_resource *resource, int *width, int *height) {
 | 
				
			||||||
 | 
						if (!wlr_dmabuf_resource_is_buffer(resource)) {
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_dmabuf_buffer *dmabuf =
 | 
				
			||||||
 | 
							wlr_dmabuf_buffer_from_buffer_resource(resource);
 | 
				
			||||||
 | 
						*width = dmabuf->attributes.width;
 | 
				
			||||||
 | 
						*height = dmabuf->attributes.height;
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void gles2_texture_get_buffer_size(struct wlr_texture *texture,
 | 
				
			||||||
 | 
							struct wl_resource *resource, int *width, int *height) {
 | 
				
			||||||
	struct wl_shm_buffer *buffer = wl_shm_buffer_get(resource);
 | 
						struct wl_shm_buffer *buffer = wl_shm_buffer_get(resource);
 | 
				
			||||||
	if (!buffer) {
 | 
						if (!buffer) {
 | 
				
			||||||
		struct wlr_gles2_texture *tex = (struct wlr_gles2_texture *)texture;
 | 
							struct wlr_gles2_texture *tex = (struct wlr_gles2_texture *)texture;
 | 
				
			||||||
| 
						 | 
					@ -249,12 +313,13 @@ static void gles2_texture_get_buffer_size(struct wlr_texture *texture, struct
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (!wlr_egl_query_buffer(tex->egl, resource, EGL_WIDTH,
 | 
							if (!wlr_egl_query_buffer(tex->egl, resource, EGL_WIDTH,
 | 
				
			||||||
				(EGLint*)width)) {
 | 
									(EGLint*)width)) {
 | 
				
			||||||
			wlr_log(L_ERROR, "could not get size of the buffer "
 | 
								if (!gles2_texture_get_dmabuf_size(texture, resource, width,
 | 
				
			||||||
				"(no buffer found)");
 | 
										height)) {
 | 
				
			||||||
 | 
									wlr_log(L_ERROR, "could not get size of the buffer");
 | 
				
			||||||
				return;
 | 
									return;
 | 
				
			||||||
		};
 | 
								}
 | 
				
			||||||
		wlr_egl_query_buffer(tex->egl, resource, EGL_HEIGHT,
 | 
							}
 | 
				
			||||||
			(EGLint*)height);
 | 
							wlr_egl_query_buffer(tex->egl, resource, EGL_HEIGHT, (EGLint*)height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -263,19 +328,15 @@ static void gles2_texture_get_buffer_size(struct wlr_texture *texture, struct
 | 
				
			||||||
	*height = wl_shm_buffer_get_height(buffer);
 | 
						*height = wl_shm_buffer_get_height(buffer);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void gles2_texture_bind(struct wlr_texture *_texture) {
 | 
					static void gles2_texture_destroy(struct wlr_texture *wlr_texture) {
 | 
				
			||||||
	struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture;
 | 
						struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
 | 
				
			||||||
	GL_CALL(glBindTexture(GL_TEXTURE_2D, texture->tex_id));
 | 
					 | 
				
			||||||
	GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
 | 
					 | 
				
			||||||
	GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
 | 
					 | 
				
			||||||
	GL_CALL(glUseProgram(*texture->pixel_format->shader));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void gles2_texture_destroy(struct wlr_texture *_texture) {
 | 
						wlr_signal_emit_safe(&texture->wlr_texture.destroy_signal,
 | 
				
			||||||
	struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture;
 | 
							&texture->wlr_texture);
 | 
				
			||||||
	wlr_signal_emit_safe(&texture->wlr_texture.destroy_signal, &texture->wlr_texture);
 | 
					 | 
				
			||||||
	if (texture->tex_id) {
 | 
						if (texture->tex_id) {
 | 
				
			||||||
		GL_CALL(glDeleteTextures(1, &texture->tex_id));
 | 
							GLES2_DEBUG_PUSH;
 | 
				
			||||||
 | 
							glDeleteTextures(1, &texture->tex_id);
 | 
				
			||||||
 | 
							GLES2_DEBUG_POP;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (texture->image) {
 | 
						if (texture->image) {
 | 
				
			||||||
| 
						 | 
					@ -285,16 +346,15 @@ static void gles2_texture_destroy(struct wlr_texture *_texture) {
 | 
				
			||||||
	free(texture);
 | 
						free(texture);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct wlr_texture_impl wlr_texture_impl = {
 | 
					static const struct wlr_texture_impl texture_impl = {
 | 
				
			||||||
	.upload_pixels = gles2_texture_upload_pixels,
 | 
						.upload_pixels = gles2_texture_upload_pixels,
 | 
				
			||||||
	.update_pixels = gles2_texture_update_pixels,
 | 
						.update_pixels = gles2_texture_update_pixels,
 | 
				
			||||||
	.upload_shm = gles2_texture_upload_shm,
 | 
						.upload_shm = gles2_texture_upload_shm,
 | 
				
			||||||
	.update_shm = gles2_texture_update_shm,
 | 
						.update_shm = gles2_texture_update_shm,
 | 
				
			||||||
	.upload_drm = gles2_texture_upload_drm,
 | 
						.upload_drm = gles2_texture_upload_drm,
 | 
				
			||||||
 | 
						.upload_dmabuf = gles2_texture_upload_dmabuf,
 | 
				
			||||||
	.upload_eglimage = gles2_texture_upload_eglimage,
 | 
						.upload_eglimage = gles2_texture_upload_eglimage,
 | 
				
			||||||
	.get_matrix = gles2_texture_get_matrix,
 | 
					 | 
				
			||||||
	.get_buffer_size = gles2_texture_get_buffer_size,
 | 
						.get_buffer_size = gles2_texture_get_buffer_size,
 | 
				
			||||||
	.bind = gles2_texture_bind,
 | 
					 | 
				
			||||||
	.destroy = gles2_texture_destroy,
 | 
						.destroy = gles2_texture_destroy,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -303,7 +363,7 @@ struct wlr_texture *gles2_texture_create(struct wlr_egl *egl) {
 | 
				
			||||||
	if (!(texture = calloc(1, sizeof(struct wlr_gles2_texture)))) {
 | 
						if (!(texture = calloc(1, sizeof(struct wlr_gles2_texture)))) {
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	wlr_texture_init(&texture->wlr_texture, &wlr_texture_impl);
 | 
						wlr_texture_init(&texture->wlr_texture, &texture_impl);
 | 
				
			||||||
	texture->egl = egl;
 | 
						texture->egl = egl;
 | 
				
			||||||
	return &texture->wlr_texture;
 | 
						return &texture->wlr_texture;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										210
									
								
								render/matrix.c
									
										
									
									
									
								
							
							
						
						
									
										210
									
								
								render/matrix.c
									
										
									
									
									
								
							| 
						 | 
					@ -1,210 +0,0 @@
 | 
				
			||||||
#include <math.h>
 | 
					 | 
				
			||||||
#include <string.h>
 | 
					 | 
				
			||||||
#include <wayland-server-protocol.h>
 | 
					 | 
				
			||||||
#include <wlr/render/matrix.h>
 | 
					 | 
				
			||||||
#include <wlr/types/wlr_box.h>
 | 
					 | 
				
			||||||
#include <wlr/types/wlr_output.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Obtains the index for the given row/column */
 | 
					 | 
				
			||||||
static inline int mind(int row, int col) {
 | 
					 | 
				
			||||||
	return (row - 1) * 4 + col - 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void wlr_matrix_identity(float (*output)[16]) {
 | 
					 | 
				
			||||||
	static const float identity[16] = {
 | 
					 | 
				
			||||||
		1.0f, 0.0f, 0.0f, 0.0f,
 | 
					 | 
				
			||||||
		0.0f, 1.0f, 0.0f, 0.0f,
 | 
					 | 
				
			||||||
		0.0f, 0.0f, 1.0f, 0.0f,
 | 
					 | 
				
			||||||
		0.0f, 0.0f, 0.0f, 1.0f
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
	memcpy(*output, identity, sizeof(identity));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void wlr_matrix_translate(float (*output)[16], float x, float y, float z) {
 | 
					 | 
				
			||||||
	wlr_matrix_identity(output);
 | 
					 | 
				
			||||||
	(*output)[mind(1, 4)] = x;
 | 
					 | 
				
			||||||
	(*output)[mind(2, 4)] = y;
 | 
					 | 
				
			||||||
	(*output)[mind(3, 4)] = z;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void wlr_matrix_scale(float (*output)[16], float x, float y, float z) {
 | 
					 | 
				
			||||||
	wlr_matrix_identity(output);
 | 
					 | 
				
			||||||
	(*output)[mind(1, 1)] = x;
 | 
					 | 
				
			||||||
	(*output)[mind(2, 2)] = y;
 | 
					 | 
				
			||||||
	(*output)[mind(3, 3)] = z;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void wlr_matrix_rotate(float (*output)[16], float radians) {
 | 
					 | 
				
			||||||
	wlr_matrix_identity(output);
 | 
					 | 
				
			||||||
	float _cos = cosf(radians);
 | 
					 | 
				
			||||||
	float _sin = sinf(radians);
 | 
					 | 
				
			||||||
	(*output)[mind(1, 1)] = _cos;
 | 
					 | 
				
			||||||
	(*output)[mind(1, 2)] = _sin;
 | 
					 | 
				
			||||||
	(*output)[mind(2, 1)] = -_sin;
 | 
					 | 
				
			||||||
	(*output)[mind(2, 2)] = _cos;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void wlr_matrix_mul(const float (*x)[16], const float (*y)[16], float (*product)[16]) {
 | 
					 | 
				
			||||||
	float _product[16] = {
 | 
					 | 
				
			||||||
		(*x)[mind(1, 1)] * (*y)[mind(1, 1)] + (*x)[mind(1, 2)] * (*y)[mind(2, 1)] +
 | 
					 | 
				
			||||||
			(*x)[mind(1, 3)] * (*y)[mind(3, 1)] + (*x)[mind(1, 4)] * (*y)[mind(4, 1)],
 | 
					 | 
				
			||||||
		(*x)[mind(1, 1)] * (*y)[mind(1, 2)] + (*x)[mind(1, 2)] * (*y)[mind(2, 2)] +
 | 
					 | 
				
			||||||
			(*x)[mind(1, 3)] * (*y)[mind(3, 2)] + (*x)[mind(1, 4)] * (*y)[mind(4, 2)],
 | 
					 | 
				
			||||||
		(*x)[mind(1, 1)] * (*y)[mind(1, 3)] + (*x)[mind(1, 2)] * (*y)[mind(2, 3)] +
 | 
					 | 
				
			||||||
			(*x)[mind(1, 3)] * (*y)[mind(3, 3)] + (*x)[mind(1, 4)] * (*y)[mind(4, 3)],
 | 
					 | 
				
			||||||
		(*x)[mind(1, 1)] * (*y)[mind(1, 4)] + (*x)[mind(1, 2)] * (*y)[mind(2, 4)] +
 | 
					 | 
				
			||||||
			(*x)[mind(1, 4)] * (*y)[mind(3, 4)] + (*x)[mind(1, 4)] * (*y)[mind(4, 4)],
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		(*x)[mind(2, 1)] * (*y)[mind(1, 1)] + (*x)[mind(2, 2)] * (*y)[mind(2, 1)] +
 | 
					 | 
				
			||||||
			(*x)[mind(2, 3)] * (*y)[mind(3, 1)] + (*x)[mind(2, 4)] * (*y)[mind(4, 1)],
 | 
					 | 
				
			||||||
		(*x)[mind(2, 1)] * (*y)[mind(1, 2)] + (*x)[mind(2, 2)] * (*y)[mind(2, 2)] +
 | 
					 | 
				
			||||||
			(*x)[mind(2, 3)] * (*y)[mind(3, 2)] + (*x)[mind(2, 4)] * (*y)[mind(4, 2)],
 | 
					 | 
				
			||||||
		(*x)[mind(2, 1)] * (*y)[mind(1, 3)] + (*x)[mind(2, 2)] * (*y)[mind(2, 3)] +
 | 
					 | 
				
			||||||
			(*x)[mind(2, 3)] * (*y)[mind(3, 3)] + (*x)[mind(2, 4)] * (*y)[mind(4, 3)],
 | 
					 | 
				
			||||||
		(*x)[mind(2, 1)] * (*y)[mind(1, 4)] + (*x)[mind(2, 2)] * (*y)[mind(2, 4)] +
 | 
					 | 
				
			||||||
			(*x)[mind(2, 4)] * (*y)[mind(3, 4)] + (*x)[mind(2, 4)] * (*y)[mind(4, 4)],
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		(*x)[mind(3, 1)] * (*y)[mind(1, 1)] + (*x)[mind(3, 2)] * (*y)[mind(2, 1)] +
 | 
					 | 
				
			||||||
			(*x)[mind(3, 3)] * (*y)[mind(3, 1)] + (*x)[mind(3, 4)] * (*y)[mind(4, 1)],
 | 
					 | 
				
			||||||
		(*x)[mind(3, 1)] * (*y)[mind(1, 2)] + (*x)[mind(3, 2)] * (*y)[mind(2, 2)] +
 | 
					 | 
				
			||||||
			(*x)[mind(3, 3)] * (*y)[mind(3, 2)] + (*x)[mind(3, 4)] * (*y)[mind(4, 2)],
 | 
					 | 
				
			||||||
		(*x)[mind(3, 1)] * (*y)[mind(1, 3)] + (*x)[mind(3, 2)] * (*y)[mind(2, 3)] +
 | 
					 | 
				
			||||||
			(*x)[mind(3, 3)] * (*y)[mind(3, 3)] + (*x)[mind(3, 4)] * (*y)[mind(4, 3)],
 | 
					 | 
				
			||||||
		(*x)[mind(3, 1)] * (*y)[mind(1, 4)] + (*x)[mind(3, 2)] * (*y)[mind(2, 4)] +
 | 
					 | 
				
			||||||
			(*x)[mind(3, 4)] * (*y)[mind(3, 4)] + (*x)[mind(3, 4)] * (*y)[mind(4, 4)],
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		(*x)[mind(4, 1)] * (*y)[mind(1, 1)] + (*x)[mind(4, 2)] * (*y)[mind(2, 1)] +
 | 
					 | 
				
			||||||
			(*x)[mind(4, 3)] * (*y)[mind(3, 1)] + (*x)[mind(4, 4)] * (*y)[mind(4, 1)],
 | 
					 | 
				
			||||||
		(*x)[mind(4, 1)] * (*y)[mind(1, 2)] + (*x)[mind(4, 2)] * (*y)[mind(2, 2)] +
 | 
					 | 
				
			||||||
			(*x)[mind(4, 3)] * (*y)[mind(3, 2)] + (*x)[mind(4, 4)] * (*y)[mind(4, 2)],
 | 
					 | 
				
			||||||
		(*x)[mind(4, 1)] * (*y)[mind(1, 3)] + (*x)[mind(4, 2)] * (*y)[mind(2, 3)] +
 | 
					 | 
				
			||||||
			(*x)[mind(4, 3)] * (*y)[mind(3, 3)] + (*x)[mind(4, 4)] * (*y)[mind(4, 3)],
 | 
					 | 
				
			||||||
		(*x)[mind(4, 1)] * (*y)[mind(1, 4)] + (*x)[mind(4, 2)] * (*y)[mind(2, 4)] +
 | 
					 | 
				
			||||||
			(*x)[mind(4, 4)] * (*y)[mind(3, 4)] + (*x)[mind(4, 4)] * (*y)[mind(4, 4)],
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
	memcpy(*product, _product, sizeof(_product));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static const float transforms[][4] = {
 | 
					 | 
				
			||||||
	[WL_OUTPUT_TRANSFORM_NORMAL] = {
 | 
					 | 
				
			||||||
		1.0f, 0.0f,
 | 
					 | 
				
			||||||
		0.0f, 1.0f,
 | 
					 | 
				
			||||||
	},
 | 
					 | 
				
			||||||
	[WL_OUTPUT_TRANSFORM_90] = {
 | 
					 | 
				
			||||||
		0.0f, -1.0f,
 | 
					 | 
				
			||||||
		1.0f, 0.0f,
 | 
					 | 
				
			||||||
	},
 | 
					 | 
				
			||||||
	[WL_OUTPUT_TRANSFORM_180] = {
 | 
					 | 
				
			||||||
		-1.0f, 0.0f,
 | 
					 | 
				
			||||||
		0.0f, -1.0f,
 | 
					 | 
				
			||||||
	},
 | 
					 | 
				
			||||||
	[WL_OUTPUT_TRANSFORM_270] = {
 | 
					 | 
				
			||||||
		0.0f, 1.0f,
 | 
					 | 
				
			||||||
		-1.0f, 0.0f,
 | 
					 | 
				
			||||||
	},
 | 
					 | 
				
			||||||
	[WL_OUTPUT_TRANSFORM_FLIPPED] = {
 | 
					 | 
				
			||||||
		-1.0f, 0.0f,
 | 
					 | 
				
			||||||
		0.0f, 1.0f,
 | 
					 | 
				
			||||||
	},
 | 
					 | 
				
			||||||
	[WL_OUTPUT_TRANSFORM_FLIPPED_90] = {
 | 
					 | 
				
			||||||
		0.0f, -1.0f,
 | 
					 | 
				
			||||||
		-1.0f, 0.0f,
 | 
					 | 
				
			||||||
	},
 | 
					 | 
				
			||||||
	[WL_OUTPUT_TRANSFORM_FLIPPED_180] = {
 | 
					 | 
				
			||||||
		1.0f, 0.0f,
 | 
					 | 
				
			||||||
		0.0f, -1.0f,
 | 
					 | 
				
			||||||
	},
 | 
					 | 
				
			||||||
	[WL_OUTPUT_TRANSFORM_FLIPPED_270] = {
 | 
					 | 
				
			||||||
		0.0f, 1.0f,
 | 
					 | 
				
			||||||
		1.0f, 0.0f,
 | 
					 | 
				
			||||||
	},
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void wlr_matrix_transform(float mat[static 16],
 | 
					 | 
				
			||||||
		enum wl_output_transform transform) {
 | 
					 | 
				
			||||||
	memset(mat, 0, sizeof(*mat) * 16);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	const float *t = transforms[transform];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Rotation + reflection
 | 
					 | 
				
			||||||
	mat[0] = t[0];
 | 
					 | 
				
			||||||
	mat[1] = t[1];
 | 
					 | 
				
			||||||
	mat[4] = t[2];
 | 
					 | 
				
			||||||
	mat[5] = t[3];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Identity
 | 
					 | 
				
			||||||
	mat[10] = 1.0f;
 | 
					 | 
				
			||||||
	mat[15] = 1.0f;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Equivilent to glOrtho(0, width, 0, height, 1, -1) with the transform applied
 | 
					 | 
				
			||||||
void wlr_matrix_texture(float mat[static 16], int32_t width, int32_t height,
 | 
					 | 
				
			||||||
		enum wl_output_transform transform) {
 | 
					 | 
				
			||||||
	memset(mat, 0, sizeof(*mat) * 16);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	const float *t = transforms[transform];
 | 
					 | 
				
			||||||
	float x = 2.0f / width;
 | 
					 | 
				
			||||||
	float y = 2.0f / height;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Rotation + reflection
 | 
					 | 
				
			||||||
	mat[0] = x * t[0];
 | 
					 | 
				
			||||||
	mat[1] = x * t[1];
 | 
					 | 
				
			||||||
	mat[4] = y * -t[2];
 | 
					 | 
				
			||||||
	mat[5] = y * -t[3];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Translation
 | 
					 | 
				
			||||||
	mat[3] = -copysign(1.0f, mat[0] + mat[1]);
 | 
					 | 
				
			||||||
	mat[7] = -copysign(1.0f, mat[4] + mat[5]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Identity
 | 
					 | 
				
			||||||
	mat[10] = 1.0f;
 | 
					 | 
				
			||||||
	mat[15] = 1.0f;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void wlr_matrix_project_box(float (*mat)[16], struct wlr_box *box,
 | 
					 | 
				
			||||||
		enum wl_output_transform transform, float rotation,
 | 
					 | 
				
			||||||
		float (*projection)[16]) {
 | 
					 | 
				
			||||||
	int x = box->x;
 | 
					 | 
				
			||||||
	int y = box->y;
 | 
					 | 
				
			||||||
	int width = box->width;
 | 
					 | 
				
			||||||
	int height = box->height;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wlr_matrix_translate(mat, x, y, 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (rotation != 0) {
 | 
					 | 
				
			||||||
		float translate_center[16];
 | 
					 | 
				
			||||||
		wlr_matrix_translate(&translate_center, width/2, height/2, 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		float rotate[16];
 | 
					 | 
				
			||||||
		wlr_matrix_rotate(&rotate, rotation);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		float translate_origin[16];
 | 
					 | 
				
			||||||
		wlr_matrix_translate(&translate_origin, -width/2, -height/2, 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		wlr_matrix_mul(mat, &translate_center, mat);
 | 
					 | 
				
			||||||
		wlr_matrix_mul(mat, &rotate, mat);
 | 
					 | 
				
			||||||
		wlr_matrix_mul(mat, &translate_origin, mat);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	float scale[16];
 | 
					 | 
				
			||||||
	wlr_matrix_scale(&scale, width, height, 1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wlr_matrix_mul(mat, &scale, mat);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (transform != WL_OUTPUT_TRANSFORM_NORMAL) {
 | 
					 | 
				
			||||||
		float surface_translate_center[16];
 | 
					 | 
				
			||||||
		wlr_matrix_translate(&surface_translate_center, 0.5, 0.5, 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		float surface_transform[16];
 | 
					 | 
				
			||||||
		wlr_matrix_transform(surface_transform, transform);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		float surface_translate_origin[16];
 | 
					 | 
				
			||||||
		wlr_matrix_translate(&surface_translate_origin, -0.5, -0.5, 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		wlr_matrix_mul(mat, &surface_translate_center, mat);
 | 
					 | 
				
			||||||
		wlr_matrix_mul(mat, &surface_transform, mat);
 | 
					 | 
				
			||||||
		wlr_matrix_mul(mat, &surface_translate_origin, mat);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wlr_matrix_mul(projection, mat, mat);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -15,7 +15,6 @@ lib_wlr_render = static_library(
 | 
				
			||||||
		'gles2/shaders.c',
 | 
							'gles2/shaders.c',
 | 
				
			||||||
		'gles2/texture.c',
 | 
							'gles2/texture.c',
 | 
				
			||||||
		'gles2/util.c',
 | 
							'gles2/util.c',
 | 
				
			||||||
		'matrix.c',
 | 
					 | 
				
			||||||
		'wlr_renderer.c',
 | 
							'wlr_renderer.c',
 | 
				
			||||||
		'wlr_texture.c',
 | 
							'wlr_texture.c',
 | 
				
			||||||
	),
 | 
						),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,9 +1,11 @@
 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <wlr/render/interface.h>
 | 
					#include <wlr/render/interface.h>
 | 
				
			||||||
 | 
					#include <wlr/render/wlr_renderer.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_matrix.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void wlr_renderer_init(struct wlr_renderer *renderer,
 | 
					void wlr_renderer_init(struct wlr_renderer *renderer,
 | 
				
			||||||
		struct wlr_renderer_impl *impl) {
 | 
							const struct wlr_renderer_impl *impl) {
 | 
				
			||||||
	renderer->impl = impl;
 | 
						renderer->impl = impl;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,15 +17,15 @@ void wlr_renderer_destroy(struct wlr_renderer *r) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void wlr_renderer_begin(struct wlr_renderer *r, struct wlr_output *o) {
 | 
					void wlr_renderer_begin(struct wlr_renderer *r, int width, int height) {
 | 
				
			||||||
	r->impl->begin(r, o);
 | 
						r->impl->begin(r, width, height);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void wlr_renderer_end(struct wlr_renderer *r) {
 | 
					void wlr_renderer_end(struct wlr_renderer *r) {
 | 
				
			||||||
	r->impl->end(r);
 | 
						r->impl->end(r);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void wlr_renderer_clear(struct wlr_renderer *r, const float (*color)[4]) {
 | 
					void wlr_renderer_clear(struct wlr_renderer *r, const float color[static 4]) {
 | 
				
			||||||
	r->impl->clear(r, color);
 | 
						r->impl->clear(r, color);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,18 +37,30 @@ struct wlr_texture *wlr_render_texture_create(struct wlr_renderer *r) {
 | 
				
			||||||
	return r->impl->texture_create(r);
 | 
						return r->impl->texture_create(r);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool wlr_render_with_matrix(struct wlr_renderer *r,
 | 
					bool wlr_render_texture(struct wlr_renderer *r, struct wlr_texture *texture,
 | 
				
			||||||
		struct wlr_texture *texture, const float (*matrix)[16], float alpha) {
 | 
							const float projection[static 9], int x, int y, float alpha) {
 | 
				
			||||||
	return r->impl->render_with_matrix(r, texture, matrix, alpha);
 | 
						float mat[9];
 | 
				
			||||||
 | 
						wlr_matrix_identity(mat);
 | 
				
			||||||
 | 
						wlr_matrix_translate(mat, x, y);
 | 
				
			||||||
 | 
						wlr_matrix_scale(mat, texture->width, texture->height);
 | 
				
			||||||
 | 
						wlr_matrix_multiply(mat, projection, mat);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return wlr_render_texture_with_matrix(r, texture, mat, alpha);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool wlr_render_texture_with_matrix(struct wlr_renderer *r,
 | 
				
			||||||
 | 
							struct wlr_texture *texture, const float matrix[static 9],
 | 
				
			||||||
 | 
							float alpha) {
 | 
				
			||||||
 | 
						return r->impl->render_texture_with_matrix(r, texture, matrix, alpha);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void wlr_render_colored_quad(struct wlr_renderer *r,
 | 
					void wlr_render_colored_quad(struct wlr_renderer *r,
 | 
				
			||||||
		const float (*color)[4], const float (*matrix)[16]) {
 | 
							const float color[static 4], const float matrix[static 9]) {
 | 
				
			||||||
	r->impl->render_quad(r, color, matrix);
 | 
						r->impl->render_quad(r, color, matrix);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void wlr_render_colored_ellipse(struct wlr_renderer *r,
 | 
					void wlr_render_colored_ellipse(struct wlr_renderer *r,
 | 
				
			||||||
		const float (*color)[4], const float (*matrix)[16]) {
 | 
							const float color[static 4], const float matrix[static 9]) {
 | 
				
			||||||
	r->impl->render_ellipse(r, color, matrix);
 | 
						r->impl->render_ellipse(r, color, matrix);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,9 +1,10 @@
 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <wlr/render/interface.h>
 | 
					#include <wlr/render/interface.h>
 | 
				
			||||||
 | 
					#include <wlr/render/wlr_texture.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void wlr_texture_init(struct wlr_texture *texture,
 | 
					void wlr_texture_init(struct wlr_texture *texture,
 | 
				
			||||||
		struct wlr_texture_impl *impl) {
 | 
							const struct wlr_texture_impl *impl) {
 | 
				
			||||||
	texture->impl = impl;
 | 
						texture->impl = impl;
 | 
				
			||||||
	wl_signal_init(&texture->destroy_signal);
 | 
						wl_signal_init(&texture->destroy_signal);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -16,10 +17,6 @@ void wlr_texture_destroy(struct wlr_texture *texture) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void wlr_texture_bind(struct wlr_texture *texture) {
 | 
					 | 
				
			||||||
	texture->impl->bind(texture);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool wlr_texture_upload_pixels(struct wlr_texture *texture, uint32_t format,
 | 
					bool wlr_texture_upload_pixels(struct wlr_texture *texture, uint32_t format,
 | 
				
			||||||
		int stride, int width, int height, const unsigned char *pixels) {
 | 
							int stride, int width, int height, const unsigned char *pixels) {
 | 
				
			||||||
	return texture->impl->upload_pixels(texture, format, stride,
 | 
						return texture->impl->upload_pixels(texture, format, stride,
 | 
				
			||||||
| 
						 | 
					@ -53,9 +50,9 @@ bool wlr_texture_upload_eglimage(struct wlr_texture *texture,
 | 
				
			||||||
	return texture->impl->upload_eglimage(texture, image, width, height);
 | 
						return texture->impl->upload_eglimage(texture, image, width, height);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void wlr_texture_get_matrix(struct wlr_texture *texture,
 | 
					bool wlr_texture_upload_dmabuf(struct wlr_texture *texture,
 | 
				
			||||||
		float (*matrix)[16], const float (*projection)[16], int x, int y) {
 | 
							struct wl_resource *dmabuf_resource) {
 | 
				
			||||||
	texture->impl->get_matrix(texture, matrix, projection, x, y);
 | 
						return texture->impl->upload_dmabuf(texture, dmabuf_resource);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void wlr_texture_get_buffer_size(struct wlr_texture *texture, struct wl_resource
 | 
					void wlr_texture_get_buffer_size(struct wlr_texture *texture, struct wl_resource
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -200,7 +200,7 @@ static void roots_cursor_update_position(struct roots_cursor *cursor,
 | 
				
			||||||
				uy = cursor->offs_y - oy;
 | 
									uy = cursor->offs_y - oy;
 | 
				
			||||||
			int vx = cursor->cursor->x - ox,
 | 
								int vx = cursor->cursor->x - ox,
 | 
				
			||||||
				vy = cursor->cursor->y - oy;
 | 
									vy = cursor->cursor->y - oy;
 | 
				
			||||||
			float angle = atan2(vx*uy - vy*ux, vx*ux + vy*uy);
 | 
								float angle = atan2(ux*vy - uy*vx, vx*ux + vy*uy);
 | 
				
			||||||
			int steps = 12;
 | 
								int steps = 12;
 | 
				
			||||||
			angle = round(angle/M_PI*steps) / (steps/M_PI);
 | 
								angle = round(angle/M_PI*steps) / (steps/M_PI);
 | 
				
			||||||
			view_rotate(view, cursor->view_rotation + angle);
 | 
								view_rotate(view, cursor->view_rotation + angle);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,6 +9,7 @@
 | 
				
			||||||
#include <wlr/types/wlr_cursor.h>
 | 
					#include <wlr/types/wlr_cursor.h>
 | 
				
			||||||
#include <wlr/types/wlr_gamma_control.h>
 | 
					#include <wlr/types/wlr_gamma_control.h>
 | 
				
			||||||
#include <wlr/types/wlr_idle.h>
 | 
					#include <wlr/types/wlr_idle.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_linux_dmabuf.h>
 | 
				
			||||||
#include <wlr/types/wlr_output_layout.h>
 | 
					#include <wlr/types/wlr_output_layout.h>
 | 
				
			||||||
#include <wlr/types/wlr_idle_inhibit_v1.h>
 | 
					#include <wlr/types/wlr_idle_inhibit_v1.h>
 | 
				
			||||||
#include <wlr/types/wlr_primary_selection.h>
 | 
					#include <wlr/types/wlr_primary_selection.h>
 | 
				
			||||||
| 
						 | 
					@ -23,13 +24,16 @@
 | 
				
			||||||
#include "rootston/view.h"
 | 
					#include "rootston/view.h"
 | 
				
			||||||
#include "rootston/xcursor.h"
 | 
					#include "rootston/xcursor.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct roots_view *view_create(struct roots_desktop *desktop) {
 | 
				
			||||||
struct roots_view *view_create() {
 | 
					 | 
				
			||||||
	struct roots_view *view = calloc(1, sizeof(struct roots_view));
 | 
						struct roots_view *view = calloc(1, sizeof(struct roots_view));
 | 
				
			||||||
	if (!view) {
 | 
						if (!view) {
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						view->desktop = desktop;
 | 
				
			||||||
	view->alpha = 1.0f;
 | 
						view->alpha = 1.0f;
 | 
				
			||||||
 | 
						wl_signal_init(&view->events.unmap);
 | 
				
			||||||
 | 
						wl_signal_init(&view->events.destroy);
 | 
				
			||||||
 | 
						wl_list_init(&view->children);
 | 
				
			||||||
	return view;
 | 
						return view;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -52,7 +56,8 @@ void view_get_deco_box(const struct roots_view *view, struct wlr_box *box) {
 | 
				
			||||||
	box->height += (view->border_width * 2 + view->titlebar_height);
 | 
						box->height += (view->border_width * 2 + view->titlebar_height);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum roots_deco_part view_get_deco_part(struct roots_view *view, double sx, double sy) {
 | 
					enum roots_deco_part view_get_deco_part(struct roots_view *view, double sx,
 | 
				
			||||||
 | 
							double sy) {
 | 
				
			||||||
	if (!view->decorated) {
 | 
						if (!view->decorated) {
 | 
				
			||||||
		return ROOTS_DECO_PART_NONE;
 | 
							return ROOTS_DECO_PART_NONE;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -92,9 +97,15 @@ enum roots_deco_part view_get_deco_part(struct roots_view *view, double sx, doub
 | 
				
			||||||
static void view_update_output(const struct roots_view *view,
 | 
					static void view_update_output(const struct roots_view *view,
 | 
				
			||||||
		const struct wlr_box *before) {
 | 
							const struct wlr_box *before) {
 | 
				
			||||||
	struct roots_desktop *desktop = view->desktop;
 | 
						struct roots_desktop *desktop = view->desktop;
 | 
				
			||||||
	struct roots_output *output;
 | 
					
 | 
				
			||||||
 | 
						if (view->wlr_surface == NULL) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_box box;
 | 
						struct wlr_box box;
 | 
				
			||||||
	view_get_box(view, &box);
 | 
						view_get_box(view, &box);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct roots_output *output;
 | 
				
			||||||
	wl_list_for_each(output, &desktop->outputs, link) {
 | 
						wl_list_for_each(output, &desktop->outputs, link) {
 | 
				
			||||||
		bool intersected = before != NULL && wlr_output_layout_intersects(
 | 
							bool intersected = before != NULL && wlr_output_layout_intersects(
 | 
				
			||||||
			desktop->layout, output->wlr_output, before);
 | 
								desktop->layout, output->wlr_output, before);
 | 
				
			||||||
| 
						 | 
					@ -402,20 +413,22 @@ struct roots_subsurface *subsurface_create(struct roots_view *view,
 | 
				
			||||||
	return subsurface;
 | 
						return subsurface;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void view_finish(struct roots_view *view) {
 | 
					void view_destroy(struct roots_view *view) {
 | 
				
			||||||
	view_damage_whole(view);
 | 
						if (view == NULL) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl_signal_emit(&view->events.destroy, view);
 | 
						wl_signal_emit(&view->events.destroy, view);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl_list_remove(&view->new_subsurface.link);
 | 
						if (view->wlr_surface != NULL) {
 | 
				
			||||||
 | 
							view_unmap(view);
 | 
				
			||||||
	struct roots_view_child *child, *tmp;
 | 
					 | 
				
			||||||
	wl_list_for_each_safe(child, tmp, &view->children, link) {
 | 
					 | 
				
			||||||
		child->destroy(child);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (view->fullscreen_output) {
 | 
						if (view->destroy) {
 | 
				
			||||||
		view->fullscreen_output->fullscreen_view = NULL;
 | 
							view->destroy(view);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						free(view);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void view_handle_new_subsurface(struct wl_listener *listener,
 | 
					static void view_handle_new_subsurface(struct wl_listener *listener,
 | 
				
			||||||
| 
						 | 
					@ -425,12 +438,10 @@ static void view_handle_new_subsurface(struct wl_listener *listener,
 | 
				
			||||||
	subsurface_create(view, wlr_subsurface);
 | 
						subsurface_create(view, wlr_subsurface);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void view_init(struct roots_view *view, struct roots_desktop *desktop) {
 | 
					void view_map(struct roots_view *view, struct wlr_surface *surface) {
 | 
				
			||||||
	assert(view->wlr_surface);
 | 
						assert(view->wlr_surface == NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	view->desktop = desktop;
 | 
						view->wlr_surface = surface;
 | 
				
			||||||
	wl_signal_init(&view->events.destroy);
 | 
					 | 
				
			||||||
	wl_list_init(&view->children);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_subsurface *subsurface;
 | 
						struct wlr_subsurface *subsurface;
 | 
				
			||||||
	wl_list_for_each(subsurface, &view->wlr_surface->subsurface_list,
 | 
						wl_list_for_each(subsurface, &view->wlr_surface->subsurface_list,
 | 
				
			||||||
| 
						 | 
					@ -442,9 +453,35 @@ void view_init(struct roots_view *view, struct roots_desktop *desktop) {
 | 
				
			||||||
	wl_signal_add(&view->wlr_surface->events.new_subsurface,
 | 
						wl_signal_add(&view->wlr_surface->events.new_subsurface,
 | 
				
			||||||
		&view->new_subsurface);
 | 
							&view->new_subsurface);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wl_list_insert(&view->desktop->views, &view->link);
 | 
				
			||||||
	view_damage_whole(view);
 | 
						view_damage_whole(view);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void view_unmap(struct roots_view *view) {
 | 
				
			||||||
 | 
						assert(view->wlr_surface != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wl_signal_emit(&view->events.unmap, view);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						view_damage_whole(view);
 | 
				
			||||||
 | 
						wl_list_remove(&view->link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wl_list_remove(&view->new_subsurface.link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct roots_view_child *child, *tmp;
 | 
				
			||||||
 | 
						wl_list_for_each_safe(child, tmp, &view->children, link) {
 | 
				
			||||||
 | 
							child->destroy(child);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (view->fullscreen_output != NULL) {
 | 
				
			||||||
 | 
							output_damage_whole(view->fullscreen_output);
 | 
				
			||||||
 | 
							view->fullscreen_output->fullscreen_view = NULL;
 | 
				
			||||||
 | 
							view->fullscreen_output = NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						view->wlr_surface = NULL;
 | 
				
			||||||
 | 
						view->width = view->height = 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void view_initial_focus(struct roots_view *view) {
 | 
					void view_initial_focus(struct roots_view *view) {
 | 
				
			||||||
	struct roots_input *input = view->desktop->server->input;
 | 
						struct roots_input *input = view->desktop->server->input;
 | 
				
			||||||
	// TODO what seat gets focus? the one with the last input event?
 | 
						// TODO what seat gets focus? the one with the last input event?
 | 
				
			||||||
| 
						 | 
					@ -457,7 +494,10 @@ void view_initial_focus(struct roots_view *view) {
 | 
				
			||||||
void view_setup(struct roots_view *view) {
 | 
					void view_setup(struct roots_view *view) {
 | 
				
			||||||
	view_initial_focus(view);
 | 
						view_initial_focus(view);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (view->fullscreen_output == NULL && !view->maximized) {
 | 
				
			||||||
		view_center(view);
 | 
							view_center(view);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	view_update_output(view, NULL);
 | 
						view_update_output(view, NULL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -517,8 +557,8 @@ static bool view_at(struct roots_view *view, double lx, double ly,
 | 
				
			||||||
		double ox = view_sx - (double)box.width/2,
 | 
							double ox = view_sx - (double)box.width/2,
 | 
				
			||||||
			oy = view_sy - (double)box.height/2;
 | 
								oy = view_sy - (double)box.height/2;
 | 
				
			||||||
		// Rotated coordinates
 | 
							// Rotated coordinates
 | 
				
			||||||
		double rx = cos(view->rotation)*ox - sin(view->rotation)*oy,
 | 
							double rx = cos(view->rotation)*ox + sin(view->rotation)*oy,
 | 
				
			||||||
			ry = cos(view->rotation)*oy + sin(view->rotation)*ox;
 | 
								ry = cos(view->rotation)*oy - sin(view->rotation)*ox;
 | 
				
			||||||
		view_sx = rx + (double)box.width/2;
 | 
							view_sx = rx + (double)box.width/2;
 | 
				
			||||||
		view_sy = ry + (double)box.height/2;
 | 
							view_sy = ry + (double)box.height/2;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -729,6 +769,8 @@ struct roots_desktop *desktop_create(struct roots_server *server,
 | 
				
			||||||
	desktop->idle = wlr_idle_create(server->wl_display);
 | 
						desktop->idle = wlr_idle_create(server->wl_display);
 | 
				
			||||||
	desktop->idle_inhibit = wlr_idle_inhibit_v1_create(server->wl_display);
 | 
						desktop->idle_inhibit = wlr_idle_inhibit_v1_create(server->wl_display);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_egl *egl = wlr_backend_get_egl(server->backend);
 | 
				
			||||||
 | 
						desktop->linux_dmabuf = wlr_linux_dmabuf_create(server->wl_display, egl);
 | 
				
			||||||
	return desktop;
 | 
						return desktop;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,7 +7,7 @@
 | 
				
			||||||
#include <wlr/backend/headless.h>
 | 
					#include <wlr/backend/headless.h>
 | 
				
			||||||
#include <wlr/backend/multi.h>
 | 
					#include <wlr/backend/multi.h>
 | 
				
			||||||
#include <wlr/config.h>
 | 
					#include <wlr/config.h>
 | 
				
			||||||
#include <wlr/render.h>
 | 
					#include <wlr/render/wlr_renderer.h>
 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					#include <wlr/util/log.h>
 | 
				
			||||||
#include "rootston/config.h"
 | 
					#include "rootston/config.h"
 | 
				
			||||||
#include "rootston/server.h"
 | 
					#include "rootston/server.h"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,7 @@
 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <time.h>
 | 
					#include <time.h>
 | 
				
			||||||
#include <wlr/render/matrix.h>
 | 
					#include <wlr/types/wlr_matrix.h>
 | 
				
			||||||
#include <wlr/types/wlr_compositor.h>
 | 
					#include <wlr/types/wlr_compositor.h>
 | 
				
			||||||
#include <wlr/types/wlr_output_layout.h>
 | 
					#include <wlr/types/wlr_output_layout.h>
 | 
				
			||||||
#include <wlr/types/wlr_wl_shell.h>
 | 
					#include <wlr/types/wlr_wl_shell.h>
 | 
				
			||||||
| 
						 | 
					@ -29,8 +29,8 @@ static void rotate_child_position(double *sx, double *sy, double sw, double sh,
 | 
				
			||||||
		double ox = *sx - pw/2 + sw/2,
 | 
							double ox = *sx - pw/2 + sw/2,
 | 
				
			||||||
			oy = *sy - ph/2 + sh/2;
 | 
								oy = *sy - ph/2 + sh/2;
 | 
				
			||||||
		// Rotated coordinates
 | 
							// Rotated coordinates
 | 
				
			||||||
		double rx = cos(-rotation)*ox - sin(-rotation)*oy,
 | 
							double rx = cos(rotation)*ox - sin(rotation)*oy,
 | 
				
			||||||
			ry = cos(-rotation)*oy + sin(-rotation)*ox;
 | 
								ry = cos(rotation)*oy + sin(rotation)*ox;
 | 
				
			||||||
		*sx = rx + pw/2 - sw/2;
 | 
							*sx = rx + pw/2 - sw/2;
 | 
				
			||||||
		*sy = ry + ph/2 - sh/2;
 | 
							*sy = ry + ph/2 - sh/2;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -227,7 +227,7 @@ static bool surface_intersect_output(struct wlr_surface *surface,
 | 
				
			||||||
		.x = lx, .y = ly,
 | 
							.x = lx, .y = ly,
 | 
				
			||||||
		.width = surface->current->width, .height = surface->current->height,
 | 
							.width = surface->current->width, .height = surface->current->height,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	wlr_box_rotated_bounds(&layout_box, -rotation, &layout_box);
 | 
						wlr_box_rotated_bounds(&layout_box, rotation, &layout_box);
 | 
				
			||||||
	return wlr_output_layout_intersects(output_layout, wlr_output, &layout_box);
 | 
						return wlr_output_layout_intersects(output_layout, wlr_output, &layout_box);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -275,7 +275,7 @@ static void render_surface(struct wlr_surface *surface, double lx, double ly,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_box rotated;
 | 
						struct wlr_box rotated;
 | 
				
			||||||
	wlr_box_rotated_bounds(&box, -rotation, &rotated);
 | 
						wlr_box_rotated_bounds(&box, rotation, &rotated);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pixman_region32_t damage;
 | 
						pixman_region32_t damage;
 | 
				
			||||||
	pixman_region32_init(&damage);
 | 
						pixman_region32_init(&damage);
 | 
				
			||||||
| 
						 | 
					@ -287,17 +287,17 @@ static void render_surface(struct wlr_surface *surface, double lx, double ly,
 | 
				
			||||||
		goto damage_finish;
 | 
							goto damage_finish;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	float matrix[16];
 | 
						float matrix[9];
 | 
				
			||||||
	enum wl_output_transform transform =
 | 
						enum wl_output_transform transform =
 | 
				
			||||||
		wlr_output_transform_invert(surface->current->transform);
 | 
							wlr_output_transform_invert(surface->current->transform);
 | 
				
			||||||
	wlr_matrix_project_box(&matrix, &box, transform, rotation,
 | 
						wlr_matrix_project_box(matrix, &box, transform, rotation,
 | 
				
			||||||
		&output->wlr_output->transform_matrix);
 | 
							output->wlr_output->transform_matrix);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int nrects;
 | 
						int nrects;
 | 
				
			||||||
	pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects);
 | 
						pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects);
 | 
				
			||||||
	for (int i = 0; i < nrects; ++i) {
 | 
						for (int i = 0; i < nrects; ++i) {
 | 
				
			||||||
		scissor_output(output, &rects[i]);
 | 
							scissor_output(output, &rects[i]);
 | 
				
			||||||
		wlr_render_with_matrix(renderer, surface->texture, &matrix, data->alpha);
 | 
							wlr_render_texture_with_matrix(renderer, surface->texture, matrix, data->alpha);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
damage_finish:
 | 
					damage_finish:
 | 
				
			||||||
| 
						 | 
					@ -341,7 +341,7 @@ static void render_decorations(struct roots_view *view,
 | 
				
			||||||
	get_decoration_box(view, output, &box);
 | 
						get_decoration_box(view, output, &box);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_box rotated;
 | 
						struct wlr_box rotated;
 | 
				
			||||||
	wlr_box_rotated_bounds(&box, -view->rotation, &rotated);
 | 
						wlr_box_rotated_bounds(&box, view->rotation, &rotated);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pixman_region32_t damage;
 | 
						pixman_region32_t damage;
 | 
				
			||||||
	pixman_region32_init(&damage);
 | 
						pixman_region32_init(&damage);
 | 
				
			||||||
| 
						 | 
					@ -353,9 +353,9 @@ static void render_decorations(struct roots_view *view,
 | 
				
			||||||
		goto damage_finish;
 | 
							goto damage_finish;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	float matrix[16];
 | 
						float matrix[9];
 | 
				
			||||||
	wlr_matrix_project_box(&matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL,
 | 
						wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL,
 | 
				
			||||||
		view->rotation, &output->wlr_output->transform_matrix);
 | 
							view->rotation, output->wlr_output->transform_matrix);
 | 
				
			||||||
	float color[] = { 0.2, 0.2, 0.2, view->alpha };
 | 
						float color[] = { 0.2, 0.2, 0.2, view->alpha };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int nrects;
 | 
						int nrects;
 | 
				
			||||||
| 
						 | 
					@ -363,7 +363,7 @@ static void render_decorations(struct roots_view *view,
 | 
				
			||||||
		pixman_region32_rectangles(&damage, &nrects);
 | 
							pixman_region32_rectangles(&damage, &nrects);
 | 
				
			||||||
	for (int i = 0; i < nrects; ++i) {
 | 
						for (int i = 0; i < nrects; ++i) {
 | 
				
			||||||
		scissor_output(output, &rects[i]);
 | 
							scissor_output(output, &rects[i]);
 | 
				
			||||||
		wlr_render_colored_quad(renderer, &color, &matrix);
 | 
							wlr_render_colored_quad(renderer, color, matrix);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
damage_finish:
 | 
					damage_finish:
 | 
				
			||||||
| 
						 | 
					@ -433,7 +433,8 @@ static void render_output(struct roots_output *output) {
 | 
				
			||||||
	float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f};
 | 
						float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Check if we can delegate the fullscreen surface to the output
 | 
						// Check if we can delegate the fullscreen surface to the output
 | 
				
			||||||
	if (output->fullscreen_view != NULL) {
 | 
						if (output->fullscreen_view != NULL &&
 | 
				
			||||||
 | 
								output->fullscreen_view->wlr_surface != NULL) {
 | 
				
			||||||
		struct roots_view *view = output->fullscreen_view;
 | 
							struct roots_view *view = output->fullscreen_view;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Make sure the view is centered on screen
 | 
							// Make sure the view is centered on screen
 | 
				
			||||||
| 
						 | 
					@ -478,7 +479,7 @@ static void render_output(struct roots_output *output) {
 | 
				
			||||||
		goto damage_finish;
 | 
							goto damage_finish;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_renderer_begin(renderer, wlr_output);
 | 
						wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!pixman_region32_not_empty(&damage)) {
 | 
						if (!pixman_region32_not_empty(&damage)) {
 | 
				
			||||||
		// Output isn't damaged but needs buffer swap
 | 
							// Output isn't damaged but needs buffer swap
 | 
				
			||||||
| 
						 | 
					@ -489,7 +490,7 @@ static void render_output(struct roots_output *output) {
 | 
				
			||||||
	pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects);
 | 
						pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects);
 | 
				
			||||||
	for (int i = 0; i < nrects; ++i) {
 | 
						for (int i = 0; i < nrects; ++i) {
 | 
				
			||||||
		scissor_output(output, &rects[i]);
 | 
							scissor_output(output, &rects[i]);
 | 
				
			||||||
		wlr_renderer_clear(renderer, &clear_color);
 | 
							wlr_renderer_clear(renderer, clear_color);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// If a view is fullscreen on this output, render it
 | 
						// If a view is fullscreen on this output, render it
 | 
				
			||||||
| 
						 | 
					@ -501,7 +502,9 @@ static void render_output(struct roots_output *output) {
 | 
				
			||||||
			goto renderer_end;
 | 
								goto renderer_end;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (view->wlr_surface != NULL) {
 | 
				
			||||||
			view_for_each_surface(view, render_surface, &data);
 | 
								view_for_each_surface(view, render_surface, &data);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// During normal rendering the xwayland window tree isn't traversed
 | 
							// During normal rendering the xwayland window tree isn't traversed
 | 
				
			||||||
		// because all windows are rendered. Here we only want to render
 | 
							// because all windows are rendered. Here we only want to render
 | 
				
			||||||
| 
						 | 
					@ -570,6 +573,9 @@ void output_damage_whole(struct roots_output *output) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool view_accept_damage(struct roots_output *output,
 | 
					static bool view_accept_damage(struct roots_output *output,
 | 
				
			||||||
		struct roots_view *view) {
 | 
							struct roots_view *view) {
 | 
				
			||||||
 | 
						if (view->wlr_surface == NULL) {
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if (output->fullscreen_view == NULL) {
 | 
						if (output->fullscreen_view == NULL) {
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -610,7 +616,7 @@ static void damage_whole_surface(struct wlr_surface *surface,
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_box_rotated_bounds(&box, -rotation, &box);
 | 
						wlr_box_rotated_bounds(&box, rotation, &box);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_output_damage_add_box(output->damage, &box);
 | 
						wlr_output_damage_add_box(output->damage, &box);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -624,7 +630,7 @@ static void damage_whole_decoration(struct roots_view *view,
 | 
				
			||||||
	struct wlr_box box;
 | 
						struct wlr_box box;
 | 
				
			||||||
	get_decoration_box(view, output, &box);
 | 
						get_decoration_box(view, output, &box);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_box_rotated_bounds(&box, -view->rotation, &box);
 | 
						wlr_box_rotated_bounds(&box, view->rotation, &box);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_output_damage_add_box(output->damage, &box);
 | 
						wlr_output_damage_add_box(output->damage, &box);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -674,6 +680,7 @@ static void damage_from_surface(struct wlr_surface *surface,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		pixman_region32_translate(&damage, box.x, box.y);
 | 
							pixman_region32_translate(&damage, box.x, box.y);
 | 
				
			||||||
		wlr_output_damage_add(output->damage, &damage);
 | 
							wlr_output_damage_add(output->damage, &damage);
 | 
				
			||||||
 | 
							pixman_region32_fini(&damage);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		pixman_box32_t *extents =
 | 
							pixman_box32_t *extents =
 | 
				
			||||||
			pixman_region32_extents(&surface->current->surface_damage);
 | 
								pixman_region32_extents(&surface->current->surface_damage);
 | 
				
			||||||
| 
						 | 
					@ -683,7 +690,7 @@ static void damage_from_surface(struct wlr_surface *surface,
 | 
				
			||||||
			.width = (extents->x2 - extents->x1) * wlr_output->scale,
 | 
								.width = (extents->x2 - extents->x1) * wlr_output->scale,
 | 
				
			||||||
			.height = (extents->y2 - extents->y1) * wlr_output->scale,
 | 
								.height = (extents->y2 - extents->y1) * wlr_output->scale,
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
		wlr_box_rotated_bounds(&damage_box, -rotation, &damage_box);
 | 
							wlr_box_rotated_bounds(&damage_box, rotation, &damage_box);
 | 
				
			||||||
		wlr_output_damage_add_box(output->damage, &damage_box);
 | 
							wlr_output_damage_add_box(output->damage, &damage_box);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -645,6 +645,7 @@ static void seat_view_destroy(struct roots_seat_view *seat_view) {
 | 
				
			||||||
		seat->cursor->pointer_view = NULL;
 | 
							seat->cursor->pointer_view = NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wl_list_remove(&seat_view->view_unmap.link);
 | 
				
			||||||
	wl_list_remove(&seat_view->view_destroy.link);
 | 
						wl_list_remove(&seat_view->view_destroy.link);
 | 
				
			||||||
	wl_list_remove(&seat_view->link);
 | 
						wl_list_remove(&seat_view->link);
 | 
				
			||||||
	free(seat_view);
 | 
						free(seat_view);
 | 
				
			||||||
| 
						 | 
					@ -657,6 +658,12 @@ static void seat_view_destroy(struct roots_seat_view *seat_view) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void seat_view_handle_unmap(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
						struct roots_seat_view *seat_view =
 | 
				
			||||||
 | 
							wl_container_of(listener, seat_view, view_unmap);
 | 
				
			||||||
 | 
						seat_view_destroy(seat_view);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void seat_view_handle_destroy(struct wl_listener *listener, void *data) {
 | 
					static void seat_view_handle_destroy(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	struct roots_seat_view *seat_view =
 | 
						struct roots_seat_view *seat_view =
 | 
				
			||||||
		wl_container_of(listener, seat_view, view_destroy);
 | 
							wl_container_of(listener, seat_view, view_destroy);
 | 
				
			||||||
| 
						 | 
					@ -675,6 +682,8 @@ static struct roots_seat_view *seat_add_view(struct roots_seat *seat,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl_list_insert(seat->views.prev, &seat_view->link);
 | 
						wl_list_insert(seat->views.prev, &seat_view->link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						seat_view->view_unmap.notify = seat_view_handle_unmap;
 | 
				
			||||||
 | 
						wl_signal_add(&view->events.unmap, &seat_view->view_unmap);
 | 
				
			||||||
	seat_view->view_destroy.notify = seat_view_handle_destroy;
 | 
						seat_view->view_destroy.notify = seat_view_handle_destroy;
 | 
				
			||||||
	wl_signal_add(&view->events.destroy, &seat_view->view_destroy);
 | 
						wl_signal_add(&view->events.destroy, &seat_view->view_destroy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -78,6 +78,19 @@ static void close(struct roots_view *view) {
 | 
				
			||||||
	wl_client_destroy(surf->client);
 | 
						wl_client_destroy(surf->client);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void destroy(struct roots_view *view) {
 | 
				
			||||||
 | 
						assert(view->type == ROOTS_WL_SHELL_VIEW);
 | 
				
			||||||
 | 
						struct roots_wl_shell_surface *roots_surface = view->roots_wl_shell_surface;
 | 
				
			||||||
 | 
						wl_list_remove(&roots_surface->destroy.link);
 | 
				
			||||||
 | 
						wl_list_remove(&roots_surface->request_move.link);
 | 
				
			||||||
 | 
						wl_list_remove(&roots_surface->request_resize.link);
 | 
				
			||||||
 | 
						wl_list_remove(&roots_surface->request_maximize.link);
 | 
				
			||||||
 | 
						wl_list_remove(&roots_surface->request_fullscreen.link);
 | 
				
			||||||
 | 
						wl_list_remove(&roots_surface->set_state.link);
 | 
				
			||||||
 | 
						wl_list_remove(&roots_surface->surface_commit.link);
 | 
				
			||||||
 | 
						free(roots_surface);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_request_move(struct wl_listener *listener, void *data) {
 | 
					static void handle_request_move(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	struct roots_wl_shell_surface *roots_surface =
 | 
						struct roots_wl_shell_surface *roots_surface =
 | 
				
			||||||
		wl_container_of(listener, roots_surface, request_move);
 | 
							wl_container_of(listener, roots_surface, request_move);
 | 
				
			||||||
| 
						 | 
					@ -174,17 +187,7 @@ static void handle_new_popup(struct wl_listener *listener, void *data) {
 | 
				
			||||||
static void handle_destroy(struct wl_listener *listener, void *data) {
 | 
					static void handle_destroy(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	struct roots_wl_shell_surface *roots_surface =
 | 
						struct roots_wl_shell_surface *roots_surface =
 | 
				
			||||||
		wl_container_of(listener, roots_surface, destroy);
 | 
							wl_container_of(listener, roots_surface, destroy);
 | 
				
			||||||
	wl_list_remove(&roots_surface->destroy.link);
 | 
						view_destroy(roots_surface->view);
 | 
				
			||||||
	wl_list_remove(&roots_surface->request_move.link);
 | 
					 | 
				
			||||||
	wl_list_remove(&roots_surface->request_resize.link);
 | 
					 | 
				
			||||||
	wl_list_remove(&roots_surface->request_maximize.link);
 | 
					 | 
				
			||||||
	wl_list_remove(&roots_surface->request_fullscreen.link);
 | 
					 | 
				
			||||||
	wl_list_remove(&roots_surface->set_state.link);
 | 
					 | 
				
			||||||
	wl_list_remove(&roots_surface->surface_commit.link);
 | 
					 | 
				
			||||||
	wl_list_remove(&roots_surface->view->link);
 | 
					 | 
				
			||||||
	view_finish(roots_surface->view);
 | 
					 | 
				
			||||||
	free(roots_surface->view);
 | 
					 | 
				
			||||||
	free(roots_surface);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void handle_wl_shell_surface(struct wl_listener *listener, void *data) {
 | 
					void handle_wl_shell_surface(struct wl_listener *listener, void *data) {
 | 
				
			||||||
| 
						 | 
					@ -227,7 +230,7 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	roots_surface->surface_commit.notify = handle_surface_commit;
 | 
						roots_surface->surface_commit.notify = handle_surface_commit;
 | 
				
			||||||
	wl_signal_add(&surface->surface->events.commit, &roots_surface->surface_commit);
 | 
						wl_signal_add(&surface->surface->events.commit, &roots_surface->surface_commit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct roots_view *view = view_create();
 | 
						struct roots_view *view = view_create(desktop);
 | 
				
			||||||
	if (!view) {
 | 
						if (!view) {
 | 
				
			||||||
		free(roots_surface);
 | 
							free(roots_surface);
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
| 
						 | 
					@ -238,13 +241,12 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	view->wl_shell_surface = surface;
 | 
						view->wl_shell_surface = surface;
 | 
				
			||||||
	view->roots_wl_shell_surface = roots_surface;
 | 
						view->roots_wl_shell_surface = roots_surface;
 | 
				
			||||||
	view->wlr_surface = surface->surface;
 | 
					 | 
				
			||||||
	view->resize = resize;
 | 
						view->resize = resize;
 | 
				
			||||||
	view->close = close;
 | 
						view->close = close;
 | 
				
			||||||
 | 
						view->destroy = destroy;
 | 
				
			||||||
	roots_surface->view = view;
 | 
						roots_surface->view = view;
 | 
				
			||||||
	view_init(view, desktop);
 | 
					 | 
				
			||||||
	wl_list_insert(&desktop->views, &view->link);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						view_map(view, surface->surface);
 | 
				
			||||||
	view_setup(view);
 | 
						view_setup(view);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (surface->state == WLR_WL_SHELL_SURFACE_STATE_TRANSIENT) {
 | 
						if (surface->state == WLR_WL_SHELL_SURFACE_STATE_TRANSIENT) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -60,12 +60,14 @@ static void get_size(const struct roots_view *view, struct wlr_box *box) {
 | 
				
			||||||
	assert(view->type == ROOTS_XDG_SHELL_VIEW);
 | 
						assert(view->type == ROOTS_XDG_SHELL_VIEW);
 | 
				
			||||||
	struct wlr_xdg_surface *surface = view->xdg_surface;
 | 
						struct wlr_xdg_surface *surface = view->xdg_surface;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (surface->geometry->width > 0 && surface->geometry->height > 0) {
 | 
						if (surface->geometry.width > 0 && surface->geometry.height > 0) {
 | 
				
			||||||
		box->width = surface->geometry->width;
 | 
							box->width = surface->geometry.width;
 | 
				
			||||||
		box->height = surface->geometry->height;
 | 
							box->height = surface->geometry.height;
 | 
				
			||||||
	} else {
 | 
						} else if (view->wlr_surface != NULL) {
 | 
				
			||||||
		box->width = view->wlr_surface->current->width;
 | 
							box->width = view->wlr_surface->current->width;
 | 
				
			||||||
		box->height = view->wlr_surface->current->height;
 | 
							box->height = view->wlr_surface->current->height;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							box->width = box->height = 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -83,7 +85,7 @@ static void apply_size_constraints(struct wlr_xdg_surface *surface,
 | 
				
			||||||
	*dest_width = width;
 | 
						*dest_width = width;
 | 
				
			||||||
	*dest_height = height;
 | 
						*dest_height = height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_xdg_toplevel_state *state = &surface->toplevel_state->current;
 | 
						struct wlr_xdg_toplevel_state *state = &surface->toplevel->current;
 | 
				
			||||||
	if (width < state->min_width) {
 | 
						if (width < state->min_width) {
 | 
				
			||||||
		*dest_width = state->min_width;
 | 
							*dest_width = state->min_width;
 | 
				
			||||||
	} else if (state->max_width > 0 &&
 | 
						} else if (state->max_width > 0 &&
 | 
				
			||||||
| 
						 | 
					@ -180,6 +182,21 @@ static void close(struct roots_view *view) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void destroy(struct roots_view *view) {
 | 
				
			||||||
 | 
						assert(view->type == ROOTS_XDG_SHELL_VIEW);
 | 
				
			||||||
 | 
						struct roots_xdg_surface *roots_xdg_surface = view->roots_xdg_surface;
 | 
				
			||||||
 | 
						wl_list_remove(&roots_xdg_surface->surface_commit.link);
 | 
				
			||||||
 | 
						wl_list_remove(&roots_xdg_surface->destroy.link);
 | 
				
			||||||
 | 
						wl_list_remove(&roots_xdg_surface->new_popup.link);
 | 
				
			||||||
 | 
						wl_list_remove(&roots_xdg_surface->map.link);
 | 
				
			||||||
 | 
						wl_list_remove(&roots_xdg_surface->unmap.link);
 | 
				
			||||||
 | 
						wl_list_remove(&roots_xdg_surface->request_move.link);
 | 
				
			||||||
 | 
						wl_list_remove(&roots_xdg_surface->request_resize.link);
 | 
				
			||||||
 | 
						wl_list_remove(&roots_xdg_surface->request_maximize.link);
 | 
				
			||||||
 | 
						wl_list_remove(&roots_xdg_surface->request_fullscreen.link);
 | 
				
			||||||
 | 
						free(roots_xdg_surface);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_request_move(struct wl_listener *listener, void *data) {
 | 
					static void handle_request_move(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	struct roots_xdg_surface *roots_xdg_surface =
 | 
						struct roots_xdg_surface *roots_xdg_surface =
 | 
				
			||||||
		wl_container_of(listener, roots_xdg_surface, request_move);
 | 
							wl_container_of(listener, roots_xdg_surface, request_move);
 | 
				
			||||||
| 
						 | 
					@ -219,7 +236,7 @@ static void handle_request_maximize(struct wl_listener *listener, void *data) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	view_maximize(view, surface->toplevel_state->next.maximized);
 | 
						view_maximize(view, surface->toplevel->next.maximized);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_request_fullscreen(struct wl_listener *listener,
 | 
					static void handle_request_fullscreen(struct wl_listener *listener,
 | 
				
			||||||
| 
						 | 
					@ -243,6 +260,10 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	struct roots_view *view = roots_surface->view;
 | 
						struct roots_view *view = roots_surface->view;
 | 
				
			||||||
	struct wlr_xdg_surface *surface = view->xdg_surface;
 | 
						struct wlr_xdg_surface *surface = view->xdg_surface;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!surface->mapped) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	view_apply_damage(view);
 | 
						view_apply_damage(view);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_box size;
 | 
						struct wlr_box size;
 | 
				
			||||||
| 
						 | 
					@ -277,20 +298,30 @@ static void handle_new_popup(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	popup_create(roots_xdg_surface->view, wlr_popup);
 | 
						popup_create(roots_xdg_surface->view, wlr_popup);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_map(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
						struct roots_xdg_surface *roots_xdg_surface =
 | 
				
			||||||
 | 
							wl_container_of(listener, roots_xdg_surface, map);
 | 
				
			||||||
 | 
						struct roots_view *view = roots_xdg_surface->view;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_box box;
 | 
				
			||||||
 | 
						get_size(view, &box);
 | 
				
			||||||
 | 
						view->width = box.width;
 | 
				
			||||||
 | 
						view->height = box.height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						view_map(view, view->xdg_surface->surface);
 | 
				
			||||||
 | 
						view_setup(view);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_unmap(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
						struct roots_xdg_surface *roots_xdg_surface =
 | 
				
			||||||
 | 
							wl_container_of(listener, roots_xdg_surface, unmap);
 | 
				
			||||||
 | 
						view_unmap(roots_xdg_surface->view);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_destroy(struct wl_listener *listener, void *data) {
 | 
					static void handle_destroy(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	struct roots_xdg_surface *roots_xdg_surface =
 | 
						struct roots_xdg_surface *roots_xdg_surface =
 | 
				
			||||||
		wl_container_of(listener, roots_xdg_surface, destroy);
 | 
							wl_container_of(listener, roots_xdg_surface, destroy);
 | 
				
			||||||
	wl_list_remove(&roots_xdg_surface->surface_commit.link);
 | 
						view_destroy(roots_xdg_surface->view);
 | 
				
			||||||
	wl_list_remove(&roots_xdg_surface->destroy.link);
 | 
					 | 
				
			||||||
	wl_list_remove(&roots_xdg_surface->new_popup.link);
 | 
					 | 
				
			||||||
	wl_list_remove(&roots_xdg_surface->request_move.link);
 | 
					 | 
				
			||||||
	wl_list_remove(&roots_xdg_surface->request_resize.link);
 | 
					 | 
				
			||||||
	wl_list_remove(&roots_xdg_surface->request_maximize.link);
 | 
					 | 
				
			||||||
	wl_list_remove(&roots_xdg_surface->request_fullscreen.link);
 | 
					 | 
				
			||||||
	wl_list_remove(&roots_xdg_surface->view->link);
 | 
					 | 
				
			||||||
	view_finish(roots_xdg_surface->view);
 | 
					 | 
				
			||||||
	free(roots_xdg_surface->view);
 | 
					 | 
				
			||||||
	free(roots_xdg_surface);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void handle_xdg_shell_surface(struct wl_listener *listener, void *data) {
 | 
					void handle_xdg_shell_surface(struct wl_listener *listener, void *data) {
 | 
				
			||||||
| 
						 | 
					@ -319,6 +350,10 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) {
 | 
				
			||||||
		&roots_surface->surface_commit);
 | 
							&roots_surface->surface_commit);
 | 
				
			||||||
	roots_surface->destroy.notify = handle_destroy;
 | 
						roots_surface->destroy.notify = handle_destroy;
 | 
				
			||||||
	wl_signal_add(&surface->events.destroy, &roots_surface->destroy);
 | 
						wl_signal_add(&surface->events.destroy, &roots_surface->destroy);
 | 
				
			||||||
 | 
						roots_surface->map.notify = handle_map;
 | 
				
			||||||
 | 
						wl_signal_add(&surface->events.map, &roots_surface->map);
 | 
				
			||||||
 | 
						roots_surface->unmap.notify = handle_unmap;
 | 
				
			||||||
 | 
						wl_signal_add(&surface->events.unmap, &roots_surface->unmap);
 | 
				
			||||||
	roots_surface->request_move.notify = handle_request_move;
 | 
						roots_surface->request_move.notify = handle_request_move;
 | 
				
			||||||
	wl_signal_add(&surface->events.request_move, &roots_surface->request_move);
 | 
						wl_signal_add(&surface->events.request_move, &roots_surface->request_move);
 | 
				
			||||||
	roots_surface->request_resize.notify = handle_request_resize;
 | 
						roots_surface->request_resize.notify = handle_request_resize;
 | 
				
			||||||
| 
						 | 
					@ -333,7 +368,7 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	roots_surface->new_popup.notify = handle_new_popup;
 | 
						roots_surface->new_popup.notify = handle_new_popup;
 | 
				
			||||||
	wl_signal_add(&surface->events.new_popup, &roots_surface->new_popup);
 | 
						wl_signal_add(&surface->events.new_popup, &roots_surface->new_popup);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct roots_view *view = view_create();
 | 
						struct roots_view *view = view_create(desktop);
 | 
				
			||||||
	if (!view) {
 | 
						if (!view) {
 | 
				
			||||||
		free(roots_surface);
 | 
							free(roots_surface);
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
| 
						 | 
					@ -342,22 +377,19 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	view->xdg_surface = surface;
 | 
						view->xdg_surface = surface;
 | 
				
			||||||
	view->roots_xdg_surface = roots_surface;
 | 
						view->roots_xdg_surface = roots_surface;
 | 
				
			||||||
	view->wlr_surface = surface->surface;
 | 
					 | 
				
			||||||
	view->activate = activate;
 | 
						view->activate = activate;
 | 
				
			||||||
	view->resize = resize;
 | 
						view->resize = resize;
 | 
				
			||||||
	view->move_resize = move_resize;
 | 
						view->move_resize = move_resize;
 | 
				
			||||||
	view->maximize = maximize;
 | 
						view->maximize = maximize;
 | 
				
			||||||
	view->set_fullscreen = set_fullscreen;
 | 
						view->set_fullscreen = set_fullscreen;
 | 
				
			||||||
	view->close = close;
 | 
						view->close = close;
 | 
				
			||||||
 | 
						view->destroy = destroy;
 | 
				
			||||||
	roots_surface->view = view;
 | 
						roots_surface->view = view;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_box box;
 | 
						if (surface->toplevel->next.maximized) {
 | 
				
			||||||
	get_size(view, &box);
 | 
							view_maximize(view, true);
 | 
				
			||||||
	view->width = box.width;
 | 
						}
 | 
				
			||||||
	view->height = box.height;
 | 
						if (surface->toplevel->next.fullscreen) {
 | 
				
			||||||
 | 
							view_set_fullscreen(view, true, NULL);
 | 
				
			||||||
	view_init(view, desktop);
 | 
						}
 | 
				
			||||||
	wl_list_insert(&desktop->views, &view->link);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	view_setup(view);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -60,12 +60,14 @@ static void get_size(const struct roots_view *view, struct wlr_box *box) {
 | 
				
			||||||
	assert(view->type == ROOTS_XDG_SHELL_V6_VIEW);
 | 
						assert(view->type == ROOTS_XDG_SHELL_V6_VIEW);
 | 
				
			||||||
	struct wlr_xdg_surface_v6 *surface = view->xdg_surface_v6;
 | 
						struct wlr_xdg_surface_v6 *surface = view->xdg_surface_v6;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (surface->geometry->width > 0 && surface->geometry->height > 0) {
 | 
						if (surface->geometry.width > 0 && surface->geometry.height > 0) {
 | 
				
			||||||
		box->width = surface->geometry->width;
 | 
							box->width = surface->geometry.width;
 | 
				
			||||||
		box->height = surface->geometry->height;
 | 
							box->height = surface->geometry.height;
 | 
				
			||||||
	} else {
 | 
						} else if (view->wlr_surface != NULL) {
 | 
				
			||||||
		box->width = view->wlr_surface->current->width;
 | 
							box->width = view->wlr_surface->current->width;
 | 
				
			||||||
		box->height = view->wlr_surface->current->height;
 | 
							box->height = view->wlr_surface->current->height;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							box->width = box->height = 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -83,7 +85,7 @@ static void apply_size_constraints(struct wlr_xdg_surface_v6 *surface,
 | 
				
			||||||
	*dest_width = width;
 | 
						*dest_width = width;
 | 
				
			||||||
	*dest_height = height;
 | 
						*dest_height = height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_xdg_toplevel_v6_state *state = &surface->toplevel_state->current;
 | 
						struct wlr_xdg_toplevel_v6_state *state = &surface->toplevel->current;
 | 
				
			||||||
	if (width < state->min_width) {
 | 
						if (width < state->min_width) {
 | 
				
			||||||
		*dest_width = state->min_width;
 | 
							*dest_width = state->min_width;
 | 
				
			||||||
	} else if (state->max_width > 0 &&
 | 
						} else if (state->max_width > 0 &&
 | 
				
			||||||
| 
						 | 
					@ -180,6 +182,21 @@ static void close(struct roots_view *view) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void destroy(struct roots_view *view) {
 | 
				
			||||||
 | 
						assert(view->type == ROOTS_XDG_SHELL_V6_VIEW);
 | 
				
			||||||
 | 
						struct roots_xdg_surface_v6 *roots_xdg_surface = view->roots_xdg_surface_v6;
 | 
				
			||||||
 | 
						wl_list_remove(&roots_xdg_surface->surface_commit.link);
 | 
				
			||||||
 | 
						wl_list_remove(&roots_xdg_surface->destroy.link);
 | 
				
			||||||
 | 
						wl_list_remove(&roots_xdg_surface->new_popup.link);
 | 
				
			||||||
 | 
						wl_list_remove(&roots_xdg_surface->map.link);
 | 
				
			||||||
 | 
						wl_list_remove(&roots_xdg_surface->unmap.link);
 | 
				
			||||||
 | 
						wl_list_remove(&roots_xdg_surface->request_move.link);
 | 
				
			||||||
 | 
						wl_list_remove(&roots_xdg_surface->request_resize.link);
 | 
				
			||||||
 | 
						wl_list_remove(&roots_xdg_surface->request_maximize.link);
 | 
				
			||||||
 | 
						wl_list_remove(&roots_xdg_surface->request_fullscreen.link);
 | 
				
			||||||
 | 
						free(roots_xdg_surface);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_request_move(struct wl_listener *listener, void *data) {
 | 
					static void handle_request_move(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	struct roots_xdg_surface_v6 *roots_xdg_surface =
 | 
						struct roots_xdg_surface_v6 *roots_xdg_surface =
 | 
				
			||||||
		wl_container_of(listener, roots_xdg_surface, request_move);
 | 
							wl_container_of(listener, roots_xdg_surface, request_move);
 | 
				
			||||||
| 
						 | 
					@ -219,7 +236,7 @@ static void handle_request_maximize(struct wl_listener *listener, void *data) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	view_maximize(view, surface->toplevel_state->next.maximized);
 | 
						view_maximize(view, surface->toplevel->next.maximized);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_request_fullscreen(struct wl_listener *listener,
 | 
					static void handle_request_fullscreen(struct wl_listener *listener,
 | 
				
			||||||
| 
						 | 
					@ -243,6 +260,10 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	struct roots_view *view = roots_surface->view;
 | 
						struct roots_view *view = roots_surface->view;
 | 
				
			||||||
	struct wlr_xdg_surface_v6 *surface = view->xdg_surface_v6;
 | 
						struct wlr_xdg_surface_v6 *surface = view->xdg_surface_v6;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!surface->mapped) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	view_apply_damage(view);
 | 
						view_apply_damage(view);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_box size;
 | 
						struct wlr_box size;
 | 
				
			||||||
| 
						 | 
					@ -277,20 +298,30 @@ static void handle_new_popup(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	popup_create(roots_xdg_surface->view, wlr_popup);
 | 
						popup_create(roots_xdg_surface->view, wlr_popup);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_map(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
						struct roots_xdg_surface_v6 *roots_xdg_surface =
 | 
				
			||||||
 | 
							wl_container_of(listener, roots_xdg_surface, map);
 | 
				
			||||||
 | 
						struct roots_view *view = roots_xdg_surface->view;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_box box;
 | 
				
			||||||
 | 
						get_size(view, &box);
 | 
				
			||||||
 | 
						view->width = box.width;
 | 
				
			||||||
 | 
						view->height = box.height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						view_map(view, view->xdg_surface_v6->surface);
 | 
				
			||||||
 | 
						view_setup(view);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_unmap(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
						struct roots_xdg_surface_v6 *roots_xdg_surface =
 | 
				
			||||||
 | 
							wl_container_of(listener, roots_xdg_surface, unmap);
 | 
				
			||||||
 | 
						view_unmap(roots_xdg_surface->view);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_destroy(struct wl_listener *listener, void *data) {
 | 
					static void handle_destroy(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	struct roots_xdg_surface_v6 *roots_xdg_surface =
 | 
						struct roots_xdg_surface_v6 *roots_xdg_surface =
 | 
				
			||||||
		wl_container_of(listener, roots_xdg_surface, destroy);
 | 
							wl_container_of(listener, roots_xdg_surface, destroy);
 | 
				
			||||||
	wl_list_remove(&roots_xdg_surface->surface_commit.link);
 | 
						view_destroy(roots_xdg_surface->view);
 | 
				
			||||||
	wl_list_remove(&roots_xdg_surface->destroy.link);
 | 
					 | 
				
			||||||
	wl_list_remove(&roots_xdg_surface->new_popup.link);
 | 
					 | 
				
			||||||
	wl_list_remove(&roots_xdg_surface->request_move.link);
 | 
					 | 
				
			||||||
	wl_list_remove(&roots_xdg_surface->request_resize.link);
 | 
					 | 
				
			||||||
	wl_list_remove(&roots_xdg_surface->request_maximize.link);
 | 
					 | 
				
			||||||
	wl_list_remove(&roots_xdg_surface->request_fullscreen.link);
 | 
					 | 
				
			||||||
	wl_list_remove(&roots_xdg_surface->view->link);
 | 
					 | 
				
			||||||
	view_finish(roots_xdg_surface->view);
 | 
					 | 
				
			||||||
	free(roots_xdg_surface->view);
 | 
					 | 
				
			||||||
	free(roots_xdg_surface);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {
 | 
					void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {
 | 
				
			||||||
| 
						 | 
					@ -319,6 +350,10 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {
 | 
				
			||||||
		&roots_surface->surface_commit);
 | 
							&roots_surface->surface_commit);
 | 
				
			||||||
	roots_surface->destroy.notify = handle_destroy;
 | 
						roots_surface->destroy.notify = handle_destroy;
 | 
				
			||||||
	wl_signal_add(&surface->events.destroy, &roots_surface->destroy);
 | 
						wl_signal_add(&surface->events.destroy, &roots_surface->destroy);
 | 
				
			||||||
 | 
						roots_surface->map.notify = handle_map;
 | 
				
			||||||
 | 
						wl_signal_add(&surface->events.map, &roots_surface->map);
 | 
				
			||||||
 | 
						roots_surface->unmap.notify = handle_unmap;
 | 
				
			||||||
 | 
						wl_signal_add(&surface->events.unmap, &roots_surface->unmap);
 | 
				
			||||||
	roots_surface->request_move.notify = handle_request_move;
 | 
						roots_surface->request_move.notify = handle_request_move;
 | 
				
			||||||
	wl_signal_add(&surface->events.request_move, &roots_surface->request_move);
 | 
						wl_signal_add(&surface->events.request_move, &roots_surface->request_move);
 | 
				
			||||||
	roots_surface->request_resize.notify = handle_request_resize;
 | 
						roots_surface->request_resize.notify = handle_request_resize;
 | 
				
			||||||
| 
						 | 
					@ -333,7 +368,7 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	roots_surface->new_popup.notify = handle_new_popup;
 | 
						roots_surface->new_popup.notify = handle_new_popup;
 | 
				
			||||||
	wl_signal_add(&surface->events.new_popup, &roots_surface->new_popup);
 | 
						wl_signal_add(&surface->events.new_popup, &roots_surface->new_popup);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct roots_view *view = view_create();
 | 
						struct roots_view *view = view_create(desktop);
 | 
				
			||||||
	if (!view) {
 | 
						if (!view) {
 | 
				
			||||||
		free(roots_surface);
 | 
							free(roots_surface);
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
| 
						 | 
					@ -342,22 +377,19 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	view->xdg_surface_v6 = surface;
 | 
						view->xdg_surface_v6 = surface;
 | 
				
			||||||
	view->roots_xdg_surface_v6 = roots_surface;
 | 
						view->roots_xdg_surface_v6 = roots_surface;
 | 
				
			||||||
	view->wlr_surface = surface->surface;
 | 
					 | 
				
			||||||
	view->activate = activate;
 | 
						view->activate = activate;
 | 
				
			||||||
	view->resize = resize;
 | 
						view->resize = resize;
 | 
				
			||||||
	view->move_resize = move_resize;
 | 
						view->move_resize = move_resize;
 | 
				
			||||||
	view->maximize = maximize;
 | 
						view->maximize = maximize;
 | 
				
			||||||
	view->set_fullscreen = set_fullscreen;
 | 
						view->set_fullscreen = set_fullscreen;
 | 
				
			||||||
	view->close = close;
 | 
						view->close = close;
 | 
				
			||||||
 | 
						view->destroy = destroy;
 | 
				
			||||||
	roots_surface->view = view;
 | 
						roots_surface->view = view;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_box box;
 | 
						if (surface->toplevel->next.maximized) {
 | 
				
			||||||
	get_size(view, &box);
 | 
							view_maximize(view, true);
 | 
				
			||||||
	view->width = box.width;
 | 
						}
 | 
				
			||||||
	view->height = box.height;
 | 
						if (surface->toplevel->next.fullscreen) {
 | 
				
			||||||
 | 
							view_set_fullscreen(view, true, NULL);
 | 
				
			||||||
	view_init(view, desktop);
 | 
						}
 | 
				
			||||||
	wl_list_insert(&desktop->views, &view->link);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	view_setup(view);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -106,11 +106,9 @@ static void set_fullscreen(struct roots_view *view, bool fullscreen) {
 | 
				
			||||||
	wlr_xwayland_surface_set_fullscreen(view->xwayland_surface, fullscreen);
 | 
						wlr_xwayland_surface_set_fullscreen(view->xwayland_surface, fullscreen);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_destroy(struct wl_listener *listener, void *data) {
 | 
					static void destroy(struct roots_view *view) {
 | 
				
			||||||
	struct roots_xwayland_surface *roots_surface =
 | 
						assert(view->type == ROOTS_XWAYLAND_VIEW);
 | 
				
			||||||
		wl_container_of(listener, roots_surface, destroy);
 | 
						struct roots_xwayland_surface *roots_surface = view->roots_xwayland_surface;
 | 
				
			||||||
	struct wlr_xwayland_surface *xwayland_surface =
 | 
					 | 
				
			||||||
		roots_surface->view->xwayland_surface;
 | 
					 | 
				
			||||||
	wl_list_remove(&roots_surface->destroy.link);
 | 
						wl_list_remove(&roots_surface->destroy.link);
 | 
				
			||||||
	wl_list_remove(&roots_surface->request_configure.link);
 | 
						wl_list_remove(&roots_surface->request_configure.link);
 | 
				
			||||||
	wl_list_remove(&roots_surface->request_move.link);
 | 
						wl_list_remove(&roots_surface->request_move.link);
 | 
				
			||||||
| 
						 | 
					@ -118,14 +116,15 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	wl_list_remove(&roots_surface->request_maximize.link);
 | 
						wl_list_remove(&roots_surface->request_maximize.link);
 | 
				
			||||||
	wl_list_remove(&roots_surface->map_notify.link);
 | 
						wl_list_remove(&roots_surface->map_notify.link);
 | 
				
			||||||
	wl_list_remove(&roots_surface->unmap_notify.link);
 | 
						wl_list_remove(&roots_surface->unmap_notify.link);
 | 
				
			||||||
	if (xwayland_surface->mapped) {
 | 
					 | 
				
			||||||
		wl_list_remove(&roots_surface->view->link);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	view_finish(roots_surface->view);
 | 
					 | 
				
			||||||
	free(roots_surface->view);
 | 
					 | 
				
			||||||
	free(roots_surface);
 | 
						free(roots_surface);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_destroy(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
						struct roots_xwayland_surface *roots_surface =
 | 
				
			||||||
 | 
							wl_container_of(listener, roots_surface, destroy);
 | 
				
			||||||
 | 
						view_destroy(roots_surface->view);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_request_configure(struct wl_listener *listener, void *data) {
 | 
					static void handle_request_configure(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	struct roots_xwayland_surface *roots_surface =
 | 
						struct roots_xwayland_surface *roots_surface =
 | 
				
			||||||
		wl_container_of(listener, roots_surface, request_configure);
 | 
							wl_container_of(listener, roots_surface, request_configure);
 | 
				
			||||||
| 
						 | 
					@ -231,22 +230,13 @@ static void handle_map_notify(struct wl_listener *listener, void *data) {
 | 
				
			||||||
		wl_container_of(listener, roots_surface, map_notify);
 | 
							wl_container_of(listener, roots_surface, map_notify);
 | 
				
			||||||
	struct wlr_xwayland_surface *xsurface = data;
 | 
						struct wlr_xwayland_surface *xsurface = data;
 | 
				
			||||||
	struct roots_view *view = roots_surface->view;
 | 
						struct roots_view *view = roots_surface->view;
 | 
				
			||||||
	struct roots_desktop *desktop = view->desktop;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	view->wlr_surface = xsurface->surface;
 | 
					 | 
				
			||||||
	view->x = xsurface->x;
 | 
						view->x = xsurface->x;
 | 
				
			||||||
	view->y = xsurface->y;
 | 
						view->y = xsurface->y;
 | 
				
			||||||
	view->width = xsurface->surface->current->width;
 | 
						view->width = xsurface->surface->current->width;
 | 
				
			||||||
	view->height = xsurface->surface->current->height;
 | 
						view->height = xsurface->surface->current->height;
 | 
				
			||||||
	wl_list_insert(&desktop->views, &view->link);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_subsurface *subsurface;
 | 
						view_map(view, xsurface->surface);
 | 
				
			||||||
	wl_list_for_each(subsurface, &view->wlr_surface->subsurface_list,
 | 
					 | 
				
			||||||
			parent_link) {
 | 
					 | 
				
			||||||
		subsurface_create(view, subsurface);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	view_damage_whole(view);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	roots_surface->surface_commit.notify = handle_surface_commit;
 | 
						roots_surface->surface_commit.notify = handle_surface_commit;
 | 
				
			||||||
	wl_signal_add(&xsurface->surface->events.commit,
 | 
						wl_signal_add(&xsurface->surface->events.commit,
 | 
				
			||||||
| 
						 | 
					@ -260,22 +250,7 @@ static void handle_unmap_notify(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl_list_remove(&roots_surface->surface_commit.link);
 | 
						wl_list_remove(&roots_surface->surface_commit.link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	view_damage_whole(view);
 | 
						view_unmap(view);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct roots_view_child *child, *tmp;
 | 
					 | 
				
			||||||
	wl_list_for_each_safe(child, tmp, &view->children, link) {
 | 
					 | 
				
			||||||
		child->destroy(child);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (view->fullscreen_output != NULL) {
 | 
					 | 
				
			||||||
		output_damage_whole(view->fullscreen_output);
 | 
					 | 
				
			||||||
		view->fullscreen_output->fullscreen_view = NULL;
 | 
					 | 
				
			||||||
		view->fullscreen_output = NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	view->wlr_surface = NULL;
 | 
					 | 
				
			||||||
	view->width = view->height = 0;
 | 
					 | 
				
			||||||
	wl_list_remove(&view->link);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void handle_xwayland_surface(struct wl_listener *listener, void *data) {
 | 
					void handle_xwayland_surface(struct wl_listener *listener, void *data) {
 | 
				
			||||||
| 
						 | 
					@ -317,7 +292,7 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	wl_signal_add(&surface->surface->events.commit,
 | 
						wl_signal_add(&surface->surface->events.commit,
 | 
				
			||||||
		&roots_surface->surface_commit);
 | 
							&roots_surface->surface_commit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct roots_view *view = view_create();
 | 
						struct roots_view *view = view_create(desktop);
 | 
				
			||||||
	if (view == NULL) {
 | 
						if (view == NULL) {
 | 
				
			||||||
		free(roots_surface);
 | 
							free(roots_surface);
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
| 
						 | 
					@ -330,7 +305,6 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	view->xwayland_surface = surface;
 | 
						view->xwayland_surface = surface;
 | 
				
			||||||
	view->roots_xwayland_surface = roots_surface;
 | 
						view->roots_xwayland_surface = roots_surface;
 | 
				
			||||||
	view->wlr_surface = surface->surface;
 | 
					 | 
				
			||||||
	view->activate = activate;
 | 
						view->activate = activate;
 | 
				
			||||||
	view->resize = resize;
 | 
						view->resize = resize;
 | 
				
			||||||
	view->move = move;
 | 
						view->move = move;
 | 
				
			||||||
| 
						 | 
					@ -338,9 +312,10 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	view->maximize = maximize;
 | 
						view->maximize = maximize;
 | 
				
			||||||
	view->set_fullscreen = set_fullscreen;
 | 
						view->set_fullscreen = set_fullscreen;
 | 
				
			||||||
	view->close = close;
 | 
						view->close = close;
 | 
				
			||||||
 | 
						view->destroy = destroy;
 | 
				
			||||||
	roots_surface->view = view;
 | 
						roots_surface->view = view;
 | 
				
			||||||
	view_init(view, desktop);
 | 
					
 | 
				
			||||||
	wl_list_insert(&desktop->views, &view->link);
 | 
						view_map(view, surface->surface);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!surface->override_redirect) {
 | 
						if (!surface->override_redirect) {
 | 
				
			||||||
		if (surface->decorations == WLR_XWAYLAND_SURFACE_DECORATIONS_ALL) {
 | 
							if (surface->decorations == WLR_XWAYLAND_SURFACE_DECORATIONS_ALL) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,10 +6,13 @@ lib_wlr_types = static_library(
 | 
				
			||||||
		'wlr_cursor.c',
 | 
							'wlr_cursor.c',
 | 
				
			||||||
		'wlr_data_device.c',
 | 
							'wlr_data_device.c',
 | 
				
			||||||
		'wlr_gamma_control.c',
 | 
							'wlr_gamma_control.c',
 | 
				
			||||||
 | 
							'wlr_idle_inhibit_v1.c',
 | 
				
			||||||
		'wlr_idle.c',
 | 
							'wlr_idle.c',
 | 
				
			||||||
		'wlr_input_device.c',
 | 
							'wlr_input_device.c',
 | 
				
			||||||
		'wlr_keyboard.c',
 | 
							'wlr_keyboard.c',
 | 
				
			||||||
 | 
							'wlr_linux_dmabuf.c',
 | 
				
			||||||
		'wlr_list.c',
 | 
							'wlr_list.c',
 | 
				
			||||||
 | 
							'wlr_matrix.c',
 | 
				
			||||||
		'wlr_output_damage.c',
 | 
							'wlr_output_damage.c',
 | 
				
			||||||
		'wlr_output_layout.c',
 | 
							'wlr_output_layout.c',
 | 
				
			||||||
		'wlr_output.c',
 | 
							'wlr_output.c',
 | 
				
			||||||
| 
						 | 
					@ -27,7 +30,6 @@ lib_wlr_types = static_library(
 | 
				
			||||||
		'wlr_xcursor_manager.c',
 | 
							'wlr_xcursor_manager.c',
 | 
				
			||||||
		'wlr_xdg_shell_v6.c',
 | 
							'wlr_xdg_shell_v6.c',
 | 
				
			||||||
		'wlr_xdg_shell.c',
 | 
							'wlr_xdg_shell.c',
 | 
				
			||||||
		'wlr_idle_inhibit_v1.c',
 | 
					 | 
				
			||||||
	),
 | 
						),
 | 
				
			||||||
	include_directories: wlr_inc,
 | 
						include_directories: wlr_inc,
 | 
				
			||||||
	dependencies: [pixman, xkbcommon, wayland_server, wlr_protos],
 | 
						dependencies: [pixman, xkbcommon, wayland_server, wlr_protos],
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										463
									
								
								types/wlr_linux_dmabuf.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										463
									
								
								types/wlr_linux_dmabuf.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,463 @@
 | 
				
			||||||
 | 
					#ifndef _POSIX_C_SOURCE
 | 
				
			||||||
 | 
					#define _POSIX_C_SOURCE 200809L
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <wayland-server.h>
 | 
				
			||||||
 | 
					#include <wlr/render/egl.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_linux_dmabuf.h>
 | 
				
			||||||
 | 
					#include <wlr/util/log.h>
 | 
				
			||||||
 | 
					#include "linux-dmabuf-unstable-v1-protocol.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void wl_buffer_destroy(struct wl_client *client,
 | 
				
			||||||
 | 
							struct wl_resource *resource) {
 | 
				
			||||||
 | 
						wl_resource_destroy(resource);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct wl_buffer_interface wl_buffer_impl = {
 | 
				
			||||||
 | 
						wl_buffer_destroy,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool wlr_dmabuf_buffer_has_inverted_y(struct wlr_dmabuf_buffer *dmabuf) {
 | 
				
			||||||
 | 
						return dmabuf->attributes.flags
 | 
				
			||||||
 | 
							& ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool wlr_dmabuf_resource_is_buffer(struct wl_resource *buffer_resource) {
 | 
				
			||||||
 | 
						if (!wl_resource_instance_of(buffer_resource, &wl_buffer_interface,
 | 
				
			||||||
 | 
							&wl_buffer_impl)) {
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_dmabuf_buffer *buffer = wl_resource_get_user_data(buffer_resource);
 | 
				
			||||||
 | 
						if (buffer && buffer->buffer_resource && !buffer->params_resource &&
 | 
				
			||||||
 | 
							buffer->buffer_resource == buffer_resource) {
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_dmabuf_buffer *wlr_dmabuf_buffer_from_buffer_resource(
 | 
				
			||||||
 | 
							struct wl_resource *buffer_resource) {
 | 
				
			||||||
 | 
						assert(wl_resource_instance_of(buffer_resource, &wl_buffer_interface,
 | 
				
			||||||
 | 
								&wl_buffer_impl));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_dmabuf_buffer *buffer = wl_resource_get_user_data(buffer_resource);
 | 
				
			||||||
 | 
						assert(buffer);
 | 
				
			||||||
 | 
						assert(buffer->buffer_resource);
 | 
				
			||||||
 | 
						assert(!buffer->params_resource);
 | 
				
			||||||
 | 
						assert(buffer->buffer_resource == buffer_resource);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return buffer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void linux_dmabuf_buffer_destroy(struct wlr_dmabuf_buffer *buffer) {
 | 
				
			||||||
 | 
						for (int i = 0; i < buffer->attributes.n_planes; i++) {
 | 
				
			||||||
 | 
							close(buffer->attributes.fd[i]);
 | 
				
			||||||
 | 
							buffer->attributes.fd[i] = -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						buffer->attributes.n_planes = 0;
 | 
				
			||||||
 | 
						free(buffer);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void params_destroy(struct wl_client *client, struct wl_resource *resource) {
 | 
				
			||||||
 | 
						wl_resource_destroy(resource);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void params_add(struct wl_client *client,
 | 
				
			||||||
 | 
							struct wl_resource *params_resource, int32_t name_fd,
 | 
				
			||||||
 | 
							uint32_t plane_idx, uint32_t offset, uint32_t stride,
 | 
				
			||||||
 | 
							uint32_t modifier_hi, uint32_t modifier_lo) {
 | 
				
			||||||
 | 
						struct wlr_dmabuf_buffer *buffer = wlr_dmabuf_buffer_from_params_resource(
 | 
				
			||||||
 | 
							params_resource);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!buffer) {
 | 
				
			||||||
 | 
							wl_resource_post_error(params_resource,
 | 
				
			||||||
 | 
								ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
 | 
				
			||||||
 | 
								"params was already used to create a wl_buffer");
 | 
				
			||||||
 | 
							close(name_fd);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (plane_idx >= WLR_LINUX_DMABUF_MAX_PLANES) {
 | 
				
			||||||
 | 
							wl_resource_post_error(params_resource,
 | 
				
			||||||
 | 
								ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_IDX,
 | 
				
			||||||
 | 
								"plane index %u > %u", plane_idx, WLR_LINUX_DMABUF_MAX_PLANES);
 | 
				
			||||||
 | 
							close(name_fd);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (buffer->attributes.fd[plane_idx] != -1) {
 | 
				
			||||||
 | 
							wl_resource_post_error(params_resource,
 | 
				
			||||||
 | 
								ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_SET,
 | 
				
			||||||
 | 
								"a dmabuf with id %d has already been added for plane %u",
 | 
				
			||||||
 | 
								buffer->attributes.fd[plane_idx],
 | 
				
			||||||
 | 
								plane_idx);
 | 
				
			||||||
 | 
							close(name_fd);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						buffer->attributes.fd[plane_idx] = name_fd;
 | 
				
			||||||
 | 
						buffer->attributes.offset[plane_idx] = offset;
 | 
				
			||||||
 | 
						buffer->attributes.stride[plane_idx] = stride;
 | 
				
			||||||
 | 
						buffer->attributes.modifier[plane_idx] = ((uint64_t)modifier_hi << 32) |
 | 
				
			||||||
 | 
							modifier_lo;
 | 
				
			||||||
 | 
						buffer->attributes.n_planes++;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_buffer_destroy(struct wl_resource *buffer_resource)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct wlr_dmabuf_buffer *buffer = wlr_dmabuf_buffer_from_buffer_resource(
 | 
				
			||||||
 | 
							buffer_resource);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						linux_dmabuf_buffer_destroy(buffer);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void params_create_common(struct wl_client *client,
 | 
				
			||||||
 | 
							struct wl_resource *params_resource, uint32_t buffer_id, int32_t width,
 | 
				
			||||||
 | 
							int32_t height, uint32_t format, uint32_t flags) {
 | 
				
			||||||
 | 
						if (!wl_resource_get_user_data(params_resource)) {
 | 
				
			||||||
 | 
							wl_resource_post_error(params_resource,
 | 
				
			||||||
 | 
								ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
 | 
				
			||||||
 | 
								"params was already used to create a wl_buffer");
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						struct wlr_dmabuf_buffer *buffer = wlr_dmabuf_buffer_from_params_resource(
 | 
				
			||||||
 | 
							params_resource);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Switch the linux_dmabuf_buffer object from params resource to
 | 
				
			||||||
 | 
						 * eventually wl_buffer resource. */
 | 
				
			||||||
 | 
						wl_resource_set_user_data(buffer->params_resource, NULL);
 | 
				
			||||||
 | 
						buffer->params_resource = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!buffer->attributes.n_planes) {
 | 
				
			||||||
 | 
							wl_resource_post_error(params_resource,
 | 
				
			||||||
 | 
								ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
 | 
				
			||||||
 | 
								"no dmabuf has been added to the params");
 | 
				
			||||||
 | 
							goto err_out;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* TODO: support more planes */
 | 
				
			||||||
 | 
						if (buffer->attributes.n_planes != 1) {
 | 
				
			||||||
 | 
							wl_resource_post_error(params_resource,
 | 
				
			||||||
 | 
								ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
 | 
				
			||||||
 | 
								"only single plane buffers supported not %d",
 | 
				
			||||||
 | 
								buffer->attributes.n_planes);
 | 
				
			||||||
 | 
							goto err_out;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (buffer->attributes.fd[0] == -1) {
 | 
				
			||||||
 | 
							wl_resource_post_error(params_resource,
 | 
				
			||||||
 | 
								ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
 | 
				
			||||||
 | 
								"no dmabuf has been added for plane");
 | 
				
			||||||
 | 
							goto err_out;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						buffer->attributes.width = width;
 | 
				
			||||||
 | 
						buffer->attributes.height = height;
 | 
				
			||||||
 | 
						buffer->attributes.format = format;
 | 
				
			||||||
 | 
						buffer->attributes.flags = flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (width < 1 || height < 1) {
 | 
				
			||||||
 | 
							wl_resource_post_error(params_resource,
 | 
				
			||||||
 | 
								ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_DIMENSIONS,
 | 
				
			||||||
 | 
								"invalid width %d or height %d", width, height);
 | 
				
			||||||
 | 
							goto err_out;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((uint64_t)buffer->attributes.offset[0] + buffer->attributes.stride[0] > UINT32_MAX) {
 | 
				
			||||||
 | 
							wl_resource_post_error(params_resource,
 | 
				
			||||||
 | 
								ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
 | 
				
			||||||
 | 
								"size overflow for plane");
 | 
				
			||||||
 | 
							goto err_out;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((uint64_t)buffer->attributes.offset[0] +
 | 
				
			||||||
 | 
								(uint64_t)buffer->attributes.stride[0] * height > UINT32_MAX) {
 | 
				
			||||||
 | 
							wl_resource_post_error(params_resource,
 | 
				
			||||||
 | 
								ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
 | 
				
			||||||
 | 
								"size overflow for plane");
 | 
				
			||||||
 | 
							goto err_out;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						off_t size = lseek(buffer->attributes.fd[0], 0, SEEK_END);
 | 
				
			||||||
 | 
						if (size != -1) { /* Skip checks if kernel does no support seek on buffer */
 | 
				
			||||||
 | 
							if (buffer->attributes.offset[0] >= size) {
 | 
				
			||||||
 | 
								wl_resource_post_error(params_resource,
 | 
				
			||||||
 | 
									ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
 | 
				
			||||||
 | 
									"invalid offset %i for plane",
 | 
				
			||||||
 | 
									buffer->attributes.offset[0]);
 | 
				
			||||||
 | 
								goto err_out;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (buffer->attributes.offset[0] + buffer->attributes.stride[0] > size) {
 | 
				
			||||||
 | 
								wl_resource_post_error(params_resource,
 | 
				
			||||||
 | 
									ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
 | 
				
			||||||
 | 
									"invalid stride %i for plane",
 | 
				
			||||||
 | 
									buffer->attributes.stride[0]);
 | 
				
			||||||
 | 
								goto err_out;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (buffer->attributes.offset[0] + buffer->attributes.stride[0] * height > size) {
 | 
				
			||||||
 | 
								wl_resource_post_error(params_resource,
 | 
				
			||||||
 | 
									ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
 | 
				
			||||||
 | 
									"invalid buffer stride or height for plane");
 | 
				
			||||||
 | 
								goto err_out;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* reject unknown flags */
 | 
				
			||||||
 | 
						if (buffer->attributes.flags & ~ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT) {
 | 
				
			||||||
 | 
							wl_resource_post_error(params_resource,
 | 
				
			||||||
 | 
								ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_FORMAT,
 | 
				
			||||||
 | 
								"Unknown dmabuf flags %"PRIu32, buffer->attributes.flags);
 | 
				
			||||||
 | 
							goto err_out;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Check if dmabuf is usable */
 | 
				
			||||||
 | 
						if (!wlr_egl_check_import_dmabuf(buffer->egl, buffer)) {
 | 
				
			||||||
 | 
							goto err_failed;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						buffer->buffer_resource = wl_resource_create(client, &wl_buffer_interface,
 | 
				
			||||||
 | 
							1, buffer_id);
 | 
				
			||||||
 | 
						if (!buffer->buffer_resource) {
 | 
				
			||||||
 | 
							wl_resource_post_no_memory(params_resource);
 | 
				
			||||||
 | 
							goto err_failed;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wl_resource_set_implementation(buffer->buffer_resource,
 | 
				
			||||||
 | 
							&wl_buffer_impl, buffer, handle_buffer_destroy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* send 'created' event when the request is not for an immediate
 | 
				
			||||||
 | 
						 * import, that is buffer_id is zero */
 | 
				
			||||||
 | 
						if (buffer_id == 0) {
 | 
				
			||||||
 | 
							zwp_linux_buffer_params_v1_send_created(params_resource,
 | 
				
			||||||
 | 
								buffer->buffer_resource);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					err_failed:
 | 
				
			||||||
 | 
						if (buffer_id == 0) {
 | 
				
			||||||
 | 
							zwp_linux_buffer_params_v1_send_failed(params_resource);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							/* since the behavior is left implementation defined by the
 | 
				
			||||||
 | 
							 * protocol in case of create_immed failure due to an unknown cause,
 | 
				
			||||||
 | 
							 * we choose to treat it as a fatal error and immediately kill the
 | 
				
			||||||
 | 
							 * client instead of creating an invalid handle and waiting for it
 | 
				
			||||||
 | 
							 * to be used.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							wl_resource_post_error(params_resource,
 | 
				
			||||||
 | 
								ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_WL_BUFFER,
 | 
				
			||||||
 | 
								"importing the supplied dmabufs failed");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					err_out:
 | 
				
			||||||
 | 
						linux_dmabuf_buffer_destroy(buffer);
 | 
				
			||||||
 | 
						return;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void params_create(struct wl_client *client,
 | 
				
			||||||
 | 
							struct wl_resource *params_resource,
 | 
				
			||||||
 | 
							int32_t width, int32_t height,uint32_t format, uint32_t flags) {
 | 
				
			||||||
 | 
						params_create_common(client, params_resource, 0, width, height, format, flags);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void params_create_immed(struct wl_client *client,
 | 
				
			||||||
 | 
							struct wl_resource *params_resource, uint32_t buffer_id,
 | 
				
			||||||
 | 
							int32_t width, int32_t height,uint32_t format, uint32_t flags) {
 | 
				
			||||||
 | 
						params_create_common(client, params_resource, buffer_id, width, height, format, flags);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct zwp_linux_buffer_params_v1_interface linux_buffer_params_impl = {
 | 
				
			||||||
 | 
						params_destroy,
 | 
				
			||||||
 | 
						params_add,
 | 
				
			||||||
 | 
						params_create,
 | 
				
			||||||
 | 
						params_create_immed,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_dmabuf_buffer *wlr_dmabuf_buffer_from_params_resource(
 | 
				
			||||||
 | 
							struct wl_resource *params_resource) {
 | 
				
			||||||
 | 
						assert(wl_resource_instance_of(params_resource,
 | 
				
			||||||
 | 
							&zwp_linux_buffer_params_v1_interface,
 | 
				
			||||||
 | 
							&linux_buffer_params_impl));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_dmabuf_buffer *buffer = wl_resource_get_user_data(params_resource);
 | 
				
			||||||
 | 
						assert(buffer);
 | 
				
			||||||
 | 
						assert(buffer->params_resource);
 | 
				
			||||||
 | 
						assert(!buffer->buffer_resource);
 | 
				
			||||||
 | 
						assert(buffer->params_resource == params_resource);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return buffer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_params_destroy(struct wl_resource *params_resource) {
 | 
				
			||||||
 | 
						/* Check for NULL since wlr_dmabuf_buffer_from_params_resource will choke */
 | 
				
			||||||
 | 
						if (!wl_resource_get_user_data(params_resource)) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_dmabuf_buffer *buffer =
 | 
				
			||||||
 | 
							wlr_dmabuf_buffer_from_params_resource(params_resource);
 | 
				
			||||||
 | 
						linux_dmabuf_buffer_destroy(buffer);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void linux_dmabuf_create_params(struct wl_client *client,
 | 
				
			||||||
 | 
							struct wl_resource *linux_dmabuf_resource,
 | 
				
			||||||
 | 
							uint32_t params_id) {
 | 
				
			||||||
 | 
						struct wlr_linux_dmabuf *linux_dmabuf = wlr_linux_dmabuf_from_resource(
 | 
				
			||||||
 | 
							linux_dmabuf_resource);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint32_t version = wl_resource_get_version(linux_dmabuf_resource);
 | 
				
			||||||
 | 
						struct wlr_dmabuf_buffer *buffer = calloc(1, sizeof *buffer);
 | 
				
			||||||
 | 
						if (!buffer) {
 | 
				
			||||||
 | 
							goto err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (int i = 0; i < WLR_LINUX_DMABUF_MAX_PLANES; i++) {
 | 
				
			||||||
 | 
							buffer->attributes.fd[i] = -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						buffer->egl = linux_dmabuf->egl;
 | 
				
			||||||
 | 
						buffer->params_resource = wl_resource_create(client,
 | 
				
			||||||
 | 
							&zwp_linux_buffer_params_v1_interface,
 | 
				
			||||||
 | 
							version, params_id);
 | 
				
			||||||
 | 
						if (!buffer->params_resource) {
 | 
				
			||||||
 | 
							goto err_free;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wl_resource_set_implementation(buffer->params_resource,
 | 
				
			||||||
 | 
							&linux_buffer_params_impl,buffer, handle_params_destroy);
 | 
				
			||||||
 | 
						return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					err_free:
 | 
				
			||||||
 | 
						free(buffer);
 | 
				
			||||||
 | 
					err:
 | 
				
			||||||
 | 
						wl_resource_post_no_memory(linux_dmabuf_resource);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void linux_dmabuf_destroy(struct wl_client *client, struct wl_resource *resource) {
 | 
				
			||||||
 | 
						wl_resource_destroy(resource);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct zwp_linux_dmabuf_v1_interface linux_dmabuf_impl = {
 | 
				
			||||||
 | 
						linux_dmabuf_destroy,
 | 
				
			||||||
 | 
						linux_dmabuf_create_params
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_linux_dmabuf *wlr_linux_dmabuf_from_resource(
 | 
				
			||||||
 | 
							struct wl_resource *resource) {
 | 
				
			||||||
 | 
						assert(wl_resource_instance_of(resource, &zwp_linux_dmabuf_v1_interface,
 | 
				
			||||||
 | 
								&linux_dmabuf_impl));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_linux_dmabuf *dmabuf = wl_resource_get_user_data(resource);
 | 
				
			||||||
 | 
						assert(dmabuf);
 | 
				
			||||||
 | 
						return dmabuf;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void linux_dmabuf_send_modifiers(struct wlr_linux_dmabuf *linux_dmabuf,
 | 
				
			||||||
 | 
							struct wl_resource *resource) {
 | 
				
			||||||
 | 
						struct wlr_egl *egl = linux_dmabuf->egl;
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Use EGL_EXT_image_dma_buf_import_modifiers to query and advertise
 | 
				
			||||||
 | 
						 * format/modifier codes.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						uint64_t modifier_invalid = DRM_FORMAT_MOD_INVALID;
 | 
				
			||||||
 | 
						int *formats = NULL;
 | 
				
			||||||
 | 
						int num_formats = wlr_egl_get_dmabuf_formats(egl, &formats);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (num_formats < 0) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (int i = 0; i < num_formats; i++) {
 | 
				
			||||||
 | 
							int num_modifiers;
 | 
				
			||||||
 | 
							uint64_t *modifiers = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							num_modifiers = wlr_egl_get_dmabuf_modifiers(egl, formats[i],
 | 
				
			||||||
 | 
								&modifiers);
 | 
				
			||||||
 | 
							if (num_modifiers < 0) {
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							/* send DRM_FORMAT_MOD_INVALID token when no modifiers are supported
 | 
				
			||||||
 | 
							 * for this format */
 | 
				
			||||||
 | 
							if (num_modifiers == 0) {
 | 
				
			||||||
 | 
								num_modifiers = 1;
 | 
				
			||||||
 | 
								modifiers = &modifier_invalid;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for (int j = 0; j < num_modifiers; j++) {
 | 
				
			||||||
 | 
								uint32_t modifier_lo = modifiers[j] & 0xFFFFFFFF;
 | 
				
			||||||
 | 
								uint32_t modifier_hi = modifiers[j] >> 32;
 | 
				
			||||||
 | 
								zwp_linux_dmabuf_v1_send_modifier(resource, formats[i],
 | 
				
			||||||
 | 
									modifier_hi,
 | 
				
			||||||
 | 
									modifier_lo);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (modifiers != &modifier_invalid) {
 | 
				
			||||||
 | 
								free(modifiers);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						free(formats);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void linux_dmabuf_bind(struct wl_client *client,
 | 
				
			||||||
 | 
							void *data, uint32_t version, uint32_t id) {
 | 
				
			||||||
 | 
						struct wlr_linux_dmabuf *linux_dmabuf = data;
 | 
				
			||||||
 | 
						struct wl_resource *resource = wl_resource_create(client,
 | 
				
			||||||
 | 
							  &zwp_linux_dmabuf_v1_interface,
 | 
				
			||||||
 | 
							  version, id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (resource == NULL) {
 | 
				
			||||||
 | 
							wl_client_post_no_memory(client);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wl_resource_set_implementation(resource, &linux_dmabuf_impl,
 | 
				
			||||||
 | 
							linux_dmabuf, NULL);
 | 
				
			||||||
 | 
						if (version < ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION) {
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						linux_dmabuf_send_modifiers(linux_dmabuf, resource);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void wlr_linux_dmabuf_destroy(struct wlr_linux_dmabuf *linux_dmabuf) {
 | 
				
			||||||
 | 
						if (!linux_dmabuf) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						wl_list_remove(&linux_dmabuf->display_destroy.link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wl_global_destroy(linux_dmabuf->wl_global);
 | 
				
			||||||
 | 
						free(linux_dmabuf);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_display_destroy(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
						struct wlr_linux_dmabuf *linux_dmabuf = wl_container_of(listener, linux_dmabuf, display_destroy);
 | 
				
			||||||
 | 
						wlr_linux_dmabuf_destroy(linux_dmabuf);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_linux_dmabuf *wlr_linux_dmabuf_create(struct wl_display *display,
 | 
				
			||||||
 | 
							struct wlr_egl *egl) {
 | 
				
			||||||
 | 
						struct wlr_linux_dmabuf *linux_dmabuf =
 | 
				
			||||||
 | 
							calloc(1, sizeof(struct wlr_linux_dmabuf));
 | 
				
			||||||
 | 
						if (linux_dmabuf == NULL) {
 | 
				
			||||||
 | 
							wlr_log(L_ERROR, "could not create simple dmabuf manager");
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						linux_dmabuf->display_destroy.notify = handle_display_destroy;
 | 
				
			||||||
 | 
						wl_display_add_destroy_listener(display, &linux_dmabuf->display_destroy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						linux_dmabuf->wl_global =
 | 
				
			||||||
 | 
							wl_global_create(display, &zwp_linux_dmabuf_v1_interface,
 | 
				
			||||||
 | 
								3, linux_dmabuf, linux_dmabuf_bind);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						linux_dmabuf->egl = egl;
 | 
				
			||||||
 | 
						if (!linux_dmabuf->wl_global) {
 | 
				
			||||||
 | 
							wlr_log(L_ERROR, "could not create linux dmabuf v1 wl global");
 | 
				
			||||||
 | 
							free(linux_dmabuf);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return linux_dmabuf;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										169
									
								
								types/wlr_matrix.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								types/wlr_matrix.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,169 @@
 | 
				
			||||||
 | 
					#include <math.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <wayland-server-protocol.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_matrix.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_box.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_output.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void wlr_matrix_identity(float mat[static 9]) {
 | 
				
			||||||
 | 
						static const float identity[9] = {
 | 
				
			||||||
 | 
							1.0f, 0.0f, 0.0f,
 | 
				
			||||||
 | 
							0.0f, 1.0f, 0.0f,
 | 
				
			||||||
 | 
							0.0f, 0.0f, 1.0f,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						memcpy(mat, identity, sizeof(identity));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void wlr_matrix_multiply(float mat[static 9], const float a[static 9],
 | 
				
			||||||
 | 
							const float b[static 9]) {
 | 
				
			||||||
 | 
						float product[9];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						product[0] = a[0]*b[0] + a[1]*b[3] + a[2]*b[6];
 | 
				
			||||||
 | 
						product[1] = a[0]*b[1] + a[1]*b[4] + a[2]*b[7];
 | 
				
			||||||
 | 
						product[2] = a[0]*b[2] + a[1]*b[5] + a[2]*b[8];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						product[3] = a[3]*b[0] + a[4]*b[3] + a[5]*b[6];
 | 
				
			||||||
 | 
						product[4] = a[3]*b[1] + a[4]*b[4] + a[5]*b[7];
 | 
				
			||||||
 | 
						product[5] = a[3]*b[2] + a[4]*b[5] + a[5]*b[8];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						product[6] = a[6]*b[0] + a[7]*b[3] + a[8]*b[6];
 | 
				
			||||||
 | 
						product[7] = a[6]*b[1] + a[7]*b[4] + a[8]*b[7];
 | 
				
			||||||
 | 
						product[8] = a[6]*b[2] + a[7]*b[5] + a[8]*b[8];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memcpy(mat, product, sizeof(product));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void wlr_matrix_transpose(float mat[static 9], const float a[static 9]) {
 | 
				
			||||||
 | 
						float transposition[9] = {
 | 
				
			||||||
 | 
							a[0], a[3], a[6],
 | 
				
			||||||
 | 
							a[1], a[4], a[7],
 | 
				
			||||||
 | 
							a[2], a[5], a[8],
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						memcpy(mat, transposition, sizeof(transposition));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void wlr_matrix_translate(float mat[static 9], float x, float y) {
 | 
				
			||||||
 | 
						float translate[9] = {
 | 
				
			||||||
 | 
							1.0f, 0.0f, x,
 | 
				
			||||||
 | 
							0.0f, 1.0f, y,
 | 
				
			||||||
 | 
							0.0f, 0.0f, 1.0f,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						wlr_matrix_multiply(mat, mat, translate);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void wlr_matrix_scale(float mat[static 9], float x, float y) {
 | 
				
			||||||
 | 
						float scale[9] = {
 | 
				
			||||||
 | 
							x,    0.0f, 0.0f,
 | 
				
			||||||
 | 
							0.0f, y,    0.0f,
 | 
				
			||||||
 | 
							0.0f, 0.0f, 1.0f,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						wlr_matrix_multiply(mat, mat, scale);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void wlr_matrix_rotate(float mat[static 9], float rad) {
 | 
				
			||||||
 | 
						float rotate[9] = {
 | 
				
			||||||
 | 
							cos(rad), -sin(rad), 0.0f,
 | 
				
			||||||
 | 
							sin(rad),  cos(rad), 0.0f,
 | 
				
			||||||
 | 
							0.0f,      0.0f,     1.0f,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						wlr_matrix_multiply(mat, mat, rotate);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const float transforms[][9] = {
 | 
				
			||||||
 | 
						[WL_OUTPUT_TRANSFORM_NORMAL] = {
 | 
				
			||||||
 | 
							1.0f, 0.0f, 0.0f,
 | 
				
			||||||
 | 
							0.0f, 1.0f, 0.0f,
 | 
				
			||||||
 | 
							0.0f, 0.0f, 1.0f,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						[WL_OUTPUT_TRANSFORM_90] = {
 | 
				
			||||||
 | 
							0.0f, -1.0f, 0.0f,
 | 
				
			||||||
 | 
							1.0f, 0.0f, 0.0f,
 | 
				
			||||||
 | 
							0.0f, 0.0f, 1.0f,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						[WL_OUTPUT_TRANSFORM_180] = {
 | 
				
			||||||
 | 
							-1.0f, 0.0f, 0.0f,
 | 
				
			||||||
 | 
							0.0f, -1.0f, 0.0f,
 | 
				
			||||||
 | 
							0.0f, 0.0f, 1.0f,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						[WL_OUTPUT_TRANSFORM_270] = {
 | 
				
			||||||
 | 
							0.0f, 1.0f, 0.0f,
 | 
				
			||||||
 | 
							-1.0f, 0.0f, 0.0f,
 | 
				
			||||||
 | 
							0.0f, 0.0f, 1.0f,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						[WL_OUTPUT_TRANSFORM_FLIPPED] = {
 | 
				
			||||||
 | 
							-1.0f, 0.0f, 0.0f,
 | 
				
			||||||
 | 
							0.0f, 1.0f, 0.0f,
 | 
				
			||||||
 | 
							0.0f, 0.0f, 1.0f,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						[WL_OUTPUT_TRANSFORM_FLIPPED_90] = {
 | 
				
			||||||
 | 
							0.0f, -1.0f, 0.0f,
 | 
				
			||||||
 | 
							-1.0f, 0.0f, 0.0f,
 | 
				
			||||||
 | 
							0.0f, 0.0f, 1.0f,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						[WL_OUTPUT_TRANSFORM_FLIPPED_180] = {
 | 
				
			||||||
 | 
							1.0f, 0.0f, 0.0f,
 | 
				
			||||||
 | 
							0.0f, -1.0f, 0.0f,
 | 
				
			||||||
 | 
							0.0f, 0.0f, 1.0f,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						[WL_OUTPUT_TRANSFORM_FLIPPED_270] = {
 | 
				
			||||||
 | 
							0.0f, 1.0f, 0.0f,
 | 
				
			||||||
 | 
							1.0f, 0.0f, 0.0f,
 | 
				
			||||||
 | 
							0.0f, 0.0f, 1.0f,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void wlr_matrix_transform(float mat[static 9],
 | 
				
			||||||
 | 
							enum wl_output_transform transform) {
 | 
				
			||||||
 | 
						wlr_matrix_multiply(mat, mat, transforms[transform]);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Equivilent to glOrtho(0, width, 0, height, 1, -1) with the transform applied
 | 
				
			||||||
 | 
					void wlr_matrix_projection(float mat[static 9], int width, int height,
 | 
				
			||||||
 | 
							enum wl_output_transform transform) {
 | 
				
			||||||
 | 
						memset(mat, 0, sizeof(*mat) * 9);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const float *t = transforms[transform];
 | 
				
			||||||
 | 
						float x = 2.0f / width;
 | 
				
			||||||
 | 
						float y = 2.0f / height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Rotation + reflection
 | 
				
			||||||
 | 
						mat[0] = x * t[0];
 | 
				
			||||||
 | 
						mat[1] = x * t[1];
 | 
				
			||||||
 | 
						mat[3] = y * -t[3];
 | 
				
			||||||
 | 
						mat[4] = y * -t[4];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Translation
 | 
				
			||||||
 | 
						mat[2] = -copysign(1.0f, mat[0] + mat[1]);
 | 
				
			||||||
 | 
						mat[5] = -copysign(1.0f, mat[3] + mat[4]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Identity
 | 
				
			||||||
 | 
						mat[8] = 1.0f;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void wlr_matrix_project_box(float mat[static 9], const struct wlr_box *box,
 | 
				
			||||||
 | 
							enum wl_output_transform transform, float rotation,
 | 
				
			||||||
 | 
							const float projection[static 9]) {
 | 
				
			||||||
 | 
						int x = box->x;
 | 
				
			||||||
 | 
						int y = box->y;
 | 
				
			||||||
 | 
						int width = box->width;
 | 
				
			||||||
 | 
						int height = box->height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wlr_matrix_identity(mat);
 | 
				
			||||||
 | 
						wlr_matrix_translate(mat, x, y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (rotation != 0) {
 | 
				
			||||||
 | 
							wlr_matrix_translate(mat, width/2, height/2);
 | 
				
			||||||
 | 
							wlr_matrix_rotate(mat, rotation);
 | 
				
			||||||
 | 
							wlr_matrix_translate(mat, -width/2, -height/2);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wlr_matrix_scale(mat, width, height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (transform != WL_OUTPUT_TRANSFORM_NORMAL) {
 | 
				
			||||||
 | 
							wlr_matrix_translate(mat, 0.5, 0.5);
 | 
				
			||||||
 | 
							wlr_matrix_transform(mat, transform);
 | 
				
			||||||
 | 
							wlr_matrix_translate(mat, -0.5, -0.5);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wlr_matrix_multiply(mat, projection, mat);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -6,8 +6,8 @@
 | 
				
			||||||
#include <time.h>
 | 
					#include <time.h>
 | 
				
			||||||
#include <wayland-server.h>
 | 
					#include <wayland-server.h>
 | 
				
			||||||
#include <wlr/interfaces/wlr_output.h>
 | 
					#include <wlr/interfaces/wlr_output.h>
 | 
				
			||||||
#include <wlr/render.h>
 | 
					#include <wlr/render/wlr_renderer.h>
 | 
				
			||||||
#include <wlr/render/matrix.h>
 | 
					#include <wlr/types/wlr_matrix.h>
 | 
				
			||||||
#include <wlr/types/wlr_box.h>
 | 
					#include <wlr/types/wlr_box.h>
 | 
				
			||||||
#include <wlr/types/wlr_output.h>
 | 
					#include <wlr/types/wlr_output.h>
 | 
				
			||||||
#include <wlr/types/wlr_surface.h>
 | 
					#include <wlr/types/wlr_surface.h>
 | 
				
			||||||
| 
						 | 
					@ -139,8 +139,8 @@ void wlr_output_update_enabled(struct wlr_output *output, bool enabled) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void wlr_output_update_matrix(struct wlr_output *output) {
 | 
					static void wlr_output_update_matrix(struct wlr_output *output) {
 | 
				
			||||||
	wlr_matrix_texture(output->transform_matrix, output->width, output->height,
 | 
						wlr_matrix_projection(output->transform_matrix, output->width,
 | 
				
			||||||
		output->transform);
 | 
							output->height, output->transform);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void wlr_output_enable(struct wlr_output *output, bool enable) {
 | 
					void wlr_output_enable(struct wlr_output *output, bool enable) {
 | 
				
			||||||
| 
						 | 
					@ -368,25 +368,25 @@ static void output_fullscreen_surface_render(struct wlr_output *output,
 | 
				
			||||||
	assert(renderer);
 | 
						assert(renderer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!wlr_surface_has_buffer(surface)) {
 | 
						if (!wlr_surface_has_buffer(surface)) {
 | 
				
			||||||
		wlr_renderer_clear(renderer, &(float[]){0, 0, 0, 0});
 | 
							wlr_renderer_clear(renderer, (float[]){0, 0, 0, 0});
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_box box;
 | 
						struct wlr_box box;
 | 
				
			||||||
	output_fullscreen_surface_get_box(output, surface, &box);
 | 
						output_fullscreen_surface_get_box(output, surface, &box);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	float matrix[16];
 | 
						float matrix[9];
 | 
				
			||||||
	enum wl_output_transform transform =
 | 
						enum wl_output_transform transform =
 | 
				
			||||||
		wlr_output_transform_invert(surface->current->transform);
 | 
							wlr_output_transform_invert(surface->current->transform);
 | 
				
			||||||
	wlr_matrix_project_box(&matrix, &box, transform, 0,
 | 
						wlr_matrix_project_box(matrix, &box, transform, 0,
 | 
				
			||||||
		&output->transform_matrix);
 | 
							output->transform_matrix);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int nrects;
 | 
						int nrects;
 | 
				
			||||||
	pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects);
 | 
						pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects);
 | 
				
			||||||
	for (int i = 0; i < nrects; ++i) {
 | 
						for (int i = 0; i < nrects; ++i) {
 | 
				
			||||||
		output_scissor(output, &rects[i]);
 | 
							output_scissor(output, &rects[i]);
 | 
				
			||||||
		wlr_renderer_clear(renderer, &(float[]){0, 0, 0, 0});
 | 
							wlr_renderer_clear(renderer, (float[]){0, 0, 0, 0});
 | 
				
			||||||
		wlr_render_with_matrix(surface->renderer, surface->texture, &matrix, 1.0f);
 | 
							wlr_render_texture_with_matrix(surface->renderer, surface->texture, matrix, 1.0f);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	wlr_renderer_scissor(renderer, NULL);
 | 
						wlr_renderer_scissor(renderer, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -435,15 +435,15 @@ static void output_cursor_render(struct wlr_output_cursor *cursor,
 | 
				
			||||||
		goto surface_damage_finish;
 | 
							goto surface_damage_finish;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	float matrix[16];
 | 
						float matrix[9];
 | 
				
			||||||
	wlr_matrix_project_box(&matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0,
 | 
						wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0,
 | 
				
			||||||
		&cursor->output->transform_matrix);
 | 
							cursor->output->transform_matrix);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int nrects;
 | 
						int nrects;
 | 
				
			||||||
	pixman_box32_t *rects = pixman_region32_rectangles(&surface_damage, &nrects);
 | 
						pixman_box32_t *rects = pixman_region32_rectangles(&surface_damage, &nrects);
 | 
				
			||||||
	for (int i = 0; i < nrects; ++i) {
 | 
						for (int i = 0; i < nrects; ++i) {
 | 
				
			||||||
		output_scissor(cursor->output, &rects[i]);
 | 
							output_scissor(cursor->output, &rects[i]);
 | 
				
			||||||
		wlr_render_with_matrix(renderer, texture, &matrix, 1.0f);
 | 
							wlr_render_texture_with_matrix(renderer, texture, matrix, 1.0f);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	wlr_renderer_scissor(renderer, NULL);
 | 
						wlr_renderer_scissor(renderer, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,7 +14,10 @@ void wlr_pointer_init(struct wlr_pointer *pointer,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void wlr_pointer_destroy(struct wlr_pointer *pointer) {
 | 
					void wlr_pointer_destroy(struct wlr_pointer *pointer) {
 | 
				
			||||||
	if (pointer && pointer->impl && pointer->impl->destroy) {
 | 
						if (!pointer) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (pointer->impl && pointer->impl->destroy) {
 | 
				
			||||||
		pointer->impl->destroy(pointer);
 | 
							pointer->impl->destroy(pointer);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		wl_list_remove(&pointer->events.motion.listener_list);
 | 
							wl_list_remove(&pointer->events.motion.listener_list);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,7 @@
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
#include <wayland-server.h>
 | 
					#include <wayland-server.h>
 | 
				
			||||||
#include <wlr/backend.h>
 | 
					#include <wlr/backend.h>
 | 
				
			||||||
#include <wlr/render.h>
 | 
					#include <wlr/render/wlr_renderer.h>
 | 
				
			||||||
#include <wlr/types/wlr_output.h>
 | 
					#include <wlr/types/wlr_output.h>
 | 
				
			||||||
#include <wlr/types/wlr_screenshooter.h>
 | 
					#include <wlr/types/wlr_screenshooter.h>
 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					#include <wlr/util/log.h>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,7 @@
 | 
				
			||||||
#include <wayland-server.h>
 | 
					#include <wayland-server.h>
 | 
				
			||||||
#include <wlr/render/egl.h>
 | 
					#include <wlr/render/egl.h>
 | 
				
			||||||
#include <wlr/render/interface.h>
 | 
					#include <wlr/render/interface.h>
 | 
				
			||||||
#include <wlr/render/matrix.h>
 | 
					#include <wlr/types/wlr_matrix.h>
 | 
				
			||||||
#include <wlr/types/wlr_region.h>
 | 
					#include <wlr/types/wlr_region.h>
 | 
				
			||||||
#include <wlr/types/wlr_surface.h>
 | 
					#include <wlr/types/wlr_surface.h>
 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					#include <wlr/util/log.h>
 | 
				
			||||||
| 
						 | 
					@ -325,6 +325,10 @@ static void wlr_surface_apply_damage(struct wlr_surface *surface,
 | 
				
			||||||
					surface->current->buffer)) {
 | 
										surface->current->buffer)) {
 | 
				
			||||||
			wlr_texture_upload_drm(surface->texture, surface->current->buffer);
 | 
								wlr_texture_upload_drm(surface->texture, surface->current->buffer);
 | 
				
			||||||
			goto release;
 | 
								goto release;
 | 
				
			||||||
 | 
							} else if (wlr_dmabuf_resource_is_buffer(
 | 
				
			||||||
 | 
										   surface->current->buffer)) {
 | 
				
			||||||
 | 
								wlr_texture_upload_dmabuf(surface->texture, surface->current->buffer);
 | 
				
			||||||
 | 
								goto release;
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			wlr_log(L_INFO, "Unknown buffer handle attached");
 | 
								wlr_log(L_INFO, "Unknown buffer handle attached");
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
| 
						 | 
					@ -624,22 +628,6 @@ struct wlr_surface *wlr_surface_create(struct wl_resource *res,
 | 
				
			||||||
	return surface;
 | 
						return surface;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void wlr_surface_get_matrix(struct wlr_surface *surface,
 | 
					 | 
				
			||||||
		float (*matrix)[16],
 | 
					 | 
				
			||||||
		const float (*projection)[16],
 | 
					 | 
				
			||||||
		const float (*transform)[16]) {
 | 
					 | 
				
			||||||
	int width = surface->texture->width;
 | 
					 | 
				
			||||||
	int height = surface->texture->height;
 | 
					 | 
				
			||||||
	float scale[16];
 | 
					 | 
				
			||||||
	wlr_matrix_identity(matrix);
 | 
					 | 
				
			||||||
	if (transform) {
 | 
					 | 
				
			||||||
		wlr_matrix_mul(matrix, transform, matrix);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	wlr_matrix_scale(&scale, width, height, 1);
 | 
					 | 
				
			||||||
	wlr_matrix_mul(matrix, &scale, matrix);
 | 
					 | 
				
			||||||
	wlr_matrix_mul(projection, matrix, matrix);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool wlr_surface_has_buffer(struct wlr_surface *surface) {
 | 
					bool wlr_surface_has_buffer(struct wlr_surface *surface) {
 | 
				
			||||||
	return surface->texture && surface->texture->valid;
 | 
						return surface->texture && surface->texture->valid;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -15,8 +15,8 @@ WLROOTS_0_0_0 {
 | 
				
			||||||
        wlr_drm_get_connector_props;
 | 
					        wlr_drm_get_connector_props;
 | 
				
			||||||
        wlr_drm_get_crtc_props;
 | 
					        wlr_drm_get_crtc_props;
 | 
				
			||||||
        wlr_drm_get_plane_props;
 | 
					        wlr_drm_get_plane_props;
 | 
				
			||||||
        wlr_drm_get_prop;
 | 
					 | 
				
			||||||
        wlr_drm_get_prop_blob;
 | 
					        wlr_drm_get_prop_blob;
 | 
				
			||||||
 | 
					        wlr_drm_get_prop;
 | 
				
			||||||
        wlr_drm_plane_surfaces_init;
 | 
					        wlr_drm_plane_surfaces_init;
 | 
				
			||||||
        wlr_drm_renderer_finish;
 | 
					        wlr_drm_renderer_finish;
 | 
				
			||||||
        wlr_drm_renderer_init;
 | 
					        wlr_drm_renderer_init;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue