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
25 #include <vkd3d_utils.h>
26 #include <xcb/xcb_event.h>
27 #include <xcb/xcb_icccm.h>
28 #include <xcb/xcb_keysyms.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)
57 if (!(libvulkan
= dlopen(SONAME_LIBVULKAN
, RTLD_NOW
)))
59 fprintf(stderr
, "Failed to load %s: %s.\n", SONAME_LIBVULKAN
, dlerror());
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
)
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
;
88 struct demo_window
**windows
;
93 void (*idle_func
)(struct demo
*demo
, 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
;
112 VkInstance vk_instance
;
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
)))
140 static inline bool demo_add_window(struct demo
*demo
, struct demo_window
*window
)
142 if (demo
->window_count
== demo
->windows_size
)
147 new_capacity
= max(demo
->windows_size
* 2, 4);
148 if (!(new_elements
= realloc(demo
->windows
, new_capacity
* sizeof(*demo
->windows
))))
150 demo
->windows
= new_elements
;
151 demo
->windows_size
= new_capacity
;
154 demo
->windows
[demo
->window_count
++] = window
;
159 static inline void demo_remove_window(struct demo
*demo
, const struct demo_window
*window
)
163 for (i
= 0; i
< demo
->window_count
; ++i
)
165 if (demo
->windows
[i
] != window
)
168 --demo
->window_count
;
169 memmove(&demo
->windows
[i
], &demo
->windows
[i
+ 1], (demo
->window_count
- i
) * sizeof(*demo
->windows
));
174 static inline struct demo_window
*demo_find_window(struct demo
*demo
, xcb_window_t window
)
178 for (i
= 0; i
< demo
->window_count
; ++i
)
180 if (demo
->windows
[i
]->window
== window
)
181 return demo
->windows
[i
];
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
)
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
)))
213 if (!(window
= malloc(sizeof(*window
))))
216 if (!demo_add_window(demo
, window
))
222 window
->window
= xcb_generate_id(demo
->connection
);
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
);
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
);
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
;
277 xcb_flush(demo
->connection
);
279 while (demo
->window_count
)
281 if (!demo
->idle_func
)
283 if (!(event
= xcb_wait_for_event(demo
->connection
)))
286 else if (!(event
= xcb_poll_for_event(demo
->connection
)))
288 demo
->idle_func(demo
, demo
->user_data
);
292 switch (XCB_EVENT_RESPONSE_TYPE(event
))
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
);
301 key_press
= (struct xcb_key_press_event_t
*)event
;
302 if (!(window
= demo_find_window(demo
, key_press
->event
)) || !window
->key_press_func
)
304 sym
= xcb_key_press_lookup_keysym(demo
->xcb_keysyms
, key_press
, 0);
305 window
->key_press_func(window
, sym
, window
->user_data
);
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
);
321 static inline bool demo_init(struct demo
*demo
, void *user_data
)
323 if (!(demo
->connection
= xcb_connect(NULL
, &demo
->screen
)))
325 if (xcb_connection_has_error(demo
->connection
) > 0)
327 if ((demo
->wm_delete_window_atom
= demo_get_atom(demo
->connection
, "WM_DELETE_WINDOW")) == XCB_NONE
)
329 if ((demo
->wm_protocols_atom
= demo_get_atom(demo
->connection
, "WM_PROTOCOLS")) == XCB_NONE
)
331 if (!(demo
->xcb_keysyms
= xcb_key_symbols_alloc(demo
->connection
)))
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
;
343 xcb_disconnect(demo
->connection
);
347 static inline void demo_cleanup(struct demo
*demo
)
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
;
385 if ((format
= vkd3d_get_vk_format(desc
->format
)) == VK_FORMAT_UNDEFINED
)
388 if (FAILED(ID3D12CommandQueue_GetDevice(command_queue
, &IID_ID3D12Device
, (void **)&d3d12_device
)))
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
);
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
)
411 if (vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vk_physical_device
, vk_surface
, &surface_caps
) < 0)
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
))
421 if (vkGetPhysicalDeviceSurfaceFormatsKHR(vk_physical_device
, vk_surface
, &format_count
, NULL
) < 0
422 || !format_count
|| !(formats
= calloc(format_count
, sizeof(*formats
))))
425 if (vkGetPhysicalDeviceSurfaceFormatsKHR(vk_physical_device
, vk_surface
, &format_count
, formats
) < 0)
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
)
440 if (i
== format_count
)
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)
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)
478 if (vkGetSwapchainImagesKHR(vk_device
, vk_swapchain
, &image_count
, NULL
) < 0
479 || !(vk_images
= calloc(image_count
, sizeof(*vk_images
))))
482 if (vkGetSwapchainImagesKHR(vk_device
, vk_swapchain
, &image_count
, vk_images
) < 0)
488 if (!(swapchain
= malloc(offsetof(struct demo_swapchain
, buffers
[image_count
]))))
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
]);
533 swapchain
->buffer_count
= image_count
;
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
]);
545 swapchain
->present_count
= 0;
546 ID3D12Device_Release(d3d12_device
);
548 ID3D12CommandQueue_AddRef(swapchain
->command_queue
= command_queue
);
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
);
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
);
577 static inline void demo_swapchain_present(struct demo_swapchain
*swapchain
)
579 VkPresentInfoKHR present_desc
;
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
)
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
);
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
);