mirror of
				https://gitlab.freedesktop.org/wlroots/wlroots.git
				synced 2025-11-03 09:01:40 -05:00 
			
		
		
		
	backend/x11: implement a real rendering loop
Instead of using a timer, rely on X11 Present events and send a new frame event when the parent compositor displays a new frame on screen. The previous attempt at doing this [1] hit issues with EGLSurface, but we don't use that anymore. [1]: https://github.com/swaywm/wlroots/pull/1894
This commit is contained in:
		
							parent
							
								
									c5f239f411
								
							
						
					
					
						commit
						c012d770f7
					
				
					 2 changed files with 13 additions and 27 deletions
				
			
		| 
						 | 
					@ -21,13 +21,6 @@
 | 
				
			||||||
#include "util/signal.h"
 | 
					#include "util/signal.h"
 | 
				
			||||||
#include "util/time.h"
 | 
					#include "util/time.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int signal_frame(void *data) {
 | 
					 | 
				
			||||||
	struct wlr_x11_output *output = data;
 | 
					 | 
				
			||||||
	wlr_output_send_frame(&output->wlr_output);
 | 
					 | 
				
			||||||
	wl_event_source_timer_update(output->frame_timer, output->frame_delay);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void parse_xcb_setup(struct wlr_output *output,
 | 
					static void parse_xcb_setup(struct wlr_output *output,
 | 
				
			||||||
		xcb_connection_t *xcb) {
 | 
							xcb_connection_t *xcb) {
 | 
				
			||||||
	const xcb_setup_t *xcb_setup = xcb_get_setup(xcb);
 | 
						const xcb_setup_t *xcb_setup = xcb_get_setup(xcb);
 | 
				
			||||||
| 
						 | 
					@ -49,14 +42,8 @@ static struct wlr_x11_output *get_x11_output_from_output(
 | 
				
			||||||
static void output_set_refresh(struct wlr_output *wlr_output, int32_t refresh) {
 | 
					static void output_set_refresh(struct wlr_output *wlr_output, int32_t refresh) {
 | 
				
			||||||
	struct wlr_x11_output *output = get_x11_output_from_output(wlr_output);
 | 
						struct wlr_x11_output *output = get_x11_output_from_output(wlr_output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (refresh <= 0) {
 | 
					 | 
				
			||||||
		refresh = X11_DEFAULT_REFRESH;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wlr_output_update_custom_mode(&output->wlr_output, wlr_output->width,
 | 
						wlr_output_update_custom_mode(&output->wlr_output, wlr_output->width,
 | 
				
			||||||
		wlr_output->height, refresh);
 | 
							wlr_output->height, 0);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	output->frame_delay = 1000000 / refresh;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool output_set_custom_mode(struct wlr_output *wlr_output,
 | 
					static bool output_set_custom_mode(struct wlr_output *wlr_output,
 | 
				
			||||||
| 
						 | 
					@ -97,7 +84,6 @@ static void output_destroy(struct wlr_output *wlr_output) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl_list_remove(&output->link);
 | 
						wl_list_remove(&output->link);
 | 
				
			||||||
	wl_event_source_remove(output->frame_timer);
 | 
					 | 
				
			||||||
	wlr_buffer_unlock(output->back_buffer);
 | 
						wlr_buffer_unlock(output->back_buffer);
 | 
				
			||||||
	wlr_swapchain_destroy(output->swapchain);
 | 
						wlr_swapchain_destroy(output->swapchain);
 | 
				
			||||||
	xcb_destroy_window(x11->xcb, output->win);
 | 
						xcb_destroy_window(x11->xcb, output->win);
 | 
				
			||||||
| 
						 | 
					@ -258,9 +244,10 @@ static bool output_commit_buffer(struct wlr_x11_output *output) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint32_t serial = output->wlr_output.commit_seq;
 | 
						uint32_t serial = output->wlr_output.commit_seq;
 | 
				
			||||||
	uint32_t options = 0;
 | 
						uint32_t options = 0;
 | 
				
			||||||
 | 
						uint64_t target_msc = output->last_msc ? output->last_msc + 1 : 0;
 | 
				
			||||||
	xcb_present_pixmap(x11->xcb, output->win, x11_buffer->pixmap, serial,
 | 
						xcb_present_pixmap(x11->xcb, output->win, x11_buffer->pixmap, serial,
 | 
				
			||||||
		0, region, 0, 0, XCB_NONE, XCB_NONE, XCB_NONE, options, 0, 0, 0,
 | 
							0, region, 0, 0, XCB_NONE, XCB_NONE, XCB_NONE, options, target_msc,
 | 
				
			||||||
		0, NULL);
 | 
							0, 0, 0, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (region != XCB_NONE) {
 | 
						if (region != XCB_NONE) {
 | 
				
			||||||
		xcb_xfixes_destroy_region(x11->xcb, region);
 | 
							xcb_xfixes_destroy_region(x11->xcb, region);
 | 
				
			||||||
| 
						 | 
					@ -423,12 +410,8 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend) {
 | 
				
			||||||
	xcb_map_window(x11->xcb, output->win);
 | 
						xcb_map_window(x11->xcb, output->win);
 | 
				
			||||||
	xcb_flush(x11->xcb);
 | 
						xcb_flush(x11->xcb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_event_loop *ev = wl_display_get_event_loop(x11->wl_display);
 | 
					 | 
				
			||||||
	output->frame_timer = wl_event_loop_add_timer(ev, signal_frame, output);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wl_list_insert(&x11->outputs, &output->link);
 | 
						wl_list_insert(&x11->outputs, &output->link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl_event_source_timer_update(output->frame_timer, output->frame_delay);
 | 
					 | 
				
			||||||
	wlr_output_update_enabled(wlr_output, true);
 | 
						wlr_output_update_enabled(wlr_output, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_input_device_init(&output->pointer_dev, WLR_INPUT_DEVICE_POINTER,
 | 
						wlr_input_device_init(&output->pointer_dev, WLR_INPUT_DEVICE_POINTER,
 | 
				
			||||||
| 
						 | 
					@ -448,6 +431,9 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend) {
 | 
				
			||||||
	wlr_signal_emit_safe(&x11->backend.events.new_input, &output->pointer_dev);
 | 
						wlr_signal_emit_safe(&x11->backend.events.new_input, &output->pointer_dev);
 | 
				
			||||||
	wlr_signal_emit_safe(&x11->backend.events.new_input, &output->touch_dev);
 | 
						wlr_signal_emit_safe(&x11->backend.events.new_input, &output->touch_dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Start the rendering loop by requesting the compositor to render a frame
 | 
				
			||||||
 | 
						wlr_output_schedule_frame(wlr_output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return wlr_output;
 | 
						return wlr_output;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -474,7 +460,7 @@ void handle_x11_configure_notify(struct wlr_x11_output *output,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_output_update_custom_mode(&output->wlr_output, ev->width,
 | 
						wlr_output_update_custom_mode(&output->wlr_output, ev->width,
 | 
				
			||||||
		ev->height, output->wlr_output.refresh);
 | 
							ev->height, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Move the pointer to its new location
 | 
						// Move the pointer to its new location
 | 
				
			||||||
	update_x11_pointer_position(output, output->x11->time);
 | 
						update_x11_pointer_position(output, output->x11->time);
 | 
				
			||||||
| 
						 | 
					@ -545,6 +531,8 @@ void handle_x11_present_event(struct wlr_x11_backend *x11,
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							output->last_msc = complete_notify->msc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		struct timespec t;
 | 
							struct timespec t;
 | 
				
			||||||
		timespec_from_nsec(&t, complete_notify->ust * 1000);
 | 
							timespec_from_nsec(&t, complete_notify->ust * 1000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -561,6 +549,8 @@ void handle_x11_present_event(struct wlr_x11_backend *x11,
 | 
				
			||||||
			.flags = flags,
 | 
								.flags = flags,
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
		wlr_output_send_present(&output->wlr_output, &present_event);
 | 
							wlr_output_send_present(&output->wlr_output, &present_event);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							wlr_output_send_frame(&output->wlr_output);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		wlr_log(WLR_DEBUG, "Unhandled Present event %"PRIu16, event->event_type);
 | 
							wlr_log(WLR_DEBUG, "Unhandled Present event %"PRIu16, event->event_type);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,8 +26,6 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define XCB_EVENT_RESPONSE_TYPE_MASK 0x7f
 | 
					#define XCB_EVENT_RESPONSE_TYPE_MASK 0x7f
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define X11_DEFAULT_REFRESH (60 * 1000) // 60 Hz
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct wlr_x11_backend;
 | 
					struct wlr_x11_backend;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_x11_output {
 | 
					struct wlr_x11_output {
 | 
				
			||||||
| 
						 | 
					@ -47,12 +45,10 @@ struct wlr_x11_output {
 | 
				
			||||||
	struct wlr_input_device touch_dev;
 | 
						struct wlr_input_device touch_dev;
 | 
				
			||||||
	struct wl_list touchpoints; // wlr_x11_touchpoint::link
 | 
						struct wl_list touchpoints; // wlr_x11_touchpoint::link
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_event_source *frame_timer;
 | 
					 | 
				
			||||||
	int frame_delay;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct wl_list buffers; // wlr_x11_buffer::link
 | 
						struct wl_list buffers; // wlr_x11_buffer::link
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool cursor_hidden;
 | 
						bool cursor_hidden;
 | 
				
			||||||
 | 
						uint64_t last_msc;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_x11_touchpoint {
 | 
					struct wlr_x11_touchpoint {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue