• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2020 Red Hat, Inc.
3  * Copyright © 2021 Valve Corporation
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  */
24 
25 #include "util/detect_os.h"
26 #include "driver_trace/tr_screen.h"
27 
28 #include "zink_context.h"
29 #include "zink_screen.h"
30 #include "zink_surface.h"
31 #include "zink_resource.h"
32 #include "zink_kopper.h"
33 
34 static void
zink_kopper_set_present_mode_for_interval(struct kopper_displaytarget * cdt,int interval)35 zink_kopper_set_present_mode_for_interval(struct kopper_displaytarget *cdt, int interval)
36 {
37 #if DETECT_OS_WINDOWS
38     // not hooked up yet so let's not sabotage benchmarks
39     cdt->present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR;
40 #else
41    assert(interval >= 0); /* TODO: VK_PRESENT_MODE_FIFO_RELAXED_KHR */
42    if (interval == 0) {
43       if (cdt->present_modes & BITFIELD_BIT(VK_PRESENT_MODE_IMMEDIATE_KHR))
44          cdt->present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR;
45       else
46          cdt->present_mode = VK_PRESENT_MODE_MAILBOX_KHR;
47    } else if (interval > 0) {
48       cdt->present_mode = VK_PRESENT_MODE_FIFO_KHR;
49    }
50    assert(cdt->present_modes & BITFIELD_BIT(cdt->present_mode));
51 #endif
52 }
53 
54 static void
init_dt_type(struct kopper_displaytarget * cdt)55 init_dt_type(struct kopper_displaytarget *cdt)
56 {
57    VkStructureType type = cdt->info.bos.sType;
58    switch (type) {
59 #ifdef VK_USE_PLATFORM_XCB_KHR
60    case VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR:
61       cdt->type = KOPPER_X11;
62       break;
63 #endif
64 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
65    case VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR:
66       cdt->type = KOPPER_WAYLAND;
67       break;
68 #endif
69 #ifdef VK_USE_PLATFORM_WIN32_KHR
70    case VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR:
71       cdt->type = KOPPER_WIN32;
72       break;
73 #endif
74    default:
75       unreachable("unsupported!");
76    }
77 }
78 
79 static VkSurfaceKHR
kopper_CreateSurface(struct zink_screen * screen,struct kopper_displaytarget * cdt)80 kopper_CreateSurface(struct zink_screen *screen, struct kopper_displaytarget *cdt)
81 {
82    VkSurfaceKHR surface = VK_NULL_HANDLE;
83    VkResult error = VK_SUCCESS;
84 
85    init_dt_type(cdt);
86    VkStructureType type = cdt->info.bos.sType;
87    switch (type) {
88 #ifdef VK_USE_PLATFORM_XCB_KHR
89    case VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR: {
90       VkXcbSurfaceCreateInfoKHR *xcb = (VkXcbSurfaceCreateInfoKHR *)&cdt->info.bos;
91       error = VKSCR(CreateXcbSurfaceKHR)(screen->instance, xcb, NULL, &surface);
92       break;
93    }
94 #endif
95 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
96    case VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR: {
97       VkWaylandSurfaceCreateInfoKHR *wlsci = (VkWaylandSurfaceCreateInfoKHR *)&cdt->info.bos;
98       error = VKSCR(CreateWaylandSurfaceKHR)(screen->instance, wlsci, NULL, &surface);
99       break;
100    }
101 #endif
102 #ifdef VK_USE_PLATFORM_WIN32_KHR
103    case VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR: {
104       VkWin32SurfaceCreateInfoKHR *win32 = (VkWin32SurfaceCreateInfoKHR *)&cdt->info.bos;
105       error = VKSCR(CreateWin32SurfaceKHR)(screen->instance, win32, NULL, &surface);
106       break;
107    }
108 #endif
109    default:
110       unreachable("unsupported!");
111    }
112    if (error != VK_SUCCESS) {
113       return VK_NULL_HANDLE;
114    }
115 
116    VkBool32 supported;
117    error = VKSCR(GetPhysicalDeviceSurfaceSupportKHR)(screen->pdev, screen->gfx_queue, surface, &supported);
118    if (!zink_screen_handle_vkresult(screen, error) || !supported)
119       goto fail;
120 
121    unsigned count = 10;
122    VkPresentModeKHR modes[10];
123    error = VKSCR(GetPhysicalDeviceSurfacePresentModesKHR)(screen->pdev, surface, &count, modes);
124    if (!zink_screen_handle_vkresult(screen, error))
125       goto fail;
126 
127    for (unsigned i = 0; i < count; i++) {
128       /* VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR and VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR
129       * are not handled
130       */
131       assert(modes[i] <= VK_PRESENT_MODE_FIFO_RELAXED_KHR);
132       if (modes[i] <= VK_PRESENT_MODE_FIFO_RELAXED_KHR)
133          cdt->present_modes |= BITFIELD_BIT(modes[i]);
134    }
135 
136    zink_kopper_set_present_mode_for_interval(cdt, cdt->info.initial_swap_interval);
137 
138    return surface;
139 fail:
140    VKSCR(DestroySurfaceKHR)(screen->instance, surface, NULL);
141    return VK_NULL_HANDLE;
142 }
143 
144 static void
destroy_swapchain(struct zink_screen * screen,struct kopper_swapchain * cswap)145 destroy_swapchain(struct zink_screen *screen, struct kopper_swapchain *cswap)
146 {
147    if (!cswap)
148       return;
149    util_queue_fence_destroy(&cswap->present_fence);
150    for (unsigned i = 0; i < cswap->num_images; i++) {
151       simple_mtx_lock(&screen->semaphores_lock);
152       util_dynarray_append(&screen->semaphores, VkSemaphore, cswap->images[i].acquire);
153       simple_mtx_unlock(&screen->semaphores_lock);
154       pipe_resource_reference(&cswap->images[i].readback, NULL);
155    }
156    free(cswap->images);
157    hash_table_foreach(cswap->presents, he) {
158       struct util_dynarray *arr = he->data;
159       simple_mtx_lock(&screen->semaphores_lock);
160       util_dynarray_append_dynarray(&screen->semaphores, arr);
161       simple_mtx_unlock(&screen->semaphores_lock);
162       util_dynarray_fini(arr);
163       free(arr);
164    }
165    _mesa_hash_table_destroy(cswap->presents, NULL);
166    VKSCR(DestroySwapchainKHR)(screen->dev, cswap->swapchain, NULL);
167    free(cswap);
168 }
169 
170 static void
prune_old_swapchains(struct zink_screen * screen,struct kopper_displaytarget * cdt,bool wait)171 prune_old_swapchains(struct zink_screen *screen, struct kopper_displaytarget *cdt, bool wait)
172 {
173    while (cdt->old_swapchain) {
174       struct kopper_swapchain *cswap = cdt->old_swapchain;
175       if (cswap->async_presents) {
176          if (wait)
177             continue;
178          return;
179       }
180       struct zink_batch_usage *u = cswap->batch_uses;
181       if (!zink_screen_usage_check_completion(screen, u)) {
182          /* these can't ever be pruned */
183          if (!wait || zink_batch_usage_is_unflushed(u))
184             return;
185 
186          zink_screen_timeline_wait(screen, u->usage, UINT64_MAX);
187          cswap->batch_uses = NULL;
188       }
189       cdt->old_swapchain = cswap->next;
190       destroy_swapchain(screen, cswap);
191    }
192 }
193 
194 static struct hash_entry *
find_dt_entry(struct zink_screen * screen,const struct kopper_displaytarget * cdt)195 find_dt_entry(struct zink_screen *screen, const struct kopper_displaytarget *cdt)
196 {
197    struct hash_entry *he = NULL;
198    switch (cdt->type) {
199 #ifdef VK_USE_PLATFORM_XCB_KHR
200    case KOPPER_X11: {
201       VkXcbSurfaceCreateInfoKHR *xcb = (VkXcbSurfaceCreateInfoKHR *)&cdt->info.bos;
202       he = _mesa_hash_table_search_pre_hashed(&screen->dts, xcb->window, (void*)(uintptr_t)xcb->window);
203       break;
204    }
205 #endif
206 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
207    case KOPPER_WAYLAND: {
208       VkWaylandSurfaceCreateInfoKHR *wlsci = (VkWaylandSurfaceCreateInfoKHR *)&cdt->info.bos;
209       he = _mesa_hash_table_search(&screen->dts, wlsci->surface);
210       break;
211    }
212 #endif
213 #ifdef VK_USE_PLATFORM_WIN32_KHR
214    case KOPPER_WIN32: {
215       VkWin32SurfaceCreateInfoKHR *win32 = (VkWin32SurfaceCreateInfoKHR *)&cdt->info.bos;
216       he = _mesa_hash_table_search(&screen->dts, win32->hwnd);
217       break;
218    }
219 #endif
220    default:
221       unreachable("unsupported!");
222    }
223    return he;
224 }
225 
226 void
zink_kopper_deinit_displaytarget(struct zink_screen * screen,struct kopper_displaytarget * cdt)227 zink_kopper_deinit_displaytarget(struct zink_screen *screen, struct kopper_displaytarget *cdt)
228 {
229    if (!cdt->surface)
230       return;
231    simple_mtx_lock(&screen->dt_lock);
232    struct hash_entry *he = find_dt_entry(screen, cdt);
233    assert(he);
234    /* this deinits the registered entry, which should always be the "right" entry */
235    cdt = he->data;
236    _mesa_hash_table_remove(&screen->dts, he);
237    simple_mtx_unlock(&screen->dt_lock);
238    destroy_swapchain(screen, cdt->swapchain);
239    prune_old_swapchains(screen, cdt, true);
240    VKSCR(DestroySurfaceKHR)(screen->instance, cdt->surface, NULL);
241    cdt->swapchain = cdt->old_swapchain = NULL;
242    cdt->surface = VK_NULL_HANDLE;
243 }
244 
245 static struct kopper_swapchain *
kopper_CreateSwapchain(struct zink_screen * screen,struct kopper_displaytarget * cdt,unsigned w,unsigned h,VkResult * result)246 kopper_CreateSwapchain(struct zink_screen *screen, struct kopper_displaytarget *cdt, unsigned w, unsigned h, VkResult *result)
247 {
248    VkResult error = VK_SUCCESS;
249    struct kopper_swapchain *cswap = CALLOC_STRUCT(kopper_swapchain);
250    if (!cswap) {
251       *result = VK_ERROR_OUT_OF_HOST_MEMORY;
252       return NULL;
253    }
254    cswap->last_present_prune = 1;
255    util_queue_fence_init(&cswap->present_fence);
256 
257    bool has_alpha = cdt->info.has_alpha && (cdt->caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR);
258    if (cdt->swapchain) {
259       cswap->scci = cdt->swapchain->scci;
260       /* avoid UAF if async present needs to-be-retired swapchain */
261       if (cdt->type == KOPPER_WAYLAND && cdt->swapchain->swapchain)
262          util_queue_fence_wait(&cdt->swapchain->present_fence);
263       cswap->scci.oldSwapchain = cdt->swapchain->swapchain;
264    } else {
265       cswap->scci.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
266       cswap->scci.pNext = NULL;
267       cswap->scci.surface = cdt->surface;
268       cswap->scci.flags = zink_kopper_has_srgb(cdt) ? VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR : 0;
269       cswap->scci.imageFormat = cdt->formats[0];
270       cswap->scci.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
271       // TODO: This is where you'd hook up stereo
272       cswap->scci.imageArrayLayers = 1;
273       cswap->scci.imageUsage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
274                                VK_IMAGE_USAGE_SAMPLED_BIT |
275                                VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
276                                VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
277       if (cdt->caps.supportedUsageFlags & VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT)
278          cswap->scci.imageUsage |= VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT;
279       cswap->scci.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
280       cswap->scci.queueFamilyIndexCount = 0;
281       cswap->scci.pQueueFamilyIndices = NULL;
282       cswap->scci.compositeAlpha = has_alpha ? VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
283       cswap->scci.clipped = VK_TRUE;
284    }
285    cswap->scci.presentMode = cdt->present_mode;
286    cswap->scci.minImageCount = cdt->caps.minImageCount;
287    cswap->scci.preTransform = cdt->caps.currentTransform;
288    if (cdt->formats[1])
289       cswap->scci.pNext = &cdt->format_list;
290 
291    /* different display platforms have, by vulkan spec, different sizing methodologies */
292    switch (cdt->type) {
293    case KOPPER_X11:
294    case KOPPER_WIN32:
295       /* With Xcb, minImageExtent, maxImageExtent, and currentExtent must always equal the window size.
296        * ...
297        * Due to above restrictions, it is only possible to create a new swapchain on this
298        * platform with imageExtent being equal to the current size of the window.
299        */
300       cswap->scci.imageExtent.width = cdt->caps.currentExtent.width;
301       cswap->scci.imageExtent.height = cdt->caps.currentExtent.height;
302       break;
303    case KOPPER_WAYLAND:
304       /* On Wayland, currentExtent is the special value (0xFFFFFFFF, 0xFFFFFFFF), indicating that the
305        * surface size will be determined by the extent of a swapchain targeting the surface. Whatever the
306        * application sets a swapchain’s imageExtent to will be the size of the window, after the first image is
307        * presented.
308        */
309       cswap->scci.imageExtent.width = w;
310       cswap->scci.imageExtent.height = h;
311       break;
312    default:
313       unreachable("unknown display platform");
314    }
315 
316    error = VKSCR(CreateSwapchainKHR)(screen->dev, &cswap->scci, NULL,
317                                 &cswap->swapchain);
318    if (error == VK_ERROR_NATIVE_WINDOW_IN_USE_KHR) {
319       if (util_queue_is_initialized(&screen->flush_queue))
320          util_queue_finish(&screen->flush_queue);
321       simple_mtx_lock(&screen->queue_lock);
322       VkResult wait_result = VKSCR(QueueWaitIdle)(screen->queue);
323       simple_mtx_unlock(&screen->queue_lock);
324       if (wait_result != VK_SUCCESS)
325          mesa_loge("ZINK: vkQueueWaitIdle failed (%s)", vk_Result_to_str(wait_result));
326       error = VKSCR(CreateSwapchainKHR)(screen->dev, &cswap->scci, NULL,
327                                    &cswap->swapchain);
328    }
329    if (error != VK_SUCCESS) {
330        mesa_loge("CreateSwapchainKHR failed with %s\n", vk_Result_to_str(error));
331        free(cswap);
332        *result = error;
333        return NULL;
334    }
335    cswap->last_present = UINT32_MAX;
336 
337    *result = VK_SUCCESS;
338    return cswap;
339 }
340 
341 static VkResult
kopper_GetSwapchainImages(struct zink_screen * screen,struct kopper_swapchain * cswap)342 kopper_GetSwapchainImages(struct zink_screen *screen, struct kopper_swapchain *cswap)
343 {
344    VkResult error = VKSCR(GetSwapchainImagesKHR)(screen->dev, cswap->swapchain, &cswap->num_images, NULL);
345    zink_screen_handle_vkresult(screen, error);
346    if (error != VK_SUCCESS)
347       return error;
348    cswap->images = calloc(cswap->num_images, sizeof(struct kopper_swapchain_image));
349    if (!cswap->images) {
350       mesa_loge("ZINK: failed to allocate cswap->images!");
351       return VK_ERROR_OUT_OF_HOST_MEMORY;
352    }
353    cswap->presents = _mesa_hash_table_create_u32_keys(NULL);
354    VkImage images[32];
355    error = VKSCR(GetSwapchainImagesKHR)(screen->dev, cswap->swapchain, &cswap->num_images, images);
356    assert(cswap->num_images <= ARRAY_SIZE(images));
357    if (zink_screen_handle_vkresult(screen, error)) {
358       for (unsigned i = 0; i < cswap->num_images; i++)
359          cswap->images[i].image = images[i];
360    }
361    cswap->max_acquires = cswap->num_images - cswap->scci.minImageCount + 1;
362    return error;
363 }
364 
365 static VkResult
update_caps(struct zink_screen * screen,struct kopper_displaytarget * cdt)366 update_caps(struct zink_screen *screen, struct kopper_displaytarget *cdt)
367 {
368    VkResult error = VKSCR(GetPhysicalDeviceSurfaceCapabilitiesKHR)(screen->pdev, cdt->surface, &cdt->caps);
369    zink_screen_handle_vkresult(screen, error);
370    return error;
371 }
372 
373 static VkResult
update_swapchain(struct zink_screen * screen,struct kopper_displaytarget * cdt,unsigned w,unsigned h)374 update_swapchain(struct zink_screen *screen, struct kopper_displaytarget *cdt, unsigned w, unsigned h)
375 {
376    VkResult error = update_caps(screen, cdt);
377    if (error != VK_SUCCESS)
378       return error;
379    struct kopper_swapchain *cswap = kopper_CreateSwapchain(screen, cdt, w, h, &error);
380    if (!cswap)
381       return error;
382    prune_old_swapchains(screen, cdt, false);
383    struct kopper_swapchain **pswap = &cdt->old_swapchain;
384    while (*pswap)
385       *pswap = (*pswap)->next;
386    *pswap = cdt->swapchain;
387    cdt->swapchain = cswap;
388 
389    return kopper_GetSwapchainImages(screen, cdt->swapchain);
390 }
391 
392 struct kopper_displaytarget *
zink_kopper_displaytarget_create(struct zink_screen * screen,unsigned tex_usage,enum pipe_format format,unsigned width,unsigned height,unsigned alignment,const void * loader_private,unsigned * stride)393 zink_kopper_displaytarget_create(struct zink_screen *screen, unsigned tex_usage,
394                                  enum pipe_format format, unsigned width,
395                                  unsigned height, unsigned alignment,
396                                  const void *loader_private, unsigned *stride)
397 {
398    struct kopper_displaytarget *cdt;
399    const struct kopper_loader_info *info = loader_private;
400 
401    {
402       struct kopper_displaytarget k;
403       struct hash_entry *he = NULL;
404       k.info = *info;
405       init_dt_type(&k);
406       simple_mtx_lock(&screen->dt_lock);
407       if (unlikely(!screen->dts.table)) {
408          switch (k.type) {
409          case KOPPER_X11:
410             _mesa_hash_table_init(&screen->dts, screen, NULL, _mesa_key_pointer_equal);
411             break;
412          case KOPPER_WAYLAND:
413          case KOPPER_WIN32:
414             _mesa_hash_table_init(&screen->dts, screen, _mesa_hash_pointer, _mesa_key_pointer_equal);
415             break;
416          default:
417             unreachable("unknown kopper type");
418          }
419       } else {
420          he = find_dt_entry(screen, &k);
421       }
422       simple_mtx_unlock(&screen->dt_lock);
423       if (he) {
424          cdt = he->data;
425          p_atomic_inc(&cdt->refcount);
426          *stride = cdt->stride;
427          return cdt;
428       }
429    }
430 
431    cdt = CALLOC_STRUCT(kopper_displaytarget);
432    if (!cdt)
433       return NULL;
434 
435    cdt->refcount = 1;
436    cdt->loader_private = (void*)loader_private;
437    cdt->info = *info;
438 
439    enum pipe_format srgb = PIPE_FORMAT_NONE;
440    if (screen->info.have_KHR_swapchain_mutable_format) {
441       srgb = util_format_is_srgb(format) ? util_format_linear(format) : util_format_srgb(format);
442       /* why do these helpers have different default return values? */
443       if (srgb == format)
444          srgb = PIPE_FORMAT_NONE;
445    }
446    cdt->formats[0] = zink_get_format(screen, format);
447    if (srgb) {
448       cdt->format_list.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO;
449       cdt->format_list.pNext = NULL;
450       cdt->format_list.viewFormatCount = 2;
451       cdt->format_list.pViewFormats = cdt->formats;
452 
453       cdt->formats[1] = zink_get_format(screen, srgb);
454    }
455 
456    cdt->surface = kopper_CreateSurface(screen, cdt);
457    if (!cdt->surface)
458       goto out;
459 
460    if (update_swapchain(screen, cdt, width, height) != VK_SUCCESS)
461       goto out;
462 
463    simple_mtx_lock(&screen->dt_lock);
464    switch (cdt->type) {
465 #ifdef VK_USE_PLATFORM_XCB_KHR
466    case KOPPER_X11: {
467       VkXcbSurfaceCreateInfoKHR *xcb = (VkXcbSurfaceCreateInfoKHR *)&cdt->info.bos;
468       _mesa_hash_table_insert_pre_hashed(&screen->dts, xcb->window, (void*)(uintptr_t)xcb->window, cdt);
469       break;
470    }
471 #endif
472 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
473    case KOPPER_WAYLAND: {
474       VkWaylandSurfaceCreateInfoKHR *wlsci = (VkWaylandSurfaceCreateInfoKHR *)&cdt->info.bos;
475       _mesa_hash_table_insert(&screen->dts, wlsci->surface, cdt);
476       break;
477    }
478 #endif
479 #ifdef VK_USE_PLATFORM_WIN32_KHR
480    case KOPPER_WIN32: {
481       VkWin32SurfaceCreateInfoKHR *win32 = (VkWin32SurfaceCreateInfoKHR *)&cdt->info.bos;
482       _mesa_hash_table_insert(&screen->dts, win32->hwnd, cdt);
483       break;
484    }
485 #endif
486    default:
487       unreachable("unsupported!");
488    }
489    simple_mtx_unlock(&screen->dt_lock);
490 
491    *stride = cdt->stride;
492    return cdt;
493 
494 //moar cleanup
495 out:
496    FREE(cdt);
497    return NULL;
498 }
499 
500 void
zink_kopper_displaytarget_destroy(struct zink_screen * screen,struct kopper_displaytarget * cdt)501 zink_kopper_displaytarget_destroy(struct zink_screen *screen, struct kopper_displaytarget *cdt)
502 {
503    if (!p_atomic_dec_zero(&cdt->refcount))
504       return;
505    zink_kopper_deinit_displaytarget(screen, cdt);
506    FREE(cdt);
507 }
508 
509 static VkResult
kopper_acquire(struct zink_screen * screen,struct zink_resource * res,uint64_t timeout)510 kopper_acquire(struct zink_screen *screen, struct zink_resource *res, uint64_t timeout)
511 {
512    struct kopper_displaytarget *cdt = res->obj->dt;
513 
514    /* if:
515     * - we don't need a new image
516     * - we have a swapchain image
517     * - that image is either acquired or acquiring
518     *
519     * then this is a no-op
520     */
521    if (!res->obj->new_dt && res->obj->dt_idx != UINT32_MAX &&
522        (cdt->swapchain->images[res->obj->dt_idx].acquire || cdt->swapchain->images[res->obj->dt_idx].acquired))
523       return VK_SUCCESS;
524    VkSemaphore acquire = VK_NULL_HANDLE;
525 
526    while (true) {
527       if (res->obj->new_dt) {
528          VkResult error = update_swapchain(screen, cdt, res->base.b.width0, res->base.b.height0);
529          zink_screen_handle_vkresult(screen, error);
530          if (error != VK_SUCCESS)
531             return error;
532          res->obj->new_dt = false;
533          res->layout = VK_IMAGE_LAYOUT_UNDEFINED;
534          res->obj->access = 0;
535          res->obj->access_stage = 0;
536       }
537       if (timeout == UINT64_MAX && util_queue_is_initialized(&screen->flush_queue) &&
538           p_atomic_read_relaxed(&cdt->swapchain->num_acquires) >= cdt->swapchain->max_acquires) {
539          util_queue_fence_wait(&cdt->swapchain->present_fence);
540       }
541       VkResult ret;
542       if (!acquire) {
543          acquire = zink_create_semaphore(screen);
544          assert(acquire);
545          if (!acquire)
546             return VK_ERROR_OUT_OF_HOST_MEMORY;
547       }
548       ret = VKSCR(AcquireNextImageKHR)(screen->dev, cdt->swapchain->swapchain, timeout, acquire, VK_NULL_HANDLE, &res->obj->dt_idx);
549       if (ret != VK_SUCCESS && ret != VK_SUBOPTIMAL_KHR) {
550          if (ret == VK_ERROR_OUT_OF_DATE_KHR) {
551             res->obj->new_dt = true;
552             continue;
553          }
554          VKSCR(DestroySemaphore)(screen->dev, acquire, NULL);
555          return ret;
556       }
557       break;
558    }
559 
560    cdt->swapchain->images[res->obj->dt_idx].acquire = acquire;
561    if (cdt->swapchain->images[res->obj->dt_idx].readback)
562       zink_resource(cdt->swapchain->images[res->obj->dt_idx].readback)->valid = false;
563    res->obj->image = cdt->swapchain->images[res->obj->dt_idx].image;
564    if (!cdt->age_locked)
565       zink_kopper_update_last_written(res);
566    cdt->swapchain->images[res->obj->dt_idx].acquired = NULL;
567    if (!cdt->swapchain->images[res->obj->dt_idx].init) {
568       /* swapchain images are initially in the UNDEFINED layout */
569       res->layout = VK_IMAGE_LAYOUT_UNDEFINED;
570       cdt->swapchain->images[res->obj->dt_idx].init = true;
571    }
572    if (timeout == UINT64_MAX) {
573       res->obj->indefinite_acquire = true;
574       p_atomic_inc(&cdt->swapchain->num_acquires);
575    }
576    cdt->swapchain->images[res->obj->dt_idx].dt_has_data = false;
577    return VK_SUCCESS;
578 }
579 
580 static void
kill_swapchain(struct zink_context * ctx,struct zink_resource * res)581 kill_swapchain(struct zink_context *ctx, struct zink_resource *res)
582 {
583    struct zink_screen *screen = zink_screen(ctx->base.screen);
584    /* dead swapchain */
585    mesa_loge("zink: swapchain killed %p\n", res);
586    zink_batch_reference_resource(&ctx->batch, res);
587    struct pipe_resource *pres = screen->base.resource_create(&screen->base, &res->base.b);
588    zink_resource_object_reference(screen, &res->obj, zink_resource(pres)->obj);
589    res->layout = VK_IMAGE_LAYOUT_UNDEFINED;
590    res->swapchain = false;
591    pipe_resource_reference(&pres, NULL);
592 }
593 
594 static bool
is_swapchain_kill(VkResult ret)595 is_swapchain_kill(VkResult ret)
596 {
597    return ret != VK_SUCCESS &&
598           ret != VK_TIMEOUT &&
599           ret != VK_NOT_READY &&
600           ret != VK_SUBOPTIMAL_KHR;
601 }
602 
603 bool
zink_kopper_acquire(struct zink_context * ctx,struct zink_resource * res,uint64_t timeout)604 zink_kopper_acquire(struct zink_context *ctx, struct zink_resource *res, uint64_t timeout)
605 {
606    assert(zink_is_swapchain(res));
607    struct kopper_displaytarget *cdt = res->obj->dt;
608    if (!cdt)
609       /* dead swapchain */
610       return false;
611    if (cdt->is_kill) {
612       kill_swapchain(ctx, res);
613       return false;
614    }
615    const struct kopper_swapchain *cswap = cdt->swapchain;
616    res->obj->new_dt |= res->base.b.width0 != cswap->scci.imageExtent.width ||
617                        res->base.b.height0 != cswap->scci.imageExtent.height;
618    VkResult ret = kopper_acquire(zink_screen(trace_screen_unwrap(ctx->base.screen)), res, timeout);
619    if (ret == VK_SUCCESS || ret == VK_SUBOPTIMAL_KHR) {
620       if (cswap != cdt->swapchain) {
621          ctx->swapchain_size = cdt->swapchain->scci.imageExtent;
622          res->base.b.width0 = ctx->swapchain_size.width;
623          res->base.b.height0 = ctx->swapchain_size.height;
624       }
625    } else if (is_swapchain_kill(ret)) {
626       kill_swapchain(ctx, res);
627    }
628    bool is_kill = is_swapchain_kill(ret);
629    zink_batch_usage_set(&cdt->swapchain->batch_uses, ctx->batch.state);
630    return !is_kill;
631 }
632 
633 VkSemaphore
zink_kopper_acquire_submit(struct zink_screen * screen,struct zink_resource * res)634 zink_kopper_acquire_submit(struct zink_screen *screen, struct zink_resource *res)
635 {
636    assert(res->obj->dt);
637    struct kopper_displaytarget *cdt = res->obj->dt;
638    assert(res->obj->dt_idx != UINT32_MAX);
639    if (cdt->swapchain->images[res->obj->dt_idx].dt_has_data)
640       return VK_NULL_HANDLE;
641    assert(res->obj->dt_idx != UINT32_MAX);
642    if (cdt->swapchain->images[res->obj->dt_idx].acquired) {
643       assert(!cdt->swapchain->images[res->obj->dt_idx].acquire);
644       return VK_NULL_HANDLE;
645    }
646    assert(cdt->swapchain->images[res->obj->dt_idx].acquire);
647    cdt->swapchain->images[res->obj->dt_idx].acquired = res;
648    /* this is now owned by the batch */
649    VkSemaphore acquire = cdt->swapchain->images[res->obj->dt_idx].acquire;
650    cdt->swapchain->images[res->obj->dt_idx].acquire = VK_NULL_HANDLE;
651    cdt->swapchain->images[res->obj->dt_idx].dt_has_data = true;
652    return acquire;
653 }
654 
655 VkSemaphore
zink_kopper_present(struct zink_screen * screen,struct zink_resource * res)656 zink_kopper_present(struct zink_screen *screen, struct zink_resource *res)
657 {
658    assert(res->obj->dt);
659    assert(!res->obj->present);
660    assert(zink_kopper_acquired(res->obj->dt, res->obj->dt_idx));
661    res->obj->present = zink_create_semaphore(screen);
662    return res->obj->present;
663 }
664 
665 struct kopper_present_info {
666    VkPresentInfoKHR info;
667    uint32_t image;
668    struct kopper_swapchain *swapchain;
669    struct zink_resource *res;
670    VkSemaphore sem;
671    bool indefinite_acquire;
672 };
673 
674 static void
kopper_present(void * data,void * gdata,int thread_idx)675 kopper_present(void *data, void *gdata, int thread_idx)
676 {
677    struct kopper_present_info *cpi = data;
678    struct kopper_displaytarget *cdt = cpi->res->obj->dt;
679    struct kopper_swapchain *swapchain = cpi->swapchain;
680    struct zink_screen *screen = gdata;
681    VkResult error = VK_SUCCESS;
682    cpi->info.pResults = &error;
683 
684    simple_mtx_lock(&screen->queue_lock);
685    if (screen->driver_workarounds.implicit_sync && cdt->type != KOPPER_WIN32) {
686       if (!screen->fence) {
687          VkFenceCreateInfo fci = {0};
688          fci.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
689          VKSCR(CreateFence)(screen->dev, &fci, NULL, &screen->fence);
690       }
691       VKSCR(ResetFences)(screen->dev, 1, &screen->fence);
692       VkSubmitInfo si = {0};
693       si.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
694       si.waitSemaphoreCount = 1;
695       si.pWaitSemaphores = cpi->info.pWaitSemaphores;
696       VkPipelineStageFlags stages = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
697       si.pWaitDstStageMask = &stages;
698 
699       error = VKSCR(QueueSubmit)(screen->queue, 1, &si, screen->fence);
700       if (!zink_screen_handle_vkresult(screen, error)) {
701          simple_mtx_unlock(&screen->queue_lock);
702          VKSCR(DestroySemaphore)(screen->dev, cpi->sem, NULL);
703          goto out;
704       }
705       error = VKSCR(WaitForFences)(screen->dev, 1, &screen->fence, VK_TRUE, UINT64_MAX);
706       if (!zink_screen_handle_vkresult(screen, error)) {
707          simple_mtx_unlock(&screen->queue_lock);
708          VKSCR(DestroySemaphore)(screen->dev, cpi->sem, NULL);
709          goto out;
710       }
711       cpi->info.pWaitSemaphores = NULL;
712       cpi->info.waitSemaphoreCount = 0;
713    }
714    VkResult error2 = VKSCR(QueuePresentKHR)(screen->queue, &cpi->info);
715    zink_screen_debug_marker_end(screen, screen->frame_marker_emitted);
716    zink_screen_debug_marker_begin(screen, "frame");
717    simple_mtx_unlock(&screen->queue_lock);
718    swapchain->last_present = cpi->image;
719    if (cpi->indefinite_acquire)
720       p_atomic_dec(&swapchain->num_acquires);
721    if (error2 == VK_SUBOPTIMAL_KHR && cdt->swapchain == swapchain)
722       cpi->res->obj->new_dt = true;
723 
724    /* it's illegal to destroy semaphores if they're in use by a cmdbuf.
725     * but what does "in use" actually mean?
726     * in truth, when using timelines, nobody knows. especially not VVL.
727     *
728     * thus, to avoid infinite error spam and thread-related races,
729     * present semaphores need their own free queue based on the
730     * last-known completed timeline id so that the semaphore persists through
731     * normal cmdbuf submit/signal and then also exists here when it's needed for the present operation
732     */
733    struct util_dynarray *arr;
734    for (; screen->last_finished && swapchain->last_present_prune != screen->last_finished; swapchain->last_present_prune++) {
735       struct hash_entry *he = _mesa_hash_table_search(swapchain->presents,
736                                                       (void*)(uintptr_t)swapchain->last_present_prune);
737       if (he) {
738          arr = he->data;
739          simple_mtx_lock(&screen->semaphores_lock);
740          util_dynarray_append_dynarray(&screen->semaphores, arr);
741          simple_mtx_unlock(&screen->semaphores_lock);
742          util_dynarray_fini(arr);
743          free(arr);
744          _mesa_hash_table_remove(swapchain->presents, he);
745       }
746    }
747    /* queue this wait semaphore for deletion on completion of the next batch */
748    assert(screen->curr_batch > 0);
749    uint32_t next = (uint32_t)screen->curr_batch + 1;
750    /* handle overflow */
751    next = MAX2(next + 1, 1);
752    struct hash_entry *he = _mesa_hash_table_search(swapchain->presents, (void*)(uintptr_t)next);
753    if (he)
754       arr = he->data;
755    else {
756       arr = malloc(sizeof(struct util_dynarray));
757       if (!arr) {
758          mesa_loge("ZINK: failed to allocate arr!");
759          return;
760       }
761 
762       util_dynarray_init(arr, NULL);
763       _mesa_hash_table_insert(swapchain->presents, (void*)(uintptr_t)next, arr);
764    }
765    util_dynarray_append(arr, VkSemaphore, cpi->sem);
766 out:
767    if (thread_idx != -1) {
768       p_atomic_dec(&swapchain->async_presents);
769       struct pipe_resource *pres = &cpi->res->base.b;
770       pipe_resource_reference(&pres, NULL);
771    }
772    free(cpi);
773 }
774 
775 void
zink_kopper_present_queue(struct zink_screen * screen,struct zink_resource * res)776 zink_kopper_present_queue(struct zink_screen *screen, struct zink_resource *res)
777 {
778    assert(res->obj->dt);
779    struct kopper_displaytarget *cdt = res->obj->dt;
780    assert(zink_kopper_acquired(res->obj->dt, res->obj->dt_idx));
781    assert(res->obj->present);
782 
783    /* always try to prune if the current swapchain has seen presents */
784    if (cdt->swapchain->last_present != UINT32_MAX)
785       prune_old_swapchains(screen, cdt, false);
786 
787    struct kopper_present_info *cpi = malloc(sizeof(struct kopper_present_info));
788    if (!cpi) {
789       mesa_loge("ZINK: failed to allocate cpi!");
790       return;
791    }
792 
793    cpi->sem = res->obj->present;
794    cpi->res = res;
795    cpi->swapchain = cdt->swapchain;
796    cpi->indefinite_acquire = res->obj->indefinite_acquire;
797    cpi->image = res->obj->dt_idx;
798    cpi->info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
799    cpi->info.pNext = NULL;
800    cpi->info.waitSemaphoreCount = 1;
801    cpi->info.pWaitSemaphores = &cpi->sem;
802    cpi->info.swapchainCount = 1;
803    cpi->info.pSwapchains = &cdt->swapchain->swapchain;
804    cpi->info.pImageIndices = &cpi->image;
805    cpi->info.pResults = NULL;
806    res->obj->present = VK_NULL_HANDLE;
807    /* Ex GLX_EXT_buffer_age:
808     *
809     *  Buffers' ages are initialized to 0 at buffer creation time.
810     *  When a frame boundary is reached, the following occurs before
811     *  any exchanging or copying of color buffers:
812     *
813     *  * The current back buffer's age is set to 1.
814     *  * Any other color buffers' ages are incremented by 1 if
815     *    their age was previously greater than 0.
816     */
817    if (!cdt->age_locked) {
818       for (int i = 0; i < cdt->swapchain->num_images; i++) {
819             if (i == res->obj->dt_idx)
820                cdt->swapchain->images[i].age = 1;
821             else if (cdt->swapchain->images[i].age > 0)
822                cdt->swapchain->images[i].age += 1;
823       }
824    }
825    if (util_queue_is_initialized(&screen->flush_queue)) {
826       p_atomic_inc(&cpi->swapchain->async_presents);
827       struct pipe_resource *pres = NULL;
828       pipe_resource_reference(&pres, &res->base.b);
829       util_queue_add_job(&screen->flush_queue, cpi, &cdt->swapchain->present_fence,
830                          kopper_present, NULL, 0);
831    } else {
832       kopper_present(cpi, screen, -1);
833    }
834    res->obj->indefinite_acquire = false;
835    cdt->swapchain->images[res->obj->dt_idx].acquired = NULL;
836    res->obj->dt_idx = UINT32_MAX;
837 }
838 
839 void
zink_kopper_update_last_written(struct zink_resource * res)840 zink_kopper_update_last_written(struct zink_resource *res)
841 {
842    res->obj->last_dt_idx = res->obj->dt_idx;
843 }
844 
845 void
zink_kopper_set_readback_needs_update(struct zink_resource * res)846 zink_kopper_set_readback_needs_update(struct zink_resource *res)
847 {
848    struct kopper_displaytarget *cdt = res->obj->dt;
849    struct kopper_swapchain *cswap = cdt->swapchain;
850    cswap->images[res->obj->dt_idx].readback_needs_update = true;
851 }
852 
853 static bool
kopper_ensure_readback(struct zink_screen * screen,struct zink_resource * res)854 kopper_ensure_readback(struct zink_screen *screen, struct zink_resource *res)
855 {
856    struct kopper_displaytarget *cdt = res->obj->dt;
857    struct kopper_swapchain *cswap = cdt->swapchain;
858 
859    for (unsigned i = 0; i < cswap->num_images; i++) {
860       if (cswap->images[i].readback)
861          return false;
862       struct pipe_resource templ = res->base.b;
863       templ.bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
864       cswap->images[i].readback = screen->base.resource_create(&screen->base, &templ);
865    }
866    return true;
867 }
868 
869 bool
zink_kopper_acquire_readback(struct zink_context * ctx,struct zink_resource * res,struct zink_resource ** readback)870 zink_kopper_acquire_readback(struct zink_context *ctx, struct zink_resource *res, struct zink_resource **readback)
871 {
872    struct zink_screen *screen = zink_screen(ctx->base.screen);
873    assert(res->obj->dt);
874    struct kopper_displaytarget *cdt = res->obj->dt;
875    const struct kopper_swapchain *cswap = cdt->swapchain;
876    uint32_t last_dt_idx = res->obj->last_dt_idx;
877    VkResult ret = VK_SUCCESS;
878 
879    if (++cdt->readback_counter >= ZINK_READBACK_THRESHOLD) {
880       if (kopper_ensure_readback(screen, res) && cswap->images[res->obj->dt_idx].readback_needs_update)
881          zink_kopper_readback_update(ctx, res);
882    }
883    /* if this hasn't been presented or if it has data, use this as the readback target */
884    if (res->obj->last_dt_idx == UINT32_MAX ||
885        (res->obj->dt_idx != UINT32_MAX && cdt->swapchain->images[res->obj->dt_idx].age)) {
886       *readback = res;
887       return false;
888    }
889    if (cswap->images[last_dt_idx].acquired) {
890       struct zink_resource *rb = cswap->images[last_dt_idx].acquired;
891       *readback = rb;
892       return false;
893    }
894    if (cswap->images[last_dt_idx].readback) {
895       struct zink_resource *rb = zink_resource(cswap->images[res->obj->last_dt_idx].readback);
896       if (!cswap->images[last_dt_idx].readback_needs_update) {
897          *readback = rb;
898          return false;
899       }
900    }
901    while (res->obj->dt_idx != last_dt_idx) {
902       cdt->age_locked = true;
903       if (res->obj->dt_idx != UINT32_MAX && !zink_kopper_present_readback(ctx, res))
904          break;
905       cdt->age_locked = true;
906       do {
907          ret = kopper_acquire(screen, res, 0);
908       } while (!is_swapchain_kill(ret) && (ret == VK_NOT_READY || ret == VK_TIMEOUT));
909       if (is_swapchain_kill(ret)) {
910          kill_swapchain(ctx, res);
911          *readback = NULL;
912          cdt->age_locked = false;
913          return false;
914       }
915    }
916    if (cswap != cdt->swapchain) {
917       ctx->swapchain_size = cdt->swapchain->scci.imageExtent;
918       res->base.b.width0 = ctx->swapchain_size.width;
919       res->base.b.height0 = ctx->swapchain_size.height;
920    }
921    zink_batch_usage_set(&cdt->swapchain->batch_uses, ctx->batch.state);
922    *readback = res;
923    return true;
924 }
925 
926 bool
zink_kopper_present_readback(struct zink_context * ctx,struct zink_resource * res)927 zink_kopper_present_readback(struct zink_context *ctx, struct zink_resource *res)
928 {
929    struct zink_screen *screen = zink_screen(ctx->base.screen);
930    VkSubmitInfo si = {0};
931    assert(zink_is_swapchain(res));
932    if (res->obj->last_dt_idx == UINT32_MAX)
933       return true;
934    if (res->layout != VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) {
935       zink_screen(ctx->base.screen)->image_barrier(ctx, res, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, 0, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
936       ctx->base.flush(&ctx->base, NULL, 0);
937    }
938    si.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
939    si.signalSemaphoreCount = 1;
940    VkPipelineStageFlags mask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
941    si.pWaitDstStageMask = &mask;
942    VkSemaphore acquire = zink_kopper_acquire_submit(screen, res);
943    VkSemaphore present = res->obj->present ? res->obj->present : zink_kopper_present(screen, res);
944    if (screen->threaded_submit)
945       util_queue_finish(&screen->flush_queue);
946    si.waitSemaphoreCount = !!acquire;
947    si.pWaitSemaphores = &acquire;
948    si.pSignalSemaphores = &present;
949    simple_mtx_lock(&screen->queue_lock);
950    VkResult error = VKSCR(QueueSubmit)(screen->queue, 1, &si, VK_NULL_HANDLE);
951    simple_mtx_unlock(&screen->queue_lock);
952    if (!zink_screen_handle_vkresult(screen, error))
953       return false;
954 
955    zink_kopper_present_queue(screen, res);
956    if (util_queue_is_initialized(&screen->flush_queue)) {
957       struct kopper_displaytarget *cdt = res->obj->dt;
958       util_queue_fence_wait(&cdt->swapchain->present_fence);
959    }
960 
961    simple_mtx_lock(&screen->queue_lock);
962    error = VKSCR(QueueWaitIdle)(screen->queue);
963    simple_mtx_unlock(&screen->queue_lock);
964 
965    simple_mtx_lock(&screen->semaphores_lock);
966    util_dynarray_append(&screen->semaphores, VkSemaphore, acquire);
967    simple_mtx_unlock(&screen->semaphores_lock);
968 
969    struct kopper_displaytarget *cdt = res->obj->dt;
970    cdt->age_locked = false;
971 
972    return zink_screen_handle_vkresult(screen, error);
973 }
974 
975 void
zink_kopper_readback_update(struct zink_context * ctx,struct zink_resource * res)976 zink_kopper_readback_update(struct zink_context *ctx, struct zink_resource *res)
977 {
978    assert(res->obj->dt);
979    struct kopper_displaytarget *cdt = res->obj->dt;
980    struct kopper_swapchain *cswap = cdt->swapchain;
981    assert(res->obj->dt_idx != UINT32_MAX);
982    struct pipe_resource *readback = cswap->images[res->obj->dt_idx].readback;
983    struct pipe_box box = {0, 0, 0, res->base.b.width0, res->base.b.height0, res->base.b.depth0};
984 
985    if (cswap->images[res->obj->dt_idx].readback_needs_update && readback)
986       ctx->base.resource_copy_region(&ctx->base, readback, 0, 0, 0, 0, &res->base.b, 0, &box);
987    cswap->images[res->obj->dt_idx].readback_needs_update = false;
988 }
989 
990 bool
zink_kopper_update(struct pipe_screen * pscreen,struct pipe_resource * pres,int * w,int * h)991 zink_kopper_update(struct pipe_screen *pscreen, struct pipe_resource *pres, int *w, int *h)
992 {
993    struct zink_resource *res = zink_resource(pres);
994    struct zink_screen *screen = zink_screen(pscreen);
995    if (!res->obj->dt)
996       return false;
997    struct kopper_displaytarget *cdt = res->obj->dt;
998    if (cdt->type != KOPPER_X11) {
999       *w = res->base.b.width0;
1000       *h = res->base.b.height0;
1001       return true;
1002    }
1003    VkResult ret = update_caps(screen, cdt);
1004    if (ret != VK_SUCCESS) {
1005       mesa_loge("zink: failed to update swapchain capabilities: %s", vk_Result_to_str(ret));
1006       cdt->is_kill = true;
1007       return false;
1008    }
1009    *w = cdt->caps.currentExtent.width;
1010    *h = cdt->caps.currentExtent.height;
1011    return true;
1012 }
1013 
1014 bool
zink_kopper_is_cpu(const struct pipe_screen * pscreen)1015 zink_kopper_is_cpu(const struct pipe_screen *pscreen)
1016 {
1017    const struct zink_screen *screen = (const struct zink_screen*)pscreen;
1018    return screen->is_cpu;
1019 }
1020 
1021 void
zink_kopper_fixup_depth_buffer(struct zink_context * ctx)1022 zink_kopper_fixup_depth_buffer(struct zink_context *ctx)
1023 {
1024    struct zink_screen *screen = zink_screen(ctx->base.screen);
1025    if (!ctx->fb_state.zsbuf)
1026       return;
1027 
1028    assert(ctx->fb_state.zsbuf->texture->bind & PIPE_BIND_DISPLAY_TARGET);
1029 
1030    struct zink_resource *res = zink_resource(ctx->fb_state.zsbuf->texture);
1031    struct zink_surface *surf = zink_csurface(ctx->fb_state.zsbuf);
1032    struct zink_ctx_surface *csurf = (struct zink_ctx_surface*)ctx->fb_state.zsbuf;
1033    if (surf->info.width == ctx->fb_state.width &&
1034        surf->info.height == ctx->fb_state.height)
1035       return;
1036 
1037    struct pipe_resource templ = *ctx->fb_state.zsbuf->texture;
1038    templ.width0 = ctx->fb_state.width;
1039    templ.height0 = ctx->fb_state.height;
1040    struct pipe_resource *pz = screen->base.resource_create(&screen->base, &templ);
1041    struct zink_resource *z = zink_resource(pz);
1042    zink_resource_object_reference(screen, &res->obj, z->obj);
1043    res->base.b.width0 = ctx->fb_state.width;
1044    res->base.b.height0 = ctx->fb_state.height;
1045    pipe_resource_reference(&pz, NULL);
1046 
1047    ctx->fb_state.zsbuf->width = ctx->fb_state.width;
1048    ctx->fb_state.zsbuf->height = ctx->fb_state.height;
1049    struct pipe_surface *psurf = ctx->base.create_surface(&ctx->base, &res->base.b, ctx->fb_state.zsbuf);
1050    struct zink_ctx_surface *cz = (struct zink_ctx_surface*)psurf;
1051 
1052    /* oh god why */
1053    zink_surface_reference(screen, &csurf->surf, cz->surf);
1054    pipe_surface_release(&ctx->base, &psurf);
1055 }
1056 
1057 bool
zink_kopper_check(struct pipe_resource * pres)1058 zink_kopper_check(struct pipe_resource *pres)
1059 {
1060    struct zink_resource *res = zink_resource(pres);
1061    assert(pres->bind & PIPE_BIND_DISPLAY_TARGET);
1062    if (!res->obj->dt)
1063       return false;
1064    struct kopper_displaytarget *cdt = res->obj->dt;
1065    return !cdt->is_kill;
1066 }
1067 
1068 void
zink_kopper_set_swap_interval(struct pipe_screen * pscreen,struct pipe_resource * pres,int interval)1069 zink_kopper_set_swap_interval(struct pipe_screen *pscreen, struct pipe_resource *pres, int interval)
1070 {
1071    struct zink_resource *res = zink_resource(pres);
1072    struct zink_screen *screen = zink_screen(pscreen);
1073    assert(res->obj->dt);
1074    struct kopper_displaytarget *cdt = res->obj->dt;
1075    VkPresentModeKHR old_present_mode = cdt->present_mode;
1076 
1077    zink_kopper_set_present_mode_for_interval(cdt, interval);
1078 
1079    if (old_present_mode != cdt->present_mode)
1080       update_swapchain(screen, cdt, cdt->caps.currentExtent.width, cdt->caps.currentExtent.height);
1081 }
1082 
1083 int
zink_kopper_query_buffer_age(struct pipe_context * pctx,struct pipe_resource * pres)1084 zink_kopper_query_buffer_age(struct pipe_context *pctx, struct pipe_resource *pres)
1085 {
1086    struct zink_context *ctx = zink_context(pctx);
1087    struct zink_resource *res = zink_resource(pres);
1088    assert(res->obj->dt);
1089    struct kopper_displaytarget *cdt = res->obj->dt;
1090 
1091    ctx = zink_tc_context_unwrap(pctx, zink_screen(pctx->screen)->threaded);
1092 
1093    /* Returning 0 here isn't ideal (yes, the buffer is undefined, because you
1094     * lost it) but threading the error up is more hassle than it's worth.
1095     */
1096    if (!zink_kopper_acquired(res->obj->dt, res->obj->dt_idx))
1097       if (!zink_kopper_acquire(ctx, res, UINT64_MAX))
1098          return 0;
1099 
1100    return cdt->swapchain->images[res->obj->dt_idx].age;
1101 }
1102 
1103 static void
swapchain_prune_batch_usage(struct kopper_swapchain * cswap,const struct zink_batch_usage * u)1104 swapchain_prune_batch_usage(struct kopper_swapchain *cswap, const struct zink_batch_usage *u)
1105 {
1106    if (cswap->batch_uses == u)
1107       cswap->batch_uses = NULL;
1108 }
1109 
1110 void
zink_kopper_prune_batch_usage(struct kopper_displaytarget * cdt,const struct zink_batch_usage * u)1111 zink_kopper_prune_batch_usage(struct kopper_displaytarget *cdt, const struct zink_batch_usage *u)
1112 {
1113    struct kopper_swapchain *cswap = cdt->swapchain;
1114    swapchain_prune_batch_usage(cswap, u);
1115    for (cswap = cdt->old_swapchain; cswap; cswap = cswap->next)
1116       swapchain_prune_batch_usage(cswap, u);
1117 }
1118