Both demo programs run flawlessly. Unfortunately, the d3d12 test is broken, due to Metal getting an invalid pixel format. This needs investigation and perhaps fixing on the MoltenVK side.
Signed-off-by: Chip Davis cdavis@codeweavers.com --- Makefile.am | 6 +- configure.ac | 21 +- demos/demo.h | 4 + demos/demo_mvk.h | 666 +++++++++++++++++++++++++ libs/vkd3d-utils/vkd3d_utils_main.c | 4 + libs/vkd3d-utils/vkd3d_utils_private.h | 5 + libs/vkd3d/device.c | 10 +- tests/vkd3d_api.c | 16 + 8 files changed, 727 insertions(+), 5 deletions(-) create mode 100644 demos/demo_mvk.h
diff --git a/Makefile.am b/Makefile.am index 4e8f942..fe87f44 100644 --- a/Makefile.am +++ b/Makefile.am @@ -47,6 +47,7 @@ vkd3d_demos = \ vkd3d_demos_headers = \ demos/demo.h \ demos/demo_win32.h \ + demos/demo_mvk.h \ demos/demo_xcb.h
BUILT_SOURCES = $(widl_headers) @@ -131,15 +132,18 @@ TESTS = $(vkd3d_tests) $(vkd3d_cross_tests) tests_d3d12_LDADD = $(LDADD) @PTHREAD_LIBS@ tests_vkd3d_api_LDADD = libvkd3d.la @VULKAN_LIBS@
-DEMOS_LDADD = $(LDADD) libvkd3d-shader.la @XCB_LIBS@ @VULKAN_LIBS@ +DEMOS_LDADD = $(LDADD) libvkd3d-shader.la @XCB_LIBS@ @METAL_LIBS@ @VULKAN_LIBS@ DEMOS_CFLAGS = $(AM_CFLAGS) @XCB_CFLAGS@ +DEMOS_CPPFLAGS = $(AM_CPPFLAGS) @METAL_CPPFLAGS@ noinst_PROGRAMS += $(vkd3d_demos) EXTRA_DIST += $(vkd3d_test_headers) $(vkd3d_demos_headers)
demos_gears_CFLAGS = $(DEMOS_CFLAGS) +demos_gears_CPPFLAGS = $(DEMOS_CPPFLAGS) demos_gears_LDADD = $(DEMOS_LDADD) -lm
demos_triangle_CFLAGS = $(DEMOS_CFLAGS) +demos_triangle_CPPFLAGS = $(DEMOS_CPPFLAGS) demos_triangle_LDADD = $(DEMOS_LDADD)
VKD3D_V_WIDL = $(vkd3d_v_widl_@AM_V@) diff --git a/configure.ac b/configure.ac index 2773a15..c3f5a40 100644 --- a/configure.ac +++ b/configure.ac @@ -77,7 +77,9 @@ AC_CHECK_LIB([pthread], [pthread_create], AC_SUBST([VULKAN_LIBS]) AC_CHECK_LIB([vulkan], [vkGetInstanceProcAddr], [VULKAN_LIBS="-lvulkan"], - [AC_MSG_ERROR([libvulkan not found.])]) + [AC_CHECK_LIB([MoltenVK], [vkGetInstanceProcAddr], + [VULKAN_LIBS="-lMoltenVK"], + [AC_MSG_ERROR([libvulkan and libMoltenVK not found.])])])
HAVE_SPIRV_TOOLS=no AS_IF([test "x$with_spirv_tools" = "xyes"], @@ -85,7 +87,22 @@ AS_IF([test "x$with_spirv_tools" = "xyes"], [AC_DEFINE([HAVE_SPIRV_TOOLS], [1], [Define to 1 if you have SPIRV-Tools.]) HAVE_SPIRV_TOOLS=yes])])
-PKG_CHECK_MODULES([XCB], [xcb xcb-keysyms]) +case $host_os in + darwin*|macosx*) + AC_LANG_PUSH([Objective C]) + AC_CHECK_HEADERS(Metal/Metal.h MoltenVK/vk_mvk_moltenvk.h) + AC_LANG_POP([Objective C]) + if test "x$ac_cv_header_Metal_Metal_h" = xno || + test "x$ac_cv_header_MoltenVK_vk_mvk_moltenvk_h" = xno; then + AC_MSG_ERROR([Metal and MoltenVK required to use vkd3d on Mac OS.]) + fi + AC_SUBST(METAL_LIBS, "-framework CoreFoundation -framework AppKit -framework QuartzCore -framework Metal") + AC_SUBST(METAL_CPPFLAGS, "-x objective-c") + ;; + *) + PKG_CHECK_MODULES([XCB], [xcb xcb-keysyms]) + ;; +esac
dnl Check for functions VKD3D_CHECK_FUNC([HAVE_BUILTIN_CLZ], [__builtin_clz], [__builtin_clz(0)]) diff --git a/demos/demo.h b/demos/demo.h index 2869ea7..de8eae0 100644 --- a/demos/demo.h +++ b/demos/demo.h @@ -143,5 +143,9 @@ static inline HRESULT demo_create_root_signature(ID3D12Device *device, #else #include <vkd3d_utils.h> #define INFINITE VKD3D_INFINITE +#ifdef __APPLE__ +#include "demo_mvk.h" +#else #include "demo_xcb.h" #endif +#endif diff --git a/demos/demo_mvk.h b/demos/demo_mvk.h new file mode 100644 index 0000000..bcf5a4a --- /dev/null +++ b/demos/demo_mvk.h @@ -0,0 +1,666 @@ +/* + * Copyright 2016 Józef Kucia for CodeWeavers + * Copyright 2016 Henri Verbeet for CodeWeavers + * Copyright 2018 Chip Davis for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define VK_USE_PLATFORM_MACOS_MVK +#include <vkd3d.h> +#include <sys/stat.h> +#include <limits.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdbool.h> + +#define BOOL OBJC_BOOL +#undef interface +#include <CoreFoundation/CFRunLoop.h> +#import <Foundation/NSNotification.h> +#import <Foundation/NSString.h> +#import <AppKit/NSApplication.h> +#import <AppKit/NSEvent.h> +#import <AppKit/NSMenu.h> +#import <AppKit/NSWindow.h> +#import <AppKit/NSView.h> +#import <QuartzCore/CAMetalLayer.h> +#import <MoltenVK/vk_mvk_moltenvk.h> +#undef BOOL + +#ifndef __MAC_OS_X_VERSION_10_12 +#define nonnull +#endif + +@class DemoView; + +struct demo +{ + struct demo_window **windows; + size_t windows_size; + size_t window_count; + + void *user_data; + void (*idle_func)(struct demo *demo, void *user_data); +}; + +struct demo_window +{ + NSWindow *window; + DemoView *view; + struct demo *demo; + + void *user_data; + void (*expose_func)(struct demo_window *window, void *user_data); + void (*key_press_func)(struct demo_window *window, demo_key key, void *user_data); +}; + +struct demo_swapchain +{ + VkSurfaceKHR vk_surface; + VkSwapchainKHR vk_swapchain; + VkFence vk_fence; + + VkInstance vk_instance; + VkDevice vk_device; + ID3D12CommandQueue *command_queue; + + uint32_t current_buffer; + unsigned int buffer_count; + ID3D12Resource *buffers[1]; +}; + +static inline bool demo_add_window(struct demo *demo, struct demo_window *window) +{ + if (demo->window_count == demo->windows_size) + { + size_t new_capacity; + void *new_elements; + + new_capacity = max(demo->windows_size * 2, 4); + if (!(new_elements = realloc(demo->windows, new_capacity * sizeof(*demo->windows)))) + return false; + demo->windows = new_elements; + demo->windows_size = new_capacity; + } + + demo->windows[demo->window_count++] = window; + + return true; +} + +static inline void demo_remove_window(struct demo *demo, const struct demo_window *window) +{ + size_t i; + + for (i = 0; i < demo->window_count; ++i) + { + if (demo->windows[i] != window) + continue; + + --demo->window_count; + memmove(&demo->windows[i], &demo->windows[i + 1], (demo->window_count - i) * sizeof(*demo->windows)); + break; + } + + if (!demo->window_count) + /* Time to stop. */ + [NSApp stop:NSApp]; +} + +static inline struct demo_window *demo_find_window(struct demo *demo, NSWindow *window) +{ + size_t i; + + for (i = 0; i < demo->window_count; ++i) + { + if (demo->windows[i]->window == window) + return demo->windows[i]; + } + + return NULL; +} + +static inline struct demo_window *demo_window_create(struct demo *demo, const char *title, + unsigned int width, unsigned int height, void *user_data) +{ + struct demo_window *window; + NSAutoreleasePool *pool; + + if (!(window = malloc(sizeof(*window)))) + return NULL; + + if (!demo_add_window(demo, window)) + { + free(window); + return NULL; + } + + pool = [[NSAutoreleasePool alloc] init]; + window->window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, width, height) + styleMask:NSTitledWindowMask|NSClosableWindowMask| + NSMiniaturizableWindowMask + backing:NSBackingStoreBuffered + defer:YES]; + window->view = nil; + window->demo = demo; + window->user_data = user_data; + window->expose_func = NULL; + window->key_press_func = NULL; + window->window.title = [NSString stringWithCString:title encoding:NSUTF8StringEncoding]; + window->window.opaque = YES; + window->window.releasedWhenClosed = NO; + + [window->window center]; + [window->window makeKeyAndOrderFront:nil]; + + [pool release]; + + return window; +} + +static inline void demo_window_destroy(struct demo_window *window) +{ + if (window->view) + { + [window->view release]; + [NSApp removeWindowsItem:window->window]; + } + [window->window release]; + demo_remove_window(window->demo, window); + free(window); +} + +static inline void demo_window_set_key_press_func(struct demo_window *window, + void (*key_press_func)(struct demo_window *window, demo_key key, void *user_data)) +{ + window->key_press_func = key_press_func; +} + +static inline void demo_window_set_expose_func(struct demo_window *window, + void (*expose_func)(struct demo_window *window, void *user_data)) +{ + window->expose_func = expose_func; +} + +static inline demo_key demo_key_from_nskey(unsigned short code) +{ + static const struct + { + unsigned short code; + demo_key demo_key; + } + lookup[] = + { + {0x35 /*kVK_Escape*/, DEMO_KEY_ESCAPE}, + {0x7B /*kVK_LeftArrow*/, DEMO_KEY_LEFT}, + {0x7C /*kVK_RightArrow*/, DEMO_KEY_RIGHT}, + {0x7E /*kVK_UpArrow*/, DEMO_KEY_UP}, + {0x7D /*kVK_DownArrow*/, DEMO_KEY_DOWN}, + }; + unsigned int i; + + if (code >= '0' && code <= '9') + return code; + if (code >= 'A' && code <= 'Z') + return code; + + for (i = 0; i < ARRAY_SIZE(lookup); ++i) + { + if (lookup[i].code == code) + return lookup[i].demo_key; + } + + return DEMO_KEY_UNKNOWN; +} + +@interface DemoView : NSView <NSWindowDelegate> +{ + struct demo_window *_demo_window; + id<MTLDevice> _device; +} + +- (instancetype)initWithWindow:(struct demo_window *)window device:(id<MTLDevice>)device; + +- (void)windowWillClose:(NSNotification *)notification; + +@end + +@implementation DemoView + +- (instancetype)initWithWindow:(struct demo_window *)window device:(id<MTLDevice>)device +{ + NSRect content_rect; + + content_rect = [window->window contentRectForFrameRect:window->window.frame]; + self = [super initWithFrame:content_rect]; + if (self) + { + _demo_window = window; + _device = [device retain]; + self.wantsLayer = YES; + self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawNever; + } + return self; +} + +- (void)dealloc +{ + [_device release]; + [super dealloc]; +} + +- (OBJC_BOOL)acceptsFirstResponder +{ + return YES; +} + +- (void)keyDown:(NSEvent *)event +{ + demo_key sym; + + [super keyDown:event]; + if (!_demo_window->key_press_func) + return; + sym = demo_key_from_nskey(event.keyCode); + _demo_window->key_press_func(_demo_window, sym, _demo_window->user_data); +} + +- (void)viewWillDraw +{ + if (_demo_window->expose_func) + _demo_window->expose_func(_demo_window, _demo_window->user_data); +} + +- (CALayer *)makeBackingLayer +{ + CAMetalLayer *layer = [CAMetalLayer layer]; + layer.device = _device; + layer.framebufferOnly = YES; + layer.magnificationFilter = kCAFilterNearest; + layer.backgroundColor = CGColorGetConstantColor(kCGColorBlack); + return layer; +} + +- (OBJC_BOOL)isOpaque +{ + return YES; +} + +- (void)windowWillClose:(NSNotification *)notification +{ + demo_window_destroy(_demo_window); +} + +@end + +static inline void demo_process_events(struct demo *demo) +{ + NSAutoreleasePool *pool; + + if (demo->idle_func) + { + /* Stick a timer on the main run loop that will call the + * idle function every 1 ms. */ + CFRunLoopTimerRef timer = CFRunLoopTimerCreateWithHandler(NULL, 0.0, 0.001, 0, 0, ^(CFRunLoopTimerRef timer){ + demo->idle_func(demo, demo->user_data); + }); + CFRunLoopAddTimer(CFRunLoopGetMain(), timer, kCFRunLoopCommonModes); + } + pool = [[NSAutoreleasePool alloc] init]; + [NSApp run]; + [pool release]; +} + +static inline bool demo_init(struct demo *demo, void *user_data) +{ + NSMenu *mainMenu, *submenu; + NSMenuItem *item; + + [NSApplication sharedApplication]; + NSApp.activationPolicy = NSApplicationActivationPolicyRegular; + + mainMenu = [[NSMenu alloc] init]; + /* App menu */ + submenu = [[NSMenu alloc] initWithTitle:@"VKD3D Demo"]; + item = [submenu addItemWithTitle:@"Hide" action:@selector(hide:) keyEquivalent:@"h"]; + item.keyEquivalentModifierMask = NSCommandKeyMask; + item = [submenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; + item.keyEquivalentModifierMask = NSCommandKeyMask | NSAlternateKeyMask; + [submenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; + [submenu addItem:[NSMenuItem separatorItem]]; + item = [submenu addItemWithTitle:@"Quit" action:@selector(terminate:) keyEquivalent:@"q"]; + item.keyEquivalentModifierMask = NSCommandKeyMask; + + item = [[NSMenuItem alloc] init]; + item.title = @"VKD3D Demo"; + item.submenu = submenu; + [mainMenu addItem:item]; + [submenu release]; + [item release]; + + /* Window menu */ + submenu = [[NSMenu alloc] initWithTitle:@"Window"]; + item = [submenu addItemWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"]; + item.keyEquivalentModifierMask = NSCommandKeyMask; + [submenu addItem:[NSMenuItem separatorItem]]; + [submenu addItemWithTitle:@"Bring All to Front" action:@selector(arrangeInFront:) keyEquivalent:@""]; + + item = [[NSMenuItem alloc] init]; + item.title = @"Window"; + item.submenu = submenu; + [mainMenu addItem:item]; + [item release]; + + NSApp.mainMenu = mainMenu; + NSApp.windowsMenu = submenu; + [submenu release]; + + demo->windows = NULL; + demo->windows_size = 0; + demo->window_count = 0; + demo->user_data = user_data; + demo->idle_func = NULL; + + return true; +} + +static inline void demo_cleanup(struct demo *demo) +{ + free(demo->windows); +} + +static inline void demo_set_idle_func(struct demo *demo, + void (*idle_func)(struct demo *demo, void *user_data)) +{ + demo->idle_func = idle_func; +} + +static inline struct demo_swapchain *demo_swapchain_create(ID3D12CommandQueue *command_queue, + struct demo_window *window, const struct demo_swapchain_desc *desc) +{ + struct vkd3d_image_resource_create_info resource_create_info; + struct VkSwapchainCreateInfoKHR vk_swapchain_desc; + struct VkMacOSSurfaceCreateInfoMVK surface_desc; + VkSwapchainKHR vk_swapchain = VK_NULL_HANDLE; + uint32_t format_count, queue_family_index; + VkSurfaceCapabilitiesKHR surface_caps; + VkPhysicalDevice vk_physical_device; + VkFence vk_fence = VK_NULL_HANDLE; + struct demo_swapchain *swapchain; + unsigned int image_count, i, j; + VkFenceCreateInfo fence_desc; + VkSurfaceFormatKHR *formats; + ID3D12Device *d3d12_device; + VkSurfaceKHR vk_surface; + VkInstance vk_instance; + VkBool32 supported; + VkDevice vk_device; + VkImage *vk_images; + VkFormat format; + id<MTLDevice> mtl_device; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + if ((format = vkd3d_get_vk_format(desc->format)) == VK_FORMAT_UNDEFINED) + { + [pool release]; + return NULL; + } + + if (FAILED(ID3D12CommandQueue_GetDevice(command_queue, &IID_ID3D12Device, (void **)&d3d12_device))) + { + [pool release]; + return NULL; + } + + vk_instance = vkd3d_instance_get_vk_instance(vkd3d_instance_from_device(d3d12_device)); + vk_physical_device = vkd3d_get_vk_physical_device(d3d12_device); + vk_device = vkd3d_get_vk_device(d3d12_device); + vkGetMTLDeviceMVK(vk_physical_device, &mtl_device); + + window->view = [[DemoView alloc] initWithWindow:window device:mtl_device]; + window->window.initialFirstResponder = window->view; + window->window.contentView = window->view; + window->window.delegate = window->view; + [NSApp addWindowsItem:window->window title:window->window.title filename:NO]; + + surface_desc.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK; + surface_desc.pNext = NULL; + surface_desc.flags = 0; + surface_desc.pView = window->view; + if (vkCreateMacOSSurfaceMVK(vk_instance, &surface_desc, NULL, &vk_surface) < 0) + { + ID3D12Device_Release(d3d12_device); + [pool release]; + return NULL; + } + + queue_family_index = vkd3d_get_vk_queue_family_index(command_queue); + if (vkGetPhysicalDeviceSurfaceSupportKHR(vk_physical_device, + queue_family_index, vk_surface, &supported) < 0 || !supported) + goto fail; + + if (vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vk_physical_device, vk_surface, &surface_caps) < 0) + goto fail; + + if ((surface_caps.maxImageCount && desc->buffer_count > surface_caps.maxImageCount) + || desc->buffer_count < surface_caps.minImageCount + || desc->width > surface_caps.maxImageExtent.width || desc->width < surface_caps.minImageExtent.width + || desc->height > surface_caps.maxImageExtent.height || desc->height < surface_caps.minImageExtent.height + || !(surface_caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR)) + goto fail; + + if (vkGetPhysicalDeviceSurfaceFormatsKHR(vk_physical_device, vk_surface, &format_count, NULL) < 0 + || !format_count || !(formats = calloc(format_count, sizeof(*formats)))) + goto fail; + + if (vkGetPhysicalDeviceSurfaceFormatsKHR(vk_physical_device, vk_surface, &format_count, formats) < 0) + { + free(formats); + goto fail; + } + + if (format_count != 1 || formats->format != VK_FORMAT_UNDEFINED + || formats->colorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) + { + for (i = 0; i < format_count; ++i) + { + if (formats[i].format == format && formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) + break; + } + + if (i == format_count) + { + free(formats); + goto fail; + } + } + + free(formats); + formats = NULL; + + vk_swapchain_desc.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + vk_swapchain_desc.pNext = NULL; + vk_swapchain_desc.flags = 0; + vk_swapchain_desc.surface = vk_surface; + vk_swapchain_desc.minImageCount = desc->buffer_count; + vk_swapchain_desc.imageFormat = format; + vk_swapchain_desc.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; + vk_swapchain_desc.imageExtent.width = desc->width; + vk_swapchain_desc.imageExtent.height = desc->height; + vk_swapchain_desc.imageArrayLayers = 1; + vk_swapchain_desc.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + vk_swapchain_desc.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + vk_swapchain_desc.queueFamilyIndexCount = 0; + vk_swapchain_desc.pQueueFamilyIndices = NULL; + vk_swapchain_desc.preTransform = surface_caps.currentTransform; + vk_swapchain_desc.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + vk_swapchain_desc.presentMode = VK_PRESENT_MODE_FIFO_KHR; + vk_swapchain_desc.clipped = VK_TRUE; + vk_swapchain_desc.oldSwapchain = VK_NULL_HANDLE; + if (vkCreateSwapchainKHR(vk_device, &vk_swapchain_desc, NULL, &vk_swapchain) < 0) + goto fail; + + fence_desc.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fence_desc.pNext = NULL; + fence_desc.flags = 0; + if (vkCreateFence(vk_device, &fence_desc, NULL, &vk_fence) < 0) + goto fail; + + if (vkGetSwapchainImagesKHR(vk_device, vk_swapchain, &image_count, NULL) < 0 + || !(vk_images = calloc(image_count, sizeof(*vk_images)))) + goto fail; + + if (vkGetSwapchainImagesKHR(vk_device, vk_swapchain, &image_count, vk_images) < 0) + { + free(vk_images); + goto fail; + } + + if (!(swapchain = malloc(offsetof(struct demo_swapchain, buffers[image_count])))) + { + free(vk_images); + goto fail; + } + swapchain->vk_surface = vk_surface; + swapchain->vk_swapchain = vk_swapchain; + swapchain->vk_fence = vk_fence; + swapchain->vk_instance = vk_instance; + swapchain->vk_device = vk_device; + + vkAcquireNextImageKHR(vk_device, vk_swapchain, UINT64_MAX, + VK_NULL_HANDLE, vk_fence, &swapchain->current_buffer); + vkWaitForFences(vk_device, 1, &vk_fence, VK_TRUE, UINT64_MAX); + vkResetFences(vk_device, 1, &vk_fence); + + resource_create_info.type = VKD3D_STRUCTURE_TYPE_IMAGE_RESOURCE_CREATE_INFO; + resource_create_info.next = NULL; + resource_create_info.desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; + resource_create_info.desc.Alignment = 0; + resource_create_info.desc.Width = desc->width; + resource_create_info.desc.Height = desc->height; + resource_create_info.desc.DepthOrArraySize = 1; + resource_create_info.desc.MipLevels = 1; + resource_create_info.desc.Format = desc->format; + resource_create_info.desc.SampleDesc.Count = 1; + resource_create_info.desc.SampleDesc.Quality = 0; + resource_create_info.desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; + resource_create_info.desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; + resource_create_info.flags = VKD3D_RESOURCE_INITIAL_STATE_TRANSITION | VKD3D_RESOURCE_PRESENT_STATE_TRANSITION; + resource_create_info.present_state = D3D12_RESOURCE_STATE_PRESENT; + for (i = 0; i < image_count; ++i) + { + resource_create_info.vk_image = vk_images[i]; + if (FAILED(vkd3d_create_image_resource(d3d12_device, &resource_create_info, &swapchain->buffers[i]))) + { + for (j = 0; j < i; ++j) + { + ID3D12Resource_Release(swapchain->buffers[j]); + } + free(swapchain); + free(vk_images); + goto fail; + } + } + swapchain->buffer_count = image_count; + free(vk_images); + ID3D12Device_Release(d3d12_device); + + ID3D12CommandQueue_AddRef(swapchain->command_queue = command_queue); + + [pool release]; + + return swapchain; + +fail: + if (vk_fence != VK_NULL_HANDLE) + vkDestroyFence(vk_device, vk_fence, NULL); + if (vk_swapchain != VK_NULL_HANDLE) + vkDestroySwapchainKHR(vk_device, vk_swapchain, NULL); + vkDestroySurfaceKHR(vk_instance, vk_surface, NULL); + ID3D12Device_Release(d3d12_device); + [pool release]; + return NULL; +} + +static inline unsigned int demo_swapchain_get_current_back_buffer_index(struct demo_swapchain *swapchain) +{ + return swapchain->current_buffer; +} + +static inline ID3D12Resource *demo_swapchain_get_back_buffer(struct demo_swapchain *swapchain, unsigned int index) +{ + ID3D12Resource *resource = NULL; + + if (index < swapchain->buffer_count && (resource = swapchain->buffers[index])) + ID3D12Resource_AddRef(resource); + + return resource; +} + +static inline void demo_swapchain_present(struct demo_swapchain *swapchain) +{ + VkPresentInfoKHR present_desc; + VkQueue vk_queue; + + present_desc.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + present_desc.pNext = NULL; + present_desc.waitSemaphoreCount = 0; + present_desc.pWaitSemaphores = NULL; + present_desc.swapchainCount = 1; + present_desc.pSwapchains = &swapchain->vk_swapchain; + present_desc.pImageIndices = &swapchain->current_buffer; + present_desc.pResults = NULL; + + vk_queue = vkd3d_acquire_vk_queue(swapchain->command_queue); + vkQueuePresentKHR(vk_queue, &present_desc); + vkd3d_release_vk_queue(swapchain->command_queue); + + vkAcquireNextImageKHR(swapchain->vk_device, swapchain->vk_swapchain, UINT64_MAX, + VK_NULL_HANDLE, swapchain->vk_fence, &swapchain->current_buffer); + vkWaitForFences(swapchain->vk_device, 1, &swapchain->vk_fence, VK_TRUE, UINT64_MAX); + vkResetFences(swapchain->vk_device, 1, &swapchain->vk_fence); +} + +static inline void demo_swapchain_destroy(struct demo_swapchain *swapchain) +{ + unsigned int i; + + ID3D12CommandQueue_Release(swapchain->command_queue); + for (i = 0; i < swapchain->buffer_count; ++i) + { + ID3D12Resource_Release(swapchain->buffers[i]); + } + vkDestroyFence(swapchain->vk_device, swapchain->vk_fence, NULL); + vkDestroySwapchainKHR(swapchain->vk_device, swapchain->vk_swapchain, NULL); + vkDestroySurfaceKHR(swapchain->vk_instance, swapchain->vk_surface, NULL); + free(swapchain); +} + +static inline HANDLE demo_create_event(void) +{ + return vkd3d_create_event(); +} + +static inline unsigned int demo_wait_event(HANDLE event, unsigned int ms) +{ + return vkd3d_wait_event(event, ms); +} + +static inline void demo_destroy_event(HANDLE event) +{ + vkd3d_destroy_event(event); +} + diff --git a/libs/vkd3d-utils/vkd3d_utils_main.c b/libs/vkd3d-utils/vkd3d_utils_main.c index 2c4d89a..fce7cf7 100644 --- a/libs/vkd3d-utils/vkd3d_utils_main.c +++ b/libs/vkd3d-utils/vkd3d_utils_main.c @@ -34,7 +34,11 @@ HRESULT WINAPI D3D12CreateDevice(IUnknown *adapter, static const char * const instance_extensions[] = { VK_KHR_SURFACE_EXTENSION_NAME, +#ifdef __APPLE__ + VK_MVK_MACOS_SURFACE_EXTENSION_NAME, +#else VK_KHR_XCB_SURFACE_EXTENSION_NAME, +#endif }; static const char * const device_extensions[] = { diff --git a/libs/vkd3d-utils/vkd3d_utils_private.h b/libs/vkd3d-utils/vkd3d_utils_private.h index 6aa0df6..a59f471 100644 --- a/libs/vkd3d-utils/vkd3d_utils_private.h +++ b/libs/vkd3d-utils/vkd3d_utils_private.h @@ -20,7 +20,12 @@ #define __VKD3D_UTILS_PRIVATE_H
#define VK_NO_PROTOTYPES + +#ifdef __APPLE__ +#define VK_USE_PLATFORM_MACOS_MVK +#else #define VK_USE_PLATFORM_XCB_KHR +#endif
#include <pthread.h> #include <vkd3d.h> diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c index 6fa0017..0052eba 100644 --- a/libs/vkd3d/device.c +++ b/libs/vkd3d/device.c @@ -205,6 +205,12 @@ static HRESULT vkd3d_init_instance_caps(struct vkd3d_instance *instance, return S_OK; }
+#ifdef HAVE_MOLTENVK_VK_MVK_MOLTENVK_H +#define VULKAN_SO_NAME "libMoltenVK.dylib" +#else +#define VULKAN_SO_NAME "libvulkan.so.1" +#endif + static HRESULT vkd3d_init_vk_global_procs(struct vkd3d_instance *instance, PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr) { @@ -212,9 +218,9 @@ static HRESULT vkd3d_init_vk_global_procs(struct vkd3d_instance *instance,
if (!vkGetInstanceProcAddr) { - if (!(instance->libvulkan = dlopen("libvulkan.so.1", RTLD_NOW))) + if (!(instance->libvulkan = dlopen(VULKAN_SO_NAME, RTLD_NOW))) { - ERR("Failed to load libvulkan.\n"); + ERR("Failed to load libvulkan: %s\n", dlerror()); return E_FAIL; }
diff --git a/tests/vkd3d_api.c b/tests/vkd3d_api.c index e2d9d01..3980b4e 100644 --- a/tests/vkd3d_api.c +++ b/tests/vkd3d_api.c @@ -19,8 +19,12 @@ #define COBJMACROS #define INITGUID #define WIDL_C_INLINE_WRAPPERS +#ifdef __APPLE__ +#define VK_USE_PLATFORM_MACOS_MVK +#else #define VK_USE_PLATFORM_XCB_KHR #define VK_USE_PLATFORM_XLIB_KHR +#endif #include "vkd3d_test.h" #include <vkd3d.h>
@@ -215,8 +219,12 @@ static void test_additional_instance_extensions(void) struct vulkan_extension extensions[] = { {VK_KHR_SURFACE_EXTENSION_NAME}, +#ifdef __APPLE__ + {VK_MVK_MACOS_SURFACE_EXTENSION_NAME}, +#else {VK_KHR_XCB_SURFACE_EXTENSION_NAME}, {VK_KHR_XLIB_SURFACE_EXTENSION_NAME}, +#endif };
const char *enabled_extensions[ARRAY_SIZE(extensions)]; @@ -249,6 +257,13 @@ static void test_additional_instance_extensions(void) if (!extensions[i].is_supported) continue;
+#ifdef __APPLE__ + if (!strcmp(extensions[i].name, VK_MVK_MACOS_SURFACE_EXTENSION_NAME)) + { + pfn = vkGetInstanceProcAddr(vk_instance, "vkCreateMacOSSurfaceMVK"); + ok(pfn, "Failed to get proc addr for vkCreateMacOSSurfaceMVK.\n"); + } +#else if (!strcmp(extensions[i].name, VK_KHR_XCB_SURFACE_EXTENSION_NAME)) { pfn = vkGetInstanceProcAddr(vk_instance, "vkCreateXcbSurfaceKHR"); @@ -259,6 +274,7 @@ static void test_additional_instance_extensions(void) pfn = vkGetInstanceProcAddr(vk_instance, "vkCreateXlibSurfaceKHR"); ok(pfn, "Failed to get proc addr for vkCreateXlibSurfaceKHR.\n"); } +#endif }
refcount = vkd3d_instance_decref(instance);