1 /*
2 * Copyright 2020 Red Hat, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24 #include "GL/internal/mesa_interface.h"
25 #include "git_sha1.h"
26 #include "util/format/u_format.h"
27 #include "util/u_memory.h"
28 #include "util/u_inlines.h"
29 #include "util/u_box.h"
30 #include "util/log.h"
31 #include "pipe/p_context.h"
32 #include "pipe-loader/pipe_loader.h"
33 #include "state_tracker/st_context.h"
34 #include "zink/zink_public.h"
35 #include "zink/zink_kopper.h"
36 #include "driver_trace/tr_screen.h"
37
38 #include "dri_screen.h"
39 #include "dri_context.h"
40 #include "dri_drawable.h"
41 #include "dri_helpers.h"
42 #include "dri_query_renderer.h"
43 #include "loader_dri_helper.h"
44
45 #include <vulkan/vulkan.h>
46
47 #ifdef VK_USE_PLATFORM_XCB_KHR
48 #include <xcb/xcb.h>
49 #include <xcb/dri3.h>
50 #include <xcb/present.h>
51 #include <xcb/xfixes.h>
52 #include "util/libsync.h"
53 #include <X11/Xlib-xcb.h>
54 #include "drm-uapi/drm_fourcc.h"
55 #endif
56
57 extern const __DRIimageExtension driVkImageExtension;
58 extern const __DRIimageExtension driVkImageExtensionSw;
59
60 static struct dri_drawable *
61 kopper_create_drawable(struct dri_screen *screen, const struct gl_config *visual,
62 bool isPixmap, void *loaderPrivate);
63
64 static inline void
kopper_invalidate_drawable(__DRIdrawable * dPriv)65 kopper_invalidate_drawable(__DRIdrawable *dPriv)
66 {
67 struct dri_drawable *drawable = dri_drawable(dPriv);
68
69 drawable->texture_stamp = drawable->lastStamp - 1;
70
71 p_atomic_inc(&drawable->base.stamp);
72 }
73
74 static const __DRI2flushExtension driVkFlushExtension = {
75 .base = { __DRI2_FLUSH, 4 },
76
77 .flush = dri_flush_drawable,
78 .invalidate = kopper_invalidate_drawable,
79 .flush_with_flags = dri_flush,
80 };
81
82 static const __DRIrobustnessExtension dri2Robustness = {
83 .base = { __DRI2_ROBUSTNESS, 1 }
84 };
85
86 const __DRIkopperExtension driKopperExtension;
87
88 static const __DRIextension *drivk_screen_extensions[] = {
89 &driTexBufferExtension.base,
90 &dri2RendererQueryExtension.base,
91 &dri2ConfigQueryExtension.base,
92 &dri2FenceExtension.base,
93 &dri2Robustness.base,
94 &driVkImageExtension.base,
95 &dri2FlushControlExtension.base,
96 &driVkFlushExtension.base,
97 &driKopperExtension.base,
98 NULL
99 };
100
101 static const __DRIextension *drivk_sw_screen_extensions[] = {
102 &driTexBufferExtension.base,
103 &dri2RendererQueryExtension.base,
104 &dri2ConfigQueryExtension.base,
105 &dri2FenceExtension.base,
106 &dri2Robustness.base,
107 &driVkImageExtensionSw.base,
108 &dri2FlushControlExtension.base,
109 &driVkFlushExtension.base,
110 NULL
111 };
112
113 static const __DRIconfig **
kopper_init_screen(struct dri_screen * screen)114 kopper_init_screen(struct dri_screen *screen)
115 {
116 const __DRIconfig **configs;
117 struct pipe_screen *pscreen = NULL;
118
119 if (!screen->kopper_loader) {
120 fprintf(stderr, "mesa: Kopper interface not found!\n"
121 " Ensure the versions of %s built with this version of Zink are\n"
122 " in your library path!\n", KOPPER_LIB_NAMES);
123 return NULL;
124 }
125
126 screen->can_share_buffer = true;
127
128 bool success;
129 if (screen->fd != -1)
130 success = pipe_loader_drm_probe_fd(&screen->dev, screen->fd, false);
131 else
132 success = pipe_loader_vk_probe_dri(&screen->dev, NULL);
133
134 if (success)
135 pscreen = pipe_loader_create_screen(screen->dev);
136
137 if (!pscreen)
138 goto fail;
139
140 dri_init_options(screen);
141 screen->unwrapped_screen = trace_screen_unwrap(pscreen);
142
143 configs = dri_init_screen(screen, pscreen);
144 if (!configs)
145 goto fail;
146
147 assert(pscreen->get_param(pscreen, PIPE_CAP_DEVICE_RESET_STATUS_QUERY));
148 screen->has_reset_status_query = true;
149 screen->lookup_egl_image = dri2_lookup_egl_image;
150 screen->has_dmabuf = pscreen->get_param(pscreen, PIPE_CAP_DMABUF);
151 screen->has_modifiers = pscreen->query_dmabuf_modifiers != NULL;
152 screen->is_sw = zink_kopper_is_cpu(pscreen);
153 if (screen->has_dmabuf)
154 screen->extensions = drivk_screen_extensions;
155 else
156 screen->extensions = drivk_sw_screen_extensions;
157
158 const __DRIimageLookupExtension *image = screen->dri2.image;
159 if (image &&
160 image->base.version >= 2 &&
161 image->validateEGLImage &&
162 image->lookupEGLImageValidated) {
163 screen->validate_egl_image = dri2_validate_egl_image;
164 screen->lookup_egl_image_validated = dri2_lookup_egl_image_validated;
165 }
166
167 screen->create_drawable = kopper_create_drawable;
168
169 return configs;
170 fail:
171 dri_release_screen(screen);
172 return NULL;
173 }
174
175 // copypasta alert
176
177 extern bool
178 dri_image_drawable_get_buffers(struct dri_drawable *drawable,
179 struct __DRIimageList *images,
180 const enum st_attachment_type *statts,
181 unsigned statts_count);
182
183 #ifdef VK_USE_PLATFORM_XCB_KHR
184 /* Translate from the pipe_format enums used by Gallium to the DRM FourCC
185 * codes used by dmabuf import */
186 static int
pipe_format_to_fourcc(enum pipe_format format)187 pipe_format_to_fourcc(enum pipe_format format)
188 {
189 switch (format) {
190 case PIPE_FORMAT_BGRA8888_SRGB: return __DRI_IMAGE_FOURCC_SABGR8888;
191 case PIPE_FORMAT_BGRX8888_SRGB: return __DRI_IMAGE_FOURCC_SXRGB8888;
192 case PIPE_FORMAT_RGBA8888_SRGB: return __DRI_IMAGE_FOURCC_SABGR8888;
193 case PIPE_FORMAT_B5G6R5_UNORM: return DRM_FORMAT_RGB565;
194 case PIPE_FORMAT_BGRX8888_UNORM: return DRM_FORMAT_XRGB8888;
195 case PIPE_FORMAT_BGRA8888_UNORM: return DRM_FORMAT_ARGB8888;
196 case PIPE_FORMAT_RGBA8888_UNORM: return DRM_FORMAT_ABGR8888;
197 case PIPE_FORMAT_RGBX8888_UNORM: return DRM_FORMAT_XBGR8888;
198 case PIPE_FORMAT_B10G10R10X2_UNORM: return DRM_FORMAT_XRGB2101010;
199 case PIPE_FORMAT_B10G10R10A2_UNORM: return DRM_FORMAT_ARGB2101010;
200 case PIPE_FORMAT_R10G10B10X2_UNORM: return DRM_FORMAT_XBGR2101010;
201 case PIPE_FORMAT_R10G10B10A2_UNORM: return DRM_FORMAT_ABGR2101010;
202 case PIPE_FORMAT_R16G16B16A16_FLOAT: return DRM_FORMAT_XBGR16161616F;
203 case PIPE_FORMAT_R16G16B16X16_FLOAT: return DRM_FORMAT_ABGR16161616F;
204 case PIPE_FORMAT_B5G5R5A1_UNORM: return DRM_FORMAT_ARGB1555;
205 case PIPE_FORMAT_R5G5B5A1_UNORM: return DRM_FORMAT_ABGR1555;
206 case PIPE_FORMAT_B4G4R4A4_UNORM: return DRM_FORMAT_ARGB4444;
207 case PIPE_FORMAT_R4G4B4A4_UNORM: return DRM_FORMAT_ABGR4444;
208 default: return DRM_FORMAT_INVALID;
209 }
210 }
211
212 #ifdef HAVE_DRI3_MODIFIERS
213 static __DRIimage *
dri3_create_image_from_buffers(xcb_connection_t * c,xcb_dri3_buffers_from_pixmap_reply_t * bp_reply,uint32_t fourcc,struct dri_screen * screen,const __DRIimageExtension * image,void * loaderPrivate)214 dri3_create_image_from_buffers(xcb_connection_t *c,
215 xcb_dri3_buffers_from_pixmap_reply_t *bp_reply,
216 uint32_t fourcc,
217 struct dri_screen *screen,
218 const __DRIimageExtension *image,
219 void *loaderPrivate)
220 {
221 __DRIimage *ret;
222 int *fds;
223 uint32_t *strides_in, *offsets_in;
224 int strides[4], offsets[4];
225 unsigned error;
226 int i;
227
228 if (bp_reply->nfd > 4)
229 return NULL;
230
231 fds = xcb_dri3_buffers_from_pixmap_reply_fds(c, bp_reply);
232 strides_in = xcb_dri3_buffers_from_pixmap_strides(bp_reply);
233 offsets_in = xcb_dri3_buffers_from_pixmap_offsets(bp_reply);
234 for (i = 0; i < bp_reply->nfd; i++) {
235 strides[i] = strides_in[i];
236 offsets[i] = offsets_in[i];
237 }
238
239 ret = image->createImageFromDmaBufs2(opaque_dri_screen(screen),
240 bp_reply->width,
241 bp_reply->height,
242 fourcc,
243 bp_reply->modifier,
244 fds, bp_reply->nfd,
245 strides, offsets,
246 0, 0, 0, 0, /* UNDEFINED */
247 &error, loaderPrivate);
248
249 for (i = 0; i < bp_reply->nfd; i++)
250 close(fds[i]);
251
252 return ret;
253 }
254 #endif
255
256 static __DRIimage *
dri3_create_image(xcb_connection_t * c,xcb_dri3_buffer_from_pixmap_reply_t * bp_reply,uint32_t fourcc,struct dri_screen * screen,const __DRIimageExtension * image,void * loaderPrivate)257 dri3_create_image(xcb_connection_t *c,
258 xcb_dri3_buffer_from_pixmap_reply_t *bp_reply,
259 uint32_t fourcc,
260 struct dri_screen *screen,
261 const __DRIimageExtension *image,
262 void *loaderPrivate)
263 {
264 int *fds;
265 __DRIimage *image_planar, *ret;
266 int stride, offset;
267
268 /* Get an FD for the pixmap object
269 */
270 fds = xcb_dri3_buffer_from_pixmap_reply_fds(c, bp_reply);
271
272 stride = bp_reply->stride;
273 offset = 0;
274
275 /* createImageFromFds creates a wrapper __DRIimage structure which
276 * can deal with multiple planes for things like Yuv images. So, once
277 * we've gotten the planar wrapper, pull the single plane out of it and
278 * discard the wrapper.
279 */
280 image_planar = image->createImageFromFds(opaque_dri_screen(screen),
281 bp_reply->width,
282 bp_reply->height,
283 fourcc,
284 fds, 1,
285 &stride, &offset, loaderPrivate);
286 close(fds[0]);
287 if (!image_planar)
288 return NULL;
289
290 ret = image->fromPlanar(image_planar, 0, loaderPrivate);
291
292 if (!ret)
293 ret = image_planar;
294 else
295 image->destroyImage(image_planar);
296
297 return ret;
298 }
299
300
301 static void
handle_in_fence(struct dri_context * ctx,__DRIimage * img)302 handle_in_fence(struct dri_context *ctx, __DRIimage *img)
303 {
304 struct pipe_context *pipe = ctx->st->pipe;
305 struct pipe_fence_handle *fence;
306 int fd = img->in_fence_fd;
307
308 if (fd == -1)
309 return;
310
311 validate_fence_fd(fd);
312
313 img->in_fence_fd = -1;
314
315 pipe->create_fence_fd(pipe, &fence, fd, PIPE_FD_TYPE_NATIVE_SYNC);
316 pipe->fence_server_sync(pipe, fence);
317 pipe->screen->fence_reference(pipe->screen, &fence, NULL);
318
319 close(fd);
320 }
321
322 /** kopper_get_pixmap_buffer
323 *
324 * Get the DRM object for a pixmap from the X server and
325 * wrap that with a __DRIimage structure using createImageFromFds
326 */
327 static struct pipe_resource *
kopper_get_pixmap_buffer(struct dri_drawable * drawable,enum pipe_format pf)328 kopper_get_pixmap_buffer(struct dri_drawable *drawable,
329 enum pipe_format pf)
330 {
331 xcb_drawable_t pixmap;
332 int width;
333 int height;
334 uint32_t fourcc = pipe_format_to_fourcc(pf);
335 struct kopper_loader_info *info = &drawable->info;
336 assert(info->bos.sType == VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR);
337 VkXcbSurfaceCreateInfoKHR *xcb = (VkXcbSurfaceCreateInfoKHR *)&info->bos;
338 xcb_connection_t *conn = xcb->connection;
339 pixmap = xcb->window;
340
341 if (drawable->image)
342 return drawable->image->texture;
343
344 /* FIXME: probably broken for OBS studio?
345 * see dri3_get_pixmap_buffer()
346 */
347 struct dri_screen *screen = drawable->screen;
348
349 #ifdef HAVE_DRI3_MODIFIERS
350 if (drawable->has_modifiers) {
351 xcb_dri3_buffers_from_pixmap_cookie_t bps_cookie;
352 xcb_dri3_buffers_from_pixmap_reply_t *bps_reply;
353 xcb_generic_error_t *error;
354
355 bps_cookie = xcb_dri3_buffers_from_pixmap(conn, pixmap);
356 bps_reply = xcb_dri3_buffers_from_pixmap_reply(conn, bps_cookie, &error);
357 if (!bps_reply) {
358 mesa_loge("kopper: could not create texture from pixmap (%u)", error->error_code);
359 return NULL;
360 }
361 drawable->image =
362 dri3_create_image_from_buffers(conn, bps_reply, fourcc,
363 screen, &driVkImageExtension,
364 drawable);
365 if (!drawable->image)
366 return NULL;
367 width = bps_reply->width;
368 height = bps_reply->height;
369 free(bps_reply);
370 } else
371 #endif
372 {
373 xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie;
374 xcb_dri3_buffer_from_pixmap_reply_t *bp_reply;
375 xcb_generic_error_t *error;
376
377 bp_cookie = xcb_dri3_buffer_from_pixmap(conn, pixmap);
378 bp_reply = xcb_dri3_buffer_from_pixmap_reply(conn, bp_cookie, &error);
379 if (!bp_reply) {
380 mesa_loge("kopper: could not create texture from pixmap (%u)", error->error_code);
381 return NULL;
382 }
383
384 drawable->image = dri3_create_image(conn, bp_reply, fourcc,
385 screen, &driVkImageExtension,
386 drawable);
387 if (!drawable->image)
388 return NULL;
389 width = bp_reply->width;
390 height = bp_reply->height;
391 free(bp_reply);
392 }
393
394 drawable->w = width;
395 drawable->h = height;
396
397 return drawable->image->texture;
398 }
399 #endif //VK_USE_PLATFORM_XCB_KHR
400
401 static void
kopper_allocate_textures(struct dri_context * ctx,struct dri_drawable * drawable,const enum st_attachment_type * statts,unsigned statts_count)402 kopper_allocate_textures(struct dri_context *ctx,
403 struct dri_drawable *drawable,
404 const enum st_attachment_type *statts,
405 unsigned statts_count)
406 {
407 struct dri_screen *screen = drawable->screen;
408 struct pipe_resource templ;
409 unsigned width, height;
410 bool resized;
411 unsigned i;
412 struct __DRIimageList images;
413 const __DRIimageLoaderExtension *image = screen->image.loader;
414
415 bool is_window = drawable->is_window;
416 bool is_pixmap = !is_window && drawable->info.bos.sType == VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
417
418 width = drawable->w;
419 height = drawable->h;
420
421 resized = (drawable->old_w != width ||
422 drawable->old_h != height);
423
424 /* Wait for glthread to finish because we can't use pipe_context from
425 * multiple threads.
426 */
427 _mesa_glthread_finish(ctx->st->ctx);
428
429 /* First get the buffers from the loader */
430 if (image) {
431 if (!dri_image_drawable_get_buffers(drawable, &images,
432 statts, statts_count))
433 return;
434 }
435
436 if (image) {
437 if (images.image_mask & __DRI_IMAGE_BUFFER_FRONT) {
438 struct pipe_resource **buf =
439 &drawable->textures[ST_ATTACHMENT_FRONT_LEFT];
440 struct pipe_resource *texture = images.front->texture;
441
442 drawable->w = texture->width0;
443 drawable->h = texture->height0;
444
445 pipe_resource_reference(buf, texture);
446 }
447
448 if (images.image_mask & __DRI_IMAGE_BUFFER_BACK) {
449 struct pipe_resource **buf =
450 &drawable->textures[ST_ATTACHMENT_BACK_LEFT];
451 struct pipe_resource *texture = images.back->texture;
452
453 drawable->w = texture->width0;
454 drawable->h = texture->height0;
455
456 pipe_resource_reference(buf, texture);
457 }
458
459 if (images.image_mask & __DRI_IMAGE_BUFFER_SHARED) {
460 struct pipe_resource **buf =
461 &drawable->textures[ST_ATTACHMENT_BACK_LEFT];
462 struct pipe_resource *texture = images.back->texture;
463
464 drawable->w = texture->width0;
465 drawable->h = texture->height0;
466
467 pipe_resource_reference(buf, texture);
468
469 ctx->is_shared_buffer_bound = true;
470 } else {
471 ctx->is_shared_buffer_bound = false;
472 }
473 } else {
474 /* remove outdated textures */
475 if (resized) {
476 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
477 if (drawable->textures[i] && i < ST_ATTACHMENT_DEPTH_STENCIL && !is_pixmap) {
478 drawable->textures[i]->width0 = width;
479 drawable->textures[i]->height0 = height;
480 /* force all contexts to revalidate framebuffer */
481 p_atomic_inc(&drawable->base.stamp);
482 } else
483 pipe_resource_reference(&drawable->textures[i], NULL);
484 pipe_resource_reference(&drawable->msaa_textures[i], NULL);
485 if (is_pixmap && i == ST_ATTACHMENT_FRONT_LEFT) {
486 FREE(drawable->image);
487 drawable->image = NULL;
488 }
489 }
490 }
491 }
492
493 drawable->old_w = width;
494 drawable->old_h = height;
495
496 memset(&templ, 0, sizeof(templ));
497 templ.target = screen->target;
498 templ.width0 = width;
499 templ.height0 = height;
500 templ.depth0 = 1;
501 templ.array_size = 1;
502 templ.last_level = 0;
503
504 #if 0
505 XXX do this once swapinterval is hooked up
506 /* pixmaps always have front buffers.
507 * Exchange swaps also mandate fake front buffers.
508 */
509 if (draw->type != LOADER_DRI3_DRAWABLE_WINDOW)
510 buffer_mask |= __DRI_IMAGE_BUFFER_FRONT;
511 #endif
512
513 uint32_t attachments = 0;
514 for (i = 0; i < statts_count; i++)
515 attachments |= BITFIELD_BIT(statts[i]);
516 bool front_only = attachments & ST_ATTACHMENT_FRONT_LEFT_MASK && !(attachments & ST_ATTACHMENT_BACK_LEFT_MASK);
517
518 for (i = 0; i < statts_count; i++) {
519 enum pipe_format format;
520 unsigned bind;
521
522 dri_drawable_get_format(drawable, statts[i], &format, &bind);
523 templ.format = format;
524
525 /* the texture already exists or not requested */
526 if (!drawable->textures[statts[i]]) {
527 if (statts[i] == ST_ATTACHMENT_BACK_LEFT ||
528 statts[i] == ST_ATTACHMENT_DEPTH_STENCIL ||
529 (statts[i] == ST_ATTACHMENT_FRONT_LEFT && front_only))
530 bind |= PIPE_BIND_DISPLAY_TARGET;
531
532 if (format == PIPE_FORMAT_NONE)
533 continue;
534
535 templ.bind = bind;
536 templ.nr_samples = 0;
537 templ.nr_storage_samples = 0;
538
539 if (statts[i] < ST_ATTACHMENT_DEPTH_STENCIL && is_window) {
540 void *data;
541 if (statts[i] == ST_ATTACHMENT_BACK_LEFT || (statts[i] == ST_ATTACHMENT_FRONT_LEFT && front_only))
542 data = &drawable->info;
543 else
544 data = drawable->textures[ST_ATTACHMENT_BACK_LEFT];
545 assert(data);
546 drawable->textures[statts[i]] =
547 screen->base.screen->resource_create_drawable(screen->base.screen, &templ, data);
548 }
549 #ifdef VK_USE_PLATFORM_XCB_KHR
550 else if (is_pixmap && statts[i] == ST_ATTACHMENT_FRONT_LEFT && !screen->is_sw) {
551 drawable->textures[statts[i]] = kopper_get_pixmap_buffer(drawable, format);
552 if (drawable->textures[statts[i]])
553 handle_in_fence(ctx, drawable->image);
554 }
555 #endif
556 if (!drawable->textures[statts[i]])
557 drawable->textures[statts[i]] =
558 screen->base.screen->resource_create(screen->base.screen, &templ);
559 }
560 if (drawable->stvis.samples > 1 && !drawable->msaa_textures[statts[i]]) {
561 templ.bind = bind &
562 ~(PIPE_BIND_SCANOUT | PIPE_BIND_SHARED | PIPE_BIND_DISPLAY_TARGET);
563 templ.nr_samples = drawable->stvis.samples;
564 templ.nr_storage_samples = drawable->stvis.samples;
565 drawable->msaa_textures[statts[i]] =
566 screen->base.screen->resource_create(screen->base.screen, &templ);
567
568 dri_pipe_blit(ctx->st->pipe,
569 drawable->msaa_textures[statts[i]],
570 drawable->textures[statts[i]]);
571 }
572 }
573 }
574
575 static inline void
get_drawable_info(struct dri_drawable * drawable,int * x,int * y,int * w,int * h)576 get_drawable_info(struct dri_drawable *drawable, int *x, int *y, int *w, int *h)
577 {
578 const __DRIswrastLoaderExtension *loader = drawable->screen->swrast_loader;
579
580 if (loader)
581 loader->getDrawableInfo(opaque_dri_drawable(drawable),
582 x, y, w, h,
583 drawable->loaderPrivate);
584 }
585
586 static void
kopper_update_drawable_info(struct dri_drawable * drawable)587 kopper_update_drawable_info(struct dri_drawable *drawable)
588 {
589 struct dri_screen *screen = drawable->screen;
590 bool is_window = drawable->info.bos.sType != 0;
591 int x, y;
592 struct pipe_screen *pscreen = screen->unwrapped_screen;
593 struct pipe_resource *ptex = drawable->textures[ST_ATTACHMENT_BACK_LEFT] ?
594 drawable->textures[ST_ATTACHMENT_BACK_LEFT] :
595 drawable->textures[ST_ATTACHMENT_FRONT_LEFT];
596
597 bool do_kopper_update = is_window && ptex && screen->fd == -1;
598 if (drawable->info.bos.sType == VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR && do_kopper_update)
599 zink_kopper_update(pscreen, ptex, &drawable->w, &drawable->h);
600 else
601 get_drawable_info(drawable, &x, &y, &drawable->w, &drawable->h);
602 }
603
604 static inline void
kopper_present_texture(struct pipe_context * pipe,struct dri_drawable * drawable,struct pipe_resource * ptex,struct pipe_box * sub_box)605 kopper_present_texture(struct pipe_context *pipe, struct dri_drawable *drawable,
606 struct pipe_resource *ptex, struct pipe_box *sub_box)
607 {
608 struct dri_screen *screen = drawable->screen;
609
610 screen->base.screen->flush_frontbuffer(screen->base.screen, pipe, ptex, 0, 0, drawable, sub_box);
611 }
612
613 static inline void
kopper_copy_to_front(struct pipe_context * pipe,struct dri_drawable * drawable,struct pipe_resource * ptex)614 kopper_copy_to_front(struct pipe_context *pipe,
615 struct dri_drawable *drawable,
616 struct pipe_resource *ptex)
617 {
618 kopper_present_texture(pipe, drawable, ptex, NULL);
619
620 kopper_invalidate_drawable(opaque_dri_drawable(drawable));
621 }
622
623 static bool
kopper_flush_frontbuffer(struct dri_context * ctx,struct dri_drawable * drawable,enum st_attachment_type statt)624 kopper_flush_frontbuffer(struct dri_context *ctx,
625 struct dri_drawable *drawable,
626 enum st_attachment_type statt)
627 {
628 struct pipe_resource *ptex;
629
630 if (!ctx || statt != ST_ATTACHMENT_FRONT_LEFT)
631 return false;
632
633 /* Wait for glthread to finish because we can't use pipe_context from
634 * multiple threads.
635 */
636 _mesa_glthread_finish(ctx->st->ctx);
637
638 if (drawable) {
639 /* prevent recursion */
640 if (drawable->flushing)
641 return true;
642
643 drawable->flushing = true;
644 }
645
646 if (drawable->stvis.samples > 1) {
647 /* Resolve the front buffer. */
648 dri_pipe_blit(ctx->st->pipe,
649 drawable->textures[ST_ATTACHMENT_FRONT_LEFT],
650 drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT]);
651 }
652 ptex = drawable->textures[statt];
653
654 if (ptex) {
655 ctx->st->pipe->flush_resource(ctx->st->pipe, drawable->textures[ST_ATTACHMENT_FRONT_LEFT]);
656 struct pipe_screen *screen = drawable->screen->base.screen;
657 struct st_context *st;
658 struct pipe_fence_handle *new_fence = NULL;
659
660 st = ctx->st;
661
662 st_context_flush(st, ST_FLUSH_FRONT, &new_fence, NULL, NULL);
663 if (drawable) {
664 drawable->flushing = false;
665 }
666 /* throttle on the previous fence */
667 if (drawable->throttle_fence) {
668 screen->fence_finish(screen, NULL, drawable->throttle_fence, OS_TIMEOUT_INFINITE);
669 screen->fence_reference(screen, &drawable->throttle_fence, NULL);
670 }
671 drawable->throttle_fence = new_fence;
672 kopper_copy_to_front(st->pipe, ctx->draw, ptex);
673 }
674
675 return true;
676 }
677
678 static inline void
get_image(struct dri_drawable * drawable,int x,int y,int width,int height,void * data)679 get_image(struct dri_drawable *drawable, int x, int y, int width, int height, void *data)
680 {
681 const __DRIswrastLoaderExtension *loader = drawable->screen->swrast_loader;
682
683 loader->getImage(opaque_dri_drawable(drawable),
684 x, y, width, height,
685 data, drawable->loaderPrivate);
686 }
687
688 static inline bool
get_image_shm(struct dri_drawable * drawable,int x,int y,int width,int height,struct pipe_resource * res)689 get_image_shm(struct dri_drawable *drawable, int x, int y, int width, int height,
690 struct pipe_resource *res)
691 {
692 const __DRIswrastLoaderExtension *loader = drawable->screen->swrast_loader;
693 struct winsys_handle whandle;
694
695 whandle.type = WINSYS_HANDLE_TYPE_SHMID;
696
697 if (loader->base.version < 4 || !loader->getImageShm)
698 return false;
699
700 if (!res->screen->resource_get_handle(res->screen, NULL, res, &whandle, PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE))
701 return false;
702
703 if (loader->base.version > 5 && loader->getImageShm2)
704 return loader->getImageShm2(opaque_dri_drawable(drawable), x, y, width, height, whandle.handle, drawable->loaderPrivate);
705
706 loader->getImageShm(opaque_dri_drawable(drawable), x, y, width, height, whandle.handle, drawable->loaderPrivate);
707 return true;
708 }
709
710 static void
kopper_update_tex_buffer(struct dri_drawable * drawable,struct dri_context * ctx,struct pipe_resource * res)711 kopper_update_tex_buffer(struct dri_drawable *drawable,
712 struct dri_context *ctx,
713 struct pipe_resource *res)
714 {
715 struct dri_screen *screen = drawable->screen;
716 struct st_context *st_ctx = (struct st_context *)ctx->st;
717 struct pipe_context *pipe = st_ctx->pipe;
718 struct pipe_transfer *transfer;
719 char *map;
720 int x, y, w, h;
721 int ximage_stride, line;
722 if (screen->has_dmabuf || drawable->is_window || drawable->info.bos.sType != VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR)
723 return;
724 int cpp = util_format_get_blocksize(res->format);
725
726 /* Wait for glthread to finish because we can't use pipe_context from
727 * multiple threads.
728 */
729 _mesa_glthread_finish(ctx->st->ctx);
730
731 get_drawable_info(drawable, &x, &y, &w, &h);
732
733 map = pipe_texture_map(pipe, res,
734 0, 0, // level, layer,
735 PIPE_MAP_WRITE,
736 x, y, w, h, &transfer);
737
738 /* Copy the Drawable content to the mapped texture buffer */
739 if (!get_image_shm(drawable, x, y, w, h, res))
740 get_image(drawable, x, y, w, h, map);
741
742 /* The pipe transfer has a pitch rounded up to the nearest 64 pixels.
743 get_image() has a pitch rounded up to 4 bytes. */
744 ximage_stride = ((w * cpp) + 3) & -4;
745 for (line = h-1; line; --line) {
746 memmove(&map[line * transfer->stride],
747 &map[line * ximage_stride],
748 ximage_stride);
749 }
750
751 pipe_texture_unmap(pipe, transfer);
752 }
753
754 static void
kopper_flush_swapbuffers(struct dri_context * ctx,struct dri_drawable * drawable)755 kopper_flush_swapbuffers(struct dri_context *ctx,
756 struct dri_drawable *drawable)
757 {
758 /* does this actually need to do anything? */
759 }
760
761 static void
762 kopper_swap_buffers(struct dri_drawable *drawable);
763
764 static struct dri_drawable *
kopper_create_drawable(struct dri_screen * screen,const struct gl_config * visual,bool isPixmap,void * loaderPrivate)765 kopper_create_drawable(struct dri_screen *screen, const struct gl_config *visual,
766 bool isPixmap, void *loaderPrivate)
767 {
768 /* always pass !pixmap because it isn't "handled" or relevant */
769 struct dri_drawable *drawable = dri_create_drawable(screen, visual, false,
770 loaderPrivate);
771 if (!drawable)
772 return NULL;
773
774 // relocate references to the old struct
775 drawable->base.visual = &drawable->stvis;
776
777 // and fill in the vtable
778 drawable->allocate_textures = kopper_allocate_textures;
779 drawable->update_drawable_info = kopper_update_drawable_info;
780 drawable->flush_frontbuffer = kopper_flush_frontbuffer;
781 drawable->update_tex_buffer = kopper_update_tex_buffer;
782 drawable->flush_swapbuffers = kopper_flush_swapbuffers;
783 drawable->swap_buffers = kopper_swap_buffers;
784
785 drawable->info.has_alpha = visual->alphaBits > 0;
786 if (screen->kopper_loader->SetSurfaceCreateInfo)
787 screen->kopper_loader->SetSurfaceCreateInfo(drawable->loaderPrivate,
788 &drawable->info);
789 drawable->is_window = !isPixmap && drawable->info.bos.sType != 0;
790
791 return drawable;
792 }
793
794 static int64_t
kopperSwapBuffers(__DRIdrawable * dPriv,uint32_t flush_flags)795 kopperSwapBuffers(__DRIdrawable *dPriv, uint32_t flush_flags)
796 {
797 struct dri_drawable *drawable = dri_drawable(dPriv);
798 struct dri_context *ctx = dri_get_current();
799 struct pipe_resource *ptex;
800
801 if (!ctx)
802 return 0;
803
804 ptex = drawable->textures[ST_ATTACHMENT_BACK_LEFT];
805 if (!ptex)
806 return 0;
807
808 /* ensure invalidation is applied before renderpass ends */
809 if (flush_flags & __DRI2_FLUSH_INVALIDATE_ANCILLARY)
810 _mesa_glthread_invalidate_zsbuf(ctx->st->ctx);
811
812 /* Wait for glthread to finish because we can't use pipe_context from
813 * multiple threads.
814 */
815 _mesa_glthread_finish(ctx->st->ctx);
816
817 drawable->texture_stamp = drawable->lastStamp - 1;
818
819 dri_flush(opaque_dri_context(ctx), opaque_dri_drawable(drawable),
820 __DRI2_FLUSH_DRAWABLE | __DRI2_FLUSH_CONTEXT | flush_flags,
821 __DRI2_THROTTLE_SWAPBUFFER);
822
823 kopper_copy_to_front(ctx->st->pipe, drawable, ptex);
824 if (drawable->is_window && !zink_kopper_check(ptex))
825 return -1;
826 if (!drawable->textures[ST_ATTACHMENT_FRONT_LEFT]) {
827 return 0;
828 }
829
830 /* have to manually swap the pointers here to make frontbuffer readback work */
831 drawable->textures[ST_ATTACHMENT_BACK_LEFT] = drawable->textures[ST_ATTACHMENT_FRONT_LEFT];
832 drawable->textures[ST_ATTACHMENT_FRONT_LEFT] = ptex;
833
834 return 0;
835 }
836
837 static void
kopper_swap_buffers(struct dri_drawable * drawable)838 kopper_swap_buffers(struct dri_drawable *drawable)
839 {
840 kopperSwapBuffers(opaque_dri_drawable(drawable), 0);
841 }
842
843 static __DRIdrawable *
kopperCreateNewDrawable(__DRIscreen * psp,const __DRIconfig * config,void * data,__DRIkopperDrawableInfo * info)844 kopperCreateNewDrawable(__DRIscreen *psp,
845 const __DRIconfig *config,
846 void *data,
847 __DRIkopperDrawableInfo *info)
848 {
849 assert(data != NULL);
850
851 struct dri_screen *screen = dri_screen(psp);
852 struct dri_drawable *drawable =
853 screen->create_drawable(screen, &config->modes, info->is_pixmap, data);
854 if (drawable)
855 drawable->has_modifiers = screen->has_modifiers && info->multiplanes_available;
856
857 return opaque_dri_drawable(drawable);
858 }
859
860 static void
kopperSetSwapInterval(__DRIdrawable * dPriv,int interval)861 kopperSetSwapInterval(__DRIdrawable *dPriv, int interval)
862 {
863 struct dri_drawable *drawable = dri_drawable(dPriv);
864 struct dri_screen *screen = drawable->screen;
865 struct pipe_screen *pscreen = screen->unwrapped_screen;
866 struct pipe_resource *ptex = drawable->textures[ST_ATTACHMENT_BACK_LEFT] ?
867 drawable->textures[ST_ATTACHMENT_BACK_LEFT] :
868 drawable->textures[ST_ATTACHMENT_FRONT_LEFT];
869
870 /* the conditional is because we can be called before buffer allocation. If
871 * we're before allocation, then the initial_swap_interval will be used when
872 * the swapchain is eventually created.
873 */
874 if (ptex)
875 zink_kopper_set_swap_interval(pscreen, ptex, interval);
876 drawable->info.initial_swap_interval = interval;
877 }
878
879 static int
kopperQueryBufferAge(__DRIdrawable * dPriv)880 kopperQueryBufferAge(__DRIdrawable *dPriv)
881 {
882 struct dri_drawable *drawable = dri_drawable(dPriv);
883 struct dri_context *ctx = dri_get_current();
884 struct pipe_resource *ptex = drawable->textures[ST_ATTACHMENT_BACK_LEFT] ?
885 drawable->textures[ST_ATTACHMENT_BACK_LEFT] :
886 drawable->textures[ST_ATTACHMENT_FRONT_LEFT];
887
888 /* Wait for glthread to finish because we can't use pipe_context from
889 * multiple threads.
890 */
891 _mesa_glthread_finish(ctx->st->ctx);
892
893 return zink_kopper_query_buffer_age(ctx->st->pipe, ptex);
894 }
895
896 const __DRIkopperExtension driKopperExtension = {
897 .base = { __DRI_KOPPER, 1 },
898 .createNewDrawable = kopperCreateNewDrawable,
899 .swapBuffers = kopperSwapBuffers,
900 .setSwapInterval = kopperSetSwapInterval,
901 .queryBufferAge = kopperQueryBufferAge,
902 };
903
904 static const struct __DRImesaCoreExtensionRec mesaCoreExtension = {
905 .base = { __DRI_MESA, 1 },
906 .version_string = MESA_INTERFACE_VERSION_STRING,
907 .createNewScreen = driCreateNewScreen2,
908 .createContext = driCreateContextAttribs,
909 .initScreen = kopper_init_screen,
910 };
911
912 const __DRIextension *galliumvk_driver_extensions[] = {
913 &driCoreExtension.base,
914 &mesaCoreExtension.base,
915 &driSWRastExtension.base,
916 &driDRI2Extension.base,
917 &driImageDriverExtension.base,
918 &driKopperExtension.base,
919 &gallium_config_options.base,
920 NULL
921 };
922
923 /* vim: set sw=3 ts=8 sts=3 expandtab: */
924