summaryrefslogtreecommitdiff
path: root/src/common/vulkan.c
blob: 62bc3a08c6765acbf6c52c9ec61ba389d853e23b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#if YASL_HAS_WAYLAND
#define VK_USE_PLATFORM_WAYLAND_KHR
#endif
#if YASL_HAS_X11
#define VK_USE_PLATFORM_XLIB_KHR
#endif
#if YASL_HAS_COCOA
#define VK_USE_PLATFORM_METAL_EXT
#endif
#include "yasl/vulkan.h"
#include "public_internal.h"
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#if YASL_HAS_WAYLAND
#include "yasl/native/wayland.h"
#endif
#if YASL_HAS_X11
#include "yasl/native/x11.h"
#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)
{
    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);
}
const char *const *yasl_vulkan_instance_extensions(const yasl_surface *s,uint32_t *count)
{
    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;
    }
}
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)
{
    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 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;
    }
#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;
    }
#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;
    }
#endif
    default:break;
    }
    if(result==VK_SUCCESS)s->presenter=YASL_PRIVATE_PRESENTER_VULKAN;
    else yasl_public_fail(result==VK_ERROR_EXTENSION_NOT_PRESENT?ENOTSUP:EIO);
    return result;
}