output: make attach_render and rollback_render optional

If these aren't provided by the backend, allocate a swapchain for the
output.
This commit is contained in:
Simon Ser 2020-12-01 16:22:42 +01:00
parent 233a2617cf
commit 1a06ea7750
3 changed files with 142 additions and 12 deletions

View file

@ -17,8 +17,7 @@
/** /**
* A backend implementation of wlr_output. * A backend implementation of wlr_output.
* *
* The functions commit, attach_render and rollback_render are mandatory. Other * The commit function is mandatory. Other functions are optional.
* functions are optional.
*/ */
struct wlr_output_impl { struct wlr_output_impl {
/** /**

View file

@ -185,6 +185,9 @@ struct wlr_output {
struct wlr_buffer *cursor_front_buffer; struct wlr_buffer *cursor_front_buffer;
int software_cursor_locks; // number of locks forcing software cursors int software_cursor_locks; // number of locks forcing software cursors
struct wlr_swapchain *swapchain;
struct wlr_buffer *back_buffer;
struct wl_listener display_destroy; struct wl_listener display_destroy;
void *data; void *data;

View file

@ -232,6 +232,13 @@ void wlr_output_update_custom_mode(struct wlr_output *output, int32_t width,
output->refresh = refresh; output->refresh = refresh;
if (output->swapchain != NULL &&
(output->swapchain->width != output->width ||
output->swapchain->height != output->height)) {
wlr_swapchain_destroy(output->swapchain);
output->swapchain = NULL;
}
struct wl_resource *resource; struct wl_resource *resource;
wl_resource_for_each(resource, &output->resources) { wl_resource_for_each(resource, &output->resources) {
send_current_mode(resource); send_current_mode(resource);
@ -336,7 +343,10 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) {
void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend, void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend,
const struct wlr_output_impl *impl, struct wl_display *display) { const struct wlr_output_impl *impl, struct wl_display *display) {
assert(impl->attach_render && impl->rollback_render && impl->commit); assert(impl->commit);
if (impl->attach_render || impl->rollback_render) {
assert(impl->attach_render && impl->rollback_render);
}
if (impl->set_cursor || impl->move_cursor) { if (impl->set_cursor || impl->move_cursor) {
assert(impl->set_cursor && impl->move_cursor); assert(impl->set_cursor && impl->move_cursor);
} }
@ -373,6 +383,8 @@ void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend,
wl_display_add_destroy_listener(display, &output->display_destroy); wl_display_add_destroy_listener(display, &output->display_destroy);
} }
static void output_clear_back_buffer(struct wlr_output *output);
void wlr_output_destroy(struct wlr_output *output) { void wlr_output_destroy(struct wlr_output *output) {
if (!output) { if (!output) {
return; return;
@ -380,6 +392,7 @@ void wlr_output_destroy(struct wlr_output *output) {
wl_list_remove(&output->display_destroy.link); wl_list_remove(&output->display_destroy.link);
wlr_output_destroy_global(output); wlr_output_destroy_global(output);
output_clear_back_buffer(output);
wlr_signal_emit_safe(&output->events.destroy, output); wlr_signal_emit_safe(&output->events.destroy, output);
@ -393,6 +406,8 @@ void wlr_output_destroy(struct wlr_output *output) {
wlr_swapchain_destroy(output->cursor_swapchain); wlr_swapchain_destroy(output->cursor_swapchain);
wlr_buffer_unlock(output->cursor_front_buffer); wlr_buffer_unlock(output->cursor_front_buffer);
wlr_swapchain_destroy(output->swapchain);
if (output->idle_frame != NULL) { if (output->idle_frame != NULL) {
wl_event_source_remove(output->idle_frame); wl_event_source_remove(output->idle_frame);
} }
@ -457,14 +472,106 @@ static void output_state_clear_buffer(struct wlr_output_state *state) {
state->committed &= ~WLR_OUTPUT_STATE_BUFFER; state->committed &= ~WLR_OUTPUT_STATE_BUFFER;
} }
bool wlr_output_attach_render(struct wlr_output *output, int *buffer_age) { static struct wlr_drm_format *output_pick_format(struct wlr_output *output,
if (!output->impl->attach_render(output, buffer_age)) { const struct wlr_drm_format_set *display_formats);
static bool output_create_swapchain(struct wlr_output *output) {
if (output->swapchain != NULL) {
return true;
}
struct wlr_allocator *allocator = backend_get_allocator(output->backend);
if (allocator == NULL) {
wlr_log(WLR_ERROR, "Failed to get backend allocator");
return false; return false;
} }
output_state_clear_buffer(&output->pending); const struct wlr_drm_format_set *display_formats = NULL;
output->pending.committed |= WLR_OUTPUT_STATE_BUFFER; if (output->impl->get_primary_formats) {
output->pending.buffer_type = WLR_OUTPUT_STATE_BUFFER_RENDER; 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);
if (format == NULL) {
wlr_log(WLR_ERROR, "Failed to pick primary buffer format for output '%s'",
output->name);
return false;
}
wlr_log(WLR_DEBUG, "Choosing primary buffer format 0x%"PRIX32" for output '%s'",
format->format, output->name);
output->swapchain = wlr_swapchain_create(allocator, output->width,
output->height, format);
free(format);
if (output->swapchain == NULL) {
wlr_log(WLR_ERROR, "Failed to create output swapchain");
return false;
}
return true;
}
static bool output_attach_back_buffer(struct wlr_output *output,
int *buffer_age) {
assert(output->back_buffer == NULL);
if (!output_create_swapchain(output)) {
return false;
}
struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend);
assert(renderer != NULL);
struct wlr_buffer *buffer =
wlr_swapchain_acquire(output->swapchain, buffer_age);
if (buffer == NULL) {
return false;
}
if (!wlr_renderer_bind_buffer(renderer, buffer)) {
wlr_buffer_unlock(buffer);
return false;
}
output->back_buffer = buffer;
return true;
}
static void output_clear_back_buffer(struct wlr_output *output) {
if (output->back_buffer == NULL) {
return;
}
struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend);
assert(renderer != NULL);
wlr_renderer_bind_buffer(renderer, NULL);
wlr_buffer_unlock(output->back_buffer);
output->back_buffer = NULL;
}
bool wlr_output_attach_render(struct wlr_output *output, int *buffer_age) {
if (output->impl->attach_render) {
if (!output->impl->attach_render(output, buffer_age)) {
return false;
}
output_state_clear_buffer(&output->pending);
output->pending.committed |= WLR_OUTPUT_STATE_BUFFER;
output->pending.buffer_type = WLR_OUTPUT_STATE_BUFFER_RENDER;
} else {
if (!output_attach_back_buffer(output, buffer_age)) {
return false;
}
wlr_output_attach_buffer(output, output->back_buffer);
}
return true; return true;
} }
@ -474,11 +581,24 @@ uint32_t wlr_output_preferred_read_format(struct wlr_output *output) {
return DRM_FORMAT_INVALID; return DRM_FORMAT_INVALID;
} }
if (!output->impl->attach_render(output, NULL)) { if (output->impl->attach_render) {
return DRM_FORMAT_INVALID; if (!output->impl->attach_render(output, NULL)) {
return false;
}
} else {
if (!output_attach_back_buffer(output, NULL)) {
return false;
}
} }
uint32_t fmt = renderer->impl->preferred_read_format(renderer); uint32_t fmt = renderer->impl->preferred_read_format(renderer);
output->impl->rollback_render(output);
if (output->impl->rollback_render) {
output->impl->rollback_render(output);
} else {
output_clear_back_buffer(output);
}
return fmt; return fmt;
} }
@ -529,7 +649,8 @@ static bool output_basic_test(struct wlr_output *output) {
return false; return false;
} }
if (output->pending.buffer_type == WLR_OUTPUT_STATE_BUFFER_SCANOUT) { if (output->pending.buffer_type == WLR_OUTPUT_STATE_BUFFER_SCANOUT &&
output->back_buffer == NULL) {
if (output->attach_render_locks > 0) { if (output->attach_render_locks > 0) {
wlr_log(WLR_DEBUG, "Direct scan-out disabled by lock"); wlr_log(WLR_DEBUG, "Direct scan-out disabled by lock");
return false; return false;
@ -660,6 +781,12 @@ bool wlr_output_commit(struct wlr_output *output) {
if (output->pending.committed & WLR_OUTPUT_STATE_BUFFER) { if (output->pending.committed & WLR_OUTPUT_STATE_BUFFER) {
output->frame_pending = true; output->frame_pending = true;
output->needs_frame = false; output->needs_frame = false;
if (output->back_buffer != NULL) {
wlr_swapchain_set_buffer_submitted(output->swapchain,
output->back_buffer);
output_clear_back_buffer(output);
}
} }
uint32_t committed = output->pending.committed; uint32_t committed = output->pending.committed;
@ -681,6 +808,7 @@ void wlr_output_rollback(struct wlr_output *output) {
output->pending.buffer_type == WLR_OUTPUT_STATE_BUFFER_RENDER) { output->pending.buffer_type == WLR_OUTPUT_STATE_BUFFER_RENDER) {
output->impl->rollback_render(output); output->impl->rollback_render(output);
} }
output_clear_back_buffer(output);
output_state_clear(&output->pending); output_state_clear(&output->pending);
} }