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