This commit is contained in:
2026-03-23 21:18:57 +01:00
committed by kbz_8
parent 2751206578
commit 564942ad35
11 changed files with 390 additions and 30 deletions

View File

@@ -47,7 +47,6 @@ namespace mlx
std::unordered_map<std::string, std::pair<std::size_t, ProfileResult>> m_profile_data;
std::ofstream m_output_stream;
std::mutex m_mutex;
bool m_runtime_session_began = false;
};

View File

@@ -20,7 +20,6 @@ namespace mlx
void SetInputBinding(std::function<void(SDL_Event*)> functor);
VkSurfaceKHR CreateVulkanSurface(Handle window, VkInstance instance) const noexcept;
std::vector<const char*> GetRequiredVulkanInstanceExtentions(Handle window) const noexcept;
Vec2ui GetVulkanDrawableSize(Handle window) const noexcept;
void MoveMouseOnWindow(Handle window, int x, int y) const noexcept;
void GetScreenSizeWindowIsOn(Handle window, int* x, int* y) const noexcept;

View File

@@ -35,7 +35,6 @@ namespace mlx
MLX_FORCEINLINE void GetSize(int* x, int* y) { *x = GetWidth(); *y = GetHeight(); }
MLX_FORCEINLINE VkSurfaceKHR CreateVulkanSurface(VkInstance instance) const noexcept { return SDLManager::Get().CreateVulkanSurface(p_window, instance); }
MLX_FORCEINLINE std::vector<const char*> GetRequiredVulkanInstanceExtentions() const noexcept { return SDLManager::Get().GetRequiredVulkanInstanceExtentions(p_window); }
MLX_FORCEINLINE Vec2ui GetVulkanDrawableSize() const noexcept { return SDLManager::Get().GetVulkanDrawableSize(p_window); }
[[nodiscard]] inline Handle GetRawHandle() const noexcept { return p_window; }

View File

@@ -25,12 +25,12 @@
#error Failed to find SDL2 headers
#endif
#if __has_include(<SDL2/SDL_vulkan.h>)
#include <SDL2/SDL_vulkan.h>
#elif __has_include(<SDL_vulkan.h>)
#include <SDL_vulkan.h>
#if __has_include(<SDL2/SDL_syswm.h>)
#include <SDL2/SDL_syswm.h>
#elif __has_include(<SDL_syswm.h>)
#include <SDL_syswm.h>
#else
#error Failed to find SDL2 Vulkan headers
#error Failed to find SDL2 SysWMinfo
#endif
#include <functional>

56
runtime/Includes/Renderer/Surface.h git.filemode.normal_file
View File

@@ -0,0 +1,56 @@
#ifndef __MLX_SURFACE__
#define __MLX_SURFACE__
#include <Utils/NonOwningPtr.h>
#include <Renderer/Image.h>
namespace mlx
{
class Surface
{
public:
Surface() = default;
void Init(NonOwningPtr<class Window> window);
void Destroy();
[[nodiscard]] inline VkSurfaceKHR Get() const noexcept { return m_surface; }
~Surface() = default;
private:
#ifdef VK_USE_PLATFORM_ANDROID_KHR
// VK_KHR_android_surface
void Create(ANativeWindow* window, VkAndroidSurfaceCreateFlagsKHR flags = 0, const VkAllocationCallbacks* allocator = nullptr);
#endif
#ifdef VK_USE_PLATFORM_XCB_KHR
// VK_KHR_xcb_surface
void Create(xcb_connection_t* connection, xcb_window_t window, VkXcbSurfaceCreateFlagsKHR flags = 0, const VkAllocationCallbacks* allocator = nullptr);
#endif
#ifdef VK_USE_PLATFORM_XLIB_KHR
// VK_KHR_xlib_surface
void Create(Display* display, ::Window window, VkXlibSurfaceCreateFlagsKHR flags = 0, const VkAllocationCallbacks* allocator = nullptr);
#endif
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
// VK_KHR_wayland_surface
void Create(wl_display* display, wl_surface* surface, VkWaylandSurfaceCreateFlagsKHR flags = 0, const VkAllocationCallbacks* allocator = nullptr);
#endif
#ifdef VK_USE_PLATFORM_WIN32_KHR
// VK_KHR_win32_surface
void Create(HINSTANCE instance, HWND handle, VkWin32SurfaceCreateFlagsKHR flags = 0, const VkAllocationCallbacks* allocator = nullptr);
#endif
#ifdef VK_USE_PLATFORM_METAL_EXT
void Create(id layer, const VkAllocationCallbacks* allocator = nullptr);
#endif
private:
VkSurfaceKHR m_surface = VK_NULL_HANDLE;
};
}
#endif

View File

@@ -123,5 +123,41 @@
MLX_VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfaceFormatsKHR)
MLX_VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfacePresentModesKHR)
MLX_VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfaceSupportKHR)
#ifdef VK_USE_PLATFORM_ANDROID_KHR
#ifdef VK_KHR_android_surface
MLX_VULKAN_INSTANCE_FUNCTION(vkCreateAndroidSurfaceKHR)
#endif
#endif
#ifdef VK_USE_PLATFORM_XCB_KHR
#ifdef VK_KHR_xcb_surface
MLX_VULKAN_INSTANCE_FUNCTION(vkCreateXcbSurfaceKHR)
#endif
#endif
#ifdef VK_USE_PLATFORM_XLIB_KHR
#ifdef VK_KHR_xlib_surface
MLX_VULKAN_INSTANCE_FUNCTION(vkCreateXlibSurfaceKHR)
#endif
#endif
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
#ifdef VK_KHR_wayland_surface
MLX_VULKAN_INSTANCE_FUNCTION(vkCreateWaylandSurfaceKHR)
#endif
#endif
#ifdef VK_USE_PLATFORM_WIN32_KHR
#ifdef VK_KHR_win32_surface
MLX_VULKAN_INSTANCE_FUNCTION(vkCreateWin32SurfaceKHR)
#endif
#endif
#ifdef VK_USE_PLATFORM_METAL_EXT
#ifdef VK_EXT_metal_surface
MLX_VULKAN_INSTANCE_FUNCTION(vkCreateMetalSurfaceEXT)
#endif
#endif
#endif
#endif

View File

@@ -8,7 +8,6 @@ namespace mlx
void Profiler::BeginRuntimeSession()
{
std::lock_guard lock(m_mutex);
if(m_runtime_session_began)
return;
m_output_stream.open("./runtime_profile.mlx.json", std::ofstream::out | std::ofstream::trunc);
@@ -22,7 +21,6 @@ namespace mlx
void Profiler::AppendProfileData(ProfileResult&& result)
{
std::lock_guard lock(m_mutex);
auto it = m_profile_data.find(result.name);
if(it != m_profile_data.end())
{
@@ -49,7 +47,6 @@ namespace mlx
void Profiler::EndRuntimeSession()
{
std::lock_guard lock(m_mutex);
if(!m_runtime_session_began)
return;
for(auto& [_, pair] : m_profile_data)

View File

@@ -43,7 +43,7 @@ namespace mlx
Internal::WindowInfos* infos = new Internal::WindowInfos;
Verify(infos != nullptr, "SDL: window allocation failed");
std::uint32_t flags = SDL_WINDOW_VULKAN;
std::uint32_t flags = 0;
if(hidden)
flags |= SDL_WINDOW_HIDDEN;
else
@@ -88,28 +88,38 @@ namespace mlx
VkSurfaceKHR SDLManager::CreateVulkanSurface(Handle window, VkInstance instance) const noexcept
{
VkSurfaceKHR surface;
if(!SDL_Vulkan_CreateSurface(static_cast<Internal::WindowInfos*>(window)->window, instance, &surface))
FatalError("SDL: could not create a Vulkan surface; %", SDL_GetError());
return surface;
}
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
if(SDL_GetWindowWMInfo(static_cast<Internal::WindowInfos*>(window)->window, &info) != SDL_TRUE)
FatalError("SDL Manager: cannot retrieve window informations");
std::vector<const char*> SDLManager::GetRequiredVulkanInstanceExtentions(Handle window) const noexcept
{
std::uint32_t count;
if(!SDL_Vulkan_GetInstanceExtensions(static_cast<Internal::WindowInfos*>(window)->window, &count, nullptr))
FatalError("SDL Manager: could not retrieve Vulkan instance extensions");
std::vector<const char*> extensions(count);
if(!SDL_Vulkan_GetInstanceExtensions(static_cast<Internal::WindowInfos*>(window)->window, &count, extensions.data()))
FatalError("SDL Manager: could not retrieve Vulkan instance extensions");
extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
return extensions;
switch(info.subsystem)
{
#ifdef SDL_VIDEO_DRIVER_WINDOWS
case SDL_SYSWM_WINDOWS: return kvfCreateSurfaceKHR(instance, KVF_SURFACE_WINDOWS, static_cast<void*>(info.info.win.hinstance), static_cast<void*>(info.info.win.window));
#endif
#ifdef SDL_VIDEO_DRIVER_X11
case SDL_SYSWM_X11: return kvfCreateSurfaceKHR(instance, KVF_SURFACE_XLIB, static_cast<void*>(info.info.x11.display), static_cast<void*>(&info.info.x11.window));
#endif
#ifdef SDL_VIDEO_DRIVER_COCOA
case SDL_SYSWM_COCOA: FatalError("SDL Manager: Vulkan surfaces over Metal are not supported yet. Please fill an issue here https://github.com/seekrs/MacroLibX/issues/new");
#endif
#ifdef SDL_VIDEO_DRIVER_WAYLAND
case SDL_SYSWM_WAYLAND: return kvfCreateSurfaceKHR(instance, KVF_SURFACE_WAYLAND, static_cast<void*>(info.info.wl.display), static_cast<void*>(info.info.wl.surface));
#endif
#ifdef SDL_VIDEO_DRIVER_ANDROID
case SDL_SYSWM_ANDROID: return kvfCreateSurfaceKHR(instance, KVF_SURFACE_ANDROID, nullptr, static_cast<void*>(info.info.android.window));
#endif
default : FatalError("SDL Manager: unsupported windowing system"); break;
}
return VK_NULL_HANDLE;
}
Vec2ui SDLManager::GetVulkanDrawableSize(Handle window) const noexcept
{
Vec2i extent;
SDL_Vulkan_GetDrawableSize(static_cast<Internal::WindowInfos*>(window)->window, &extent.x, &extent.y);
SDL_GetWindowSizeInPixels(static_cast<Internal::WindowInfos*>(window)->window, &extent.x, &extent.y);
return Vec2ui{ extent };
}
@@ -266,6 +276,7 @@ namespace mlx
case SDL_WINDOWEVENT_LEAVE: functor(MLX_WINDOW_EVENT, id, 6); break;
case SDL_WINDOWEVENT_FOCUS_LOST: functor(MLX_WINDOW_EVENT, id, 7); break;
case SDL_WINDOWEVENT_SIZE_CHANGED: functor(MLX_WINDOW_EVENT, id, 8); break;
case SDL_WINDOWEVENT_RESTORED: functor(MLX_WINDOW_EVENT, id, 11); break;
default : break;
}
@@ -284,6 +295,7 @@ namespace mlx
{
if(m_drop_sdl_responsability)
return;
SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTS);
SDL_Quit();
s_instance = nullptr;

View File

@@ -127,6 +127,9 @@ namespace mlx
void GraphicPipeline::Destroy() noexcept
{
MLX_PROFILE_FUNCTION();
if(m_pipeline == VK_NULL_HANDLE)
return;
p_vertex_shader.reset();
p_fragment_shader.reset();
for(auto fb : m_framebuffers)

View File

@@ -100,8 +100,25 @@ namespace mlx
info.width = 1;
info.height = 1;
window = std::make_unique<Window>(&info, true);
instance_extensions = window->GetRequiredVulkanInstanceExtentions();
#ifdef MLX_PLAT_MACOS
instance_extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
#ifdef VK_USE_PLATFORM_XCB_KHR
instance_extensions.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
#endif
#ifdef VK_USE_PLATFORM_XLIB_KHR
instance_extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
#endif
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
instance_extensions.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
#endif
#ifdef VK_USE_PLATFORM_WIN32_KHR
instance_extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#endif
#ifdef VK_USE_PLATFORM_METAL_EXT
instance_extensions.push_back(VK_EXT_METAL_SURFACE_EXTENSION_NAME);
instance_extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
#endif
}
@@ -185,6 +202,41 @@ namespace mlx
MLX_LOAD_FUNCTION(vkGetPhysicalDeviceSurfaceFormatsKHR);
MLX_LOAD_FUNCTION(vkGetPhysicalDeviceSurfacePresentModesKHR);
MLX_LOAD_FUNCTION(vkGetPhysicalDeviceSurfaceSupportKHR);
#ifdef VK_USE_PLATFORM_ANDROID_KHR
#ifdef VK_KHR_android_surface
MLX_LOAD_FUNCTION(vkCreateAndroidSurfaceKHR);
#endif
#endif
#ifdef VK_USE_PLATFORM_XCB_KHR
#ifdef VK_KHR_xcb_surface
MLX_LOAD_FUNCTION(vkCreateXcbSurfaceKHR);
#endif
#endif
#ifdef VK_USE_PLATFORM_XLIB_KHR
#ifdef VK_KHR_xlib_surface
MLX_LOAD_FUNCTION(vkCreateXlibSurfaceKHR);
#endif
#endif
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
#ifdef VK_KHR_wayland_surface
MLX_LOAD_FUNCTION(vkCreateWaylandSurfaceKHR);
#endif
#endif
#ifdef VK_USE_PLATFORM_WIN32_KHR
#ifdef VK_KHR_win32_surface
MLX_LOAD_FUNCTION(vkCreateWin32SurfaceKHR);
#endif
#endif
#ifdef VK_USE_PLATFORM_METAL_EXT
#ifdef VK_EXT_metal_surface
MLX_LOAD_FUNCTION(vkCreateMetalSurfaceEXT);
#endif
#endif
kvfPassInstanceVulkanFunctionPointers(&pfns);
}

207
third_party/kvf.h vendored
View File

@@ -55,6 +55,46 @@
#define VK_NO_PROTOTYPES
#endif
#ifndef KVF_NO_KHR
#ifdef VK_USE_PLATFORM_ANDROID_KHR
#include <vulkan/vulkan_android.h>
#endif
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
#include <vulkan/vulkan_wayland.h>
#endif
#ifdef VK_USE_PLATFORM_WIN32_KHR
typedef struct HINSTANCE__* HINSTANCE;
typedef struct HWND__* HWND;
typedef struct HMONITOR__* HMONITOR;
typedef void* HANDLE;
typedef /*_Null_terminated_*/ const wchar_t* LPCWSTR;
typedef unsigned long DWORD;
typedef struct _SECURITY_ATTRIBUTES SECURITY_ATTRIBUTES;
#include <vulkan/vulkan_win32.h>
#endif
#ifdef VK_USE_PLATFORM_XCB_KHR
struct xcb_connection_t;
typedef uint32_t xcb_window_t;
typedef uint32_t xcb_visualid_t;
#include <vulkan/vulkan_xcb.h>
#endif
#ifdef VK_USE_PLATFORM_METAL_EXT
#include <vulkan/vulkan_metal.h>
#endif
#ifdef VK_USE_PLATFORM_XLIB_KHR
typedef struct _XDisplay Display;
typedef unsigned long XID;
typedef XID Window;
typedef unsigned long VisualID;
#include <vulkan/vulkan_xlib.h>
#endif
#endif
#include <vulkan/vulkan_core.h>
#include <stdint.h>
@@ -82,6 +122,18 @@ typedef enum
KVF_IMAGE_OTHER = 4,
} KvfImageType;
#ifndef KVF_NO_KHR
typedef enum
{
KVF_SURFACE_ANDROID = 0,
KVF_SURFACE_XLIB = 1,
KVF_SURFACE_XCB = 2,
KVF_SURFACE_WAYLAND = 3,
KVF_SURFACE_WINDOWS = 4,
KVF_SURFACE_METAL = 5,
} KvfSurfaceType;
#endif
typedef void (*KvfErrorCallback)(const char* message);
#ifdef KVF_IMPL_VK_NO_PROTOTYPES
@@ -148,6 +200,33 @@ void kvfDestroySemaphore(VkDevice device, VkSemaphore semaphore);
uint32_t kvfGetSwapchainMinImagesCount(VkSwapchainKHR swapchain);
VkExtent2D kvfGetSwapchainImagesSize(VkSwapchainKHR swapchain);
void kvfDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain);
/**
* For Windows:
* - instance_handle -> HINSTANCE
* - window_handle -> HWND window handle
*
* For Wayland:
* - instance_handle -> wl_display
* - window_handle -> wl_surface
*
* For XLIB:
* - instance_handle -> Display
* - window_handle -> Window
*
* For XCB:
* - instance_handle -> xcb_connection_t
* - window_handle -> xcb_window_t
*
* For Metal:
* - instance_handle -> ignored
* - window_handle -> CAMetalLayer
*
* For Android:
* - instance_handle -> ignored
* - window_handle -> ANativeWindow
*/
VkSurfaceKHR kvfCreateSurfaceKHR(VkInstance instance, KvfSurfaceType type, void* instance_handle, void* window_handle);
#endif
VkImage kvfCreateImage(VkDevice device, uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, KvfImageType type);
@@ -272,6 +351,42 @@ int32_t kvfFindMemoryType(VkPhysicalDevice physical_device, uint32_t type_filter
KVF_DEFINE_VULKAN_FUNCTION_PROTOTYPE(vkGetPhysicalDeviceSurfaceFormatsKHR);
KVF_DEFINE_VULKAN_FUNCTION_PROTOTYPE(vkGetPhysicalDeviceSurfacePresentModesKHR);
KVF_DEFINE_VULKAN_FUNCTION_PROTOTYPE(vkGetPhysicalDeviceSurfaceSupportKHR);
#ifdef VK_USE_PLATFORM_ANDROID_KHR
#ifdef VK_KHR_android_surface
KVF_DEFINE_VULKAN_FUNCTION_PROTOTYPE(vkCreateAndroidSurfaceKHR);
#endif
#endif
#ifdef VK_USE_PLATFORM_XCB_KHR
#ifdef VK_KHR_xcb_surface
KVF_DEFINE_VULKAN_FUNCTION_PROTOTYPE(vkCreateXcbSurfaceKHR);
#endif
#endif
#ifdef VK_USE_PLATFORM_XLIB_KHR
#ifdef VK_KHR_xlib_surface
KVF_DEFINE_VULKAN_FUNCTION_PROTOTYPE(vkCreateXlibSurfaceKHR);
#endif
#endif
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
#ifdef VK_KHR_wayland_surface
KVF_DEFINE_VULKAN_FUNCTION_PROTOTYPE(vkCreateWaylandSurfaceKHR);
#endif
#endif
#ifdef VK_USE_PLATFORM_WIN32_KHR
#ifdef VK_KHR_win32_surface
KVF_DEFINE_VULKAN_FUNCTION_PROTOTYPE(vkCreateWin32SurfaceKHR);
#endif
#endif
#ifdef VK_USE_PLATFORM_METAL_EXT
#ifdef VK_EXT_metal_surface
KVF_DEFINE_VULKAN_FUNCTION_PROTOTYPE(vkCreateMetalSurfaceEXT);
#endif
#endif
#endif
};
@@ -2093,6 +2208,98 @@ void kvfDestroySemaphore(VkDevice device, VkSemaphore semaphore)
KVF_ASSERT(device != VK_NULL_HANDLE);
__kvfDestroySwapchain(device, swapchain);
}
VkSurfaceKHR kvfCreateSurfaceKHR(VkInstance instance, KvfSurfaceType type, void* instance_handle, void* window_handle)
{
VkSurfaceKHR surface = VK_NULL_HANDLE;
switch(type)
{
#ifdef VK_USE_PLATFORM_ANDROID_KHR
case KVF_SURFACE_ANDROID:
{
VkAndroidSurfaceCreateInfoKHR create_info = {};
create_info.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
create_info.pNext = nullptr;
create_info.flags = 0;
create_info.window = (ANativeWindow*)window_handle;
kvfCheckVk(KVF_GET_INSTANCE_FUNCTION(vkCreateAndroidSurfaceKHR)(instance, &create_info, NULL, &surface));
break;
}
#endif
#ifdef VK_USE_PLATFORM_XLIB_KHR
case KVF_SURFACE_XLIB:
{
VkXlibSurfaceCreateInfoKHR create_info = {};
create_info.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
create_info.pNext = nullptr;
create_info.flags = 0;
create_info.dpy = (Display*)instance_handle;
create_info.window = *(Window*)window_handle;
kvfCheckVk(KVF_GET_INSTANCE_FUNCTION(vkCreateXlibSurfaceKHR)(instance, &create_info, NULL, &surface));
break;
}
#endif
#ifdef VK_USE_PLATFORM_XCB_KHR
case KVF_SURFACE_XCB:
{
VkXcbSurfaceCreateInfoKHR create_info = {};
create_info.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
create_info.pNext = nullptr;
create_info.flags = 0;
create_info.connection = (xcb_connection_t*)instance_handle;
create_info.window = (*xcb_window_t*)window_handle;
kvfCheckVk(KVF_GET_INSTANCE_FUNCTION(vkCreateXcbSurfaceKHR)(instance, &create_info, NULL, &surface));
break;
}
#endif
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
case KVF_SURFACE_WAYLAND:
{
VkWaylandSurfaceCreateInfoKHR create_info = {};
create_info.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
create_info.pNext = nullptr;
create_info.flags = 0;
create_info.display = (wl_display*)instance_handle;
create_info.surface = (wl_surface*)window_handle;
kvfCheckVk(KVF_GET_INSTANCE_FUNCTION(vkCreateWaylandSurfaceKHR)(instance, &create_info, NULL, &surface));
break;
}
#endif
#ifdef VK_USE_PLATFORM_WIN32_KHR
case KVF_SURFACE_WINDOWS:
{
VkWin32SurfaceCreateInfoKHR create_info = {};
create_info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
create_info.pNext = nullptr;
create_info.flags = 0;
create_info.hinstance = (HINSTANCE)instance_handle;
create_info.hwnd = (HWND)window_handle;
kvfCheckVk(KVF_GET_INSTANCE_FUNCTION(vkCreateWin32SurfaceKHR)(instance, &create_info, NULL, &surface));
break;
}
#endif
#ifdef VK_USE_PLATFORM_METAL_EXT
case KVF_SURFACE_METAL:
{
VkMetalSurfaceCreateInfoEXT create_info = {};
create_info.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_KHR;
create_info.pNext = nullptr;
create_info.flags = 0;
create_info.pLayer = (CAMetalLayer*)window_handle;
kvfCheckVk(KVF_GET_INSTANCE_FUNCTION(vkCreateMetalSurfaceEXT)(instance, &create_info, NULL, &surface));
break;
}
#endif
default: break;
}
return surface;
}
#endif
VkImage kvfCreateImage(VkDevice device, uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, KvfImageType type)