vkd3d-shader/hlsl: Handle error instructions in add_shader_compilation().
[vkd3d.git] / demos / demo_xcb.h
blobb9209b121cddb1bd5fd6b33073da90bbf31879d4
1 /*
2 * Copyright 2016 Józef Kucia for CodeWeavers
3 * Copyright 2016 Henri Verbeet for CodeWeavers
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #define VK_NO_PROTOTYPES
21 #define VK_USE_PLATFORM_XCB_KHR
22 #define VKD3D_UTILS_API_VERSION VKD3D_API_VERSION_1_14
23 #include "config.h"
24 #include <vkd3d.h>
25 #include <vkd3d_utils.h>
26 #include <xcb/xcb_event.h>
27 #include <xcb/xcb_icccm.h>
28 #include <xcb/xcb_keysyms.h>
29 #include <sys/stat.h>
30 #include <dlfcn.h>
31 #include <limits.h>
32 #include <unistd.h>
33 #include <fcntl.h>
34 #include <stdbool.h>
35 #include <stdio.h>
37 #define DECLARE_VK_PFN(name) PFN_##name name;
38 DECLARE_VK_PFN(vkAcquireNextImageKHR)
39 DECLARE_VK_PFN(vkCreateFence)
40 DECLARE_VK_PFN(vkCreateSwapchainKHR)
41 DECLARE_VK_PFN(vkCreateXcbSurfaceKHR)
42 DECLARE_VK_PFN(vkDestroyFence)
43 DECLARE_VK_PFN(vkDestroySurfaceKHR)
44 DECLARE_VK_PFN(vkDestroySwapchainKHR)
45 DECLARE_VK_PFN(vkGetPhysicalDeviceSurfaceCapabilitiesKHR)
46 DECLARE_VK_PFN(vkGetPhysicalDeviceSurfaceFormatsKHR)
47 DECLARE_VK_PFN(vkGetPhysicalDeviceSurfaceSupportKHR)
48 DECLARE_VK_PFN(vkGetSwapchainImagesKHR)
49 DECLARE_VK_PFN(vkQueuePresentKHR)
50 DECLARE_VK_PFN(vkResetFences)
51 DECLARE_VK_PFN(vkWaitForFences)
53 static void load_vulkan_procs(void)
55 void *libvulkan;
57 if (!(libvulkan = dlopen(SONAME_LIBVULKAN, RTLD_NOW)))
59 fprintf(stderr, "Failed to load %s: %s.\n", SONAME_LIBVULKAN, dlerror());
60 exit(1);
63 #define LOAD_VK_PFN(name) name = (void *)dlsym(libvulkan, #name);
64 LOAD_VK_PFN(vkAcquireNextImageKHR)
65 LOAD_VK_PFN(vkCreateFence)
66 LOAD_VK_PFN(vkCreateSwapchainKHR)
67 LOAD_VK_PFN(vkCreateXcbSurfaceKHR)
68 LOAD_VK_PFN(vkDestroyFence)
69 LOAD_VK_PFN(vkDestroySurfaceKHR)
70 LOAD_VK_PFN(vkDestroySwapchainKHR)
71 LOAD_VK_PFN(vkGetPhysicalDeviceSurfaceCapabilitiesKHR)
72 LOAD_VK_PFN(vkGetPhysicalDeviceSurfaceFormatsKHR)
73 LOAD_VK_PFN(vkGetPhysicalDeviceSurfaceSupportKHR)
74 LOAD_VK_PFN(vkGetSwapchainImagesKHR)
75 LOAD_VK_PFN(vkQueuePresentKHR)
76 LOAD_VK_PFN(vkResetFences)
77 LOAD_VK_PFN(vkWaitForFences)
80 struct demo
82 xcb_connection_t *connection;
83 xcb_atom_t wm_protocols_atom;
84 xcb_atom_t wm_delete_window_atom;
85 xcb_key_symbols_t *xcb_keysyms;
86 int screen;
88 struct demo_window **windows;
89 size_t windows_size;
90 size_t window_count;
92 void *user_data;
93 void (*idle_func)(struct demo *demo, void *user_data);
96 struct demo_window
98 xcb_window_t window;
99 struct demo *demo;
101 void *user_data;
102 void (*expose_func)(struct demo_window *window, void *user_data);
103 void (*key_press_func)(struct demo_window *window, demo_key key, void *user_data);
106 struct demo_swapchain
108 VkSurfaceKHR vk_surface;
109 VkSwapchainKHR vk_swapchain;
110 VkFence vk_fence;
112 VkInstance vk_instance;
113 VkDevice vk_device;
114 ID3D12CommandQueue *command_queue;
116 ID3D12Fence *present_fence;
117 unsigned long long present_count;
119 uint32_t current_buffer;
120 unsigned int buffer_count;
121 ID3D12Resource *buffers[1];
124 static inline xcb_atom_t demo_get_atom(xcb_connection_t *c, const char *name)
126 xcb_intern_atom_cookie_t cookie;
127 xcb_intern_atom_reply_t *reply;
128 xcb_atom_t atom = XCB_NONE;
130 cookie = xcb_intern_atom(c, 0, strlen(name), name);
131 if ((reply = xcb_intern_atom_reply(c, cookie, NULL)))
133 atom = reply->atom;
134 free(reply);
137 return atom;
140 static inline bool demo_add_window(struct demo *demo, struct demo_window *window)
142 if (demo->window_count == demo->windows_size)
144 size_t new_capacity;
145 void *new_elements;
147 new_capacity = max(demo->windows_size * 2, 4);
148 if (!(new_elements = realloc(demo->windows, new_capacity * sizeof(*demo->windows))))
149 return false;
150 demo->windows = new_elements;
151 demo->windows_size = new_capacity;
154 demo->windows[demo->window_count++] = window;
156 return true;
159 static inline void demo_remove_window(struct demo *demo, const struct demo_window *window)
161 size_t i;
163 for (i = 0; i < demo->window_count; ++i)
165 if (demo->windows[i] != window)
166 continue;
168 --demo->window_count;
169 memmove(&demo->windows[i], &demo->windows[i + 1], (demo->window_count - i) * sizeof(*demo->windows));
170 break;
174 static inline struct demo_window *demo_find_window(struct demo *demo, xcb_window_t window)
176 size_t i;
178 for (i = 0; i < demo->window_count; ++i)
180 if (demo->windows[i]->window == window)
181 return demo->windows[i];
184 return NULL;
187 static inline xcb_screen_t *demo_get_screen(xcb_connection_t *c, int idx)
189 xcb_screen_iterator_t iter;
191 iter = xcb_setup_roots_iterator(xcb_get_setup(c));
192 for (; iter.rem; xcb_screen_next(&iter), --idx)
194 if (!idx)
195 return iter.data;
198 return NULL;
201 static inline struct demo_window *demo_window_create(struct demo *demo, const char *title,
202 unsigned int width, unsigned int height, void *user_data)
204 static const uint32_t window_events = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_KEY_PRESS;
206 struct demo_window *window;
207 xcb_size_hints_t hints;
208 xcb_screen_t *screen;
210 if (!(screen = demo_get_screen(demo->connection, demo->screen)))
211 return NULL;
213 if (!(window = malloc(sizeof(*window))))
214 return NULL;
216 if (!demo_add_window(demo, window))
218 free(window);
219 return NULL;
222 window->window = xcb_generate_id(demo->connection);
223 window->demo = demo;
224 window->user_data = user_data;
225 window->expose_func = NULL;
226 window->key_press_func = NULL;
227 xcb_create_window(demo->connection, XCB_COPY_FROM_PARENT, window->window, screen->root, 0, 0,
228 width, height, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual,
229 XCB_CW_EVENT_MASK, &window_events);
230 xcb_change_property(demo->connection, XCB_PROP_MODE_REPLACE, window->window, XCB_ATOM_WM_NAME,
231 XCB_ATOM_STRING, 8, strlen(title), title);
232 xcb_change_property(demo->connection, XCB_PROP_MODE_REPLACE, window->window, demo->wm_protocols_atom,
233 XCB_ATOM_ATOM, 32, 1, &demo->wm_delete_window_atom);
234 hints.flags = XCB_ICCCM_SIZE_HINT_P_MIN_SIZE | XCB_ICCCM_SIZE_HINT_P_MAX_SIZE;
235 hints.min_width = width;
236 hints.min_height = height;
237 hints.max_width = width;
238 hints.max_height = height;
239 xcb_change_property(demo->connection, XCB_PROP_MODE_REPLACE, window->window, XCB_ATOM_WM_NORMAL_HINTS,
240 XCB_ATOM_WM_SIZE_HINTS, 32, sizeof(hints) >> 2, &hints);
242 xcb_map_window(demo->connection, window->window);
244 xcb_flush(demo->connection);
246 return window;
249 static inline void demo_window_destroy(struct demo_window *window)
251 xcb_destroy_window(window->demo->connection, window->window);
252 xcb_flush(window->demo->connection);
253 demo_remove_window(window->demo, window);
254 free(window);
257 static inline void demo_window_set_key_press_func(struct demo_window *window,
258 void (*key_press_func)(struct demo_window *window, demo_key key, void *user_data))
260 window->key_press_func = key_press_func;
263 static inline void demo_window_set_expose_func(struct demo_window *window,
264 void (*expose_func)(struct demo_window *window, void *user_data))
266 window->expose_func = expose_func;
269 static inline void demo_process_events(struct demo *demo)
271 const struct xcb_client_message_event_t *client_message;
272 struct xcb_key_press_event_t *key_press;
273 xcb_generic_event_t *event;
274 struct demo_window *window;
275 xcb_keysym_t sym;
277 xcb_flush(demo->connection);
279 while (demo->window_count)
281 if (!demo->idle_func)
283 if (!(event = xcb_wait_for_event(demo->connection)))
284 break;
286 else if (!(event = xcb_poll_for_event(demo->connection)))
288 demo->idle_func(demo, demo->user_data);
289 continue;
292 switch (XCB_EVENT_RESPONSE_TYPE(event))
294 case XCB_EXPOSE:
295 if ((window = demo_find_window(demo, ((struct xcb_expose_event_t *)event)->window))
296 && window->expose_func)
297 window->expose_func(window, window->user_data);
298 break;
300 case XCB_KEY_PRESS:
301 key_press = (struct xcb_key_press_event_t *)event;
302 if (!(window = demo_find_window(demo, key_press->event)) || !window->key_press_func)
303 break;
304 sym = xcb_key_press_lookup_keysym(demo->xcb_keysyms, key_press, 0);
305 window->key_press_func(window, sym, window->user_data);
306 break;
308 case XCB_CLIENT_MESSAGE:
309 client_message = (xcb_client_message_event_t *)event;
310 if (client_message->type == demo->wm_protocols_atom
311 && client_message->data.data32[0] == demo->wm_delete_window_atom
312 && (window = demo_find_window(demo, client_message->window)))
313 demo_window_destroy(window);
314 break;
317 free(event);
321 static inline bool demo_init(struct demo *demo, void *user_data)
323 if (!(demo->connection = xcb_connect(NULL, &demo->screen)))
324 return false;
325 if (xcb_connection_has_error(demo->connection) > 0)
326 goto fail;
327 if ((demo->wm_delete_window_atom = demo_get_atom(demo->connection, "WM_DELETE_WINDOW")) == XCB_NONE)
328 goto fail;
329 if ((demo->wm_protocols_atom = demo_get_atom(demo->connection, "WM_PROTOCOLS")) == XCB_NONE)
330 goto fail;
331 if (!(demo->xcb_keysyms = xcb_key_symbols_alloc(demo->connection)))
332 goto fail;
334 demo->windows = NULL;
335 demo->windows_size = 0;
336 demo->window_count = 0;
337 demo->user_data = user_data;
338 demo->idle_func = NULL;
340 return true;
342 fail:
343 xcb_disconnect(demo->connection);
344 return false;
347 static inline void demo_cleanup(struct demo *demo)
349 free(demo->windows);
350 xcb_key_symbols_free(demo->xcb_keysyms);
351 xcb_disconnect(demo->connection);
354 static inline void demo_set_idle_func(struct demo *demo,
355 void (*idle_func)(struct demo *demo, void *user_data))
357 demo->idle_func = idle_func;
360 static inline struct demo_swapchain *demo_swapchain_create(ID3D12CommandQueue *command_queue,
361 struct demo_window *window, const struct demo_swapchain_desc *desc)
363 struct vkd3d_image_resource_create_info resource_create_info;
364 struct VkSwapchainCreateInfoKHR vk_swapchain_desc;
365 struct VkXcbSurfaceCreateInfoKHR surface_desc;
366 VkSwapchainKHR vk_swapchain = VK_NULL_HANDLE;
367 uint32_t format_count, queue_family_index;
368 VkSurfaceCapabilitiesKHR surface_caps;
369 VkPhysicalDevice vk_physical_device;
370 VkFence vk_fence = VK_NULL_HANDLE;
371 struct demo_swapchain *swapchain;
372 unsigned int image_count, i, j;
373 VkFenceCreateInfo fence_desc;
374 VkSurfaceFormatKHR *formats;
375 ID3D12Device *d3d12_device;
376 VkSurfaceKHR vk_surface;
377 VkInstance vk_instance;
378 VkBool32 supported;
379 VkDevice vk_device;
380 VkImage *vk_images;
381 VkFormat format;
383 load_vulkan_procs();
385 if ((format = vkd3d_get_vk_format(desc->format)) == VK_FORMAT_UNDEFINED)
386 return NULL;
388 if (FAILED(ID3D12CommandQueue_GetDevice(command_queue, &IID_ID3D12Device, (void **)&d3d12_device)))
389 return NULL;
391 vk_instance = vkd3d_instance_get_vk_instance(vkd3d_instance_from_device(d3d12_device));
392 vk_physical_device = vkd3d_get_vk_physical_device(d3d12_device);
393 vk_device = vkd3d_get_vk_device(d3d12_device);
395 surface_desc.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
396 surface_desc.pNext = NULL;
397 surface_desc.flags = 0;
398 surface_desc.connection = window->demo->connection;
399 surface_desc.window = window->window;
400 if (vkCreateXcbSurfaceKHR(vk_instance, &surface_desc, NULL, &vk_surface) < 0)
402 ID3D12Device_Release(d3d12_device);
403 return NULL;
406 queue_family_index = vkd3d_get_vk_queue_family_index(command_queue);
407 if (vkGetPhysicalDeviceSurfaceSupportKHR(vk_physical_device,
408 queue_family_index, vk_surface, &supported) < 0 || !supported)
409 goto fail;
411 if (vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vk_physical_device, vk_surface, &surface_caps) < 0)
412 goto fail;
414 if ((surface_caps.maxImageCount && desc->buffer_count > surface_caps.maxImageCount)
415 || desc->buffer_count < surface_caps.minImageCount
416 || desc->width > surface_caps.maxImageExtent.width || desc->width < surface_caps.minImageExtent.width
417 || desc->height > surface_caps.maxImageExtent.height || desc->height < surface_caps.minImageExtent.height
418 || !(surface_caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR))
419 goto fail;
421 if (vkGetPhysicalDeviceSurfaceFormatsKHR(vk_physical_device, vk_surface, &format_count, NULL) < 0
422 || !format_count || !(formats = calloc(format_count, sizeof(*formats))))
423 goto fail;
425 if (vkGetPhysicalDeviceSurfaceFormatsKHR(vk_physical_device, vk_surface, &format_count, formats) < 0)
427 free(formats);
428 goto fail;
431 if (format_count != 1 || formats->format != VK_FORMAT_UNDEFINED
432 || formats->colorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
434 for (i = 0; i < format_count; ++i)
436 if (formats[i].format == format && formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
437 break;
440 if (i == format_count)
442 free(formats);
443 goto fail;
447 free(formats);
448 formats = NULL;
450 vk_swapchain_desc.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
451 vk_swapchain_desc.pNext = NULL;
452 vk_swapchain_desc.flags = 0;
453 vk_swapchain_desc.surface = vk_surface;
454 vk_swapchain_desc.minImageCount = desc->buffer_count;
455 vk_swapchain_desc.imageFormat = format;
456 vk_swapchain_desc.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
457 vk_swapchain_desc.imageExtent.width = desc->width;
458 vk_swapchain_desc.imageExtent.height = desc->height;
459 vk_swapchain_desc.imageArrayLayers = 1;
460 vk_swapchain_desc.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
461 vk_swapchain_desc.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
462 vk_swapchain_desc.queueFamilyIndexCount = 0;
463 vk_swapchain_desc.pQueueFamilyIndices = NULL;
464 vk_swapchain_desc.preTransform = surface_caps.currentTransform;
465 vk_swapchain_desc.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
466 vk_swapchain_desc.presentMode = VK_PRESENT_MODE_FIFO_KHR;
467 vk_swapchain_desc.clipped = VK_TRUE;
468 vk_swapchain_desc.oldSwapchain = VK_NULL_HANDLE;
469 if (vkCreateSwapchainKHR(vk_device, &vk_swapchain_desc, NULL, &vk_swapchain) < 0)
470 goto fail;
472 fence_desc.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
473 fence_desc.pNext = NULL;
474 fence_desc.flags = 0;
475 if (vkCreateFence(vk_device, &fence_desc, NULL, &vk_fence) < 0)
476 goto fail;
478 if (vkGetSwapchainImagesKHR(vk_device, vk_swapchain, &image_count, NULL) < 0
479 || !(vk_images = calloc(image_count, sizeof(*vk_images))))
480 goto fail;
482 if (vkGetSwapchainImagesKHR(vk_device, vk_swapchain, &image_count, vk_images) < 0)
484 free(vk_images);
485 goto fail;
488 if (!(swapchain = malloc(offsetof(struct demo_swapchain, buffers[image_count]))))
490 free(vk_images);
491 goto fail;
493 swapchain->vk_surface = vk_surface;
494 swapchain->vk_swapchain = vk_swapchain;
495 swapchain->vk_fence = vk_fence;
496 swapchain->vk_instance = vk_instance;
497 swapchain->vk_device = vk_device;
499 vkAcquireNextImageKHR(vk_device, vk_swapchain, UINT64_MAX,
500 VK_NULL_HANDLE, vk_fence, &swapchain->current_buffer);
501 vkWaitForFences(vk_device, 1, &vk_fence, VK_TRUE, UINT64_MAX);
502 vkResetFences(vk_device, 1, &vk_fence);
504 resource_create_info.type = VKD3D_STRUCTURE_TYPE_IMAGE_RESOURCE_CREATE_INFO;
505 resource_create_info.next = NULL;
506 resource_create_info.desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
507 resource_create_info.desc.Alignment = 0;
508 resource_create_info.desc.Width = desc->width;
509 resource_create_info.desc.Height = desc->height;
510 resource_create_info.desc.DepthOrArraySize = 1;
511 resource_create_info.desc.MipLevels = 1;
512 resource_create_info.desc.Format = desc->format;
513 resource_create_info.desc.SampleDesc.Count = 1;
514 resource_create_info.desc.SampleDesc.Quality = 0;
515 resource_create_info.desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
516 resource_create_info.desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
517 resource_create_info.flags = VKD3D_RESOURCE_INITIAL_STATE_TRANSITION | VKD3D_RESOURCE_PRESENT_STATE_TRANSITION;
518 resource_create_info.present_state = D3D12_RESOURCE_STATE_PRESENT;
519 for (i = 0; i < image_count; ++i)
521 resource_create_info.vk_image = vk_images[i];
522 if (FAILED(vkd3d_create_image_resource(d3d12_device, &resource_create_info, &swapchain->buffers[i])))
524 for (j = 0; j < i; ++j)
526 ID3D12Resource_Release(swapchain->buffers[j]);
528 free(swapchain);
529 free(vk_images);
530 goto fail;
533 swapchain->buffer_count = image_count;
534 free(vk_images);
536 if (FAILED(ID3D12Device_CreateFence(d3d12_device, 0, 0, &IID_ID3D12Fence, (void **)&swapchain->present_fence)))
538 for (i = 0; i < image_count; ++i)
540 ID3D12Resource_Release(swapchain->buffers[i]);
542 free(swapchain);
543 goto fail;
545 swapchain->present_count = 0;
546 ID3D12Device_Release(d3d12_device);
548 ID3D12CommandQueue_AddRef(swapchain->command_queue = command_queue);
550 return swapchain;
552 fail:
553 if (vk_fence != VK_NULL_HANDLE)
554 vkDestroyFence(vk_device, vk_fence, NULL);
555 if (vk_swapchain != VK_NULL_HANDLE)
556 vkDestroySwapchainKHR(vk_device, vk_swapchain, NULL);
557 vkDestroySurfaceKHR(vk_instance, vk_surface, NULL);
558 ID3D12Device_Release(d3d12_device);
559 return NULL;
562 static inline unsigned int demo_swapchain_get_current_back_buffer_index(struct demo_swapchain *swapchain)
564 return swapchain->current_buffer;
567 static inline ID3D12Resource *demo_swapchain_get_back_buffer(struct demo_swapchain *swapchain, unsigned int index)
569 ID3D12Resource *resource = NULL;
571 if (index < swapchain->buffer_count && (resource = swapchain->buffers[index]))
572 ID3D12Resource_AddRef(resource);
574 return resource;
577 static inline void demo_swapchain_present(struct demo_swapchain *swapchain)
579 VkPresentInfoKHR present_desc;
580 VkQueue vk_queue;
582 present_desc.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
583 present_desc.pNext = NULL;
584 present_desc.waitSemaphoreCount = 0;
585 present_desc.pWaitSemaphores = NULL;
586 present_desc.swapchainCount = 1;
587 present_desc.pSwapchains = &swapchain->vk_swapchain;
588 present_desc.pImageIndices = &swapchain->current_buffer;
589 present_desc.pResults = NULL;
591 /* Synchronize vkd3d_acquire_vk_queue() with the Direct3D 12 work
592 * already submitted to the command queue. */
593 ++swapchain->present_count;
594 ID3D12CommandQueue_Signal(swapchain->command_queue, swapchain->present_fence, swapchain->present_count);
595 ID3D12Fence_SetEventOnCompletion(swapchain->present_fence, swapchain->present_count, NULL);
597 vk_queue = vkd3d_acquire_vk_queue(swapchain->command_queue);
598 vkQueuePresentKHR(vk_queue, &present_desc);
599 vkd3d_release_vk_queue(swapchain->command_queue);
601 vkAcquireNextImageKHR(swapchain->vk_device, swapchain->vk_swapchain, UINT64_MAX,
602 VK_NULL_HANDLE, swapchain->vk_fence, &swapchain->current_buffer);
603 vkWaitForFences(swapchain->vk_device, 1, &swapchain->vk_fence, VK_TRUE, UINT64_MAX);
604 vkResetFences(swapchain->vk_device, 1, &swapchain->vk_fence);
607 static inline void demo_swapchain_destroy(struct demo_swapchain *swapchain)
609 unsigned int i;
611 ID3D12CommandQueue_Release(swapchain->command_queue);
612 ID3D12Fence_Release(swapchain->present_fence);
613 for (i = 0; i < swapchain->buffer_count; ++i)
615 ID3D12Resource_Release(swapchain->buffers[i]);
617 vkDestroyFence(swapchain->vk_device, swapchain->vk_fence, NULL);
618 vkDestroySwapchainKHR(swapchain->vk_device, swapchain->vk_swapchain, NULL);
619 vkDestroySurfaceKHR(swapchain->vk_instance, swapchain->vk_surface, NULL);
620 free(swapchain);
623 static inline HANDLE demo_create_event(void)
625 return vkd3d_create_event();
628 static inline unsigned int demo_wait_event(HANDLE event, unsigned int ms)
630 return vkd3d_wait_event(event, ms);
633 static inline void demo_destroy_event(HANDLE event)
635 vkd3d_destroy_event(event);