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:
parent
233a2617cf
commit
1a06ea7750
|
@ -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 {
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,7 +472,92 @@ static void output_state_clear_buffer(struct wlr_output_state *state) {
|
||||||
state->committed &= ~WLR_OUTPUT_STATE_BUFFER;
|
state->committed &= ~WLR_OUTPUT_STATE_BUFFER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct wlr_drm_format *output_pick_format(struct wlr_output *output,
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
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) {
|
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)) {
|
if (!output->impl->attach_render(output, buffer_age)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -465,6 +565,13 @@ bool wlr_output_attach_render(struct wlr_output *output, int *buffer_age) {
|
||||||
output_state_clear_buffer(&output->pending);
|
output_state_clear_buffer(&output->pending);
|
||||||
output->pending.committed |= WLR_OUTPUT_STATE_BUFFER;
|
output->pending.committed |= WLR_OUTPUT_STATE_BUFFER;
|
||||||
output->pending.buffer_type = WLR_OUTPUT_STATE_BUFFER_RENDER;
|
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) {
|
||||||
if (!output->impl->attach_render(output, NULL)) {
|
if (!output->impl->attach_render(output, NULL)) {
|
||||||
return DRM_FORMAT_INVALID;
|
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);
|
||||||
|
|
||||||
|
if (output->impl->rollback_render) {
|
||||||
output->impl->rollback_render(output);
|
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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue