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