output: Add function to set preferred render format
This change introduces new double buffered state to the wlr_output, corresponding to the buffer format to render to. The format being rendered to does not control the bit depth of colors being sent to the display; it does generally determine the format with which screenshot data is provided. The DRM backend _may_ sent higher bit depths if the render format depth is increased, but hardware and other limitations may apply.
This commit is contained in:
		
							parent
							
								
									3d7d6ec06f
								
							
						
					
					
						commit
						e879d566bb
					
				|  | @ -21,6 +21,7 @@ | |||
| 	(WLR_OUTPUT_STATE_DAMAGE | \ | ||||
| 	WLR_OUTPUT_STATE_SCALE | \ | ||||
| 	WLR_OUTPUT_STATE_TRANSFORM | \ | ||||
| 	WLR_OUTPUT_STATE_RENDER_FORMAT | \ | ||||
| 	WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) | ||||
| 
 | ||||
| /**
 | ||||
|  |  | |||
|  | @ -61,6 +61,7 @@ enum wlr_output_state_field { | |||
| 	WLR_OUTPUT_STATE_TRANSFORM = 1 << 5, | ||||
| 	WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED = 1 << 6, | ||||
| 	WLR_OUTPUT_STATE_GAMMA_LUT = 1 << 7, | ||||
| 	WLR_OUTPUT_STATE_RENDER_FORMAT = 1 << 8, | ||||
| }; | ||||
| 
 | ||||
| enum wlr_output_state_mode_type { | ||||
|  | @ -78,6 +79,7 @@ struct wlr_output_state { | |||
| 	float scale; | ||||
| 	enum wl_output_transform transform; | ||||
| 	bool adaptive_sync_enabled; | ||||
| 	uint32_t render_format; | ||||
| 
 | ||||
| 	// only valid if WLR_OUTPUT_STATE_BUFFER
 | ||||
| 	struct wlr_buffer *buffer; | ||||
|  | @ -134,6 +136,7 @@ struct wlr_output { | |||
| 	enum wl_output_subpixel subpixel; | ||||
| 	enum wl_output_transform transform; | ||||
| 	enum wlr_output_adaptive_sync_status adaptive_sync_status; | ||||
| 	uint32_t render_format; | ||||
| 
 | ||||
| 	bool needs_frame; | ||||
| 	// damage for cursors and fullscreen surface, in output-local coordinates
 | ||||
|  | @ -308,6 +311,22 @@ void wlr_output_set_transform(struct wlr_output *output, | |||
|  * Adaptive sync is double-buffered state, see `wlr_output_commit`. | ||||
|  */ | ||||
| void wlr_output_enable_adaptive_sync(struct wlr_output *output, bool enabled); | ||||
| /**
 | ||||
|  * Set the output buffer render format. Default value: DRM_FORMAT_XRGB8888 | ||||
|  * | ||||
|  * While high bit depth render formats are necessary for a monitor to receive | ||||
|  * useful high bit data, they do not guarantee it; a DRM_FORMAT_XBGR2101010 | ||||
|  * buffer will only lead to sending 10-bpc image data to the monitor if | ||||
|  * hardware and software permit this. | ||||
|  * | ||||
|  * This only affects the format of the output buffer used when rendering, | ||||
|  * as with `wlr_output_attach_render`. It has no impact on the cursor buffer | ||||
|  * format, or on the formats supported for direct scan-out (see also | ||||
|  * `wlr_output_attach_buffer`). | ||||
|  * | ||||
|  * This format is double-buffered state, see `wlr_output_commit`. | ||||
|  */ | ||||
| void wlr_output_set_render_format(struct wlr_output *output, uint32_t format); | ||||
| /**
 | ||||
|  * Sets a scale for the output. | ||||
|  * | ||||
|  |  | |||
|  | @ -1,10 +1,13 @@ | |||
| #define _POSIX_C_SOURCE 200809L | ||||
| #include <assert.h> | ||||
| #include <backend/backend.h> | ||||
| #include <drm_fourcc.h> | ||||
| #include <stdlib.h> | ||||
| #include <wlr/interfaces/wlr_output.h> | ||||
| #include <wlr/types/wlr_matrix.h> | ||||
| #include <wlr/types/wlr_surface.h> | ||||
| #include <wlr/util/log.h> | ||||
| #include "render/allocator/allocator.h" | ||||
| #include "render/swapchain.h" | ||||
| #include "types/wlr_output.h" | ||||
| #include "util/global.h" | ||||
|  | @ -296,6 +299,16 @@ void wlr_output_enable_adaptive_sync(struct wlr_output *output, bool enabled) { | |||
| 	output->pending.adaptive_sync_enabled = enabled; | ||||
| } | ||||
| 
 | ||||
| void wlr_output_set_render_format(struct wlr_output *output, uint32_t format) { | ||||
| 	if (output->render_format == format) { | ||||
| 		output->pending.committed &= ~WLR_OUTPUT_STATE_RENDER_FORMAT; | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	output->pending.committed |= WLR_OUTPUT_STATE_RENDER_FORMAT; | ||||
| 	output->pending.render_format = format; | ||||
| } | ||||
| 
 | ||||
| void wlr_output_set_subpixel(struct wlr_output *output, | ||||
| 		enum wl_output_subpixel subpixel) { | ||||
| 	if (output->subpixel == subpixel) { | ||||
|  | @ -343,6 +356,7 @@ void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend, | |||
| 	output->impl = impl; | ||||
| 	output->display = display; | ||||
| 	wl_list_init(&output->modes); | ||||
| 	output->render_format = DRM_FORMAT_XRGB8888; | ||||
| 	output->transform = WL_OUTPUT_TRANSFORM_NORMAL; | ||||
| 	output->scale = 1; | ||||
| 	output->commit_seq = 0; | ||||
|  | @ -542,6 +556,30 @@ static bool output_basic_test(struct wlr_output *output) { | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (output->pending.committed & WLR_OUTPUT_STATE_RENDER_FORMAT) { | ||||
| 		struct wlr_allocator *allocator = output->allocator; | ||||
| 		assert(allocator != NULL); | ||||
| 
 | ||||
| 		const struct wlr_drm_format_set *display_formats = NULL; | ||||
| 		if (output->impl->get_primary_formats) { | ||||
| 			display_formats = | ||||
| 				output->impl->get_primary_formats(output, allocator->buffer_caps); | ||||
| 			if (display_formats == NULL) { | ||||
| 				wlr_log(WLR_ERROR, "Failed to get primary display formats"); | ||||
| 				return false; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		struct wlr_drm_format *format = output_pick_format(output, display_formats, | ||||
| 			output->pending.render_format); | ||||
| 		if (format == NULL) { | ||||
| 			wlr_log(WLR_ERROR, "Failed to pick primary buffer format for output"); | ||||
| 			return false; | ||||
| 		} | ||||
| 
 | ||||
| 		free(format); | ||||
| 	} | ||||
| 
 | ||||
| 	bool enabled = output->enabled; | ||||
| 	if (output->pending.committed & WLR_OUTPUT_STATE_ENABLED) { | ||||
| 		enabled = output->pending.enabled; | ||||
|  | @ -569,6 +607,10 @@ static bool output_basic_test(struct wlr_output *output) { | |||
| 		wlr_log(WLR_DEBUG, "Tried to enable adaptive sync on a disabled output"); | ||||
| 		return false; | ||||
| 	} | ||||
| 	if (!enabled && output->pending.committed & WLR_OUTPUT_STATE_RENDER_FORMAT) { | ||||
| 		wlr_log(WLR_DEBUG, "Tried to set format for a disabled output"); | ||||
| 		return false; | ||||
| 	} | ||||
| 	if (!enabled && output->pending.committed & WLR_OUTPUT_STATE_GAMMA_LUT) { | ||||
| 		wlr_log(WLR_DEBUG, "Tried to set the gamma lut on a disabled output"); | ||||
| 		return false; | ||||
|  | @ -642,6 +684,10 @@ bool wlr_output_commit(struct wlr_output *output) { | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (output->pending.committed & WLR_OUTPUT_STATE_RENDER_FORMAT) { | ||||
| 		output->render_format = output->pending.render_format; | ||||
| 	} | ||||
| 
 | ||||
| 	output->commit_seq++; | ||||
| 
 | ||||
| 	bool scale_updated = output->pending.committed & WLR_OUTPUT_STATE_SCALE; | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ | |||
| #include "render/drm_format_set.h" | ||||
| #include "render/swapchain.h" | ||||
| #include "render/wlr_renderer.h" | ||||
| #include "render/pixel_format.h" | ||||
| #include "types/wlr_output.h" | ||||
| 
 | ||||
| bool wlr_output_init_render(struct wlr_output *output, | ||||
|  | @ -47,12 +48,6 @@ static bool output_create_swapchain(struct wlr_output *output, | |||
| 	int width, height; | ||||
| 	output_pending_resolution(output, &width, &height); | ||||
| 
 | ||||
| 	if (output->swapchain != NULL && output->swapchain->width == width && | ||||
| 			output->swapchain->height == height && | ||||
| 			(allow_modifiers || output->swapchain->format->len == 0)) { | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	struct wlr_allocator *allocator = output->allocator; | ||||
| 	assert(allocator != NULL); | ||||
| 
 | ||||
|  | @ -67,12 +62,22 @@ static bool output_create_swapchain(struct wlr_output *output, | |||
| 	} | ||||
| 
 | ||||
| 	struct wlr_drm_format *format = output_pick_format(output, display_formats, | ||||
| 		DRM_FORMAT_XRGB8888); | ||||
| 		output->render_format); | ||||
| 	if (format == NULL) { | ||||
| 		wlr_log(WLR_ERROR, "Failed to pick primary buffer format for output '%s'", | ||||
| 			output->name); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	if (output->swapchain != NULL && output->swapchain->width == width && | ||||
| 			output->swapchain->height == height && | ||||
| 			output->swapchain->format->format == format->format && | ||||
| 			(allow_modifiers || output->swapchain->format->len == 0)) { | ||||
| 		// no change, keep existing swapchain
 | ||||
| 		free(format); | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	wlr_log(WLR_DEBUG, "Choosing primary buffer format 0x%"PRIX32" for output '%s'", | ||||
| 		format->format, output->name); | ||||
| 
 | ||||
|  | @ -171,6 +176,9 @@ bool output_ensure_buffer(struct wlr_output *output) { | |||
| 	if (output->pending.committed & WLR_OUTPUT_STATE_MODE) { | ||||
| 		needs_new_buffer = true; | ||||
| 	} | ||||
| 	if (output->pending.committed & WLR_OUTPUT_STATE_RENDER_FORMAT) { | ||||
| 		needs_new_buffer = true; | ||||
| 	} | ||||
| 	if (!needs_new_buffer || | ||||
| 			(output->pending.committed & WLR_OUTPUT_STATE_BUFFER)) { | ||||
| 		return true; | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue