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