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