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