Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit 86b64d3

Browse files
committed
wip: output-swapchain: new helper
1 parent 6cb25eb commit 86b64d3

File tree

3 files changed

+243
-0
lines changed

3 files changed

+243
-0
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* This an unstable interface of wlroots. No guarantees are made regarding the
3+
* future consistency of this API.
4+
*/
5+
#ifndef WLR_USE_UNSTABLE
6+
#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
7+
#endif
8+
9+
#ifndef WLR_TYPES_WLR_OUTPUT_SWAPCHAIN_H
10+
#define WLR_TYPES_WLR_OUTPUT_SWAPCHAIN_H
11+
12+
#include <wayland-util.h>
13+
14+
struct wlr_output;
15+
16+
struct wlr_output_swapchain {
17+
struct wlr_output *output;
18+
struct wlr_swapchain *swapchain;
19+
struct wlr_renderer *renderer;
20+
21+
// private state
22+
23+
struct wlr_buffer *back_buffer;
24+
25+
struct wl_listener output_destroy;
26+
};
27+
28+
struct wlr_output_swapchain *wlr_output_swapchain_create(
29+
struct wlr_output *output);
30+
void wlr_output_swapchain_destroy(struct wlr_output_swapchain *output_swapchain);
31+
bool wlr_output_swapchain_begin(struct wlr_output_swapchain *output_swapchain);
32+
void wlr_output_swapchain_end(struct wlr_output_swapchain *output_swapchain);
33+
34+
#endif

types/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ wlr_files += files(
4242
'wlr_output_layout.c',
4343
'wlr_output_management_v1.c',
4444
'wlr_output_power_management_v1.c',
45+
'wlr_output_swapchain.c',
4546
'wlr_output.c',
4647
'wlr_pointer_constraints_v1.c',
4748
'wlr_pointer_gestures_v1.c',

types/wlr_output_swapchain.c

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
#include <assert.h>
2+
#include <drm_fourcc.h>
3+
#include <stdlib.h>
4+
#include <wlr/backend.h>
5+
#include <wlr/interfaces/wlr_output.h>
6+
#include <wlr/render/wlr_renderer.h>
7+
#include <wlr/types/wlr_output.h>
8+
#include <wlr/types/wlr_output_swapchain.h>
9+
#include <wlr/util/log.h>
10+
#include "backend/backend.h"
11+
#include "render/allocator/allocator.h"
12+
#include "render/drm_format_set.h"
13+
#include "render/swapchain.h"
14+
#include "render/wlr_renderer.h"
15+
16+
static void output_pending_resolution(struct wlr_output *output, int *width,
17+
int *height) {
18+
if (output->pending.committed & WLR_OUTPUT_STATE_MODE) {
19+
switch (output->pending.mode_type) {
20+
case WLR_OUTPUT_STATE_MODE_FIXED:
21+
*width = output->pending.mode->width;
22+
*height = output->pending.mode->height;
23+
return;
24+
case WLR_OUTPUT_STATE_MODE_CUSTOM:
25+
*width = output->pending.custom_mode.width;
26+
*height = output->pending.custom_mode.height;
27+
return;
28+
}
29+
abort();
30+
} else {
31+
*width = output->width;
32+
*height = output->height;
33+
}
34+
}
35+
36+
static struct wlr_drm_format *output_pick_format(struct wlr_output *output,
37+
const struct wlr_drm_format_set *display_formats) {
38+
struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend);
39+
struct wlr_allocator *allocator = backend_get_allocator(output->backend);
40+
assert(renderer != NULL && allocator != NULL);
41+
42+
const struct wlr_drm_format_set *render_formats =
43+
wlr_renderer_get_render_formats(renderer);
44+
if (render_formats == NULL) {
45+
wlr_log(WLR_ERROR, "Failed to get render formats");
46+
return NULL;
47+
}
48+
49+
struct wlr_drm_format *format = NULL;
50+
const uint32_t candidates[] = { DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888 };
51+
for (size_t i = 0; i < sizeof(candidates) / sizeof(candidates[0]); i++) {
52+
uint32_t fmt = candidates[i];
53+
54+
const struct wlr_drm_format *render_format =
55+
wlr_drm_format_set_get(render_formats, fmt);
56+
if (render_format == NULL) {
57+
wlr_log(WLR_DEBUG, "Renderer doesn't support format 0x%"PRIX32, fmt);
58+
continue;
59+
}
60+
61+
if (display_formats != NULL) {
62+
const struct wlr_drm_format *display_format =
63+
wlr_drm_format_set_get(display_formats, fmt);
64+
if (display_format == NULL) {
65+
wlr_log(WLR_DEBUG, "Output doesn't support format 0x%"PRIX32, fmt);
66+
continue;
67+
}
68+
format = wlr_drm_format_intersect(display_format, render_format);
69+
} else {
70+
// The output can display any format
71+
format = wlr_drm_format_dup(render_format);
72+
}
73+
74+
if (format == NULL) {
75+
wlr_log(WLR_DEBUG, "Failed to intersect display and render "
76+
"modifiers for format 0x%"PRIX32, fmt);
77+
} else {
78+
break;
79+
}
80+
}
81+
if (format == NULL) {
82+
wlr_log(WLR_ERROR, "Failed to choose a format for output '%s'",
83+
output->name);
84+
return NULL;
85+
}
86+
87+
return format;
88+
}
89+
90+
static bool update_swapchain(struct wlr_output_swapchain *output_swapchain,
91+
bool allow_modifiers) {
92+
struct wlr_output *output = output_swapchain->output;
93+
94+
int width, height;
95+
output_pending_resolution(output, &width, &height);
96+
97+
if (output_swapchain->swapchain != NULL &&
98+
output_swapchain->swapchain->width == width &&
99+
output_swapchain->swapchain->height == height &&
100+
(allow_modifiers || output->swapchain->format->len == 0)) {
101+
return true;
102+
}
103+
104+
struct wlr_allocator *allocator = backend_get_allocator(output->backend);
105+
if (allocator == NULL) {
106+
wlr_log(WLR_ERROR, "Failed to get backend allocator");
107+
return false;
108+
}
109+
110+
const struct wlr_drm_format_set *display_formats = NULL;
111+
if (output->impl->get_primary_formats) {
112+
display_formats =
113+
output->impl->get_primary_formats(output, allocator->buffer_caps);
114+
if (display_formats == NULL) {
115+
wlr_log(WLR_ERROR, "Failed to get primary display formats");
116+
return false;
117+
}
118+
}
119+
120+
struct wlr_drm_format *format = output_pick_format(output, display_formats);
121+
if (format == NULL) {
122+
wlr_log(WLR_ERROR, "Failed to pick primary buffer format for output '%s'",
123+
output->name);
124+
return false;
125+
}
126+
wlr_log(WLR_DEBUG, "Choosing primary buffer format 0x%"PRIX32" for output '%s'",
127+
format->format, output->name);
128+
129+
if (!allow_modifiers && (format->len != 1 || format->modifiers[0] != DRM_FORMAT_MOD_LINEAR)) {
130+
format->len = 0;
131+
}
132+
133+
struct wlr_swapchain *swapchain =
134+
wlr_swapchain_create(allocator, width, height, format);
135+
free(format);
136+
if (swapchain == NULL) {
137+
wlr_log(WLR_ERROR, "Failed to create output swapchain");
138+
return false;
139+
}
140+
141+
wlr_swapchain_destroy(output_swapchain->swapchain);
142+
output_swapchain->swapchain = swapchain;
143+
return true;
144+
}
145+
146+
static void handle_output_destroy(struct wl_listener *listener, void *data) {
147+
struct wlr_output_swapchain *output_swapchain =
148+
wl_container_of(listener, output_swapchain, output_destroy);
149+
wlr_output_swapchain_destroy(output_swapchain);
150+
}
151+
152+
struct wlr_output_swapchain *wlr_output_swapchain_create(
153+
struct wlr_output *output) {
154+
struct wlr_output_swapchain *output_swapchain =
155+
calloc(1, sizeof(*output_swapchain));
156+
if (output_swapchain == NULL) {
157+
return NULL;
158+
}
159+
160+
output_swapchain->output = output;
161+
162+
output_swapchain->renderer = wlr_backend_get_renderer(output->backend);
163+
assert(output_swapchain->renderer != NULL);
164+
165+
output_swapchain->output_destroy.notify = handle_output_destroy;
166+
wl_signal_add(&output->events.destroy, &output_swapchain->output_destroy);
167+
168+
return output_swapchain;
169+
}
170+
171+
void wlr_output_swapchain_destroy(struct wlr_output_swapchain *output_swapchain) {
172+
wl_list_remove(&output_swapchain->output_destroy.link);
173+
free(output_swapchain);
174+
}
175+
176+
bool wlr_output_swapchain_begin(struct wlr_output_swapchain *output_swapchain) {
177+
assert(output_swapchain->back_buffer == NULL);
178+
179+
if (!update_swapchain(output_swapchain, true)) {
180+
return false;
181+
}
182+
183+
struct wlr_buffer *buffer =
184+
wlr_swapchain_acquire(output_swapchain->swapchain, NULL);
185+
if (buffer == NULL) {
186+
return false;
187+
}
188+
189+
if (!wlr_renderer_begin_with_buffer(output_swapchain->renderer, buffer)) {
190+
wlr_buffer_unlock(buffer);
191+
return false;
192+
}
193+
194+
output_swapchain->back_buffer = buffer;
195+
return true;
196+
}
197+
198+
void wlr_output_swapchain_end(struct wlr_output_swapchain *output_swapchain) {
199+
assert(output_swapchain->back_buffer != NULL);
200+
201+
wlr_renderer_end(output_swapchain->renderer);
202+
203+
wlr_output_attach_buffer(output_swapchain->output,
204+
output_swapchain->back_buffer);
205+
206+
wlr_buffer_unlock(output_swapchain->back_buffer);
207+
output_swapchain->back_buffer = NULL;
208+
}

0 commit comments

Comments
 (0)