From 1ab3e5a123109704789c2768e11a4f9af515821d Mon Sep 17 00:00:00 2001 From: Berke Güzel Date: Wed, 14 Oct 2026 13:13:52 +0300 Subject: Redefine public and rendering APIs with explicit contracts --- src/common/vulkan.c | 223 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 178 insertions(+), 45 deletions(-) (limited to 'src/common/vulkan.c') 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;ipresenter==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; } -- cgit v1.2.3