• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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