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