core: Define VK_USE_PLATFORM_XCB_KHR before including vkd3d_utils.h.
[vkmodelviewer.git] / Core / port.cpp
blobcbafc1d16074581b28cbb290db91a75bcad9304f
1 /*
2 * Copyright 2016 Józef Kucia for CodeWeavers
3 * Copyright 2016, 2017 Henri Verbeet for CodeWeavers
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:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
24 #define VK_USE_PLATFORM_XCB_KHR
25 #include "port.h"
26 #include <vkd3d.h>
27 #include <xcb/xcb_icccm.h>
28 #include "xinput/xinput.h"
30 struct port_window
32 xcb_window_t window;
33 struct port *port;
36 struct port_swapchain
38 VkSurfaceKHR vk_surface;
39 VkSwapchainKHR vk_swapchain;
40 VkFence vk_fence;
42 VkInstance vk_instance;
43 VkDevice vk_device;
44 ID3D12CommandQueue *command_queue;
46 uint32_t current_buffer;
47 unsigned int buffer_count;
48 ID3D12Resource *buffers[1];
51 static xcb_atom_t port_get_atom(xcb_connection_t *c, const char *name)
53 xcb_intern_atom_cookie_t cookie;
54 xcb_intern_atom_reply_t *reply;
55 xcb_atom_t atom = XCB_NONE;
57 cookie = xcb_intern_atom(c, 0, strlen(name), name);
58 if ((reply = xcb_intern_atom_reply(c, cookie, NULL)))
60 atom = reply->atom;
61 free(reply);
64 return atom;
67 static bool port_add_window(struct port *port, struct port_window *window)
69 if (port->window_count == port->windows_size)
71 size_t new_capacity;
72 void *new_elements;
74 new_capacity = max(port->windows_size * 2, (size_t)4);
75 if (!(new_elements = realloc(port->windows, new_capacity * sizeof(*port->windows))))
76 return false;
77 port->windows = (struct port_window **)new_elements;
78 port->windows_size = new_capacity;
81 port->windows[port->window_count++] = window;
83 return true;
86 static void port_remove_window(struct port *port, const struct port_window *window)
88 size_t i;
90 for (i = 0; i < port->window_count; ++i)
92 if (port->windows[i] != window)
93 continue;
95 --port->window_count;
96 memmove(&port->windows[i], &port->windows[i + 1], (port->window_count - i) * sizeof(*port->windows));
97 break;
101 static struct port_window *port_find_window(struct port *port, xcb_window_t window)
103 size_t i;
105 for (i = 0; i < port->window_count; ++i)
107 if (port->windows[i]->window == window)
108 return port->windows[i];
111 return NULL;
114 static xcb_screen_t *port_get_screen(xcb_connection_t *c, int idx)
116 xcb_screen_iterator_t iter;
118 iter = xcb_setup_roots_iterator(xcb_get_setup(c));
119 for (; iter.rem; xcb_screen_next(&iter), --idx)
121 if (!idx)
122 return iter.data;
125 return NULL;
128 struct port_window *port_window_create(struct port *port, const char *title,
129 unsigned int width, unsigned int height, void *user_data)
131 static const uint32_t window_events = XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE;
133 struct port_window *window;
134 xcb_size_hints_t hints;
135 xcb_screen_t *screen;
137 if (!(screen = port_get_screen(port->connection, port->screen)))
138 return NULL;
140 if (!(window = (struct port_window *)malloc(sizeof(*window))))
141 return NULL;
143 if (!port_add_window(port, window))
145 free(window);
146 return NULL;
149 window->window = xcb_generate_id(port->connection);
150 window->port = port;
151 xcb_create_window(port->connection, XCB_COPY_FROM_PARENT, window->window, screen->root, 0, 0,
152 width, height, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual,
153 XCB_CW_EVENT_MASK, &window_events);
154 xcb_change_property(port->connection, XCB_PROP_MODE_REPLACE, window->window, XCB_ATOM_WM_NAME,
155 XCB_ATOM_STRING, 8, strlen(title), title);
156 xcb_change_property(port->connection, XCB_PROP_MODE_REPLACE, window->window, port->wm_protocols_atom,
157 XCB_ATOM_ATOM, 32, 1, &port->wm_delete_window_atom);
158 hints.flags = XCB_ICCCM_SIZE_HINT_P_MIN_SIZE | XCB_ICCCM_SIZE_HINT_P_MAX_SIZE;
159 hints.min_width = width;
160 hints.min_height = height;
161 hints.max_width = width;
162 hints.max_height = height;
163 xcb_change_property(port->connection, XCB_PROP_MODE_REPLACE, window->window, XCB_ATOM_WM_NORMAL_HINTS,
164 XCB_ATOM_WM_SIZE_HINTS, 32, sizeof(hints) >> 2, &hints);
166 xcb_map_window(port->connection, window->window);
168 xcb_flush(port->connection);
170 return window;
173 void port_window_destroy(struct port_window *window)
175 xcb_destroy_window(window->port->connection, window->window);
176 xcb_flush(window->port->connection);
177 port_remove_window(window->port, window);
178 free(window);
181 static void port_update_mouse_axes(struct port *port, xcb_input_device_class_iterator_t *it)
183 unsigned int idx = 0;
185 port->mouse_axes.x = ~0u;
186 port->mouse_axes.y = ~0u;
188 for (; it->rem; xcb_input_device_class_next(it))
190 xcb_input_valuator_class_t *v = (xcb_input_valuator_class_t *)it->data;
192 if (v->type != XCB_INPUT_INPUT_CLASS_VALUATOR || v->mode != XCB_INPUT_VALUATOR_MODE_RELATIVE)
193 continue;
195 switch (idx++)
197 case 0:
198 port->mouse_axes.x = v->number;
199 break;
201 case 1:
202 port->mouse_axes.y = v->number;
203 break;
205 default:
206 return;
211 static void port_process_xi_raw_motion_event(struct port *port, const xcb_input_raw_motion_event_t *motion_event)
213 const xcb_input_fp3232_t *values;
214 unsigned int i, j, k, idx;
215 uint32_t *mask;
216 double v;
218 if (!port->xi_client_pointer)
220 xcb_input_xi_get_client_pointer_cookie_t gcp_cookie;
221 xcb_input_xi_get_client_pointer_reply_t *gcp_reply;
222 xcb_input_xi_query_device_cookie_t query_cookie;
223 xcb_input_xi_query_device_reply_t *query_reply;
224 xcb_input_xi_device_info_iterator_t it;
225 xcb_input_device_id_t client_pointer;
227 gcp_cookie = xcb_input_xi_get_client_pointer(port->connection, XCB_WINDOW_NONE);
228 if (!(gcp_reply = xcb_input_xi_get_client_pointer_reply(port->connection, gcp_cookie, NULL))
229 || !gcp_reply->set)
231 free(gcp_reply);
232 return;
235 client_pointer = gcp_reply->deviceid;
236 free(gcp_reply);
238 query_cookie = xcb_input_xi_query_device(port->connection, XCB_INPUT_DEVICE_ALL);
239 if (!(query_reply = xcb_input_xi_query_device_reply(port->connection, query_cookie, NULL)))
240 return;
242 it = xcb_input_xi_query_device_infos_iterator(query_reply);
243 for (; it.rem; xcb_input_xi_device_info_next(&it))
245 xcb_input_device_class_iterator_t class_it;
246 xcb_input_xi_device_info_t *info = it.data;
248 if (info->deviceid != motion_event->deviceid)
249 continue;
250 if (info->type != XCB_INPUT_DEVICE_TYPE_SLAVE_POINTER)
251 continue;
252 if (info->attachment != client_pointer)
253 continue;
254 port->xi_current_slave = info->deviceid;
256 class_it = xcb_input_xi_device_info_classes_iterator(info);
257 port_update_mouse_axes(port, &class_it);
259 break;
261 free(query_reply);
263 if (!port->xi_current_slave)
264 return;
265 port->xi_client_pointer = client_pointer;
268 if (motion_event->deviceid != port->xi_current_slave)
269 return;
271 mask = (uint32_t *)(motion_event + 1);
272 values = (const xcb_input_fp3232_t *)(&mask[motion_event->valuators_len]);
273 for (i = 0, idx = 0; i < motion_event->valuators_len; ++i)
275 uint32_t m = mask[i];
277 while (m)
279 j = __builtin_ctz(m);
280 m &= ~(1u << j);
281 k = (i << 5) + j;
282 v = values[idx].integral + (double)values[idx].frac / ~0u;
284 if (k == port->mouse_axes.x)
285 port->mouse.x += v;
286 else if (k == port->mouse_axes.y)
287 port->mouse.y += v;
288 ++idx;
293 static void port_process_xi_event(struct port *port, const xcb_ge_generic_event_t *event)
295 const xcb_input_device_changed_event_t *change_event;
296 xcb_input_device_class_iterator_t class_it;
298 switch (event->event_type)
300 case XCB_INPUT_DEVICE_CHANGED:
301 change_event = (const xcb_input_device_changed_event_t *)event;
302 if (change_event->deviceid != port->xi_client_pointer
303 || change_event->reason != XCB_INPUT_CHANGE_REASON_SLAVE_SWITCH)
304 break;
305 class_it.data = (xcb_input_device_class_t *)&change_event[1];
306 class_it.rem = change_event->num_classes;
307 class_it.index = (char *)class_it.data - (char *)change_event;
308 port_update_mouse_axes(port, &class_it);
309 port->xi_current_slave = change_event->sourceid;
310 break;
312 case XCB_INPUT_RAW_MOTION:
313 port_process_xi_raw_motion_event(port, (const xcb_input_raw_motion_event_t *)event);
314 break;
316 default:
317 fprintf(stderr, "Unhandled X Input event type %#x.\n", event->event_type);
318 break;
322 void port_process_events(struct port *port)
324 const struct xcb_client_message_event_t *client_message;
325 const xcb_ge_generic_event_t *generic_event;
326 const xcb_key_release_event_t *key_release;
327 const xcb_key_press_event_t *key_press;
328 xcb_generic_event_t *event;
329 struct port_window *window;
331 xcb_flush(port->connection);
333 while (port->window_count)
335 if (!port->idle_func)
337 if (!(event = xcb_wait_for_event(port->connection)))
338 break;
340 else if (!(event = xcb_poll_for_event(port->connection)))
342 port->idle_func(port, port->user_data);
343 continue;
346 switch (XCB_EVENT_RESPONSE_TYPE(event))
348 case XCB_CLIENT_MESSAGE:
349 client_message = (xcb_client_message_event_t *)event;
350 if (client_message->type == port->wm_protocols_atom
351 && client_message->data.data32[0] == port->wm_delete_window_atom
352 && (window = port_find_window(port, client_message->window)))
353 port_window_destroy(window);
354 break;
356 case XCB_KEY_PRESS:
357 key_press = (xcb_key_press_event_t *)event;
358 port->keys[key_press->detail >> 3] |= 1 << (key_press->detail & 0x7);
359 break;
361 case XCB_KEY_RELEASE:
362 key_release = (xcb_key_release_event_t *)event;
363 port->keys[key_release->detail >> 3] &= ~(1 << (key_release->detail & 0x7));
364 break;
366 case XCB_GE_GENERIC:
367 generic_event = (xcb_ge_generic_event_t *)event;
368 if (generic_event->extension == port->xi_opcode)
369 port_process_xi_event(port, generic_event);
370 else
371 fprintf(stderr, "Unhandled generic event %#x/%#x.\n",
372 generic_event->extension, generic_event->event_type);
373 break;
375 default:
376 fprintf(stderr, "Unhandled event type %#x.\n", XCB_EVENT_RESPONSE_TYPE(event));
377 break;
380 free(event);
384 static bool port_init_xi2(struct port *port)
386 xcb_input_xi_query_version_cookie_t version_cookie;
387 xcb_input_xi_query_version_reply_t *version_reply;
388 xcb_query_extension_cookie_t extension_cookie;
389 xcb_query_extension_reply_t *extension_reply;
390 xcb_screen_t *screen;
391 struct
393 xcb_input_event_mask_t header;
394 uint32_t bits;
395 } mask;
396 static const char ext_name[] = "XInputExtension";
398 if (!(screen = port_get_screen(port->connection, port->screen)))
399 return false;
401 extension_cookie = xcb_query_extension(port->connection, sizeof(ext_name) - 1, ext_name);
402 if (!(extension_reply = xcb_query_extension_reply(port->connection, extension_cookie, NULL))
403 || !extension_reply->present)
405 free(extension_reply);
406 return false;
408 port->xi_opcode = extension_reply->major_opcode;
409 free(extension_reply);
411 version_cookie = xcb_input_xi_query_version(port->connection, 2, 0);
412 if (!(version_reply = xcb_input_xi_query_version_reply(port->connection, version_cookie, NULL))
413 || version_reply->major_version != 2)
415 free(version_reply);
416 return false;
418 free(version_reply);
420 mask.header.deviceid = XCB_INPUT_DEVICE_ALL;
421 mask.header.mask_len = 1;
422 mask.bits = XCB_INPUT_XI_EVENT_MASK_DEVICE_CHANGED | XCB_INPUT_XI_EVENT_MASK_RAW_MOTION;
423 xcb_input_xi_select_events(port->connection, screen->root, 1, &mask.header);
425 port->xi_client_pointer = 0;
426 port->xi_current_slave = 0;
427 memset(&port->mouse, 0, sizeof(port->mouse));
429 return true;
432 bool port_init(struct port *port, void *user_data)
434 if (!(port->connection = xcb_connect(NULL, &port->screen)))
435 return false;
436 if (xcb_connection_has_error(port->connection) > 0)
437 goto fail;
438 if ((port->wm_delete_window_atom = port_get_atom(port->connection, "WM_DELETE_WINDOW")) == XCB_NONE)
439 goto fail;
440 if ((port->wm_protocols_atom = port_get_atom(port->connection, "WM_PROTOCOLS")) == XCB_NONE)
441 goto fail;
442 if (!port_init_xi2(port))
443 goto fail;
445 port->windows = NULL;
446 port->windows_size = 0;
447 port->window_count = 0;
448 port->user_data = user_data;
449 port->idle_func = NULL;
450 memset(port->keys, 0, sizeof(port->keys));
452 return true;
454 fail:
455 xcb_disconnect(port->connection);
456 return false;
459 void port_grab_pointer(struct port *port, struct port_window *window)
461 xcb_grab_pointer_cookie_t cookie;
462 xcb_cursor_t cursor_id;
463 xcb_pixmap_t pixmap_id;
464 xcb_screen_t *screen;
466 if (!(screen = port_get_screen(port->connection, port->screen)))
467 return;
469 cursor_id = xcb_generate_id(port->connection);
470 pixmap_id = xcb_generate_id(port->connection);
472 xcb_create_pixmap(port->connection, 1, pixmap_id, screen->root, 1, 1);
473 xcb_create_cursor(port->connection, cursor_id, pixmap_id, pixmap_id, 0, 0, 0, 0, 0, 0, 0, 0);
474 xcb_free_pixmap(port->connection, pixmap_id);
475 xcb_change_window_attributes(port->connection, window->window, XCB_CW_CURSOR, &cursor_id);
476 xcb_free_cursor(port->connection, cursor_id);
478 cookie = xcb_grab_pointer(port->connection, 1, window->window, 0,
479 XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, window->window, XCB_NONE, XCB_CURRENT_TIME);
480 xcb_discard_reply(port->connection, cookie.sequence);
483 void port_ungrab_pointer(struct port *port, struct port_window *window)
485 xcb_cursor_t cursor_id = XCB_NONE;
487 xcb_change_window_attributes(port->connection, window->window, XCB_CW_CURSOR, &cursor_id);
488 xcb_ungrab_pointer(port->connection, XCB_CURRENT_TIME);
491 void port_cleanup(struct port *port)
493 free(port->windows);
494 xcb_disconnect(port->connection);
497 void port_set_idle_func(struct port *port,
498 void (*idle_func)(struct port *port, void *user_data))
500 port->idle_func = idle_func;
503 struct port_swapchain *port_swapchain_create(ID3D12CommandQueue *command_queue,
504 struct port_window *window, const struct port_swapchain_desc *desc)
506 struct vkd3d_image_resource_create_info resource_create_info;
507 struct VkSwapchainCreateInfoKHR vk_swapchain_desc;
508 struct VkXcbSurfaceCreateInfoKHR surface_desc;
509 VkSwapchainKHR vk_swapchain = VK_NULL_HANDLE;
510 uint32_t format_count, queue_family_index;
511 VkSurfaceCapabilitiesKHR surface_caps;
512 VkPhysicalDevice vk_physical_device;
513 VkFence vk_fence = VK_NULL_HANDLE;
514 struct port_swapchain *swapchain;
515 unsigned int image_count, i, j;
516 VkFenceCreateInfo fence_desc;
517 VkSurfaceFormatKHR *formats;
518 ID3D12Device *d3d12_device;
519 VkSurfaceKHR vk_surface;
520 VkInstance vk_instance;
521 VkBool32 supported;
522 VkDevice vk_device;
523 VkImage *vk_images;
524 VkFormat format;
526 if ((format = vkd3d_get_vk_format(desc->format)) == VK_FORMAT_UNDEFINED)
527 return NULL;
529 if (FAILED(command_queue->GetDevice(IID_PPV_ARGS(&d3d12_device))))
530 return NULL;
532 vk_instance = vkd3d_instance_get_vk_instance(vkd3d_instance_from_device(d3d12_device));
533 vk_physical_device = vkd3d_get_vk_physical_device(d3d12_device);
534 vk_device = vkd3d_get_vk_device(d3d12_device);
536 surface_desc.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
537 surface_desc.pNext = NULL;
538 surface_desc.flags = 0;
539 surface_desc.connection = window->port->connection;
540 surface_desc.window = window->window;
541 if (vkCreateXcbSurfaceKHR(vk_instance, &surface_desc, NULL, &vk_surface) < 0)
543 d3d12_device->Release();
544 return NULL;
547 queue_family_index = vkd3d_get_vk_queue_family_index(command_queue);
548 if (vkGetPhysicalDeviceSurfaceSupportKHR(vk_physical_device,
549 queue_family_index, vk_surface, &supported) < 0 || !supported)
550 goto fail;
552 if (vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vk_physical_device, vk_surface, &surface_caps) < 0)
553 goto fail;
555 if ((surface_caps.maxImageCount && desc->buffer_count > surface_caps.maxImageCount)
556 || desc->buffer_count < surface_caps.minImageCount
557 || desc->width > surface_caps.maxImageExtent.width || desc->width < surface_caps.minImageExtent.width
558 || desc->height > surface_caps.maxImageExtent.height || desc->height < surface_caps.minImageExtent.height
559 || !(surface_caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR))
560 goto fail;
562 if (vkGetPhysicalDeviceSurfaceFormatsKHR(vk_physical_device, vk_surface, &format_count, NULL) < 0
563 || !format_count || !(formats = (VkSurfaceFormatKHR *)calloc(format_count, sizeof(*formats))))
564 goto fail;
566 if (vkGetPhysicalDeviceSurfaceFormatsKHR(vk_physical_device, vk_surface, &format_count, formats) < 0)
568 free(formats);
569 goto fail;
572 if (format_count != 1 || formats->format != VK_FORMAT_UNDEFINED
573 || formats->colorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
575 for (i = 0; i < format_count; ++i)
577 if (formats[i].format == format && formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
578 break;
581 if (i == format_count)
583 free(formats);
584 goto fail;
588 free(formats);
589 formats = NULL;
591 vk_swapchain_desc.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
592 vk_swapchain_desc.pNext = NULL;
593 vk_swapchain_desc.flags = 0;
594 vk_swapchain_desc.surface = vk_surface;
595 vk_swapchain_desc.minImageCount = desc->buffer_count;
596 vk_swapchain_desc.imageFormat = format;
597 vk_swapchain_desc.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
598 vk_swapchain_desc.imageExtent.width = desc->width;
599 vk_swapchain_desc.imageExtent.height = desc->height;
600 vk_swapchain_desc.imageArrayLayers = 1;
601 vk_swapchain_desc.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
602 vk_swapchain_desc.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
603 vk_swapchain_desc.queueFamilyIndexCount = 0;
604 vk_swapchain_desc.pQueueFamilyIndices = NULL;
605 vk_swapchain_desc.preTransform = surface_caps.currentTransform;
606 vk_swapchain_desc.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
607 vk_swapchain_desc.presentMode = VK_PRESENT_MODE_FIFO_KHR;
608 vk_swapchain_desc.clipped = VK_TRUE;
609 vk_swapchain_desc.oldSwapchain = VK_NULL_HANDLE;
610 if (vkCreateSwapchainKHR(vk_device, &vk_swapchain_desc, NULL, &vk_swapchain) < 0)
611 goto fail;
613 fence_desc.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
614 fence_desc.pNext = NULL;
615 fence_desc.flags = 0;
616 if (vkCreateFence(vk_device, &fence_desc, NULL, &vk_fence) < 0)
617 goto fail;
619 if (vkGetSwapchainImagesKHR(vk_device, vk_swapchain, &image_count, NULL) < 0
620 || !(vk_images = (VkImage *)calloc(image_count, sizeof(*vk_images))))
621 goto fail;
623 if (vkGetSwapchainImagesKHR(vk_device, vk_swapchain, &image_count, vk_images) < 0)
625 free(vk_images);
626 goto fail;
629 if (!(swapchain = (struct port_swapchain *)malloc(offsetof(struct port_swapchain,
630 buffers) + image_count * sizeof(*swapchain->buffers))))
632 free(vk_images);
633 goto fail;
635 swapchain->vk_surface = vk_surface;
636 swapchain->vk_swapchain = vk_swapchain;
637 swapchain->vk_fence = vk_fence;
638 swapchain->vk_instance = vk_instance;
639 swapchain->vk_device = vk_device;
641 vkAcquireNextImageKHR(vk_device, vk_swapchain, UINT64_MAX,
642 VK_NULL_HANDLE, vk_fence, &swapchain->current_buffer);
643 vkWaitForFences(vk_device, 1, &vk_fence, VK_TRUE, UINT64_MAX);
644 vkResetFences(vk_device, 1, &vk_fence);
646 resource_create_info.type = VKD3D_STRUCTURE_TYPE_IMAGE_RESOURCE_CREATE_INFO;
647 resource_create_info.next = NULL;
648 resource_create_info.desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
649 resource_create_info.desc.Alignment = 0;
650 resource_create_info.desc.Width = desc->width;
651 resource_create_info.desc.Height = desc->height;
652 resource_create_info.desc.DepthOrArraySize = 1;
653 resource_create_info.desc.MipLevels = 1;
654 resource_create_info.desc.Format = desc->format;
655 resource_create_info.desc.SampleDesc.Count = 1;
656 resource_create_info.desc.SampleDesc.Quality = 0;
657 resource_create_info.desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
658 resource_create_info.desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
659 resource_create_info.flags = VKD3D_RESOURCE_INITIAL_STATE_TRANSITION | VKD3D_RESOURCE_PRESENT_STATE_TRANSITION;
660 resource_create_info.present_state = D3D12_RESOURCE_STATE_PRESENT;
661 for (i = 0; i < image_count; ++i)
663 resource_create_info.vk_image = vk_images[i];
664 if (FAILED(vkd3d_create_image_resource(d3d12_device, &resource_create_info, &swapchain->buffers[i])))
666 for (j = 0; j < i; ++j)
668 swapchain->buffers[j]->Release();
670 free(swapchain);
671 free(vk_images);
672 goto fail;
675 swapchain->buffer_count = image_count;
676 free(vk_images);
677 d3d12_device->Release();
679 swapchain->command_queue = command_queue;
680 swapchain->command_queue->AddRef();
682 return swapchain;
684 fail:
685 if (vk_fence != VK_NULL_HANDLE)
686 vkDestroyFence(vk_device, vk_fence, NULL);
687 if (vk_swapchain != VK_NULL_HANDLE)
688 vkDestroySwapchainKHR(vk_device, vk_swapchain, NULL);
689 vkDestroySurfaceKHR(vk_instance, vk_surface, NULL);
690 d3d12_device->Release();
691 return NULL;
694 ID3D12Resource *port_swapchain_get_back_buffer(struct port_swapchain *swapchain, unsigned int index)
696 ID3D12Resource *resource = NULL;
698 if (index < swapchain->buffer_count && (resource = swapchain->buffers[index]))
699 resource->AddRef();
701 return resource;
704 void port_swapchain_present(struct port_swapchain *swapchain)
706 VkPresentInfoKHR present_desc;
707 VkQueue vk_queue;
709 present_desc.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
710 present_desc.pNext = NULL;
711 present_desc.waitSemaphoreCount = 0;
712 present_desc.pWaitSemaphores = NULL;
713 present_desc.swapchainCount = 1;
714 present_desc.pSwapchains = &swapchain->vk_swapchain;
715 present_desc.pImageIndices = &swapchain->current_buffer;
716 present_desc.pResults = NULL;
718 vk_queue = vkd3d_acquire_vk_queue(swapchain->command_queue);
719 vkQueuePresentKHR(vk_queue, &present_desc);
720 vkd3d_release_vk_queue(swapchain->command_queue);
722 vkAcquireNextImageKHR(swapchain->vk_device, swapchain->vk_swapchain, UINT64_MAX,
723 VK_NULL_HANDLE, swapchain->vk_fence, &swapchain->current_buffer);
724 vkWaitForFences(swapchain->vk_device, 1, &swapchain->vk_fence, VK_TRUE, UINT64_MAX);
725 vkResetFences(swapchain->vk_device, 1, &swapchain->vk_fence);
728 void port_swapchain_destroy(struct port_swapchain *swapchain)
730 unsigned int i;
732 swapchain->command_queue->Release();
733 for (i = 0; i < swapchain->buffer_count; ++i)
735 swapchain->buffers[i]->Release();
737 vkDestroyFence(swapchain->vk_device, swapchain->vk_fence, NULL);
738 vkDestroySwapchainKHR(swapchain->vk_device, swapchain->vk_swapchain, NULL);
739 vkDestroySurfaceKHR(swapchain->vk_instance, swapchain->vk_surface, NULL);
740 free(swapchain);
743 struct port_key_map *port_get_key_map(struct port *port)
745 xcb_get_keyboard_mapping_cookie_t cookie;
746 xcb_get_keyboard_mapping_reply_t *reply;
747 const xcb_keysym_t *keysyms;
748 struct port_key_map *map;
749 const xcb_setup_t *setup;
750 size_t i, count;
752 setup = xcb_get_setup(port->connection);
753 count = setup->max_keycode - setup->min_keycode + 1;
754 if (!(map = (typeof(map))malloc(offsetof(typeof(*map), symbols) + count * sizeof(*map->symbols))))
755 return NULL;
757 cookie = xcb_get_keyboard_mapping(port->connection, setup->min_keycode, count);
758 if (!(reply = xcb_get_keyboard_mapping_reply(port->connection, cookie, NULL)))
759 return NULL;
761 map->base = setup->min_keycode;
762 map->count = count;
764 keysyms = xcb_get_keyboard_mapping_keysyms(reply);
765 for (i = 0; i < map->count; ++i)
767 map->symbols[i] = keysyms[i * reply->keysyms_per_keycode];
769 free(reply);
771 return map;
774 bool port_get_key_state(const struct port *port, unsigned int key)
776 return port->keys[key >> 3] & (1 << (key & 0x7));
779 void port_get_mouse_state(struct port *port, struct port_mouse_state *s)
781 *s = port->mouse;
782 memset(&port->mouse, 0, sizeof(port->mouse));