Merge branch 'master' into xdg-positioner
This commit is contained in:
		
						commit
						30b8fb5572
					
				|  | @ -173,7 +173,7 @@ struct wlr_backend *wlr_drm_backend_create(struct wl_display *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; | ||||
|  |  | |||
|  | @ -15,9 +15,9 @@ | |||
| #include <wayland-util.h> | ||||
| #include <wlr/backend/interface.h> | ||||
| #include <wlr/interfaces/wlr_output.h> | ||||
| #include <wlr/render.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 <xf86drm.h> | ||||
| #include <xf86drmMode.h> | ||||
|  | @ -582,13 +582,10 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output, | |||
| 			return false; | ||||
| 		} | ||||
| 
 | ||||
| 		// OpenGL will read the pixels out upside down,
 | ||||
| 		// so we need to flip the image vertically
 | ||||
| 		enum wl_output_transform transform = wlr_output_transform_compose( | ||||
| 			wlr_output_transform_invert(output->transform), | ||||
| 			WL_OUTPUT_TRANSFORM_FLIPPED_180); | ||||
| 		wlr_matrix_texture(plane->matrix, plane->surf.width, plane->surf.height, | ||||
| 			transform); | ||||
| 		enum wl_output_transform transform = | ||||
| 			wlr_output_transform_invert(output->transform); | ||||
| 		wlr_matrix_projection(plane->matrix, plane->surf.width, | ||||
| 			plane->surf.height, transform); | ||||
| 
 | ||||
| 		plane->wlr_tex = | ||||
| 			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, | ||||
| 			stride, width, height, buf); | ||||
| 
 | ||||
| 		glViewport(0, 0, plane->surf.width, plane->surf.height); | ||||
| 		glClearColor(0.0, 0.0, 0.0, 0.0); | ||||
| 		glClear(GL_COLOR_BUFFER_BIT); | ||||
| 		struct wlr_renderer *rend = plane->surf.renderer->wlr_rend; | ||||
| 		wlr_renderer_begin(rend, plane->surf.width, plane->surf.height); | ||||
| 		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_texture_get_matrix(plane->wlr_tex, &matrix, &plane->matrix, 0, 0); | ||||
| 		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_renderer_read_pixels(rend, WL_SHM_FORMAT_ARGB8888, bo_stride, | ||||
| 			plane->surf.width, plane->surf.height, 0, 0, 0, 0, bo_data); | ||||
| 
 | ||||
| 		wlr_drm_surface_swap_buffers(&plane->surf, NULL); | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,15 +1,15 @@ | |||
| #include <assert.h> | ||||
| #include <EGL/egl.h> | ||||
| #include <EGL/eglext.h> | ||||
| #include <gbm.h> | ||||
| #include <GLES2/gl2.h> | ||||
| #include <stdbool.h> | ||||
| #include <stdlib.h> | ||||
| #include <unistd.h> | ||||
| #include <wayland-util.h> | ||||
| #include <wlr/render.h> | ||||
| #include <wlr/render/egl.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 "backend/drm/drm.h" | ||||
| #include "glapi.h" | ||||
|  | @ -106,9 +106,6 @@ void wlr_drm_surface_finish(struct wlr_drm_surface *surf) { | |||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	eglMakeCurrent(surf->renderer->egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, | ||||
| 		EGL_NO_CONTEXT); | ||||
| 
 | ||||
| 	if (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); | ||||
| 	glViewport(0, 0, surf->width, surf->height); | ||||
| 	glClearColor(0.0, 0.0, 0.0, 1.0); | ||||
| 	glClear(GL_COLOR_BUFFER_BIT); | ||||
| 	struct wlr_renderer *renderer = surf->renderer->wlr_rend; | ||||
| 	wlr_renderer_begin(renderer, surf->width, surf->height); | ||||
| 	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); | ||||
| } | ||||
| 
 | ||||
|  | @ -177,12 +175,15 @@ static void free_eglimage(struct gbm_bo *bo, void *data) { | |||
| 	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); | ||||
| 	if (tex) { | ||||
| 		return tex->tex; | ||||
| 	} | ||||
| 
 | ||||
| 	// TODO: use wlr_texture_upload_dmabuf instead
 | ||||
| 
 | ||||
| 	tex = malloc(sizeof(*tex)); | ||||
| 	if (!tex) { | ||||
| 		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, | ||||
| 		EGL_LINUX_DMA_BUF_EXT, NULL, attribs); | ||||
| 	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(); | ||||
| 	} | ||||
| 
 | ||||
|  | @ -226,26 +227,23 @@ struct gbm_bo *wlr_drm_surface_mgpu_copy(struct wlr_drm_surface *dest, | |||
| 	wlr_drm_surface_make_current(dest, NULL); | ||||
| 
 | ||||
| 	struct wlr_texture *tex = get_tex_for_bo(dest->renderer, src); | ||||
| 	assert(tex); | ||||
| 
 | ||||
| 	static const float matrix[16] = { | ||||
| 		[0] = 2.0f, | ||||
| 		[3] = -1.0f, | ||||
| 		[5] = 2.0f, | ||||
| 		[7] = -1.0f, | ||||
| 		[10] = 1.0f, | ||||
| 		[15] = 1.0f, | ||||
| 	}; | ||||
| 	float mat[9]; | ||||
| 	wlr_matrix_projection(mat, 1, 1, WL_OUTPUT_TRANSFORM_FLIPPED_180); | ||||
| 
 | ||||
| 	glViewport(0, 0, dest->width, dest->height); | ||||
| 	glClearColor(0.0, 0.0, 0.0, 1.0); | ||||
| 	glClear(GL_COLOR_BUFFER_BIT); | ||||
| 	wlr_render_with_matrix(dest->renderer->wlr_rend, tex, &matrix, 1.0f); | ||||
| 	struct wlr_renderer *renderer = dest->renderer->wlr_rend; | ||||
| 	wlr_renderer_begin(renderer, dest->width, dest->height); | ||||
| 	wlr_renderer_clear(renderer, (float[]){ 0.0, 0.0, 0.0, 1.0 }); | ||||
| 	wlr_render_texture_with_matrix(renderer, tex, mat, 1.0f); | ||||
| 	wlr_renderer_end(renderer); | ||||
| 
 | ||||
| 	return wlr_drm_surface_swap_buffers(dest, NULL); | ||||
| } | ||||
| 
 | ||||
| bool wlr_drm_plane_surfaces_init(struct wlr_drm_plane *plane, struct wlr_drm_backend *drm, | ||||
| 		int32_t width, uint32_t height, uint32_t format) { | ||||
| bool wlr_drm_plane_surfaces_init(struct wlr_drm_plane *plane, | ||||
| 		struct wlr_drm_backend *drm, int32_t width, uint32_t height, | ||||
| 		uint32_t format) { | ||||
| 	if (!drm->parent) { | ||||
| 		return wlr_drm_surface_init(&plane->surf, &drm->renderer, width, height, | ||||
| 			format, GBM_BO_USE_SCANOUT); | ||||
|  |  | |||
|  | @ -1,8 +1,8 @@ | |||
| #include <EGL/egl.h> | ||||
| #include <EGL/eglext.h> | ||||
| #include <GLES2/gl2.h> | ||||
| #include <stdlib.h> | ||||
| #include <wlr/interfaces/wlr_output.h> | ||||
| #include <wlr/render/wlr_renderer.h> | ||||
| #include <wlr/util/log.h> | ||||
| #include "backend/headless.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); | ||||
| 	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 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", | ||||
| 		wl_list_length(&backend->outputs) + 1); | ||||
| 
 | ||||
| 	if (!eglMakeCurrent(output->backend->egl.display, | ||||
| 			output->egl_surface, output->egl_surface, | ||||
| 			output->backend->egl.context)) { | ||||
| 		wlr_log(L_ERROR, "eglMakeCurrent failed: %s", egl_error()); | ||||
| 	if (!wlr_egl_make_current(&output->backend->egl, output->egl_surface, | ||||
| 			NULL)) { | ||||
| 		goto error; | ||||
| 	} | ||||
| 
 | ||||
| 	glViewport(0, 0, wlr_output->width, wlr_output->height); | ||||
| 	glClearColor(1.0, 1.0, 1.0, 1.0); | ||||
| 	glClear(GL_COLOR_BUFFER_BIT); | ||||
| 	wlr_renderer_begin(backend->renderer, wlr_output->width, wlr_output->height); | ||||
| 	wlr_renderer_clear(backend->renderer, (float[]){ 1.0, 1.0, 1.0, 1.0 }); | ||||
| 	wlr_renderer_end(backend->renderer); | ||||
| 
 | ||||
| 	struct wl_event_loop *ev = wl_display_get_event_loop(backend->display); | ||||
| 	output->frame_timer = wl_event_loop_add_timer(ev, signal_frame, output); | ||||
|  |  | |||
|  | @ -1,5 +1,4 @@ | |||
| #include <assert.h> | ||||
| #include <GLES2/gl2.h> | ||||
| #include <stdint.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
|  | @ -9,6 +8,7 @@ | |||
| #include <unistd.h> | ||||
| #include <wayland-client.h> | ||||
| #include <wlr/interfaces/wlr_output.h> | ||||
| #include <wlr/render/wlr_renderer.h> | ||||
| #include <wlr/util/log.h> | ||||
| #include "backend/wayland.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, | ||||
| 			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); | ||||
| 
 | ||||
| 	// start rendering loop per callbacks by rendering first frame
 | ||||
| 	if (!eglMakeCurrent(output->backend->egl.display, | ||||
| 		output->egl_surface, output->egl_surface, | ||||
| 		output->backend->egl.context)) { | ||||
| 		wlr_log(L_ERROR, "eglMakeCurrent failed: %s", egl_error()); | ||||
| 	if (!wlr_egl_make_current(&output->backend->egl, output->egl_surface, | ||||
| 			NULL)) { | ||||
| 		goto error; | ||||
| 	} | ||||
| 
 | ||||
| 	glViewport(0, 0, wlr_output->width, wlr_output->height); | ||||
| 	glClearColor(1.0, 1.0, 1.0, 1.0); | ||||
| 	glClear(GL_COLOR_BUFFER_BIT); | ||||
| 	wlr_renderer_begin(backend->renderer, wlr_output->width, wlr_output->height); | ||||
| 	wlr_renderer_clear(backend->renderer, (float[]){ 1.0, 1.0, 1.0, 1.0 }); | ||||
| 	wlr_renderer_end(backend->renderer); | ||||
| 
 | ||||
| 	output->frame_callback = wl_surface_frame(output->surface); | ||||
| 	wl_callback_add_listener(output->frame_callback, &frame_listener, output); | ||||
| 
 | ||||
| 	if (!eglSwapBuffers(output->backend->egl.display, output->egl_surface)) { | ||||
| 		wlr_log(L_ERROR, "eglSwapBuffers failed: %s", egl_error()); | ||||
| 	if (!wlr_egl_swap_buffers(&output->backend->egl, output->egl_surface, | ||||
| 			NULL)) { | ||||
| 		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
 | ||||
| 		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; | ||||
| 	output->enter_serial = serial; | ||||
| 	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 *)dev->pointer; | ||||
| 	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; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -231,6 +236,14 @@ static struct wlr_input_device *allocate_device(struct wlr_wl_backend *backend, | |||
| 	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, | ||||
| 		enum wl_seat_capability caps) { | ||||
| 	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"); | ||||
| 			return; | ||||
| 		} | ||||
| 		wlr_wl_pointer->output_destroy_listener.notify = | ||||
| 			wlr_wl_pointer_handle_output_destroy; | ||||
| 
 | ||||
| 		struct wlr_input_device *wlr_device; | ||||
| 		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); | ||||
| 		free(pointer); | ||||
| 		break; | ||||
| 	} | ||||
| 	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); | ||||
| 
 | ||||
| 	if (x11->event_source) { | ||||
| 		wl_event_source_remove(x11->event_source); | ||||
| 	} | ||||
| 	wl_list_remove(&x11->display_destroy.link); | ||||
| 
 | ||||
| 	wl_event_source_remove(x11->frame_timer); | ||||
| 	wlr_egl_finish(&x11->egl); | ||||
| 
 | ||||
| 	if (x11->xcb_conn) { | ||||
| 		xcb_disconnect(x11->xcb_conn); | ||||
| 	} | ||||
| 	if (x11->xlib_conn) { | ||||
| 		XCloseDisplay(x11->xlib_conn); | ||||
| 	} | ||||
| 	free(x11); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -5,8 +5,8 @@ | |||
| #include <wayland-client.h> | ||||
| #include <wayland-egl.h> | ||||
| #include <wlr/render/egl.h> | ||||
| #include "xdg-shell-client-protocol.h" | ||||
| #include "idle-inhibit-unstable-v1-client-protocol.h" | ||||
| #include "xdg-shell-client-protocol.h" | ||||
| 
 | ||||
| #include <linux/input-event-codes.h> | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,11 +1,11 @@ | |||
| #include <getopt.h> | ||||
| #include <pthread.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <unistd.h> | ||||
| #include <getopt.h> | ||||
| #include <pthread.h> | ||||
| #include <wayland-client.h> | ||||
| #include <wayland-client-protocol.h> | ||||
| #include <wayland-client.h> | ||||
| #include <wlr/util/log.h> | ||||
| #include "idle-client-protocol.h" | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,30 +1,30 @@ | |||
| #define _POSIX_C_SOURCE 199309L | ||||
| #define _XOPEN_SOURCE 500 | ||||
| #include <assert.h> | ||||
| #include <GLES2/gl2.h> | ||||
| #include <math.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <time.h> | ||||
| #include <string.h> | ||||
| #include <time.h> | ||||
| #include <unistd.h> | ||||
| #include <math.h> | ||||
| #include <assert.h> | ||||
| #include <wayland-server.h> | ||||
| #include <wayland-server-protocol.h> | ||||
| #include <xkbcommon/xkbcommon.h> | ||||
| #include <GLES2/gl2.h> | ||||
| #include <wlr/render/matrix.h> | ||||
| #include <wlr/render/gles2.h> | ||||
| #include <wlr/render.h> | ||||
| #include <wayland-server.h> | ||||
| #include <wlr/backend.h> | ||||
| #include <wlr/backend/session.h> | ||||
| #include <wlr/types/wlr_keyboard.h> | ||||
| #include <wlr/types/wlr_output_layout.h> | ||||
| #include <wlr/xcursor.h> | ||||
| #include <wlr/render/gles2.h> | ||||
| #include <wlr/render/wlr_renderer.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 "support/shared.h" | ||||
| #include "support/config.h" | ||||
| #include <wlr/types/wlr_matrix.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/config.h" | ||||
| #include "support/shared.h" | ||||
| 
 | ||||
| struct sample_state; | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,29 +1,29 @@ | |||
| #define _POSIX_C_SOURCE 199309L | ||||
| #define _XOPEN_SOURCE 700 | ||||
| #include <GLES2/gl2.h> | ||||
| #include <limits.h> | ||||
| #include <math.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <time.h> | ||||
| #include <string.h> | ||||
| #include <strings.h> | ||||
| #include <time.h> | ||||
| #include <unistd.h> | ||||
| #include <limits.h> | ||||
| #include <wayland-server.h> | ||||
| #include <wayland-server-protocol.h> | ||||
| #include <xkbcommon/xkbcommon.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 <wayland-server.h> | ||||
| #include <wlr/backend.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.h> | ||||
| #include <wlr/types/wlr_keyboard.h> | ||||
| #include <math.h> | ||||
| #include "support/shared.h" | ||||
| #include "support/config.h" | ||||
| #include <wlr/util/log.h> | ||||
| #include <xkbcommon/xkbcommon.h> | ||||
| #include "support/cat.h" | ||||
| #include "support/config.h" | ||||
| #include "support/shared.h" | ||||
| 
 | ||||
| struct sample_state { | ||||
| 	struct example_config *config; | ||||
|  | @ -101,8 +101,8 @@ static void handle_output_frame(struct output_state *output, | |||
| 	struct wlr_output *wlr_output = output->output; | ||||
| 
 | ||||
| 	wlr_output_make_current(wlr_output, NULL); | ||||
| 	wlr_renderer_begin(sample->renderer, wlr_output); | ||||
| 	wlr_renderer_clear(sample->renderer, &(float[]){0.25f, 0.25f, 0.25f, 1}); | ||||
| 	wlr_renderer_begin(sample->renderer, wlr_output->width, wlr_output->height); | ||||
| 	wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1}); | ||||
| 
 | ||||
| 	animate_cat(sample, output->output); | ||||
| 
 | ||||
|  | @ -111,18 +111,14 @@ static void handle_output_frame(struct output_state *output, | |||
| 		.width = 128, .height = 128, | ||||
| 	}; | ||||
| 	if (wlr_output_layout_intersects(sample->layout, output->output, &box)) { | ||||
| 		float matrix[16]; | ||||
| 
 | ||||
| 		// transform global coordinates to local coordinates
 | ||||
| 		double local_x = sample->x_offs; | ||||
| 		double local_y = sample->y_offs; | ||||
| 		wlr_output_layout_output_coords(sample->layout, output->output, | ||||
| 			&local_x, &local_y); | ||||
| 
 | ||||
| 		wlr_texture_get_matrix(sample->cat_texture, &matrix, | ||||
| 			&wlr_output->transform_matrix, local_x, local_y); | ||||
| 		wlr_render_with_matrix(sample->renderer, | ||||
| 			sample->cat_texture, &matrix, 1.0f); | ||||
| 		wlr_render_texture(sample->renderer, sample->cat_texture, | ||||
| 			wlr_output->transform_matrix, local_x, local_y, 1.0f); | ||||
| 	} | ||||
| 
 | ||||
| 	wlr_renderer_end(sample->renderer); | ||||
|  |  | |||
|  | @ -1,30 +1,30 @@ | |||
| #define _POSIX_C_SOURCE 199309L | ||||
| #define _XOPEN_SOURCE 500 | ||||
| #include <assert.h> | ||||
| #include <GLES2/gl2.h> | ||||
| #include <math.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <time.h> | ||||
| #include <string.h> | ||||
| #include <time.h> | ||||
| #include <unistd.h> | ||||
| #include <math.h> | ||||
| #include <assert.h> | ||||
| #include <wayland-server.h> | ||||
| #include <wayland-server-protocol.h> | ||||
| #include <xkbcommon/xkbcommon.h> | ||||
| #include <GLES2/gl2.h> | ||||
| #include <wlr/render/matrix.h> | ||||
| #include <wlr/render/gles2.h> | ||||
| #include <wlr/render.h> | ||||
| #include <wayland-server.h> | ||||
| #include <wlr/backend.h> | ||||
| #include <wlr/backend/session.h> | ||||
| #include <wlr/types/wlr_keyboard.h> | ||||
| #include <wlr/types/wlr_output_layout.h> | ||||
| #include <wlr/xcursor.h> | ||||
| #include <wlr/render/gles2.h> | ||||
| #include <wlr/render/wlr_renderer.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 "support/shared.h" | ||||
| #include "support/config.h" | ||||
| #include <wlr/types/wlr_matrix.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/config.h" | ||||
| #include "support/shared.h" | ||||
| 
 | ||||
| struct sample_state { | ||||
| 	struct compositor_state *compositor; | ||||
|  |  | |||
|  | @ -1,23 +1,23 @@ | |||
| #define _POSIX_C_SOURCE 199309L | ||||
| #define _XOPEN_SOURCE 500 | ||||
| #include <GLES2/gl2.h> | ||||
| #include <math.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <time.h> | ||||
| #include <string.h> | ||||
| #include <strings.h> | ||||
| #include <time.h> | ||||
| #include <unistd.h> | ||||
| #include <wayland-server.h> | ||||
| #include <wayland-server-protocol.h> | ||||
| #include <xkbcommon/xkbcommon.h> | ||||
| #include <GLES2/gl2.h> | ||||
| #include <wlr/render/matrix.h> | ||||
| #include <wlr/render/gles2.h> | ||||
| #include <wlr/render.h> | ||||
| #include <wayland-server.h> | ||||
| #include <wlr/backend.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_matrix.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" | ||||
|  | @ -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_make_current(wlr_output, NULL); | ||||
| 	wlr_renderer_begin(sample->renderer, wlr_output); | ||||
| 	wlr_renderer_clear(sample->renderer, &(float[]){0.25f, 0.25f, 0.25f, 1}); | ||||
| 	wlr_renderer_begin(sample->renderer, wlr_output->width, wlr_output->height); | ||||
| 	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 x = -128 + (int)odata->x_offs; x < width; x += 128) { | ||||
| 			wlr_texture_get_matrix(sample->cat_texture, &matrix, | ||||
| 				&wlr_output->transform_matrix, x, y); | ||||
| 			wlr_render_with_matrix(sample->renderer, | ||||
| 					sample->cat_texture, &matrix, 1.0f); | ||||
| 			wlr_render_texture(sample->renderer, sample->cat_texture, | ||||
| 				wlr_output->transform_matrix, x, y, 1.0f); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -26,6 +26,7 @@ | |||
| #include <errno.h> | ||||
| #include <fcntl.h> | ||||
| #include <limits.h> | ||||
| #include <stdbool.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | @ -36,33 +37,22 @@ | |||
| #include <wayland-client.h> | ||||
| #include <wlr/util/log.h> | ||||
| #include "screenshooter-client-protocol.h" | ||||
| #include "util/os-compatibility.h" | ||||
| 
 | ||||
| static struct wl_shm *shm = NULL; | ||||
| static struct orbital_screenshooter *screenshooter = NULL; | ||||
| static struct wl_list output_list; | ||||
| int min_x, min_y, max_x, max_y; | ||||
| int buffer_copy_done; | ||||
| static bool buffer_copy_done; | ||||
| 
 | ||||
| struct screenshooter_output { | ||||
| 	struct wl_output *output; | ||||
| 	struct wl_buffer *buffer; | ||||
| 	int width, height, offset_x, offset_y; | ||||
| 	enum wl_output_transform transform; | ||||
| 	void *data; | ||||
| 	int width, height; | ||||
| 	struct wl_list link; | ||||
| }; | ||||
| 
 | ||||
| static void output_handle_geometry(void *data, struct wl_output *wl_output, | ||||
| 		int x, int y, int physical_width, int physical_height, int subpixel, | ||||
| 		const char *make, const char *model, int transform) { | ||||
| 	struct screenshooter_output *output = wl_output_get_user_data(wl_output); | ||||
| 
 | ||||
| 	if (wl_output == output->output) { | ||||
| 		output->offset_x = x; | ||||
| 		output->offset_y = y; | ||||
| 		output->transform = transform; | ||||
| 	} | ||||
| 	// No-op
 | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
| 	buffer_copy_done = 1; | ||||
| 	buffer_copy_done = true; | ||||
| } | ||||
| 
 | ||||
| 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, | ||||
| 		uint32_t name) { | ||||
| 	// Unimplemented
 | ||||
| 	// Who cares?
 | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
| 	char template[] = "/tmp/wlroots-shared-XXXXXX"; | ||||
| 	int fd, ret; | ||||
| 
 | ||||
| 	fd = mkstemp(template); | ||||
| 	int fd = mkstemp(template); | ||||
| 	if (fd < 0) { | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	while ((ret = ftruncate(fd, size)) == EINTR) {} | ||||
| 	int ret; | ||||
| 	while ((ret = ftruncate(fd, size)) == EINTR) { | ||||
| 		// No-op
 | ||||
| 	} | ||||
| 	if (ret < 0) { | ||||
| 		close(fd); | ||||
| 		return -1; | ||||
|  | @ -140,7 +131,6 @@ static int backingfile(off_t size) { | |||
| 	return fd; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static struct wl_buffer *create_shm_buffer(int width, int height, | ||||
| 		void **data_out) { | ||||
| 	int stride = width * 4; | ||||
|  | @ -170,91 +160,8 @@ static struct wl_buffer *create_shm_buffer(int width, int height, | |||
| 	return buffer; | ||||
| } | ||||
| 
 | ||||
| static void write_image(const char *filename, int width, int height) { | ||||
| 	int buffer_stride = width * 4; | ||||
| 
 | ||||
| 	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); | ||||
| 	} | ||||
| 
 | ||||
| static void write_image(const char *filename, int width, int height, | ||||
| 		void *data) { | ||||
| 	char size[10 + 1 + 10 + 2 + 1]; // int32_t are max 10 digits
 | ||||
| 	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); | ||||
| 	} else if (child != 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)); | ||||
| 			exit(EXIT_FAILURE); | ||||
| 		} | ||||
| 		close(fd[1]); | ||||
| 		free(data); | ||||
| 		waitpid(child, NULL, 0); | ||||
| 	} else { | ||||
| 		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[]) { | ||||
| 	wlr_log_init(L_DEBUG, NULL); | ||||
| 
 | ||||
| 	struct wl_display * display = wl_display_connect(NULL); | ||||
| 	if (display == NULL) { | ||||
| 		fprintf(stderr, "failed to create display: %m\n"); | ||||
|  | @ -342,27 +219,31 @@ int main(int argc, char *argv[]) { | |||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	int width, height; | ||||
| 	if (set_buffer_size(&width, &height)) { | ||||
| 		fprintf(stderr, "cannot set buffer size\n"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	int i = 0; | ||||
| 	struct screenshooter_output *output; | ||||
| 	wl_list_for_each(output, &output_list, link) { | ||||
| 		output->buffer = create_shm_buffer(output->width, output->height, &output->data); | ||||
| 		if (output->buffer == NULL) { | ||||
| 		void *data = NULL; | ||||
| 		struct wl_buffer *buffer = | ||||
| 			create_shm_buffer(output->width, output->height, &data); | ||||
| 		if (buffer == NULL) { | ||||
| 			return -1; | ||||
| 		} | ||||
| 		struct orbital_screenshot *screenshot = orbital_screenshooter_shoot( | ||||
| 			screenshooter, output->output, output->buffer); | ||||
| 		orbital_screenshot_add_listener(screenshot, &screenshot_listener, screenshot); | ||||
| 		buffer_copy_done = 0; | ||||
| 			screenshooter, output->output, buffer); | ||||
| 		orbital_screenshot_add_listener(screenshot, &screenshot_listener, | ||||
| 			screenshot); | ||||
| 		buffer_copy_done = false; | ||||
| 		while (!buffer_copy_done) { | ||||
| 			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; | ||||
| } | ||||
|  |  | |||
|  | @ -1,11 +1,11 @@ | |||
| #define _POSIX_C_SOURCE 199309L | ||||
| #include <string.h> | ||||
| #include <GLES2/gl2.h> | ||||
| #include <inttypes.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <time.h> | ||||
| #include <inttypes.h> | ||||
| #include <wayland-server.h> | ||||
| #include <GLES2/gl2.h> | ||||
| #include <wlr/backend.h> | ||||
| #include <wlr/backend/session.h> | ||||
| #include <wlr/types/wlr_output.h> | ||||
|  |  | |||
|  | @ -1,27 +1,27 @@ | |||
| #define _POSIX_C_SOURCE 199309L | ||||
| #define _XOPEN_SOURCE 500 | ||||
| #include <GLES2/gl2.h> | ||||
| #include <math.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <time.h> | ||||
| #include <string.h> | ||||
| #include <time.h> | ||||
| #include <unistd.h> | ||||
| #include <wayland-server.h> | ||||
| #include <wayland-server-protocol.h> | ||||
| #include <xkbcommon/xkbcommon.h> | ||||
| #include <GLES2/gl2.h> | ||||
| #include <wlr/render/matrix.h> | ||||
| #include <wlr/render/gles2.h> | ||||
| #include <wlr/render.h> | ||||
| #include <wayland-server.h> | ||||
| #include <wlr/backend.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_matrix.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_tool.h> | ||||
| #include <wlr/util/log.h> | ||||
| #include <math.h> | ||||
| #include "support/shared.h" | ||||
| #include <xkbcommon/xkbcommon.h> | ||||
| #include "support/cat.h" | ||||
| #include "support/shared.h" | ||||
| 
 | ||||
| struct sample_state { | ||||
| 	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_make_current(wlr_output, NULL); | ||||
| 	wlr_renderer_begin(sample->renderer, wlr_output); | ||||
| 	wlr_renderer_clear(sample->renderer, &(float[]){0.25f, 0.25f, 0.25f, 1}); | ||||
| 	wlr_renderer_begin(sample->renderer, wlr_output->width, wlr_output->height); | ||||
| 	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 tool_color[4] = { distance, distance, distance, 1 }; | ||||
| 	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, | ||||
| 		.width = pad_width, .height = pad_height, | ||||
| 	}; | ||||
| 	wlr_matrix_project_box(&matrix, &box, 0, 0, | ||||
| 			&wlr_output->transform_matrix); | ||||
| 	wlr_render_colored_quad(sample->renderer, &sample->pad_color, &matrix); | ||||
| 	wlr_matrix_project_box(matrix, &box, 0, 0, wlr_output->transform_matrix); | ||||
| 	wlr_render_colored_quad(sample->renderer, sample->pad_color, matrix); | ||||
| 
 | ||||
| 	if (sample->proximity) { | ||||
| 		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), | ||||
| 			.height = 16 * (sample->pressure + 1), | ||||
| 		}; | ||||
| 		wlr_matrix_project_box(&matrix, &box, 0, sample->ring, | ||||
| 				&wlr_output->transform_matrix); | ||||
| 		wlr_render_colored_quad(sample->renderer, &tool_color, &matrix); | ||||
| 		wlr_matrix_project_box(matrix, &box, 0, sample->ring, | ||||
| 			wlr_output->transform_matrix); | ||||
| 		wlr_render_colored_quad(sample->renderer, tool_color, matrix); | ||||
| 		box.x += sample->x_tilt; | ||||
| 		box.y += sample->y_tilt; | ||||
| 		box.width /= 2; | ||||
| 		box.height /= 2; | ||||
| 		wlr_matrix_project_box(&matrix, &box, 0, 0, | ||||
| 				&wlr_output->transform_matrix); | ||||
| 		wlr_render_colored_quad(sample->renderer, &tool_color, &matrix); | ||||
| 		wlr_matrix_project_box(matrix, &box, 0, 0, | ||||
| 			wlr_output->transform_matrix); | ||||
| 		wlr_render_colored_quad(sample->renderer, tool_color, matrix); | ||||
| 	} | ||||
| 
 | ||||
| 	wlr_renderer_end(sample->renderer); | ||||
|  |  | |||
|  | @ -1,25 +1,25 @@ | |||
| #define _POSIX_C_SOURCE 199309L | ||||
| #define _XOPEN_SOURCE 500 | ||||
| #include <GLES2/gl2.h> | ||||
| #include <math.h> | ||||
| #include <stdint.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <time.h> | ||||
| #include <string.h> | ||||
| #include <time.h> | ||||
| #include <unistd.h> | ||||
| #include <stdint.h> | ||||
| #include <math.h> | ||||
| #include <wayland-server.h> | ||||
| #include <wayland-server-protocol.h> | ||||
| #include <xkbcommon/xkbcommon.h> | ||||
| #include <GLES2/gl2.h> | ||||
| #include <wlr/render/matrix.h> | ||||
| #include <wlr/render/gles2.h> | ||||
| #include <wlr/render.h> | ||||
| #include <wayland-server.h> | ||||
| #include <wlr/backend.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_matrix.h> | ||||
| #include <wlr/util/log.h> | ||||
| #include "support/shared.h" | ||||
| #include <xkbcommon/xkbcommon.h> | ||||
| #include "support/cat.h" | ||||
| #include "support/shared.h" | ||||
| 
 | ||||
| struct sample_state { | ||||
| 	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_make_current(wlr_output, NULL); | ||||
| 	wlr_renderer_begin(sample->renderer, wlr_output); | ||||
| 	wlr_renderer_clear(sample->renderer, &(float[]){0.25f, 0.25f, 0.25f, 1}); | ||||
| 	wlr_renderer_begin(sample->renderer, wlr_output->width, wlr_output->height); | ||||
| 	wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1}); | ||||
| 
 | ||||
| 	float matrix[16]; | ||||
| 	struct touch_point *p; | ||||
| 	wl_list_for_each(p, &sample->touch_points, link) { | ||||
| 		wlr_texture_get_matrix(sample->cat_texture, &matrix, | ||||
| 			&wlr_output->transform_matrix, | ||||
| 			(int)(p->x * width) - sample->cat_texture->width / 2, | ||||
| 			(int)(p->y * height) - sample->cat_texture->height / 2); | ||||
| 		wlr_render_with_matrix(sample->renderer, | ||||
| 			sample->cat_texture, &matrix, 1.0f); | ||||
| 		int x = (int)(p->x * width) - sample->cat_texture->width / 2; | ||||
| 		int y = (int)(p->y * height) - sample->cat_texture->height / 2; | ||||
| 		wlr_render_texture(sample->renderer, sample->cat_texture, | ||||
| 			wlr_output->transform_matrix, x, y, 1.0f); | ||||
| 	} | ||||
| 
 | ||||
| 	wlr_renderer_end(sample->renderer); | ||||
|  |  | |||
|  | @ -26,7 +26,7 @@ struct wlr_drm_plane { | |||
| 	struct wlr_drm_surface mgpu_surf; | ||||
| 
 | ||||
| 	// Only used by cursor
 | ||||
| 	float matrix[16]; | ||||
| 	float matrix[9]; | ||||
| 	struct wlr_texture *wlr_tex; | ||||
| 	struct gbm_bo *cursor_bo; | ||||
| 	bool cursor_enabled; | ||||
|  |  | |||
|  | @ -5,7 +5,7 @@ | |||
| #include <gbm.h> | ||||
| #include <stdbool.h> | ||||
| #include <stdint.h> | ||||
| #include <wlr/render.h> | ||||
| #include <wlr/render/wlr_renderer.h> | ||||
| 
 | ||||
| struct wlr_drm_backend; | ||||
| struct wlr_drm_plane; | ||||
|  |  | |||
|  | @ -7,8 +7,8 @@ | |||
| #include <wayland-server.h> | ||||
| #include <wayland-util.h> | ||||
| #include <wlr/backend/wayland.h> | ||||
| #include <wlr/render.h> | ||||
| #include <wlr/render/egl.h> | ||||
| #include <wlr/render/wlr_renderer.h> | ||||
| #include <wlr/types/wlr_box.h> | ||||
| 
 | ||||
| struct wlr_wl_backend { | ||||
|  | @ -71,6 +71,7 @@ struct wlr_wl_pointer { | |||
| 	struct wlr_pointer wlr_pointer; | ||||
| 	enum wlr_axis_source axis_source; | ||||
| 	struct wlr_wl_backend_output *current_output; | ||||
| 	struct wl_listener output_destroy_listener; | ||||
| }; | ||||
| 
 | ||||
| void wlr_wl_registry_poll(struct wlr_wl_backend *backend); | ||||
|  |  | |||
|  | @ -9,24 +9,33 @@ | |||
| #include <stdint.h> | ||||
| #include <string.h> | ||||
| #include <wlr/backend.h> | ||||
| #include <wlr/render.h> | ||||
| #include <wlr/render/egl.h> | ||||
| #include <wlr/render/interface.h> | ||||
| #include <wlr/render/wlr_renderer.h> | ||||
| #include <wlr/render/wlr_texture.h> | ||||
| #include <wlr/util/log.h> | ||||
| 
 | ||||
| extern PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES; | ||||
| 
 | ||||
| struct pixel_format { | ||||
| struct gles2_pixel_format { | ||||
| 	uint32_t wl_format; | ||||
| 	GLint gl_format, gl_type; | ||||
| 	int depth, bpp; | ||||
| 	GLuint *shader; | ||||
| 	bool has_alpha; | ||||
| }; | ||||
| 
 | ||||
| struct wlr_gles2_renderer { | ||||
| 	struct wlr_renderer wlr_renderer; | ||||
| 
 | ||||
| 	struct wlr_egl *egl; | ||||
| 
 | ||||
| 	struct { | ||||
| 		GLuint quad; | ||||
| 		GLuint ellipse; | ||||
| 		GLuint tex_rgba; | ||||
| 		GLuint tex_rgbx; | ||||
| 		GLuint tex_ext; | ||||
| 	} shaders; | ||||
| }; | ||||
| 
 | ||||
| struct wlr_gles2_texture { | ||||
|  | @ -34,36 +43,20 @@ struct wlr_gles2_texture { | |||
| 
 | ||||
| 	struct wlr_egl *egl; | ||||
| 	GLuint tex_id; | ||||
| 	const struct pixel_format *pixel_format; | ||||
| 	const struct gles2_pixel_format *pixel_format; | ||||
| 	EGLImageKHR image; | ||||
| 	GLenum target; | ||||
| }; | ||||
| 
 | ||||
| struct shaders { | ||||
| 	bool initialized; | ||||
| 	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); | ||||
| const struct gles2_pixel_format *gles2_format_from_wl(enum wl_shm_format fmt); | ||||
| const enum wl_shm_format *gles2_formats(size_t *len); | ||||
| 
 | ||||
| struct wlr_texture *gles2_texture_create(); | ||||
| struct wlr_gles2_texture *gles2_get_texture(struct wlr_texture *wlr_texture); | ||||
| 
 | ||||
| extern const GLchar quad_vertex_src[]; | ||||
| extern const GLchar quad_fragment_src[]; | ||||
| extern const GLchar ellipse_fragment_src[]; | ||||
| extern const GLchar vertex_src[]; | ||||
| 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() | ||||
| void gles2_push_marker(const char *file, const char *func); | ||||
| void gles2_pop_marker(void); | ||||
| #define GLES2_DEBUG_PUSH gles2_push_marker(wlr_strip_path(__FILE__), __func__) | ||||
| #define GLES2_DEBUG_POP gles2_pop_marker() | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ | |||
| #include <wlr/types/wlr_compositor.h> | ||||
| #include <wlr/types/wlr_gamma_control.h> | ||||
| #include <wlr/types/wlr_idle.h> | ||||
| #include <wlr/types/wlr_linux_dmabuf.h> | ||||
| #include <wlr/types/wlr_list.h> | ||||
| #include <wlr/types/wlr_output_layout.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_idle *idle; | ||||
| 	struct wlr_idle_inhibit_manager_v1 *idle_inhibit; | ||||
| 	struct wlr_linux_dmabuf *linux_dmabuf; | ||||
| 
 | ||||
| 	struct wl_listener new_output; | ||||
| 	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, | ||||
| 	double ly, struct wlr_surface **surface, double *sx, double *sy); | ||||
| 
 | ||||
| void view_init(struct roots_view *view, struct roots_desktop *desktop); | ||||
| void view_finish(struct roots_view *view); | ||||
| struct roots_view *view_create(struct roots_desktop *desktop); | ||||
| void view_destroy(struct roots_view *view); | ||||
| void view_activate(struct roots_view *view, bool activate); | ||||
| void view_apply_damage(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_size(struct roots_view *view, uint32_t width, uint32_t height); | ||||
| 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_surface(struct wl_listener *listener, void *data); | ||||
|  |  | |||
|  | @ -39,6 +39,7 @@ struct roots_seat_view { | |||
| 
 | ||||
| 	struct wl_list link; // roots_seat::views
 | ||||
| 
 | ||||
| 	struct wl_listener view_unmap; | ||||
| 	struct wl_listener view_destroy; | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -5,7 +5,7 @@ | |||
| #include <wlr/backend.h> | ||||
| #include <wlr/backend/session.h> | ||||
| #include <wlr/config.h> | ||||
| #include <wlr/render.h> | ||||
| #include <wlr/render/wlr_renderer.h> | ||||
| #include <wlr/types/wlr_data_device.h> | ||||
| #ifdef WLR_HAS_XWAYLAND | ||||
| #include <wlr/xwayland.h> | ||||
|  |  | |||
|  | @ -27,6 +27,8 @@ struct roots_xdg_surface_v6 { | |||
| 
 | ||||
| 	struct wl_listener destroy; | ||||
| 	struct wl_listener new_popup; | ||||
| 	struct wl_listener map; | ||||
| 	struct wl_listener unmap; | ||||
| 	struct wl_listener request_move; | ||||
| 	struct wl_listener request_resize; | ||||
| 	struct wl_listener request_maximize; | ||||
|  | @ -42,6 +44,8 @@ struct roots_xdg_surface { | |||
| 
 | ||||
| 	struct wl_listener destroy; | ||||
| 	struct wl_listener new_popup; | ||||
| 	struct wl_listener map; | ||||
| 	struct wl_listener unmap; | ||||
| 	struct wl_listener request_move; | ||||
| 	struct wl_listener request_resize; | ||||
| 	struct wl_listener request_maximize; | ||||
|  | @ -128,6 +132,7 @@ struct roots_view { | |||
| 	struct wl_listener new_subsurface; | ||||
| 
 | ||||
| 	struct { | ||||
| 		struct wl_signal unmap; | ||||
| 		struct wl_signal destroy; | ||||
| 	} events; | ||||
| 
 | ||||
|  | @ -140,6 +145,7 @@ struct roots_view { | |||
| 	void (*maximize)(struct roots_view *view, bool maximized); | ||||
| 	void (*set_fullscreen)(struct roots_view *view, bool fullscreen); | ||||
| 	void (*close)(struct roots_view *view); | ||||
| 	void (*destroy)(struct roots_view *view); | ||||
| }; | ||||
| 
 | ||||
| struct roots_view_child { | ||||
|  | @ -181,7 +187,6 @@ struct roots_xdg_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_activate(struct roots_view *view, bool active); | ||||
| void view_move(struct roots_view *view, double x, double y); | ||||
|  |  | |||
|  | @ -11,16 +11,39 @@ struct wlr_backend { | |||
| 	const struct wlr_backend_impl *impl; | ||||
| 
 | ||||
| 	struct { | ||||
| 		/** Raised when destroyed, passed the wlr_backend reference */ | ||||
| 		struct wl_signal destroy; | ||||
| 		/** Raised when new inputs are added, passed the wlr_input_device */ | ||||
| 		struct wl_signal new_input; | ||||
| 		/** Raised when new outputs are added, passed the wlr_output */ | ||||
| 		struct wl_signal new_output; | ||||
| 	} 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); | ||||
| /**
 | ||||
|  * 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); | ||||
| /**
 | ||||
|  * 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); | ||||
| /**
 | ||||
|  * Obtains the wlr_egl reference this backend is using. | ||||
|  */ | ||||
| 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); | ||||
| 
 | ||||
| uint32_t usec_to_msec(uint64_t usec); | ||||
|  |  | |||
|  | @ -6,6 +6,13 @@ | |||
| #include <wlr/backend/session.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_session *session, int gpu_fd, struct wlr_backend *parent); | ||||
| 
 | ||||
|  |  | |||
|  | @ -5,9 +5,23 @@ | |||
| #include <wlr/types/wlr_input_device.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); | ||||
| /**
 | ||||
|  * 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, | ||||
| 	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_backend *backend, enum wlr_input_device_type type); | ||||
| 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); | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * 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, | ||||
| 		const struct wlr_backend_impl *impl); | ||||
| 
 | ||||
|  |  | |||
|  | @ -9,7 +9,9 @@ | |||
| 
 | ||||
| struct wlr_backend *wlr_libinput_backend_create(struct wl_display *display, | ||||
| 		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_input_device_is_libinput(struct wlr_input_device *device); | ||||
|  |  | |||
|  | @ -4,11 +4,21 @@ | |||
| #include <wlr/backend.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); | ||||
| /**
 | ||||
|  * 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, | ||||
| 	struct wlr_backend *backend); | ||||
| 
 | ||||
| void wlr_multi_backend_remove(struct wlr_backend *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); | ||||
| 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 <stdbool.h> | ||||
| #include <wayland-server.h> | ||||
| #include <wlr/types/wlr_linux_dmabuf.h> | ||||
| 
 | ||||
| struct wlr_egl { | ||||
| 	EGLDisplay display; | ||||
|  | @ -18,6 +19,8 @@ struct wlr_egl { | |||
| 	struct { | ||||
| 		bool buffer_age; | ||||
| 		bool swap_buffers_with_damage; | ||||
| 		bool dmabuf_import; | ||||
| 		bool dmabuf_import_modifiers; | ||||
| 	} egl_exts; | ||||
| 
 | ||||
| 	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, | ||||
| 		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. | ||||
|  */ | ||||
| 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, | ||||
| 	int *buffer_age); | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| #define WLR_RENDER_GLES2_H | ||||
| 
 | ||||
| #include <wlr/backend.h> | ||||
| #include <wlr/render.h> | ||||
| #include <wlr/render/wlr_renderer.h> | ||||
| 
 | ||||
| struct wlr_egl; | ||||
| struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_backend *backend); | ||||
|  |  | |||
|  | @ -5,28 +5,32 @@ | |||
| #include <EGL/eglext.h> | ||||
| #include <stdbool.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_linux_dmabuf.h> | ||||
| #include <wlr/types/wlr_output.h> | ||||
| 
 | ||||
| struct wlr_renderer_impl; | ||||
| 
 | ||||
| struct wlr_renderer { | ||||
| 	struct wlr_renderer_impl *impl; | ||||
| 	const struct wlr_renderer_impl *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 (*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); | ||||
| 	struct wlr_texture *(*texture_create)(struct wlr_renderer *renderer); | ||||
| 	bool (*render_with_matrix)(struct wlr_renderer *renderer, | ||||
| 		struct wlr_texture *texture, const float (*matrix)[16], float alpha); | ||||
| 	bool (*render_texture_with_matrix)(struct wlr_renderer *renderer, | ||||
| 		struct wlr_texture *texture, const float matrix[static 9], | ||||
| 		float alpha); | ||||
| 	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, | ||||
| 		const float (*color)[4], const float (*matrix)[16]); | ||||
| 		const float color[static 4], const float matrix[static 9]); | ||||
| 	const enum wl_shm_format *(*formats)( | ||||
| 		struct wlr_renderer *renderer, size_t *len); | ||||
| 	bool (*buffer_is_drm)(struct wlr_renderer *renderer, | ||||
|  | @ -41,7 +45,7 @@ struct wlr_renderer_impl { | |||
| }; | ||||
| 
 | ||||
| void wlr_renderer_init(struct wlr_renderer *renderer, | ||||
| 		struct wlr_renderer_impl *impl); | ||||
| 		const struct wlr_renderer_impl *impl); | ||||
| 
 | ||||
| struct wlr_texture_impl { | ||||
| 	bool (*upload_pixels)(struct wlr_texture *texture, | ||||
|  | @ -58,17 +62,15 @@ struct wlr_texture_impl { | |||
| 		struct wl_resource *drm_buf); | ||||
| 	bool (*upload_eglimage)(struct wlr_texture *texture, EGLImageKHR image, | ||||
| 		uint32_t width, uint32_t height); | ||||
| 	void (*get_matrix)(struct wlr_texture *state, | ||||
| 		float (*matrix)[16], const float (*projection)[16], int x, int y); | ||||
| 	bool (*upload_dmabuf)(struct wlr_texture *texture, | ||||
| 		struct wl_resource *dmabuf_resource); | ||||
| 	void (*get_buffer_size)(struct wlr_texture *texture, | ||||
| 		struct wl_resource *resource, int *width, int *height); | ||||
| 	void (*bind)(struct wlr_texture *texture); | ||||
| 	void (*destroy)(struct wlr_texture *texture); | ||||
| }; | ||||
| 
 | ||||
| void wlr_texture_init(struct wlr_texture *texture, | ||||
| 		struct wlr_texture_impl *impl); | ||||
| void wlr_texture_bind(struct wlr_texture *texture); | ||||
| 	const struct wlr_texture_impl *impl); | ||||
| void wlr_texture_get_buffer_size(struct wlr_texture *texture, | ||||
| 	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 | ||||
|  | @ -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 | ||||
|  | @ -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 | ||||
| 
 | ||||
| #include <wayland-server.h> | ||||
| #include <wlr/render.h> | ||||
| #include <wlr/render/wlr_renderer.h> | ||||
| 
 | ||||
| struct wlr_compositor { | ||||
| 	struct wl_global *wl_global; | ||||
|  |  | |||
|  | @ -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 | ||||
|  | @ -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
 | ||||
| 	pixman_region32_t damage; | ||||
| 	bool frame_pending; | ||||
| 	float transform_matrix[16]; | ||||
| 	float transform_matrix[9]; | ||||
| 
 | ||||
| 	struct { | ||||
| 		struct wl_signal frame; | ||||
|  |  | |||
|  | @ -70,8 +70,8 @@ struct wlr_surface { | |||
| 	struct wlr_surface_state *current, *pending; | ||||
| 	const char *role; // the lifetime-bound role or null
 | ||||
| 
 | ||||
| 	float buffer_to_surface_matrix[16]; | ||||
| 	float surface_to_buffer_matrix[16]; | ||||
| 	float buffer_to_surface_matrix[9]; | ||||
| 	float surface_to_buffer_matrix[9]; | ||||
| 
 | ||||
| 	struct { | ||||
| 		struct wl_signal commit; | ||||
|  | @ -99,19 +99,6 @@ struct wlr_surface { | |||
| struct wlr_renderer; | ||||
| struct wlr_surface *wlr_surface_create(struct wl_resource *res, | ||||
| 		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 | ||||
|  |  | |||
|  | @ -53,6 +53,7 @@ struct wlr_xdg_popup_grab { | |||
| 	struct wlr_seat *seat; | ||||
| 	struct wl_list popups; | ||||
| 	struct wl_list link; // wlr_xdg_shell::popup_grabs
 | ||||
| 	struct wl_listener seat_destroy; | ||||
| }; | ||||
| 
 | ||||
| enum wlr_xdg_surface_role { | ||||
|  | @ -62,19 +63,10 @@ enum wlr_xdg_surface_role { | |||
| }; | ||||
| 
 | ||||
| struct wlr_xdg_toplevel_state { | ||||
| 	bool maximized; | ||||
| 	bool fullscreen; | ||||
| 	bool resizing; | ||||
| 	bool activated; | ||||
| 
 | ||||
| 	uint32_t width; | ||||
| 	uint32_t height; | ||||
| 
 | ||||
| 	uint32_t max_width; | ||||
| 	uint32_t max_height; | ||||
| 
 | ||||
| 	uint32_t min_width; | ||||
| 	uint32_t min_height; | ||||
| 	bool maximized, fullscreen, resizing, activated; | ||||
| 	uint32_t width, height; | ||||
| 	uint32_t max_width, max_height; | ||||
| 	uint32_t min_width, min_height; | ||||
| }; | ||||
| 
 | ||||
| struct wlr_xdg_toplevel { | ||||
|  | @ -90,7 +82,8 @@ struct wlr_xdg_toplevel { | |||
| struct wlr_xdg_surface_configure { | ||||
| 	struct wl_list link; // wlr_xdg_surface::configure_list
 | ||||
| 	uint32_t serial; | ||||
| 	struct wlr_xdg_toplevel_state state; | ||||
| 
 | ||||
| 	struct wlr_xdg_toplevel_state *toplevel_state; | ||||
| }; | ||||
| 
 | ||||
| struct wlr_xdg_surface { | ||||
|  | @ -101,14 +94,13 @@ struct wlr_xdg_surface { | |||
| 	enum wlr_xdg_surface_role role; | ||||
| 
 | ||||
| 	union { | ||||
| 		struct wlr_xdg_toplevel *toplevel_state; | ||||
| 		struct wlr_xdg_popup *popup_state; | ||||
| 		struct wlr_xdg_toplevel *toplevel; | ||||
| 		struct wlr_xdg_popup *popup; | ||||
| 	}; | ||||
| 
 | ||||
| 	struct wl_list popups; // wlr_xdg_popup::link
 | ||||
| 
 | ||||
| 	bool configured; | ||||
| 	bool added; | ||||
| 	bool added, configured, mapped; | ||||
| 	uint32_t configure_serial; | ||||
| 	struct wl_event_source *configure_idle; | ||||
| 	uint32_t configure_next_serial; | ||||
|  | @ -118,8 +110,8 @@ struct wlr_xdg_surface { | |||
| 	char *app_id; | ||||
| 
 | ||||
| 	bool has_next_geometry; | ||||
| 	struct wlr_box *next_geometry; | ||||
| 	struct wlr_box *geometry; | ||||
| 	struct wlr_box next_geometry; | ||||
| 	struct wlr_box geometry; | ||||
| 
 | ||||
| 	struct wl_listener surface_destroy_listener; | ||||
| 
 | ||||
|  | @ -127,6 +119,8 @@ struct wlr_xdg_surface { | |||
| 		struct wl_signal destroy; | ||||
| 		struct wl_signal ping_timeout; | ||||
| 		struct wl_signal new_popup; | ||||
| 		struct wl_signal map; | ||||
| 		struct wl_signal unmap; | ||||
| 
 | ||||
| 		struct wl_signal request_maximize; | ||||
| 		struct wl_signal request_fullscreen; | ||||
|  |  | |||
|  | @ -113,6 +113,7 @@ struct wlr_xdg_popup_grab_v6 { | |||
| 	struct wlr_seat *seat; | ||||
| 	struct wl_list popups; | ||||
| 	struct wl_list link; // wlr_xdg_shell_v6::popup_grabs
 | ||||
| 	struct wl_listener seat_destroy; | ||||
| }; | ||||
| 
 | ||||
| enum wlr_xdg_surface_v6_role { | ||||
|  | @ -122,19 +123,10 @@ enum wlr_xdg_surface_v6_role { | |||
| }; | ||||
| 
 | ||||
| struct wlr_xdg_toplevel_v6_state { | ||||
| 	bool maximized; | ||||
| 	bool fullscreen; | ||||
| 	bool resizing; | ||||
| 	bool activated; | ||||
| 
 | ||||
| 	uint32_t width; | ||||
| 	uint32_t height; | ||||
| 
 | ||||
| 	uint32_t max_width; | ||||
| 	uint32_t max_height; | ||||
| 
 | ||||
| 	uint32_t min_width; | ||||
| 	uint32_t min_height; | ||||
| 	bool maximized, fullscreen, resizing, activated; | ||||
| 	uint32_t width, height; | ||||
| 	uint32_t max_width, max_height; | ||||
| 	uint32_t min_width, min_height; | ||||
| }; | ||||
| 
 | ||||
| struct wlr_xdg_toplevel_v6 { | ||||
|  | @ -150,7 +142,8 @@ struct wlr_xdg_toplevel_v6 { | |||
| struct wlr_xdg_surface_v6_configure { | ||||
| 	struct wl_list link; // wlr_xdg_surface_v6::configure_list
 | ||||
| 	uint32_t serial; | ||||
| 	struct wlr_xdg_toplevel_v6_state state; | ||||
| 
 | ||||
| 	struct wlr_xdg_toplevel_v6_state *toplevel_state; | ||||
| }; | ||||
| 
 | ||||
| struct wlr_xdg_surface_v6 { | ||||
|  | @ -161,14 +154,13 @@ struct wlr_xdg_surface_v6 { | |||
| 	enum wlr_xdg_surface_v6_role role; | ||||
| 
 | ||||
| 	union { | ||||
| 		struct wlr_xdg_toplevel_v6 *toplevel_state; | ||||
| 		struct wlr_xdg_popup_v6 *popup_state; | ||||
| 		struct wlr_xdg_toplevel_v6 *toplevel; | ||||
| 		struct wlr_xdg_popup_v6 *popup; | ||||
| 	}; | ||||
| 
 | ||||
| 	struct wl_list popups; // wlr_xdg_popup_v6::link
 | ||||
| 
 | ||||
| 	bool configured; | ||||
| 	bool added; | ||||
| 	bool added, configured, mapped; | ||||
| 	uint32_t configure_serial; | ||||
| 	struct wl_event_source *configure_idle; | ||||
| 	uint32_t configure_next_serial; | ||||
|  | @ -178,8 +170,8 @@ struct wlr_xdg_surface_v6 { | |||
| 	char *app_id; | ||||
| 
 | ||||
| 	bool has_next_geometry; | ||||
| 	struct wlr_box *next_geometry; | ||||
| 	struct wlr_box *geometry; | ||||
| 	struct wlr_box next_geometry; | ||||
| 	struct wlr_box geometry; | ||||
| 
 | ||||
| 	struct wl_listener surface_destroy_listener; | ||||
| 
 | ||||
|  | @ -187,6 +179,8 @@ struct wlr_xdg_surface_v6 { | |||
| 		struct wl_signal destroy; | ||||
| 		struct wl_signal ping_timeout; | ||||
| 		struct wl_signal new_popup; | ||||
| 		struct wl_signal map; | ||||
| 		struct wl_signal unmap; | ||||
| 
 | ||||
| 		struct wl_signal request_maximize; | ||||
| 		struct wl_signal request_fullscreen; | ||||
|  |  | |||
|  | @ -21,9 +21,10 @@ wayland_scanner_client = generator( | |||
| ) | ||||
| 
 | ||||
| protocols = [ | ||||
| 	[wl_protocol_dir, 'unstable/xdg-shell/xdg-shell-unstable-v6.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/linux-dmabuf/linux-dmabuf-unstable-v1.xml'], | ||||
| 	[wl_protocol_dir, 'unstable/xdg-shell/xdg-shell-unstable-v6.xml'], | ||||
| 	'gamma-control.xml', | ||||
| 	'gtk-primary-selection.xml', | ||||
| 	'idle.xml', | ||||
|  |  | |||
							
								
								
									
										242
									
								
								render/egl.c
								
								
								
								
							
							
						
						
									
										242
									
								
								render/egl.c
								
								
								
								
							|  | @ -1,4 +1,5 @@ | |||
| #include <assert.h> | ||||
| #include <stdio.h> | ||||
| #include <EGL/egl.h> | ||||
| #include <EGL/eglext.h> | ||||
| #include <GLES2/gl2.h> | ||||
|  | @ -11,43 +12,6 @@ | |||
| // 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
 | ||||
| 
 | ||||
| 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, | ||||
| 		EGLint visual_id) { | ||||
| 	EGLint count = 0, matched = 0, ret; | ||||
|  | @ -83,6 +47,21 @@ static bool egl_get_config(EGLDisplay disp, EGLint *attribs, EGLConfig *out, | |||
| 	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) { | ||||
| 	size_t extlen = strlen(ext); | ||||
| 	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; | ||||
| } | ||||
| 
 | ||||
| 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, | ||||
| 		EGLint *config_attribs, EGLint visual_id) { | ||||
| 	if (!load_glapi()) { | ||||
| 		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) { | ||||
| 		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; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -119,13 +129,13 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, | |||
| 		egl->display = eglGetPlatformDisplayEXT(platform, remote_display, NULL); | ||||
| 	} | ||||
| 	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; | ||||
| 	} | ||||
| 
 | ||||
| 	EGLint major, minor; | ||||
| 	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; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -140,7 +150,7 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, | |||
| 		EGL_NO_CONTEXT, attribs); | ||||
| 
 | ||||
| 	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; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -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_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; | ||||
| 
 | ||||
| error: | ||||
| 	eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); | ||||
| 	if (egl->display) { | ||||
| 		eglTerminate(egl->display); | ||||
| 	} | ||||
| 	eglReleaseThread(); | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| 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); | ||||
| 	if (egl->wl_display && eglUnbindWaylandDisplayWL) { | ||||
| 		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, | ||||
| 		window, NULL); | ||||
| 	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 surf; | ||||
|  | @ -246,7 +269,7 @@ int wlr_egl_get_buffer_age(struct wlr_egl *egl, EGLSurface surface) { | |||
| 	EGLBoolean ok = eglQuerySurface(egl->display, surface, | ||||
| 		EGL_BUFFER_AGE_EXT, &buffer_age); | ||||
| 	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; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -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, | ||||
| 		int *buffer_age) { | ||||
| 	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; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -294,8 +317,137 @@ bool wlr_egl_swap_buffers(struct wlr_egl *egl, EGLSurface surface, | |||
| 	} | ||||
| 
 | ||||
| 	if (!ret) { | ||||
| 		wlr_log(L_ERROR, "eglSwapBuffers failed: %s", egl_error()); | ||||
| 		wlr_log(L_ERROR, "eglSwapBuffers failed"); | ||||
| 		return false; | ||||
| 	} | ||||
| 	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 | ||||
| -eglSwapBuffersWithDamageEXT | ||||
| -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, | ||||
| * 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, | ||||
| 		.depth = 32, | ||||
| 		.bpp = 32, | ||||
| 		.gl_format = GL_BGRA_EXT, | ||||
| 		.gl_type = GL_UNSIGNED_BYTE, | ||||
| 		.shader = &shaders.rgba | ||||
| 		.has_alpha = true, | ||||
| 	}, | ||||
| 	{ | ||||
| 		.wl_format = WL_SHM_FORMAT_XRGB8888, | ||||
|  | @ -21,7 +21,7 @@ struct pixel_format formats[] = { | |||
| 		.bpp = 32, | ||||
| 		.gl_format = GL_BGRA_EXT, | ||||
| 		.gl_type = GL_UNSIGNED_BYTE, | ||||
| 		.shader = &shaders.rgbx | ||||
| 		.has_alpha = false, | ||||
| 	}, | ||||
| 	{ | ||||
| 		.wl_format = WL_SHM_FORMAT_XBGR8888, | ||||
|  | @ -29,7 +29,7 @@ struct pixel_format formats[] = { | |||
| 		.bpp = 32, | ||||
| 		.gl_format = GL_RGBA, | ||||
| 		.gl_type = GL_UNSIGNED_BYTE, | ||||
| 		.shader = &shaders.rgbx | ||||
| 		.has_alpha = false, | ||||
| 	}, | ||||
| 	{ | ||||
| 		.wl_format = WL_SHM_FORMAT_ABGR8888, | ||||
|  | @ -37,12 +37,20 @@ struct pixel_format formats[] = { | |||
| 		.bpp = 32, | ||||
| 		.gl_format = GL_RGBA, | ||||
| 		.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
 | ||||
| 
 | ||||
| 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) { | ||||
| 		if (formats[i].wl_format == fmt) { | ||||
| 			return &formats[i]; | ||||
|  | @ -50,3 +58,8 @@ const struct pixel_format *gl_format_for_wl_format(enum wl_shm_format fmt) { | |||
| 	} | ||||
| 	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/gl2ext.h> | ||||
| #include <stdint.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <wayland-server-protocol.h> | ||||
| #include <wayland-util.h> | ||||
| #include <wlr/backend.h> | ||||
| #include <wlr/render.h> | ||||
| #include <wlr/render/egl.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 "render/gles2.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) { | ||||
| 	*shader = GL_CALL(glCreateShader(type)); | ||||
| 	int len = strlen(src); | ||||
| 	GL_CALL(glShaderSource(*shader, 1, &src, &len)); | ||||
| 	GL_CALL(glCompileShader(*shader)); | ||||
| 	GLint success; | ||||
| 	GL_CALL(glGetShaderiv(*shader, GL_COMPILE_STATUS, &success)); | ||||
| 	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 struct wlr_gles2_renderer *gles2_get_renderer( | ||||
| 		struct wlr_renderer *wlr_renderer) { | ||||
| 	assert(wlr_renderer->impl == &renderer_impl); | ||||
| 	struct wlr_gles2_renderer *renderer = | ||||
| 		(struct wlr_gles2_renderer *)wlr_renderer; | ||||
| 	assert(eglGetCurrentContext() == renderer->egl->context); | ||||
| 	return renderer; | ||||
| } | ||||
| 
 | ||||
| static bool compile_program(const GLchar *vert_src, | ||||
| 		const GLchar *frag_src, GLuint *program) { | ||||
| 	GLuint vertex, fragment; | ||||
| 	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); | ||||
| static void gles2_begin(struct wlr_renderer *wlr_renderer, uint32_t width, | ||||
| 		uint32_t height) { | ||||
| 	gles2_get_renderer(wlr_renderer); | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 	GLES2_DEBUG_PUSH; | ||||
| 
 | ||||
| static void init_default_shaders() { | ||||
| 	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)); | ||||
| 	glViewport(0, 0, width, height); | ||||
| 
 | ||||
| 	// enable transparency
 | ||||
| 	GL_CALL(glEnable(GL_BLEND)); | ||||
| 	GL_CALL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); | ||||
| 	glEnable(GL_BLEND); | ||||
| 	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
 | ||||
| 
 | ||||
| 	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
 | ||||
| } | ||||
| 
 | ||||
| static void wlr_gles2_clear(struct wlr_renderer *wlr_renderer, | ||||
| 		const float (*color)[4]) { | ||||
| 	glClearColor((*color)[0], (*color)[1], (*color)[2], (*color)[3]); | ||||
| static void gles2_clear(struct wlr_renderer *wlr_renderer, | ||||
| 		const float color[static 4]) { | ||||
| 	gles2_get_renderer(wlr_renderer); | ||||
| 
 | ||||
| 	GLES2_DEBUG_PUSH; | ||||
| 	glClearColor(color[0], color[1], color[2], color[3]); | ||||
| 	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) { | ||||
| 	gles2_get_renderer(wlr_renderer); | ||||
| 
 | ||||
| 	GLES2_DEBUG_PUSH; | ||||
| 	if (box != NULL) { | ||||
| 		glScissor(box->x, box->y, box->width, box->height); | ||||
| 		glEnable(GL_SCISSOR_TEST); | ||||
| 	} else { | ||||
| 		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) { | ||||
| 	assert(wlr_renderer->impl == &renderer_impl); | ||||
| 	struct wlr_gles2_renderer *renderer = | ||||
| 		(struct wlr_gles2_renderer *)wlr_renderer; | ||||
| 	return gles2_texture_create(renderer->egl); | ||||
|  | @ -158,80 +95,117 @@ static void draw_quad() { | |||
| 		0, 1, // bottom left
 | ||||
| 	}; | ||||
| 
 | ||||
| 	GL_CALL(glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, verts)); | ||||
| 	GL_CALL(glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, texcoord)); | ||||
| 	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, verts); | ||||
| 	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, texcoord); | ||||
| 
 | ||||
| 	GL_CALL(glEnableVertexAttribArray(0)); | ||||
| 	GL_CALL(glEnableVertexAttribArray(1)); | ||||
| 	glEnableVertexAttribArray(0); | ||||
| 	glEnableVertexAttribArray(1); | ||||
| 
 | ||||
| 	GL_CALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)); | ||||
| 	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | ||||
| 
 | ||||
| 	GL_CALL(glDisableVertexAttribArray(0)); | ||||
| 	GL_CALL(glDisableVertexAttribArray(1)); | ||||
| 	glDisableVertexAttribArray(0); | ||||
| 	glDisableVertexAttribArray(1); | ||||
| } | ||||
| 
 | ||||
| static bool wlr_gles2_render_texture(struct wlr_renderer *wlr_renderer, | ||||
| 		struct wlr_texture *texture, const float (*matrix)[16], float alpha) { | ||||
| 	if (!texture || !texture->valid) { | ||||
| static bool gles2_render_texture_with_matrix( | ||||
| 		struct wlr_renderer *wlr_renderer, struct wlr_texture *wlr_texture, | ||||
| 		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"); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	wlr_texture_bind(texture); | ||||
| 	GL_CALL(glUniformMatrix4fv(0, 1, GL_FALSE, *matrix)); | ||||
| 	GL_CALL(glUniform1f(2, alpha)); | ||||
| 	GLuint prog = renderer->shaders.tex_rgba; | ||||
| 	if (texture->target == GL_TEXTURE_EXTERNAL_OES) { | ||||
| 		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(); | ||||
| 	GLES2_DEBUG_POP; | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void wlr_gles2_render_quad(struct wlr_renderer *wlr_renderer, | ||||
| 		const float (*color)[4], const float (*matrix)[16]) { | ||||
| 	GL_CALL(glUseProgram(shaders.quad)); | ||||
| 	GL_CALL(glUniformMatrix4fv(0, 1, GL_FALSE, *matrix)); | ||||
| 	GL_CALL(glUniform4f(1, (*color)[0], (*color)[1], (*color)[2], (*color)[3])); | ||||
| static void gles2_render_quad(struct wlr_renderer *wlr_renderer, | ||||
| 		const float color[static 4], const float matrix[static 9]) { | ||||
| 	struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); | ||||
| 
 | ||||
| 	// 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(); | ||||
| 	GLES2_DEBUG_POP; | ||||
| } | ||||
| 
 | ||||
| static void wlr_gles2_render_ellipse(struct wlr_renderer *wlr_renderer, | ||||
| 		const float (*color)[4], const float (*matrix)[16]) { | ||||
| 	GL_CALL(glUseProgram(shaders.ellipse)); | ||||
| 	GL_CALL(glUniformMatrix4fv(0, 1, GL_TRUE, *matrix)); | ||||
| 	GL_CALL(glUniform4f(1, (*color)[0], (*color)[1], (*color)[2], (*color)[3])); | ||||
| static void gles2_render_ellipse(struct wlr_renderer *wlr_renderer, | ||||
| 		const float color[static 4], const float matrix[static 9]) { | ||||
| 	struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); | ||||
| 
 | ||||
| 	// 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(); | ||||
| 	GLES2_DEBUG_POP; | ||||
| } | ||||
| 
 | ||||
| static const enum wl_shm_format *wlr_gles2_formats( | ||||
| 		struct wlr_renderer *renderer, size_t *len) { | ||||
| 	static enum wl_shm_format formats[] = { | ||||
| 		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 const enum wl_shm_format *gles2_renderer_formats( | ||||
| 		struct wlr_renderer *wlr_renderer, size_t *len) { | ||||
| 	return gles2_formats(len); | ||||
| } | ||||
| 
 | ||||
| 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 wlr_gles2_renderer *renderer = | ||||
| 		(struct wlr_gles2_renderer *)wlr_renderer; | ||||
| 	struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); | ||||
| 
 | ||||
| 	EGLint format; | ||||
| 	return wlr_egl_query_buffer(renderer->egl, buffer, | ||||
| 		EGL_TEXTURE_FORMAT, &format); | ||||
| 	return wlr_egl_query_buffer(renderer->egl, buffer, EGL_TEXTURE_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, | ||||
| 		uint32_t height, uint32_t src_x, uint32_t src_y, uint32_t dst_x, | ||||
| 		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) { | ||||
| 		wlr_log(L_ERROR, "Cannot read pixels: unsupported pixel format"); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	GLES2_DEBUG_PUSH; | ||||
| 
 | ||||
| 	// Make sure any pending drawing is finished before we try to read it
 | ||||
| 	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); | ||||
| 	} | ||||
| 
 | ||||
| 	GLES2_DEBUG_POP; | ||||
| 
 | ||||
| 	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) { | ||||
| 	return gl_format_for_wl_format(wl_fmt); | ||||
| 	return gles2_format_from_wl(wl_fmt) != NULL; | ||||
| } | ||||
| 
 | ||||
| static struct wlr_renderer_impl wlr_renderer_impl = { | ||||
| 	.begin = wlr_gles2_begin, | ||||
| 	.end = wlr_gles2_end, | ||||
| 	.clear = wlr_gles2_clear, | ||||
| 	.scissor = wlr_gles2_scissor, | ||||
| 	.texture_create = wlr_gles2_texture_create, | ||||
| 	.render_with_matrix = wlr_gles2_render_texture, | ||||
| 	.render_quad = wlr_gles2_render_quad, | ||||
| 	.render_ellipse = wlr_gles2_render_ellipse, | ||||
| 	.formats = wlr_gles2_formats, | ||||
| 	.buffer_is_drm = wlr_gles2_buffer_is_drm, | ||||
| 	.read_pixels = wlr_gles2_read_pixels, | ||||
| 	.format_supported = wlr_gles2_format_supported, | ||||
| static void gles2_destroy(struct wlr_renderer *wlr_renderer) { | ||||
| 	struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); | ||||
| 
 | ||||
| 	wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL); | ||||
| 
 | ||||
| 	GLES2_DEBUG_PUSH; | ||||
| 	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); | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
| 	init_globals(); | ||||
| 	struct wlr_gles2_renderer *renderer; | ||||
| 	if (!(renderer = calloc(1, sizeof(struct wlr_gles2_renderer)))) { | ||||
| 	struct wlr_gles2_renderer *renderer = | ||||
| 		calloc(1, sizeof(struct wlr_gles2_renderer)); | ||||
| 	if (renderer == 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); | ||||
| 	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; | ||||
| 
 | ||||
| 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
 | ||||
| const GLchar quad_vertex_src[] = | ||||
| "uniform mat4 proj;" | ||||
| "uniform vec4 color;" | ||||
| "attribute vec2 pos;" | ||||
| "attribute vec2 texcoord;" | ||||
| "varying vec4 v_color;" | ||||
| "varying vec2 v_texcoord;" | ||||
| "mat4 transpose(in mat4 inMatrix) {" | ||||
| "    vec4 i0 = inMatrix[0];" | ||||
| "    vec4 i1 = inMatrix[1];" | ||||
| "    vec4 i2 = inMatrix[2];" | ||||
| "    vec4 i3 = inMatrix[3];" | ||||
| "    mat4 outMatrix = mat4(" | ||||
| "                 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;" | ||||
| "}"; | ||||
| "uniform mat3 proj;\n" | ||||
| "uniform vec4 color;\n" | ||||
| "attribute vec2 pos;\n" | ||||
| "attribute vec2 texcoord;\n" | ||||
| "varying vec4 v_color;\n" | ||||
| "varying vec2 v_texcoord;\n" | ||||
| "\n" | ||||
| "void main() {\n" | ||||
| "	gl_Position = vec4(proj * vec3(pos, 1.0), 1.0);\n" | ||||
| "	v_color = color;\n" | ||||
| "	v_texcoord = texcoord;\n" | ||||
| "}\n"; | ||||
| 
 | ||||
| const GLchar quad_fragment_src[] = | ||||
| "precision mediump float;" | ||||
| "varying vec4 v_color;" | ||||
| "varying vec2 v_texcoord;" | ||||
| "void main() {" | ||||
| "  gl_FragColor = v_color;" | ||||
| "}"; | ||||
| "precision mediump float;\n" | ||||
| "varying vec4 v_color;\n" | ||||
| "varying vec2 v_texcoord;\n" | ||||
| "\n" | ||||
| "void main() {\n" | ||||
| "	gl_FragColor = v_color;\n" | ||||
| "}\n"; | ||||
| 
 | ||||
| // Colored ellipses
 | ||||
| const GLchar ellipse_fragment_src[] = | ||||
| "precision mediump float;" | ||||
| "varying vec4 v_color;" | ||||
| "varying vec2 v_texcoord;" | ||||
| "void main() {" | ||||
| "  float l = length(v_texcoord - vec2(0.5, 0.5));" | ||||
| "  if (l > 0.5) discard;" | ||||
| "  gl_FragColor = v_color;" | ||||
| "}"; | ||||
| "precision mediump float;\n" | ||||
| "varying vec4 v_color;\n" | ||||
| "varying vec2 v_texcoord;\n" | ||||
| "\n" | ||||
| "void main() {\n" | ||||
| "	float l = length(v_texcoord - vec2(0.5, 0.5));\n" | ||||
| "	if (l > 0.5) {\n" | ||||
| "		discard;\n" | ||||
| "	}\n" | ||||
| "	gl_FragColor = v_color;\n" | ||||
| "}\n"; | ||||
| 
 | ||||
| // Textured quads
 | ||||
| const GLchar vertex_src[] = | ||||
| "uniform mat4 proj;" | ||||
| "attribute vec2 pos;" | ||||
| "attribute vec2 texcoord;" | ||||
| "varying vec2 v_texcoord;" | ||||
| "mat4 transpose(in mat4 inMatrix) {" | ||||
| "    vec4 i0 = inMatrix[0];" | ||||
| "    vec4 i1 = inMatrix[1];" | ||||
| "    vec4 i2 = inMatrix[2];" | ||||
| "    vec4 i3 = inMatrix[3];" | ||||
| "    mat4 outMatrix = mat4(" | ||||
| "                 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_texcoord = texcoord;" | ||||
| "}"; | ||||
| const GLchar tex_vertex_src[] = | ||||
| "uniform mat3 proj;\n" | ||||
| "uniform bool invert_y;\n" | ||||
| "attribute vec2 pos;\n" | ||||
| "attribute vec2 texcoord;\n" | ||||
| "varying vec2 v_texcoord;\n" | ||||
| "\n" | ||||
| "void main() {\n" | ||||
| "	gl_Position = vec4(proj * vec3(pos, 1.0), 1.0);\n" | ||||
| "	if (invert_y) {\n" | ||||
| "		v_texcoord = vec2(texcoord.s, 1.0 - texcoord.t);\n" | ||||
| "	} else {\n" | ||||
| "		v_texcoord = texcoord;\n" | ||||
| "	}\n" | ||||
| "}\n"; | ||||
| 
 | ||||
| const GLchar fragment_src_rgba[] = | ||||
| "precision mediump float;" | ||||
| "varying vec2 v_texcoord;" | ||||
| "uniform sampler2D tex;" | ||||
| "uniform float alpha;" | ||||
| "void main() {" | ||||
| "	gl_FragColor = alpha * texture2D(tex, v_texcoord);" | ||||
| "}"; | ||||
| const GLchar tex_fragment_src_rgba[] = | ||||
| "precision mediump float;\n" | ||||
| "varying vec2 v_texcoord;\n" | ||||
| "uniform sampler2D tex;\n" | ||||
| "uniform float alpha;\n" | ||||
| "\n" | ||||
| "void main() {\n" | ||||
| "	gl_FragColor = alpha * texture2D(tex, v_texcoord);\n" | ||||
| "}\n"; | ||||
| 
 | ||||
| const GLchar fragment_src_rgbx[] = | ||||
| "precision mediump float;" | ||||
| "varying vec2 v_texcoord;" | ||||
| "uniform sampler2D tex;" | ||||
| "uniform float alpha;" | ||||
| "void main() {" | ||||
| "   gl_FragColor.rgb = alpha * texture2D(tex, v_texcoord).rgb;" | ||||
| "   gl_FragColor.a = alpha;" | ||||
| "}"; | ||||
| const GLchar tex_fragment_src_rgbx[] = | ||||
| "precision mediump float;\n" | ||||
| "varying vec2 v_texcoord;\n" | ||||
| "uniform sampler2D tex;\n" | ||||
| "uniform float alpha;\n" | ||||
| "\n" | ||||
| "void main() {\n" | ||||
| "	gl_FragColor.rgb = alpha * texture2D(tex, v_texcoord).rgb;\n" | ||||
| "	gl_FragColor.a = alpha;\n" | ||||
| "}\n"; | ||||
| 
 | ||||
| const GLchar fragment_src_external[] = | ||||
| "#extension GL_OES_EGL_image_external : require\n" | ||||
| "precision mediump float;" | ||||
| "varying vec2 v_texcoord;" | ||||
| "uniform samplerExternalOES texture0;" | ||||
| "void main() {" | ||||
| "  vec4 col = texture2D(texture0, v_texcoord);" | ||||
| "  gl_FragColor = vec4(col.rgb, col.a);" | ||||
| "}"; | ||||
| const GLchar tex_fragment_src_external[] = | ||||
| "#extension GL_OES_EGL_image_external : require\n\n" | ||||
| "precision mediump float;\n" | ||||
| "varying vec2 v_texcoord;\n" | ||||
| "uniform samplerExternalOES texture0;\n" | ||||
| "uniform float alpha;\n" | ||||
| "\n" | ||||
| "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 <wayland-server-protocol.h> | ||||
| #include <wayland-util.h> | ||||
| #include <wlr/render.h> | ||||
| #include <wlr/render/wlr_texture.h> | ||||
| #include <wlr/render/egl.h> | ||||
| #include <wlr/render/interface.h> | ||||
| #include <wlr/render/matrix.h> | ||||
| #include <wlr/types/wlr_matrix.h> | ||||
| #include <wlr/util/log.h> | ||||
| #include "render/gles2.h" | ||||
| #include "util/signal.h" | ||||
| 
 | ||||
| static struct pixel_format external_pixel_format = { | ||||
| static struct gles2_pixel_format external_pixel_format = { | ||||
| 	.wl_format = 0, | ||||
| 	.depth = 0, | ||||
| 	.bpp = 0, | ||||
| 	.gl_format = 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) { | ||||
| 		return; | ||||
| 	} | ||||
| 	GL_CALL(glGenTextures(1, &texture->tex_id)); | ||||
| 	GL_CALL(glBindTexture(GL_TEXTURE_2D, texture->tex_id)); | ||||
| 	GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); | ||||
| 	GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); | ||||
| 	texture->target = target; | ||||
| 	glGenTextures(1, &texture->tex_id); | ||||
| 	glBindTexture(target, texture->tex_id); | ||||
| 	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, | ||||
| 		const unsigned char *pixels) { | ||||
| 	struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture; | ||||
| 	assert(texture); | ||||
| 	const struct pixel_format *fmt = gl_format_for_wl_format(format); | ||||
| 	struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); | ||||
| 
 | ||||
| 	const struct gles2_pixel_format *fmt = gles2_format_from_wl(format); | ||||
| 	if (!fmt || !fmt->gl_format) { | ||||
| 		wlr_log(L_ERROR, "No supported pixel format for this texture"); | ||||
| 		return false; | ||||
|  | @ -47,44 +55,50 @@ static bool gles2_texture_upload_pixels(struct wlr_texture *_texture, | |||
| 	texture->wlr_texture.format = format; | ||||
| 	texture->pixel_format = fmt; | ||||
| 
 | ||||
| 	gles2_texture_ensure_texture(texture); | ||||
| 	GL_CALL(glBindTexture(GL_TEXTURE_2D, texture->tex_id)); | ||||
| 	GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride)); | ||||
| 	GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, fmt->gl_format, width, height, 0, | ||||
| 			fmt->gl_format, fmt->gl_type, pixels)); | ||||
| 	GLES2_DEBUG_PUSH; | ||||
| 	gles2_texture_ensure(texture, GL_TEXTURE_2D); | ||||
| 	glBindTexture(GL_TEXTURE_2D, texture->tex_id); | ||||
| 	glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride); | ||||
| 	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; | ||||
| 	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, | ||||
| 		int width, int height, const unsigned char *pixels) { | ||||
| 	struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture; | ||||
| 	assert(texture); | ||||
| 	struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); | ||||
| 
 | ||||
| 	// TODO: Test if the unpack subimage extension is supported and adjust the
 | ||||
| 	// upload strategy if not
 | ||||
| 	if (!texture->wlr_texture.valid | ||||
| 			|| texture->wlr_texture.format != format | ||||
| 		/*	|| unpack not supported */) { | ||||
| 		return gles2_texture_upload_pixels(&texture->wlr_texture, | ||||
| 				format, stride, width, height, pixels); | ||||
| 		return gles2_texture_upload_pixels(&texture->wlr_texture, format, | ||||
| 			stride, width, height, pixels); | ||||
| 	} | ||||
| 	const struct pixel_format *fmt = texture->pixel_format; | ||||
| 	GL_CALL(glBindTexture(GL_TEXTURE_2D, texture->tex_id)); | ||||
| 	GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride)); | ||||
| 	GL_CALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, x)); | ||||
| 	GL_CALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, y)); | ||||
| 	GL_CALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, | ||||
| 			fmt->gl_format, fmt->gl_type, pixels)); | ||||
| 	GL_CALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0)); | ||||
| 	GL_CALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0)); | ||||
| 	const struct gles2_pixel_format *fmt = texture->pixel_format; | ||||
| 	GLES2_DEBUG_PUSH; | ||||
| 	glBindTexture(GL_TEXTURE_2D, texture->tex_id); | ||||
| 	glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride); | ||||
| 	glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, x); | ||||
| 	glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, y); | ||||
| 	glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, fmt->gl_format, | ||||
| 		fmt->gl_type, pixels); | ||||
| 	glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0); | ||||
| 	glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0); | ||||
| 	GLES2_DEBUG_POP; | ||||
| 	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) { | ||||
| 	struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture; | ||||
| 	const struct pixel_format *fmt = gl_format_for_wl_format(format); | ||||
| 	struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); | ||||
| 
 | ||||
| 	const struct gles2_pixel_format *fmt = gles2_format_from_wl(format); | ||||
| 	if (!fmt || !fmt->gl_format) { | ||||
| 		wlr_log(L_ERROR, "Unsupported pixel format %"PRIu32" for this texture", | ||||
| 				format); | ||||
|  | @ -100,23 +114,26 @@ static bool gles2_texture_upload_shm(struct wlr_texture *_texture, | |||
| 	texture->wlr_texture.format = format; | ||||
| 	texture->pixel_format = fmt; | ||||
| 
 | ||||
| 	gles2_texture_ensure_texture(texture); | ||||
| 	GL_CALL(glBindTexture(GL_TEXTURE_2D, texture->tex_id)); | ||||
| 	GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, pitch)); | ||||
| 	GL_CALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0)); | ||||
| 	GL_CALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0)); | ||||
| 	GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, fmt->gl_format, width, height, 0, | ||||
| 				fmt->gl_format, fmt->gl_type, pixels)); | ||||
| 	GLES2_DEBUG_PUSH; | ||||
| 	gles2_texture_ensure(texture, GL_TEXTURE_2D); | ||||
| 	glBindTexture(GL_TEXTURE_2D, texture->tex_id); | ||||
| 	glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, pitch); | ||||
| 	glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0); | ||||
| 	glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0); | ||||
| 	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; | ||||
| 	wl_shm_buffer_end_access(buffer); | ||||
| 	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, | ||||
| 		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
 | ||||
| 	// upload strategy if not
 | ||||
| 	assert(texture); | ||||
|  | @ -125,28 +142,30 @@ static bool gles2_texture_update_shm(struct wlr_texture *_texture, | |||
| 		/*	|| unpack not supported */) { | ||||
| 		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); | ||||
| 	uint8_t *pixels = wl_shm_buffer_get_data(buffer); | ||||
| 	int pitch = wl_shm_buffer_get_stride(buffer) / (fmt->bpp / 8); | ||||
| 
 | ||||
| 	GL_CALL(glBindTexture(GL_TEXTURE_2D, texture->tex_id)); | ||||
| 	GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, pitch)); | ||||
| 	GL_CALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, x)); | ||||
| 	GL_CALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, y)); | ||||
| 	GL_CALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, | ||||
| 			fmt->gl_format, fmt->gl_type, pixels)); | ||||
| 	GL_CALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0)); | ||||
| 	GL_CALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0)); | ||||
| 	GLES2_DEBUG_PUSH; | ||||
| 	glBindTexture(GL_TEXTURE_2D, texture->tex_id); | ||||
| 	glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, pitch); | ||||
| 	glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, x); | ||||
| 	glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, y); | ||||
| 	glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, | ||||
| 			fmt->gl_format, fmt->gl_type, pixels); | ||||
| 	glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0); | ||||
| 	glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0); | ||||
| 	GLES2_DEBUG_POP; | ||||
| 
 | ||||
| 	wl_shm_buffer_end_access(buffer); | ||||
| 
 | ||||
| 	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 wlr_gles2_texture *tex = (struct wlr_gles2_texture *)_tex; | ||||
| 	struct wlr_gles2_texture *tex = gles2_get_texture(wlr_texture); | ||||
| 	if (!glEGLImageTargetTexture2DOES) { | ||||
| 		return false; | ||||
| 	} | ||||
|  | @ -163,15 +182,18 @@ static bool gles2_texture_upload_drm(struct wlr_texture *_tex, | |||
| 		(EGLint*)&tex->wlr_texture.height); | ||||
| 
 | ||||
| 	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; | ||||
| 	const struct pixel_format *pf; | ||||
| 	const struct gles2_pixel_format *pf; | ||||
| 	switch (format) { | ||||
| 	case EGL_TEXTURE_RGB: | ||||
| 	case EGL_TEXTURE_RGBA: | ||||
| 		target = GL_TEXTURE_2D; | ||||
| 		pf = gl_format_for_wl_format(WL_SHM_FORMAT_ARGB8888); | ||||
| 		pf = gles2_format_from_wl(WL_SHM_FORMAT_ARGB8888); | ||||
| 		break; | ||||
| 	case EGL_TEXTURE_EXTERNAL_WL: | ||||
| 		target = GL_TEXTURE_EXTERNAL_OES; | ||||
|  | @ -182,8 +204,10 @@ static bool gles2_texture_upload_drm(struct wlr_texture *_tex, | |||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	gles2_texture_ensure_texture(tex); | ||||
| 	GL_CALL(glBindTexture(GL_TEXTURE_2D, tex->tex_id)); | ||||
| 	GLES2_DEBUG_PUSH; | ||||
| 	gles2_texture_ensure(tex, target); | ||||
| 	glBindTexture(GL_TEXTURE_2D, tex->tex_id); | ||||
| 	GLES2_DEBUG_POP; | ||||
| 
 | ||||
| 	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, | ||||
| 		(EGLClientBuffer*) buf, attribs); | ||||
| 	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; | ||||
| 	} | ||||
| 
 | ||||
| 	GL_CALL(glActiveTexture(GL_TEXTURE0)); | ||||
| 	GL_CALL(glBindTexture(target, tex->tex_id)); | ||||
| 	GL_CALL(glEGLImageTargetTexture2DOES(target, tex->image)); | ||||
| 	GLES2_DEBUG_PUSH; | ||||
| 	glActiveTexture(GL_TEXTURE0); | ||||
| 	glBindTexture(target, tex->tex_id); | ||||
| 	glEGLImageTargetTexture2DOES(target, tex->image); | ||||
| 	GLES2_DEBUG_POP; | ||||
| 	tex->wlr_texture.valid = true; | ||||
| 	tex->pixel_format = pf; | ||||
| 
 | ||||
| 	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) { | ||||
| 	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->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.height = height; | ||||
| 
 | ||||
| 	gles2_texture_ensure_texture(tex); | ||||
| 
 | ||||
| 	GL_CALL(glActiveTexture(GL_TEXTURE0)); | ||||
| 	GL_CALL(glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex->tex_id)); | ||||
| 	GL_CALL(glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, tex->image)); | ||||
| 	GLES2_DEBUG_PUSH; | ||||
| 	gles2_texture_ensure(tex, GL_TEXTURE_2D); | ||||
| 	glActiveTexture(GL_TEXTURE0); | ||||
| 	glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex->tex_id); | ||||
| 	glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, tex->image); | ||||
| 	GLES2_DEBUG_POP; | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| static void gles2_texture_get_matrix(struct wlr_texture *_texture, | ||||
| 		float (*matrix)[16], const float (*projection)[16], int x, int y) { | ||||
| 	struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture; | ||||
| 	float world[16]; | ||||
| 	wlr_matrix_identity(matrix); | ||||
| 	wlr_matrix_translate(&world, x, y, 0); | ||||
| 	wlr_matrix_mul(matrix, &world, matrix); | ||||
| 	wlr_matrix_scale(&world, | ||||
| 			texture->wlr_texture.width, texture->wlr_texture.height, 1); | ||||
| 	wlr_matrix_mul(matrix, &world, matrix); | ||||
| 	wlr_matrix_mul(projection, matrix, matrix); | ||||
| static bool gles2_texture_upload_dmabuf(struct wlr_texture *wlr_texture, | ||||
| 		struct wl_resource *dmabuf_resource) { | ||||
| 	struct wlr_gles2_texture *tex = gles2_get_texture(wlr_texture); | ||||
| 	struct wlr_dmabuf_buffer *dmabuf = | ||||
| 		wlr_dmabuf_buffer_from_buffer_resource(dmabuf_resource); | ||||
| 
 | ||||
| 	if (!tex->egl->egl_exts.dmabuf_import) { | ||||
| 		wlr_log(L_ERROR, "Want dmabuf but extension not present"); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| static void gles2_texture_get_buffer_size(struct wlr_texture *texture, struct | ||||
| 	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 bool gles2_texture_get_dmabuf_size(struct wlr_texture *texture, struct | ||||
| 		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); | ||||
| 	if (!buffer) { | ||||
| 		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, | ||||
| 				(EGLint*)width)) { | ||||
| 			wlr_log(L_ERROR, "could not get size of the buffer " | ||||
| 				"(no buffer found)"); | ||||
| 			if (!gles2_texture_get_dmabuf_size(texture, resource, width, | ||||
| 					height)) { | ||||
| 				wlr_log(L_ERROR, "could not get size of the buffer"); | ||||
| 				return; | ||||
| 		}; | ||||
| 		wlr_egl_query_buffer(tex->egl, resource, EGL_HEIGHT, | ||||
| 			(EGLint*)height); | ||||
| 			} | ||||
| 		} | ||||
| 		wlr_egl_query_buffer(tex->egl, resource, EGL_HEIGHT, (EGLint*)height); | ||||
| 
 | ||||
| 		return; | ||||
| 	} | ||||
|  | @ -263,19 +328,15 @@ static void gles2_texture_get_buffer_size(struct wlr_texture *texture, struct | |||
| 	*height = wl_shm_buffer_get_height(buffer); | ||||
| } | ||||
| 
 | ||||
| static void gles2_texture_bind(struct wlr_texture *_texture) { | ||||
| 	struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_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 *wlr_texture) { | ||||
| 	struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); | ||||
| 
 | ||||
| static void gles2_texture_destroy(struct wlr_texture *_texture) { | ||||
| 	struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture; | ||||
| 	wlr_signal_emit_safe(&texture->wlr_texture.destroy_signal, &texture->wlr_texture); | ||||
| 	wlr_signal_emit_safe(&texture->wlr_texture.destroy_signal, | ||||
| 		&texture->wlr_texture); | ||||
| 	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) { | ||||
|  | @ -285,16 +346,15 @@ static void gles2_texture_destroy(struct wlr_texture *_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, | ||||
| 	.update_pixels = gles2_texture_update_pixels, | ||||
| 	.upload_shm = gles2_texture_upload_shm, | ||||
| 	.update_shm = gles2_texture_update_shm, | ||||
| 	.upload_drm = gles2_texture_upload_drm, | ||||
| 	.upload_dmabuf = gles2_texture_upload_dmabuf, | ||||
| 	.upload_eglimage = gles2_texture_upload_eglimage, | ||||
| 	.get_matrix = gles2_texture_get_matrix, | ||||
| 	.get_buffer_size = gles2_texture_get_buffer_size, | ||||
| 	.bind = gles2_texture_bind, | ||||
| 	.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)))) { | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	wlr_texture_init(&texture->wlr_texture, &wlr_texture_impl); | ||||
| 	wlr_texture_init(&texture->wlr_texture, &texture_impl); | ||||
| 	texture->egl = egl; | ||||
| 	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/texture.c', | ||||
| 		'gles2/util.c', | ||||
| 		'matrix.c', | ||||
| 		'wlr_renderer.c', | ||||
| 		'wlr_texture.c', | ||||
| 	), | ||||
|  |  | |||
|  | @ -1,9 +1,11 @@ | |||
| #include <stdbool.h> | ||||
| #include <stdlib.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, | ||||
| 		struct wlr_renderer_impl *impl) { | ||||
| 		const struct wlr_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) { | ||||
| 	r->impl->begin(r, o); | ||||
| void wlr_renderer_begin(struct wlr_renderer *r, int width, int height) { | ||||
| 	r->impl->begin(r, width, height); | ||||
| } | ||||
| 
 | ||||
| void wlr_renderer_end(struct wlr_renderer *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); | ||||
| } | ||||
| 
 | ||||
|  | @ -35,18 +37,30 @@ struct wlr_texture *wlr_render_texture_create(struct wlr_renderer *r) { | |||
| 	return r->impl->texture_create(r); | ||||
| } | ||||
| 
 | ||||
| bool wlr_render_with_matrix(struct wlr_renderer *r, | ||||
| 		struct wlr_texture *texture, const float (*matrix)[16], float alpha) { | ||||
| 	return r->impl->render_with_matrix(r, texture, matrix, alpha); | ||||
| bool wlr_render_texture(struct wlr_renderer *r, struct wlr_texture *texture, | ||||
| 		const float projection[static 9], int x, int y, float 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, | ||||
| 		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); | ||||
| } | ||||
| 
 | ||||
| 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); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,9 +1,10 @@ | |||
| #include <stdbool.h> | ||||
| #include <stdlib.h> | ||||
| #include <wlr/render/interface.h> | ||||
| #include <wlr/render/wlr_texture.h> | ||||
| 
 | ||||
| void wlr_texture_init(struct wlr_texture *texture, | ||||
| 		struct wlr_texture_impl *impl) { | ||||
| 		const struct wlr_texture_impl *impl) { | ||||
| 	texture->impl = impl; | ||||
| 	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, | ||||
| 		int stride, int width, int height, const unsigned char *pixels) { | ||||
| 	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); | ||||
| } | ||||
| 
 | ||||
| void wlr_texture_get_matrix(struct wlr_texture *texture, | ||||
| 		float (*matrix)[16], const float (*projection)[16], int x, int y) { | ||||
| 	texture->impl->get_matrix(texture, matrix, projection, x, y); | ||||
| bool wlr_texture_upload_dmabuf(struct wlr_texture *texture, | ||||
| 		struct wl_resource *dmabuf_resource) { | ||||
| 	return texture->impl->upload_dmabuf(texture, dmabuf_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; | ||||
| 			int vx = cursor->cursor->x - ox, | ||||
| 				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; | ||||
| 			angle = round(angle/M_PI*steps) / (steps/M_PI); | ||||
| 			view_rotate(view, cursor->view_rotation + angle); | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ | |||
| #include <wlr/types/wlr_cursor.h> | ||||
| #include <wlr/types/wlr_gamma_control.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_idle_inhibit_v1.h> | ||||
| #include <wlr/types/wlr_primary_selection.h> | ||||
|  | @ -23,13 +24,16 @@ | |||
| #include "rootston/view.h" | ||||
| #include "rootston/xcursor.h" | ||||
| 
 | ||||
| 
 | ||||
| struct roots_view *view_create() { | ||||
| struct roots_view *view_create(struct roots_desktop *desktop) { | ||||
| 	struct roots_view *view = calloc(1, sizeof(struct roots_view)); | ||||
| 	if (!view) { | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	view->desktop = desktop; | ||||
| 	view->alpha = 1.0f; | ||||
| 	wl_signal_init(&view->events.unmap); | ||||
| 	wl_signal_init(&view->events.destroy); | ||||
| 	wl_list_init(&view->children); | ||||
| 	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); | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
| 		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, | ||||
| 		const struct wlr_box *before) { | ||||
| 	struct roots_desktop *desktop = view->desktop; | ||||
| 	struct roots_output *output; | ||||
| 
 | ||||
| 	if (view->wlr_surface == NULL) { | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	struct wlr_box box; | ||||
| 	view_get_box(view, &box); | ||||
| 
 | ||||
| 	struct roots_output *output; | ||||
| 	wl_list_for_each(output, &desktop->outputs, link) { | ||||
| 		bool intersected = before != NULL && wlr_output_layout_intersects( | ||||
| 			desktop->layout, output->wlr_output, before); | ||||
|  | @ -402,20 +413,22 @@ struct roots_subsurface *subsurface_create(struct roots_view *view, | |||
| 	return subsurface; | ||||
| } | ||||
| 
 | ||||
| void view_finish(struct roots_view *view) { | ||||
| 	view_damage_whole(view); | ||||
| void view_destroy(struct roots_view *view) { | ||||
| 	if (view == NULL) { | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	wl_signal_emit(&view->events.destroy, view); | ||||
| 
 | ||||
| 	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->wlr_surface != NULL) { | ||||
| 		view_unmap(view); | ||||
| 	} | ||||
| 
 | ||||
| 	if (view->fullscreen_output) { | ||||
| 		view->fullscreen_output->fullscreen_view = NULL; | ||||
| 	if (view->destroy) { | ||||
| 		view->destroy(view); | ||||
| 	} | ||||
| 
 | ||||
| 	free(view); | ||||
| } | ||||
| 
 | ||||
| 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); | ||||
| } | ||||
| 
 | ||||
| void view_init(struct roots_view *view, struct roots_desktop *desktop) { | ||||
| 	assert(view->wlr_surface); | ||||
| void view_map(struct roots_view *view, struct wlr_surface *surface) { | ||||
| 	assert(view->wlr_surface == NULL); | ||||
| 
 | ||||
| 	view->desktop = desktop; | ||||
| 	wl_signal_init(&view->events.destroy); | ||||
| 	wl_list_init(&view->children); | ||||
| 	view->wlr_surface = surface; | ||||
| 
 | ||||
| 	struct wlr_subsurface *subsurface; | ||||
| 	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, | ||||
| 		&view->new_subsurface); | ||||
| 
 | ||||
| 	wl_list_insert(&view->desktop->views, &view->link); | ||||
| 	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) { | ||||
| 	struct roots_input *input = view->desktop->server->input; | ||||
| 	// 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) { | ||||
| 	view_initial_focus(view); | ||||
| 
 | ||||
| 	if (view->fullscreen_output == NULL && !view->maximized) { | ||||
| 		view_center(view); | ||||
| 	} | ||||
| 
 | ||||
| 	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, | ||||
| 			oy = view_sy - (double)box.height/2; | ||||
| 		// Rotated coordinates
 | ||||
| 		double rx = cos(view->rotation)*ox - sin(view->rotation)*oy, | ||||
| 			ry = cos(view->rotation)*oy + sin(view->rotation)*ox; | ||||
| 		double rx = cos(view->rotation)*ox + sin(view->rotation)*oy, | ||||
| 			ry = cos(view->rotation)*oy - sin(view->rotation)*ox; | ||||
| 		view_sx = rx + (double)box.width/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_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; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -7,7 +7,7 @@ | |||
| #include <wlr/backend/headless.h> | ||||
| #include <wlr/backend/multi.h> | ||||
| #include <wlr/config.h> | ||||
| #include <wlr/render.h> | ||||
| #include <wlr/render/wlr_renderer.h> | ||||
| #include <wlr/util/log.h> | ||||
| #include "rootston/config.h" | ||||
| #include "rootston/server.h" | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ | |||
| #include <stdbool.h> | ||||
| #include <stdlib.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_output_layout.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, | ||||
| 			oy = *sy - ph/2 + sh/2; | ||||
| 		// Rotated coordinates
 | ||||
| 		double rx = cos(-rotation)*ox - sin(-rotation)*oy, | ||||
| 			ry = cos(-rotation)*oy + sin(-rotation)*ox; | ||||
| 		double rx = cos(rotation)*ox - sin(rotation)*oy, | ||||
| 			ry = cos(rotation)*oy + sin(rotation)*ox; | ||||
| 		*sx = rx + pw/2 - sw/2; | ||||
| 		*sy = ry + ph/2 - sh/2; | ||||
| 	} | ||||
|  | @ -227,7 +227,7 @@ static bool surface_intersect_output(struct wlr_surface *surface, | |||
| 		.x = lx, .y = ly, | ||||
| 		.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); | ||||
| } | ||||
| 
 | ||||
|  | @ -275,7 +275,7 @@ static void render_surface(struct wlr_surface *surface, double lx, double ly, | |||
| 	} | ||||
| 
 | ||||
| 	struct wlr_box rotated; | ||||
| 	wlr_box_rotated_bounds(&box, -rotation, &rotated); | ||||
| 	wlr_box_rotated_bounds(&box, rotation, &rotated); | ||||
| 
 | ||||
| 	pixman_region32_t damage; | ||||
| 	pixman_region32_init(&damage); | ||||
|  | @ -287,17 +287,17 @@ static void render_surface(struct wlr_surface *surface, double lx, double ly, | |||
| 		goto damage_finish; | ||||
| 	} | ||||
| 
 | ||||
| 	float matrix[16]; | ||||
| 	float matrix[9]; | ||||
| 	enum wl_output_transform transform = | ||||
| 		wlr_output_transform_invert(surface->current->transform); | ||||
| 	wlr_matrix_project_box(&matrix, &box, transform, rotation, | ||||
| 		&output->wlr_output->transform_matrix); | ||||
| 	wlr_matrix_project_box(matrix, &box, transform, rotation, | ||||
| 		output->wlr_output->transform_matrix); | ||||
| 
 | ||||
| 	int nrects; | ||||
| 	pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); | ||||
| 	for (int i = 0; i < nrects; ++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: | ||||
|  | @ -341,7 +341,7 @@ static void render_decorations(struct roots_view *view, | |||
| 	get_decoration_box(view, output, &box); | ||||
| 
 | ||||
| 	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_init(&damage); | ||||
|  | @ -353,9 +353,9 @@ static void render_decorations(struct roots_view *view, | |||
| 		goto damage_finish; | ||||
| 	} | ||||
| 
 | ||||
| 	float matrix[16]; | ||||
| 	wlr_matrix_project_box(&matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, | ||||
| 		view->rotation, &output->wlr_output->transform_matrix); | ||||
| 	float matrix[9]; | ||||
| 	wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, | ||||
| 		view->rotation, output->wlr_output->transform_matrix); | ||||
| 	float color[] = { 0.2, 0.2, 0.2, view->alpha }; | ||||
| 
 | ||||
| 	int nrects; | ||||
|  | @ -363,7 +363,7 @@ static void render_decorations(struct roots_view *view, | |||
| 		pixman_region32_rectangles(&damage, &nrects); | ||||
| 	for (int i = 0; i < nrects; ++i) { | ||||
| 		scissor_output(output, &rects[i]); | ||||
| 		wlr_render_colored_quad(renderer, &color, &matrix); | ||||
| 		wlr_render_colored_quad(renderer, color, matrix); | ||||
| 	} | ||||
| 
 | ||||
| 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}; | ||||
| 
 | ||||
| 	// 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; | ||||
| 
 | ||||
| 		// Make sure the view is centered on screen
 | ||||
|  | @ -478,7 +479,7 @@ static void render_output(struct roots_output *output) { | |||
| 		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)) { | ||||
| 		// 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); | ||||
| 	for (int i = 0; i < nrects; ++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
 | ||||
|  | @ -501,7 +502,9 @@ static void render_output(struct roots_output *output) { | |||
| 			goto renderer_end; | ||||
| 		} | ||||
| 
 | ||||
| 		if (view->wlr_surface != NULL) { | ||||
| 			view_for_each_surface(view, render_surface, &data); | ||||
| 		} | ||||
| 
 | ||||
| 		// During normal rendering the xwayland window tree isn't traversed
 | ||||
| 		// 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, | ||||
| 		struct roots_view *view) { | ||||
| 	if (view->wlr_surface == NULL) { | ||||
| 		return false; | ||||
| 	} | ||||
| 	if (output->fullscreen_view == NULL) { | ||||
| 		return true; | ||||
| 	} | ||||
|  | @ -610,7 +616,7 @@ static void damage_whole_surface(struct wlr_surface *surface, | |||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	wlr_box_rotated_bounds(&box, -rotation, &box); | ||||
| 	wlr_box_rotated_bounds(&box, rotation, &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; | ||||
| 	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); | ||||
| } | ||||
|  | @ -674,6 +680,7 @@ static void damage_from_surface(struct wlr_surface *surface, | |||
| 		} | ||||
| 		pixman_region32_translate(&damage, box.x, box.y); | ||||
| 		wlr_output_damage_add(output->damage, &damage); | ||||
| 		pixman_region32_fini(&damage); | ||||
| 	} else { | ||||
| 		pixman_box32_t *extents = | ||||
| 			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, | ||||
| 			.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); | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -645,6 +645,7 @@ static void seat_view_destroy(struct roots_seat_view *seat_view) { | |||
| 		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->link); | ||||
| 	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) { | ||||
| 	struct roots_seat_view *seat_view = | ||||
| 		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); | ||||
| 
 | ||||
| 	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; | ||||
| 	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); | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
| 	struct roots_wl_shell_surface *roots_surface = | ||||
| 		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) { | ||||
| 	struct roots_wl_shell_surface *roots_surface = | ||||
| 		wl_container_of(listener, roots_surface, destroy); | ||||
| 	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); | ||||
| 	wl_list_remove(&roots_surface->view->link); | ||||
| 	view_finish(roots_surface->view); | ||||
| 	free(roots_surface->view); | ||||
| 	free(roots_surface); | ||||
| 	view_destroy(roots_surface->view); | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
| 	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) { | ||||
| 		free(roots_surface); | ||||
| 		return; | ||||
|  | @ -238,13 +241,12 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) { | |||
| 
 | ||||
| 	view->wl_shell_surface = surface; | ||||
| 	view->roots_wl_shell_surface = roots_surface; | ||||
| 	view->wlr_surface = surface->surface; | ||||
| 	view->resize = resize; | ||||
| 	view->close = close; | ||||
| 	view->destroy = destroy; | ||||
| 	roots_surface->view = view; | ||||
| 	view_init(view, desktop); | ||||
| 	wl_list_insert(&desktop->views, &view->link); | ||||
| 
 | ||||
| 	view_map(view, surface->surface); | ||||
| 	view_setup(view); | ||||
| 
 | ||||
| 	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); | ||||
| 	struct wlr_xdg_surface *surface = view->xdg_surface; | ||||
| 
 | ||||
| 	if (surface->geometry->width > 0 && surface->geometry->height > 0) { | ||||
| 		box->width = surface->geometry->width; | ||||
| 		box->height = surface->geometry->height; | ||||
| 	} else { | ||||
| 	if (surface->geometry.width > 0 && surface->geometry.height > 0) { | ||||
| 		box->width = surface->geometry.width; | ||||
| 		box->height = surface->geometry.height; | ||||
| 	} else if (view->wlr_surface != NULL) { | ||||
| 		box->width = view->wlr_surface->current->width; | ||||
| 		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_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) { | ||||
| 		*dest_width = state->min_width; | ||||
| 	} 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) { | ||||
| 	struct roots_xdg_surface *roots_xdg_surface = | ||||
| 		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; | ||||
| 	} | ||||
| 
 | ||||
| 	view_maximize(view, surface->toplevel_state->next.maximized); | ||||
| 	view_maximize(view, surface->toplevel->next.maximized); | ||||
| } | ||||
| 
 | ||||
| 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 wlr_xdg_surface *surface = view->xdg_surface; | ||||
| 
 | ||||
| 	if (!surface->mapped) { | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	view_apply_damage(view); | ||||
| 
 | ||||
| 	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); | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
| 	struct roots_xdg_surface *roots_xdg_surface = | ||||
| 		wl_container_of(listener, roots_xdg_surface, destroy); | ||||
| 	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->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); | ||||
| 	view_destroy(roots_xdg_surface->view); | ||||
| } | ||||
| 
 | ||||
| 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->destroy.notify = handle_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; | ||||
| 	wl_signal_add(&surface->events.request_move, &roots_surface->request_move); | ||||
| 	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; | ||||
| 	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) { | ||||
| 		free(roots_surface); | ||||
| 		return; | ||||
|  | @ -342,22 +377,19 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) { | |||
| 
 | ||||
| 	view->xdg_surface = surface; | ||||
| 	view->roots_xdg_surface = roots_surface; | ||||
| 	view->wlr_surface = surface->surface; | ||||
| 	view->activate = activate; | ||||
| 	view->resize = resize; | ||||
| 	view->move_resize = move_resize; | ||||
| 	view->maximize = maximize; | ||||
| 	view->set_fullscreen = set_fullscreen; | ||||
| 	view->close = close; | ||||
| 	view->destroy = destroy; | ||||
| 	roots_surface->view = view; | ||||
| 
 | ||||
| 	struct wlr_box box; | ||||
| 	get_size(view, &box); | ||||
| 	view->width = box.width; | ||||
| 	view->height = box.height; | ||||
| 
 | ||||
| 	view_init(view, desktop); | ||||
| 	wl_list_insert(&desktop->views, &view->link); | ||||
| 
 | ||||
| 	view_setup(view); | ||||
| 	if (surface->toplevel->next.maximized) { | ||||
| 		view_maximize(view, true); | ||||
| 	} | ||||
| 	if (surface->toplevel->next.fullscreen) { | ||||
| 		view_set_fullscreen(view, true, NULL); | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -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); | ||||
| 	struct wlr_xdg_surface_v6 *surface = view->xdg_surface_v6; | ||||
| 
 | ||||
| 	if (surface->geometry->width > 0 && surface->geometry->height > 0) { | ||||
| 		box->width = surface->geometry->width; | ||||
| 		box->height = surface->geometry->height; | ||||
| 	} else { | ||||
| 	if (surface->geometry.width > 0 && surface->geometry.height > 0) { | ||||
| 		box->width = surface->geometry.width; | ||||
| 		box->height = surface->geometry.height; | ||||
| 	} else if (view->wlr_surface != NULL) { | ||||
| 		box->width = view->wlr_surface->current->width; | ||||
| 		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_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) { | ||||
| 		*dest_width = state->min_width; | ||||
| 	} 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) { | ||||
| 	struct roots_xdg_surface_v6 *roots_xdg_surface = | ||||
| 		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; | ||||
| 	} | ||||
| 
 | ||||
| 	view_maximize(view, surface->toplevel_state->next.maximized); | ||||
| 	view_maximize(view, surface->toplevel->next.maximized); | ||||
| } | ||||
| 
 | ||||
| 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 wlr_xdg_surface_v6 *surface = view->xdg_surface_v6; | ||||
| 
 | ||||
| 	if (!surface->mapped) { | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	view_apply_damage(view); | ||||
| 
 | ||||
| 	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); | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
| 	struct roots_xdg_surface_v6 *roots_xdg_surface = | ||||
| 		wl_container_of(listener, roots_xdg_surface, destroy); | ||||
| 	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->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); | ||||
| 	view_destroy(roots_xdg_surface->view); | ||||
| } | ||||
| 
 | ||||
| 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->destroy.notify = handle_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; | ||||
| 	wl_signal_add(&surface->events.request_move, &roots_surface->request_move); | ||||
| 	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; | ||||
| 	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) { | ||||
| 		free(roots_surface); | ||||
| 		return; | ||||
|  | @ -342,22 +377,19 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { | |||
| 
 | ||||
| 	view->xdg_surface_v6 = surface; | ||||
| 	view->roots_xdg_surface_v6 = roots_surface; | ||||
| 	view->wlr_surface = surface->surface; | ||||
| 	view->activate = activate; | ||||
| 	view->resize = resize; | ||||
| 	view->move_resize = move_resize; | ||||
| 	view->maximize = maximize; | ||||
| 	view->set_fullscreen = set_fullscreen; | ||||
| 	view->close = close; | ||||
| 	view->destroy = destroy; | ||||
| 	roots_surface->view = view; | ||||
| 
 | ||||
| 	struct wlr_box box; | ||||
| 	get_size(view, &box); | ||||
| 	view->width = box.width; | ||||
| 	view->height = box.height; | ||||
| 
 | ||||
| 	view_init(view, desktop); | ||||
| 	wl_list_insert(&desktop->views, &view->link); | ||||
| 
 | ||||
| 	view_setup(view); | ||||
| 	if (surface->toplevel->next.maximized) { | ||||
| 		view_maximize(view, true); | ||||
| 	} | ||||
| 	if (surface->toplevel->next.fullscreen) { | ||||
| 		view_set_fullscreen(view, true, NULL); | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -106,11 +106,9 @@ static void set_fullscreen(struct roots_view *view, bool fullscreen) { | |||
| 	wlr_xwayland_surface_set_fullscreen(view->xwayland_surface, fullscreen); | ||||
| } | ||||
| 
 | ||||
| static void handle_destroy(struct wl_listener *listener, void *data) { | ||||
| 	struct roots_xwayland_surface *roots_surface = | ||||
| 		wl_container_of(listener, roots_surface, destroy); | ||||
| 	struct wlr_xwayland_surface *xwayland_surface = | ||||
| 		roots_surface->view->xwayland_surface; | ||||
| static void destroy(struct roots_view *view) { | ||||
| 	assert(view->type == ROOTS_XWAYLAND_VIEW); | ||||
| 	struct roots_xwayland_surface *roots_surface = view->roots_xwayland_surface; | ||||
| 	wl_list_remove(&roots_surface->destroy.link); | ||||
| 	wl_list_remove(&roots_surface->request_configure.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->map_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); | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
| 	struct roots_xwayland_surface *roots_surface = | ||||
| 		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); | ||||
| 	struct wlr_xwayland_surface *xsurface = data; | ||||
| 	struct roots_view *view = roots_surface->view; | ||||
| 	struct roots_desktop *desktop = view->desktop; | ||||
| 
 | ||||
| 	view->wlr_surface = xsurface->surface; | ||||
| 	view->x = xsurface->x; | ||||
| 	view->y = xsurface->y; | ||||
| 	view->width = xsurface->surface->current->width; | ||||
| 	view->height = xsurface->surface->current->height; | ||||
| 	wl_list_insert(&desktop->views, &view->link); | ||||
| 
 | ||||
| 	struct wlr_subsurface *subsurface; | ||||
| 	wl_list_for_each(subsurface, &view->wlr_surface->subsurface_list, | ||||
| 			parent_link) { | ||||
| 		subsurface_create(view, subsurface); | ||||
| 	} | ||||
| 
 | ||||
| 	view_damage_whole(view); | ||||
| 	view_map(view, xsurface->surface); | ||||
| 
 | ||||
| 	roots_surface->surface_commit.notify = handle_surface_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); | ||||
| 
 | ||||
| 	view_damage_whole(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); | ||||
| 	view_unmap(view); | ||||
| } | ||||
| 
 | ||||
| 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, | ||||
| 		&roots_surface->surface_commit); | ||||
| 
 | ||||
| 	struct roots_view *view = view_create(); | ||||
| 	struct roots_view *view = view_create(desktop); | ||||
| 	if (view == NULL) { | ||||
| 		free(roots_surface); | ||||
| 		return; | ||||
|  | @ -330,7 +305,6 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) { | |||
| 
 | ||||
| 	view->xwayland_surface = surface; | ||||
| 	view->roots_xwayland_surface = roots_surface; | ||||
| 	view->wlr_surface = surface->surface; | ||||
| 	view->activate = activate; | ||||
| 	view->resize = resize; | ||||
| 	view->move = move; | ||||
|  | @ -338,9 +312,10 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) { | |||
| 	view->maximize = maximize; | ||||
| 	view->set_fullscreen = set_fullscreen; | ||||
| 	view->close = close; | ||||
| 	view->destroy = destroy; | ||||
| 	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->decorations == WLR_XWAYLAND_SURFACE_DECORATIONS_ALL) { | ||||
|  |  | |||
|  | @ -6,10 +6,13 @@ lib_wlr_types = static_library( | |||
| 		'wlr_cursor.c', | ||||
| 		'wlr_data_device.c', | ||||
| 		'wlr_gamma_control.c', | ||||
| 		'wlr_idle_inhibit_v1.c', | ||||
| 		'wlr_idle.c', | ||||
| 		'wlr_input_device.c', | ||||
| 		'wlr_keyboard.c', | ||||
| 		'wlr_linux_dmabuf.c', | ||||
| 		'wlr_list.c', | ||||
| 		'wlr_matrix.c', | ||||
| 		'wlr_output_damage.c', | ||||
| 		'wlr_output_layout.c', | ||||
| 		'wlr_output.c', | ||||
|  | @ -27,7 +30,6 @@ lib_wlr_types = static_library( | |||
| 		'wlr_xcursor_manager.c', | ||||
| 		'wlr_xdg_shell_v6.c', | ||||
| 		'wlr_xdg_shell.c', | ||||
| 		'wlr_idle_inhibit_v1.c', | ||||
| 	), | ||||
| 	include_directories: wlr_inc, | ||||
| 	dependencies: [pixman, xkbcommon, wayland_server, wlr_protos], | ||||
|  |  | |||
|  | @ -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; | ||||
| } | ||||
|  | @ -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 <wayland-server.h> | ||||
| #include <wlr/interfaces/wlr_output.h> | ||||
| #include <wlr/render.h> | ||||
| #include <wlr/render/matrix.h> | ||||
| #include <wlr/render/wlr_renderer.h> | ||||
| #include <wlr/types/wlr_matrix.h> | ||||
| #include <wlr/types/wlr_box.h> | ||||
| #include <wlr/types/wlr_output.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) { | ||||
| 	wlr_matrix_texture(output->transform_matrix, output->width, output->height, | ||||
| 		output->transform); | ||||
| 	wlr_matrix_projection(output->transform_matrix, output->width, | ||||
| 		output->height, output->transform); | ||||
| } | ||||
| 
 | ||||
| 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); | ||||
| 
 | ||||
| 	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; | ||||
| 	} | ||||
| 
 | ||||
| 	struct wlr_box box; | ||||
| 	output_fullscreen_surface_get_box(output, surface, &box); | ||||
| 
 | ||||
| 	float matrix[16]; | ||||
| 	float matrix[9]; | ||||
| 	enum wl_output_transform transform = | ||||
| 		wlr_output_transform_invert(surface->current->transform); | ||||
| 	wlr_matrix_project_box(&matrix, &box, transform, 0, | ||||
| 		&output->transform_matrix); | ||||
| 	wlr_matrix_project_box(matrix, &box, transform, 0, | ||||
| 		output->transform_matrix); | ||||
| 
 | ||||
| 	int nrects; | ||||
| 	pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); | ||||
| 	for (int i = 0; i < nrects; ++i) { | ||||
| 		output_scissor(output, &rects[i]); | ||||
| 		wlr_renderer_clear(renderer, &(float[]){0, 0, 0, 0}); | ||||
| 		wlr_render_with_matrix(surface->renderer, surface->texture, &matrix, 1.0f); | ||||
| 		wlr_renderer_clear(renderer, (float[]){0, 0, 0, 0}); | ||||
| 		wlr_render_texture_with_matrix(surface->renderer, surface->texture, matrix, 1.0f); | ||||
| 	} | ||||
| 	wlr_renderer_scissor(renderer, NULL); | ||||
| 
 | ||||
|  | @ -435,15 +435,15 @@ static void output_cursor_render(struct wlr_output_cursor *cursor, | |||
| 		goto surface_damage_finish; | ||||
| 	} | ||||
| 
 | ||||
| 	float matrix[16]; | ||||
| 	wlr_matrix_project_box(&matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0, | ||||
| 		&cursor->output->transform_matrix); | ||||
| 	float matrix[9]; | ||||
| 	wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0, | ||||
| 		cursor->output->transform_matrix); | ||||
| 
 | ||||
| 	int nrects; | ||||
| 	pixman_box32_t *rects = pixman_region32_rectangles(&surface_damage, &nrects); | ||||
| 	for (int i = 0; i < nrects; ++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); | ||||
| 
 | ||||
|  |  | |||
|  | @ -14,7 +14,10 @@ void wlr_pointer_init(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); | ||||
| 	} else { | ||||
| 		wl_list_remove(&pointer->events.motion.listener_list); | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ | |||
| #include <string.h> | ||||
| #include <wayland-server.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_screenshooter.h> | ||||
| #include <wlr/util/log.h> | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ | |||
| #include <wayland-server.h> | ||||
| #include <wlr/render/egl.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_surface.h> | ||||
| #include <wlr/util/log.h> | ||||
|  | @ -325,6 +325,10 @@ static void wlr_surface_apply_damage(struct wlr_surface *surface, | |||
| 					surface->current->buffer)) { | ||||
| 			wlr_texture_upload_drm(surface->texture, surface->current->buffer); | ||||
| 			goto release; | ||||
| 		} else if (wlr_dmabuf_resource_is_buffer( | ||||
| 					   surface->current->buffer)) { | ||||
| 			wlr_texture_upload_dmabuf(surface->texture, surface->current->buffer); | ||||
| 			goto release; | ||||
| 		} else { | ||||
| 			wlr_log(L_INFO, "Unknown buffer handle attached"); | ||||
| 			return; | ||||
|  | @ -624,22 +628,6 @@ struct wlr_surface *wlr_surface_create(struct wl_resource *res, | |||
| 	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) { | ||||
| 	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_crtc_props; | ||||
|         wlr_drm_get_plane_props; | ||||
|         wlr_drm_get_prop; | ||||
|         wlr_drm_get_prop_blob; | ||||
|         wlr_drm_get_prop; | ||||
|         wlr_drm_plane_surfaces_init; | ||||
|         wlr_drm_renderer_finish; | ||||
|         wlr_drm_renderer_init; | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue