Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/vulkan/wsi/wsi_common_display.c
7263 views
1
/*
2
* Copyright © 2017 Keith Packard
3
*
4
* Permission to use, copy, modify, distribute, and sell this software and its
5
* documentation for any purpose is hereby granted without fee, provided that
6
* the above copyright notice appear in all copies and that both that copyright
7
* notice and this permission notice appear in supporting documentation, and
8
* that the name of the copyright holders not be used in advertising or
9
* publicity pertaining to distribution of the software without specific,
10
* written prior permission. The copyright holders make no representations
11
* about the suitability of this software for any purpose. It is provided "as
12
* is" without express or implied warranty.
13
*
14
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20
* OF THIS SOFTWARE.
21
*/
22
23
#include "util/macros.h"
24
#include <stdlib.h>
25
#include <stdio.h>
26
#include <unistd.h>
27
#include <errno.h>
28
#include <string.h>
29
#include <fcntl.h>
30
#include <poll.h>
31
#include <stdbool.h>
32
#include <math.h>
33
#include <xf86drm.h>
34
#include <xf86drmMode.h>
35
#include "drm-uapi/drm_fourcc.h"
36
#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
37
#include <xcb/randr.h>
38
#include <X11/Xlib-xcb.h>
39
#endif
40
#include "util/hash_table.h"
41
#include "util/list.h"
42
43
#include "vk_util.h"
44
#include "wsi_common_private.h"
45
#include "wsi_common_display.h"
46
#include "wsi_common_queue.h"
47
48
#if 0
49
#define wsi_display_debug(...) fprintf(stderr, __VA_ARGS__)
50
#define wsi_display_debug_code(...) __VA_ARGS__
51
#else
52
#define wsi_display_debug(...)
53
#define wsi_display_debug_code(...)
54
#endif
55
56
/* These have lifetime equal to the instance, so they effectively
57
* never go away. This means we must keep track of them separately
58
* from all other resources.
59
*/
60
typedef struct wsi_display_mode {
61
struct list_head list;
62
struct wsi_display_connector *connector;
63
bool valid; /* was found in most recent poll */
64
bool preferred;
65
uint32_t clock; /* in kHz */
66
uint16_t hdisplay, hsync_start, hsync_end, htotal, hskew;
67
uint16_t vdisplay, vsync_start, vsync_end, vtotal, vscan;
68
uint32_t flags;
69
} wsi_display_mode;
70
71
typedef struct wsi_display_connector {
72
struct list_head list;
73
struct wsi_display *wsi;
74
uint32_t id;
75
uint32_t crtc_id;
76
char *name;
77
bool connected;
78
bool active;
79
struct list_head display_modes;
80
wsi_display_mode *current_mode;
81
drmModeModeInfo current_drm_mode;
82
uint32_t dpms_property;
83
#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
84
xcb_randr_output_t output;
85
#endif
86
} wsi_display_connector;
87
88
struct wsi_display {
89
struct wsi_interface base;
90
91
const VkAllocationCallbacks *alloc;
92
93
int fd;
94
95
pthread_mutex_t wait_mutex;
96
pthread_cond_t wait_cond;
97
pthread_t wait_thread;
98
99
struct list_head connectors; /* list of all discovered connectors */
100
};
101
102
#define wsi_for_each_display_mode(_mode, _conn) \
103
list_for_each_entry_safe(struct wsi_display_mode, _mode, \
104
&(_conn)->display_modes, list)
105
106
#define wsi_for_each_connector(_conn, _dev) \
107
list_for_each_entry_safe(struct wsi_display_connector, _conn, \
108
&(_dev)->connectors, list)
109
110
enum wsi_image_state {
111
WSI_IMAGE_IDLE,
112
WSI_IMAGE_DRAWING,
113
WSI_IMAGE_QUEUED,
114
WSI_IMAGE_FLIPPING,
115
WSI_IMAGE_DISPLAYING
116
};
117
118
struct wsi_display_image {
119
struct wsi_image base;
120
struct wsi_display_swapchain *chain;
121
enum wsi_image_state state;
122
uint32_t fb_id;
123
uint32_t buffer[4];
124
uint64_t flip_sequence;
125
};
126
127
struct wsi_display_swapchain {
128
struct wsi_swapchain base;
129
struct wsi_display *wsi;
130
VkIcdSurfaceDisplay *surface;
131
uint64_t flip_sequence;
132
VkResult status;
133
struct wsi_display_image images[0];
134
};
135
136
struct wsi_display_fence {
137
struct wsi_fence base;
138
bool event_received;
139
bool destroyed;
140
uint32_t syncobj; /* syncobj to signal on event */
141
uint64_t sequence;
142
};
143
144
static uint64_t fence_sequence;
145
146
ICD_DEFINE_NONDISP_HANDLE_CASTS(wsi_display_mode, VkDisplayModeKHR)
147
ICD_DEFINE_NONDISP_HANDLE_CASTS(wsi_display_connector, VkDisplayKHR)
148
149
static bool
150
wsi_display_mode_matches_drm(wsi_display_mode *wsi,
151
drmModeModeInfoPtr drm)
152
{
153
return wsi->clock == drm->clock &&
154
wsi->hdisplay == drm->hdisplay &&
155
wsi->hsync_start == drm->hsync_start &&
156
wsi->hsync_end == drm->hsync_end &&
157
wsi->htotal == drm->htotal &&
158
wsi->hskew == drm->hskew &&
159
wsi->vdisplay == drm->vdisplay &&
160
wsi->vsync_start == drm->vsync_start &&
161
wsi->vsync_end == drm->vsync_end &&
162
wsi->vtotal == drm->vtotal &&
163
MAX2(wsi->vscan, 1) == MAX2(drm->vscan, 1) &&
164
wsi->flags == drm->flags;
165
}
166
167
static double
168
wsi_display_mode_refresh(struct wsi_display_mode *wsi)
169
{
170
return (double) wsi->clock * 1000.0 / ((double) wsi->htotal *
171
(double) wsi->vtotal *
172
(double) MAX2(wsi->vscan, 1));
173
}
174
175
static uint64_t wsi_rel_to_abs_time(uint64_t rel_time)
176
{
177
uint64_t current_time = wsi_common_get_current_time();
178
179
/* check for overflow */
180
if (rel_time > UINT64_MAX - current_time)
181
return UINT64_MAX;
182
183
return current_time + rel_time;
184
}
185
186
static struct wsi_display_mode *
187
wsi_display_find_drm_mode(struct wsi_device *wsi_device,
188
struct wsi_display_connector *connector,
189
drmModeModeInfoPtr mode)
190
{
191
wsi_for_each_display_mode(display_mode, connector) {
192
if (wsi_display_mode_matches_drm(display_mode, mode))
193
return display_mode;
194
}
195
return NULL;
196
}
197
198
static void
199
wsi_display_invalidate_connector_modes(struct wsi_device *wsi_device,
200
struct wsi_display_connector *connector)
201
{
202
wsi_for_each_display_mode(display_mode, connector) {
203
display_mode->valid = false;
204
}
205
}
206
207
static VkResult
208
wsi_display_register_drm_mode(struct wsi_device *wsi_device,
209
struct wsi_display_connector *connector,
210
drmModeModeInfoPtr drm_mode)
211
{
212
struct wsi_display *wsi =
213
(struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
214
struct wsi_display_mode *display_mode =
215
wsi_display_find_drm_mode(wsi_device, connector, drm_mode);
216
217
if (display_mode) {
218
display_mode->valid = true;
219
return VK_SUCCESS;
220
}
221
222
display_mode = vk_zalloc(wsi->alloc, sizeof (struct wsi_display_mode),
223
8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
224
if (!display_mode)
225
return VK_ERROR_OUT_OF_HOST_MEMORY;
226
227
display_mode->connector = connector;
228
display_mode->valid = true;
229
display_mode->preferred = (drm_mode->type & DRM_MODE_TYPE_PREFERRED) != 0;
230
display_mode->clock = drm_mode->clock; /* kHz */
231
display_mode->hdisplay = drm_mode->hdisplay;
232
display_mode->hsync_start = drm_mode->hsync_start;
233
display_mode->hsync_end = drm_mode->hsync_end;
234
display_mode->htotal = drm_mode->htotal;
235
display_mode->hskew = drm_mode->hskew;
236
display_mode->vdisplay = drm_mode->vdisplay;
237
display_mode->vsync_start = drm_mode->vsync_start;
238
display_mode->vsync_end = drm_mode->vsync_end;
239
display_mode->vtotal = drm_mode->vtotal;
240
display_mode->vscan = drm_mode->vscan;
241
display_mode->flags = drm_mode->flags;
242
243
list_addtail(&display_mode->list, &connector->display_modes);
244
return VK_SUCCESS;
245
}
246
247
/*
248
* Update our information about a specific connector
249
*/
250
251
static struct wsi_display_connector *
252
wsi_display_find_connector(struct wsi_device *wsi_device,
253
uint32_t connector_id)
254
{
255
struct wsi_display *wsi =
256
(struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
257
258
wsi_for_each_connector(connector, wsi) {
259
if (connector->id == connector_id)
260
return connector;
261
}
262
263
return NULL;
264
}
265
266
static struct wsi_display_connector *
267
wsi_display_alloc_connector(struct wsi_display *wsi,
268
uint32_t connector_id)
269
{
270
struct wsi_display_connector *connector =
271
vk_zalloc(wsi->alloc, sizeof (struct wsi_display_connector),
272
8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
273
274
connector->id = connector_id;
275
connector->wsi = wsi;
276
connector->active = false;
277
/* XXX use EDID name */
278
connector->name = "monitor";
279
list_inithead(&connector->display_modes);
280
return connector;
281
}
282
283
static struct wsi_display_connector *
284
wsi_display_get_connector(struct wsi_device *wsi_device,
285
int drm_fd,
286
uint32_t connector_id)
287
{
288
struct wsi_display *wsi =
289
(struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
290
291
if (drm_fd < 0)
292
return NULL;
293
294
drmModeConnectorPtr drm_connector =
295
drmModeGetConnector(drm_fd, connector_id);
296
297
if (!drm_connector)
298
return NULL;
299
300
struct wsi_display_connector *connector =
301
wsi_display_find_connector(wsi_device, connector_id);
302
303
if (!connector) {
304
connector = wsi_display_alloc_connector(wsi, connector_id);
305
if (!connector) {
306
drmModeFreeConnector(drm_connector);
307
return NULL;
308
}
309
list_addtail(&connector->list, &wsi->connectors);
310
}
311
312
connector->connected = drm_connector->connection != DRM_MODE_DISCONNECTED;
313
314
/* Look for a DPMS property if we haven't already found one */
315
for (int p = 0; connector->dpms_property == 0 &&
316
p < drm_connector->count_props; p++)
317
{
318
drmModePropertyPtr prop = drmModeGetProperty(drm_fd,
319
drm_connector->props[p]);
320
if (!prop)
321
continue;
322
if (prop->flags & DRM_MODE_PROP_ENUM) {
323
if (!strcmp(prop->name, "DPMS"))
324
connector->dpms_property = drm_connector->props[p];
325
}
326
drmModeFreeProperty(prop);
327
}
328
329
/* Mark all connector modes as invalid */
330
wsi_display_invalidate_connector_modes(wsi_device, connector);
331
332
/*
333
* List current modes, adding new ones and marking existing ones as
334
* valid
335
*/
336
for (int m = 0; m < drm_connector->count_modes; m++) {
337
VkResult result = wsi_display_register_drm_mode(wsi_device,
338
connector,
339
&drm_connector->modes[m]);
340
if (result != VK_SUCCESS) {
341
drmModeFreeConnector(drm_connector);
342
return NULL;
343
}
344
}
345
346
drmModeFreeConnector(drm_connector);
347
348
return connector;
349
}
350
351
#define MM_PER_PIXEL (1.0/96.0 * 25.4)
352
353
static uint32_t
354
mode_size(struct wsi_display_mode *mode)
355
{
356
/* fortunately, these are both uint16_t, so this is easy */
357
return (uint32_t) mode->hdisplay * (uint32_t) mode->vdisplay;
358
}
359
360
static void
361
wsi_display_fill_in_display_properties(struct wsi_device *wsi_device,
362
struct wsi_display_connector *connector,
363
VkDisplayProperties2KHR *properties2)
364
{
365
assert(properties2->sType == VK_STRUCTURE_TYPE_DISPLAY_PROPERTIES_2_KHR);
366
VkDisplayPropertiesKHR *properties = &properties2->displayProperties;
367
368
properties->display = wsi_display_connector_to_handle(connector);
369
properties->displayName = connector->name;
370
371
/* Find the first preferred mode and assume that's the physical
372
* resolution. If there isn't a preferred mode, find the largest mode and
373
* use that.
374
*/
375
376
struct wsi_display_mode *preferred_mode = NULL, *largest_mode = NULL;
377
wsi_for_each_display_mode(display_mode, connector) {
378
if (!display_mode->valid)
379
continue;
380
if (display_mode->preferred) {
381
preferred_mode = display_mode;
382
break;
383
}
384
if (largest_mode == NULL ||
385
mode_size(display_mode) > mode_size(largest_mode))
386
{
387
largest_mode = display_mode;
388
}
389
}
390
391
if (preferred_mode) {
392
properties->physicalResolution.width = preferred_mode->hdisplay;
393
properties->physicalResolution.height = preferred_mode->vdisplay;
394
} else if (largest_mode) {
395
properties->physicalResolution.width = largest_mode->hdisplay;
396
properties->physicalResolution.height = largest_mode->vdisplay;
397
} else {
398
properties->physicalResolution.width = 1024;
399
properties->physicalResolution.height = 768;
400
}
401
402
/* Make up physical size based on 96dpi */
403
properties->physicalDimensions.width =
404
floor(properties->physicalResolution.width * MM_PER_PIXEL + 0.5);
405
properties->physicalDimensions.height =
406
floor(properties->physicalResolution.height * MM_PER_PIXEL + 0.5);
407
408
properties->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
409
properties->planeReorderPossible = VK_FALSE;
410
properties->persistentContent = VK_FALSE;
411
}
412
413
/*
414
* Implement vkGetPhysicalDeviceDisplayPropertiesKHR (VK_KHR_display)
415
*/
416
VkResult
417
wsi_display_get_physical_device_display_properties(
418
VkPhysicalDevice physical_device,
419
struct wsi_device *wsi_device,
420
uint32_t *property_count,
421
VkDisplayPropertiesKHR *properties)
422
{
423
struct wsi_display *wsi =
424
(struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
425
426
if (properties == NULL) {
427
return wsi_display_get_physical_device_display_properties2(
428
physical_device, wsi_device, property_count, NULL);
429
} else {
430
/* If we're actually returning properties, allocate a temporary array of
431
* VkDisplayProperties2KHR structs, call properties2 to fill them out,
432
* and then copy them to the client. This seems a bit expensive but
433
* wsi_display_get_physical_device_display_properties2() calls
434
* drmModeGetResources() which does an ioctl and then a bunch of
435
* allocations so this should get lost in the noise.
436
*/
437
VkDisplayProperties2KHR *props2 =
438
vk_zalloc(wsi->alloc, sizeof(*props2) * *property_count, 8,
439
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
440
if (props2 == NULL)
441
return VK_ERROR_OUT_OF_HOST_MEMORY;
442
443
for (uint32_t i = 0; i < *property_count; i++)
444
props2[i].sType = VK_STRUCTURE_TYPE_DISPLAY_PROPERTIES_2_KHR;
445
446
VkResult result = wsi_display_get_physical_device_display_properties2(
447
physical_device, wsi_device, property_count, props2);
448
449
if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
450
for (uint32_t i = 0; i < *property_count; i++)
451
properties[i] = props2[i].displayProperties;
452
}
453
454
vk_free(wsi->alloc, props2);
455
456
return result;
457
}
458
}
459
460
VkResult
461
wsi_display_get_physical_device_display_properties2(
462
VkPhysicalDevice physical_device,
463
struct wsi_device *wsi_device,
464
uint32_t *property_count,
465
VkDisplayProperties2KHR *properties)
466
{
467
struct wsi_display *wsi =
468
(struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
469
470
if (wsi->fd < 0)
471
goto bail;
472
473
drmModeResPtr mode_res = drmModeGetResources(wsi->fd);
474
475
if (!mode_res)
476
goto bail;
477
478
VK_OUTARRAY_MAKE(conn, properties, property_count);
479
480
/* Get current information */
481
482
for (int c = 0; c < mode_res->count_connectors; c++) {
483
struct wsi_display_connector *connector =
484
wsi_display_get_connector(wsi_device, wsi->fd,
485
mode_res->connectors[c]);
486
487
if (!connector) {
488
drmModeFreeResources(mode_res);
489
return VK_ERROR_OUT_OF_HOST_MEMORY;
490
}
491
492
if (connector->connected) {
493
vk_outarray_append(&conn, prop) {
494
wsi_display_fill_in_display_properties(wsi_device,
495
connector,
496
prop);
497
}
498
}
499
}
500
501
drmModeFreeResources(mode_res);
502
503
return vk_outarray_status(&conn);
504
505
bail:
506
*property_count = 0;
507
return VK_SUCCESS;
508
}
509
510
/*
511
* Implement vkGetPhysicalDeviceDisplayPlanePropertiesKHR (VK_KHR_display
512
*/
513
static void
514
wsi_display_fill_in_display_plane_properties(
515
struct wsi_device *wsi_device,
516
struct wsi_display_connector *connector,
517
VkDisplayPlaneProperties2KHR *properties)
518
{
519
assert(properties->sType == VK_STRUCTURE_TYPE_DISPLAY_PLANE_PROPERTIES_2_KHR);
520
VkDisplayPlanePropertiesKHR *prop = &properties->displayPlaneProperties;
521
522
if (connector && connector->active) {
523
prop->currentDisplay = wsi_display_connector_to_handle(connector);
524
prop->currentStackIndex = 0;
525
} else {
526
prop->currentDisplay = VK_NULL_HANDLE;
527
prop->currentStackIndex = 0;
528
}
529
}
530
531
VkResult
532
wsi_display_get_physical_device_display_plane_properties(
533
VkPhysicalDevice physical_device,
534
struct wsi_device *wsi_device,
535
uint32_t *property_count,
536
VkDisplayPlanePropertiesKHR *properties)
537
{
538
struct wsi_display *wsi =
539
(struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
540
541
VK_OUTARRAY_MAKE(conn, properties, property_count);
542
543
wsi_for_each_connector(connector, wsi) {
544
vk_outarray_append(&conn, prop) {
545
VkDisplayPlaneProperties2KHR prop2 = {
546
.sType = VK_STRUCTURE_TYPE_DISPLAY_PLANE_PROPERTIES_2_KHR,
547
};
548
wsi_display_fill_in_display_plane_properties(wsi_device, connector,
549
&prop2);
550
*prop = prop2.displayPlaneProperties;
551
}
552
}
553
return vk_outarray_status(&conn);
554
}
555
556
VkResult
557
wsi_display_get_physical_device_display_plane_properties2(
558
VkPhysicalDevice physical_device,
559
struct wsi_device *wsi_device,
560
uint32_t *property_count,
561
VkDisplayPlaneProperties2KHR *properties)
562
{
563
struct wsi_display *wsi =
564
(struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
565
566
VK_OUTARRAY_MAKE(conn, properties, property_count);
567
568
wsi_for_each_connector(connector, wsi) {
569
vk_outarray_append(&conn, prop) {
570
wsi_display_fill_in_display_plane_properties(wsi_device, connector,
571
prop);
572
}
573
}
574
return vk_outarray_status(&conn);
575
}
576
577
/*
578
* Implement vkGetDisplayPlaneSupportedDisplaysKHR (VK_KHR_display)
579
*/
580
581
VkResult
582
wsi_display_get_display_plane_supported_displays(
583
VkPhysicalDevice physical_device,
584
struct wsi_device *wsi_device,
585
uint32_t plane_index,
586
uint32_t *display_count,
587
VkDisplayKHR *displays)
588
{
589
struct wsi_display *wsi =
590
(struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
591
592
VK_OUTARRAY_MAKE(conn, displays, display_count);
593
594
int c = 0;
595
596
wsi_for_each_connector(connector, wsi) {
597
if (c == plane_index && connector->connected) {
598
vk_outarray_append(&conn, display) {
599
*display = wsi_display_connector_to_handle(connector);
600
}
601
}
602
c++;
603
}
604
return vk_outarray_status(&conn);
605
}
606
607
/*
608
* Implement vkGetDisplayModePropertiesKHR (VK_KHR_display)
609
*/
610
611
static void
612
wsi_display_fill_in_display_mode_properties(
613
struct wsi_device *wsi_device,
614
struct wsi_display_mode *display_mode,
615
VkDisplayModeProperties2KHR *properties)
616
{
617
assert(properties->sType == VK_STRUCTURE_TYPE_DISPLAY_MODE_PROPERTIES_2_KHR);
618
VkDisplayModePropertiesKHR *prop = &properties->displayModeProperties;
619
620
prop->displayMode = wsi_display_mode_to_handle(display_mode);
621
prop->parameters.visibleRegion.width = display_mode->hdisplay;
622
prop->parameters.visibleRegion.height = display_mode->vdisplay;
623
prop->parameters.refreshRate =
624
(uint32_t) (wsi_display_mode_refresh(display_mode) * 1000 + 0.5);
625
}
626
627
VkResult
628
wsi_display_get_display_mode_properties(VkPhysicalDevice physical_device,
629
struct wsi_device *wsi_device,
630
VkDisplayKHR display,
631
uint32_t *property_count,
632
VkDisplayModePropertiesKHR *properties)
633
{
634
struct wsi_display_connector *connector =
635
wsi_display_connector_from_handle(display);
636
637
VK_OUTARRAY_MAKE(conn, properties, property_count);
638
639
wsi_for_each_display_mode(display_mode, connector) {
640
if (!display_mode->valid)
641
continue;
642
643
vk_outarray_append(&conn, prop) {
644
VkDisplayModeProperties2KHR prop2 = {
645
.sType = VK_STRUCTURE_TYPE_DISPLAY_MODE_PROPERTIES_2_KHR,
646
};
647
wsi_display_fill_in_display_mode_properties(wsi_device,
648
display_mode, &prop2);
649
*prop = prop2.displayModeProperties;
650
}
651
}
652
return vk_outarray_status(&conn);
653
}
654
655
VkResult
656
wsi_display_get_display_mode_properties2(VkPhysicalDevice physical_device,
657
struct wsi_device *wsi_device,
658
VkDisplayKHR display,
659
uint32_t *property_count,
660
VkDisplayModeProperties2KHR *properties)
661
{
662
struct wsi_display_connector *connector =
663
wsi_display_connector_from_handle(display);
664
665
VK_OUTARRAY_MAKE(conn, properties, property_count);
666
667
wsi_for_each_display_mode(display_mode, connector) {
668
if (!display_mode->valid)
669
continue;
670
671
vk_outarray_append(&conn, prop) {
672
wsi_display_fill_in_display_mode_properties(wsi_device,
673
display_mode, prop);
674
}
675
}
676
return vk_outarray_status(&conn);
677
}
678
679
static bool
680
wsi_display_mode_matches_vk(wsi_display_mode *wsi,
681
const VkDisplayModeParametersKHR *vk)
682
{
683
return (vk->visibleRegion.width == wsi->hdisplay &&
684
vk->visibleRegion.height == wsi->vdisplay &&
685
fabs(wsi_display_mode_refresh(wsi) * 1000.0 - vk->refreshRate) < 10);
686
}
687
688
/*
689
* Implement vkCreateDisplayModeKHR (VK_KHR_display)
690
*/
691
VkResult
692
wsi_display_create_display_mode(VkPhysicalDevice physical_device,
693
struct wsi_device *wsi_device,
694
VkDisplayKHR display,
695
const VkDisplayModeCreateInfoKHR *create_info,
696
const VkAllocationCallbacks *allocator,
697
VkDisplayModeKHR *mode)
698
{
699
struct wsi_display_connector *connector =
700
wsi_display_connector_from_handle(display);
701
702
if (create_info->flags != 0)
703
return VK_ERROR_INITIALIZATION_FAILED;
704
705
/* Check and see if the requested mode happens to match an existing one and
706
* return that. This makes the conformance suite happy. Doing more than
707
* this would involve embedding the CVT function into the driver, which seems
708
* excessive.
709
*/
710
wsi_for_each_display_mode(display_mode, connector) {
711
if (display_mode->valid) {
712
if (wsi_display_mode_matches_vk(display_mode, &create_info->parameters)) {
713
*mode = wsi_display_mode_to_handle(display_mode);
714
return VK_SUCCESS;
715
}
716
}
717
}
718
return VK_ERROR_INITIALIZATION_FAILED;
719
}
720
721
/*
722
* Implement vkGetDisplayPlaneCapabilities
723
*/
724
VkResult
725
wsi_get_display_plane_capabilities(VkPhysicalDevice physical_device,
726
struct wsi_device *wsi_device,
727
VkDisplayModeKHR mode_khr,
728
uint32_t plane_index,
729
VkDisplayPlaneCapabilitiesKHR *capabilities)
730
{
731
struct wsi_display_mode *mode = wsi_display_mode_from_handle(mode_khr);
732
733
/* XXX use actual values */
734
capabilities->supportedAlpha = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR;
735
capabilities->minSrcPosition.x = 0;
736
capabilities->minSrcPosition.y = 0;
737
capabilities->maxSrcPosition.x = 0;
738
capabilities->maxSrcPosition.y = 0;
739
capabilities->minSrcExtent.width = mode->hdisplay;
740
capabilities->minSrcExtent.height = mode->vdisplay;
741
capabilities->maxSrcExtent.width = mode->hdisplay;
742
capabilities->maxSrcExtent.height = mode->vdisplay;
743
capabilities->minDstPosition.x = 0;
744
capabilities->minDstPosition.y = 0;
745
capabilities->maxDstPosition.x = 0;
746
capabilities->maxDstPosition.y = 0;
747
capabilities->minDstExtent.width = mode->hdisplay;
748
capabilities->minDstExtent.height = mode->vdisplay;
749
capabilities->maxDstExtent.width = mode->hdisplay;
750
capabilities->maxDstExtent.height = mode->vdisplay;
751
return VK_SUCCESS;
752
}
753
754
VkResult
755
wsi_get_display_plane_capabilities2(
756
VkPhysicalDevice physical_device,
757
struct wsi_device *wsi_device,
758
const VkDisplayPlaneInfo2KHR *pDisplayPlaneInfo,
759
VkDisplayPlaneCapabilities2KHR *capabilities)
760
{
761
assert(capabilities->sType ==
762
VK_STRUCTURE_TYPE_DISPLAY_PLANE_CAPABILITIES_2_KHR);
763
764
VkResult result =
765
wsi_get_display_plane_capabilities(physical_device, wsi_device,
766
pDisplayPlaneInfo->mode,
767
pDisplayPlaneInfo->planeIndex,
768
&capabilities->capabilities);
769
770
vk_foreach_struct(ext, capabilities->pNext) {
771
switch (ext->sType) {
772
case VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR: {
773
VkSurfaceProtectedCapabilitiesKHR *protected = (void *)ext;
774
protected->supportsProtected = VK_FALSE;
775
break;
776
}
777
778
default:
779
/* Ignored */
780
break;
781
}
782
}
783
784
return result;
785
}
786
787
VkResult
788
wsi_create_display_surface(VkInstance instance,
789
const VkAllocationCallbacks *allocator,
790
const VkDisplaySurfaceCreateInfoKHR *create_info,
791
VkSurfaceKHR *surface_khr)
792
{
793
VkIcdSurfaceDisplay *surface = vk_zalloc(allocator, sizeof *surface, 8,
794
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
795
796
if (surface == NULL)
797
return VK_ERROR_OUT_OF_HOST_MEMORY;
798
799
surface->base.platform = VK_ICD_WSI_PLATFORM_DISPLAY;
800
801
surface->displayMode = create_info->displayMode;
802
surface->planeIndex = create_info->planeIndex;
803
surface->planeStackIndex = create_info->planeStackIndex;
804
surface->transform = create_info->transform;
805
surface->globalAlpha = create_info->globalAlpha;
806
surface->alphaMode = create_info->alphaMode;
807
surface->imageExtent = create_info->imageExtent;
808
809
*surface_khr = VkIcdSurfaceBase_to_handle(&surface->base);
810
return VK_SUCCESS;
811
}
812
813
814
static VkResult
815
wsi_display_surface_get_support(VkIcdSurfaceBase *surface,
816
struct wsi_device *wsi_device,
817
uint32_t queueFamilyIndex,
818
VkBool32* pSupported)
819
{
820
struct wsi_display *wsi =
821
(struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
822
823
*pSupported = wsi->fd != -1;
824
return VK_SUCCESS;
825
}
826
827
static VkResult
828
wsi_display_surface_get_capabilities(VkIcdSurfaceBase *surface_base,
829
struct wsi_device *wsi_device,
830
VkSurfaceCapabilitiesKHR* caps)
831
{
832
VkIcdSurfaceDisplay *surface = (VkIcdSurfaceDisplay *) surface_base;
833
wsi_display_mode *mode = wsi_display_mode_from_handle(surface->displayMode);
834
835
caps->currentExtent.width = mode->hdisplay;
836
caps->currentExtent.height = mode->vdisplay;
837
838
caps->minImageExtent = (VkExtent2D) { 1, 1 };
839
caps->maxImageExtent = (VkExtent2D) {
840
wsi_device->maxImageDimension2D,
841
wsi_device->maxImageDimension2D,
842
};
843
844
caps->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
845
846
caps->minImageCount = 2;
847
caps->maxImageCount = 0;
848
849
caps->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
850
caps->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
851
caps->maxImageArrayLayers = 1;
852
caps->supportedUsageFlags =
853
VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
854
VK_IMAGE_USAGE_SAMPLED_BIT |
855
VK_IMAGE_USAGE_TRANSFER_DST_BIT |
856
VK_IMAGE_USAGE_STORAGE_BIT |
857
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
858
859
return VK_SUCCESS;
860
}
861
862
static VkResult
863
wsi_display_surface_get_surface_counters(
864
VkIcdSurfaceBase *surface_base,
865
VkSurfaceCounterFlagsEXT *counters)
866
{
867
*counters = VK_SURFACE_COUNTER_VBLANK_EXT;
868
return VK_SUCCESS;
869
}
870
871
static VkResult
872
wsi_display_surface_get_capabilities2(VkIcdSurfaceBase *icd_surface,
873
struct wsi_device *wsi_device,
874
const void *info_next,
875
VkSurfaceCapabilities2KHR *caps)
876
{
877
assert(caps->sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR);
878
VkResult result;
879
880
result = wsi_display_surface_get_capabilities(icd_surface, wsi_device,
881
&caps->surfaceCapabilities);
882
if (result != VK_SUCCESS)
883
return result;
884
885
struct wsi_surface_supported_counters *counters =
886
vk_find_struct( caps->pNext, WSI_SURFACE_SUPPORTED_COUNTERS_MESA);
887
888
if (counters) {
889
result = wsi_display_surface_get_surface_counters(
890
icd_surface,
891
&counters->supported_surface_counters);
892
}
893
894
return result;
895
}
896
897
static const struct {
898
VkFormat format;
899
uint32_t drm_format;
900
} available_surface_formats[] = {
901
{ .format = VK_FORMAT_B8G8R8A8_SRGB, .drm_format = DRM_FORMAT_XRGB8888 },
902
{ .format = VK_FORMAT_B8G8R8A8_UNORM, .drm_format = DRM_FORMAT_XRGB8888 },
903
};
904
905
static void
906
get_sorted_vk_formats(struct wsi_device *wsi_device, VkFormat *sorted_formats)
907
{
908
for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++)
909
sorted_formats[i] = available_surface_formats[i].format;
910
911
if (wsi_device->force_bgra8_unorm_first) {
912
for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) {
913
if (sorted_formats[i] == VK_FORMAT_B8G8R8A8_UNORM) {
914
sorted_formats[i] = sorted_formats[0];
915
sorted_formats[0] = VK_FORMAT_B8G8R8A8_UNORM;
916
break;
917
}
918
}
919
}
920
}
921
922
static VkResult
923
wsi_display_surface_get_formats(VkIcdSurfaceBase *icd_surface,
924
struct wsi_device *wsi_device,
925
uint32_t *surface_format_count,
926
VkSurfaceFormatKHR *surface_formats)
927
{
928
VK_OUTARRAY_MAKE(out, surface_formats, surface_format_count);
929
930
VkFormat sorted_formats[ARRAY_SIZE(available_surface_formats)];
931
get_sorted_vk_formats(wsi_device, sorted_formats);
932
933
for (unsigned i = 0; i < ARRAY_SIZE(sorted_formats); i++) {
934
vk_outarray_append(&out, f) {
935
f->format = sorted_formats[i];
936
f->colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
937
}
938
}
939
940
return vk_outarray_status(&out);
941
}
942
943
static VkResult
944
wsi_display_surface_get_formats2(VkIcdSurfaceBase *surface,
945
struct wsi_device *wsi_device,
946
const void *info_next,
947
uint32_t *surface_format_count,
948
VkSurfaceFormat2KHR *surface_formats)
949
{
950
VK_OUTARRAY_MAKE(out, surface_formats, surface_format_count);
951
952
VkFormat sorted_formats[ARRAY_SIZE(available_surface_formats)];
953
get_sorted_vk_formats(wsi_device, sorted_formats);
954
955
for (unsigned i = 0; i < ARRAY_SIZE(sorted_formats); i++) {
956
vk_outarray_append(&out, f) {
957
assert(f->sType == VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR);
958
f->surfaceFormat.format = sorted_formats[i];
959
f->surfaceFormat.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
960
}
961
}
962
963
return vk_outarray_status(&out);
964
}
965
966
static VkResult
967
wsi_display_surface_get_present_modes(VkIcdSurfaceBase *surface,
968
uint32_t *present_mode_count,
969
VkPresentModeKHR *present_modes)
970
{
971
VK_OUTARRAY_MAKE(conn, present_modes, present_mode_count);
972
973
vk_outarray_append(&conn, present) {
974
*present = VK_PRESENT_MODE_FIFO_KHR;
975
}
976
977
return vk_outarray_status(&conn);
978
}
979
980
static VkResult
981
wsi_display_surface_get_present_rectangles(VkIcdSurfaceBase *surface_base,
982
struct wsi_device *wsi_device,
983
uint32_t* pRectCount,
984
VkRect2D* pRects)
985
{
986
VkIcdSurfaceDisplay *surface = (VkIcdSurfaceDisplay *) surface_base;
987
wsi_display_mode *mode = wsi_display_mode_from_handle(surface->displayMode);
988
VK_OUTARRAY_MAKE(out, pRects, pRectCount);
989
990
if (wsi_device_matches_drm_fd(wsi_device, mode->connector->wsi->fd)) {
991
vk_outarray_append(&out, rect) {
992
*rect = (VkRect2D) {
993
.offset = { 0, 0 },
994
.extent = { mode->hdisplay, mode->vdisplay },
995
};
996
}
997
}
998
999
return vk_outarray_status(&out);
1000
}
1001
1002
static void
1003
wsi_display_destroy_buffer(struct wsi_display *wsi,
1004
uint32_t buffer)
1005
{
1006
(void) drmIoctl(wsi->fd, DRM_IOCTL_GEM_CLOSE,
1007
&((struct drm_gem_close) { .handle = buffer }));
1008
}
1009
1010
static VkResult
1011
wsi_display_image_init(VkDevice device_h,
1012
struct wsi_swapchain *drv_chain,
1013
const VkSwapchainCreateInfoKHR *create_info,
1014
const VkAllocationCallbacks *allocator,
1015
struct wsi_display_image *image)
1016
{
1017
struct wsi_display_swapchain *chain =
1018
(struct wsi_display_swapchain *) drv_chain;
1019
struct wsi_display *wsi = chain->wsi;
1020
uint32_t drm_format = 0;
1021
1022
for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) {
1023
if (create_info->imageFormat == available_surface_formats[i].format) {
1024
drm_format = available_surface_formats[i].drm_format;
1025
break;
1026
}
1027
}
1028
1029
/* the application provided an invalid format, bail */
1030
if (drm_format == 0)
1031
return VK_ERROR_DEVICE_LOST;
1032
1033
VkResult result = wsi_create_native_image(&chain->base, create_info,
1034
0, NULL, NULL,
1035
&image->base);
1036
if (result != VK_SUCCESS)
1037
return result;
1038
1039
memset(image->buffer, 0, sizeof (image->buffer));
1040
1041
for (unsigned int i = 0; i < image->base.num_planes; i++) {
1042
int ret = drmPrimeFDToHandle(wsi->fd, image->base.fds[i],
1043
&image->buffer[i]);
1044
1045
close(image->base.fds[i]);
1046
image->base.fds[i] = -1;
1047
if (ret < 0)
1048
goto fail_handle;
1049
}
1050
1051
image->chain = chain;
1052
image->state = WSI_IMAGE_IDLE;
1053
image->fb_id = 0;
1054
1055
int ret = drmModeAddFB2(wsi->fd,
1056
create_info->imageExtent.width,
1057
create_info->imageExtent.height,
1058
drm_format,
1059
image->buffer,
1060
image->base.row_pitches,
1061
image->base.offsets,
1062
&image->fb_id, 0);
1063
1064
if (ret)
1065
goto fail_fb;
1066
1067
return VK_SUCCESS;
1068
1069
fail_fb:
1070
fail_handle:
1071
for (unsigned int i = 0; i < image->base.num_planes; i++) {
1072
if (image->buffer[i])
1073
wsi_display_destroy_buffer(wsi, image->buffer[i]);
1074
if (image->base.fds[i] != -1) {
1075
close(image->base.fds[i]);
1076
image->base.fds[i] = -1;
1077
}
1078
}
1079
1080
wsi_destroy_image(&chain->base, &image->base);
1081
1082
return VK_ERROR_OUT_OF_HOST_MEMORY;
1083
}
1084
1085
static void
1086
wsi_display_image_finish(struct wsi_swapchain *drv_chain,
1087
const VkAllocationCallbacks *allocator,
1088
struct wsi_display_image *image)
1089
{
1090
struct wsi_display_swapchain *chain =
1091
(struct wsi_display_swapchain *) drv_chain;
1092
struct wsi_display *wsi = chain->wsi;
1093
1094
drmModeRmFB(wsi->fd, image->fb_id);
1095
for (unsigned int i = 0; i < image->base.num_planes; i++)
1096
wsi_display_destroy_buffer(wsi, image->buffer[i]);
1097
wsi_destroy_image(&chain->base, &image->base);
1098
}
1099
1100
static VkResult
1101
wsi_display_swapchain_destroy(struct wsi_swapchain *drv_chain,
1102
const VkAllocationCallbacks *allocator)
1103
{
1104
struct wsi_display_swapchain *chain =
1105
(struct wsi_display_swapchain *) drv_chain;
1106
1107
for (uint32_t i = 0; i < chain->base.image_count; i++)
1108
wsi_display_image_finish(drv_chain, allocator, &chain->images[i]);
1109
1110
wsi_swapchain_finish(&chain->base);
1111
vk_free(allocator, chain);
1112
return VK_SUCCESS;
1113
}
1114
1115
static struct wsi_image *
1116
wsi_display_get_wsi_image(struct wsi_swapchain *drv_chain,
1117
uint32_t image_index)
1118
{
1119
struct wsi_display_swapchain *chain =
1120
(struct wsi_display_swapchain *) drv_chain;
1121
1122
return &chain->images[image_index].base;
1123
}
1124
1125
static void
1126
wsi_display_idle_old_displaying(struct wsi_display_image *active_image)
1127
{
1128
struct wsi_display_swapchain *chain = active_image->chain;
1129
1130
wsi_display_debug("idle everyone but %ld\n",
1131
active_image - &(chain->images[0]));
1132
for (uint32_t i = 0; i < chain->base.image_count; i++)
1133
if (chain->images[i].state == WSI_IMAGE_DISPLAYING &&
1134
&chain->images[i] != active_image)
1135
{
1136
wsi_display_debug("idle %d\n", i);
1137
chain->images[i].state = WSI_IMAGE_IDLE;
1138
}
1139
}
1140
1141
static VkResult
1142
_wsi_display_queue_next(struct wsi_swapchain *drv_chain);
1143
1144
static void
1145
wsi_display_page_flip_handler2(int fd,
1146
unsigned int frame,
1147
unsigned int sec,
1148
unsigned int usec,
1149
uint32_t crtc_id,
1150
void *data)
1151
{
1152
struct wsi_display_image *image = data;
1153
struct wsi_display_swapchain *chain = image->chain;
1154
1155
wsi_display_debug("image %ld displayed at %d\n",
1156
image - &(image->chain->images[0]), frame);
1157
image->state = WSI_IMAGE_DISPLAYING;
1158
wsi_display_idle_old_displaying(image);
1159
VkResult result = _wsi_display_queue_next(&(chain->base));
1160
if (result != VK_SUCCESS)
1161
chain->status = result;
1162
}
1163
1164
static void wsi_display_fence_event_handler(struct wsi_display_fence *fence);
1165
1166
static void wsi_display_page_flip_handler(int fd,
1167
unsigned int frame,
1168
unsigned int sec,
1169
unsigned int usec,
1170
void *data)
1171
{
1172
wsi_display_page_flip_handler2(fd, frame, sec, usec, 0, data);
1173
}
1174
1175
static void wsi_display_vblank_handler(int fd, unsigned int frame,
1176
unsigned int sec, unsigned int usec,
1177
void *data)
1178
{
1179
struct wsi_display_fence *fence = data;
1180
1181
wsi_display_fence_event_handler(fence);
1182
}
1183
1184
static void wsi_display_sequence_handler(int fd, uint64_t frame,
1185
uint64_t nsec, uint64_t user_data)
1186
{
1187
struct wsi_display_fence *fence =
1188
(struct wsi_display_fence *) (uintptr_t) user_data;
1189
1190
wsi_display_fence_event_handler(fence);
1191
}
1192
1193
static drmEventContext event_context = {
1194
.version = DRM_EVENT_CONTEXT_VERSION,
1195
.page_flip_handler = wsi_display_page_flip_handler,
1196
#if DRM_EVENT_CONTEXT_VERSION >= 3
1197
.page_flip_handler2 = wsi_display_page_flip_handler2,
1198
#endif
1199
.vblank_handler = wsi_display_vblank_handler,
1200
.sequence_handler = wsi_display_sequence_handler,
1201
};
1202
1203
static void *
1204
wsi_display_wait_thread(void *data)
1205
{
1206
struct wsi_display *wsi = data;
1207
struct pollfd pollfd = {
1208
.fd = wsi->fd,
1209
.events = POLLIN
1210
};
1211
1212
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
1213
for (;;) {
1214
int ret = poll(&pollfd, 1, -1);
1215
if (ret > 0) {
1216
pthread_mutex_lock(&wsi->wait_mutex);
1217
(void) drmHandleEvent(wsi->fd, &event_context);
1218
pthread_cond_broadcast(&wsi->wait_cond);
1219
pthread_mutex_unlock(&wsi->wait_mutex);
1220
}
1221
}
1222
return NULL;
1223
}
1224
1225
static int
1226
wsi_display_start_wait_thread(struct wsi_display *wsi)
1227
{
1228
if (!wsi->wait_thread) {
1229
int ret = pthread_create(&wsi->wait_thread, NULL,
1230
wsi_display_wait_thread, wsi);
1231
if (ret)
1232
return ret;
1233
}
1234
return 0;
1235
}
1236
1237
static void
1238
wsi_display_stop_wait_thread(struct wsi_display *wsi)
1239
{
1240
pthread_mutex_lock(&wsi->wait_mutex);
1241
if (wsi->wait_thread) {
1242
pthread_cancel(wsi->wait_thread);
1243
pthread_join(wsi->wait_thread, NULL);
1244
wsi->wait_thread = 0;
1245
}
1246
pthread_mutex_unlock(&wsi->wait_mutex);
1247
}
1248
1249
/*
1250
* Wait for at least one event from the kernel to be processed.
1251
* Call with wait_mutex held
1252
*/
1253
static int
1254
wsi_display_wait_for_event(struct wsi_display *wsi,
1255
uint64_t timeout_ns)
1256
{
1257
int ret;
1258
1259
ret = wsi_display_start_wait_thread(wsi);
1260
1261
if (ret)
1262
return ret;
1263
1264
struct timespec abs_timeout = {
1265
.tv_sec = timeout_ns / 1000000000ULL,
1266
.tv_nsec = timeout_ns % 1000000000ULL,
1267
};
1268
1269
ret = pthread_cond_timedwait(&wsi->wait_cond, &wsi->wait_mutex,
1270
&abs_timeout);
1271
1272
wsi_display_debug("%9ld done waiting for event %d\n", pthread_self(), ret);
1273
return ret;
1274
}
1275
1276
static VkResult
1277
wsi_display_acquire_next_image(struct wsi_swapchain *drv_chain,
1278
const VkAcquireNextImageInfoKHR *info,
1279
uint32_t *image_index)
1280
{
1281
struct wsi_display_swapchain *chain =
1282
(struct wsi_display_swapchain *)drv_chain;
1283
struct wsi_display *wsi = chain->wsi;
1284
int ret = 0;
1285
VkResult result = VK_SUCCESS;
1286
1287
/* Bail early if the swapchain is broken */
1288
if (chain->status != VK_SUCCESS)
1289
return chain->status;
1290
1291
uint64_t timeout = info->timeout;
1292
if (timeout != 0 && timeout != UINT64_MAX)
1293
timeout = wsi_rel_to_abs_time(timeout);
1294
1295
pthread_mutex_lock(&wsi->wait_mutex);
1296
for (;;) {
1297
for (uint32_t i = 0; i < chain->base.image_count; i++) {
1298
if (chain->images[i].state == WSI_IMAGE_IDLE) {
1299
*image_index = i;
1300
wsi_display_debug("image %d available\n", i);
1301
chain->images[i].state = WSI_IMAGE_DRAWING;
1302
result = VK_SUCCESS;
1303
goto done;
1304
}
1305
wsi_display_debug("image %d state %d\n", i, chain->images[i].state);
1306
}
1307
1308
if (ret == ETIMEDOUT) {
1309
result = VK_TIMEOUT;
1310
goto done;
1311
}
1312
1313
ret = wsi_display_wait_for_event(wsi, timeout);
1314
1315
if (ret && ret != ETIMEDOUT) {
1316
result = VK_ERROR_SURFACE_LOST_KHR;
1317
goto done;
1318
}
1319
}
1320
done:
1321
pthread_mutex_unlock(&wsi->wait_mutex);
1322
1323
if (result != VK_SUCCESS)
1324
return result;
1325
1326
return chain->status;
1327
}
1328
1329
/*
1330
* Check whether there are any other connectors driven by this crtc
1331
*/
1332
static bool
1333
wsi_display_crtc_solo(struct wsi_display *wsi,
1334
drmModeResPtr mode_res,
1335
drmModeConnectorPtr connector,
1336
uint32_t crtc_id)
1337
{
1338
/* See if any other connectors share the same encoder */
1339
for (int c = 0; c < mode_res->count_connectors; c++) {
1340
if (mode_res->connectors[c] == connector->connector_id)
1341
continue;
1342
1343
drmModeConnectorPtr other_connector =
1344
drmModeGetConnector(wsi->fd, mode_res->connectors[c]);
1345
1346
if (other_connector) {
1347
bool match = (other_connector->encoder_id == connector->encoder_id);
1348
drmModeFreeConnector(other_connector);
1349
if (match)
1350
return false;
1351
}
1352
}
1353
1354
/* See if any other encoders share the same crtc */
1355
for (int e = 0; e < mode_res->count_encoders; e++) {
1356
if (mode_res->encoders[e] == connector->encoder_id)
1357
continue;
1358
1359
drmModeEncoderPtr other_encoder =
1360
drmModeGetEncoder(wsi->fd, mode_res->encoders[e]);
1361
1362
if (other_encoder) {
1363
bool match = (other_encoder->crtc_id == crtc_id);
1364
drmModeFreeEncoder(other_encoder);
1365
if (match)
1366
return false;
1367
}
1368
}
1369
return true;
1370
}
1371
1372
/*
1373
* Pick a suitable CRTC to drive this connector. Prefer a CRTC which is
1374
* currently driving this connector and not any others. Settle for a CRTC
1375
* which is currently idle.
1376
*/
1377
static uint32_t
1378
wsi_display_select_crtc(const struct wsi_display_connector *connector,
1379
drmModeResPtr mode_res,
1380
drmModeConnectorPtr drm_connector)
1381
{
1382
struct wsi_display *wsi = connector->wsi;
1383
1384
/* See what CRTC is currently driving this connector */
1385
if (drm_connector->encoder_id) {
1386
drmModeEncoderPtr encoder =
1387
drmModeGetEncoder(wsi->fd, drm_connector->encoder_id);
1388
1389
if (encoder) {
1390
uint32_t crtc_id = encoder->crtc_id;
1391
drmModeFreeEncoder(encoder);
1392
if (crtc_id) {
1393
if (wsi_display_crtc_solo(wsi, mode_res, drm_connector, crtc_id))
1394
return crtc_id;
1395
}
1396
}
1397
}
1398
uint32_t crtc_id = 0;
1399
for (int c = 0; crtc_id == 0 && c < mode_res->count_crtcs; c++) {
1400
drmModeCrtcPtr crtc = drmModeGetCrtc(wsi->fd, mode_res->crtcs[c]);
1401
if (crtc && crtc->buffer_id == 0)
1402
crtc_id = crtc->crtc_id;
1403
drmModeFreeCrtc(crtc);
1404
}
1405
return crtc_id;
1406
}
1407
1408
static VkResult
1409
wsi_display_setup_connector(wsi_display_connector *connector,
1410
wsi_display_mode *display_mode)
1411
{
1412
struct wsi_display *wsi = connector->wsi;
1413
1414
if (connector->current_mode == display_mode && connector->crtc_id)
1415
return VK_SUCCESS;
1416
1417
VkResult result = VK_SUCCESS;
1418
1419
drmModeResPtr mode_res = drmModeGetResources(wsi->fd);
1420
if (!mode_res) {
1421
if (errno == ENOMEM)
1422
result = VK_ERROR_OUT_OF_HOST_MEMORY;
1423
else
1424
result = VK_ERROR_SURFACE_LOST_KHR;
1425
goto bail;
1426
}
1427
1428
drmModeConnectorPtr drm_connector =
1429
drmModeGetConnectorCurrent(wsi->fd, connector->id);
1430
1431
if (!drm_connector) {
1432
if (errno == ENOMEM)
1433
result = VK_ERROR_OUT_OF_HOST_MEMORY;
1434
else
1435
result = VK_ERROR_SURFACE_LOST_KHR;
1436
goto bail_mode_res;
1437
}
1438
1439
/* Pick a CRTC if we don't have one */
1440
if (!connector->crtc_id) {
1441
connector->crtc_id = wsi_display_select_crtc(connector,
1442
mode_res, drm_connector);
1443
if (!connector->crtc_id) {
1444
result = VK_ERROR_SURFACE_LOST_KHR;
1445
goto bail_connector;
1446
}
1447
}
1448
1449
if (connector->current_mode != display_mode) {
1450
1451
/* Find the drm mode corresponding to the requested VkDisplayMode */
1452
drmModeModeInfoPtr drm_mode = NULL;
1453
1454
for (int m = 0; m < drm_connector->count_modes; m++) {
1455
drm_mode = &drm_connector->modes[m];
1456
if (wsi_display_mode_matches_drm(display_mode, drm_mode))
1457
break;
1458
drm_mode = NULL;
1459
}
1460
1461
if (!drm_mode) {
1462
result = VK_ERROR_SURFACE_LOST_KHR;
1463
goto bail_connector;
1464
}
1465
1466
connector->current_mode = display_mode;
1467
connector->current_drm_mode = *drm_mode;
1468
}
1469
1470
bail_connector:
1471
drmModeFreeConnector(drm_connector);
1472
bail_mode_res:
1473
drmModeFreeResources(mode_res);
1474
bail:
1475
return result;
1476
1477
}
1478
1479
static VkResult
1480
wsi_display_fence_wait(struct wsi_fence *fence_wsi, uint64_t timeout)
1481
{
1482
const struct wsi_device *wsi_device = fence_wsi->wsi_device;
1483
struct wsi_display *wsi =
1484
(struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1485
struct wsi_display_fence *fence = (struct wsi_display_fence *) fence_wsi;
1486
1487
wsi_display_debug("%9lu wait fence %lu %ld\n",
1488
pthread_self(), fence->sequence,
1489
(int64_t) (timeout - wsi_common_get_current_time()));
1490
wsi_display_debug_code(uint64_t start_ns = wsi_common_get_current_time());
1491
pthread_mutex_lock(&wsi->wait_mutex);
1492
1493
VkResult result;
1494
int ret = 0;
1495
for (;;) {
1496
if (fence->event_received) {
1497
wsi_display_debug("%9lu fence %lu passed\n",
1498
pthread_self(), fence->sequence);
1499
result = VK_SUCCESS;
1500
break;
1501
}
1502
1503
if (ret == ETIMEDOUT) {
1504
wsi_display_debug("%9lu fence %lu timeout\n",
1505
pthread_self(), fence->sequence);
1506
result = VK_TIMEOUT;
1507
break;
1508
}
1509
1510
ret = wsi_display_wait_for_event(wsi, timeout);
1511
1512
if (ret && ret != ETIMEDOUT) {
1513
wsi_display_debug("%9lu fence %lu error\n",
1514
pthread_self(), fence->sequence);
1515
result = VK_ERROR_DEVICE_LOST;
1516
break;
1517
}
1518
}
1519
pthread_mutex_unlock(&wsi->wait_mutex);
1520
wsi_display_debug("%9lu fence wait %f ms\n",
1521
pthread_self(),
1522
((int64_t) (wsi_common_get_current_time() - start_ns)) /
1523
1.0e6);
1524
return result;
1525
}
1526
1527
static void
1528
wsi_display_fence_check_free(struct wsi_display_fence *fence)
1529
{
1530
if (fence->event_received && fence->destroyed)
1531
vk_free(fence->base.alloc, fence);
1532
}
1533
1534
static void wsi_display_fence_event_handler(struct wsi_display_fence *fence)
1535
{
1536
struct wsi_display *wsi =
1537
(struct wsi_display *) fence->base.wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1538
1539
if (fence->syncobj) {
1540
(void) drmSyncobjSignal(wsi->fd, &fence->syncobj, 1);
1541
(void) drmSyncobjDestroy(wsi->fd, fence->syncobj);
1542
}
1543
1544
fence->event_received = true;
1545
wsi_display_fence_check_free(fence);
1546
}
1547
1548
static void
1549
wsi_display_fence_destroy(struct wsi_fence *fence_wsi)
1550
{
1551
struct wsi_display_fence *fence = (struct wsi_display_fence *) fence_wsi;
1552
1553
assert(!fence->destroyed);
1554
fence->destroyed = true;
1555
wsi_display_fence_check_free(fence);
1556
}
1557
1558
static struct wsi_display_fence *
1559
wsi_display_fence_alloc(VkDevice device,
1560
const struct wsi_device *wsi_device,
1561
VkDisplayKHR display,
1562
const VkAllocationCallbacks *allocator,
1563
int sync_fd)
1564
{
1565
struct wsi_display *wsi =
1566
(struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1567
struct wsi_display_fence *fence =
1568
vk_zalloc2(wsi->alloc, allocator, sizeof (*fence),
1569
8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1570
1571
if (!fence)
1572
return NULL;
1573
1574
if (sync_fd >= 0) {
1575
int ret = drmSyncobjFDToHandle(wsi->fd, sync_fd, &fence->syncobj);
1576
if (ret) {
1577
vk_free2(wsi->alloc, allocator, fence);
1578
return NULL;
1579
}
1580
}
1581
1582
fence->base.device = device;
1583
fence->base.display = display;
1584
fence->base.wsi_device = wsi_device;
1585
fence->base.alloc = allocator ? allocator : wsi->alloc;
1586
fence->base.wait = wsi_display_fence_wait;
1587
fence->base.destroy = wsi_display_fence_destroy;
1588
fence->event_received = false;
1589
fence->destroyed = false;
1590
fence->sequence = ++fence_sequence;
1591
return fence;
1592
}
1593
1594
static VkResult
1595
wsi_register_vblank_event(struct wsi_display_fence *fence,
1596
const struct wsi_device *wsi_device,
1597
VkDisplayKHR display,
1598
uint32_t flags,
1599
uint64_t frame_requested,
1600
uint64_t *frame_queued)
1601
{
1602
struct wsi_display *wsi =
1603
(struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1604
struct wsi_display_connector *connector =
1605
wsi_display_connector_from_handle(display);
1606
1607
if (wsi->fd < 0)
1608
return VK_ERROR_INITIALIZATION_FAILED;
1609
1610
for (;;) {
1611
int ret = drmCrtcQueueSequence(wsi->fd, connector->crtc_id,
1612
flags,
1613
frame_requested,
1614
frame_queued,
1615
(uintptr_t) fence);
1616
1617
if (!ret)
1618
return VK_SUCCESS;
1619
1620
if (errno != ENOMEM) {
1621
1622
/* Something unexpected happened. Pause for a moment so the
1623
* application doesn't just spin and then return a failure indication
1624
*/
1625
1626
wsi_display_debug("queue vblank event %lu failed\n", fence->sequence);
1627
struct timespec delay = {
1628
.tv_sec = 0,
1629
.tv_nsec = 100000000ull,
1630
};
1631
nanosleep(&delay, NULL);
1632
return VK_ERROR_OUT_OF_HOST_MEMORY;
1633
}
1634
1635
/* The kernel event queue is full. Wait for some events to be
1636
* processed and try again
1637
*/
1638
1639
pthread_mutex_lock(&wsi->wait_mutex);
1640
ret = wsi_display_wait_for_event(wsi, wsi_rel_to_abs_time(100000000ull));
1641
pthread_mutex_unlock(&wsi->wait_mutex);
1642
1643
if (ret) {
1644
wsi_display_debug("vblank queue full, event wait failed\n");
1645
return VK_ERROR_OUT_OF_HOST_MEMORY;
1646
}
1647
}
1648
}
1649
1650
/*
1651
* Check to see if the kernel has no flip queued and if there's an image
1652
* waiting to be displayed.
1653
*/
1654
static VkResult
1655
_wsi_display_queue_next(struct wsi_swapchain *drv_chain)
1656
{
1657
struct wsi_display_swapchain *chain =
1658
(struct wsi_display_swapchain *) drv_chain;
1659
struct wsi_display *wsi = chain->wsi;
1660
VkIcdSurfaceDisplay *surface = chain->surface;
1661
wsi_display_mode *display_mode =
1662
wsi_display_mode_from_handle(surface->displayMode);
1663
wsi_display_connector *connector = display_mode->connector;
1664
1665
if (wsi->fd < 0)
1666
return VK_ERROR_SURFACE_LOST_KHR;
1667
1668
if (display_mode != connector->current_mode)
1669
connector->active = false;
1670
1671
for (;;) {
1672
1673
/* Check to see if there is an image to display, or if some image is
1674
* already queued */
1675
1676
struct wsi_display_image *image = NULL;
1677
1678
for (uint32_t i = 0; i < chain->base.image_count; i++) {
1679
struct wsi_display_image *tmp_image = &chain->images[i];
1680
1681
switch (tmp_image->state) {
1682
case WSI_IMAGE_FLIPPING:
1683
/* already flipping, don't send another to the kernel yet */
1684
return VK_SUCCESS;
1685
case WSI_IMAGE_QUEUED:
1686
/* find the oldest queued */
1687
if (!image || tmp_image->flip_sequence < image->flip_sequence)
1688
image = tmp_image;
1689
break;
1690
default:
1691
break;
1692
}
1693
}
1694
1695
if (!image)
1696
return VK_SUCCESS;
1697
1698
int ret;
1699
if (connector->active) {
1700
ret = drmModePageFlip(wsi->fd, connector->crtc_id, image->fb_id,
1701
DRM_MODE_PAGE_FLIP_EVENT, image);
1702
if (ret == 0) {
1703
image->state = WSI_IMAGE_FLIPPING;
1704
return VK_SUCCESS;
1705
}
1706
wsi_display_debug("page flip err %d %s\n", ret, strerror(-ret));
1707
} else {
1708
ret = -EINVAL;
1709
}
1710
1711
if (ret == -EINVAL) {
1712
VkResult result = wsi_display_setup_connector(connector, display_mode);
1713
1714
if (result != VK_SUCCESS) {
1715
image->state = WSI_IMAGE_IDLE;
1716
return result;
1717
}
1718
1719
/* XXX allow setting of position */
1720
ret = drmModeSetCrtc(wsi->fd, connector->crtc_id,
1721
image->fb_id, 0, 0,
1722
&connector->id, 1,
1723
&connector->current_drm_mode);
1724
if (ret == 0) {
1725
/* Disable the HW cursor as the app doesn't have a mechanism
1726
* to control it.
1727
* Refer to question 12 of the VK_KHR_display spec.
1728
*/
1729
ret = drmModeSetCursor(wsi->fd, connector->crtc_id, 0, 0, 0 );
1730
if (ret != 0) {
1731
wsi_display_debug("failed to hide cursor err %d %s\n", ret, strerror(-ret));
1732
}
1733
1734
/* Assume that the mode set is synchronous and that any
1735
* previous image is now idle.
1736
*/
1737
image->state = WSI_IMAGE_DISPLAYING;
1738
wsi_display_idle_old_displaying(image);
1739
connector->active = true;
1740
return VK_SUCCESS;
1741
}
1742
}
1743
1744
if (ret != -EACCES) {
1745
connector->active = false;
1746
image->state = WSI_IMAGE_IDLE;
1747
return VK_ERROR_SURFACE_LOST_KHR;
1748
}
1749
1750
/* Some other VT is currently active. Sit here waiting for
1751
* our VT to become active again by polling once a second
1752
*/
1753
usleep(1000 * 1000);
1754
connector->active = false;
1755
}
1756
}
1757
1758
static VkResult
1759
wsi_display_queue_present(struct wsi_swapchain *drv_chain,
1760
uint32_t image_index,
1761
const VkPresentRegionKHR *damage)
1762
{
1763
struct wsi_display_swapchain *chain =
1764
(struct wsi_display_swapchain *) drv_chain;
1765
struct wsi_display *wsi = chain->wsi;
1766
struct wsi_display_image *image = &chain->images[image_index];
1767
VkResult result;
1768
1769
/* Bail early if the swapchain is broken */
1770
if (chain->status != VK_SUCCESS)
1771
return chain->status;
1772
1773
assert(image->state == WSI_IMAGE_DRAWING);
1774
wsi_display_debug("present %d\n", image_index);
1775
1776
pthread_mutex_lock(&wsi->wait_mutex);
1777
1778
image->flip_sequence = ++chain->flip_sequence;
1779
image->state = WSI_IMAGE_QUEUED;
1780
1781
result = _wsi_display_queue_next(drv_chain);
1782
if (result != VK_SUCCESS)
1783
chain->status = result;
1784
1785
pthread_mutex_unlock(&wsi->wait_mutex);
1786
1787
if (result != VK_SUCCESS)
1788
return result;
1789
1790
return chain->status;
1791
}
1792
1793
static VkResult
1794
wsi_display_surface_create_swapchain(
1795
VkIcdSurfaceBase *icd_surface,
1796
VkDevice device,
1797
struct wsi_device *wsi_device,
1798
const VkSwapchainCreateInfoKHR *create_info,
1799
const VkAllocationCallbacks *allocator,
1800
struct wsi_swapchain **swapchain_out)
1801
{
1802
struct wsi_display *wsi =
1803
(struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1804
1805
assert(create_info->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR);
1806
1807
const unsigned num_images = create_info->minImageCount;
1808
struct wsi_display_swapchain *chain =
1809
vk_zalloc(allocator,
1810
sizeof(*chain) + num_images * sizeof(chain->images[0]),
1811
8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1812
1813
if (chain == NULL)
1814
return VK_ERROR_OUT_OF_HOST_MEMORY;
1815
1816
VkResult result = wsi_swapchain_init(wsi_device, &chain->base, device,
1817
create_info, allocator);
1818
if (result != VK_SUCCESS) {
1819
vk_free(allocator, chain);
1820
return result;
1821
}
1822
1823
chain->base.destroy = wsi_display_swapchain_destroy;
1824
chain->base.get_wsi_image = wsi_display_get_wsi_image;
1825
chain->base.acquire_next_image = wsi_display_acquire_next_image;
1826
chain->base.queue_present = wsi_display_queue_present;
1827
chain->base.present_mode = wsi_swapchain_get_present_mode(wsi_device, create_info);
1828
chain->base.image_count = num_images;
1829
1830
chain->wsi = wsi;
1831
chain->status = VK_SUCCESS;
1832
1833
chain->surface = (VkIcdSurfaceDisplay *) icd_surface;
1834
1835
for (uint32_t image = 0; image < chain->base.image_count; image++) {
1836
result = wsi_display_image_init(device, &chain->base,
1837
create_info, allocator,
1838
&chain->images[image]);
1839
if (result != VK_SUCCESS) {
1840
while (image > 0) {
1841
--image;
1842
wsi_display_image_finish(&chain->base, allocator,
1843
&chain->images[image]);
1844
}
1845
vk_free(allocator, chain);
1846
goto fail_init_images;
1847
}
1848
}
1849
1850
*swapchain_out = &chain->base;
1851
1852
return VK_SUCCESS;
1853
1854
fail_init_images:
1855
return result;
1856
}
1857
1858
static bool
1859
wsi_init_pthread_cond_monotonic(pthread_cond_t *cond)
1860
{
1861
pthread_condattr_t condattr;
1862
bool ret = false;
1863
1864
if (pthread_condattr_init(&condattr) != 0)
1865
goto fail_attr_init;
1866
1867
if (pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC) != 0)
1868
goto fail_attr_set;
1869
1870
if (pthread_cond_init(cond, &condattr) != 0)
1871
goto fail_cond_init;
1872
1873
ret = true;
1874
1875
fail_cond_init:
1876
fail_attr_set:
1877
pthread_condattr_destroy(&condattr);
1878
fail_attr_init:
1879
return ret;
1880
}
1881
1882
1883
/*
1884
* Local version fo the libdrm helper. Added to avoid depending on bleeding
1885
* edge version of the library.
1886
*/
1887
static int
1888
local_drmIsMaster(int fd)
1889
{
1890
/* Detect master by attempting something that requires master.
1891
*
1892
* Authenticating magic tokens requires master and 0 is an
1893
* internal kernel detail which we could use. Attempting this on
1894
* a master fd would fail therefore fail with EINVAL because 0
1895
* is invalid.
1896
*
1897
* A non-master fd will fail with EACCES, as the kernel checks
1898
* for master before attempting to do anything else.
1899
*
1900
* Since we don't want to leak implementation details, use
1901
* EACCES.
1902
*/
1903
return drmAuthMagic(fd, 0) != -EACCES;
1904
}
1905
1906
VkResult
1907
wsi_display_init_wsi(struct wsi_device *wsi_device,
1908
const VkAllocationCallbacks *alloc,
1909
int display_fd)
1910
{
1911
struct wsi_display *wsi = vk_zalloc(alloc, sizeof(*wsi), 8,
1912
VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1913
VkResult result;
1914
1915
if (!wsi) {
1916
result = VK_ERROR_OUT_OF_HOST_MEMORY;
1917
goto fail;
1918
}
1919
1920
wsi->fd = display_fd;
1921
if (wsi->fd != -1 && !local_drmIsMaster(wsi->fd))
1922
wsi->fd = -1;
1923
1924
wsi->alloc = alloc;
1925
1926
list_inithead(&wsi->connectors);
1927
1928
int ret = pthread_mutex_init(&wsi->wait_mutex, NULL);
1929
if (ret) {
1930
result = VK_ERROR_OUT_OF_HOST_MEMORY;
1931
goto fail_mutex;
1932
}
1933
1934
if (!wsi_init_pthread_cond_monotonic(&wsi->wait_cond)) {
1935
result = VK_ERROR_OUT_OF_HOST_MEMORY;
1936
goto fail_cond;
1937
}
1938
1939
wsi->base.get_support = wsi_display_surface_get_support;
1940
wsi->base.get_capabilities2 = wsi_display_surface_get_capabilities2;
1941
wsi->base.get_formats = wsi_display_surface_get_formats;
1942
wsi->base.get_formats2 = wsi_display_surface_get_formats2;
1943
wsi->base.get_present_modes = wsi_display_surface_get_present_modes;
1944
wsi->base.get_present_rectangles = wsi_display_surface_get_present_rectangles;
1945
wsi->base.create_swapchain = wsi_display_surface_create_swapchain;
1946
1947
wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY] = &wsi->base;
1948
1949
return VK_SUCCESS;
1950
1951
fail_cond:
1952
pthread_mutex_destroy(&wsi->wait_mutex);
1953
fail_mutex:
1954
vk_free(alloc, wsi);
1955
fail:
1956
return result;
1957
}
1958
1959
void
1960
wsi_display_finish_wsi(struct wsi_device *wsi_device,
1961
const VkAllocationCallbacks *alloc)
1962
{
1963
struct wsi_display *wsi =
1964
(struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1965
1966
if (wsi) {
1967
wsi_for_each_connector(connector, wsi) {
1968
wsi_for_each_display_mode(mode, connector) {
1969
vk_free(wsi->alloc, mode);
1970
}
1971
vk_free(wsi->alloc, connector);
1972
}
1973
1974
wsi_display_stop_wait_thread(wsi);
1975
pthread_mutex_destroy(&wsi->wait_mutex);
1976
pthread_cond_destroy(&wsi->wait_cond);
1977
1978
vk_free(alloc, wsi);
1979
}
1980
}
1981
1982
/*
1983
* Implement vkReleaseDisplay
1984
*/
1985
VkResult
1986
wsi_release_display(VkPhysicalDevice physical_device,
1987
struct wsi_device *wsi_device,
1988
VkDisplayKHR display)
1989
{
1990
struct wsi_display *wsi =
1991
(struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1992
1993
if (wsi->fd >= 0) {
1994
wsi_display_stop_wait_thread(wsi);
1995
1996
close(wsi->fd);
1997
wsi->fd = -1;
1998
}
1999
2000
#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
2001
wsi_display_connector_from_handle(display)->output = None;
2002
#endif
2003
2004
return VK_SUCCESS;
2005
}
2006
2007
#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
2008
2009
static struct wsi_display_connector *
2010
wsi_display_find_output(struct wsi_device *wsi_device,
2011
xcb_randr_output_t output)
2012
{
2013
struct wsi_display *wsi =
2014
(struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2015
2016
wsi_for_each_connector(connector, wsi) {
2017
if (connector->output == output)
2018
return connector;
2019
}
2020
2021
return NULL;
2022
}
2023
2024
/*
2025
* Given a RandR output, find the associated kernel connector_id by
2026
* looking at the CONNECTOR_ID property provided by the X server
2027
*/
2028
2029
static uint32_t
2030
wsi_display_output_to_connector_id(xcb_connection_t *connection,
2031
xcb_atom_t *connector_id_atom_p,
2032
xcb_randr_output_t output)
2033
{
2034
uint32_t connector_id = 0;
2035
xcb_atom_t connector_id_atom = *connector_id_atom_p;
2036
2037
if (connector_id_atom == 0) {
2038
/* Go dig out the CONNECTOR_ID property */
2039
xcb_intern_atom_cookie_t ia_c = xcb_intern_atom(connection,
2040
true,
2041
12,
2042
"CONNECTOR_ID");
2043
xcb_intern_atom_reply_t *ia_r = xcb_intern_atom_reply(connection,
2044
ia_c,
2045
NULL);
2046
if (ia_r) {
2047
*connector_id_atom_p = connector_id_atom = ia_r->atom;
2048
free(ia_r);
2049
}
2050
}
2051
2052
/* If there's an CONNECTOR_ID atom in the server, then there may be a
2053
* CONNECTOR_ID property. Otherwise, there will not be and we don't even
2054
* need to bother.
2055
*/
2056
if (connector_id_atom) {
2057
2058
xcb_randr_query_version_cookie_t qv_c =
2059
xcb_randr_query_version(connection, 1, 6);
2060
xcb_randr_get_output_property_cookie_t gop_c =
2061
xcb_randr_get_output_property(connection,
2062
output,
2063
connector_id_atom,
2064
0,
2065
0,
2066
0xffffffffUL,
2067
0,
2068
0);
2069
xcb_randr_query_version_reply_t *qv_r =
2070
xcb_randr_query_version_reply(connection, qv_c, NULL);
2071
free(qv_r);
2072
xcb_randr_get_output_property_reply_t *gop_r =
2073
xcb_randr_get_output_property_reply(connection, gop_c, NULL);
2074
if (gop_r) {
2075
if (gop_r->num_items == 1 && gop_r->format == 32)
2076
memcpy(&connector_id, xcb_randr_get_output_property_data(gop_r), 4);
2077
free(gop_r);
2078
}
2079
}
2080
return connector_id;
2081
}
2082
2083
static bool
2084
wsi_display_check_randr_version(xcb_connection_t *connection)
2085
{
2086
xcb_randr_query_version_cookie_t qv_c =
2087
xcb_randr_query_version(connection, 1, 6);
2088
xcb_randr_query_version_reply_t *qv_r =
2089
xcb_randr_query_version_reply(connection, qv_c, NULL);
2090
bool ret = false;
2091
2092
if (!qv_r)
2093
return false;
2094
2095
/* Check for version 1.6 or newer */
2096
ret = (qv_r->major_version > 1 ||
2097
(qv_r->major_version == 1 && qv_r->minor_version >= 6));
2098
2099
free(qv_r);
2100
return ret;
2101
}
2102
2103
/*
2104
* Given a kernel connector id, find the associated RandR output using the
2105
* CONNECTOR_ID property
2106
*/
2107
2108
static xcb_randr_output_t
2109
wsi_display_connector_id_to_output(xcb_connection_t *connection,
2110
uint32_t connector_id)
2111
{
2112
if (!wsi_display_check_randr_version(connection))
2113
return 0;
2114
2115
const xcb_setup_t *setup = xcb_get_setup(connection);
2116
2117
xcb_atom_t connector_id_atom = 0;
2118
xcb_randr_output_t output = 0;
2119
2120
/* Search all of the screens for the provided output */
2121
xcb_screen_iterator_t iter;
2122
for (iter = xcb_setup_roots_iterator(setup);
2123
output == 0 && iter.rem;
2124
xcb_screen_next(&iter))
2125
{
2126
xcb_randr_get_screen_resources_cookie_t gsr_c =
2127
xcb_randr_get_screen_resources(connection, iter.data->root);
2128
xcb_randr_get_screen_resources_reply_t *gsr_r =
2129
xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
2130
2131
if (!gsr_r)
2132
return 0;
2133
2134
xcb_randr_output_t *ro = xcb_randr_get_screen_resources_outputs(gsr_r);
2135
int o;
2136
2137
for (o = 0; o < gsr_r->num_outputs; o++) {
2138
if (wsi_display_output_to_connector_id(connection,
2139
&connector_id_atom, ro[o])
2140
== connector_id)
2141
{
2142
output = ro[o];
2143
break;
2144
}
2145
}
2146
free(gsr_r);
2147
}
2148
return output;
2149
}
2150
2151
/*
2152
* Given a RandR output, find out which screen it's associated with
2153
*/
2154
static xcb_window_t
2155
wsi_display_output_to_root(xcb_connection_t *connection,
2156
xcb_randr_output_t output)
2157
{
2158
if (!wsi_display_check_randr_version(connection))
2159
return 0;
2160
2161
const xcb_setup_t *setup = xcb_get_setup(connection);
2162
xcb_window_t root = 0;
2163
2164
/* Search all of the screens for the provided output */
2165
for (xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
2166
root == 0 && iter.rem;
2167
xcb_screen_next(&iter))
2168
{
2169
xcb_randr_get_screen_resources_cookie_t gsr_c =
2170
xcb_randr_get_screen_resources(connection, iter.data->root);
2171
xcb_randr_get_screen_resources_reply_t *gsr_r =
2172
xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
2173
2174
if (!gsr_r)
2175
return 0;
2176
2177
xcb_randr_output_t *ro = xcb_randr_get_screen_resources_outputs(gsr_r);
2178
2179
for (int o = 0; o < gsr_r->num_outputs; o++) {
2180
if (ro[o] == output) {
2181
root = iter.data->root;
2182
break;
2183
}
2184
}
2185
free(gsr_r);
2186
}
2187
return root;
2188
}
2189
2190
static bool
2191
wsi_display_mode_matches_x(struct wsi_display_mode *wsi,
2192
xcb_randr_mode_info_t *xcb)
2193
{
2194
return wsi->clock == (xcb->dot_clock + 500) / 1000 &&
2195
wsi->hdisplay == xcb->width &&
2196
wsi->hsync_start == xcb->hsync_start &&
2197
wsi->hsync_end == xcb->hsync_end &&
2198
wsi->htotal == xcb->htotal &&
2199
wsi->hskew == xcb->hskew &&
2200
wsi->vdisplay == xcb->height &&
2201
wsi->vsync_start == xcb->vsync_start &&
2202
wsi->vsync_end == xcb->vsync_end &&
2203
wsi->vtotal == xcb->vtotal &&
2204
wsi->vscan <= 1 &&
2205
wsi->flags == xcb->mode_flags;
2206
}
2207
2208
static struct wsi_display_mode *
2209
wsi_display_find_x_mode(struct wsi_device *wsi_device,
2210
struct wsi_display_connector *connector,
2211
xcb_randr_mode_info_t *mode)
2212
{
2213
wsi_for_each_display_mode(display_mode, connector) {
2214
if (wsi_display_mode_matches_x(display_mode, mode))
2215
return display_mode;
2216
}
2217
return NULL;
2218
}
2219
2220
static VkResult
2221
wsi_display_register_x_mode(struct wsi_device *wsi_device,
2222
struct wsi_display_connector *connector,
2223
xcb_randr_mode_info_t *x_mode,
2224
bool preferred)
2225
{
2226
struct wsi_display *wsi =
2227
(struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2228
struct wsi_display_mode *display_mode =
2229
wsi_display_find_x_mode(wsi_device, connector, x_mode);
2230
2231
if (display_mode) {
2232
display_mode->valid = true;
2233
return VK_SUCCESS;
2234
}
2235
2236
display_mode = vk_zalloc(wsi->alloc, sizeof (struct wsi_display_mode),
2237
8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2238
if (!display_mode)
2239
return VK_ERROR_OUT_OF_HOST_MEMORY;
2240
2241
display_mode->connector = connector;
2242
display_mode->valid = true;
2243
display_mode->preferred = preferred;
2244
display_mode->clock = (x_mode->dot_clock + 500) / 1000; /* kHz */
2245
display_mode->hdisplay = x_mode->width;
2246
display_mode->hsync_start = x_mode->hsync_start;
2247
display_mode->hsync_end = x_mode->hsync_end;
2248
display_mode->htotal = x_mode->htotal;
2249
display_mode->hskew = x_mode->hskew;
2250
display_mode->vdisplay = x_mode->height;
2251
display_mode->vsync_start = x_mode->vsync_start;
2252
display_mode->vsync_end = x_mode->vsync_end;
2253
display_mode->vtotal = x_mode->vtotal;
2254
display_mode->vscan = 0;
2255
display_mode->flags = x_mode->mode_flags;
2256
2257
list_addtail(&display_mode->list, &connector->display_modes);
2258
return VK_SUCCESS;
2259
}
2260
2261
static struct wsi_display_connector *
2262
wsi_display_get_output(struct wsi_device *wsi_device,
2263
xcb_connection_t *connection,
2264
xcb_randr_output_t output)
2265
{
2266
struct wsi_display *wsi =
2267
(struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2268
struct wsi_display_connector *connector;
2269
uint32_t connector_id;
2270
2271
xcb_window_t root = wsi_display_output_to_root(connection, output);
2272
if (!root)
2273
return NULL;
2274
2275
/* See if we already have a connector for this output */
2276
connector = wsi_display_find_output(wsi_device, output);
2277
2278
if (!connector) {
2279
xcb_atom_t connector_id_atom = 0;
2280
2281
/*
2282
* Go get the kernel connector ID for this X output
2283
*/
2284
connector_id = wsi_display_output_to_connector_id(connection,
2285
&connector_id_atom,
2286
output);
2287
2288
/* Any X server with lease support will have this atom */
2289
if (!connector_id) {
2290
return NULL;
2291
}
2292
2293
/* See if we already have a connector for this id */
2294
connector = wsi_display_find_connector(wsi_device, connector_id);
2295
2296
if (connector == NULL) {
2297
connector = wsi_display_alloc_connector(wsi, connector_id);
2298
if (!connector) {
2299
return NULL;
2300
}
2301
list_addtail(&connector->list, &wsi->connectors);
2302
}
2303
connector->output = output;
2304
}
2305
2306
xcb_randr_get_screen_resources_cookie_t src =
2307
xcb_randr_get_screen_resources(connection, root);
2308
xcb_randr_get_output_info_cookie_t oic =
2309
xcb_randr_get_output_info(connection, output, XCB_CURRENT_TIME);
2310
xcb_randr_get_screen_resources_reply_t *srr =
2311
xcb_randr_get_screen_resources_reply(connection, src, NULL);
2312
xcb_randr_get_output_info_reply_t *oir =
2313
xcb_randr_get_output_info_reply(connection, oic, NULL);
2314
2315
if (oir && srr) {
2316
/* Get X modes and add them */
2317
2318
connector->connected =
2319
oir->connection != XCB_RANDR_CONNECTION_DISCONNECTED;
2320
2321
wsi_display_invalidate_connector_modes(wsi_device, connector);
2322
2323
xcb_randr_mode_t *x_modes = xcb_randr_get_output_info_modes(oir);
2324
for (int m = 0; m < oir->num_modes; m++) {
2325
xcb_randr_mode_info_iterator_t i =
2326
xcb_randr_get_screen_resources_modes_iterator(srr);
2327
while (i.rem) {
2328
xcb_randr_mode_info_t *mi = i.data;
2329
if (mi->id == x_modes[m]) {
2330
VkResult result = wsi_display_register_x_mode(
2331
wsi_device, connector, mi, m < oir->num_preferred);
2332
if (result != VK_SUCCESS) {
2333
free(oir);
2334
free(srr);
2335
return NULL;
2336
}
2337
break;
2338
}
2339
xcb_randr_mode_info_next(&i);
2340
}
2341
}
2342
}
2343
2344
free(oir);
2345
free(srr);
2346
return connector;
2347
}
2348
2349
static xcb_randr_crtc_t
2350
wsi_display_find_crtc_for_output(xcb_connection_t *connection,
2351
xcb_window_t root,
2352
xcb_randr_output_t output)
2353
{
2354
xcb_randr_get_screen_resources_cookie_t gsr_c =
2355
xcb_randr_get_screen_resources(connection, root);
2356
xcb_randr_get_screen_resources_reply_t *gsr_r =
2357
xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
2358
2359
if (!gsr_r)
2360
return 0;
2361
2362
xcb_randr_crtc_t *rc = xcb_randr_get_screen_resources_crtcs(gsr_r);
2363
xcb_randr_crtc_t idle_crtc = 0;
2364
xcb_randr_crtc_t active_crtc = 0;
2365
2366
/* Find either a crtc already connected to the desired output or idle */
2367
for (int c = 0; active_crtc == 0 && c < gsr_r->num_crtcs; c++) {
2368
xcb_randr_get_crtc_info_cookie_t gci_c =
2369
xcb_randr_get_crtc_info(connection, rc[c], gsr_r->config_timestamp);
2370
xcb_randr_get_crtc_info_reply_t *gci_r =
2371
xcb_randr_get_crtc_info_reply(connection, gci_c, NULL);
2372
2373
if (gci_r) {
2374
if (gci_r->mode) {
2375
int num_outputs = xcb_randr_get_crtc_info_outputs_length(gci_r);
2376
xcb_randr_output_t *outputs =
2377
xcb_randr_get_crtc_info_outputs(gci_r);
2378
2379
if (num_outputs == 1 && outputs[0] == output)
2380
active_crtc = rc[c];
2381
2382
} else if (idle_crtc == 0) {
2383
int num_possible = xcb_randr_get_crtc_info_possible_length(gci_r);
2384
xcb_randr_output_t *possible =
2385
xcb_randr_get_crtc_info_possible(gci_r);
2386
2387
for (int p = 0; p < num_possible; p++)
2388
if (possible[p] == output) {
2389
idle_crtc = rc[c];
2390
break;
2391
}
2392
}
2393
free(gci_r);
2394
}
2395
}
2396
free(gsr_r);
2397
2398
if (active_crtc)
2399
return active_crtc;
2400
return idle_crtc;
2401
}
2402
2403
VkResult
2404
wsi_acquire_xlib_display(VkPhysicalDevice physical_device,
2405
struct wsi_device *wsi_device,
2406
Display *dpy,
2407
VkDisplayKHR display)
2408
{
2409
struct wsi_display *wsi =
2410
(struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2411
xcb_connection_t *connection = XGetXCBConnection(dpy);
2412
struct wsi_display_connector *connector =
2413
wsi_display_connector_from_handle(display);
2414
xcb_window_t root;
2415
2416
/* XXX no support for multiple leases yet */
2417
if (wsi->fd >= 0)
2418
return VK_ERROR_INITIALIZATION_FAILED;
2419
2420
if (!connector->output) {
2421
connector->output = wsi_display_connector_id_to_output(connection,
2422
connector->id);
2423
2424
/* Check and see if we found the output */
2425
if (!connector->output)
2426
return VK_ERROR_INITIALIZATION_FAILED;
2427
}
2428
2429
root = wsi_display_output_to_root(connection, connector->output);
2430
if (!root)
2431
return VK_ERROR_INITIALIZATION_FAILED;
2432
2433
xcb_randr_crtc_t crtc = wsi_display_find_crtc_for_output(connection,
2434
root,
2435
connector->output);
2436
2437
if (!crtc)
2438
return VK_ERROR_INITIALIZATION_FAILED;
2439
2440
#ifdef HAVE_DRI3_MODIFIERS
2441
xcb_randr_lease_t lease = xcb_generate_id(connection);
2442
xcb_randr_create_lease_cookie_t cl_c =
2443
xcb_randr_create_lease(connection, root, lease, 1, 1,
2444
&crtc, &connector->output);
2445
xcb_randr_create_lease_reply_t *cl_r =
2446
xcb_randr_create_lease_reply(connection, cl_c, NULL);
2447
if (!cl_r)
2448
return VK_ERROR_INITIALIZATION_FAILED;
2449
2450
int fd = -1;
2451
if (cl_r->nfd > 0) {
2452
int *rcl_f = xcb_randr_create_lease_reply_fds(connection, cl_r);
2453
2454
fd = rcl_f[0];
2455
}
2456
free (cl_r);
2457
if (fd < 0)
2458
return VK_ERROR_INITIALIZATION_FAILED;
2459
2460
wsi->fd = fd;
2461
#endif
2462
2463
return VK_SUCCESS;
2464
}
2465
2466
VkResult
2467
wsi_get_randr_output_display(VkPhysicalDevice physical_device,
2468
struct wsi_device *wsi_device,
2469
Display *dpy,
2470
RROutput output,
2471
VkDisplayKHR *display)
2472
{
2473
xcb_connection_t *connection = XGetXCBConnection(dpy);
2474
struct wsi_display_connector *connector =
2475
wsi_display_get_output(wsi_device, connection, (xcb_randr_output_t) output);
2476
2477
if (connector)
2478
*display = wsi_display_connector_to_handle(connector);
2479
else
2480
*display = VK_NULL_HANDLE;
2481
return VK_SUCCESS;
2482
}
2483
2484
#endif
2485
2486
/* VK_EXT_display_control */
2487
VkResult
2488
wsi_display_power_control(VkDevice device,
2489
struct wsi_device *wsi_device,
2490
VkDisplayKHR display,
2491
const VkDisplayPowerInfoEXT *display_power_info)
2492
{
2493
struct wsi_display *wsi =
2494
(struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2495
struct wsi_display_connector *connector =
2496
wsi_display_connector_from_handle(display);
2497
int mode;
2498
2499
if (wsi->fd < 0)
2500
return VK_ERROR_INITIALIZATION_FAILED;
2501
2502
switch (display_power_info->powerState) {
2503
case VK_DISPLAY_POWER_STATE_OFF_EXT:
2504
mode = DRM_MODE_DPMS_OFF;
2505
break;
2506
case VK_DISPLAY_POWER_STATE_SUSPEND_EXT:
2507
mode = DRM_MODE_DPMS_SUSPEND;
2508
break;
2509
default:
2510
mode = DRM_MODE_DPMS_ON;
2511
break;
2512
}
2513
drmModeConnectorSetProperty(wsi->fd,
2514
connector->id,
2515
connector->dpms_property,
2516
mode);
2517
return VK_SUCCESS;
2518
}
2519
2520
VkResult
2521
wsi_register_device_event(VkDevice device,
2522
struct wsi_device *wsi_device,
2523
const VkDeviceEventInfoEXT *device_event_info,
2524
const VkAllocationCallbacks *allocator,
2525
struct wsi_fence **fence_p,
2526
int sync_fd)
2527
{
2528
return VK_ERROR_FEATURE_NOT_PRESENT;
2529
}
2530
2531
VkResult
2532
wsi_register_display_event(VkDevice device,
2533
struct wsi_device *wsi_device,
2534
VkDisplayKHR display,
2535
const VkDisplayEventInfoEXT *display_event_info,
2536
const VkAllocationCallbacks *allocator,
2537
struct wsi_fence **fence_p,
2538
int sync_fd)
2539
{
2540
struct wsi_display *wsi =
2541
(struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2542
struct wsi_display_fence *fence;
2543
VkResult ret;
2544
2545
switch (display_event_info->displayEvent) {
2546
case VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT:
2547
2548
fence = wsi_display_fence_alloc(device, wsi_device, display, allocator, sync_fd);
2549
2550
if (!fence)
2551
return VK_ERROR_OUT_OF_HOST_MEMORY;
2552
2553
ret = wsi_register_vblank_event(fence, wsi_device, display,
2554
DRM_CRTC_SEQUENCE_RELATIVE, 1, NULL);
2555
2556
if (ret == VK_SUCCESS) {
2557
if (fence_p)
2558
*fence_p = &fence->base;
2559
else
2560
fence->base.destroy(&fence->base);
2561
} else if (fence != NULL) {
2562
if (fence->syncobj)
2563
drmSyncobjDestroy(wsi->fd, fence->syncobj);
2564
vk_free2(wsi->alloc, allocator, fence);
2565
}
2566
2567
break;
2568
default:
2569
ret = VK_ERROR_FEATURE_NOT_PRESENT;
2570
break;
2571
}
2572
2573
return ret;
2574
}
2575
2576
2577
VkResult
2578
wsi_get_swapchain_counter(VkDevice device,
2579
struct wsi_device *wsi_device,
2580
VkSwapchainKHR _swapchain,
2581
VkSurfaceCounterFlagBitsEXT flag_bits,
2582
uint64_t *value)
2583
{
2584
struct wsi_display *wsi =
2585
(struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2586
struct wsi_display_swapchain *swapchain =
2587
(struct wsi_display_swapchain *) wsi_swapchain_from_handle(_swapchain);
2588
struct wsi_display_connector *connector =
2589
wsi_display_mode_from_handle(swapchain->surface->displayMode)->connector;
2590
2591
if (wsi->fd < 0)
2592
return VK_ERROR_INITIALIZATION_FAILED;
2593
2594
if (!connector->active) {
2595
*value = 0;
2596
return VK_SUCCESS;
2597
}
2598
2599
int ret = drmCrtcGetSequence(wsi->fd, connector->crtc_id, value, NULL);
2600
if (ret)
2601
*value = 0;
2602
2603
return VK_SUCCESS;
2604
}
2605
2606
VkResult
2607
wsi_acquire_drm_display(VkPhysicalDevice pDevice,
2608
struct wsi_device *wsi_device,
2609
int drm_fd,
2610
VkDisplayKHR display)
2611
{
2612
if (!wsi_device_matches_drm_fd(wsi_device, drm_fd))
2613
return VK_ERROR_UNKNOWN;
2614
2615
struct wsi_display *wsi =
2616
(struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2617
2618
/* XXX no support for mulitple leases yet */
2619
if (wsi->fd >= 0 || !local_drmIsMaster(drm_fd))
2620
return VK_ERROR_INITIALIZATION_FAILED;
2621
2622
struct wsi_display_connector *connector =
2623
wsi_display_connector_from_handle(display);
2624
2625
drmModeConnectorPtr drm_connector =
2626
drmModeGetConnectorCurrent(drm_fd, connector->id);
2627
2628
if (!drm_connector)
2629
return VK_ERROR_INITIALIZATION_FAILED;
2630
2631
drmModeFreeConnector(drm_connector);
2632
2633
wsi->fd = drm_fd;
2634
return VK_SUCCESS;
2635
}
2636
2637
VkResult
2638
wsi_get_drm_display(VkPhysicalDevice pDevice,
2639
struct wsi_device *wsi_device,
2640
int drm_fd,
2641
int connector_id,
2642
VkDisplayKHR *display)
2643
{
2644
if (!wsi_device_matches_drm_fd(wsi_device, drm_fd))
2645
return VK_ERROR_UNKNOWN;
2646
2647
struct wsi_display_connector *connector =
2648
wsi_display_get_connector(wsi_device, drm_fd, connector_id);
2649
2650
if (!connector) {
2651
*display = VK_NULL_HANDLE;
2652
return VK_ERROR_UNKNOWN;
2653
}
2654
2655
*display = wsi_display_connector_to_handle(connector);
2656
return VK_SUCCESS;
2657
}
2658
2659
2660