@@ -21,13 +21,22 @@ extern "C" {
2121#include < wlr/render/interface.h>
2222#undef static
2323#include < wlr/types/wlr_output_layout.h>
24+ #ifdef slots
25+ #undef slots // using at swapchain.h
26+ #endif
27+ #include < wlr/render/swapchain.h>
28+ #include < wlr/render/allocator.h>
29+ #include < wlr/render/wlr_renderer.h>
2430}
2531
2632#include < QLoggingCategory>
2733#include < QCoreApplication>
2834#include < QQuickWindow>
2935#include < QCursor>
3036
37+ #include < xf86drm.h>
38+ #include < drm_fourcc.h>
39+
3140QW_USE_NAMESPACE
3241WAYLIB_SERVER_BEGIN_NAMESPACE
3342
@@ -139,6 +148,262 @@ QWAllocator *WOutput::allocator() const
139148 return QWAllocator::from (d->nativeHandle ()->allocator );
140149}
141150
151+ // Copy from wlroots
152+ static const struct wlr_drm_format_set *wlr_renderer_get_render_formats (
153+ struct wlr_renderer *r) {
154+ if (!r->impl ->get_render_formats ) {
155+ return NULL ;
156+ }
157+ return r->impl ->get_render_formats (r);
158+ }
159+
160+ static bool wlr_drm_format_copy (struct wlr_drm_format *dst, const struct wlr_drm_format *src) {
161+ assert (src->len <= src->capacity );
162+
163+ uint64_t *modifiers = reinterpret_cast <uint64_t *>(malloc (sizeof (*modifiers) * src->len ));
164+ if (!modifiers) {
165+ return false ;
166+ }
167+
168+ memcpy (modifiers, src->modifiers , sizeof (*modifiers) * src->len );
169+
170+ wlr_drm_format_finish (dst);
171+ dst->capacity = src->len ;
172+ dst->len = src->len ;
173+ dst->format = src->format ;
174+ dst->modifiers = modifiers;
175+ return true ;
176+ }
177+
178+ static bool wlr_drm_format_has (const struct wlr_drm_format *fmt, uint64_t modifier) {
179+ for (size_t i = 0 ; i < fmt->len ; ++i) {
180+ if (fmt->modifiers [i] == modifier) {
181+ return true ;
182+ }
183+ }
184+ return false ;
185+ }
186+
187+ static bool wlr_drm_format_add (struct wlr_drm_format *fmt, uint64_t modifier) {
188+ if (wlr_drm_format_has (fmt, modifier)) {
189+ return true ;
190+ }
191+
192+ if (fmt->len == fmt->capacity ) {
193+ size_t capacity = fmt->capacity ? fmt->capacity * 2 : 4 ;
194+
195+ uint64_t *new_modifiers = reinterpret_cast <uint64_t *>(realloc (fmt->modifiers , sizeof (*fmt->modifiers ) * capacity));
196+ if (!new_modifiers) {
197+ qCritical (" Allocation failed" );
198+ return false ;
199+ }
200+
201+ fmt->capacity = capacity;
202+ fmt->modifiers = new_modifiers;
203+ }
204+
205+ fmt->modifiers [fmt->len ++] = modifier;
206+ return true ;
207+ }
208+
209+ static bool wlr_drm_format_intersect (struct wlr_drm_format *dst,
210+ const struct wlr_drm_format *a, const struct wlr_drm_format *b) {
211+ assert (a->format == b->format );
212+
213+ size_t capacity = a->len < b->len ? a->len : b->len ;
214+ uint64_t *modifiers = reinterpret_cast <uint64_t *>(malloc (sizeof (*modifiers) * capacity));
215+ if (!modifiers) {
216+ return false ;
217+ }
218+
219+ wlr_drm_format fmt = {
220+ .format = a->format ,
221+ .len = 0 ,
222+ .capacity = capacity,
223+ .modifiers = modifiers,
224+ };
225+
226+ for (size_t i = 0 ; i < a->len ; i++) {
227+ for (size_t j = 0 ; j < b->len ; j++) {
228+ if (a->modifiers [i] == b->modifiers [j]) {
229+ assert (fmt.len < fmt.capacity );
230+ fmt.modifiers [fmt.len ++] = a->modifiers [i];
231+ break ;
232+ }
233+ }
234+ }
235+
236+ wlr_drm_format_finish (dst);
237+ *dst = fmt;
238+ return true ;
239+ }
240+
241+ static bool output_pick_format (struct wlr_output *output,
242+ const struct wlr_drm_format_set *display_formats,
243+ struct wlr_drm_format *format, uint32_t fmt) {
244+ struct wlr_renderer *renderer = output->renderer ;
245+ struct wlr_allocator *allocator = output->allocator ;
246+ assert (renderer != NULL && allocator != NULL );
247+
248+ const struct wlr_drm_format_set *render_formats =
249+ wlr_renderer_get_render_formats (renderer);
250+ if (render_formats == NULL ) {
251+ qCritical (" Failed to get render formats" );
252+ return false ;
253+ }
254+
255+ const struct wlr_drm_format *render_format =
256+ wlr_drm_format_set_get (render_formats, fmt);
257+ if (render_format == NULL ) {
258+ qDebug (" Renderer doesn't support format 0x%" PRIX32, fmt);
259+ return false ;
260+ }
261+
262+ if (display_formats != NULL ) {
263+ const struct wlr_drm_format *display_format =
264+ wlr_drm_format_set_get (display_formats, fmt);
265+ if (display_format == NULL ) {
266+ qDebug (" Output doesn't support format 0x%" PRIX32, fmt);
267+ return false ;
268+ }
269+ if (!wlr_drm_format_intersect (format, display_format, render_format)) {
270+ qDebug (" Failed to intersect display and render "
271+ " modifiers for format 0x%" PRIX32 " on output %s" ,
272+ fmt, output->name );
273+ return false ;
274+ }
275+ } else {
276+ // The output can display any format
277+ if (!wlr_drm_format_copy (format, render_format)) {
278+ return false ;
279+ }
280+ }
281+
282+ if (format->len == 0 ) {
283+ wlr_drm_format_finish (format);
284+ qDebug (" Failed to pick output format" );
285+ return false ;
286+ }
287+
288+ return true ;
289+ }
290+
291+ static struct wlr_swapchain *create_swapchain (struct wlr_output *output,
292+ int width, int height,
293+ uint32_t render_format,
294+ bool allow_modifiers) {
295+ wlr_allocator *allocator = output->allocator ;
296+ assert (output->allocator != NULL );
297+
298+ const struct wlr_drm_format_set *display_formats =
299+ wlr_output_get_primary_formats (output, allocator->buffer_caps );
300+ struct wlr_drm_format format = {0 };
301+ if (!output_pick_format (output, display_formats, &format, render_format)) {
302+ qDebug (" Failed to pick primary buffer format for output '%s'" ,
303+ output->name );
304+ return NULL ;
305+ }
306+
307+ char *format_name = drmGetFormatName (format.format );
308+ qDebug (" Choosing primary buffer format %s (0x%08" PRIX32 " ) for output '%s'" ,
309+ format_name ? format_name : " <unknown>" , format.format , output->name );
310+ free (format_name);
311+
312+ if (!allow_modifiers && (format.len != 1 || format.modifiers [0 ] != DRM_FORMAT_MOD_LINEAR)) {
313+ if (!wlr_drm_format_has (&format, DRM_FORMAT_MOD_INVALID)) {
314+ qDebug (" Implicit modifiers not supported" );
315+ wlr_drm_format_finish (&format);
316+ return NULL ;
317+ }
318+
319+ format.len = 0 ;
320+ if (!wlr_drm_format_add (&format, DRM_FORMAT_MOD_INVALID)) {
321+ qDebug (" Failed to add implicit modifier to format" );
322+ wlr_drm_format_finish (&format);
323+ return NULL ;
324+ }
325+ }
326+
327+ struct wlr_swapchain *swapchain = wlr_swapchain_create (allocator, width, height, &format);
328+ wlr_drm_format_finish (&format);
329+ return swapchain;
330+ }
331+
332+ static bool test_swapchain (struct wlr_output *output,
333+ struct wlr_swapchain *swapchain, const struct wlr_output_state *state) {
334+ struct wlr_buffer *buffer = wlr_swapchain_acquire (swapchain, NULL );
335+ if (buffer == NULL ) {
336+ return false ;
337+ }
338+
339+ struct wlr_output_state copy = *state;
340+ copy.committed |= WLR_OUTPUT_STATE_BUFFER;
341+ copy.buffer = buffer;
342+ bool ok = wlr_output_test_state (output, ©);
343+ wlr_buffer_unlock (buffer);
344+ return ok;
345+ }
346+
347+ static bool wlr_output_configure_primary_swapchain (struct wlr_output *output, int width, int height,
348+ uint32_t format, struct wlr_swapchain **swapchain_ptr,
349+ bool test) {
350+ wlr_output_state empty_state;
351+ wlr_output_state_init (&empty_state);
352+ wlr_output_state *state = &empty_state;
353+
354+ // Re-use the existing swapchain if possible
355+ struct wlr_swapchain *old_swapchain = *swapchain_ptr;
356+ if (old_swapchain != NULL &&
357+ old_swapchain->width == width && old_swapchain->height == height &&
358+ old_swapchain->format .format == format) {
359+ return true ;
360+ }
361+
362+ struct wlr_swapchain *swapchain = create_swapchain (output, width, height, format, true );
363+ if (swapchain == NULL ) {
364+ qCritical (" Failed to create swapchain for output '%s'" , output->name );
365+ return false ;
366+ }
367+
368+ if (test) {
369+ qDebug (" Testing swapchain for output '%s'" , output->name );
370+ if (!test_swapchain (output, swapchain, state)) {
371+ qDebug (" Output test failed on '%s', retrying without modifiers" ,
372+ output->name );
373+ wlr_swapchain_destroy (swapchain);
374+ swapchain = create_swapchain (output, width, height, format, false );
375+ if (swapchain == NULL ) {
376+ qCritical (" Failed to create modifier-less swapchain for output '%s'" ,
377+ output->name );
378+ return false ;
379+ }
380+ qDebug (" Testing modifier-less swapchain for output '%s'" , output->name );
381+ if (!test_swapchain (output, swapchain, state)) {
382+ qCritical (" Swapchain for output '%s' failed test" , output->name );
383+ wlr_swapchain_destroy (swapchain);
384+ return false ;
385+ }
386+ }
387+ }
388+
389+ wlr_swapchain_destroy (*swapchain_ptr);
390+ *swapchain_ptr = swapchain;
391+ return true ;
392+ }
393+ // End
394+
395+ bool WOutput::configureSwapchain (const QSize &size, uint32_t format,
396+ QWSwapchain **swapchain, bool doTest)
397+ {
398+ wlr_swapchain *sc = (*swapchain)->handle ();
399+ bool ok = wlr_output_configure_primary_swapchain (nativeHandle (), size.width (), size.height (),
400+ format, &sc, doTest);
401+ if (!ok)
402+ return false ;
403+ *swapchain = QWSwapchain::from (sc);
404+ return true ;
405+ }
406+
142407QWOutput *WOutput::handle () const
143408{
144409 W_DC (WOutput);
0 commit comments