Merge upstream

This commit is contained in:
Christian Kröner 2022-02-23 21:43:41 +01:00
commit c673b684a0
203 changed files with 6752 additions and 4861 deletions

View file

@ -3,15 +3,34 @@
#include <stdlib.h>
#include <wlr/interfaces/wlr_output.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_matrix.h>
#include <wlr/types/wlr_surface.h>
#include <wlr/util/log.h>
#include "backend/backend.h"
#include "render/allocator/allocator.h"
#include "render/swapchain.h"
#include "types/wlr_output.h"
#include "util/signal.h"
static bool output_set_hardware_cursor(struct wlr_output *output,
struct wlr_buffer *buffer, int hotspot_x, int hotspot_y) {
if (!output->impl->set_cursor) {
return false;
}
if (!output->impl->set_cursor(output, buffer, hotspot_x, hotspot_y)) {
return false;
}
wlr_buffer_unlock(output->cursor_front_buffer);
output->cursor_front_buffer = NULL;
if (buffer != NULL) {
output->cursor_front_buffer = wlr_buffer_lock(buffer);
}
return true;
}
static void output_cursor_damage_whole(struct wlr_output_cursor *cursor);
void wlr_output_lock_software_cursors(struct wlr_output *output, bool lock) {
@ -26,8 +45,7 @@ void wlr_output_lock_software_cursors(struct wlr_output *output, bool lock) {
output->software_cursor_locks);
if (output->software_cursor_locks > 0 && output->hardware_cursor != NULL) {
assert(output->impl->set_cursor);
output->impl->set_cursor(output, NULL, 0, 0);
output_set_hardware_cursor(output, NULL, 0, 0);
output_cursor_damage_whole(output->hardware_cursor);
output->hardware_cursor = NULL;
}
@ -38,7 +56,7 @@ void wlr_output_lock_software_cursors(struct wlr_output *output, bool lock) {
}
static void output_scissor(struct wlr_output *output, pixman_box32_t *rect) {
struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend);
struct wlr_renderer *renderer = output->renderer;
assert(renderer);
struct wlr_box box = {
@ -71,8 +89,7 @@ static void output_cursor_get_box(struct wlr_output_cursor *cursor,
static void output_cursor_render(struct wlr_output_cursor *cursor,
pixman_region32_t *damage) {
struct wlr_renderer *renderer =
wlr_backend_get_renderer(cursor->output->backend);
struct wlr_renderer *renderer = cursor->output->renderer;
assert(renderer);
struct wlr_texture *texture = cursor->texture;
@ -195,7 +212,7 @@ static void output_cursor_update_visible(struct wlr_output_cursor *cursor) {
}
static struct wlr_drm_format *output_pick_cursor_format(struct wlr_output *output) {
struct wlr_allocator *allocator = backend_get_allocator(output->backend);
struct wlr_allocator *allocator = output->allocator;
assert(allocator != NULL);
const struct wlr_drm_format_set *display_formats = NULL;
@ -208,7 +225,7 @@ static struct wlr_drm_format *output_pick_cursor_format(struct wlr_output *outpu
}
}
return output_pick_format(output, display_formats);
return output_pick_format(output, display_formats, DRM_FORMAT_ARGB8888);
}
static struct wlr_buffer *render_cursor_buffer(struct wlr_output_cursor *cursor) {
@ -226,17 +243,9 @@ static struct wlr_buffer *render_cursor_buffer(struct wlr_output_cursor *cursor)
return NULL;
}
struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend);
if (renderer == NULL) {
wlr_log(WLR_ERROR, "Failed to get backend renderer");
return NULL;
}
struct wlr_allocator *allocator = backend_get_allocator(output->backend);
if (allocator == NULL) {
wlr_log(WLR_ERROR, "Failed to get backend allocator");
return NULL;
}
struct wlr_allocator *allocator = output->allocator;
struct wlr_renderer *renderer = output->renderer;
assert(allocator != NULL && renderer != NULL);
int width = texture->width;
int height = texture->height;
@ -355,14 +364,10 @@ static bool output_cursor_attempt_hardware(struct wlr_output_cursor *cursor) {
wlr_output_transform_invert(output->transform),
buffer ? buffer->width : 0, buffer ? buffer->height : 0);
bool ok = output->impl->set_cursor(cursor->output, buffer,
hotspot.x, hotspot.y);
bool ok = output_set_hardware_cursor(output, buffer, hotspot.x, hotspot.y);
wlr_buffer_unlock(buffer);
if (ok) {
wlr_buffer_unlock(output->cursor_front_buffer);
output->cursor_front_buffer = buffer;
output->hardware_cursor = cursor;
} else {
wlr_buffer_unlock(buffer);
}
return ok;
}
@ -370,8 +375,7 @@ static bool output_cursor_attempt_hardware(struct wlr_output_cursor *cursor) {
bool wlr_output_cursor_set_image(struct wlr_output_cursor *cursor,
const uint8_t *pixels, int32_t stride, uint32_t width, uint32_t height,
int32_t hotspot_x, int32_t hotspot_y) {
struct wlr_renderer *renderer =
wlr_backend_get_renderer(cursor->output->backend);
struct wlr_renderer *renderer = cursor->output->renderer;
if (!renderer) {
// if the backend has no renderer, we can't draw a cursor, but this is
// actually okay, for ex. with the noop backend
@ -476,9 +480,8 @@ void wlr_output_cursor_set_surface(struct wlr_output_cursor *cursor,
wlr_output_transform_invert(cursor->output->transform),
buffer ? buffer->width : 0, buffer ? buffer->height : 0);
assert(cursor->output->impl->set_cursor);
cursor->output->impl->set_cursor(cursor->output,
buffer, hotspot.x, hotspot.y);
output_set_hardware_cursor(cursor->output, buffer,
hotspot.x, hotspot.y);
}
return;
}
@ -501,8 +504,7 @@ void wlr_output_cursor_set_surface(struct wlr_output_cursor *cursor,
cursor->height = 0;
if (cursor->output->hardware_cursor == cursor) {
assert(cursor->output->impl->set_cursor);
cursor->output->impl->set_cursor(cursor->output, NULL, 0, 0);
output_set_hardware_cursor(cursor->output, NULL, 0, 0);
}
}
}
@ -563,9 +565,7 @@ void wlr_output_cursor_destroy(struct wlr_output_cursor *cursor) {
wlr_signal_emit_safe(&cursor->events.destroy, cursor);
if (cursor->output->hardware_cursor == cursor) {
// If this cursor was the hardware cursor, disable it
if (cursor->output->impl->set_cursor) {
cursor->output->impl->set_cursor(cursor->output, NULL, 0, 0);
}
output_set_hardware_cursor(cursor->output, NULL, 0, 0);
cursor->output->hardware_cursor = NULL;
}
wlr_texture_destroy(cursor->texture);

View file

@ -1,16 +1,19 @@
#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_compositor.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"
#include "util/signal.h"
#define OUTPUT_VERSION 3
#define OUTPUT_VERSION 4
static void send_geometry(struct wl_resource *resource) {
struct wlr_output *output = wlr_output_from_resource(resource);
@ -40,6 +43,23 @@ static void send_scale(struct wl_resource *resource) {
}
}
static void send_name(struct wl_resource *resource) {
struct wlr_output *output = wlr_output_from_resource(resource);
uint32_t version = wl_resource_get_version(resource);
if (version >= WL_OUTPUT_NAME_SINCE_VERSION) {
wl_output_send_name(resource, output->name);
}
}
static void send_description(struct wl_resource *resource) {
struct wlr_output *output = wlr_output_from_resource(resource);
uint32_t version = wl_resource_get_version(resource);
if (output->description != NULL &&
version >= WL_OUTPUT_DESCRIPTION_SINCE_VERSION) {
wl_output_send_description(resource, output->description);
}
}
static void send_done(struct wl_resource *resource) {
uint32_t version = wl_resource_get_version(resource);
if (version >= WL_OUTPUT_DONE_SINCE_VERSION) {
@ -84,6 +104,8 @@ static void output_bind(struct wl_client *wl_client, void *data,
send_geometry(resource);
send_current_mode(resource);
send_scale(resource);
send_name(resource);
send_description(resource);
send_done(resource);
struct wlr_output_event_bind evt = {
@ -118,7 +140,7 @@ void wlr_output_destroy_global(struct wlr_output *output) {
wl_list_init(wl_resource_get_link(resource));
}
wlr_global_destroy_safe(output->global, output->display);
wlr_global_destroy_safe(output->global);
output->global = NULL;
}
@ -128,10 +150,7 @@ static void schedule_done_handle_idle_timer(void *data) {
struct wl_resource *resource;
wl_resource_for_each(resource, &output->resources) {
uint32_t version = wl_resource_get_version(resource);
if (version >= WL_OUTPUT_DONE_SINCE_VERSION) {
wl_output_send_done(resource);
}
send_done(resource);
}
}
@ -296,6 +315,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) {
@ -311,6 +340,13 @@ void wlr_output_set_subpixel(struct wlr_output *output,
wlr_output_schedule_done(output);
}
void wlr_output_set_name(struct wlr_output *output, const char *name) {
assert(output->global == NULL);
free(output->name);
output->name = strdup(name);
}
void wlr_output_set_description(struct wlr_output *output, const char *desc) {
if (output->description != NULL && desc != NULL &&
strcmp(output->description, desc) == 0) {
@ -324,6 +360,12 @@ void wlr_output_set_description(struct wlr_output *output, const char *desc) {
output->description = NULL;
}
struct wl_resource *resource;
wl_resource_for_each(resource, &output->resources) {
send_description(resource);
}
wlr_output_schedule_done(output);
wlr_signal_emit_safe(&output->events.description, output);
}
@ -343,6 +385,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;
@ -379,9 +422,6 @@ void wlr_output_destroy(struct wlr_output *output) {
return;
}
wlr_buffer_unlock(output->front_buffer);
output->front_buffer = NULL;
wl_list_remove(&output->display_destroy.link);
wlr_output_destroy_global(output);
output_clear_back_buffer(output);
@ -409,6 +449,7 @@ void wlr_output_destroy(struct wlr_output *output) {
wl_event_source_remove(output->idle_done);
}
free(output->name);
free(output->description);
pixman_region32_fini(&output->pending.damage);
@ -542,6 +583,22 @@ 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 =
wlr_output_get_primary_formats(output, allocator->buffer_caps);
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 +626,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;
@ -578,6 +639,9 @@ static bool output_basic_test(struct wlr_output *output) {
}
bool wlr_output_test(struct wlr_output *output) {
bool had_buffer = output->pending.committed & WLR_OUTPUT_STATE_BUFFER;
bool success;
if (!output_basic_test(output)) {
return false;
}
@ -587,7 +651,13 @@ bool wlr_output_test(struct wlr_output *output) {
if (!output->impl->test) {
return true;
}
return output->impl->test(output);
success = output->impl->test(output);
if (!had_buffer) {
output_clear_back_buffer(output);
}
return success;
}
bool wlr_output_commit(struct wlr_output *output) {
@ -642,6 +712,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;
@ -669,13 +743,13 @@ bool wlr_output_commit(struct wlr_output *output) {
wlr_output_schedule_done(output);
}
// Unset the front-buffer when a new buffer will replace it or when the
// output is getting disabled
if ((output->pending.committed & WLR_OUTPUT_STATE_BUFFER) ||
((output->pending.committed & WLR_OUTPUT_STATE_ENABLED) &&
!output->pending.enabled)) {
wlr_buffer_unlock(output->front_buffer);
output->front_buffer = NULL;
// Destroy the swapchains when an output is disabled
if ((output->pending.committed & WLR_OUTPUT_STATE_ENABLED) &&
!output->pending.enabled) {
wlr_swapchain_destroy(output->swapchain);
output->swapchain = NULL;
wlr_swapchain_destroy(output->cursor_swapchain);
output->cursor_swapchain = NULL;
}
if (output->pending.committed & WLR_OUTPUT_STATE_BUFFER) {
@ -685,8 +759,6 @@ bool wlr_output_commit(struct wlr_output *output) {
if (back_buffer != NULL) {
wlr_swapchain_set_buffer_submitted(output->swapchain, back_buffer);
wlr_buffer_unlock(output->front_buffer);
output->front_buffer = back_buffer;
}
uint32_t committed = output->pending.committed;
@ -696,9 +768,14 @@ bool wlr_output_commit(struct wlr_output *output) {
.output = output,
.committed = committed,
.when = &now,
.buffer = back_buffer,
};
wlr_signal_emit_safe(&output->events.commit, &event);
if (back_buffer != NULL) {
wlr_buffer_unlock(back_buffer);
}
return true;
}
@ -819,3 +896,21 @@ void wlr_output_damage_whole(struct wlr_output *output) {
pixman_region32_fini(&damage);
}
const struct wlr_drm_format_set *wlr_output_get_primary_formats(
struct wlr_output *output, uint32_t buffer_caps) {
if (!output->impl->get_primary_formats) {
return NULL;
}
const struct wlr_drm_format_set *formats =
output->impl->get_primary_formats(output, buffer_caps);
if (formats == NULL) {
wlr_log(WLR_ERROR, "Failed to get primary display formats");
static const struct wlr_drm_format_set empty_format_set = {0};
return &empty_format_set;
}
return formats;
}

View file

@ -9,8 +9,33 @@
#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,
struct wlr_allocator *allocator, struct wlr_renderer *renderer) {
assert(output->allocator == NULL && allocator != NULL);
assert(output->renderer == NULL && renderer != NULL);
uint32_t backend_caps = backend_get_buffer_caps(output->backend);
uint32_t renderer_caps = renderer_get_render_buffer_caps(renderer);
if (!(backend_caps & allocator->buffer_caps)) {
wlr_log(WLR_ERROR, "output backend and allocator buffer capabilities "
"don't match");
return false;
} else if (!(renderer_caps & allocator->buffer_caps)) {
wlr_log(WLR_ERROR, "renderer and allocator buffer capabilities "
"don't match");
return false;
}
output->allocator = allocator;
output->renderer = renderer;
return true;
}
/**
* Ensure the output has a suitable swapchain. The swapchain is re-created if
* necessary.
@ -23,39 +48,40 @@ 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);
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);
const struct wlr_drm_format_set *display_formats =
wlr_output_get_primary_formats(output, allocator->buffer_caps);
struct wlr_drm_format *format = output_pick_format(output, display_formats,
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);
if (!allow_modifiers && (format->len != 1 || format->modifiers[0] != DRM_FORMAT_MOD_LINEAR)) {
if (!wlr_drm_format_has(format, DRM_FORMAT_MOD_INVALID)) {
wlr_log(WLR_DEBUG, "Implicit modifiers not supported");
free(format);
return false;
}
format->len = 0;
wlr_drm_format_add(&format, DRM_FORMAT_MOD_INVALID);
}
struct wlr_swapchain *swapchain =
@ -80,7 +106,7 @@ static bool output_attach_back_buffer(struct wlr_output *output,
return false;
}
struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend);
struct wlr_renderer *renderer = output->renderer;
assert(renderer != NULL);
struct wlr_buffer *buffer =
@ -103,7 +129,7 @@ void output_clear_back_buffer(struct wlr_output *output) {
return;
}
struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend);
struct wlr_renderer *renderer = output->renderer;
assert(renderer != NULL);
renderer_bind_buffer(renderer, NULL);
@ -130,7 +156,7 @@ static bool output_attach_empty_buffer(struct wlr_output *output) {
int width, height;
output_pending_resolution(output, &width, &height);
struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend);
struct wlr_renderer *renderer = output->renderer;
wlr_renderer_begin(renderer, width, height);
wlr_renderer_clear(renderer, (float[]){0, 0, 0, 0});
wlr_renderer_end(renderer);
@ -149,6 +175,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;
@ -210,9 +239,10 @@ void wlr_output_lock_attach_render(struct wlr_output *output, bool lock) {
}
struct wlr_drm_format *output_pick_format(struct wlr_output *output,
const struct wlr_drm_format_set *display_formats) {
struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend);
struct wlr_allocator *allocator = backend_get_allocator(output->backend);
const struct wlr_drm_format_set *display_formats,
uint32_t fmt) {
struct wlr_renderer *renderer = output->renderer;
struct wlr_allocator *allocator = output->allocator;
assert(renderer != NULL && allocator != NULL);
const struct wlr_drm_format_set *render_formats =
@ -222,41 +252,31 @@ struct wlr_drm_format *output_pick_format(struct wlr_output *output,
return NULL;
}
struct wlr_drm_format *format = NULL;
const uint32_t candidates[] = { DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888 };
for (size_t i = 0; i < sizeof(candidates) / sizeof(candidates[0]); i++) {
uint32_t fmt = candidates[i];
const struct wlr_drm_format *render_format =
wlr_drm_format_set_get(render_formats, fmt);
if (render_format == NULL) {
wlr_log(WLR_DEBUG, "Renderer doesn't support format 0x%"PRIX32, fmt);
continue;
}
if (display_formats != NULL) {
const struct wlr_drm_format *display_format =
wlr_drm_format_set_get(display_formats, fmt);
if (display_format == NULL) {
wlr_log(WLR_DEBUG, "Output doesn't support format 0x%"PRIX32, fmt);
continue;
}
format = wlr_drm_format_intersect(display_format, render_format);
} else {
// The output can display any format
format = wlr_drm_format_dup(render_format);
}
if (format == NULL) {
wlr_log(WLR_DEBUG, "Failed to intersect display and render "
"modifiers for format 0x%"PRIX32, fmt);
} else {
break;
}
const struct wlr_drm_format *render_format =
wlr_drm_format_set_get(render_formats, fmt);
if (render_format == NULL) {
wlr_log(WLR_DEBUG, "Renderer doesn't support format 0x%"PRIX32, fmt);
return NULL;
}
struct wlr_drm_format *format = NULL;
if (display_formats != NULL) {
const struct wlr_drm_format *display_format =
wlr_drm_format_set_get(display_formats, fmt);
if (display_format == NULL) {
wlr_log(WLR_DEBUG, "Output doesn't support format 0x%"PRIX32, fmt);
return NULL;
}
format = wlr_drm_format_intersect(display_format, render_format);
} else {
// The output can display any format
format = wlr_drm_format_dup(render_format);
}
if (format == NULL) {
wlr_log(WLR_ERROR, "Failed to choose a format for output '%s'",
output->name);
wlr_log(WLR_DEBUG, "Failed to intersect display and render "
"modifiers for format 0x%"PRIX32 " on output '%s",
fmt, output->name);
return NULL;
}
@ -264,7 +284,9 @@ struct wlr_drm_format *output_pick_format(struct wlr_output *output,
}
uint32_t wlr_output_preferred_read_format(struct wlr_output *output) {
struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend);
struct wlr_renderer *renderer = output->renderer;
assert(renderer != NULL);
if (!renderer->impl->preferred_read_format || !renderer->impl->read_pixels) {
return DRM_FORMAT_INVALID;
}