diff options
Diffstat (limited to 'backend')
| -rw-r--r-- | backend/drm/atomic.c | 2 | ||||
| -rw-r--r-- | backend/drm/backend.c | 9 | ||||
| -rw-r--r-- | backend/drm/drm.c | 255 | ||||
| -rw-r--r-- | backend/drm/renderer.c | 321 | ||||
| -rw-r--r-- | backend/drm/util.c | 8 | 
5 files changed, 342 insertions, 253 deletions
diff --git a/backend/drm/atomic.c b/backend/drm/atomic.c index 71b18f98..05dd9d1f 100644 --- a/backend/drm/atomic.c +++ b/backend/drm/atomic.c @@ -172,7 +172,7 @@ static bool atomic_crtc_set_cursor(struct wlr_drm_backend *drm,  	if (bo) {  		uint32_t fb_id = -			get_fb_for_bo(bo, plane->drm_format, drm->addfb2_modifiers); +			get_fb_for_bo(bo, drm->addfb2_modifiers);  		set_plane_props(&atom, plane, crtc->id, fb_id, false);  	} else {  		atomic_add(&atom, plane->id, plane->props.fb_id, 0); diff --git a/backend/drm/backend.c b/backend/drm/backend.c index a58af02c..7aeaa01e 100644 --- a/backend/drm/backend.c +++ b/backend/drm/backend.c @@ -105,8 +105,13 @@ static void session_signal(struct wl_listener *listener, void *data) {  			}  			struct wlr_drm_plane *plane = conn->crtc->cursor; -			drm->iface->crtc_set_cursor(drm, conn->crtc, -				(plane && plane->cursor_enabled) ? plane->surf.back : NULL); +			struct gbm_bo *bo = NULL; +			if (plane->cursor_enabled) { +				bo = drm_fb_acquire(&plane->current_fb, drm, +					&plane->mgpu_surf); +			} + +			drm->iface->crtc_set_cursor(drm, conn->crtc, bo);  			drm->iface->crtc_move_cursor(drm, conn->crtc, conn->cursor_x,  				conn->cursor_y); diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 9be67244..ed74c7d1 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -331,7 +331,37 @@ static struct wlr_drm_connector *get_drm_connector_from_output(  static bool drm_connector_attach_render(struct wlr_output *output,  		int *buffer_age) {  	struct wlr_drm_connector *conn = get_drm_connector_from_output(output); -	return make_drm_surface_current(&conn->crtc->primary->surf, buffer_age); +	return drm_surface_make_current(&conn->crtc->primary->surf, buffer_age); +} + +static bool drm_crtc_page_flip(struct wlr_drm_connector *conn, +		struct wlr_drm_mode *mode) { +	struct wlr_drm_backend *drm = get_drm_backend_from_backend(conn->output.backend); +	struct wlr_drm_crtc *crtc = conn->crtc; +	struct wlr_drm_plane *plane = crtc->primary; +	struct gbm_bo *bo; +	uint32_t fb_id; +	drmModeModeInfo *drm_mode = mode ? &mode->drm_mode : NULL; + +	if (conn->pageflip_pending) { +		wlr_log(WLR_ERROR, "Skipping pageflip on output '%s'", conn->output.name); +		return false; +	} + +	bo = drm_fb_acquire(&plane->queued_fb, drm, &plane->mgpu_surf); +	if (!bo) { +		return false; +	} + +	fb_id = get_fb_for_bo(bo, drm->addfb2_modifiers); +	if (!drm->iface->crtc_pageflip(drm, conn, crtc, fb_id, drm_mode)) { +		return false; +	} + +	conn->pageflip_pending = true; +	drm_fb_move(&crtc->primary->queued_fb, &crtc->primary->pending_fb); +	wlr_output_update_enabled(&conn->output, true); +	return true;  }  static uint32_t strip_alpha_channel(uint32_t format) { @@ -405,76 +435,31 @@ static bool drm_connector_commit_buffer(struct wlr_output *output) {  	}  	struct wlr_drm_plane *plane = crtc->primary; -	pixman_region32_t *damage = NULL; -	if (output->pending.committed & WLR_OUTPUT_STATE_DAMAGE) { -		damage = &output->pending.damage; -	} - -	struct gbm_bo *bo; -	uint32_t fb_id = 0;  	assert(output->pending.committed & WLR_OUTPUT_STATE_BUFFER);  	switch (output->pending.buffer_type) {  	case WLR_OUTPUT_STATE_BUFFER_RENDER: -		bo = swap_drm_surface_buffers(&plane->surf, damage); -		if (bo == NULL) { -			wlr_log(WLR_ERROR, "swap_drm_surface_buffers failed"); -			return false; -		} - -		if (drm->parent) { -			bo = copy_drm_surface_mgpu(&plane->mgpu_surf, bo); -			if (bo == NULL) { -				wlr_log(WLR_ERROR, "copy_drm_surface_mgpu failed"); -				return false; -			} -		} -		fb_id = get_fb_for_bo(bo, plane->drm_format, drm->addfb2_modifiers); -		if (fb_id == 0) { -			wlr_log(WLR_ERROR, "get_fb_for_bo failed"); +		if (!drm_fb_lock_surface(&plane->pending_fb, &plane->surf)) { +			wlr_log(WLR_ERROR, "drm_fb_lock_surface failed");  			return false;  		}  		break;  	case WLR_OUTPUT_STATE_BUFFER_SCANOUT:; -		struct wlr_dmabuf_attributes attribs; -		if (!wlr_buffer_get_dmabuf(output->pending.buffer, &attribs)) { -			return false; -		} - -		bo = import_gbm_bo(&drm->renderer, &attribs); -		if (bo == NULL) { -			wlr_log(WLR_ERROR, "import_gbm_bo failed"); +		struct wlr_buffer *buffer = output->pending.buffer; +		if (!test_buffer(conn, output->pending.buffer)) {  			return false;  		} - -		if (conn->pending_bo != NULL) { -			gbm_bo_destroy(conn->pending_bo); -		} -		conn->pending_bo = bo; - -		fb_id = get_fb_for_bo(bo, gbm_bo_get_format(bo), drm->addfb2_modifiers); -		if (fb_id == 0) { -			wlr_log(WLR_ERROR, "get_fb_for_bo failed"); +		if (!drm_fb_import_wlr(&plane->pending_fb, &drm->renderer, buffer, +				&crtc->primary->formats)) {  			return false;  		}  		break;  	} -	if (conn->pageflip_pending) { -		wlr_log(WLR_ERROR, "Skipping pageflip on output '%s'", conn->output.name); -		return false; -	} - -	if (!drm->iface->crtc_pageflip(drm, conn, crtc, fb_id, NULL)) { +	if (!drm_crtc_page_flip(conn, NULL)) { +		drm_fb_clear(&plane->pending_fb);  		return false;  	} -	conn->pageflip_pending = true; -	if (output->pending.buffer_type == WLR_OUTPUT_STATE_BUFFER_SCANOUT) { -		wlr_buffer_unlock(conn->pending_buffer); -		conn->pending_buffer = wlr_buffer_lock(output->pending.buffer); -	} - -	wlr_output_update_enabled(output, true);  	return true;  } @@ -648,37 +633,54 @@ static bool drm_connector_export_dmabuf(struct wlr_output *output,  		struct wlr_dmabuf_attributes *attribs) {  	struct wlr_drm_connector *conn = get_drm_connector_from_output(output);  	struct wlr_drm_backend *drm = get_drm_backend_from_backend(output->backend); +	struct wlr_drm_crtc *crtc = conn->crtc;  	if (!drm->session->active) {  		return false;  	} -	struct wlr_drm_crtc *crtc = conn->crtc;  	if (!crtc) {  		return false;  	} +  	struct wlr_drm_plane *plane = crtc->primary; -	struct wlr_drm_surface *surf = &plane->surf; -	return export_drm_bo(surf->back, attribs); +	if (plane->current_fb.type == WLR_DRM_FB_TYPE_NONE) { +		return false; +	} + +	return export_drm_bo(plane->current_fb.bo, attribs); +} + +struct wlr_drm_fb *plane_get_next_fb(struct wlr_drm_plane *plane) { +	if (plane->pending_fb.type != WLR_DRM_FB_TYPE_NONE) { +		return &plane->pending_fb; +	} +	if (plane->queued_fb.type != WLR_DRM_FB_TYPE_NONE) { +		return &plane->queued_fb; +	} +	return &plane->current_fb;  }  static bool drm_connector_pageflip_renderer(struct wlr_drm_connector *conn,  		struct wlr_drm_mode *mode) { -	struct wlr_drm_backend *drm = -		get_drm_backend_from_backend(conn->output.backend);  	struct wlr_drm_crtc *crtc = conn->crtc;  	if (!crtc) {  		wlr_log(WLR_ERROR, "Page-flip failed on connector '%s': no CRTC",  			conn->output.name);  		return false;  	} + +	// drm_crtc_page_flip expects a FB to be available  	struct wlr_drm_plane *plane = crtc->primary; +	if (plane_get_next_fb(plane)->type == WLR_DRM_FB_TYPE_NONE) { +		drm_surface_render_black_frame(&plane->surf); +		if (!drm_fb_lock_surface(&plane->pending_fb, &plane->surf)) { +			return false; +		} +	} -	struct gbm_bo *bo = get_drm_surface_front( -		drm->parent ? &plane->mgpu_surf : &plane->surf); -	uint32_t fb_id = get_fb_for_bo(bo, plane->drm_format, drm->addfb2_modifiers); -	return drm->iface->crtc_pageflip(drm, conn, crtc, fb_id, &mode->drm_mode); +	return drm_crtc_page_flip(conn, mode);  }  static void drm_connector_start_renderer(struct wlr_drm_connector *conn) { @@ -689,10 +691,7 @@ static void drm_connector_start_renderer(struct wlr_drm_connector *conn) {  	wlr_log(WLR_DEBUG, "Starting renderer on output '%s'", conn->output.name);  	struct wlr_drm_mode *mode = (struct wlr_drm_mode *)conn->output.current_mode; -	if (drm_connector_pageflip_renderer(conn, mode)) { -		conn->pageflip_pending = true; -		wlr_output_update_enabled(&conn->output, true); -	} else { +	if (!drm_connector_pageflip_renderer(conn, mode)) {  		wl_event_source_timer_update(conn->retry_pageflip,  			1000000.0f / conn->output.current_mode->refresh);  	} @@ -731,7 +730,7 @@ static bool drm_connector_init_renderer(struct wlr_drm_connector *conn,  		modifiers = false;  	} -	if (!init_drm_plane_surfaces(plane, drm, width, height, format, modifiers) || +	if (!drm_plane_init_surface(plane, drm, width, height, format, 0, modifiers) ||  			!drm_connector_pageflip_renderer(conn, mode)) {  		if (!modifiers) {  			wlr_log(WLR_ERROR, "Failed to initialize renderer " @@ -742,14 +741,12 @@ static bool drm_connector_init_renderer(struct wlr_drm_connector *conn,  		// If page-flipping with modifiers enabled doesn't work, retry without  		// modifiers -		finish_drm_surface(&plane->surf); -		finish_drm_surface(&plane->mgpu_surf);  		wlr_log(WLR_INFO, "Page-flip failed with primary FB modifiers enabled, "  			"retrying without modifiers");  		modifiers = false; -		if (!init_drm_plane_surfaces(plane, drm, width, height, format, -				modifiers)) { +		if (!drm_plane_init_surface(plane, drm, width, height, format, +				0, modifiers)) {  			return false;  		}  		if (!drm_connector_pageflip_renderer(conn, mode)) { @@ -908,8 +905,8 @@ static bool drm_connector_set_cursor(struct wlr_output *output,  		int32_t hotspot_x, int32_t hotspot_y, bool update_texture) {  	struct wlr_drm_connector *conn = get_drm_connector_from_output(output);  	struct wlr_drm_backend *drm = get_drm_backend_from_backend(output->backend); -  	struct wlr_drm_crtc *crtc = conn->crtc; +  	if (!crtc) {  		return false;  	} @@ -933,31 +930,15 @@ static bool drm_connector_set_cursor(struct wlr_output *output,  		ret = drmGetCap(drm->fd, DRM_CAP_CURSOR_HEIGHT, &h);  		h = ret ? 64 : h; -		if (!drm->parent) { -			if (!init_drm_surface(&plane->surf, &drm->renderer, w, h, -					drm->renderer.gbm_format, NULL, -					GBM_BO_USE_LINEAR | GBM_BO_USE_SCANOUT)) { -				wlr_log(WLR_ERROR, "Cannot allocate cursor resources"); -				return false; -			} -		} else { -			if (!init_drm_surface(&plane->surf, &drm->parent->renderer, w, h, -					drm->parent->renderer.gbm_format, NULL, -					GBM_BO_USE_LINEAR)) { -				wlr_log(WLR_ERROR, "Cannot allocate cursor resources"); -				return false; -			} - -			if (!init_drm_surface(&plane->mgpu_surf, &drm->renderer, w, h, -					drm->renderer.gbm_format, NULL, -					GBM_BO_USE_LINEAR | GBM_BO_USE_SCANOUT)) { -				wlr_log(WLR_ERROR, "Cannot allocate cursor resources"); -				return false; -			} +		if (!drm_plane_init_surface(plane, drm, w, h, +				DRM_FORMAT_ARGB8888, GBM_BO_USE_LINEAR, false)) { +			wlr_log(WLR_ERROR, "Cannot allocate cursor resources"); +			return false;  		}  	} -	wlr_matrix_projection(plane->matrix, plane->surf.width, +	float hotspot_proj[9]; +	wlr_matrix_projection(hotspot_proj, plane->surf.width,  		plane->surf.height, output->transform);  	struct wlr_box hotspot = { .x = hotspot_x, .y = hotspot_y }; @@ -999,21 +980,23 @@ static bool drm_connector_set_cursor(struct wlr_output *output,  			return false;  		} -		make_drm_surface_current(&plane->surf, NULL); +		drm_surface_make_current(&plane->surf, NULL);  		struct wlr_renderer *rend = plane->surf.renderer->wlr_rend;  		struct wlr_box cursor_box = { .width = width, .height = height };  		float matrix[9]; -		wlr_matrix_project_box(matrix, &cursor_box, transform, 0, plane->matrix); +		wlr_matrix_project_box(matrix, &cursor_box, transform, 0, hotspot_proj);  		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_with_matrix(rend, texture, matrix, 1.0);  		wlr_renderer_end(rend); -		swap_drm_surface_buffers(&plane->surf, NULL); +		if (!drm_fb_lock_surface(&plane->pending_fb, &plane->surf)) { +			return false; +		}  		plane->cursor_enabled = true;  	} @@ -1022,25 +1005,30 @@ static bool drm_connector_set_cursor(struct wlr_output *output,  		return true; // will be committed when session is resumed  	} -	struct gbm_bo *bo = plane->cursor_enabled ? plane->surf.back : NULL; -	if (bo && drm->parent) { -		bo = copy_drm_surface_mgpu(&plane->mgpu_surf, bo); -	} +	struct gbm_bo *bo = NULL; + +	if (plane->cursor_enabled) { +		bo = drm_fb_acquire(&plane->pending_fb, drm, &plane->mgpu_surf); + +		wlr_log(WLR_DEBUG, "SET_CURSOR %p %p", plane->pending_fb.bo, bo); -	if (bo) { -		// workaround for nouveau -		// Buffers created with GBM_BO_USER_LINEAR are placed in NOUVEAU_GEM_DOMAIN_GART. -		// When the bo is attached to the cursor plane it is moved to NOUVEAU_GEM_DOMAIN_VRAM. -		// However, this does not wait for the render operations to complete, leaving an empty surface. -		// see https://bugs.freedesktop.org/show_bug.cgi?id=109631 -		// The render operations can be waited for using: +		/* Workaround for nouveau buffers created with GBM_BO_USER_LINEAR are +		 * placed in NOUVEAU_GEM_DOMAIN_GART. When the bo is attached to the +		 * cursor plane it is moved to NOUVEAU_GEM_DOMAIN_VRAM. However, this +		 * does not wait for the render operations to complete, leaving an +		 * empty surface. See +		 * https://gitlab.freedesktop.org/xorg/driver/xf86-video-nouveau/issues/480 +		 * The render operations can be waited for using: +		 */  		glFinish();  	} -	bool ok = drm->iface->crtc_set_cursor(drm, crtc, bo); -	if (ok) { -		wlr_output_update_needs_frame(output); + +	if (!drm->iface->crtc_set_cursor(drm, crtc, bo)) { +		return false;  	} -	return ok; + +	wlr_output_update_needs_frame(output); +	return true;  }  static bool drm_connector_move_cursor(struct wlr_output *output, @@ -1133,8 +1121,8 @@ static void dealloc_crtc(struct wlr_drm_connector *conn) {  		conn->crtc - drm->crtcs, conn->output.name);  	set_drm_connector_gamma(&conn->output, 0, NULL, NULL, NULL); -	finish_drm_surface(&conn->crtc->primary->surf); -	finish_drm_surface(&conn->crtc->cursor->surf); +	drm_plane_finish_surface(conn->crtc->primary); +	drm_plane_finish_surface(conn->crtc->cursor);  	drm->iface->conn_enable(drm, conn, false); @@ -1544,15 +1532,15 @@ static int mhz_to_nsec(int mhz) {  static void page_flip_handler(int fd, unsigned seq,  		unsigned tv_sec, unsigned tv_usec, unsigned crtc_id, void *data) {  	struct wlr_drm_backend *drm = data; +  	struct wlr_drm_connector *conn = NULL;  	struct wlr_drm_connector *search; -  	wl_list_for_each(search, &drm->outputs, link) {  		if (search->crtc && search->crtc->id == crtc_id) {  			conn = search; +			break;  		}  	} -  	if (!conn) {  		wlr_log(WLR_DEBUG, "No connector for crtc_id %u", crtc_id);  		return; @@ -1564,27 +1552,24 @@ static void page_flip_handler(int fd, unsigned seq,  		return;  	} -	// Release the old buffer as it's not displayed anymore. The pending -	// buffer becomes the current buffer. -	wlr_buffer_unlock(conn->current_buffer); -	conn->current_buffer = conn->pending_buffer; -	conn->pending_buffer = NULL; - -	if (conn->current_bo != NULL) { -		gbm_bo_destroy(conn->current_bo); +	struct wlr_drm_plane *plane = conn->crtc->primary; +	if (plane->queued_fb.type != WLR_DRM_FB_TYPE_NONE) { +		drm_fb_move(&plane->current_fb, &plane->queued_fb); +	} +	if (conn->crtc->cursor && +			conn->crtc->cursor->queued_fb.type != WLR_DRM_FB_TYPE_NONE) { +		drm_fb_move(&conn->crtc->cursor->current_fb, +			&conn->crtc->cursor->queued_fb);  	} -	conn->current_bo = conn->pending_bo; -	conn->pending_bo = NULL;  	uint32_t present_flags = WLR_OUTPUT_PRESENT_VSYNC |  		WLR_OUTPUT_PRESENT_HW_CLOCK | WLR_OUTPUT_PRESENT_HW_COMPLETION; -	if (conn->current_buffer != NULL) { +	/* Don't report ZERO_COPY in multi-gpu situations, because we had to copy +	 * data between the GPUs, even if we were using the direct scanout +	 * interface. +	 */ +	if (!drm->parent && plane->current_fb.type == WLR_DRM_FB_TYPE_WLR_BUFFER) {  		present_flags |= WLR_OUTPUT_PRESENT_ZERO_COPY; -	} else { -		post_drm_surface(&conn->crtc->primary->surf); -		if (drm->parent) { -			post_drm_surface(&conn->crtc->primary->mgpu_surf); -		}  	}  	struct timespec present_time = { @@ -1687,10 +1672,6 @@ static void drm_connector_cleanup(struct wlr_drm_connector *conn) {  		conn->output.needs_frame = false;  		conn->output.frame_pending = false; -		wlr_buffer_unlock(conn->pending_buffer); -		wlr_buffer_unlock(conn->current_buffer); -		conn->pending_buffer = conn->current_buffer = NULL; -  		/* Fallthrough */  	case WLR_DRM_CONN_NEEDS_MODESET:  		wlr_log(WLR_INFO, "Emitting destruction signal for '%s'", diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index 8b295db1..4a16732c 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -3,6 +3,7 @@  #include <gbm.h>  #include <stdbool.h>  #include <stdlib.h> +#include <string.h>  #include <unistd.h>  #include <wayland-util.h>  #include <wlr/render/egl.h> @@ -61,7 +62,7 @@ void finish_drm_renderer(struct wlr_drm_renderer *renderer) {  	gbm_device_destroy(renderer->gbm);  } -bool init_drm_surface(struct wlr_drm_surface *surf, +static bool init_drm_surface(struct wlr_drm_surface *surf,  		struct wlr_drm_renderer *renderer, uint32_t width, uint32_t height,  		uint32_t format, struct wlr_drm_format_set *set, uint32_t flags) {  	if (surf->width == width && surf->height == height) { @@ -73,14 +74,6 @@ bool init_drm_surface(struct wlr_drm_surface *surf,  	surf->height = height;  	if (surf->gbm) { -		if (surf->front) { -			gbm_surface_release_buffer(surf->gbm, surf->front); -			surf->front = NULL; -		} -		if (surf->back) { -			gbm_surface_release_buffer(surf->gbm, surf->back); -			surf->back = NULL; -		}  		gbm_surface_destroy(surf->gbm);  		surf->gbm = NULL;  	} @@ -119,18 +112,11 @@ error_zero:  	return false;  } -void finish_drm_surface(struct wlr_drm_surface *surf) { +static void finish_drm_surface(struct wlr_drm_surface *surf) {  	if (!surf || !surf->renderer) {  		return;  	} -	if (surf->front) { -		gbm_surface_release_buffer(surf->gbm, surf->front); -	} -	if (surf->back) { -		gbm_surface_release_buffer(surf->gbm, surf->back); -	} -  	wlr_egl_destroy_surface(&surf->renderer->egl, surf->egl);  	if (surf->gbm) {  		gbm_surface_destroy(surf->gbm); @@ -139,82 +125,11 @@ void finish_drm_surface(struct wlr_drm_surface *surf) {  	memset(surf, 0, sizeof(*surf));  } -bool make_drm_surface_current(struct wlr_drm_surface *surf, +bool drm_surface_make_current(struct wlr_drm_surface *surf,  		int *buffer_damage) {  	return wlr_egl_make_current(&surf->renderer->egl, surf->egl, buffer_damage);  } -struct gbm_bo *swap_drm_surface_buffers(struct wlr_drm_surface *surf, -		pixman_region32_t *damage) { -	if (surf->front) { -		gbm_surface_release_buffer(surf->gbm, surf->front); -	} - -	wlr_egl_swap_buffers(&surf->renderer->egl, surf->egl, damage); - -	surf->front = surf->back; -	surf->back = gbm_surface_lock_front_buffer(surf->gbm); -	return surf->back; -} - -struct gbm_bo *get_drm_surface_front(struct wlr_drm_surface *surf) { -	if (surf->front) { -		return surf->front; -	} - -	make_drm_surface_current(surf, NULL); -	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 swap_drm_surface_buffers(surf, NULL); -} - -void post_drm_surface(struct wlr_drm_surface *surf) { -	if (surf->front) { -		gbm_surface_release_buffer(surf->gbm, surf->front); -		surf->front = NULL; -	} -} - -struct gbm_bo *import_gbm_bo(struct wlr_drm_renderer *renderer, -		struct wlr_dmabuf_attributes *attribs) { -	if (attribs->modifier == DRM_FORMAT_MOD_INVALID && attribs->n_planes == 1 -			&& attribs->offset[0] == 0) { -		struct gbm_import_fd_data data = { -			.fd = attribs->fd[0], -			.width = attribs->width, -			.height = attribs->height, -			.stride = attribs->stride[0], -			.format = attribs->format, -		}; - -		return gbm_bo_import(renderer->gbm, GBM_BO_IMPORT_FD, -			&data, GBM_BO_USE_SCANOUT); -	} else { -		struct gbm_import_fd_modifier_data data = { -			.width = attribs->width, -			.height = attribs->height, -			.format = attribs->format, -			.num_fds = attribs->n_planes, -			.modifier = attribs->modifier, -		}; - -		if ((size_t)attribs->n_planes > sizeof(data.fds) / sizeof(data.fds[0])) { -			return NULL; -		} - -		for (size_t i = 0; i < (size_t)attribs->n_planes; ++i) { -			data.fds[i] = attribs->fd[i]; -			data.strides[i] = attribs->stride[i]; -			data.offsets[i] = attribs->offset[i]; -		} - -		return gbm_bo_import(renderer->gbm, GBM_BO_IMPORT_FD_MODIFIER, -			&data, GBM_BO_USE_SCANOUT); -	} -} -  bool export_drm_bo(struct gbm_bo *bo, struct wlr_dmabuf_attributes *attribs) {  	memset(attribs, 0, sizeof(struct wlr_dmabuf_attributes)); @@ -268,46 +183,234 @@ static struct wlr_texture *get_tex_for_bo(struct wlr_drm_renderer *renderer,  	return tex;  } -struct gbm_bo *copy_drm_surface_mgpu(struct wlr_drm_surface *dest, -		struct gbm_bo *src) { -	make_drm_surface_current(dest, NULL); - -	struct wlr_texture *tex = get_tex_for_bo(dest->renderer, src); -	assert(tex); - -	float mat[9]; -	wlr_matrix_projection(mat, 1, 1, WL_OUTPUT_TRANSFORM_NORMAL); +void drm_plane_finish_surface(struct wlr_drm_plane *plane) { +	if (!plane) { +		return; +	} -	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, 0.0 }); -	wlr_render_texture_with_matrix(renderer, tex, mat, 1.0f); -	wlr_renderer_end(renderer); +	drm_fb_clear(&plane->pending_fb); +	drm_fb_clear(&plane->queued_fb); +	drm_fb_clear(&plane->current_fb); -	return swap_drm_surface_buffers(dest, NULL); +	finish_drm_surface(&plane->surf); +	finish_drm_surface(&plane->mgpu_surf);  } -bool init_drm_plane_surfaces(struct wlr_drm_plane *plane, +bool drm_plane_init_surface(struct wlr_drm_plane *plane,  		struct wlr_drm_backend *drm, int32_t width, uint32_t height, -		uint32_t format, bool with_modifiers) { +		uint32_t format, uint32_t flags, bool with_modifiers) {  	struct wlr_drm_format_set *format_set =  		with_modifiers ? &plane->formats : NULL; +	drm_plane_finish_surface(plane); +  	if (!drm->parent) {  		return init_drm_surface(&plane->surf, &drm->renderer, width, height, -			format, format_set, GBM_BO_USE_SCANOUT); +			format, format_set, flags | GBM_BO_USE_SCANOUT);  	}  	if (!init_drm_surface(&plane->surf, &drm->parent->renderer, -			width, height, format, NULL, GBM_BO_USE_LINEAR)) { +			width, height, format, NULL, +			flags | GBM_BO_USE_LINEAR)) {  		return false;  	}  	if (!init_drm_surface(&plane->mgpu_surf, &drm->renderer, -			width, height, format, format_set, GBM_BO_USE_SCANOUT)) { +			width, height, format, format_set, +			flags | GBM_BO_USE_SCANOUT)) {  		finish_drm_surface(&plane->surf);  		return false;  	}  	return true;  } + +void drm_fb_clear(struct wlr_drm_fb *fb) { +	switch (fb->type) { +	case WLR_DRM_FB_TYPE_NONE: +		assert(!fb->bo); +		break; +	case WLR_DRM_FB_TYPE_SURFACE: +		gbm_surface_release_buffer(fb->surf->gbm, fb->bo); +		break; +	case WLR_DRM_FB_TYPE_WLR_BUFFER: +		gbm_bo_destroy(fb->bo); +		wlr_buffer_unlock(fb->wlr_buf); +		fb->wlr_buf = NULL; +		break; +	} + +	fb->type = WLR_DRM_FB_TYPE_NONE; +	fb->bo = NULL; + +	if (fb->mgpu_bo) { +		assert(fb->mgpu_surf); +		gbm_surface_release_buffer(fb->mgpu_surf->gbm, fb->mgpu_bo); +		fb->mgpu_bo = NULL; +		fb->mgpu_surf = NULL; +	} +} + +bool drm_fb_lock_surface(struct wlr_drm_fb *fb, struct wlr_drm_surface *surf) { +	drm_fb_clear(fb); + +	if (!wlr_egl_swap_buffers(&surf->renderer->egl, surf->egl, NULL)) { +		wlr_log(WLR_ERROR, "Failed to swap buffers"); +		return false; +	} + +	fb->bo = gbm_surface_lock_front_buffer(surf->gbm); +	if (!fb->bo) { +		wlr_log(WLR_ERROR, "Failed to lock front buffer"); +		return false; +	} + +	fb->type = WLR_DRM_FB_TYPE_SURFACE; +	fb->surf = surf; +	return true; +} + +static uint32_t strip_alpha_channel(uint32_t format) { +	switch (format) { +	case DRM_FORMAT_ARGB8888: +		return DRM_FORMAT_XRGB8888; +	default: +		return DRM_FORMAT_INVALID; +	} +} + +bool drm_fb_import_wlr(struct wlr_drm_fb *fb, struct wlr_drm_renderer *renderer, +		struct wlr_buffer *buf, struct wlr_drm_format_set *set) { +	drm_fb_clear(fb); + +	struct wlr_dmabuf_attributes attribs; +	if (!wlr_buffer_get_dmabuf(buf, &attribs)) { +		return false; +	} + +	if (!wlr_drm_format_set_has(set, attribs.format, attribs.modifier)) { +		// The format isn't supported by the plane. Try stripping the alpha +		// channel, if any. +		uint32_t format = strip_alpha_channel(attribs.format); +		if (wlr_drm_format_set_has(set, format, attribs.modifier)) { +			attribs.format = format; +		} else { +			return false; +		} +	} + +	if (attribs.modifier != DRM_FORMAT_MOD_INVALID || +			attribs.n_planes > 1 || attribs.offset[0] != 0) { +		struct gbm_import_fd_modifier_data data = { +			.width = attribs.width, +			.height = attribs.height, +			.format = attribs.format, +			.num_fds = attribs.n_planes, +			.modifier = attribs.modifier, +		}; + +		if ((size_t)attribs.n_planes > sizeof(data.fds) / sizeof(data.fds[0])) { +			return false; +		} + +		for (size_t i = 0; i < (size_t)attribs.n_planes; ++i) { +			data.fds[i] = attribs.fd[i]; +			data.strides[i] = attribs.stride[i]; +			data.offsets[i] = attribs.offset[i]; +		} + +		fb->bo = gbm_bo_import(renderer->gbm, GBM_BO_IMPORT_FD_MODIFIER, +			&data, GBM_BO_USE_SCANOUT); +	} else { +		struct gbm_import_fd_data data = { +			.fd = attribs.fd[0], +			.width = attribs.width, +			.height = attribs.height, +			.stride = attribs.stride[0], +			.format = attribs.format, +		}; + +		fb->bo = gbm_bo_import(renderer->gbm, GBM_BO_IMPORT_FD, +			&data, GBM_BO_USE_SCANOUT); +	} + +	if (!fb->bo) { +		return false; +	} + +	fb->type = WLR_DRM_FB_TYPE_WLR_BUFFER; +	fb->wlr_buf = wlr_buffer_lock(buf); + +	return true; +} + +void drm_fb_move(struct wlr_drm_fb *new, struct wlr_drm_fb *old) { +	drm_fb_clear(new); + +	*new = *old; +	memset(old, 0, sizeof(*old)); +} + +bool drm_surface_render_black_frame(struct wlr_drm_surface *surf) { +	struct wlr_renderer *renderer = surf->renderer->wlr_rend; + +	if (!drm_surface_make_current(surf, NULL)) { +		return false; +	} + +	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 true; +} + +struct gbm_bo *drm_fb_acquire(struct wlr_drm_fb *fb, struct wlr_drm_backend *drm, +		struct wlr_drm_surface *mgpu) { +	if (!fb->bo) { +		wlr_log(WLR_ERROR, "Tried to acquire an FB with a NULL BO"); +		return NULL; +	} + +	if (!drm->parent) { +		return fb->bo; +	} + +	if (fb->mgpu_bo) { +		return fb->mgpu_bo; +	} + +	/* Perform copy across GPUs */ + +	struct wlr_renderer *renderer = mgpu->renderer->wlr_rend; + +	if (!drm_surface_make_current(mgpu, NULL)) { +		return NULL; +	} + +	struct wlr_texture *tex = get_tex_for_bo(mgpu->renderer, fb->bo); +	if (!tex) { +		return NULL; +	} + +	float mat[9]; +	wlr_matrix_projection(mat, 1, 1, WL_OUTPUT_TRANSFORM_NORMAL); + +	wlr_renderer_begin(renderer, mgpu->width, mgpu->height); +	wlr_renderer_clear(renderer, (float[]){ 0.0, 0.0, 0.0, 0.0 }); +	wlr_render_texture_with_matrix(renderer, tex, mat, 1.0f); +	wlr_renderer_end(renderer); + +	if (!wlr_egl_swap_buffers(&mgpu->renderer->egl, mgpu->egl, NULL)) { +		wlr_log(WLR_ERROR, "Failed to swap buffers"); +		return NULL; +	} + +	fb->mgpu_bo = gbm_surface_lock_front_buffer(mgpu->gbm); +	if (!fb->mgpu_bo) { +		wlr_log(WLR_ERROR, "Failed to lock front buffer"); +		return NULL; +	} + +	fb->mgpu_surf = mgpu; +	return fb->mgpu_bo; +} diff --git a/backend/drm/util.c b/backend/drm/util.c index f8a344d1..86d66be4 100644 --- a/backend/drm/util.c +++ b/backend/drm/util.c @@ -179,8 +179,7 @@ static void free_fb(struct gbm_bo *bo, void *data) {  	}  } -uint32_t get_fb_for_bo(struct gbm_bo *bo, uint32_t drm_format, -		bool with_modifiers) { +uint32_t get_fb_for_bo(struct gbm_bo *bo, bool with_modifiers) {  	uint32_t id = (uintptr_t)gbm_bo_get_user_data(bo);  	if (id) {  		return id; @@ -191,6 +190,7 @@ uint32_t get_fb_for_bo(struct gbm_bo *bo, uint32_t drm_format,  	int fd = gbm_device_get_fd(gbm);  	uint32_t width = gbm_bo_get_width(bo);  	uint32_t height = gbm_bo_get_height(bo); +	uint32_t format = gbm_bo_get_format(bo);  	uint32_t handles[4] = {0};  	uint32_t strides[4] = {0}; @@ -205,12 +205,12 @@ uint32_t get_fb_for_bo(struct gbm_bo *bo, uint32_t drm_format,  	}  	if (with_modifiers && gbm_bo_get_modifier(bo) != DRM_FORMAT_MOD_INVALID) { -		if (drmModeAddFB2WithModifiers(fd, width, height, drm_format, handles, +		if (drmModeAddFB2WithModifiers(fd, width, height, format, handles,  				strides, offsets, modifiers, &id, DRM_MODE_FB_MODIFIERS)) {  			wlr_log_errno(WLR_ERROR, "Unable to add DRM framebuffer");  		}  	} else { -		if (drmModeAddFB2(fd, width, height, drm_format, handles, strides, +		if (drmModeAddFB2(fd, width, height, format, handles, strides,  				offsets, &id, 0)) {  			wlr_log_errno(WLR_ERROR, "Unable to add DRM framebuffer");  		}  | 
