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