summaryrefslogtreecommitdiff
path: root/src/common/vulkan.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/vulkan.c')
-rw-r--r--src/common/vulkan.c223
1 files changed, 178 insertions, 45 deletions
diff --git a/src/common/vulkan.c b/src/common/vulkan.c
index 62bc3a0..77a4dd4 100644
--- a/src/common/vulkan.c
+++ b/src/common/vulkan.c
@@ -20,69 +20,202 @@
#endif
static PFN_vkGetInstanceProcAddr get_proc;
static bool portability;
-void yasl_private_vulkan_reset(void) { get_proc=NULL; portability=false; }
-bool yasl_vulkan_init(PFN_vkGetInstanceProcAddr loader)
+void yasl_private_vulkan_reset(void)
{
- if(!loader)return yasl_public_fail(EINVAL);
- get_proc=loader;portability=false;
- PFN_vkEnumerateInstanceExtensionProperties enumerate=(PFN_vkEnumerateInstanceExtensionProperties)get_proc(VK_NULL_HANDLE,"vkEnumerateInstanceExtensionProperties");
- if(!enumerate)return yasl_public_fail(ENOTSUP);
- uint32_t count=0;VkResult r=enumerate(NULL,&count,NULL);
- if(r!=VK_SUCCESS)return yasl_public_fail(EIO);
- VkExtensionProperties *ext=count?calloc(count,sizeof(*ext)):NULL;
- if(count&&!ext)return yasl_public_fail(ENOMEM);
- r=enumerate(NULL,&count,ext);
- if(r==VK_SUCCESS)for(uint32_t i=0;i<count;i++)if(!strcmp(ext[i].extensionName,"VK_KHR_portability_enumeration"))portability=true;
- free(ext);return r==VK_SUCCESS||yasl_public_fail(EIO);
+ get_proc = NULL;
+ portability = false;
}
-const char *const *yasl_vulkan_instance_extensions(const yasl_surface *s,uint32_t *count)
+struct yasl_vulkan_binding {
+ VkInstance instance;
+ VkSurfaceKHR surface;
+ VkAllocationCallbacks allocator;
+ bool has_allocator;
+ PFN_vkDestroySurfaceKHR destroy;
+};
+int yasl_vulkan_init(PFN_vkGetInstanceProcAddr loader)
{
- static const char *wayland[]={"VK_KHR_surface","VK_KHR_wayland_surface"};
- static const char *x11[]={"VK_KHR_surface","VK_KHR_xlib_surface"};
- static const char *metal[]={"VK_KHR_surface","VK_EXT_metal_surface","VK_KHR_portability_enumeration"};
- if(count)*count=0;
- if(!s||!count||s->presenter==YASL_PRIVATE_PRESENTER_CPU||s->presenter==YASL_PRIVATE_PRESENTER_GL){yasl_public_fail(EINVAL);return NULL;}
- switch(s->display->ops->type) {
- case YASL_PRIVATE_BACKEND_WAYLAND:*count=2;return wayland;
- case YASL_PRIVATE_BACKEND_X11:*count=2;return x11;
- case YASL_PRIVATE_BACKEND_COCOA:*count=portability?3:2;return metal;
- default:yasl_public_fail(ENOTSUP);return NULL;
+ struct yasl_private_display *d = yasl_public_display();
+ if (d && !yasl_public_owner())
+ return -errno;
+ if (!loader)
+ return yasl_public_error(EINVAL);
+ if (d)
+ for (yasl_surface *s = d->surfaces; s; s = s->event_next)
+ if (s->vulkan)
+ return yasl_public_error(EBUSY);
+ PFN_vkEnumerateInstanceExtensionProperties enumerate =
+ (PFN_vkEnumerateInstanceExtensionProperties)loader(
+ VK_NULL_HANDLE, "vkEnumerateInstanceExtensionProperties");
+ if (!enumerate)
+ return yasl_public_error(ENOTSUP);
+ uint32_t count = 0;
+ VkResult result = enumerate(NULL, &count, NULL);
+ if (result != VK_SUCCESS)
+ return yasl_public_error(EIO);
+ VkExtensionProperties *ext = count ? calloc(count, sizeof(*ext)) : NULL;
+ if (count && !ext)
+ return yasl_public_error(ENOMEM);
+ bool next_portability = false;
+ if (count)
+ result = enumerate(NULL, &count, ext);
+ if (result == VK_SUCCESS)
+ for (uint32_t i = 0; i < count; i++)
+ if (!strcmp(ext[i].extensionName, "VK_KHR_portability_enumeration"))
+ next_portability = true;
+ free(ext);
+ if (result != VK_SUCCESS)
+ return yasl_public_error(EIO);
+ get_proc = loader;
+ portability = next_portability;
+ return 0;
+}
+int yasl_vulkan_get_requirements(const yasl_surface *s, struct yasl_vulkan_requirements *out)
+{
+ static const char *const wayland[] = {"VK_KHR_surface", "VK_KHR_wayland_surface"};
+ static const char *const x11[] = {"VK_KHR_surface", "VK_KHR_xlib_surface"};
+ static const char *const metal[] = {"VK_KHR_surface", "VK_EXT_metal_surface",
+ "VK_KHR_portability_enumeration"};
+ if (!out)
+ return yasl_public_error(EINVAL);
+ *out = (struct yasl_vulkan_requirements){0};
+ if (!yasl_public_surface((yasl_surface *)s, false))
+ return -errno;
+ if (!get_proc)
+ return yasl_public_error(ENODEV);
+ if (s->presenter != YASL_PRIVATE_PRESENTER_NONE &&
+ s->presenter != YASL_PRIVATE_PRESENTER_VULKAN)
+ return yasl_public_error(EBUSY);
+ switch (s->display->ops->type) {
+ case YASL_PRIVATE_BACKEND_WAYLAND:
+ out->extensions = wayland;
+ out->extension_count = 2;
+ break;
+ case YASL_PRIVATE_BACKEND_X11:
+ out->extensions = x11;
+ out->extension_count = 2;
+ break;
+ case YASL_PRIVATE_BACKEND_COCOA:
+ out->extensions = metal;
+ out->extension_count = portability ? 3 : 2;
+ out->flags = portability ? VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR : 0;
+ break;
+ default:
+ return yasl_public_error(ENOTSUP);
}
+ return 0;
+}
+int yasl_vulkan_destroy_surface(yasl_surface *s)
+{
+ if (!yasl_public_surface(s, true))
+ return -errno;
+ struct yasl_vulkan_binding *binding = s->vulkan;
+ if (!binding)
+ return 0;
+ binding->destroy(binding->instance, binding->surface,
+ binding->has_allocator ? &binding->allocator : NULL);
+ free(binding);
+ s->vulkan = NULL;
+ s->presenter = YASL_PRIVATE_PRESENTER_NONE;
+ return 0;
}
-VkInstanceCreateFlags yasl_vulkan_instance_flags(const yasl_surface *s)
-{ return s&&s->display->ops->type==YASL_PRIVATE_BACKEND_COCOA&&portability?VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR:0; }
-VkResult yasl_vulkan_create_surface(yasl_surface *s,VkInstance instance,const VkAllocationCallbacks *allocator,VkSurfaceKHR *out)
+VkResult yasl_vulkan_create_surface(yasl_surface *s, VkInstance instance,
+ const VkAllocationCallbacks *allocator, VkSurfaceKHR *out)
{
- if(out)*out=VK_NULL_HANDLE;
- if(!yasl_public_surface(s,false)||!instance||!out||!get_proc){yasl_public_fail(EINVAL);return VK_ERROR_INITIALIZATION_FAILED;}
- if(s->display->offline){yasl_public_fail(ENOTCONN);return VK_ERROR_SURFACE_LOST_KHR;}
- if(s->presenter!=YASL_PRIVATE_PRESENTER_NONE){yasl_public_fail(EBUSY);return VK_ERROR_NATIVE_WINDOW_IN_USE_KHR;}
- VkResult result=VK_ERROR_EXTENSION_NOT_PRESENT;
- switch(s->display->ops->type) {
+ if (out)
+ *out = VK_NULL_HANDLE;
+ if (!yasl_public_surface(s, true))
+ return VK_ERROR_INITIALIZATION_FAILED;
+ if (!instance || !out) {
+ yasl_public_fail(EINVAL);
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+ if (!get_proc) {
+ yasl_public_fail(ENODEV);
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+ if (s->display->offline) {
+ yasl_public_fail(ENOTCONN);
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
+ if (s->vulkan || s->presenter != YASL_PRIVATE_PRESENTER_NONE) {
+ yasl_public_fail(EBUSY);
+ return VK_ERROR_NATIVE_WINDOW_IN_USE_KHR;
+ }
+ PFN_vkDestroySurfaceKHR destroy =
+ (PFN_vkDestroySurfaceKHR)get_proc(instance, "vkDestroySurfaceKHR");
+ if (!destroy) {
+ yasl_public_fail(ENOTSUP);
+ return VK_ERROR_EXTENSION_NOT_PRESENT;
+ }
+ struct yasl_vulkan_binding *binding = calloc(1, sizeof(*binding));
+ if (!binding) {
+ yasl_public_fail(ENOMEM);
+ return VK_ERROR_OUT_OF_HOST_MEMORY;
+ }
+ VkResult result = VK_ERROR_EXTENSION_NOT_PRESENT;
+ switch (s->display->ops->type) {
#if YASL_HAS_WAYLAND
case YASL_PRIVATE_BACKEND_WAYLAND: {
- PFN_vkCreateWaylandSurfaceKHR create=(PFN_vkCreateWaylandSurfaceKHR)get_proc(instance,"vkCreateWaylandSurfaceKHR");
- if(create) { VkWaylandSurfaceCreateInfoKHR info={.sType=VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR,
- .display=yasl_wayland_display(s),.surface=yasl_wayland_surface(s)};result=create(instance,&info,allocator,out); }break;
+ struct yasl_wayland_handles native;
+ if (yasl_wayland_get_native(s, &native) < 0)
+ break;
+ PFN_vkCreateWaylandSurfaceKHR create =
+ (PFN_vkCreateWaylandSurfaceKHR)get_proc(instance, "vkCreateWaylandSurfaceKHR");
+ if (create) {
+ VkWaylandSurfaceCreateInfoKHR info = {
+ .sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR,
+ .display = native.display,
+ .surface = native.surface};
+ result = create(instance, &info, allocator, out);
+ }
+ break;
}
#endif
#if YASL_HAS_X11
case YASL_PRIVATE_BACKEND_X11: {
- PFN_vkCreateXlibSurfaceKHR create=(PFN_vkCreateXlibSurfaceKHR)get_proc(instance,"vkCreateXlibSurfaceKHR");
- if(create) { VkXlibSurfaceCreateInfoKHR info={.sType=VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR,
- .dpy=yasl_x11_display(s),.window=(Window)yasl_x11_window(s)};result=create(instance,&info,allocator,out); }break;
+ struct yasl_x11_handles native;
+ if (yasl_x11_get_native(s, &native) < 0)
+ break;
+ PFN_vkCreateXlibSurfaceKHR create =
+ (PFN_vkCreateXlibSurfaceKHR)get_proc(instance, "vkCreateXlibSurfaceKHR");
+ if (create) {
+ VkXlibSurfaceCreateInfoKHR info = {.sType =
+ VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR,
+ .dpy = native.display,
+ .window = (Window)native.window};
+ result = create(instance, &info, allocator, out);
+ }
+ break;
}
#endif
#if YASL_HAS_COCOA
case YASL_PRIVATE_BACKEND_COCOA: {
- PFN_vkCreateMetalSurfaceEXT create=(PFN_vkCreateMetalSurfaceEXT)get_proc(instance,"vkCreateMetalSurfaceEXT");
- if(create&&s->display->ops->surface_get_metal_layer) { VkMetalSurfaceCreateInfoEXT info={.sType=VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT,
- .pLayer=s->display->ops->surface_get_metal_layer(s)};result=create(instance,&info,allocator,out); }break;
+ PFN_vkCreateMetalSurfaceEXT create =
+ (PFN_vkCreateMetalSurfaceEXT)get_proc(instance, "vkCreateMetalSurfaceEXT");
+ if (create && s->display->ops->surface_get_metal_layer) {
+ VkMetalSurfaceCreateInfoEXT info = {
+ .sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT,
+ .pLayer = s->display->ops->surface_get_metal_layer(s)};
+ result = create(instance, &info, allocator, out);
+ }
+ break;
}
#endif
- default:break;
+ default:
+ break;
+ }
+ if (result == VK_SUCCESS) {
+ binding->instance = instance;
+ binding->surface = *out;
+ binding->destroy = destroy;
+ binding->has_allocator = allocator != NULL;
+ if (allocator)
+ binding->allocator = *allocator;
+ s->vulkan = binding;
+ s->presenter = YASL_PRIVATE_PRESENTER_VULKAN;
+ } else {
+ free(binding);
+ yasl_public_fail(result == VK_ERROR_EXTENSION_NOT_PRESENT ? ENOTSUP : EIO);
}
- if(result==VK_SUCCESS)s->presenter=YASL_PRIVATE_PRESENTER_VULKAN;
- else yasl_public_fail(result==VK_ERROR_EXTENSION_NOT_PRESENT?ENOTSUP:EIO);
return result;
}