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