backend/drm: add basic support for direct scan-out
This commit is contained in:
		
							parent
							
								
									3dec88e455
								
							
						
					
					
						commit
						96d6fde5dc
					
				|  | @ -820,6 +820,52 @@ static bool drm_connector_schedule_frame(struct wlr_output *output) { | |||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| static bool drm_connector_set_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); | ||||
| 	if (!drm->session->active) { | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	struct wlr_drm_crtc *crtc = conn->crtc; | ||||
| 	if (!crtc) { | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	// TODO: check plane input formats
 | ||||
| 
 | ||||
| 	if (attribs->width != output->width || attribs->height != output->height) { | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	struct gbm_bo *bo = import_gbm_bo(&drm->renderer, attribs); | ||||
| 	if (bo == NULL) { | ||||
| 		wlr_log(WLR_ERROR, "import_gbm_bo failed"); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	uint32_t fb_id = get_fb_for_bo(bo, gbm_bo_get_format(bo)); | ||||
| 	if (fb_id == 0) { | ||||
| 		wlr_log(WLR_ERROR, "get_fb_for_bo failed"); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	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)) { | ||||
| 		wlr_log(WLR_ERROR, "crtc_pageflip failed"); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	conn->pageflip_pending = true; | ||||
| 	wlr_output_update_enabled(output, true); | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| static void drm_connector_destroy(struct wlr_output *output) { | ||||
| 	struct wlr_drm_connector *conn = get_drm_connector_from_output(output); | ||||
| 	drm_connector_cleanup(conn); | ||||
|  | @ -842,6 +888,7 @@ static const struct wlr_output_impl output_impl = { | |||
| 	.get_gamma_size = drm_connector_get_gamma_size, | ||||
| 	.export_dmabuf = drm_connector_export_dmabuf, | ||||
| 	.schedule_frame = drm_connector_schedule_frame, | ||||
| 	.set_dmabuf = drm_connector_set_dmabuf, | ||||
| }; | ||||
| 
 | ||||
| bool wlr_output_is_drm(struct wlr_output *output) { | ||||
|  |  | |||
|  | @ -163,6 +163,30 @@ void post_drm_surface(struct wlr_drm_surface *surf) { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| struct gbm_bo *import_gbm_bo(struct wlr_drm_renderer *renderer, | ||||
| 		struct wlr_dmabuf_attributes *attribs) { | ||||
| 	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)); | ||||
| 
 | ||||
|  |  | |||
|  | @ -184,21 +184,18 @@ uint32_t get_fb_for_bo(struct gbm_bo *bo, uint32_t drm_format) { | |||
| 		return id; | ||||
| 	} | ||||
| 
 | ||||
| 	assert(gbm_bo_get_format(bo) == GBM_FORMAT_ARGB8888); | ||||
| 	assert(drm_format == DRM_FORMAT_ARGB8888 || | ||||
| 		drm_format == DRM_FORMAT_XRGB8888); | ||||
| 
 | ||||
| 	struct gbm_device *gbm = gbm_bo_get_device(bo); | ||||
| 
 | ||||
| 	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 handles[4] = {gbm_bo_get_handle(bo).u32}; | ||||
| 	uint32_t pitches[4] = {gbm_bo_get_stride(bo)}; | ||||
| 	uint32_t strides[4] = {gbm_bo_get_stride(bo)}; | ||||
| 	uint32_t offsets[4] = {gbm_bo_get_offset(bo, 0)}; | ||||
| 	uint64_t modifiers[4] = {gbm_bo_get_modifier(bo)}; | ||||
| 
 | ||||
| 	if (drmModeAddFB2(fd, width, height, drm_format, | ||||
| 			handles, pitches, offsets, &id, 0)) { | ||||
| 	if (drmModeAddFB2WithModifiers(fd, width, height, drm_format, | ||||
| 			handles, strides, offsets, modifiers, &id, DRM_MODE_FB_MODIFIERS)) { | ||||
| 		wlr_log_errno(WLR_ERROR, "Unable to add DRM framebuffer"); | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -54,6 +54,8 @@ struct gbm_bo *get_drm_surface_front(struct wlr_drm_surface *surf); | |||
| void post_drm_surface(struct wlr_drm_surface *surf); | ||||
| struct gbm_bo *copy_drm_surface_mgpu(struct wlr_drm_surface *dest, | ||||
| 	struct gbm_bo *src); | ||||
| struct gbm_bo *import_gbm_bo(struct wlr_drm_renderer *renderer, | ||||
| 	struct wlr_dmabuf_attributes *attribs); | ||||
| bool export_drm_bo(struct gbm_bo *bo, struct wlr_dmabuf_attributes *attribs); | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -34,6 +34,8 @@ struct wlr_output_impl { | |||
| 	bool (*export_dmabuf)(struct wlr_output *output, | ||||
| 		struct wlr_dmabuf_attributes *attribs); | ||||
| 	bool (*schedule_frame)(struct wlr_output *output); | ||||
| 	bool (*set_dmabuf)(struct wlr_output *output, | ||||
| 		struct wlr_dmabuf_attributes *attribs); | ||||
| }; | ||||
| 
 | ||||
| void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend, | ||||
|  |  | |||
|  | @ -243,6 +243,8 @@ bool wlr_output_preferred_read_format(struct wlr_output *output, | |||
|  */ | ||||
| void wlr_output_set_damage(struct wlr_output *output, | ||||
| 	pixman_region32_t *damage); | ||||
| bool wlr_output_set_dmabuf(struct wlr_output *output, | ||||
| 	struct wlr_dmabuf_attributes *attribs); | ||||
| /**
 | ||||
|  * Commit the pending output state. If `wlr_output_attach_render` has been | ||||
|  * called, the pending frame will be submitted for display. | ||||
|  |  | |||
|  | @ -478,6 +478,30 @@ bool wlr_output_commit(struct wlr_output *output) { | |||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| bool wlr_output_set_dmabuf(struct wlr_output *output, | ||||
| 		struct wlr_dmabuf_attributes *attribs) { | ||||
| 	if (output->frame_pending) { | ||||
| 		wlr_log(WLR_ERROR, "Tried to swap buffers when a frame is pending"); | ||||
| 		return false; | ||||
| 	} | ||||
| 	if (output->idle_frame != NULL) { | ||||
| 		wl_event_source_remove(output->idle_frame); | ||||
| 		output->idle_frame = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!output->impl->set_dmabuf) { | ||||
| 		return false; | ||||
| 	} | ||||
| 	if (!output->impl->set_dmabuf(output, attribs)) { | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	output->frame_pending = true; | ||||
| 	output->needs_swap = false; | ||||
| 	pixman_region32_clear(&output->damage); | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| void wlr_output_send_frame(struct wlr_output *output) { | ||||
| 	output->frame_pending = false; | ||||
| 	wlr_signal_emit_safe(&output->events.frame, output); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue