diff options
| author | Andre Weissflog <floooh@gmail.com> | 2025-12-02 17:00:33 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-12-02 17:00:33 +0100 |
| commit | c5d1a4732b0182b3429c73ccc51b52ca22e71ea8 (patch) | |
| tree | 0fdaf95c1daac1de38456f9718ba54501eea5650 | |
| parent | 406f1e908d7e957ee8484d9ea0aac4355fb7db7b (diff) | |
| parent | 091279eb377d847e9163428811d4df6cd4cf711b (diff) | |
Merge pull request #1350 from floooh/experimental-vulkan
Add initial Vulkan backend (wip)
| -rw-r--r-- | CHANGELOG.md | 32 | ||||
| -rw-r--r-- | sokol_app.h | 1367 | ||||
| -rw-r--r-- | sokol_gfx.h | 3873 | ||||
| -rw-r--r-- | sokol_glue.h | 100 | ||||
| -rw-r--r-- | util/sokol_debugtext.h | 180 | ||||
| -rw-r--r-- | util/sokol_fontstash.h | 221 | ||||
| -rw-r--r-- | util/sokol_gfx_imgui.h | 30 | ||||
| -rw-r--r-- | util/sokol_gl.h | 217 | ||||
| -rw-r--r-- | util/sokol_imgui.h | 196 | ||||
| -rw-r--r-- | util/sokol_nuklear.h | 197 | ||||
| -rw-r--r-- | util/sokol_spine.h | 248 |
11 files changed, 6221 insertions, 440 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e7850f0..18710cf3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,38 @@ - sokol_gfx.h gl: unused framebuffer attachment slots are now explicitly cleared in `sg_begin_pass()`. See PR https://github.com/floooh/sokol/pull/1390 for details! Many thanks to @etherbound-dev for catching and fixing the issue! +- sokol_app.h: some minor breaking changes in the public API (most code won't be affected): + - the platform/backend specific config items in `sapp_desc` have been moved + into nested structs to allow a more consistent designated-init coding style + - a new enum `sapp_pixel_format` has been added and the functions `sapp_color_format()` and + `sapp_depth_format()` now return `sapp_pixel_format` instead of an `int`. Note + that the `sapp_pixel_format` values are no longer directly convertible to `sg_pixel_format` + values, you need some mapping code between the two enum types + - a new function `sapp_get_environment()` has been added which returns a new struct + `sapp_environment()`, this conceptually plugs into the sokol-gfx struct `sg_environement` + but requires mapping code to translate `sapp_environment` into `sg_environment` (an example + of such mapping code is for instance in sokol_glue.h) + - likewise, a new function `sapp_get_swapchain()` has been added which returns a new + struct `sapp_swapchain`, which conceptually plugs into the sokol-gfx struct `sg_swapchain` + - a ton of platform/backend specific functions have been removed which returned type-erased + pointers to various 3D backend objects, those pointers have moved into the new + structs `sapp_environemnt` and `sapp_swapchain` +- sokol_gfx.h: a similar minor breaking change in `sg_desc` as was implemented in `sapp_desc`: + the individual backend-specific config items have been moved into nested structs + to allow a more consistent designated-init style +- An *experimental Vulkan backend* has been added to sokol_app.h and sokol_gfx.h, + [please read this blog post for an overview](https://floooh.github.io/2025/12/01/sokol-vulkan-backend-1.html). + Currently the backend only supports Linux and has only been tested on an Intel + Meteor Lake embedded GPU. If you want to test this with the sokol-samples: + - make sure the following packages are installed (this is for Ubuntu + apt): + - libvulkan-dev + - vulkan-tools + - vulkan-validationlayers + - clone https://github.com/floooh/sokol-samples + - from within sokol-samples: + - ./fips set config sapp-vk-linux-ninja-debug + - ./fips build + - ./fips run cube-sapp-ui ### 13-Nov-2025 diff --git a/sokol_app.h b/sokol_app.h index 797bbf95..a7f9d810 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -1797,6 +1797,24 @@ typedef struct sapp_allocator { _SAPP_LOGITEM_XMACRO(WGPU_REQUEST_ADAPTER_STATUS_ERROR, "wgpu: requesting adapter failed with status 'error'") \ _SAPP_LOGITEM_XMACRO(WGPU_REQUEST_ADAPTER_STATUS_UNKNOWN, "wgpu: requesting adapter failed with status 'unknown'") \ _SAPP_LOGITEM_XMACRO(WGPU_CREATE_INSTANCE_FAILED, "wgpu: failed to create instance") \ + _SAPP_LOGITEM_XMACRO(VULKAN_ALLOC_DEVICE_MEMORY_NO_SUITABLE_MEMORY_TYPE, "vulkan: could not find suitable memory type") \ + _SAPP_LOGITEM_XMACRO(VULKAN_ALLOCATE_MEMORY_FAILED, "vulkan: vkAllocateMemory() failed!") \ + _SAPP_LOGITEM_XMACRO(VULKAN_CREATE_INSTANCE_FAILED, "vulkan: vkCreateInstance failed") \ + _SAPP_LOGITEM_XMACRO(VULKAN_ENUMERATE_PHYSICAL_DEVICES_FAILED, "vulkan: vkEnumeratePhysicalDevices failed") \ + _SAPP_LOGITEM_XMACRO(VULKAN_NO_PHYSICAL_DEVICES_FOUND, "vulkan: vkEnumeratePhysicalDevices return no devices") \ + _SAPP_LOGITEM_XMACRO(VULKAN_NO_SUITABLE_PHYSICAL_DEVICE_FOUND, "vulkan: no suitable physical device found") \ + _SAPP_LOGITEM_XMACRO(VULKAN_CREATE_DEVICE_FAILED_EXTENSION_NOT_PRESENT, "vulkan: vkCreateDevice failed (extension not present)") \ + _SAPP_LOGITEM_XMACRO(VULKAN_CREATE_DEVICE_FAILED_FEATURE_NOT_PRESENT, "vulkan: vkCreateDevice failed (feature not present)") \ + _SAPP_LOGITEM_XMACRO(VULKAN_CREATE_DEVICE_FAILED_INITIALIZATION_FAILED, "vulkan: vkCreateDevice failed (initialization failed)") \ + _SAPP_LOGITEM_XMACRO(VULKAN_CREATE_DEVICE_FAILED_OTHER, "vulkan: vkCreateDevice failed (other)") \ + _SAPP_LOGITEM_XMACRO(VULKAN_CREATE_SURFACE_FAILED, "vulkan: vkCreate*SurfaceKHR failed") \ + _SAPP_LOGITEM_XMACRO(VULKAN_CREATE_SWAPCHAIN_FAILED, "vulkan: vkCreateSwapchainKHR failed") \ + _SAPP_LOGITEM_XMACRO(VULKAN_SWAPCHAIN_CREATE_IMAGE_VIEW_FAILED, "vulkan: vkCreateImageView for swapchain image failed") \ + _SAPP_LOGITEM_XMACRO(VULKAN_SWAPCHAIN_CREATE_IMAGE_FAILED, "vulkan: vkCreateImage for depth-stencil image failed") \ + _SAPP_LOGITEM_XMACRO(VULKAN_SWAPCHAIN_ALLOC_IMAGE_DEVICE_MEMORY_FAILED, "vulkan: failed to allocate device memory for depth-stencil image") \ + _SAPP_LOGITEM_XMACRO(VULKAN_SWAPCHAIN_BIND_IMAGE_MEMORY_FAILED, "vulkan: vkBindImageMemory() for depth-stencil image failed") \ + _SAPP_LOGITEM_XMACRO(VULKAN_ACQUIRE_NEXT_IMAGE_FAILED, "vulkan: vkAcquireNextImageKHR failed") \ + _SAPP_LOGITEM_XMACRO(VULKAN_QUEUE_PRESENT_FAILED, "vulkan: vkQueuePresentKHR failed") \ _SAPP_LOGITEM_XMACRO(IMAGE_DATA_SIZE_MISMATCH, "image data size mismatch (must be width*height*4 bytes)") \ _SAPP_LOGITEM_XMACRO(DROPPED_FILE_PATH_TOO_LONG, "dropped file path too long (sapp_desc.max_dropped_filed_path_length)") \ _SAPP_LOGITEM_XMACRO(CLIPBOARD_STRING_TOO_BIG, "clipboard string didn't fit into clipboard buffer") \ @@ -1808,6 +1826,133 @@ typedef enum sapp_log_item { #undef _SAPP_LOGITEM_XMACRO /* + sapp_pixel_format + + Defines the pixel format for swapchain surfaces. + + NOTE: when using sokol_gfx.h do not assume that the underlying + values are compatible with sg_pixel_format! + +*/ +typedef enum sapp_pixel_format { + _SAPP_PIXELFORMAT_DEFAULT, + SAPP_PIXELFORMAT_NONE, + SAPP_PIXELFORMAT_RGBA8, + SAPP_PIXELFORMAT_SRGB8A8, + SAPP_PIXELFORMAT_BGRA8, + SAPP_PIXELFORMAT_SBGRA8, + SAPP_PIXELFORMAT_DEPTH, + SAPP_PIXELFORMAT_DEPTH_STENCIL, + _SA_PPPIXELFORMAT_FORCE_U32 = 0x7FFFFFFF +} sapp_pixel_format; + +/* + sapp_environment + + Used to provide runtime environment information to the + outside world (like default pixel formats and the backend + 3D API device pointer) via a call to sapp_get_environment(). + + NOTE: when using sokol_gfx.h, don't assume that sapp_environment + is binary compatible with sg_environment! Always use a translation + function like sglue_environment() to populate sg_environment + from sapp_environment! +*/ +typedef struct sapp_environment_defaults { + sapp_pixel_format color_format; + sapp_pixel_format depth_format; + int sample_count; +} sapp_environment_defaults; + +typedef struct sapp_metal_environment { + const void* device; +} sapp_metal_environment; + +typedef struct sapp_d3d11_environment { + const void* device; + const void* device_context; +} sapp_d3d11_environment; + +typedef struct sapp_wgpu_environment { + const void* device; +} sapp_wgpu_environment; + +typedef struct sapp_vulkan_environment { + const void* physical_device; + const void* device; + const void* queue; + uint32_t queue_family_index; +} sapp_vulkan_environment; + +typedef struct sapp_environment { + sapp_environment_defaults defaults; + sapp_metal_environment metal; + sapp_d3d11_environment d3d11; + sapp_wgpu_environment wgpu; + sapp_vulkan_environment vulkan; +} sapp_environment; + +/* + sapp_swapchain + + Provides swapchain information for the current frame to the outside + world via a call to sapp_get_swapchain(). + + NOTE: sapp_get_swapchain() must be called exactly once per frame since + on some backends it will also acquire the next swapchain image. + + NOTE: when using sokol_gfx.h, don't assume that the sapp_swapchain struct + has the same memory layout as sg_swapchain! Use the sokol_log.h helper + function sglue_swapchain() to translate sapp_swapchain into a + sg_swapchain instead. +*/ +typedef struct sapp_metal_swapchain { + const void* current_drawable; // CAMetalDrawable (NOT MTLDrawable!!!) + const void* depth_stencil_texture; // MTLTexture + const void* msaa_color_texture; // MTLTexture +} sapp_metal_swapchain; + +typedef struct sapp_d3d11_swapchain { + const void* render_view; // ID3D11RenderTargetView + const void* resolve_view; // ID3D11RenderTargetView + const void* depth_stencil_view; // ID3D11DepthStencilView +} sapp_d3d11_swapchain; + +typedef struct sapp_wgpu_swapchain { + const void* render_view; // WGPUTextureView + const void* resolve_view; // WGPUTextureView + const void* depth_stencil_view; // WGPUTextureView +} sapp_wgpu_swapchain; + +typedef struct sapp_vulkan_swapchain { + const void* render_image; // vkImage + const void* render_view; // vkImageView + const void* resolve_image; // vkImage; + const void* resolve_view; // vkImageView + const void* depth_stencil_image; // vkImage + const void* depth_stencil_view; // vkImageView + const void* render_finished_semaphore; // vkSemaphore + const void* present_complete_semaphore; // vkSemaphore +} sapp_vulkan_swapchain; + +typedef struct sapp_gl_swapchain { + uint32_t framebuffer; // GL framebuffer object +} sapp_gl_swapchain; + +typedef struct sapp_swapchain { + int width; + int height; + int sample_count; + sapp_pixel_format color_format; + sapp_pixel_format depth_format; + sapp_metal_swapchain metal; + sapp_d3d11_swapchain d3d11; + sapp_wgpu_swapchain wgpu; + sapp_vulkan_swapchain vulkan; + sapp_gl_swapchain gl; +} sapp_swapchain; + +/* sapp_logger Used in sapp_desc to provide a logging function. Please be aware that @@ -1832,6 +1977,37 @@ typedef struct sapp_logger { sokol-app initialization options, used as return value of sokol_main() or sapp_run() argument. */ +typedef struct sapp_gl_desc { + int major_version; // override GL/GLES major and minor version (defaults: GL4.1 (macOS) or GL4.3, GLES3.1 (Android) or GLES3.0 + int minor_version; +} sapp_gl_desc; + +typedef struct sapp_win32_desc { + bool console_utf8; // if true, set the output console codepage to UTF-8 + bool console_create; // if true, attach stdout/stderr to a new console window + bool console_attach; // if true, attach stdout/stderr to parent process +} sapp_win32_desc; + +typedef struct sapp_html5_desc { + const char* canvas_selector; // css selector of the HTML5 canvas element, default is "#canvas" + bool canvas_resize; // if true, the HTML5 canvas size is set to sapp_desc.width/height, otherwise canvas size is tracked + bool preserve_drawing_buffer; // HTML5 only: whether to preserve default framebuffer content between frames + bool premultiplied_alpha; // HTML5 only: whether the rendered pixels use premultiplied alpha convention + bool ask_leave_site; // initial state of the internal html5_ask_leave_site flag (see sapp_html5_ask_leave_site()) + bool update_document_title; // if true, update the HTML document.title with sapp_desc.window_title + bool bubble_mouse_events; // if true, mouse events will bubble up to the web page + bool bubble_touch_events; // same for touch events + bool bubble_wheel_events; // same for wheel events + bool bubble_key_events; // if true, bubble up *all* key events to browser, not just key events that represent characters + bool bubble_char_events; // if true, bubble up character events to browser + bool use_emsc_set_main_loop; // if true, use emscripten_set_main_loop() instead of emscripten_request_animation_frame_loop() + bool emsc_set_main_loop_simulate_infinite_loop; // this will be passed as the simulate_infinite_loop arg to emscripten_set_main_loop() +} sapp_html5_desc; + +typedef struct sapp_ios_desc { + bool keyboard_resizes_canvas; // if true, showing the iOS keyboard shrinks the canvas +} sapp_ios_desc; + typedef struct sapp_desc { void (*init_cb)(void); // these are the user-provided callbacks without user data void (*frame_cb)(void); @@ -1862,25 +2038,10 @@ typedef struct sapp_desc { sapp_logger logger; // logging callback override (default: NO LOGGING!) // backend-specific options - int gl_major_version; // override GL/GLES major and minor version (defaults: GL4.1 (macOS) or GL4.3, GLES3.1 (Android) or GLES3.0 - int gl_minor_version; - bool win32_console_utf8; // if true, set the output console codepage to UTF-8 - bool win32_console_create; // if true, attach stdout/stderr to a new console window - bool win32_console_attach; // if true, attach stdout/stderr to parent process - const char* html5_canvas_selector; // css selector of the HTML5 canvas element, default is "#canvas" - bool html5_canvas_resize; // if true, the HTML5 canvas size is set to sapp_desc.width/height, otherwise canvas size is tracked - bool html5_preserve_drawing_buffer; // HTML5 only: whether to preserve default framebuffer content between frames - bool html5_premultiplied_alpha; // HTML5 only: whether the rendered pixels use premultiplied alpha convention - bool html5_ask_leave_site; // initial state of the internal html5_ask_leave_site flag (see sapp_html5_ask_leave_site()) - bool html5_update_document_title; // if true, update the HTML document.title with sapp_desc.window_title - bool html5_bubble_mouse_events; // if true, mouse events will bubble up to the web page - bool html5_bubble_touch_events; // same for touch events - bool html5_bubble_wheel_events; // same for wheel events - bool html5_bubble_key_events; // if true, bubble up *all* key events to browser, not just key events that represent characters - bool html5_bubble_char_events; // if true, bubble up character events to browser - bool html5_use_emsc_set_main_loop; // if true, use emscripten_set_main_loop() instead of emscripten_request_animation_frame_loop() - bool html5_emsc_set_main_loop_simulate_infinite_loop; // this will be passed as the simulate_infinite_loop arg to emscripten_set_main_loop() - bool ios_keyboard_resizes_canvas; // if true, showing the iOS keyboard shrinks the canvas + sapp_gl_desc gl; + sapp_win32_desc win32; + sapp_html5_desc html5; + sapp_ios_desc ios; } sapp_desc; /* HTML5 specific: request and response structs for @@ -1958,9 +2119,9 @@ SOKOL_APP_API_DECL int sapp_height(void); /* same as sapp_height(), but returns float */ SOKOL_APP_API_DECL float sapp_heightf(void); /* get default framebuffer color pixel format */ -SOKOL_APP_API_DECL int sapp_color_format(void); +SOKOL_APP_API_DECL sapp_pixel_format sapp_color_format(void); /* get default framebuffer depth pixel format */ -SOKOL_APP_API_DECL int sapp_depth_format(void); +SOKOL_APP_API_DECL sapp_pixel_format sapp_depth_format(void); /* get default framebuffer sample count */ SOKOL_APP_API_DECL int sapp_sample_count(void); /* returns true when high_dpi was requested and actually running in a high-dpi scenario */ @@ -2023,6 +2184,11 @@ SOKOL_APP_API_DECL const char* sapp_get_dropped_file_path(int index); /* special run-function for SOKOL_NO_ENTRY (in standard mode this is an empty stub) */ SOKOL_APP_API_DECL void sapp_run(const sapp_desc* desc); +/* get runtime environment information */ +sapp_environment sapp_get_environment(void); +/* get current frame's swapchain information (call once per frame!) */ +sapp_swapchain sapp_get_swapchain(void); + /* EGL: get EGLDisplay object */ SOKOL_APP_API_DECL const void* sapp_egl_get_display(void); /* EGL: get EGLContext object */ @@ -2035,45 +2201,17 @@ SOKOL_APP_API_DECL uint32_t sapp_html5_get_dropped_file_size(int index); /* HTML5: asynchronously load the content of a dropped file */ SOKOL_APP_API_DECL void sapp_html5_fetch_dropped_file(const sapp_html5_fetch_request* request); -/* Metal: get bridged pointer to Metal device object */ -SOKOL_APP_API_DECL const void* sapp_metal_get_device(void); -/* Metal: get bridged pointer to MTKView's current drawable of type CAMetalDrawable */ -SOKOL_APP_API_DECL const void* sapp_metal_get_current_drawable(void); -/* Metal: get bridged pointer to MTKView's depth-stencil texture of type MTLTexture */ -SOKOL_APP_API_DECL const void* sapp_metal_get_depth_stencil_texture(void); -/* Metal: get bridged pointer to MTKView's msaa-color-texture of type MTLTexture (may be null) */ -SOKOL_APP_API_DECL const void* sapp_metal_get_msaa_color_texture(void); /* macOS: get bridged pointer to macOS NSWindow */ SOKOL_APP_API_DECL const void* sapp_macos_get_window(void); /* iOS: get bridged pointer to iOS UIWindow */ SOKOL_APP_API_DECL const void* sapp_ios_get_window(void); -/* D3D11: get pointer to ID3D11Device object */ -SOKOL_APP_API_DECL const void* sapp_d3d11_get_device(void); -/* D3D11: get pointer to ID3D11DeviceContext object */ -SOKOL_APP_API_DECL const void* sapp_d3d11_get_device_context(void); /* D3D11: get pointer to IDXGISwapChain object */ SOKOL_APP_API_DECL const void* sapp_d3d11_get_swap_chain(void); -/* D3D11: get pointer to ID3D11RenderTargetView object for rendering */ -SOKOL_APP_API_DECL const void* sapp_d3d11_get_render_view(void); -/* D3D11: get pointer ID3D11RenderTargetView object for msaa-resolve (may return null) */ -SOKOL_APP_API_DECL const void* sapp_d3d11_get_resolve_view(void); -/* D3D11: get pointer ID3D11DepthStencilView */ -SOKOL_APP_API_DECL const void* sapp_d3d11_get_depth_stencil_view(void); + /* Win32: get the HWND window handle */ SOKOL_APP_API_DECL const void* sapp_win32_get_hwnd(void); -/* WebGPU: get WGPUDevice handle */ -SOKOL_APP_API_DECL const void* sapp_wgpu_get_device(void); -/* WebGPU: get swapchain's WGPUTextureView handle for rendering */ -SOKOL_APP_API_DECL const void* sapp_wgpu_get_render_view(void); -/* WebGPU: get swapchain's MSAA-resolve WGPUTextureView (may return null) */ -SOKOL_APP_API_DECL const void* sapp_wgpu_get_resolve_view(void); -/* WebGPU: get swapchain's WGPUTextureView for the depth-stencil surface */ -SOKOL_APP_API_DECL const void* sapp_wgpu_get_depth_stencil_view(void); - -/* GL: get framebuffer object */ -SOKOL_APP_API_DECL uint32_t sapp_gl_get_framebuffer(void); /* GL: get major version */ SOKOL_APP_API_DECL int sapp_gl_get_major_version(void); /* GL: get minor version */ @@ -2122,14 +2260,15 @@ inline void sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } #define _sapp_def(val, def) (((val) == 0) ? (def) : (val)) #define _sapp_absf(a) (((a)<0.0f)?-(a):(a)) +#ifdef __cplusplus +#define _SAPP_STRUCT(TYPE, NAME) TYPE NAME = {} +#else +#define _SAPP_STRUCT(TYPE, NAME) TYPE NAME = {0} +#endif + #define _SAPP_MAX_TITLE_LENGTH (128) #define _SAPP_FALLBACK_DEFAULT_WINDOW_WIDTH (640) #define _SAPP_FALLBACK_DEFAULT_WINDOW_HEIGHT (480) -// NOTE: the pixel format values *must* be compatible with sg_pixel_format -#define _SAPP_PIXELFORMAT_RGBA8 (23) -#define _SAPP_PIXELFORMAT_BGRA8 (28) -#define _SAPP_PIXELFORMAT_DEPTH (43) -#define _SAPP_PIXELFORMAT_DEPTH_STENCIL (44) // check if the config defines are alright #if defined(__APPLE__) @@ -2142,13 +2281,13 @@ inline void sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } #define _SAPP_APPLE (1) #include <TargetConditionals.h> #if defined(TARGET_OS_IPHONE) && !TARGET_OS_IPHONE - /* MacOS */ + // MacOS #define _SAPP_MACOS (1) #if !defined(SOKOL_METAL) && !defined(SOKOL_GLCORE) && !defined(SOKOL_WGPU) #error("sokol_app.h: unknown 3D API selected for MacOS, must be SOKOL_METAL, SOKOL_GLCORE or SOKOL_WGPU") #endif #else - /* iOS or iOS Simulator */ + // iOS or iOS Simulator #define _SAPP_IOS (1) #if !defined(SOKOL_METAL) && !defined(SOKOL_GLES3) #error("sokol_app.h: unknown 3D API selected for iOS, must be SOKOL_METAL or SOKOL_GLES3") @@ -2158,19 +2297,19 @@ inline void sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } #endif #endif #elif defined(__EMSCRIPTEN__) - /* emscripten (asm.js or wasm) */ + // Emscripten #define _SAPP_EMSCRIPTEN (1) #if !defined(SOKOL_GLES3) && !defined(SOKOL_WGPU) #error("sokol_app.h: unknown 3D API selected for emscripten, must be SOKOL_GLES3 or SOKOL_WGPU") #endif #elif defined(_WIN32) - /* Windows (D3D11 or GL) */ + // Windows (D3D11 or GL) #define _SAPP_WIN32 (1) #if !defined(SOKOL_D3D11) && !defined(SOKOL_GLCORE) && !defined(SOKOL_WGPU) && !defined(SOKOL_NOAPI) #error("sokol_app.h: unknown 3D API selected for Win32, must be SOKOL_D3D11, SOKOL_GLCORE, SOKOL_WGPU or SOKOL_NOAPI") #endif #elif defined(__ANDROID__) - /* Android */ + // Android #define _SAPP_ANDROID (1) #if !defined(SOKOL_GLES3) #error("sokol_app.h: unknown 3D API selected for Android, must be SOKOL_GLES3") @@ -2179,10 +2318,10 @@ inline void sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } #error("sokol_app.h: SOKOL_NO_ENTRY is not supported on Android") #endif #elif defined(__linux__) || defined(__unix__) - /* Linux */ + // Linux #define _SAPP_LINUX (1) - #if !defined(SOKOL_GLCORE) && !defined(SOKOL_GLES3) && !defined(SOKOL_WGPU) - #error("sokol_app.h: unknown 3D API selected for Linux, must be SOKOL_GLCORE, SOKOL_GLES3 or SOKOL_WGPU") + #if !defined(SOKOL_GLCORE) && !defined(SOKOL_GLES3) && !defined(SOKOL_WGPU) && !defined(SOKOL_VULKAN) + #error("sokol_app.h: unknown 3D API selected for Linux, must be SOKOL_GLCORE, SOKOL_GLES3, SOKOL_WGPU or SOKOL_VULKAN") #endif #if defined(SOKOL_GLCORE) #if defined(SOKOL_FORCE_EGL) @@ -2196,6 +2335,9 @@ inline void sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } #define _SAPP_EGL (1) #include <GLES3/gl3.h> #include <GLES3/gl3ext.h> + #elif defined(SOKOL_VULKAN) + #define VK_USE_PLATFORM_XLIB_KHR + #include <vulkan/vulkan.h> #endif #else #error "sokol_app.h: Unknown platform" @@ -2618,6 +2760,38 @@ typedef struct { } _sapp_wgpu_t; #endif +#if defined(SOKOL_VULKAN) +#define _SAPP_VK_MAX_SWAPCHAIN_IMAGES (8) + +typedef struct { + VkImage img; + VkDeviceMemory mem; + VkImageView view; +} _sapp_vk_swapchain_surface_t; + +typedef struct { + VkInstance instance; + VkSurfaceKHR surface; + VkSurfaceFormatKHR surface_format; + VkPhysicalDevice physical_device; + uint32_t queue_family_index; + VkDevice device; + VkQueue queue; + VkSwapchainKHR swapchain; + uint32_t num_swapchain_images; + uint32_t cur_swapchain_image_index; + VkImage swapchain_images[_SAPP_VK_MAX_SWAPCHAIN_IMAGES]; + VkImageView swapchain_views[_SAPP_VK_MAX_SWAPCHAIN_IMAGES]; + _sapp_vk_swapchain_surface_t msaa; + _sapp_vk_swapchain_surface_t depth; + uint32_t sync_slot; + struct { + VkSemaphore render_finished_sem; + VkSemaphore present_complete_sem; + } sync[_SAPP_VK_MAX_SWAPCHAIN_IMAGES]; +} _sapp_vk_t; +#endif + #if defined(_SAPP_MACOS) @interface _sapp_macos_app_delegate : NSObject<NSApplicationDelegate> @end @@ -3107,6 +3281,9 @@ typedef struct { #if defined(SOKOL_WGPU) _sapp_wgpu_t wgpu; #endif + #if defined(SOKOL_VULKAN) + _sapp_vk_t vk; + #endif #if defined(_SAPP_MACOS) _sapp_macos_t macos; #elif defined(_SAPP_IOS) @@ -3338,24 +3515,24 @@ _SOKOL_PRIVATE sapp_desc _sapp_desc_defaults(const sapp_desc* desc) { sapp_desc res = *desc; res.sample_count = _sapp_def(res.sample_count, 1); res.swap_interval = _sapp_def(res.swap_interval, 1); - if (0 == res.gl_major_version) { + if (0 == res.gl.major_version) { #if defined(SOKOL_GLCORE) - res.gl_major_version = 4; + res.gl.major_version = 4; #if defined(_SAPP_APPLE) - res.gl_minor_version = 1; + res.gl.minor_version = 1; #else - res.gl_minor_version = 3; + res.gl.minor_version = 3; #endif #elif defined(SOKOL_GLES3) - res.gl_major_version = 3; + res.gl.major_version = 3; #if defined(_SAPP_ANDROID) || defined(_SAPP_LINUX) - res.gl_minor_version = 1; + res.gl.minor_version = 1; #else - res.gl_minor_version = 0; + res.gl.minor_version = 0; #endif #endif } - res.html5_canvas_selector = _sapp_def(res.html5_canvas_selector, "#canvas"); + res.html5.canvas_selector = _sapp_def(res.html5.canvas_selector, "#canvas"); res.clipboard_size = _sapp_def(res.clipboard_size, 8192); res.max_dropped_files = _sapp_def(res.max_dropped_files, 1); res.max_dropped_file_path_length = _sapp_def(res.max_dropped_file_path_length, 2048); @@ -3382,9 +3559,9 @@ _SOKOL_PRIVATE void _sapp_init_state(const sapp_desc* desc) { _sapp.framebuffer_height = _sapp.window_height; _sapp.sample_count = _sapp.desc.sample_count; _sapp.swap_interval = _sapp.desc.swap_interval; - _sapp_strcpy(_sapp.desc.html5_canvas_selector, _sapp.html5_canvas_selector, sizeof(_sapp.html5_canvas_selector)); - _sapp.desc.html5_canvas_selector = _sapp.html5_canvas_selector; - _sapp.html5_ask_leave_site = _sapp.desc.html5_ask_leave_site; + _sapp_strcpy(_sapp.desc.html5.canvas_selector, _sapp.html5_canvas_selector, sizeof(_sapp.html5_canvas_selector)); + _sapp.desc.html5.canvas_selector = _sapp.html5_canvas_selector; + _sapp.html5_ask_leave_site = _sapp.desc.html5.ask_leave_site; _sapp.clipboard.enabled = _sapp.desc.enable_clipboard; if (_sapp.clipboard.enabled) { _sapp.clipboard.buf_size = _sapp.desc.clipboard_size; @@ -3755,7 +3932,7 @@ _SOKOL_PRIVATE void _sapp_wgpu_create_swapchain(bool called_from_resize) { surf_conf.alphaMode = WGPUCompositeAlphaMode_Opaque; #if defined(_SAPP_EMSCRIPTEN) // FIXME: make this further configurable? - if (_sapp.desc.html5_premultiplied_alpha) { + if (_sapp.desc.html5.premultiplied_alpha) { surf_conf.alphaMode = WGPUCompositeAlphaMode_Premultiplied; } #endif @@ -3828,7 +4005,8 @@ _SOKOL_PRIVATE void _sapp_wgpu_discard_swapchain(bool called_from_resize) { } } -_SOKOL_PRIVATE WGPUTextureView _sapp_wgpu_swapchain_next(void) { +_SOKOL_PRIVATE void _sapp_wgpu_swapchain_next(void) { + SOKOL_ASSERT(0 == _sapp.wgpu.swapchain_view); WGPUSurfaceTexture surf_tex; _sapp_clear(&surf_tex, sizeof(surf_tex)); wgpuSurfaceGetCurrentTexture(_sapp.wgpu.surface, &surf_tex); @@ -3840,19 +4018,20 @@ _SOKOL_PRIVATE WGPUTextureView _sapp_wgpu_swapchain_next(void) { case WGPUSurfaceGetCurrentTextureStatus_Timeout: case WGPUSurfaceGetCurrentTextureStatus_Outdated: case WGPUSurfaceGetCurrentTextureStatus_Lost: - // skip this frame and reconfigure surface if (surf_tex.texture) { wgpuTextureRelease(surf_tex.texture); } _sapp_wgpu_discard_swapchain(false); _sapp_wgpu_create_swapchain(false); - return 0; + // FIXME: currently this will assert in the caller + return; case WGPUSurfaceGetCurrentTextureStatus_Error: default: _SAPP_PANIC(WGPU_SWAPCHAIN_GETCURRENTTEXTURE_FAILED); break; } - return wgpuTextureCreateView(surf_tex.texture, 0); + _sapp.wgpu.swapchain_view = wgpuTextureCreateView(surf_tex.texture, 0); + SOKOL_ASSERT(_sapp.wgpu.swapchain_view); } _SOKOL_PRIVATE void _sapp_wgpu_swapchain_size_changed(void) { @@ -4063,10 +4242,11 @@ _SOKOL_PRIVATE void _sapp_wgpu_discard(void) { _SOKOL_PRIVATE void _sapp_wgpu_frame(void) { wgpuInstanceProcessEvents(_sapp.wgpu.instance); if (_sapp.wgpu.init_done) { - _sapp.wgpu.swapchain_view = _sapp_wgpu_swapchain_next(); _sapp_frame(); - wgpuTextureViewRelease(_sapp.wgpu.swapchain_view); - _sapp.wgpu.swapchain_view = 0; + if (_sapp.wgpu.swapchain_view) { + wgpuTextureViewRelease(_sapp.wgpu.swapchain_view); + _sapp.wgpu.swapchain_view = 0; + } #if !defined(_SAPP_EMSCRIPTEN) wgpuSurfacePresent(_sapp.wgpu.surface); #endif @@ -4074,6 +4254,671 @@ _SOKOL_PRIVATE void _sapp_wgpu_frame(void) { } #endif // SOKOL_WGPU +// ██ ██ ██ ██ ██ ██ ██ █████ ███ ██ +// ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ +// ██ ██ ██ ██ ██ █████ ███████ ██ ██ ██ +// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +// ████ ██████ ███████ ██ ██ ██ ██ ██ ████ +// +// >>vulkan +// >>vk +#if defined(SOKOL_VULKAN) + +#if defined(__cplusplus) +#define _SAPP_VK_ZERO_COUNT_AND_ARRAY(num, type, count_name, array_name) uint32_t count_name = 0; type array_name[num] = {} +#define _SAPP_VK_MAX_COUNT_AND_ARRAY(num, type, count_name, array_name) uint32_t count_name = num; type array_name[num] = {} +#else +#define _SAPP_VK_ZERO_COUNT_AND_ARRAY(num, type, count_name, array_name) uint32_t count_name = 0; type array_name[num] = {0} +#define _SAPP_VK_MAX_COUNT_AND_ARRAY(num, type, count_name, array_name) uint32_t count_name = num; type array_name[num] = {0} +#endif + +_SOKOL_PRIVATE int _sapp_vk_mem_find_memory_type_index(uint32_t type_filter, VkMemoryPropertyFlags props) { + SOKOL_ASSERT(_sapp.vk.physical_device); + _SAPP_STRUCT(VkPhysicalDeviceMemoryProperties, mem_props); + vkGetPhysicalDeviceMemoryProperties(_sapp.vk.physical_device, &mem_props); + for (uint32_t i = 0; i < mem_props.memoryTypeCount; i++) { + if ((type_filter & (1 << i)) && ((mem_props.memoryTypes[i].propertyFlags & props) == props)) { + return (int)i; + } + } + return -1; +} + +_SOKOL_PRIVATE void _sapp_vk_create_instance(void) { + SOKOL_ASSERT(0 == _sapp.vk.instance); + + _SAPP_STRUCT(VkApplicationInfo, app_info); + app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + app_info.pApplicationName = "sokol-app"; // FIXME: override via sapp_desc? + app_info.applicationVersion = VK_MAKE_VERSION(1, 0, 0); + app_info.pEngineName = "sokol"; + app_info.engineVersion = VK_MAKE_VERSION(1, 0, 0); + app_info.apiVersion = VK_API_VERSION_1_3; + + _SAPP_VK_ZERO_COUNT_AND_ARRAY(32, const char*, layer_count, layer_names); + #if defined(SOKOL_DEBUG) + layer_names[layer_count++] = "VK_LAYER_KHRONOS_validation"; + SOKOL_ASSERT(layer_count <= 32); + #endif + + _SAPP_VK_ZERO_COUNT_AND_ARRAY(32, const char*, ext_count, ext_names); + ext_names[ext_count++] = VK_KHR_SURFACE_EXTENSION_NAME; + #if defined(VK_USE_PLATFORM_XLIB_KHR) + ext_names[ext_count++] = VK_KHR_XLIB_SURFACE_EXTENSION_NAME; + #endif + SOKOL_ASSERT(ext_count <= 32); + + _SAPP_STRUCT(VkInstanceCreateInfo, create_info); + create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + create_info.flags = 0; + create_info.pApplicationInfo = &app_info; + create_info.enabledLayerCount = layer_count; + create_info.ppEnabledLayerNames = layer_names; + create_info.enabledExtensionCount = ext_count; + create_info.ppEnabledExtensionNames = ext_names; + VkResult res = vkCreateInstance(&create_info, 0, &_sapp.vk.instance); + if (res != VK_SUCCESS) { + _SAPP_PANIC(VULKAN_CREATE_INSTANCE_FAILED); + } + SOKOL_ASSERT(_sapp.vk.instance); +} + +_SOKOL_PRIVATE void _sapp_vk_destroy_instance(void) { + SOKOL_ASSERT(_sapp.vk.instance); + vkDestroyInstance(_sapp.vk.instance, 0); + _sapp.vk.instance = 0; +} + +_SOKOL_PRIVATE uint32_t _sapp_vk_required_device_extensions(const char** out_names, uint32_t max_count) { + SOKOL_ASSERT(out_names && (max_count > 0)); + uint32_t count = 0; + out_names[count++] = VK_KHR_SWAPCHAIN_EXTENSION_NAME; + out_names[count++] = VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME; + SOKOL_ASSERT(count <= max_count); _SOKOL_UNUSED(max_count); + return count; +} + +_SOKOL_PRIVATE bool _sapp_vk_check_device_extensions(VkPhysicalDevice pdev, const char** required_exts, uint32_t num_required_exts) { + SOKOL_ASSERT(pdev && required_exts && num_required_exts > 0); + uint32_t ext_count = 0; + VkResult res = vkEnumerateDeviceExtensionProperties(pdev, 0, &ext_count, 0); + SOKOL_ASSERT(res == VK_SUCCESS); _SOKOL_UNUSED(res); + if (ext_count == 0) { + return false; + } + VkExtensionProperties* ext_props = (VkExtensionProperties*) _sapp_malloc(sizeof(VkExtensionProperties) * ext_count); + SOKOL_ASSERT(ext_props); + res = vkEnumerateDeviceExtensionProperties(pdev, 0, &ext_count, ext_props); + bool all_supported = true; + for (uint32_t req_ext_idx = 0; req_ext_idx < num_required_exts; req_ext_idx++) { + const char* req_ext_name = required_exts[req_ext_idx]; + bool required_ext_supported = false; + for (uint32_t ext_idx = 0; ext_idx < ext_count; ext_idx++) { + const VkExtensionProperties* ext_prop = &ext_props[ext_idx]; + if (0 == strcmp(req_ext_name, ext_prop->extensionName)) { + required_ext_supported = true; + break; + } + } + if (!required_ext_supported) { + all_supported = false; + } + } + _sapp_free(ext_props); + return all_supported; +} + +_SOKOL_PRIVATE void _sapp_vk_pick_physical_device(void) { + SOKOL_ASSERT(_sapp.vk.instance); + SOKOL_ASSERT(_sapp.vk.surface); + SOKOL_ASSERT(0 == _sapp.vk.physical_device); + VkResult res = VK_SUCCESS; + + _SAPP_VK_MAX_COUNT_AND_ARRAY(8, VkPhysicalDevice, physical_device_count, physical_devices); + res = vkEnumeratePhysicalDevices(_sapp.vk.instance, &physical_device_count, physical_devices); + if ((res != VK_SUCCESS) && (res != VK_INCOMPLETE)) { + _SAPP_PANIC(VULKAN_ENUMERATE_PHYSICAL_DEVICES_FAILED); + } + if (physical_device_count == 0) { + _SAPP_PANIC(VULKAN_NO_PHYSICAL_DEVICES_FOUND); + } + _SAPP_VK_ZERO_COUNT_AND_ARRAY(32, const char*, ext_count, ext_names); + ext_count = _sapp_vk_required_device_extensions(ext_names, 32); + + VkPhysicalDevice pdev = 0; + for (uint32_t pdev_idx = 0; pdev_idx < physical_device_count; pdev_idx++) { + pdev = physical_devices[pdev_idx]; + _SAPP_STRUCT(VkPhysicalDeviceProperties, dev_props); + vkGetPhysicalDeviceProperties(pdev, &dev_props); + if (dev_props.apiVersion < VK_API_VERSION_1_3) { + continue; + } + if (!_sapp_vk_check_device_extensions(pdev, ext_names, ext_count)) { + continue; + } + // FIXME: handle theoretical case where graphics and present aren't supported by the same queue family index + _SAPP_VK_MAX_COUNT_AND_ARRAY(8, VkQueueFamilyProperties, queue_family_props_count, queue_family_props); + vkGetPhysicalDeviceQueueFamilyProperties(pdev, &queue_family_props_count, queue_family_props); + bool has_required_queues = false; + const VkQueueFlags required_flags = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT; + for (uint32_t qfp_idx = 0; qfp_idx < queue_family_props_count; qfp_idx++) { + const VkQueueFlags queue_flags = queue_family_props[qfp_idx].queueFlags; + if ((queue_flags & required_flags) == required_flags) { + _sapp.vk.queue_family_index = qfp_idx; + has_required_queues = true; + break; + } + } + if (!has_required_queues) { + continue; + } + + VkBool32 presentation_supported = false; + res = vkGetPhysicalDeviceSurfaceSupportKHR(pdev, _sapp.vk.queue_family_index, _sapp.vk.surface, &presentation_supported); + SOKOL_ASSERT(VK_SUCCESS == res); + if (!presentation_supported) { + continue; + } + + // if we arrive here, found a suitable device + break; + } + if (0 == pdev) { + _SAPP_PANIC(VULKAN_NO_SUITABLE_PHYSICAL_DEVICE_FOUND); + } + _sapp.vk.physical_device = pdev; + SOKOL_ASSERT(_sapp.vk.physical_device); +} + +_SOKOL_PRIVATE void _sapp_vk_create_device(void) { + SOKOL_ASSERT(_sapp.vk.physical_device); + SOKOL_ASSERT(0 == _sapp.vk.device); + + const float queue_priority = 0.0f; + _SAPP_STRUCT(VkDeviceQueueCreateInfo, queue_create_info); + queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queue_create_info.queueFamilyIndex = _sapp.vk.queue_family_index; + queue_create_info.queueCount = 1; + queue_create_info.pQueuePriorities = &queue_priority; + + _SAPP_VK_ZERO_COUNT_AND_ARRAY(32, const char*, ext_count, ext_names); + ext_count = _sapp_vk_required_device_extensions(ext_names, 32); + + _SAPP_STRUCT(VkPhysicalDeviceFeatures2, supports); + supports.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + vkGetPhysicalDeviceFeatures2(_sapp.vk.physical_device, &supports); + + _SAPP_STRUCT(VkPhysicalDeviceDescriptorBufferFeaturesEXT, descriptor_buffer_features); + descriptor_buffer_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT; + descriptor_buffer_features.descriptorBuffer = VK_TRUE; + + _SAPP_STRUCT(VkPhysicalDeviceExtendedDynamicStateFeaturesEXT, xds_features); + xds_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT; + xds_features.pNext = &descriptor_buffer_features; + xds_features.extendedDynamicState = VK_TRUE; + + _SAPP_STRUCT(VkPhysicalDeviceVulkan12Features, vk12_features); + vk12_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; + vk12_features.pNext = &xds_features; + vk12_features.bufferDeviceAddress = VK_TRUE; + + _SAPP_STRUCT(VkPhysicalDeviceVulkan13Features, vk13_features); + vk13_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES; + vk13_features.pNext = &vk12_features; + vk13_features.dynamicRendering = VK_TRUE; + vk13_features.synchronization2 = VK_TRUE; + + _SAPP_STRUCT(VkPhysicalDeviceFeatures2, required); + required.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + required.pNext = &vk13_features; + required.features.samplerAnisotropy = VK_TRUE; + if (supports.features.textureCompressionBC) { + required.features.textureCompressionBC = VK_TRUE; + } + if (supports.features.textureCompressionETC2) { + required.features.textureCompressionETC2 = VK_TRUE; + } + if (supports.features.textureCompressionASTC_LDR) { + required.features.textureCompressionASTC_LDR = VK_TRUE; + } + _SAPP_STRUCT(VkDeviceCreateInfo, dev_create_info); + dev_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + dev_create_info.pNext = &required; + dev_create_info.queueCreateInfoCount = 1; + dev_create_info.pQueueCreateInfos = &queue_create_info; + dev_create_info.enabledExtensionCount = ext_count; + dev_create_info.ppEnabledExtensionNames = ext_names; + + VkResult res = vkCreateDevice(_sapp.vk.physical_device, &dev_create_info, 0, &_sapp.vk.device); + if (res != VK_SUCCESS) { + switch (res) { + case VK_ERROR_EXTENSION_NOT_PRESENT: + _SAPP_PANIC(VULKAN_CREATE_DEVICE_FAILED_EXTENSION_NOT_PRESENT); + break; + case VK_ERROR_FEATURE_NOT_PRESENT: + _SAPP_PANIC(VULKAN_CREATE_DEVICE_FAILED_FEATURE_NOT_PRESENT); + break; + case VK_ERROR_INITIALIZATION_FAILED: + _SAPP_PANIC(VULKAN_CREATE_DEVICE_FAILED_INITIALIZATION_FAILED); + break; + default: + _SAPP_PANIC(VULKAN_CREATE_DEVICE_FAILED_OTHER); + break; + } + } + SOKOL_ASSERT(_sapp.vk.device); + + SOKOL_ASSERT(0 == _sapp.vk.queue); + vkGetDeviceQueue(_sapp.vk.device, _sapp.vk.queue_family_index, 0, &_sapp.vk.queue); + SOKOL_ASSERT(_sapp.vk.queue); +} + +_SOKOL_PRIVATE void _sapp_vk_destroy_device(void) { + SOKOL_ASSERT(_sapp.vk.device); + vkDestroyDevice(_sapp.vk.device, 0); + _sapp.vk.device = 0; + _sapp.vk.queue = 0; +} + +_SOKOL_PRIVATE void _sapp_vk_create_surface(void) { + SOKOL_ASSERT(_sapp.vk.instance); + SOKOL_ASSERT(0 == _sapp.vk.surface); + VkResult res = VK_SUCCESS; + + #if defined(_SAPP_LINUX) + _SAPP_STRUCT(VkXlibSurfaceCreateInfoKHR, xlib_info); + xlib_info.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; + xlib_info.dpy = _sapp.x11.display; + xlib_info.window = _sapp.x11.window; + res = vkCreateXlibSurfaceKHR(_sapp.vk.instance, &xlib_info, 0, &_sapp.vk.surface); + #else + #error "sokol_app.h: unsupported Vulkan platform" + #endif + if (res != VK_SUCCESS) { + _SAPP_PANIC(VULKAN_CREATE_SURFACE_FAILED); + } + SOKOL_ASSERT(_sapp.vk.surface); +} + +_SOKOL_PRIVATE void _sapp_vk_destroy_surface(void) { + SOKOL_ASSERT(_sapp.vk.instance); + SOKOL_ASSERT(_sapp.vk.surface); + vkDestroySurfaceKHR(_sapp.vk.instance, _sapp.vk.surface, 0); + _sapp.vk.surface = 0; +} + +_SOKOL_PRIVATE VkSurfaceFormatKHR _sapp_vk_pick_surface_format(void) { + SOKOL_ASSERT(_sapp.vk.instance); + SOKOL_ASSERT(_sapp.vk.surface); + _SAPP_VK_MAX_COUNT_AND_ARRAY(64, VkSurfaceFormatKHR, fmt_count, formats); + VkResult res = vkGetPhysicalDeviceSurfaceFormatsKHR(_sapp.vk.physical_device, _sapp.vk.surface, &fmt_count, formats); + SOKOL_ASSERT((res == VK_SUCCESS) || (res == VK_INCOMPLETE)); _SOKOL_UNUSED(res); + SOKOL_ASSERT(fmt_count > 0); + // FIXME: only accept non-SRGB formats until sokol_app.h gets proper SRGB support + for (uint32_t i = 0; i < fmt_count; i++) { + switch (formats[i].format) { + case VK_FORMAT_B8G8R8A8_UNORM: + case VK_FORMAT_R8G8B8A8_UNORM: + return formats[i]; + default: break; + } + } + // FIXME: fallback might still return an SRGB format + return formats[0]; +} + +_SOKOL_PRIVATE void _sapp_vk_create_sync_objects(void) { + SOKOL_ASSERT(_sapp.vk.device); + _SAPP_STRUCT(VkSemaphoreCreateInfo, create_info); + create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + VkResult res; + _SOKOL_UNUSED(res); + for (uint32_t i = 0; i < _sapp.vk.num_swapchain_images; i++) { + SOKOL_ASSERT(0 == _sapp.vk.sync[i].present_complete_sem); + SOKOL_ASSERT(0 == _sapp.vk.sync[i].render_finished_sem); + res = vkCreateSemaphore(_sapp.vk.device, &create_info, 0, &_sapp.vk.sync[i].present_complete_sem); + SOKOL_ASSERT((res == VK_SUCCESS) && (_sapp.vk.sync[i].present_complete_sem)); + res = vkCreateSemaphore(_sapp.vk.device, &create_info, 0, &_sapp.vk.sync[i].render_finished_sem); + SOKOL_ASSERT((res == VK_SUCCESS) && (_sapp.vk.sync[i].render_finished_sem)); + } +} + +_SOKOL_PRIVATE void _sapp_vk_destroy_sync_objects(void) { + SOKOL_ASSERT(_sapp.vk.device); + for (uint32_t i = 0; i < _sapp.vk.num_swapchain_images; i++) { + SOKOL_ASSERT(_sapp.vk.sync[i].present_complete_sem); + SOKOL_ASSERT(_sapp.vk.sync[i].render_finished_sem); + vkDestroySemaphore(_sapp.vk.device, _sapp.vk.sync[i].present_complete_sem, 0); + vkDestroySemaphore(_sapp.vk.device, _sapp.vk.sync[i].render_finished_sem, 0); + _sapp.vk.sync[i].present_complete_sem = 0; + _sapp.vk.sync[i].render_finished_sem = 0; + } +} + +_SOKOL_PRIVATE VkDeviceMemory _sapp_vk_mem_alloc_image_memory(const VkMemoryRequirements* mem_reqs) { + SOKOL_ASSERT(_sapp.vk.device); + SOKOL_ASSERT(mem_reqs); + int mem_type_index = _sapp_vk_mem_find_memory_type_index(mem_reqs->memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + if (-1 == mem_type_index) { + _SAPP_ERROR(VULKAN_ALLOC_DEVICE_MEMORY_NO_SUITABLE_MEMORY_TYPE); + return 0; + } + _SAPP_STRUCT(VkMemoryAllocateInfo, alloc_info); + alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + alloc_info.allocationSize = mem_reqs->size; + alloc_info.memoryTypeIndex = (uint32_t) mem_type_index; + VkDeviceMemory vk_dev_mem = 0; + VkResult res = vkAllocateMemory(_sapp.vk.device, &alloc_info, 0, &vk_dev_mem); + if (res != VK_SUCCESS) { + _SAPP_ERROR(VULKAN_ALLOCATE_MEMORY_FAILED); + return 0; + } + SOKOL_ASSERT(vk_dev_mem); + return vk_dev_mem; +} + +_SOKOL_PRIVATE void _sapp_vk_mem_free_image_memory(VkDeviceMemory vk_dev_mem) { + SOKOL_ASSERT(_sapp.vk.device); + SOKOL_ASSERT(vk_dev_mem); + vkFreeMemory(_sapp.vk.device, vk_dev_mem, 0); +} + +_SOKOL_PRIVATE void _sapp_vk_swapchain_destroy_surface(_sapp_vk_swapchain_surface_t* surf) { + SOKOL_ASSERT(surf); + SOKOL_ASSERT(surf->img); + SOKOL_ASSERT(surf->mem); + SOKOL_ASSERT(surf->view); + vkDestroyImageView(_sapp.vk.device, surf->view, 0); + surf->view = 0; + _sapp_vk_mem_free_image_memory(surf->mem); + surf->mem = 0; + vkDestroyImage(_sapp.vk.device, surf->img, 0); + surf->img = 0; +} + +_SOKOL_PRIVATE void _sapp_vk_swapchain_create_surface( + _sapp_vk_swapchain_surface_t* surf, + bool recreate, + VkFormat format, + uint32_t width, + uint32_t height, + VkSampleCountFlagBits sample_count_flags, + VkImageUsageFlags usage, + VkImageAspectFlags aspect_mask) +{ + SOKOL_ASSERT(_sapp.vk.physical_device); + SOKOL_ASSERT(_sapp.vk.device); + SOKOL_ASSERT(surf); + if (recreate) { + _sapp_vk_swapchain_destroy_surface(surf); + } + SOKOL_ASSERT(0 == surf->img); + SOKOL_ASSERT(0 == surf->mem); + SOKOL_ASSERT(0 == surf->view); + VkResult res; + + _SAPP_STRUCT(VkImageCreateInfo, img_create_info); + img_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + img_create_info.imageType = VK_IMAGE_TYPE_2D; + img_create_info.format = format; + img_create_info.extent.width = width; + img_create_info.extent.height = height; + img_create_info.extent.depth = 1; + img_create_info.mipLevels = 1; + img_create_info.arrayLayers = 1; + img_create_info.samples = sample_count_flags; + img_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; + img_create_info.usage = usage; + img_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + img_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + res = vkCreateImage(_sapp.vk.device, &img_create_info, 0, &surf->img); + if (res != VK_SUCCESS) { + _SAPP_PANIC(VULKAN_SWAPCHAIN_CREATE_IMAGE_FAILED); + } + SOKOL_ASSERT(surf->img); + + _SAPP_STRUCT(VkMemoryRequirements, mem_reqs); + vkGetImageMemoryRequirements(_sapp.vk.device, surf->img, &mem_reqs); + surf->mem = _sapp_vk_mem_alloc_image_memory(&mem_reqs); + if (0 == surf->mem) { + _SAPP_PANIC(VULKAN_SWAPCHAIN_ALLOC_IMAGE_DEVICE_MEMORY_FAILED); + } + res = vkBindImageMemory(_sapp.vk.device, surf->img, surf->mem, 0); + if (res != VK_SUCCESS) { + _SAPP_PANIC(VULKAN_SWAPCHAIN_BIND_IMAGE_MEMORY_FAILED); + } + SOKOL_ASSERT(surf->mem); + + _SAPP_STRUCT(VkImageViewCreateInfo, view_create_info); + view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + view_create_info.image = surf->img; + view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; + view_create_info.format = format; + view_create_info.subresourceRange.aspectMask = aspect_mask; + view_create_info.subresourceRange.levelCount = 1; + view_create_info.subresourceRange.layerCount = 1; + res = vkCreateImageView(_sapp.vk.device, &view_create_info, 0, &surf->view); + if (res != VK_SUCCESS) { + _SAPP_PANIC(VULKAN_SWAPCHAIN_CREATE_IMAGE_VIEW_FAILED); + } + SOKOL_ASSERT(surf->view); +} + +_SOKOL_PRIVATE void _sapp_vk_create_swapchain(bool recreate) { + SOKOL_ASSERT(_sapp.vk.physical_device); + SOKOL_ASSERT(_sapp.vk.surface); + SOKOL_ASSERT(_sapp.vk.device); + if (!recreate) { + SOKOL_ASSERT(0 == _sapp.vk.swapchain); + SOKOL_ASSERT(0 == _sapp.vk.num_swapchain_images); + SOKOL_ASSERT(0 == _sapp.vk.swapchain_images[0]); + SOKOL_ASSERT(0 == _sapp.vk.swapchain_views[0]); + } else { + SOKOL_ASSERT(_sapp.vk.swapchain); + SOKOL_ASSERT(_sapp.vk.num_swapchain_images > 0); + SOKOL_ASSERT(_sapp.vk.swapchain_images[0]); + SOKOL_ASSERT(_sapp.vk.swapchain_views[0]); + } + + VkSwapchainKHR old_swapchain = _sapp.vk.swapchain; + + _SAPP_STRUCT(VkSurfaceCapabilitiesKHR, surf_caps); + VkResult res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(_sapp.vk.physical_device, _sapp.vk.surface, &surf_caps); + SOKOL_ASSERT(res == VK_SUCCESS); + const uint32_t width = surf_caps.currentExtent.width; + const uint32_t height = surf_caps.currentExtent.height; + + _sapp.vk.surface_format = _sapp_vk_pick_surface_format(); + // FIXME: pick better present-mode if supported + VkPresentModeKHR present_mode = VK_PRESENT_MODE_FIFO_KHR; + + // FIXME: better imageExtent (scale vs no-scale!) + _SAPP_STRUCT(VkSwapchainCreateInfoKHR, create_info); + create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + create_info.flags = 0; // FIXME? + create_info.surface = _sapp.vk.surface; + create_info.minImageCount = surf_caps.minImageCount; + create_info.imageFormat = _sapp.vk.surface_format.format; + create_info.imageColorSpace = _sapp.vk.surface_format.colorSpace; + create_info.imageExtent.width = width; + create_info.imageExtent.height = height; + create_info.imageArrayLayers = 1; + create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + create_info.preTransform = surf_caps.currentTransform; + create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + create_info.presentMode = present_mode; + create_info.clipped = true; + create_info.oldSwapchain = old_swapchain; + res = vkCreateSwapchainKHR(_sapp.vk.device, &create_info, 0, &_sapp.vk.swapchain); + if (res != VK_SUCCESS) { + _SAPP_PANIC(VULKAN_CREATE_SWAPCHAIN_FAILED); + } + SOKOL_ASSERT(_sapp.vk.swapchain); + + if (old_swapchain) { + // NOTE: destroying the depth- and msaa-surfaces happens + // down in the respective _sapp_vk_swapchain_create_surface() calls! + for (uint32_t i = 0; i < _sapp.vk.num_swapchain_images; i++) { + SOKOL_ASSERT(_sapp.vk.swapchain_views[i]); + vkDestroyImageView(_sapp.vk.device, _sapp.vk.swapchain_views[i], 0); + _sapp.vk.swapchain_views[i] = 0; + } + vkDestroySwapchainKHR(_sapp.vk.device, old_swapchain, 0); + } + + _sapp.vk.num_swapchain_images = _SAPP_VK_MAX_SWAPCHAIN_IMAGES; + res = vkGetSwapchainImagesKHR(_sapp.vk.device, + _sapp.vk.swapchain, + &_sapp.vk.num_swapchain_images, + _sapp.vk.swapchain_images); + SOKOL_ASSERT(res == VK_SUCCESS); + SOKOL_ASSERT(_sapp.vk.num_swapchain_images >= surf_caps.minImageCount); + + _SAPP_STRUCT(VkImageViewCreateInfo, view_create_info); + view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; + view_create_info.format = _sapp.vk.surface_format.format; + view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + view_create_info.subresourceRange.levelCount = 1; + view_create_info.subresourceRange.layerCount = 1; + for (uint32_t i = 0; i < _sapp.vk.num_swapchain_images; i++) { + SOKOL_ASSERT(_sapp.vk.swapchain_images[i]); + SOKOL_ASSERT(0 == _sapp.vk.swapchain_views[i]); + view_create_info.image = _sapp.vk.swapchain_images[i]; + res = vkCreateImageView(_sapp.vk.device, &view_create_info, 0, &_sapp.vk.swapchain_views[i]); + if (res != VK_SUCCESS) { + _SAPP_PANIC(VULKAN_SWAPCHAIN_CREATE_IMAGE_VIEW_FAILED); + } + SOKOL_ASSERT(_sapp.vk.swapchain_views[i]); + } + + // create depth-stencil buffer + _sapp_vk_swapchain_create_surface(&_sapp.vk.depth, + recreate, + VK_FORMAT_D32_SFLOAT_S8_UINT, + width, + height, + (VkSampleCountFlagBits)_sapp.sample_count, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, + VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); + + // optionally create MSAA surface + if (_sapp.sample_count > 1) { + _sapp_vk_swapchain_create_surface(&_sapp.vk.msaa, + recreate, + _sapp.vk.surface_format.format, + width, + height, + (VkSampleCountFlagBits)_sapp.sample_count, + VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + VK_IMAGE_ASPECT_COLOR_BIT); + } + + // this is the only place in the Vulkan code path which updates + // _sapp.framebuffer_width/height + _sapp.framebuffer_width = (int)surf_caps.currentExtent.width; + _sapp.framebuffer_height = (int)surf_caps.currentExtent.height; +} + +_SOKOL_PRIVATE void _sapp_vk_destroy_swapchain(void) { + SOKOL_ASSERT(_sapp.vk.device); + SOKOL_ASSERT(_sapp.vk.swapchain); + SOKOL_ASSERT(_sapp.vk.num_swapchain_images > 0); + if (_sapp.vk.msaa.img) { + _sapp_vk_swapchain_destroy_surface(&_sapp.vk.msaa); + } + _sapp_vk_swapchain_destroy_surface(&_sapp.vk.depth); + for (uint32_t i = 0; i < _sapp.vk.num_swapchain_images; i++) { + SOKOL_ASSERT(_sapp.vk.swapchain_views[i]); + vkDestroyImageView(_sapp.vk.device, _sapp.vk.swapchain_views[i], 0); + _sapp.vk.swapchain_views[i] = 0; + _sapp.vk.swapchain_images[i] = 0; + + } + vkDestroySwapchainKHR(_sapp.vk.device, _sapp.vk.swapchain, 0); + _sapp.vk.swapchain = 0; + _sapp.vk.num_swapchain_images = 0; +} + +#if defined(_SAPP_LINUX) +_SOKOL_PRIVATE void _sapp_x11_app_event(sapp_event_type type); +#endif + +_SOKOL_PRIVATE void _sapp_vk_recreate_swapchain(void) { + SOKOL_ASSERT(_sapp.vk.device); + vkDeviceWaitIdle(_sapp.vk.device); + int fb_width = _sapp.framebuffer_width; + int fb_height = _sapp.framebuffer_height; + _sapp_vk_create_swapchain(true); + if ((fb_width != _sapp.framebuffer_width) || (fb_height != _sapp.framebuffer_height)) { + if (!_sapp.first_frame) { + #if defined(_SAPP_LINUX) + _sapp_x11_app_event(SAPP_EVENTTYPE_RESIZED); + #endif + } + } +} + +_SOKOL_PRIVATE void _sapp_vk_init(void) { + _sapp_vk_create_instance(); + _sapp_vk_create_surface(); + _sapp_vk_pick_physical_device(); + _sapp_vk_create_device(); + _sapp_vk_create_swapchain(false); + _sapp_vk_create_sync_objects(); +} + +_SOKOL_PRIVATE void _sapp_vk_discard(void) { + SOKOL_ASSERT(_sapp.vk.device); + vkDeviceWaitIdle(_sapp.vk.device); + _sapp_vk_destroy_sync_objects(); + _sapp_vk_destroy_swapchain(); + _sapp_vk_destroy_device(); + _sapp_vk_destroy_surface(); + _sapp_vk_destroy_instance(); +} + +_SOKOL_PRIVATE void _sapp_vk_swapchain_next(void) { + SOKOL_ASSERT(_sapp.vk.device); + SOKOL_ASSERT(_sapp.vk.swapchain); + VkResult res = vkAcquireNextImageKHR( + _sapp.vk.device, + _sapp.vk.swapchain, + UINT64_MAX, // timeout + _sapp.vk.sync[_sapp.vk.sync_slot].present_complete_sem, // semaphore to signal + 0, // fence to signal + &_sapp.vk.cur_swapchain_image_index); + if ((res != VK_NOT_READY) && (res != VK_SUBOPTIMAL_KHR) && (res != VK_SUCCESS) && (res != VK_TIMEOUT)) { + _SAPP_WARN(VULKAN_ACQUIRE_NEXT_IMAGE_FAILED); + } +} + +_SOKOL_PRIVATE void _sapp_vk_present(void) { + SOKOL_ASSERT(_sapp.vk.queue); + _SAPP_STRUCT(VkPresentInfoKHR, present_info); + present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + present_info.waitSemaphoreCount = 1; + present_info.pWaitSemaphores = &_sapp.vk.sync[_sapp.vk.cur_swapchain_image_index].render_finished_sem; + present_info.swapchainCount = 1; + present_info.pSwapchains = &_sapp.vk.swapchain; + present_info.pImageIndices = &_sapp.vk.cur_swapchain_image_index; + VkResult res = vkQueuePresentKHR(_sapp.vk.queue, &present_info); + if ((res == VK_ERROR_OUT_OF_DATE_KHR) || (res == VK_SUBOPTIMAL_KHR)) { + _sapp_vk_recreate_swapchain(); + } else if (res != VK_SUCCESS) { + _SAPP_WARN(VULKAN_QUEUE_PRESENT_FAILED); + } +} + +_SOKOL_PRIVATE void _sapp_vk_frame(void) { + _sapp_frame(); + _sapp_vk_present(); + _sapp.vk.sync_slot = (_sapp.vk.sync_slot + 1) % _sapp.vk.num_swapchain_images; +} + +#endif // SOKOL_VULKAN + // █████ ██████ ██████ ██ ███████ // ██ ██ ██ ██ ██ ██ ██ ██ // ███████ ██████ ██████ ██ █████ @@ -4151,7 +4996,7 @@ _SOKOL_PRIVATE void _sapp_macos_gl_init(NSRect window_rect) { attrs[i++] = NSOpenGLPFAAccelerated; attrs[i++] = NSOpenGLPFADoubleBuffer; attrs[i++] = NSOpenGLPFAOpenGLProfile; - const int glVersion = _sapp.desc.gl_major_version * 10 + _sapp.desc.gl_minor_version; + const int glVersion = _sapp.desc.gl.major_version * 10 + _sapp.desc.gl.minor_version; switch(glVersion) { case 10: attrs[i++] = NSOpenGLProfileVersionLegacy; break; case 32: attrs[i++] = NSOpenGLProfileVersion3_2Core; break; @@ -5503,7 +6348,7 @@ _SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) { _sapp.onscreen_keyboard_shown = true; /* query the keyboard's size, and modify the content view's size */ #if !defined(_SAPP_TVOS) - if (_sapp.desc.ios_keyboard_resizes_canvas) { + if (_sapp.desc.ios.keyboard_resizes_canvas) { NSDictionary* info = notif.userInfo; CGFloat kbd_h = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height; CGRect view_frame = UIScreen.mainScreen.bounds; @@ -5514,14 +6359,14 @@ _SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) { } - (void)keyboardWillBeHidden:(NSNotification*)notif { _sapp.onscreen_keyboard_shown = false; - if (_sapp.desc.ios_keyboard_resizes_canvas) { + if (_sapp.desc.ios.keyboard_resizes_canvas) { _sapp.ios.view.frame = UIScreen.mainScreen.bounds; } } - (void)keyboardDidChangeFrame:(NSNotification*)notif { /* this is for the case when the screen rotation changes while the keyboard is open */ #if !defined(_SAPP_TVOS) - if (_sapp.onscreen_keyboard_shown && _sapp.desc.ios_keyboard_resizes_canvas) { + if (_sapp.onscreen_keyboard_shown && _sapp.desc.ios.keyboard_resizes_canvas) { NSDictionary* info = notif.userInfo; CGFloat kbd_h = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height; CGRect view_frame = UIScreen.mainScreen.bounds; @@ -6240,7 +7085,7 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_size_changed(int event_type, const EmscriptenU _SOKOL_PRIVATE EM_BOOL _sapp_emsc_mouse_cb(int emsc_type, const EmscriptenMouseEvent* emsc_event, void* user_data) { _SOKOL_UNUSED(user_data); - bool consume_event = !_sapp.desc.html5_bubble_mouse_events; + bool consume_event = !_sapp.desc.html5.bubble_mouse_events; _sapp.emsc.mouse_buttons = emsc_event->buttons; if (_sapp.mouse.locked) { _sapp.mouse.dx = (float) emsc_event->movementX; @@ -6314,7 +7159,7 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_mouse_cb(int emsc_type, const EmscriptenMouseE _SOKOL_PRIVATE EM_BOOL _sapp_emsc_wheel_cb(int emsc_type, const EmscriptenWheelEvent* emsc_event, void* user_data) { _SOKOL_UNUSED(emsc_type); _SOKOL_UNUSED(user_data); - bool consume_event = !_sapp.desc.html5_bubble_wheel_events; + bool consume_event = !_sapp.desc.html5.bubble_wheel_events; _sapp.emsc.mouse_buttons = emsc_event->mouse.buttons; if (_sapp_events_enabled()) { _sapp_init_event(SAPP_EVENTTYPE_MOUSE_SCROLL); @@ -6489,7 +7334,7 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_key_cb(int emsc_type, const EmscriptenKeyboard if (type == SAPP_EVENTTYPE_CHAR) { // NOTE: charCode doesn't appear to be supported on Android Chrome _sapp.event.char_code = emsc_event->charCode; - consume_event |= !_sapp.desc.html5_bubble_char_events; + consume_event |= !_sapp.desc.html5.bubble_char_events; } else { if (0 != emsc_event->code[0]) { // This code path is for desktop browsers which send untranslated 'physical' key code strings @@ -6518,7 +7363,7 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_key_cb(int emsc_type, const EmscriptenKeyboard // 'character key events' will always need to bubble up, otherwise the browser // wouldn't be able to generate character events. if (!_sapp_emsc_is_char_key(_sapp.event.key_code)) { - consume_event |= !_sapp.desc.html5_bubble_key_events; + consume_event |= !_sapp.desc.html5.bubble_key_events; } } consume_event |= _sapp_call_event(&_sapp.event); @@ -6534,7 +7379,7 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_key_cb(int emsc_type, const EmscriptenKeyboard _SOKOL_PRIVATE EM_BOOL _sapp_emsc_touch_cb(int emsc_type, const EmscriptenTouchEvent* emsc_event, void* user_data) { _SOKOL_UNUSED(user_data); - bool consume_event = !_sapp.desc.html5_bubble_touch_events; + bool consume_event = !_sapp.desc.html5.bubble_touch_events; if (_sapp_events_enabled()) { sapp_event_type type; switch (emsc_type) { @@ -6621,8 +7466,8 @@ _SOKOL_PRIVATE void _sapp_emsc_webgl_init(void) { attrs.depth = true; attrs.stencil = true; attrs.antialias = _sapp.sample_count > 1; - attrs.premultipliedAlpha = _sapp.desc.html5_premultiplied_alpha; - attrs.preserveDrawingBuffer = _sapp.desc.html5_preserve_drawing_buffer; + attrs.premultipliedAlpha = _sapp.desc.html5.premultiplied_alpha; + attrs.preserveDrawingBuffer = _sapp.desc.html5.preserve_drawing_buffer; attrs.enableExtensionsByDefault = true; attrs.majorVersion = 2; EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_create_context(_sapp.html5_canvas_selector, &attrs); @@ -6686,7 +7531,7 @@ _SOKOL_PRIVATE void _sapp_emsc_unregister_eventhandlers(void) { emscripten_set_focus_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, true, 0); emscripten_set_blur_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, true, 0); emscripten_set_fullscreenchange_callback(_sapp.html5_canvas_selector, 0, true, 0); - if (!_sapp.desc.html5_canvas_resize) { + if (!_sapp.desc.html5.canvas_resize) { emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, true, 0); } sapp_js_remove_beforeunload_listener(); @@ -6742,10 +7587,10 @@ _SOKOL_PRIVATE void _sapp_emsc_frame_main_loop(void) { _SOKOL_PRIVATE void _sapp_emsc_run(const sapp_desc* desc) { _sapp_init_state(desc); _sapp.fullscreen = false; // override user provided fullscreen state: can't start in fullscreen on the web! - const char* document_title = desc->html5_update_document_title ? _sapp.window_title : 0; + const char* document_title = desc->html5.update_document_title ? _sapp.window_title : 0; sapp_js_init(_sapp.html5_canvas_selector, document_title); double w, h; - if (_sapp.desc.html5_canvas_resize) { + if (_sapp.desc.html5.canvas_resize) { w = (double) _sapp_def(_sapp.desc.width, _SAPP_FALLBACK_DEFAULT_WINDOW_WIDTH); h = (double) _sapp_def(_sapp.desc.height, _SAPP_FALLBACK_DEFAULT_WINDOW_HEIGHT); } else { @@ -6770,8 +7615,8 @@ _SOKOL_PRIVATE void _sapp_emsc_run(const sapp_desc* desc) { sapp_set_icon(&desc->icon); // start the frame loop - if (_sapp.desc.html5_use_emsc_set_main_loop) { - emscripten_set_main_loop(_sapp_emsc_frame_main_loop, 0, _sapp.desc.html5_emsc_set_main_loop_simulate_infinite_loop); + if (_sapp.desc.html5.use_emsc_set_main_loop) { + emscripten_set_main_loop(_sapp_emsc_frame_main_loop, 0, _sapp.desc.html5.emsc_set_main_loop_simulate_infinite_loop); } else { emscripten_request_animation_frame_loop(_sapp_emsc_frame_animation_loop, 0); } @@ -7694,8 +8539,8 @@ _SOKOL_PRIVATE void _sapp_wgl_create_context(void) { _SAPP_PANIC(WIN32_WGL_ARB_CREATE_CONTEXT_PROFILE_REQUIRED); } const int attrs[] = { - WGL_CONTEXT_MAJOR_VERSION_ARB, _sapp.desc.gl_major_version, - WGL_CONTEXT_MINOR_VERSION_ARB, _sapp.desc.gl_minor_version, + WGL_CONTEXT_MAJOR_VERSION_ARB, _sapp.desc.gl.major_version, + WGL_CONTEXT_MINOR_VERSION_ARB, _sapp.desc.gl.minor_version, #if defined(SOKOL_DEBUG) WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB | WGL_CONTEXT_DEBUG_BIT_ARB, #else @@ -8560,12 +9405,12 @@ _SOKOL_PRIVATE void _sapp_win32_destroy_icons(void) { } _SOKOL_PRIVATE void _sapp_win32_init_console(void) { - if (_sapp.desc.win32_console_create || _sapp.desc.win32_console_attach) { + if (_sapp.desc.win32.console_create || _sapp.desc.win32.console_attach) { BOOL con_valid = FALSE; - if (_sapp.desc.win32_console_attach) { + if (_sapp.desc.win32.console_attach) { con_valid = AttachConsole(ATTACH_PARENT_PROCESS); } - if (!con_valid && _sapp.desc.win32_console_create) { + if (!con_valid && _sapp.desc.win32.console_create) { con_valid = AllocConsole(); } if (con_valid) { @@ -8577,14 +9422,14 @@ _SOKOL_PRIVATE void _sapp_win32_init_console(void) { (void)err; } } - if (_sapp.desc.win32_console_utf8) { + if (_sapp.desc.win32.console_utf8) { _sapp.win32.orig_codepage = GetConsoleOutputCP(); SetConsoleOutputCP(CP_UTF8); } } _SOKOL_PRIVATE void _sapp_win32_restore_console(void) { - if (_sapp.desc.win32_console_utf8) { + if (_sapp.desc.win32.console_utf8) { SetConsoleOutputCP(_sapp.win32.orig_codepage); } } @@ -9058,8 +9903,8 @@ _SOKOL_PRIVATE bool _sapp_android_init_egl(void) { } EGLint ctx_attributes[] = { - EGL_CONTEXT_MAJOR_VERSION, _sapp.desc.gl_major_version, - EGL_CONTEXT_MINOR_VERSION, _sapp.desc.gl_minor_version, + EGL_CONTEXT_MAJOR_VERSION, _sapp.desc.gl.major_version, + EGL_CONTEXT_MINOR_VERSION, _sapp.desc.gl.minor_version, EGL_NONE, }; EGLContext context = eglCreateContext(display, config, EGL_NO_CONTEXT, ctx_attributes); @@ -11158,8 +12003,8 @@ _SOKOL_PRIVATE void _sapp_glx_create_context(void) { } _sapp_x11_grab_error_handler(); const int attribs[] = { - GLX_CONTEXT_MAJOR_VERSION_ARB, _sapp.desc.gl_major_version, - GLX_CONTEXT_MINOR_VERSION_ARB, _sapp.desc.gl_minor_version, + GLX_CONTEXT_MAJOR_VERSION_ARB, _sapp.desc.gl.major_version, + GLX_CONTEXT_MINOR_VERSION_ARB, _sapp.desc.gl.minor_version, GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, 0, 0 @@ -11246,19 +12091,23 @@ _SOKOL_PRIVATE void _sapp_x11_update_dimensions(int x11_window_width, int x11_wi const float window_scale = _sapp.x11.dpi / 96.0f; _sapp.window_width = _sapp_roundf_gzero(x11_window_width / window_scale); _sapp.window_height = _sapp_roundf_gzero(x11_window_height / window_scale); - int cur_fb_width = _sapp.framebuffer_width; - int cur_fb_height = _sapp.framebuffer_height; - _sapp.framebuffer_width = _sapp_roundf_gzero(_sapp.window_width * _sapp.dpi_scale); - _sapp.framebuffer_height = _sapp_roundf_gzero(_sapp.window_height * _sapp.dpi_scale); - bool dim_changed = (_sapp.framebuffer_width != cur_fb_width) || (_sapp.framebuffer_height != cur_fb_height); - if (dim_changed) { - #if defined(SOKOL_WGPU) - _sapp_wgpu_swapchain_size_changed(); - #endif - if (!_sapp.first_frame) { - _sapp_x11_app_event(SAPP_EVENTTYPE_RESIZED); + // NOTE: on Vulkan, updating the framebuffer dimensions is entirely handled + // by the swapchain management code + #if !defined(SOKOL_VULKAN) + int cur_fb_width = _sapp.framebuffer_width; + int cur_fb_height = _sapp.framebuffer_height; + _sapp.framebuffer_width = _sapp_roundf_gzero(_sapp.window_width * _sapp.dpi_scale); + _sapp.framebuffer_height = _sapp_roundf_gzero(_sapp.window_height * _sapp.dpi_scale); + bool dim_changed = (_sapp.framebuffer_width != cur_fb_width) || (_sapp.framebuffer_height != cur_fb_height); + if (dim_changed) { + #if defined(SOKOL_WGPU) + _sapp_wgpu_swapchain_size_changed(); + #endif + if (!_sapp.first_frame) { + _sapp_x11_app_event(SAPP_EVENTTYPE_RESIZED); + } } - } + #endif } _SOKOL_PRIVATE void _sapp_x11_update_dimensions_from_window_size(void) { @@ -12400,8 +13249,8 @@ _SOKOL_PRIVATE void _sapp_egl_init(void) { } EGLint ctx_attrs[] = { - EGL_CONTEXT_MAJOR_VERSION, _sapp.desc.gl_major_version, - EGL_CONTEXT_MINOR_VERSION, _sapp.desc.gl_minor_version, + EGL_CONTEXT_MAJOR_VERSION, _sapp.desc.gl.major_version, + EGL_CONTEXT_MINOR_VERSION, _sapp.desc.gl.minor_version, #if defined(SOKOL_GLCORE) EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, #endif @@ -12446,6 +13295,8 @@ _SOKOL_PRIVATE void _sapp_linux_frame(void) { _sapp_x11_update_dimensions_from_window_size(); #if defined(SOKOL_WGPU) _sapp_wgpu_frame(); + #elif defined(SOKOL_VULKAN) + _sapp_vk_frame(); #else _sapp_frame(); #if defined(_SAPP_GLX) @@ -12496,6 +13347,9 @@ _SOKOL_PRIVATE void _sapp_linux_run(const sapp_desc* desc) { #elif defined(SOKOL_WGPU) _sapp_x11_create_window(0, 0); _sapp_wgpu_init(); + #elif defined(SOKOL_VULKAN) + _sapp_x11_create_window(0, 0); + _sapp_vk_init(); #endif sapp_set_icon(&desc->icon); _sapp.valid = true; @@ -12532,6 +13386,8 @@ _SOKOL_PRIVATE void _sapp_linux_run(const sapp_desc* desc) { _sapp_egl_destroy(); #elif defined(SOKOL_WGPU) _sapp_wgpu_discard(); + #elif defined(SOKOL_VULKAN) + _sapp_vk_discard(); #endif _sapp_x11_destroy_window(); _sapp_x11_destroy_standard_cursors(); @@ -12624,26 +13480,37 @@ SOKOL_API_IMPL float sapp_heightf(void) { return (float)sapp_height(); } -SOKOL_API_IMPL int sapp_color_format(void) { +SOKOL_API_IMPL sapp_pixel_format sapp_color_format(void) { #if defined(SOKOL_WGPU) switch (_sapp.wgpu.render_format) { case WGPUTextureFormat_RGBA8Unorm: - return _SAPP_PIXELFORMAT_RGBA8; + return SAPP_PIXELFORMAT_RGBA8; case WGPUTextureFormat_BGRA8Unorm: - return _SAPP_PIXELFORMAT_BGRA8; + return SAPP_PIXELFORMAT_BGRA8; default: SOKOL_UNREACHABLE; - return 0; + return SAPP_PIXELFORMAT_NONE; + } + #elif defined(SOKOL_VULKAN) + switch (_sapp.vk.surface_format.format) { + case VK_FORMAT_R8G8B8A8_UNORM: + return SAPP_PIXELFORMAT_RGBA8; + case VK_FORMAT_B8G8R8A8_UNORM: + return SAPP_PIXELFORMAT_BGRA8; + default: + // FIXME! + SOKOL_UNREACHABLE; + return SAPP_PIXELFORMAT_NONE; } #elif defined(SOKOL_METAL) || defined(SOKOL_D3D11) - return _SAPP_PIXELFORMAT_BGRA8; + return SAPP_PIXELFORMAT_BGRA8; #else - return _SAPP_PIXELFORMAT_RGBA8; + return SAPP_PIXELFORMAT_RGBA8; #endif } -SOKOL_API_IMPL int sapp_depth_format(void) { - return _SAPP_PIXELFORMAT_DEPTH_STENCIL; +SOKOL_API_IMPL sapp_pixel_format sapp_depth_format(void) { + return SAPP_PIXELFORMAT_DEPTH_STENCIL; } SOKOL_API_IMPL int sapp_sample_count(void) { @@ -12981,62 +13848,104 @@ SOKOL_API_IMPL void sapp_html5_fetch_dropped_file(const sapp_html5_fetch_request #endif } -SOKOL_API_IMPL const void* sapp_metal_get_device(void) { +SOKOL_API_IMPL sapp_environment sapp_get_environment(void) { SOKOL_ASSERT(_sapp.valid); + sapp_environment res; + _sapp_clear(&res, sizeof(res)); + res.defaults.color_format = sapp_color_format(); + res.defaults.depth_format = sapp_depth_format(); + res.defaults.sample_count = sapp_sample_count(); #if defined(SOKOL_METAL) #if defined(_SAPP_MACOS) - const void* obj = (__bridge const void*) _sapp.macos.mtl_device; + res.metal.device = (__bridge const void*) _sapp.macos.mtl_device; #else - const void* obj = (__bridge const void*) _sapp.ios.mtl_device; + res.metal.device = (__bridge const void*) _sapp.ios.mtl_device; #endif - SOKOL_ASSERT(obj); - return obj; - #else - return 0; #endif -} - -SOKOL_API_IMPL const void* sapp_metal_get_current_drawable(void) { - SOKOL_ASSERT(_sapp.valid); - #if defined(SOKOL_METAL) - #if defined(_SAPP_MACOS) - const void* obj = (__bridge const void*) [_sapp.macos.view currentDrawable]; - #else - const void* obj = (__bridge const void*) [_sapp.ios.view currentDrawable]; - #endif - SOKOL_ASSERT(obj); - return obj; - #else - return 0; + #if defined(SOKOL_D3D11) + res.d3d11.device = (const void*) _sapp.d3d11.device; + res.d3d11.device_context = (const void*) _sapp.d3d11.device_context; #endif -} - -SOKOL_API_IMPL const void* sapp_metal_get_depth_stencil_texture(void) { - SOKOL_ASSERT(_sapp.valid); - #if defined(SOKOL_METAL) - #if defined(_SAPP_MACOS) - const void* obj = (__bridge const void*) [_sapp.macos.view depthStencilTexture]; - #else - const void* obj = (__bridge const void*) [_sapp.ios.view depthStencilTexture]; - #endif - return obj; - #else - return 0; + #if defined(SOKOL_WGPU) + res.wgpu.device = (const void*) _sapp.wgpu.device; #endif + #if defined(SOKOL_VULKAN) + res.vulkan.physical_device = (const void*) _sapp.vk.physical_device; + res.vulkan.device = (const void*) _sapp.vk.device; + res.vulkan.queue = (const void*) _sapp.vk.queue; + res.vulkan.queue_family_index = _sapp.vk.queue_family_index; + #endif + return res; } -SOKOL_API_IMPL const void* sapp_metal_get_msaa_color_texture(void) { +SOKOL_API_IMPL sapp_swapchain sapp_get_swapchain(void) { SOKOL_ASSERT(_sapp.valid); + sapp_swapchain res; + _sapp_clear(&res, sizeof(res)); + res.width = sapp_width(); + res.height = sapp_height(); + res.color_format = sapp_color_format(); + res.depth_format = sapp_depth_format(); + res.sample_count = sapp_sample_count(); #if defined(SOKOL_METAL) #if defined(_SAPP_MACOS) - const void* obj = (__bridge const void*) [_sapp.macos.view multisampleColorTexture]; + res.metal.current_drawable = (__bridge const void*) [_sapp.macos.view currentDrawable]; + res.metal.depth_stencil_texture = (__bridge const void*) [_sapp.macos.view depthStencilTexture]; + res.metal.msaa_color_texture = (__bridge const void*) [_sapp.macos.view multisampleColorTexture]; #else - const void* obj = (__bridge const void*) [_sapp.ios.view multisampleColorTexture]; + res.metal.current_drawable = (__bridge const void*) [_sapp.ios.view currentDrawable]; + res.metal.depth_stencil_texture = (__bridge const void*) [_sapp.ios.view depthStencilTexture]; + res.metal.msaa_color_texture = (__bridge const void*) [_sapp.ios.view multisampleColorTexture]; #endif - return obj; - #else - return 0; #endif + #if defined(SOKOL_D3D11) + SOKOL_ASSERT(_sapp.d3d11.rtv); + if (_sapp.sample_count > 1) { + SOKOL_ASSERT(_sapp.d3d11.msaa_rtv); + res.d3d11.render_view = (const void*) _sapp.d3d11.msaa_rtv; + res.d3d11.resolve_view = (const void*) _sapp.d3d11.rtv; + } else { + res.d3d11.render_view = (const void*) _sapp.d3d11.rtv; + } + res.d3d11.depth_stencil_view = (const void*) _sapp.d3d11.dsv; + #endif + #if defined(SOKOL_WGPU) + SOKOL_ASSERT(0 == _sapp.wgpu.swapchain_view); + _sapp_wgpu_swapchain_next(); + // FIXME: swapchain_view being null must be allowed and should skip the frame + SOKOL_ASSERT(_sapp.wgpu.swapchain_view); + if (_sapp.sample_count > 1) { + SOKOL_ASSERT(_sapp.wgpu.msaa_view); + res.wgpu.render_view = (const void*) _sapp.wgpu.msaa_view; + res.wgpu.resolve_view = (const void*) _sapp.wgpu.swapchain_view; + } else { + res.wgpu.render_view = (const void*) _sapp.wgpu.swapchain_view; + } + res.wgpu.depth_stencil_view = (const void*) _sapp.wgpu.depth_stencil_view; + #endif + #if defined(SOKOL_VULKAN) + _sapp_vk_swapchain_next(); + // FIXME: swapchain_view being null must be allowed and should skip the frame + uint32_t img_idx = _sapp.vk.cur_swapchain_image_index; + if (_sapp.sample_count > 1) { + SOKOL_ASSERT(_sapp.vk.msaa.img && _sapp.vk.msaa.view); + res.vulkan.render_image = (const void*) _sapp.vk.msaa.img; + res.vulkan.render_view = (const void*) _sapp.vk.msaa.view; + res.vulkan.resolve_image = (const void*) _sapp.vk.swapchain_images[img_idx]; + res.vulkan.resolve_view = (const void*) _sapp.vk.swapchain_views[img_idx]; + } else { + res.vulkan.render_image = (const void*) _sapp.vk.swapchain_images[img_idx]; + res.vulkan.render_view = (const void*) _sapp.vk.swapchain_views[img_idx]; + } + res.vulkan.depth_stencil_image = (const void*) _sapp.vk.depth.img; + res.vulkan.depth_stencil_view = (const void*) _sapp.vk.depth.view; + res.vulkan.render_finished_semaphore = _sapp.vk.sync[img_idx].render_finished_sem; + res.vulkan.present_complete_semaphore = _sapp.vk.sync[_sapp.vk.sync_slot].present_complete_sem; + #endif + #if defined(_SAPP_ANY_GL) + res.gl.framebuffer = _sapp.gl.framebuffer; + #endif + return res; } SOKOL_API_IMPL const void* sapp_macos_get_window(void) { @@ -13059,24 +13968,6 @@ SOKOL_API_IMPL const void* sapp_ios_get_window(void) { #endif } -SOKOL_API_IMPL const void* sapp_d3d11_get_device(void) { - SOKOL_ASSERT(_sapp.valid); - #if defined(SOKOL_D3D11) - return _sapp.d3d11.device; - #else - return 0; - #endif -} - -SOKOL_API_IMPL const void* sapp_d3d11_get_device_context(void) { - SOKOL_ASSERT(_sapp.valid); - #if defined(SOKOL_D3D11) - return _sapp.d3d11.device_context; - #else - return 0; - #endif -} - SOKOL_API_IMPL const void* sapp_d3d11_get_swap_chain(void) { SOKOL_ASSERT(_sapp.valid); #if defined(SOKOL_D3D11) @@ -13086,44 +13977,6 @@ SOKOL_API_IMPL const void* sapp_d3d11_get_swap_chain(void) { #endif } -SOKOL_API_IMPL const void* sapp_d3d11_get_render_view(void) { - SOKOL_ASSERT(_sapp.valid); - #if defined(SOKOL_D3D11) - if (_sapp.sample_count > 1) { - SOKOL_ASSERT(_sapp.d3d11.msaa_rtv); - return _sapp.d3d11.msaa_rtv; - } else { - SOKOL_ASSERT(_sapp.d3d11.rtv); - return _sapp.d3d11.rtv; - } - #else - return 0; - #endif -} - -SOKOL_API_IMPL const void* sapp_d3d11_get_resolve_view(void) { - SOKOL_ASSERT(_sapp.valid); - #if defined(SOKOL_D3D11) - if (_sapp.sample_count > 1) { - SOKOL_ASSERT(_sapp.d3d11.rtv); - return _sapp.d3d11.rtv; - } else { - return 0; - } - #else - return 0; - #endif -} - -SOKOL_API_IMPL const void* sapp_d3d11_get_depth_stencil_view(void) { - SOKOL_ASSERT(_sapp.valid); - #if defined(SOKOL_D3D11) - return _sapp.d3d11.dsv; - #else - return 0; - #endif -} - SOKOL_API_IMPL const void* sapp_win32_get_hwnd(void) { SOKOL_ASSERT(_sapp.valid); #if defined(_SAPP_WIN32) @@ -13133,66 +13986,10 @@ SOKOL_API_IMPL const void* sapp_win32_get_hwnd(void) { #endif } -SOKOL_API_IMPL const void* sapp_wgpu_get_device(void) { - SOKOL_ASSERT(_sapp.valid); - #if defined(SOKOL_WGPU) - return (const void*) _sapp.wgpu.device; - #else - return 0; - #endif -} - -SOKOL_API_IMPL const void* sapp_wgpu_get_render_view(void) { - SOKOL_ASSERT(_sapp.valid); - #if defined(SOKOL_WGPU) - if (_sapp.sample_count > 1) { - SOKOL_ASSERT(_sapp.wgpu.msaa_view); - return (const void*) _sapp.wgpu.msaa_view; - } else { - SOKOL_ASSERT(_sapp.wgpu.swapchain_view); - return (const void*) _sapp.wgpu.swapchain_view; - } - #else - return 0; - #endif -} - -SOKOL_API_IMPL const void* sapp_wgpu_get_resolve_view(void) { - SOKOL_ASSERT(_sapp.valid); - #if defined(SOKOL_WGPU) - if (_sapp.sample_count > 1) { - SOKOL_ASSERT(_sapp.wgpu.swapchain_view); - return (const void*) _sapp.wgpu.swapchain_view; - } else { - return 0; - } - #else - return 0; - #endif -} - -SOKOL_API_IMPL const void* sapp_wgpu_get_depth_stencil_view(void) { - SOKOL_ASSERT(_sapp.valid); - #if defined(SOKOL_WGPU) - return (const void*) _sapp.wgpu.depth_stencil_view; - #else - return 0; - #endif -} - -SOKOL_API_IMPL uint32_t sapp_gl_get_framebuffer(void) { - SOKOL_ASSERT(_sapp.valid); - #if defined(_SAPP_ANY_GL) - return _sapp.gl.framebuffer; - #else - return 0; - #endif -} - SOKOL_API_IMPL int sapp_gl_get_major_version(void) { SOKOL_ASSERT(_sapp.valid); #if defined(_SAPP_ANY_GL) - return _sapp.desc.gl_major_version; + return _sapp.desc.gl.major_version; #else return 0; #endif @@ -13201,7 +13998,7 @@ SOKOL_API_IMPL int sapp_gl_get_major_version(void) { SOKOL_API_IMPL int sapp_gl_get_minor_version(void) { SOKOL_ASSERT(_sapp.valid); #if defined(_SAPP_ANY_GL) - return _sapp.desc.gl_minor_version; + return _sapp.desc.gl.minor_version; #else return 0; #endif diff --git a/sokol_gfx.h b/sokol_gfx.h index c53702b3..a9cf53a7 100644 --- a/sokol_gfx.h +++ b/sokol_gfx.h @@ -22,6 +22,7 @@ #define SOKOL_D3D11 #define SOKOL_METAL #define SOKOL_WGPU + #define SOKOL_VULKAN #define SOKOL_DUMMY_BACKEND I.e. for the desktop GL it should look like this: @@ -1867,7 +1868,7 @@ - sg_apply_bindings(): the sokol-gfx WebGPU backend implements a bindgroup cache to prevent excessive creation and destruction of BindGroup objects when calling sg_apply_bindings(). The number of slots in the bindgroups - cache is defined in sg_desc.wgpu_bindgroups_cache_size when calling + cache is defined in sg_desc.wgpu.bindgroups_cache_size when calling sg_setup. The cache size must be a power-of-2 number, with the default being 1024. The bindgroups cache behaviour can be observed by calling the new function sg_query_frame_stats(), where the following struct items are @@ -2053,6 +2054,7 @@ typedef enum sg_backend { SG_BACKEND_METAL_MACOS, SG_BACKEND_METAL_SIMULATOR, SG_BACKEND_WGPU, + SG_BACKEND_VULKAN, SG_BACKEND_DUMMY, } sg_backend; @@ -2148,7 +2150,6 @@ typedef enum sg_pixel_format { SG_PIXELFORMAT_RGBA32SI, SG_PIXELFORMAT_RGBA32F, - // NOTE: when adding/removing pixel formats before DEPTH, also update sokol_app.h/_SAPP_PIXELFORMAT_* SG_PIXELFORMAT_DEPTH, SG_PIXELFORMAT_DEPTH_STENCIL, @@ -2231,6 +2232,7 @@ typedef struct sg_limits { int gl_max_vertex_uniform_components; // GL_MAX_VERTEX_UNIFORM_COMPONENTS (only on GL backends) int gl_max_combined_texture_image_units; // GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS (only on GL backends) int d3d11_max_unordered_access_views; // 8 on feature level 11.0, otherwise 32 (clamped to SG_MAX_VIEW_BINDSLOTS) + int vk_min_uniform_buffer_offset_alignment; } sg_limits; /* @@ -2935,6 +2937,17 @@ typedef struct sg_wgpu_swapchain { const void* depth_stencil_view; // WGPUTextureView } sg_wgpu_swapchain; +typedef struct sg_vulkan_swapchain { + const void* render_image; // vkImage + const void* render_view; // vkImageView + const void* resolve_image; // vkImage + const void* resolve_view; // vkImageView + const void* depth_stencil_image; // vkImage + const void* depth_stencil_view; // vkImageView + const void* render_finished_semaphore; // vkSemaphore + const void* present_complete_semaphore; // vkSemaphore +} sg_vulkan_swapchain; + typedef struct sg_gl_swapchain { uint32_t framebuffer; // GL framebuffer object } sg_gl_swapchain; @@ -2948,6 +2961,7 @@ typedef struct sg_swapchain { sg_metal_swapchain metal; sg_d3d11_swapchain d3d11; sg_wgpu_swapchain wgpu; + sg_vulkan_swapchain vulkan; sg_gl_swapchain gl; } sg_swapchain; @@ -3617,7 +3631,8 @@ typedef struct sg_shader_uniform_block { uint32_t size; uint8_t hlsl_register_b_n; // HLSL register(bn) uint8_t msl_buffer_n; // MSL [[buffer(n)]] - uint8_t wgsl_group0_binding_n; // WGSL @group(0) @binding(n) + uint8_t wgsl_group0_binding_n; // WGSL @group(0) @binding(n) + uint8_t spirv_set0_binding_n; // Vulkan GLSL layout(set=0, binding=n) sg_uniform_layout layout; sg_glsl_shader_uniform glsl_uniforms[SG_MAX_UNIFORMBLOCK_MEMBERS]; } sg_shader_uniform_block; @@ -3630,6 +3645,7 @@ typedef struct sg_shader_texture_view { uint8_t hlsl_register_t_n; // HLSL register(tn) bind slot uint8_t msl_texture_n; // MSL [[texture(n)]] bind slot uint8_t wgsl_group1_binding_n; // WGSL @group(1) @binding(n) bind slot + uint8_t spirv_set1_binding_n; // Vulkan GLSL layout(set=1, binding=0) } sg_shader_texture_view; typedef struct sg_shader_storage_buffer_view { @@ -3639,6 +3655,7 @@ typedef struct sg_shader_storage_buffer_view { uint8_t hlsl_register_u_n; // HLSL register(un) bind slot (for read/write access) uint8_t msl_buffer_n; // MSL [[buffer(n)]] bind slot uint8_t wgsl_group1_binding_n; // WGSL @group(1) @binding(n) bind slot + uint8_t spirv_set1_binding_n; // Vulkan GLSL layout(set=1, binding=0) uint8_t glsl_binding_n; // GLSL layout(binding=n) } sg_shader_storage_buffer_view; @@ -3650,6 +3667,7 @@ typedef struct sg_shader_storage_image_view { uint8_t hlsl_register_u_n; // HLSL register(un) bind slot uint8_t msl_texture_n; // MSL [[texture(n)]] bind slot uint8_t wgsl_group1_binding_n; // WGSL @group(2) @binding(n) bind slot + uint8_t spirv_set1_binding_n; // Vulkan GLSL layout(set=1, binding=0) uint8_t glsl_binding_n; // GLSL layout(binding=n) } sg_shader_storage_image_view; @@ -3665,6 +3683,7 @@ typedef struct sg_shader_sampler { uint8_t hlsl_register_s_n; // HLSL register(sn) bind slot uint8_t msl_sampler_n; // MSL [[sampler(n)]] bind slot uint8_t wgsl_group1_binding_n; // WGSL @group(1) @binding(n) bind slot + uint8_t spirv_set1_binding_n; // Vulkan GLSL layout(set=1, binding=0) } sg_shader_sampler; typedef struct sg_shader_texture_sampler_pair { @@ -4234,6 +4253,19 @@ typedef struct sg_frame_stats_wgpu { sg_frame_stats_wgpu_bindings bindings; } sg_frame_stats_wgpu; +typedef struct sg_frame_stats_vk { + uint32_t num_cmd_pipeline_barrier; + uint32_t num_allocate_memory; + uint32_t num_free_memory; + uint32_t size_allocate_memory; + uint32_t num_delete_queue_added; + uint32_t num_delete_queue_collected; + uint32_t num_cmd_copy_buffer; + uint32_t num_cmd_copy_buffer_to_image; + uint32_t num_cmd_set_descriptor_buffer_offsets; + uint32_t size_descriptor_buffer_writes; +} sg_frame_stats_vk; + typedef struct sg_resource_stats { uint32_t total_alive; // number of live objects in pool uint32_t total_free; // number of free objects in pool @@ -4275,6 +4307,7 @@ typedef struct sg_frame_stats { sg_frame_stats_d3d11 d3d11; sg_frame_stats_metal metal; sg_frame_stats_wgpu wgpu; + sg_frame_stats_vk vk; } sg_frame_stats; /* @@ -4356,8 +4389,8 @@ typedef struct sg_frame_stats { _SG_LOGITEM_XMACRO(METAL_CREATE_RPS_OUTPUT, "") \ _SG_LOGITEM_XMACRO(METAL_CREATE_DSS_FAILED, "failed to create depth stencil state (metal)") \ _SG_LOGITEM_XMACRO(WGPU_BINDGROUPS_POOL_EXHAUSTED, "bindgroups pool exhausted (increase sg_desc.bindgroups_cache_size) (wgpu)") \ - _SG_LOGITEM_XMACRO(WGPU_BINDGROUPSCACHE_SIZE_GREATER_ONE, "sg_desc.wgpu_bindgroups_cache_size must be > 1 (wgpu)") \ - _SG_LOGITEM_XMACRO(WGPU_BINDGROUPSCACHE_SIZE_POW2, "sg_desc.wgpu_bindgroups_cache_size must be a power of 2 (wgpu)") \ + _SG_LOGITEM_XMACRO(WGPU_BINDGROUPSCACHE_SIZE_GREATER_ONE, "sg_desc.wgpu.bindgroups_cache_size must be > 1 (wgpu)") \ + _SG_LOGITEM_XMACRO(WGPU_BINDGROUPSCACHE_SIZE_POW2, "sg_desc.wgpu.bindgroups_cache_size must be a power of 2 (wgpu)") \ _SG_LOGITEM_XMACRO(WGPU_CREATEBINDGROUP_FAILED, "wgpuDeviceCreateBindGroup failed") \ _SG_LOGITEM_XMACRO(WGPU_CREATE_BUFFER_FAILED, "wgpuDeviceCreateBuffer() failed") \ _SG_LOGITEM_XMACRO(WGPU_CREATE_TEXTURE_FAILED, "wgpuDeviceCreateTexture() failed") \ @@ -4373,6 +4406,41 @@ typedef struct sg_frame_stats { _SG_LOGITEM_XMACRO(WGPU_CREATE_PIPELINE_LAYOUT_FAILED, "wgpuDeviceCreatePipelineLayout() failed") \ _SG_LOGITEM_XMACRO(WGPU_CREATE_RENDER_PIPELINE_FAILED, "wgpuDeviceCreateRenderPipeline() failed") \ _SG_LOGITEM_XMACRO(WGPU_CREATE_COMPUTE_PIPELINE_FAILED, "wgpuDeviceCreateComputePipeline() failed") \ + _SG_LOGITEM_XMACRO(VULKAN_REQUIRED_EXTENSION_FUNCTION_MISSING, "vulkan: could not look up a required extension function pointer") \ + _SG_LOGITEM_XMACRO(VULKAN_ALLOC_DEVICE_MEMORY_NO_SUITABLE_MEMORY_TYPE, "vulkan: could not find suitable memory type") \ + _SG_LOGITEM_XMACRO(VULKAN_ALLOCATE_MEMORY_FAILED, "vulkan: vkAllocateMemory() failed!") \ + _SG_LOGITEM_XMACRO(VULKAN_ALLOC_BUFFER_DEVICE_MEMORY_FAILED, "vulkan: allocating buffer device memory failed") \ + _SG_LOGITEM_XMACRO(VULKAN_ALLOC_IMAGE_DEVICE_MEMORY_FAILED, "vulkan: allocating image device memory failed") \ + _SG_LOGITEM_XMACRO(VULKAN_DELETE_QUEUE_EXHAUSTED, "vulkan: internal delete queue exhausted (too many objects destroyed per frame)") \ + _SG_LOGITEM_XMACRO(VULKAN_STAGING_CREATE_BUFFER_FAILED, "vulkan: vkCreateBuffer() failed for staging buffer") \ + _SG_LOGITEM_XMACRO(VULKAN_STAGING_ALLOCATE_MEMORY_FAILED, "vulkan: allocating device memory for staging buffer failed") \ + _SG_LOGITEM_XMACRO(VULKAN_STAGING_BIND_BUFFER_MEMORY_FAILED, "vulkan: vkBindBufferMemory() failed for staging buffer") \ + _SG_LOGITEM_XMACRO(VULKAN_STAGING_STREAM_BUFFER_OVERFLOW, "vulkan: per-frame stream staging buffer has overflown (sg_desc.vulkan.stream_staging_buffer_size)") \ + _SG_LOGITEM_XMACRO(VULKAN_CREATE_SHARED_BUFFER_FAILED, "vulkan: vkCreateBuffer() failed for cpu/gpu-shared buffer") \ + _SG_LOGITEM_XMACRO(VULKAN_ALLOCATE_SHARED_BUFFER_MEMORY_FAILED, "vulkan: allocating device memory for cpu/gpu-shared buffer failed") \ + _SG_LOGITEM_XMACRO(VULKAN_BIND_SHARED_BUFFER_MEMORY_FAILED, "vulkan: vkBindBufferMemory() failed for cpu/gpu-shared buffer") \ + _SG_LOGITEM_XMACRO(VULKAN_MAP_SHARED_BUFFER_MEMORY_FAILED, "vulkan: vkMapMemory() failed on cpu/gpu-shared buffer") \ + _SG_LOGITEM_XMACRO(VULKAN_CREATE_BUFFER_FAILED, "vulkan: vkCreateBuffer() failed!") \ + _SG_LOGITEM_XMACRO(VULKAN_BIND_BUFFER_MEMORY_FAILED, "vulkan: vkBindBufferMemory() failed!") \ + _SG_LOGITEM_XMACRO(VULKAN_CREATE_IMAGE_FAILED, "vulkan: vkCreateImage() failed!") \ + _SG_LOGITEM_XMACRO(VULKAN_BIND_IMAGE_MEMORY_FAILED, "vulkan: vkBindImageMemory() failed!") \ + _SG_LOGITEM_XMACRO(VULKAN_CREATE_SHADER_MODULE_FAILED, "vukan: vkCreateShaderModule() failed!") \ + _SG_LOGITEM_XMACRO(VULKAN_UNIFORMBLOCK_SPIRV_SET0_BINDING_OUT_OF_RANGE, "vulkan: uniform block 'spirv_set0_binding_n' is out of range (must be 0..15)") \ + _SG_LOGITEM_XMACRO(VULKAN_TEXTURE_SPIRV_SET1_BINDING_OUT_OF_RANGE, "vulkan: texture 'spirv_set1_binding_n' is out of range (must be 0..127)") \ + _SG_LOGITEM_XMACRO(VULKAN_STORAGEBUFFER_SPIRV_SET1_BINDING_OUT_OF_RANGE, "vulkan: storage buffer 'spirv_set1_binding_n' is out of range (must be 0..127)") \ + _SG_LOGITEM_XMACRO(VULKAN_STORAGEIMAGE_SPIRV_SET1_BINDING_OUT_OF_RANGE, "vulkan: storage image 'spirv_set1_binding_n' is out of range (must be 0..127)") \ + _SG_LOGITEM_XMACRO(VULKAN_SAMPLER_SPIRV_SET1_BINDING_OUT_OF_RANGE, "vulkan: sampler 'spirv_set1_binding_n' is out of range (must be 0..127)") \ + _SG_LOGITEM_XMACRO(VULKAN_CREATE_DESCRIPTOR_SET_LAYOUT_FAILED, "vulkan: vkCreateDescriptorSetLayout() failed!") \ + _SG_LOGITEM_XMACRO(VULKAN_CREATE_PIPELINE_LAYOUT_FAILED, "vulkan: vkCreatePipelineLayout() failed!") \ + _SG_LOGITEM_XMACRO(VULKAN_CREATE_GRAPHICS_PIPELINE_FAILED, "vulkan: vkCreateGraphicsPipelines() failed!") \ + _SG_LOGITEM_XMACRO(VULKAN_CREATE_COMPUTE_PIPELINE_FAILED, "vulkan: vkCreateComputePipelines() failed!") \ + _SG_LOGITEM_XMACRO(VULKAN_CREATE_IMAGE_VIEW_FAILED, "vulkan: vkCreateImageView() failed!") \ + _SG_LOGITEM_XMACRO(VULKAN_VIEW_MAX_DESCRIPTOR_SIZE, "vulkan: required view descriptor size is greater than _SG_VK_MAX_DESCRIPTOR_DATA_SIZE") \ + _SG_LOGITEM_XMACRO(VULKAN_CREATE_SAMPLER_FAILED, "vulkan: vkCreateSampler() failed!") \ + _SG_LOGITEM_XMACRO(VULKAN_SAMPLER_MAX_DESCRIPTOR_SIZE, "vulkan: required sampler descriptor size is greater than _SG_VK_MAX_DESCRIPTOR_DATA_SIZE") \ + _SG_LOGITEM_XMACRO(VULKAN_WAIT_FOR_FENCE_FAILED, "vulkan: vkWaitForFence() failed!") \ + _SG_LOGITEM_XMACRO(VULKAN_UNIFORM_BUFFER_OVERFLOW, "vulkan: uniform buffer has overflown (increase sg_desc.uniform_buffer_size)") \ + _SG_LOGITEM_XMACRO(VULKAN_DESCRIPTOR_BUFFER_OVERFLOW, "vulkan: desccriptor buffer has overflown (increase sg_desc.vulkan.descriptor_buffer_size)") \ _SG_LOGITEM_XMACRO(IDENTICAL_COMMIT_LISTENER, "attempting to add identical commit listener") \ _SG_LOGITEM_XMACRO(COMMIT_LISTENER_ARRAY_FULL, "commit listener array full") \ _SG_LOGITEM_XMACRO(TRACE_HOOKS_NOT_ENABLED, "sg_install_trace_hooks() called, but SOKOL_TRACE_HOOKS is not defined") \ @@ -4478,6 +4546,7 @@ typedef struct sg_frame_stats { _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_UNIFORMBLOCK_METAL_BUFFER_SLOT_COLLISION, "sg_shader_desc.uniform_blocks[].msl_buffer_n must be unique across uniform blocks and storage buffers in same shader stage") \ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_UNIFORMBLOCK_HLSL_REGISTER_B_COLLISION, "sg_shader_desc.uniform_blocks[].hlsl_register_b_n must be unique across uniform blocks in same shader stage") \ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_UNIFORMBLOCK_WGSL_GROUP0_BINDING_COLLISION, "sg_shader_desc.uniform_blocks[].wgsl_group0_binding_n must be unique across all uniform blocks") \ + _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_UNIFORMBLOCK_SPIRV_SET0_BINDING_COLLISION, "sg_shader_desc.unifrom_blocks[].spirv_set0_binding_n must be unique across all uniform blocks") \ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_UNIFORMBLOCK_NO_MEMBERS, "sg_shader_desc.uniform_blocks[].glsl_uniforms[]: GL backend requires uniform block member declarations") \ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_UNIFORMBLOCK_UNIFORM_GLSL_NAME, "sg_shader_desc.uniform_blocks[].glsl_uniforms[].glsl_name missing") \ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_UNIFORMBLOCK_SIZE_MISMATCH, "sg_shader_desc.uniform_blocks[].glsl_uniforms[]: size of uniform block members doesn't match uniform block size") \ @@ -4487,18 +4556,22 @@ typedef struct sg_frame_stats { _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_VIEW_STORAGEBUFFER_HLSL_REGISTER_T_COLLISION, "sg_shader_desc.views[].storage_buffer.hlsl_register_t_n must be unique across read-only storage buffers and images in same shader stage") \ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_VIEW_STORAGEBUFFER_HLSL_REGISTER_U_COLLISION, "sg_shader_desc.views[].storage_buffer.hlsl_register_u_n must be unique across read/write storage buffers and storage images in same shader stage") \ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_VIEW_STORAGEBUFFER_GLSL_BINDING_COLLISION, "sg_shader_desc.views[].storage_buffer.glsl_binding_n must be unique across shader stages") \ - _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_VIEW_STORAGEBUFFER_WGSL_GROUP1_BINDING_COLLISION, "sg_shader_desc.views[].storage_buffer.wgsl_group1_binding_n must be unique across all images, samplers and storage buffers") \ + _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_VIEW_STORAGEBUFFER_WGSL_GROUP1_BINDING_COLLISION, "sg_shader_desc.views[].storage_buffer.wgsl_group1_binding_n must be unique across all view and sampler bindings") \ + _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_VIEW_STORAGEBUFFER_SPIRV_SET1_BINDING_COLLISION, "sg_shader_desc.views[].storage_buffer.spirv_set1_binding_n must be unique across all view and sampler bindings") \ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_VIEW_STORAGEIMAGE_EXPECT_COMPUTE_STAGE, "sg_shader_desc.views[].storage_image: storage images are allowed on the compute stage") \ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_VIEW_STORAGEIMAGE_METAL_TEXTURE_SLOT_COLLISION, "sg_shader_desc.views[].storage_image.msl_texture_n must be unique across images and storage images in same shader stage") \ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_VIEW_STORAGEIMAGE_HLSL_REGISTER_U_COLLISION, "sg_shader_desc.views[].storage_image.hlsl_register_u_n must be unique across storage images and read/write storage buffers in same shader stage") \ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_VIEW_STORAGEIMAGE_GLSL_BINDING_COLLISION, "sg_shader_desc.views[].storage_image.glsl_binding_n must be unique across shader stages") \ - _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_VIEW_STORAGEIMAGE_WGSL_GROUP1_BINDING_COLLISION, "sg_shader_desc.views[].storage_image.wgsl_group1_binding_n must be unique in same shader stage") \ + _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_VIEW_STORAGEIMAGE_WGSL_GROUP1_BINDING_COLLISION, "sg_shader_desc.views[].storage_image.wgsl_group1_binding_n must be unique across all view and sampler bindings") \ + _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_VIEW_STORAGEIMAGE_SPIRV_SET1_BINDING_COLLISION, "sg_shader_desc.views[].storage_image.spirv_set1_binding_n must be unique across all view and sampler bindings") \ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_VIEW_TEXTURE_METAL_TEXTURE_SLOT_COLLISION, "sg_shader_desc.views[].texture.msl_texture_n must be unique across textures and storage images in same shader stage") \ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_VIEW_TEXTURE_HLSL_REGISTER_T_COLLISION, "sg_shader_desc.views[].texture.hlsl_register_t_n must be unique across textures and storage buffers in same shader stage") \ - _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_VIEW_TEXTURE_WGSL_GROUP1_BINDING_COLLISION, "sg_shader_desc.views[].texture.wgsl_group1_binding_n must be unique across all images, samplers and storage buffers") \ + _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_VIEW_TEXTURE_WGSL_GROUP1_BINDING_COLLISION, "sg_shader_desc.views[].texture.wgsl_group1_binding_n must be unique across all view and sampler bindings") \ + _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_VIEW_TEXTURE_SPIRV_SET1_BINDING_COLLISION, "sg_shader_desc.views[].texture.spirv_set1_binding_n must be unique across all view and sampler bindings") \ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_SAMPLER_METAL_SAMPLER_SLOT_COLLISION, "sg_shader_desc.samplers[].msl_sampler_n must be unique in same shader stage") \ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_SAMPLER_HLSL_REGISTER_S_COLLISION, "sg_shader_desc.samplers[].hlsl_register_s_n must be unique in same shader stage") \ - _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_SAMPLER_WGSL_GROUP1_BINDING_COLLISION, "sg_shader_desc.samplers[].wgsl_group1_binding_n must be unique across all images, samplers and storage buffers") \ + _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_SAMPLER_WGSL_GROUP1_BINDING_COLLISION, "sg_shader_desc.samplers[].wgsl_group1_binding_n must be unique across all view and sampler bindings") \ + _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_SAMPLER_SPIRV_SET1_BINDING_COLLISION, "sg_shader_desc.samplers[].spirv_set1_binding_n must be unique across all view and sampler bindings") \ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_TEXTURE_SAMPLER_PAIR_VIEW_SLOT_OUT_OF_RANGE, "texture-sampler-pair view slot index is out of range (sg_shader_desc.texture_sampler_pairs[].view_slot)") \ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_TEXTURE_SAMPLER_PAIR_SAMPLER_SLOT_OUT_OF_RANGE, "texture-sampler-pair sampler slot index is out of range (sg_shader_desc.texture_sampler_pairs[].sampler_slot)") \ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_TEXTURE_SAMPLER_PAIR_TEXTURE_STAGE_MISMATCH, "texture-sampler-pair stage doesn't match referenced texture stage") \ @@ -4584,7 +4657,7 @@ typedef struct sg_frame_stats { _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_COLORATTACHMENTVIEW_IMAGE_ALIVE, "sg_begin_pass: color attachment view's image object is uninitialized or no longer alive") \ _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_COLORATTACHMENTVIEW_IMAGE_VALID, "sg_begin_pass: color attachment view's image is not in valid state (SG_RESOURCESTATE_VALID)") \ _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_COLORATTACHMENTVIEW_SIZES, "sg_begin_pass: all color attachments must have the same width and height") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_COLORATTACHMENTVIEW_SAMPLECOUNT, "sg_begin_pass: when resolve attachments are provided, the color attachment sample count must be 1") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_COLORATTACHMENTVIEW_SAMPLECOUNT, "sg_begin_pass: when resolve attachments are provided, the color attachment sample count must be > 1") \ _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_COLORATTACHMENTVIEW_SAMPLECOUNTS_EQUAL, "sg_begin_pass: all color attachments must have the same sample count") \ _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_RESOLVEATTACHMENTVIEW_NO_COLORATTACHMENTVIEW, "sg_begin_pass: a resolve attachment view must have an associated color attachment view at the same index") \ _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_RESOLVEATTACHMENTVIEW_ALIVE, "sg_begin_pass: resolve attachment view no longer alive") \ @@ -4719,18 +4792,22 @@ typedef enum sg_log_item { The default configuration is: - .buffer_pool_size 128 - .image_pool_size 128 - .sampler_pool_size 64 - .shader_pool_size 32 - .pipeline_pool_size 64 - .view_pool_size 256 - .uniform_buffer_size 4 MB (4*1024*1024) - .max_commit_listeners 1024 - .disable_validation false - .mtl_force_managed_storage_mode false - .wgpu_disable_bindgroups_cache false - .wgpu_bindgroups_cache_size 1024 + .buffer_pool_size 128 + .image_pool_size 128 + .sampler_pool_size 64 + .shader_pool_size 32 + .pipeline_pool_size 64 + .view_pool_size 256 + .uniform_buffer_size 4 MB (4*1024*1024) + .max_commit_listeners 1024 + .disable_validation false + .metal.force_managed_storage_mode false + .metal.use_command_buffer_with_retained_references false + .wgpu.disable_bindgroups_cache false + .wgpu.bindgroups_cache_size 1024 + .vulkan.copy_staging_buffer_size 4 MB + .vulkan.stream_staging_buffer_size 16 MB + .vulkan.descriptor_buffer_size 16 MB .allocator.alloc_fn 0 (in this case, malloc() will be called) .allocator.free_fn 0 (in this case, free() will be called) @@ -4751,11 +4828,11 @@ typedef enum sg_log_item { must hold a strong reference to the Objective-C object until sg_setup() returns. - .mtl_force_managed_storage_mode + .metal.force_managed_storage_mode when enabled, Metal buffers and texture resources are created in managed storage mode, otherwise sokol-gfx will decide whether to create buffers and textures in managed or shared storage mode (this is mainly a debugging option) - .mtl_use_command_buffer_with_retained_references + .metal.use_command_buffer_with_retained_references when true, the sokol-gfx Metal backend will use Metal command buffers which bump the reference count of resource objects as long as they are inflight, this is slower than the default command-buffer-with-unretained-references @@ -4770,7 +4847,7 @@ typedef enum sg_log_item { before sg_setup() is called .environment.d3d11.device_context a pointer to the ID3D11DeviceContext object - .d3d11_shader_debugging + .d3d11.shader_debugging set this to true to compile shaders which are provided as HLSL source code with debug information and without optimization, this allows shader debugging in tools like RenderDoc, to output source code @@ -4778,11 +4855,11 @@ typedef enum sg_log_item { option WebGPU specific: - .wgpu_disable_bindgroups_cache + .wgpu.disable_bindgroups_cache When this is true, the WebGPU backend will create and immediately release a BindGroup object in the sg_apply_bindings() call, only use this for debugging purposes. - .wgpu_bindgroups_cache_size + .wgpu.bindgroups_cache_size The size of the bindgroups cache for re-using BindGroup objects between sg_apply_bindings() calls. The smaller the cache size, the more likely are cache slot collisions which will cause @@ -4794,6 +4871,29 @@ typedef enum sg_log_item { .environment.wgpu.device a WGPUDevice handle + Vulkan specific: + .vulkan.copy_staging_buffer_size + Size of the staging buffer in bytes for uploading the initial + content of buffers and images, and for updating + .usage.dynamic_update resources. The default is 4 MB, + bigger resource updates are split into multiple chunks + of the staging buffer size + .vulkan.stream_staging_buffer_size + Size of the staging buffer in bytes for updating .usage.stream_update + resources. The default is 16 MB. The size must be big enough + to accomodate all update into .usage.stream_update resources. + Any additional data will cause an error log message and + incomplete rendering. Note that the actually allocated size + will be twice as much because the stream-staging-buffer is + double-buffered. + .vulkan.descriptor_buffer_size + Size of the descriptor-upload buffer in bytes. The default + size is 16 bytes. The size must be big enough to accomodate + all unifrom-block, view- and sampler-bindings in a single + frame (assume a worst-case of 256 bytes per binding). Note + that the actually allocated size will be twice as much + because the descriptor-buffer is double-buffered. + When using sokol_gfx.h and sokol_app.h together, consider using the helper function sglue_environment() in the sokol_glue.h header to initialize the sg_desc.environment nested struct. sglue_environment() returns @@ -4819,11 +4919,19 @@ typedef struct sg_wgpu_environment { const void* device; } sg_wgpu_environment; +typedef struct sg_vulkan_environment { + const void* physical_device; + const void* device; + const void* queue; + uint32_t queue_family_index; +} sg_vulkan_environment; + typedef struct sg_environment { sg_environment_defaults defaults; sg_metal_environment metal; sg_d3d11_environment d3d11; sg_wgpu_environment wgpu; + sg_vulkan_environment vulkan; } sg_environment; /* @@ -4877,6 +4985,26 @@ typedef struct sg_logger { void* user_data; } sg_logger; +typedef struct sg_d3d11_desc { + bool shader_debugging; // if true, HLSL shaders are compiled with D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION +} sg_d3d11_desc; + +typedef struct sg_metal_desc { + bool force_managed_storage_mode; // for debugging: use Metal managed storage mode for resources even with UMA + bool use_command_buffer_with_retained_references; // Metal: use a managed MTLCommandBuffer which ref-counts used resources +} sg_metal_desc; + +typedef struct sg_wgpu_desc { + bool disable_bindgroups_cache; // set to true to disable the WebGPU backend BindGroup cache + int bindgroups_cache_size; // number of slots in the WebGPU bindgroup cache (must be 2^N) +} sg_wgpu_desc; + +typedef struct sg_vulkan_desc { + int copy_staging_buffer_size; // size of staging buffer for immutable and dynamic resources (default: 4 MB) + int stream_staging_buffer_size; // size of per-frame staging buffer for updating streaming resources (default: 16 MB) + int descriptor_buffer_size; // size of per-frame descriptor buffer for updating resource bindings (default: 16 MB) +} sg_vulkan_desc; + typedef struct sg_desc { uint32_t _start_canary; int buffer_pool_size; @@ -4885,18 +5013,17 @@ typedef struct sg_desc { int shader_pool_size; int pipeline_pool_size; int view_pool_size; - int uniform_buffer_size; - int max_commit_listeners; - bool disable_validation; // disable validation layer even in debug mode, useful for tests - bool enforce_portable_limits; // if true, enforce portable resource binding limits (SG_MAX_PORTABLE_*) - bool d3d11_shader_debugging; // if true, HLSL shaders are compiled with D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION - bool mtl_force_managed_storage_mode; // for debugging: use Metal managed storage mode for resources even with UMA - bool mtl_use_command_buffer_with_retained_references; // Metal: use a managed MTLCommandBuffer which ref-counts used resources - bool wgpu_disable_bindgroups_cache; // set to true to disable the WebGPU backend BindGroup cache - int wgpu_bindgroups_cache_size; // number of slots in the WebGPU bindgroup cache (must be 2^N) - sg_allocator allocator; - sg_logger logger; // optional log function override - sg_environment environment; + int uniform_buffer_size; // max size of all sg_apply_uniform() calls per frame, with worst-case 256 byte alignment + int max_commit_listeners; // max number of commit listener hook functions + bool disable_validation; // disable validation layer even in debug mode, useful for tests + bool enforce_portable_limits; // if true, enforce portable resource binding limits (SG_MAX_PORTABLE_*) + sg_d3d11_desc d3d11; // d3d11-specific setup parameters + sg_metal_desc metal; // metal-specific setup parameters + sg_wgpu_desc wgpu; // webgpu-specific setup parameters + sg_vulkan_desc vulkan; // vulkan-specific setup parameters + sg_allocator allocator; // optional memory allocation hooks + sg_logger logger; // optional log function override + sg_environment environment; // required externally provided runtime objects and defaults uint32_t _end_canary; } sg_desc; @@ -5267,8 +5394,8 @@ inline int sg_append_buffer(sg_buffer buf_id, const sg_range& data) { return sg_ #ifdef SOKOL_GFX_IMPL #define SOKOL_GFX_IMPL_INCLUDED (1) -#if !(defined(SOKOL_GLCORE)||defined(SOKOL_GLES3)||defined(SOKOL_D3D11)||defined(SOKOL_METAL)||defined(SOKOL_WGPU)||defined(SOKOL_DUMMY_BACKEND)) -#error "Please select a backend with SOKOL_GLCORE, SOKOL_GLES3, SOKOL_D3D11, SOKOL_METAL, SOKOL_WGPU or SOKOL_DUMMY_BACKEND" +#if !(defined(SOKOL_GLCORE)||defined(SOKOL_GLES3)||defined(SOKOL_D3D11)||defined(SOKOL_METAL)||defined(SOKOL_WGPU)||defined(SOKOL_VULKAN)||defined(SOKOL_DUMMY_BACKEND)) +#error "Please select a backend with SOKOL_GLCORE, SOKOL_GLES3, SOKOL_D3D11, SOKOL_METAL, SOKOL_WGPU, SOKOL_VULKAN or SOKOL_DUMMY_BACKEND" #endif #if defined(SOKOL_MALLOC) || defined(SOKOL_CALLOC) || defined(SOKOL_FREE) #error "SOKOL_MALLOC/CALLOC/FREE macros are no longer supported, please use sg_desc.allocator to override memory allocation functions" @@ -5314,6 +5441,12 @@ inline int sg_append_buffer(sg_buffer buf_id, const sg_range& data) { return sg_ #define _SG_TRACE_NOARGS(fn) #endif +#ifdef __cplusplus +#define _SG_STRUCT(TYPE, NAME) TYPE NAME = {} +#else +#define _SG_STRUCT(TYPE, NAME) TYPE NAME = {0} +#endif + // default clear values #ifndef SG_DEFAULT_CLEAR_RED #define SG_DEFAULT_CLEAR_RED (0.5f) @@ -5390,6 +5523,8 @@ inline int sg_append_buffer(sg_buffer buf_id, const sg_range& data) { return sg_ #if defined(__EMSCRIPTEN__) #include <emscripten/emscripten.h> #endif +#elif defined(SOKOL_VULKAN) + #include <vulkan/vulkan.h> #elif defined(SOKOL_GLCORE) || defined(SOKOL_GLES3) #define _SOKOL_ANY_GL (1) @@ -5893,6 +6028,15 @@ typedef struct { int* free_queue; } _sg_pool_t; +// resource hazard tracking struct +typedef struct { + int num_slots; + int cur_slot; + uint32_t* slots; // tracked unique resource ids + uint32_t occupy_num_bytes; // size of occupy_bits array in bytes + uint8_t* occupy_bits; // one set bit for each unique resource (idx = (id & 0xFFFF) >> 3) +} _sg_track_t; + // resource func forward decls struct _sg_buffer_s; struct _sg_image_s; @@ -5953,6 +6097,9 @@ enum { _SG_DEFAULT_UB_SIZE = 4 * 1024 * 1024, _SG_DEFAULT_MAX_COMMIT_LISTENERS = 1024, _SG_DEFAULT_WGPU_BINDGROUP_CACHE_SIZE = 1024, + _SG_DEFAULT_VK_COPY_STAGING_SIZE = (4 * 1024 * 1024), + _SG_DEFAULT_VK_STREAM_STAGING_SIZE = (16 * 1024 * 1024), + _SG_DEFAULT_VK_DESCRIPTOR_BUFFER_SIZE = (16 * 1024 * 1024), _SG_MAX_STORAGEBUFFER_BINDINGS_PER_STAGE = SG_MAX_VIEW_BINDSLOTS, _SG_MAX_STORAGEIMAGE_BINDINGS_PER_STAGE = SG_MAX_VIEW_BINDSLOTS, _SG_MAX_TEXTURE_BINDINGS_PER_STAGE = SG_MAX_VIEW_BINDSLOTS, @@ -6743,7 +6890,228 @@ typedef struct { _sg_wgpu_bindgroups_cache_t bindgroups_cache; _sg_wgpu_bindgroups_pool_t bindgroups_pool; } _sg_wgpu_backend_t; -#endif // SOKOL_WGPU + +#elif defined(SOKOL_VULKAN) + +#define _SG_VK_MAX_UNIFORM_UPDATE_SIZE (1<<16) +#define _SG_VK_NUM_DESCRIPTORSETS (2) // 0: uniforms, 1: images, samplers, storage buffers, storage images +#define _SG_VK_UB_DESCRIPTORSET_INDEX (0) +#define _SG_VK_VIEW_SMP_DESCRIPTORSET_INDEX (1) +#define _SG_VK_MAX_UB_DESCRIPTORSET_ENTRIES (SG_MAX_UNIFORMBLOCK_BINDSLOTS) +#define _SG_VK_MAX_UB_DESCRIPTORSET_SLOTS (2 * SG_MAX_UNIFORMBLOCK_BINDSLOTS) +#define _SG_VK_MAX_VIEW_SMP_DESCRIPTORSET_ENTRIES (SG_MAX_VIEW_BINDSLOTS + SG_MAX_SAMPLER_BINDSLOTS) +#define _SG_VK_MAX_VIEW_SMP_DESCRIPTORSET_SLOTS (128) +#define _SG_VK_MAX_DESCRIPTOR_DATA_SIZE (256) // FIXME: llvmpipe needs 280 bytes, do we need to care about that? + +typedef enum { + _SG_VK_MEMTYPE_STORAGE_BUFFER, + _SG_VK_MEMTYPE_GENERIC_BUFFER, + _SG_VK_MEMTYPE_IMAGE, + _SG_VK_MEMTYPE_STAGING_COPY, + _SG_VK_MEMTYPE_STAGING_STREAM, + _SG_VK_MEMTYPE_UNIFORMS, + _SG_VK_MEMTYPE_DESCRIPTORS, +} _sg_vk_memtype_t; + +typedef void (*_sg_vk_delete_queue_destructor_t)(void* obj); + +typedef struct { + _sg_vk_delete_queue_destructor_t destructor; + void* obj; +} _sg_vk_delete_queue_item_t; + +typedef struct { + uint32_t index; + uint32_t num; + _sg_vk_delete_queue_item_t* items; +} _sg_vk_delete_queue_t; + +typedef enum { + _SG_VK_ACCESS_NONE = (0), // initial state for new resources + _SG_VK_ACCESS_STAGING = (1<<0), + _SG_VK_ACCESS_VERTEXBUFFER = (1<<1), + _SG_VK_ACCESS_INDEXBUFFER = (1<<2), + _SG_VK_ACCESS_STORAGEBUFFER_RO = (1<<3), + _SG_VK_ACCESS_STORAGEBUFFER_RW = (1<<4), + _SG_VK_ACCESS_TEXTURE = (1<<5), + _SG_VK_ACCESS_STORAGEIMAGE = (1<<6), + _SG_VK_ACCESS_COLOR_ATTACHMENT = (1<<7), + _SG_VK_ACCESS_RESOLVE_ATTACHMENT = (1<<8), + _SG_VK_ACCESS_DEPTH_ATTACHMENT = (1<<9), + _SG_VK_ACCESS_STENCIL_ATTACHMENT = (1<<10), + _SG_VK_ACCESS_DISCARD = (1<<11), // in combination with attachments + _SG_VK_ACCESS_PRESENT = (1<<12), +} _sg_vk_access_bits_t; +typedef int _sg_vk_access_t; + +typedef struct _sg_buffer_s { + _sg_slot_t slot; + _sg_buffer_common_t cmn; + struct { + VkBuffer buf; + VkDeviceMemory mem; + VkDeviceAddress dev_addr; // only valid for storage buffers + _sg_vk_access_t cur_access; + } vk; +} _sg_vk_buffer_t; +typedef _sg_vk_buffer_t _sg_buffer_t; + +typedef struct _sg_image_s { + _sg_slot_t slot; + _sg_image_common_t cmn; + struct { + VkImage img; + VkDeviceMemory mem; + _sg_vk_access_t cur_access; + } vk; +} _sg_vk_image_t; +typedef _sg_vk_image_t _sg_image_t; + +typedef struct _sg_sampler_s { + _sg_slot_t slot; + _sg_sampler_common_t cmn; + struct { + VkSampler smp; + size_t descriptor_size; + uint8_t descriptor_data[_SG_VK_MAX_DESCRIPTOR_DATA_SIZE]; + } vk; +} _sg_vk_sampler_t; +typedef _sg_vk_sampler_t _sg_sampler_t; + +typedef struct { + VkShaderModule module; + _sg_str_t entry; +} _sg_vk_shader_func_t; + +typedef struct _sg_shader_s { + _sg_slot_t slot; + _sg_shader_common_t cmn; + struct { + _sg_vk_shader_func_t vertex_func; + _sg_vk_shader_func_t fragment_func; + _sg_vk_shader_func_t compute_func; + VkDescriptorSetLayout ub_dsl; + VkDeviceSize ub_dset_size; + VkDescriptorSetLayout view_smp_dsl; + VkDeviceSize view_smp_dset_size; + VkPipelineLayout pip_layout; + // indexed by sokol-gfx bind-slot + uint8_t ub_set0_bnd_n[SG_MAX_UNIFORMBLOCK_BINDSLOTS]; + uint8_t view_set1_bnd_n[SG_MAX_VIEW_BINDSLOTS]; + uint8_t smp_set1_bnd_n[SG_MAX_SAMPLER_BINDSLOTS]; + // relative descriptor offsets to start of descriptor set in descriptor buffer + uint16_t ub_dset_offsets[SG_MAX_UNIFORMBLOCK_BINDSLOTS]; + uint16_t view_dset_offsets[SG_MAX_VIEW_BINDSLOTS]; + uint16_t smp_dset_offsets[SG_MAX_SAMPLER_BINDSLOTS]; + } vk; +} _sg_vk_shader_t; +typedef _sg_vk_shader_t _sg_shader_t; + +typedef struct _sg_pipeline_s { + _sg_slot_t slot; + _sg_pipeline_common_t cmn; + struct { + VkPipeline pip; + } vk; +} _sg_vk_pipeline_t; +typedef _sg_vk_pipeline_t _sg_pipeline_t; + +typedef struct _sg_view_s { + _sg_slot_t slot; + _sg_view_common_t cmn; + struct { + VkImageView img_view; + size_t descriptor_size; + uint8_t descriptor_data[_SG_VK_MAX_DESCRIPTOR_DATA_SIZE]; + } vk; +} _sg_vk_view_t; +typedef _sg_vk_view_t _sg_view_t; + +// a double-buffer cpu-write / gpu-read buffer +#define _SG_VK_SHARED_BUFFER_OVERFLOW_RESULT (0xFFFFFFFF) +typedef struct { + uint32_t size; // buffer size + uint32_t align; // required buffer offset alignemnt + uint32_t offset; // current offset into buffer + VkBuffer cur_buf; // currently mapped buffer + void* cur_mem_ptr; // current pointer into currently mapped buffer + VkDeviceAddress cur_dev_addr; // current buffer device address (only valid for some buffer types) + bool overflown; // true when in overflown state + struct { + VkBuffer buf; + VkDeviceMemory mem; + VkDeviceAddress dev_addr; // only valid for some buffer types! + void* mem_ptr; + } slots[SG_NUM_INFLIGHT_FRAMES]; +} _sg_vk_shared_buffer_t; + +typedef struct { + VkDescriptorAddressInfoEXT addr_info; + VkDescriptorGetInfoEXT get_info; +} _sg_vk_uniform_bindinfo_t; + +typedef struct { + bool valid; + VkPhysicalDevice phys_dev; + VkDevice dev; + VkQueue queue; + uint32_t queue_family_index; + sg_vulkan_swapchain swapchain; + VkSemaphore present_complete_sem; + VkSemaphore render_finished_sem; + + // extension function pointers + struct { + PFN_vkGetDescriptorSetLayoutSizeEXT get_descriptor_set_layout_size; + PFN_vkGetDescriptorSetLayoutBindingOffsetEXT get_descriptor_set_layout_binding_offset; + PFN_vkGetDescriptorEXT get_descriptor; + PFN_vkCmdBindDescriptorBuffersEXT cmd_bind_descriptor_buffers; + PFN_vkCmdSetDescriptorBufferOffsetsEXT cmd_set_descriptor_buffer_offsets; + } ext; + + uint32_t frame_slot; + struct { + VkCommandPool cmd_pool; + VkCommandBuffer cmd_buf; + VkCommandBuffer stream_cmd_buf; + struct { + VkFence fence; + VkCommandBuffer command_buffer; + VkCommandBuffer stream_command_buffer; + _sg_vk_delete_queue_t delete_queue; + } slot[SG_NUM_INFLIGHT_FRAMES]; + } frame; + // staging system + struct { + // staging system for immutable and dynamic resources, generally causes a stall + struct { + VkCommandPool cmd_pool; + VkCommandBuffer cmd_buf; + uint32_t size; + VkBuffer buf; + VkDeviceMemory mem; + } copy; + // staging buffer for per-frame streaming updates + _sg_vk_shared_buffer_t stream; + } stage; + // uniform update system + bool uniforms_dirty; + _sg_vk_shared_buffer_t uniform; + _sg_vk_uniform_bindinfo_t uniform_bindinfos[SG_MAX_UNIFORMBLOCK_BINDSLOTS]; + // resource binding system (using descriptor buffers) + _sg_vk_shared_buffer_t bind; + // hazard tracking system for buffers and images + struct { + _sg_track_t buffers; + _sg_track_t images; + } track; + // device properties and features (initialized at startup) + VkPhysicalDeviceProperties2 dev_props; + VkPhysicalDeviceDescriptorBufferPropertiesEXT descriptor_buffer_props; + VkPhysicalDeviceFeatures2 dev_features; +} _sg_vk_backend_t; + +#endif // SOKOL_VULKAN // this *MUST* remain 0 #define _SG_INVALID_SLOT_INDEX (0) @@ -6810,6 +7178,7 @@ typedef struct { bool is_compute; _sg_dimi_t dim; sg_attachments atts; + sg_pass_action action; struct { sg_pixel_format color_fmt; sg_pixel_format depth_fmt; @@ -6841,6 +7210,8 @@ typedef struct { _sg_d3d11_backend_t d3d11; #elif defined(SOKOL_WGPU) _sg_wgpu_backend_t wgpu; + #elif defined(SOKOL_VULKAN) + _sg_vk_backend_t vk; #endif #if defined(SOKOL_TRACE_HOOKS) sg_trace_hooks hooks; @@ -6897,6 +7268,22 @@ static void _sg_log(sg_log_item log_item, uint32_t log_level, const char* msg, u // // >>memory +_SOKOL_PRIVATE int _sg_roundup(int val, int round_to) { + return (val+(round_to-1)) & ~(round_to-1); +} + +_SOKOL_PRIVATE uint32_t _sg_roundup_u32(uint32_t val, uint32_t round_to) { + return (val+(round_to-1)) & ~(round_to-1); +} + +_SOKOL_PRIVATE uint64_t _sg_roundup_u64(uint64_t val, uint64_t round_to) { + return (val+(round_to-1)) & ~(round_to-1); +} + +_SOKOL_PRIVATE bool _sg_multiple_u64(uint64_t val, uint64_t of) { + return (val & (of-1)) == 0; +} + // a helper macro to clear a struct with potentially ARC'ed ObjC references #if defined(SOKOL_METAL) #if defined(__cplusplus) @@ -7269,6 +7656,86 @@ _SOKOL_PRIVATE _sg_view_t* _sg_lookup_view(uint32_t view_id) { return 0; } +// ████████ ██████ █████ ██████ ██ ██ +// ██ ██ ██ ██ ██ ██ ██ ██ +// ██ ██████ ███████ ██ █████ +// ██ ██ ██ ██ ██ ██ ██ ██ +// ██ ██ ██ ██ ██ ██████ ██ ██ +// +// >>track +_SOKOL_PRIVATE void _sg_track_init(_sg_track_t* track, int num_slots) { + SOKOL_ASSERT(track && (num_slots > 0)); + _sg_clear(track, sizeof(_sg_track_t)); + track->num_slots = num_slots; + track->slots = (uint32_t*)_sg_malloc_clear((size_t)num_slots * sizeof(uint32_t)); + track->occupy_num_bytes = _sg_roundup_u32((uint32_t)num_slots, 8) >> 3; + track->occupy_bits = (uint8_t*)_sg_malloc_clear(track->occupy_num_bytes); +} + +_SOKOL_PRIVATE void _sg_track_discard(_sg_track_t* track) { + SOKOL_ASSERT(track); + if (track->slots) { + _sg_free(track->slots); + track->slots = 0; + } + if (track->occupy_bits) { + _sg_free(track->occupy_bits); + track->occupy_num_bytes = 0; + track->occupy_bits = 0; + } + track->num_slots = 0; + track->cur_slot = 0; +} + +_SOKOL_PRIVATE void _sg_track_reset(_sg_track_t* track) { + SOKOL_ASSERT(track && track->slots && track->occupy_bits); + track->cur_slot = 0; + _sg_clear(track->occupy_bits, track->occupy_num_bytes); +} + +_SOKOL_PRIVATE int _sg_track_occupy_index(int slot_index) { + const int occupy_index = slot_index >> 3; + return occupy_index; +} + +_SOKOL_PRIVATE uint8_t _sg_track_occupy_mask(int slot_index) { + return (uint8_t)(1 << (slot_index & 7)); +} + +_SOKOL_PRIVATE void _sg_track_add(_sg_track_t* track, uint32_t id) { + SOKOL_ASSERT(track && track->slots && track->occupy_bits); + SOKOL_ASSERT(id != SG_INVALID_ID); + const int slot_index = _sg_slot_index(id); + const int occupy_index = _sg_track_occupy_index(slot_index); + SOKOL_ASSERT((uint32_t)occupy_index < track->occupy_num_bytes); + const uint8_t occupy_mask = _sg_track_occupy_mask(slot_index); + // don't record the same resource twice + if (0 == (track->occupy_bits[occupy_index] & occupy_mask)) { + SOKOL_ASSERT(track->cur_slot < track->num_slots); + track->slots[track->cur_slot++] = id; + track->occupy_bits[occupy_index] |= occupy_mask; + } +} + +_SOKOL_PRIVATE void _sg_track_remove(_sg_track_t* track, uint32_t id) { + SOKOL_ASSERT(track && track->slots && track->occupy_bits); + SOKOL_ASSERT(id != SG_INVALID_ID); + const int slot_index = _sg_slot_index(id); + const int occupy_index = _sg_track_occupy_index(slot_index); + const uint8_t occupy_mask = _sg_track_occupy_mask(slot_index); + if (track->occupy_bits[occupy_index] & occupy_mask) { + track->occupy_bits[occupy_index] &= ~occupy_mask; + // remove tracked id from the slots array + for (int i = 0; i < track->cur_slot; i++) { + if (id == track->slots[i]) { + SOKOL_ASSERT(track->cur_slot > 0); + track->slots[i] = track->slots[--track->cur_slot]; + break; + } + } + } +} + // ██████ ███████ ███████ ███████ // ██ ██ ██ ██ ██ // ██████ █████ █████ ███████ @@ -8092,28 +8559,17 @@ _SOKOL_PRIVATE int _sg_pixelformat_bytesize(sg_pixel_format fmt) { } } -_SOKOL_PRIVATE int _sg_roundup(int val, int round_to) { - return (val+(round_to-1)) & ~(round_to-1); -} - -_SOKOL_PRIVATE uint32_t _sg_roundup_u32(uint32_t val, uint32_t round_to) { - return (val+(round_to-1)) & ~(round_to-1); -} - -_SOKOL_PRIVATE uint64_t _sg_roundup_u64(uint64_t val, uint64_t round_to) { - return (val+(round_to-1)) & ~(round_to-1); -} - -_SOKOL_PRIVATE bool _sg_multiple_u64(uint64_t val, uint64_t of) { - return (val & (of-1)) == 0; +// return the texture block width/height of an image format +_SOKOL_PRIVATE int _sg_block_dim(sg_pixel_format fmt) { + if (_sg_is_compressed_pixel_format(fmt)) { + return 4; + } else { + return 1; + } } -/* return row pitch for an image - - see ComputePitch in https://github.com/microsoft/DirectXTex/blob/master/DirectXTex/DirectXTexUtil.cpp -*/ -_SOKOL_PRIVATE int _sg_row_pitch(sg_pixel_format fmt, int width, int row_align) { - int pitch; +// return texture block size in bytes +_SOKOL_PRIVATE int _sg_block_bytesize(sg_pixel_format fmt) { switch (fmt) { case SG_PIXELFORMAT_BC1_RGBA: case SG_PIXELFORMAT_BC4_R: @@ -8123,9 +8579,7 @@ _SOKOL_PRIVATE int _sg_row_pitch(sg_pixel_format fmt, int width, int row_align) case SG_PIXELFORMAT_ETC2_RGB8A1: case SG_PIXELFORMAT_EAC_R11: case SG_PIXELFORMAT_EAC_R11SN: - pitch = ((width + 3) / 4) * 8; - pitch = pitch < 8 ? 8 : pitch; - break; + return 8; case SG_PIXELFORMAT_BC2_RGBA: case SG_PIXELFORMAT_BC3_RGBA: case SG_PIXELFORMAT_BC3_SRGBA: @@ -8141,50 +8595,30 @@ _SOKOL_PRIVATE int _sg_row_pitch(sg_pixel_format fmt, int width, int row_align) case SG_PIXELFORMAT_EAC_RG11SN: case SG_PIXELFORMAT_ASTC_4x4_RGBA: case SG_PIXELFORMAT_ASTC_4x4_SRGBA: - pitch = ((width + 3) / 4) * 16; - pitch = pitch < 16 ? 16 : pitch; - break; + return 16; default: - pitch = width * _sg_pixelformat_bytesize(fmt); - break; + return _sg_pixelformat_bytesize(fmt); } +} + +/* return row pitch for an image + + see ComputePitch in https://github.com/microsoft/DirectXTex/blob/master/DirectXTex/DirectXTexUtil.cpp +*/ +_SOKOL_PRIVATE int _sg_row_pitch(sg_pixel_format fmt, int width, int row_align) { + const int block_dim = _sg_block_dim(fmt); + const int num_blocks_in_row = (width + (block_dim-1)) / block_dim; + const int block_num_bytes = _sg_block_bytesize(fmt); + int pitch = num_blocks_in_row * block_num_bytes; + pitch = (pitch < block_num_bytes) ? block_num_bytes : pitch; pitch = _sg_roundup(pitch, row_align); return pitch; } // compute the number of rows in a surface depending on pixel format _SOKOL_PRIVATE int _sg_num_rows(sg_pixel_format fmt, int height) { - int num_rows; - switch (fmt) { - case SG_PIXELFORMAT_BC1_RGBA: - case SG_PIXELFORMAT_BC4_R: - case SG_PIXELFORMAT_BC4_RSN: - case SG_PIXELFORMAT_ETC2_RGB8: - case SG_PIXELFORMAT_ETC2_SRGB8: - case SG_PIXELFORMAT_ETC2_RGB8A1: - case SG_PIXELFORMAT_ETC2_RGBA8: - case SG_PIXELFORMAT_ETC2_SRGB8A8: - case SG_PIXELFORMAT_EAC_R11: - case SG_PIXELFORMAT_EAC_R11SN: - case SG_PIXELFORMAT_EAC_RG11: - case SG_PIXELFORMAT_EAC_RG11SN: - case SG_PIXELFORMAT_BC2_RGBA: - case SG_PIXELFORMAT_BC3_RGBA: - case SG_PIXELFORMAT_BC3_SRGBA: - case SG_PIXELFORMAT_BC5_RG: - case SG_PIXELFORMAT_BC5_RGSN: - case SG_PIXELFORMAT_BC6H_RGBF: - case SG_PIXELFORMAT_BC6H_RGBUF: - case SG_PIXELFORMAT_BC7_RGBA: - case SG_PIXELFORMAT_BC7_SRGBA: - case SG_PIXELFORMAT_ASTC_4x4_RGBA: - case SG_PIXELFORMAT_ASTC_4x4_SRGBA: - num_rows = ((height + 3) / 4); - break; - default: - num_rows = height; - break; - } + const int block_dim = _sg_block_dim(fmt); + int num_rows = (height + (block_dim-1)) / block_dim; if (num_rows < 1) { num_rows = 1; } @@ -12842,7 +13276,7 @@ _SOKOL_PRIVATE ID3DBlob* _sg_d3d11_compile_shader(const sg_shader_function* shd_ } SOKOL_ASSERT(shd_func->d3d11_target); UINT flags1 = D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR; - if (_sg.desc.d3d11_shader_debugging) { + if (_sg.desc.d3d11.shader_debugging) { flags1 |= D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; } else { flags1 |= D3DCOMPILE_OPTIMIZATION_LEVEL3; @@ -14372,11 +14806,11 @@ _SOKOL_PRIVATE void _sg_mtl_init_pool(const sg_desc* desc) { _sg.mtl.idpool.num_slots = 2 * ( 2 * desc->buffer_pool_size + - 4 * desc->image_pool_size + + 2 * desc->image_pool_size + 1 * desc->sampler_pool_size + - 4 * desc->shader_pool_size + - 2 * desc->pipeline_pool_size + - desc->view_pool_size + + 6 * desc->shader_pool_size + + 3 * desc->pipeline_pool_size + + 1 * desc->view_pool_size + 128 ); _sg.mtl.idpool.pool = [NSMutableArray arrayWithCapacity:(NSUInteger)_sg.mtl.idpool.num_slots]; @@ -14703,7 +15137,7 @@ _SOKOL_PRIVATE void _sg_mtl_setup_backend(const sg_desc* desc) { #endif } - if (desc->mtl_force_managed_storage_mode) { + if (desc->metal.force_managed_storage_mode) { _sg.mtl.use_shared_storage_mode = false; } else if (@available(macOS 10.15, iOS 13.0, *)) { // on Intel Macs, always use managed resources even though the @@ -15603,7 +16037,7 @@ _SOKOL_PRIVATE void _sg_mtl_begin_pass(const sg_pass* pass, const _sg_attachment if (nil == _sg.mtl.cmd_buffer) { // block until the oldest frame in flight has finished dispatch_semaphore_wait(_sg.mtl.sem, DISPATCH_TIME_FOREVER); - if (_sg.desc.mtl_use_command_buffer_with_retained_references) { + if (_sg.desc.metal.use_command_buffer_with_retained_references) { _sg.mtl.cmd_buffer = [_sg.mtl.cmd_queue commandBuffer]; } else { _sg.mtl.cmd_buffer = [_sg.mtl.cmd_queue commandBufferWithUnretainedReferences]; @@ -16191,7 +16625,7 @@ _SOKOL_PRIVATE WGPUTextureViewDimension _sg_wgpu_attachment_view_dimension(sg_im switch (t) { case SG_IMAGETYPE_2D: return WGPUTextureViewDimension_2D; case SG_IMAGETYPE_CUBE: return WGPUTextureViewDimension_2DArray; // not a bug - case SG_IMAGETYPE_3D: return WGPUTextureViewDimension_2D; + case SG_IMAGETYPE_3D: return WGPUTextureViewDimension_2D; // not a bug case SG_IMAGETYPE_ARRAY: return WGPUTextureViewDimension_2DArray; default: SOKOL_UNREACHABLE; return WGPUTextureViewDimension_Force32; } @@ -16374,6 +16808,7 @@ _SOKOL_PRIVATE WGPUTextureFormat _sg_wgpu_textureformat(sg_pixel_format p) { case SG_PIXELFORMAT_BGRA8: return WGPUTextureFormat_BGRA8Unorm; case SG_PIXELFORMAT_RGB10A2: return WGPUTextureFormat_RGB10A2Unorm; case SG_PIXELFORMAT_RG11B10F: return WGPUTextureFormat_RG11B10Ufloat; + case SG_PIXELFORMAT_RGB9E5: return WGPUTextureFormat_RGB9E5Ufloat; case SG_PIXELFORMAT_RG32UI: return WGPUTextureFormat_RG32Uint; case SG_PIXELFORMAT_RG32SI: return WGPUTextureFormat_RG32Sint; case SG_PIXELFORMAT_RG32F: return WGPUTextureFormat_RG32Float; @@ -16406,7 +16841,6 @@ _SOKOL_PRIVATE WGPUTextureFormat _sg_wgpu_textureformat(sg_pixel_format p) { case SG_PIXELFORMAT_EAC_R11SN: return WGPUTextureFormat_EACR11Snorm; case SG_PIXELFORMAT_EAC_RG11: return WGPUTextureFormat_EACRG11Unorm; case SG_PIXELFORMAT_EAC_RG11SN: return WGPUTextureFormat_EACRG11Snorm; - case SG_PIXELFORMAT_RGB9E5: return WGPUTextureFormat_RGB9E5Ufloat; case SG_PIXELFORMAT_ASTC_4x4_RGBA: return WGPUTextureFormat_ASTC4x4Unorm; case SG_PIXELFORMAT_ASTC_4x4_SRGBA: return WGPUTextureFormat_ASTC4x4UnormSrgb; // NOT SUPPORTED @@ -16688,10 +17122,10 @@ _SOKOL_PRIVATE void _sg_wgpu_uniform_buffer_on_commit(void) { } _SOKOL_PRIVATE void _sg_wgpu_bindgroups_pool_init(const sg_desc* desc) { - SOKOL_ASSERT((desc->wgpu_bindgroups_cache_size > 0) && (desc->wgpu_bindgroups_cache_size < _SG_MAX_POOL_SIZE)); + SOKOL_ASSERT((desc->wgpu.bindgroups_cache_size > 0) && (desc->wgpu.bindgroups_cache_size < _SG_MAX_POOL_SIZE)); _sg_wgpu_bindgroups_pool_t* p = &_sg.wgpu.bindgroups_pool; SOKOL_ASSERT(0 == p->bindgroups); - const int pool_size = desc->wgpu_bindgroups_cache_size; + const int pool_size = desc->wgpu.bindgroups_cache_size; _sg_pool_init(&p->pool, pool_size); size_t pool_byte_size = sizeof(_sg_wgpu_bindgroup_t) * (size_t)p->pool.size; p->bindgroups = (_sg_wgpu_bindgroup_t*) _sg_malloc_clear(pool_byte_size); @@ -16954,14 +17388,14 @@ _SOKOL_PRIVATE void _sg_wgpu_bindgroups_cache_init(const sg_desc* desc) { SOKOL_ASSERT(_sg.wgpu.bindgroups_cache.num == 0); SOKOL_ASSERT(_sg.wgpu.bindgroups_cache.index_mask == 0); SOKOL_ASSERT(_sg.wgpu.bindgroups_cache.items == 0); - const int num = desc->wgpu_bindgroups_cache_size; + const int num = desc->wgpu.bindgroups_cache_size; if (num <= 1) { _SG_PANIC(WGPU_BINDGROUPSCACHE_SIZE_GREATER_ONE); } if (!_sg_ispow2(num)) { _SG_PANIC(WGPU_BINDGROUPSCACHE_SIZE_POW2); } - _sg.wgpu.bindgroups_cache.num = (uint32_t)desc->wgpu_bindgroups_cache_size; + _sg.wgpu.bindgroups_cache.num = (uint32_t)desc->wgpu.bindgroups_cache_size; _sg.wgpu.bindgroups_cache.index_mask = _sg.wgpu.bindgroups_cache.num - 1; size_t size_in_bytes = sizeof(_sg_wgpu_bindgroup_handle_t) * (size_t)num; _sg.wgpu.bindgroups_cache.items = (_sg_wgpu_bindgroup_handle_t*)_sg_malloc_clear(size_in_bytes); @@ -17107,7 +17541,7 @@ _SOKOL_PRIVATE void _sg_wgpu_set_bindgroup(uint32_t bg_idx, _sg_wgpu_bindgroup_t } _SOKOL_PRIVATE bool _sg_wgpu_apply_bindings_bindgroup(_sg_bindings_ptrs_t* bnd) { - if (!_sg.desc.wgpu_disable_bindgroups_cache) { + if (!_sg.desc.wgpu.disable_bindgroups_cache) { _sg_wgpu_bindgroup_t* bg = 0; _sg_wgpu_bindgroups_cache_key_t key; _sg_wgpu_init_bindgroups_cache_key(&key, bnd); @@ -17206,7 +17640,6 @@ _SOKOL_PRIVATE void _sg_wgpu_setup_backend(const sg_desc* desc) { SOKOL_ASSERT(desc); SOKOL_ASSERT(desc->environment.wgpu.device); SOKOL_ASSERT(desc->uniform_buffer_size > 0); - _sg.backend = SG_BACKEND_WGPU; _sg.wgpu.valid = true; _sg.wgpu.dev = (WGPUDevice) desc->environment.wgpu.device; _sg.wgpu.queue = wgpuDeviceGetQueue(_sg.wgpu.dev); @@ -17707,7 +18140,6 @@ _SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_pipeline(_sg_pipeline_t* pip, c // - @group(0) for uniform blocks // - @group(1) for all image, sampler and storagebuffer resources - // - @group(2) optional: storage image attachments in compute passes size_t num_bgls = 2; WGPUBindGroupLayout wgpu_bgl[_SG_WGPU_MAX_BINDGROUPS]; _sg_clear(&wgpu_bgl, sizeof(wgpu_bgl)); @@ -18170,13 +18602,12 @@ _SOKOL_PRIVATE void _sg_wgpu_dispatch(int num_groups_x, int num_groups_y, int nu } _SOKOL_PRIVATE void _sg_wgpu_update_buffer(_sg_buffer_t* buf, const sg_range* data) { - SOKOL_ASSERT(data && data->ptr && (data->size > 0)); - SOKOL_ASSERT(buf); + SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0)); _sg_wgpu_copy_buffer_data(buf, 0, data); } _SOKOL_PRIVATE void _sg_wgpu_append_buffer(_sg_buffer_t* buf, const sg_range* data, bool new_frame) { - SOKOL_ASSERT(data && data->ptr && (data->size > 0)); + SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0)); _SOKOL_UNUSED(new_frame); _sg_wgpu_copy_buffer_data(buf, (uint64_t)buf->cmn.append_pos, data); } @@ -18185,6 +18616,3128 @@ _SOKOL_PRIVATE void _sg_wgpu_update_image(_sg_image_t* img, const sg_image_data* SOKOL_ASSERT(img && data); _sg_wgpu_copy_image_data(img, img->wgpu.tex, data); } + +// ██ ██ ██ ██ ██ ██ ██ █████ ███ ██ ██████ █████ ██████ ██ ██ ███████ ███ ██ ██████ +// ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ +// ██ ██ ██ ██ ██ █████ ███████ ██ ██ ██ ██████ ███████ ██ █████ █████ ██ ██ ██ ██ ██ +// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +// ████ ██████ ███████ ██ ██ ██ ██ ██ ████ ██████ ██ ██ ██████ ██ ██ ███████ ██ ████ ██████ +// +// >>vulkan +// >>vk +#elif defined(SOKOL_VULKAN) + +_SOKOL_PRIVATE void _sg_vk_set_object_label(VkObjectType obj_type, uint64_t obj_handle, const char* label) { + SOKOL_ASSERT(_sg.vk.dev); + SOKOL_ASSERT(obj_handle != 0); + if (label) { + // FIXME: use vkSetDebugUtilsObjectNamesEXT + _SOKOL_UNUSED(obj_type && obj_handle && label); + } +} + +_SOKOL_PRIVATE bool _sg_vk_is_read_access(_sg_vk_access_t access) { + _sg_vk_access_t read_bits = + _SG_VK_ACCESS_VERTEXBUFFER | + _SG_VK_ACCESS_INDEXBUFFER | + _SG_VK_ACCESS_STORAGEBUFFER_RO | + _SG_VK_ACCESS_TEXTURE | + _SG_VK_ACCESS_PRESENT; + return 0 == (access & ~read_bits); +} + +_SOKOL_PRIVATE VkPipelineStageFlags2 _sg_vk_stage_mask(_sg_vk_access_t access, bool is_dst_access) { + access &= ~_SG_VK_ACCESS_DISCARD; + if (is_dst_access) { + SOKOL_ASSERT(access != _SG_VK_ACCESS_NONE); + } + VkPipelineStageFlags2 f = 0; + if (access == _SG_VK_ACCESS_NONE) { + return VK_PIPELINE_STAGE_2_NONE; + } + if (access & _SG_VK_ACCESS_PRESENT) { + return VK_PIPELINE_STAGE_2_NONE; + } + if (access & _SG_VK_ACCESS_STAGING) { + f |= VK_PIPELINE_STAGE_2_COPY_BIT; + } + if (access & _SG_VK_ACCESS_VERTEXBUFFER) { + f |= VK_PIPELINE_STAGE_2_VERTEX_ATTRIBUTE_INPUT_BIT; + } + if (access & _SG_VK_ACCESS_INDEXBUFFER) { + f |= VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT; + } + if (access & (_SG_VK_ACCESS_STORAGEBUFFER_RO|_SG_VK_ACCESS_TEXTURE)) { + f |= VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT | + VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT | + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT; + } + if (access & _SG_VK_ACCESS_STORAGEBUFFER_RW) { + f |= VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT; + } + if (access & _SG_VK_ACCESS_STORAGEIMAGE) { + f |= VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT; + } + if (access & _SG_VK_ACCESS_COLOR_ATTACHMENT) { + f |= VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT; + } + if (access & _SG_VK_ACCESS_RESOLVE_ATTACHMENT) { + f |= VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT; + } + if (access & (_SG_VK_ACCESS_DEPTH_ATTACHMENT|_SG_VK_ACCESS_STENCIL_ATTACHMENT)) { + f |= VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT|VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT; + } + SOKOL_ASSERT(f != 0); + return f; +} + +// return pipeline stages on 'before' side of a barrier +_SOKOL_PRIVATE VkPipelineStageFlags2 _sg_vk_src_stage_mask(_sg_vk_access_t access) { + return _sg_vk_stage_mask(access, false); +} + +// return pipeline stage on 'after side' of a barrier +_SOKOL_PRIVATE VkPipelineStageFlags2 _sg_vk_dst_stage_mask(_sg_vk_access_t access) { + return _sg_vk_stage_mask(access, true); +} + +_SOKOL_PRIVATE VkAccessFlags2 _sg_vk_access_mask(_sg_vk_access_t access, bool is_dst_access) { + access &= ~_SG_VK_ACCESS_DISCARD; + if (access == _SG_VK_ACCESS_NONE) { + return VK_ACCESS_2_NONE; + } + if (access & _SG_VK_ACCESS_PRESENT) { + return VK_ACCESS_2_NONE; + } + VkAccessFlags2 f = VK_ACCESS_2_NONE; + if (is_dst_access) { + // NOTE: read bits don't make sense for src-mask + if (access & _SG_VK_ACCESS_VERTEXBUFFER) { + f |= VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT; + } + if (access & _SG_VK_ACCESS_INDEXBUFFER) { + f |= VK_ACCESS_2_INDEX_READ_BIT; + } + if (access & _SG_VK_ACCESS_STORAGEBUFFER_RO) { + f |= VK_ACCESS_2_SHADER_STORAGE_READ_BIT; + } + if (access & _SG_VK_ACCESS_TEXTURE) { + f |= VK_ACCESS_2_SHADER_SAMPLED_READ_BIT; + } + } + if (access & _SG_VK_ACCESS_STAGING) { + f |= VK_ACCESS_2_TRANSFER_WRITE_BIT; + } + if (access & _SG_VK_ACCESS_STORAGEBUFFER_RW) { + f |= VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT | VK_ACCESS_2_SHADER_STORAGE_READ_BIT; + } + if (access & _SG_VK_ACCESS_STORAGEIMAGE) { + f |= VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT | VK_ACCESS_2_SHADER_STORAGE_READ_BIT; + } + if (access & _SG_VK_ACCESS_COLOR_ATTACHMENT) { + f |= VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT; + } + if (access & _SG_VK_ACCESS_RESOLVE_ATTACHMENT) { + f |= VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT; + } + if (access & (_SG_VK_ACCESS_DEPTH_ATTACHMENT | _SG_VK_ACCESS_STENCIL_ATTACHMENT)) { + f |= VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + if (is_dst_access) { + f |= VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT; + } + } + return f; +} + +_SOKOL_PRIVATE VkAccessFlags2 _sg_vk_src_access_mask(_sg_vk_access_t access) { + return _sg_vk_access_mask(access, false); +} + +_SOKOL_PRIVATE VkAccessFlags2 _sg_vk_dst_access_mask(_sg_vk_access_t access) { + return _sg_vk_access_mask(access, true); +} + +_SOKOL_PRIVATE VkImageLayout _sg_vk_image_layout(_sg_vk_access_t access) { + // NOTE: "image layout transitions with VK_IMAGE_LAYOUT_UNDEFINED allow + // the implementation to discard the image subresource range" + if (access & _SG_VK_ACCESS_DISCARD) { + return VK_IMAGE_LAYOUT_UNDEFINED; + } + switch (access) { + case _SG_VK_ACCESS_NONE: + return VK_IMAGE_LAYOUT_UNDEFINED; + case _SG_VK_ACCESS_STAGING: + return VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + case _SG_VK_ACCESS_TEXTURE: + return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + case _SG_VK_ACCESS_STORAGEIMAGE: + return VK_IMAGE_LAYOUT_GENERAL; + case _SG_VK_ACCESS_COLOR_ATTACHMENT: + case _SG_VK_ACCESS_RESOLVE_ATTACHMENT: + case _SG_VK_ACCESS_DEPTH_ATTACHMENT: + case _SG_VK_ACCESS_DEPTH_ATTACHMENT|_SG_VK_ACCESS_STENCIL_ATTACHMENT: + return VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL; + case _SG_VK_ACCESS_PRESENT: + return VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + default: + SOKOL_UNREACHABLE; + return VK_IMAGE_LAYOUT_UNDEFINED; + } +} + +_SOKOL_PRIVATE void _sg_vk_swapchain_beginpass_barrier(VkCommandBuffer cmd_buf, VkImage vkimg, _sg_vk_access_t pass_access) { + SOKOL_ASSERT(cmd_buf); + _SG_STRUCT(VkImageMemoryBarrier2, barrier); + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2; + barrier.srcStageMask = _sg_vk_src_stage_mask(pass_access); + barrier.srcAccessMask = _sg_vk_src_access_mask(pass_access); + barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + barrier.dstStageMask = _sg_vk_dst_stage_mask(pass_access); + barrier.dstAccessMask = _sg_vk_dst_access_mask(pass_access); + barrier.newLayout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.image = vkimg; + if (0 != (pass_access & (_SG_VK_ACCESS_DEPTH_ATTACHMENT|_SG_VK_ACCESS_STENCIL_ATTACHMENT))) { + barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; + if (0 != (pass_access & _SG_VK_ACCESS_STENCIL_ATTACHMENT)) { + barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; + } + } else { + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + } + barrier.subresourceRange.levelCount = 1; + barrier.subresourceRange.layerCount = 1; + _SG_STRUCT(VkDependencyInfo, dep_info); + dep_info.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; + dep_info.imageMemoryBarrierCount = 1; + dep_info.pImageMemoryBarriers = &barrier; + vkCmdPipelineBarrier2(cmd_buf, &dep_info); + _sg_stats_add(vk.num_cmd_pipeline_barrier, 1); +} + +_SOKOL_PRIVATE void _sg_vk_swapchain_endpass_barrier(VkCommandBuffer cmd_buf, VkImage vkimg, _sg_vk_access_t pass_access, bool present) { + SOKOL_ASSERT(cmd_buf); + _SG_STRUCT(VkImageMemoryBarrier2, barrier); + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2; + barrier.srcStageMask = _sg_vk_src_stage_mask(pass_access); + barrier.srcAccessMask = _sg_vk_src_access_mask(pass_access); + barrier.oldLayout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL; + barrier.dstStageMask = VK_PIPELINE_STAGE_2_NONE; + barrier.dstAccessMask = VK_ACCESS_2_NONE; + if (present) { + barrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + } else { + barrier.newLayout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL; + } + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.image = vkimg; + if (0 != (pass_access & (_SG_VK_ACCESS_DEPTH_ATTACHMENT|_SG_VK_ACCESS_STENCIL_ATTACHMENT))) { + barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; + if (0 != (pass_access & _SG_VK_ACCESS_STENCIL_ATTACHMENT)) { + barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; + } + } else { + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + } + barrier.subresourceRange.levelCount = 1; + barrier.subresourceRange.layerCount = 1; + _SG_STRUCT(VkDependencyInfo, dep_info); + dep_info.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; + dep_info.imageMemoryBarrierCount = 1; + dep_info.pImageMemoryBarriers = &barrier; + vkCmdPipelineBarrier2(cmd_buf, &dep_info); + _sg_stats_add(vk.num_cmd_pipeline_barrier, 1); +} + +_SOKOL_PRIVATE void _sg_vk_image_barrier(VkCommandBuffer cmd_buf, _sg_image_t* img, _sg_vk_access_t new_access) { + SOKOL_ASSERT(cmd_buf && img && img->vk.img); + if (_sg_vk_is_read_access(img->vk.cur_access) && _sg_vk_is_read_access(new_access)) { + return; + } + _SG_STRUCT(VkImageMemoryBarrier2, barrier); + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2; + barrier.srcStageMask = _sg_vk_src_stage_mask(img->vk.cur_access); + barrier.srcAccessMask = _sg_vk_src_access_mask(img->vk.cur_access); + barrier.oldLayout = _sg_vk_image_layout(img->vk.cur_access); + barrier.dstStageMask = _sg_vk_dst_stage_mask(new_access); + barrier.dstAccessMask = _sg_vk_dst_access_mask(new_access); + barrier.newLayout = _sg_vk_image_layout(new_access); + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.image = img->vk.img; + if (_sg_is_depth_or_depth_stencil_format(img->cmn.pixel_format)) { + barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; + if (_sg_is_depth_stencil_format(img->cmn.pixel_format)) { + barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; + } + } else { + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + } + barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + _SG_STRUCT(VkDependencyInfo, dep_info); + dep_info.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; + dep_info.imageMemoryBarrierCount = 1; + dep_info.pImageMemoryBarriers = &barrier; + vkCmdPipelineBarrier2(cmd_buf, &dep_info); + _sg_stats_add(vk.num_cmd_pipeline_barrier, 1); + img->vk.cur_access = new_access; +} + +_SOKOL_PRIVATE void _sg_vk_buffer_barrier(VkCommandBuffer cmd_buf, _sg_buffer_t* buf, _sg_vk_access_t new_access) { + SOKOL_ASSERT(cmd_buf && buf && buf->vk.buf); + if (_sg_vk_is_read_access(buf->vk.cur_access) && _sg_vk_is_read_access(new_access)) { + return; + } + _SG_STRUCT(VkBufferMemoryBarrier2, barrier); + barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2; + barrier.srcStageMask = _sg_vk_src_stage_mask(buf->vk.cur_access); + barrier.srcAccessMask = _sg_vk_src_access_mask(buf->vk.cur_access); + barrier.dstStageMask = _sg_vk_dst_stage_mask(new_access); + barrier.dstAccessMask = _sg_vk_dst_access_mask(new_access); + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.buffer = buf->vk.buf; + barrier.offset = 0; + barrier.size = VK_WHOLE_SIZE; + _SG_STRUCT(VkDependencyInfo, dep_info); + dep_info.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; + dep_info.bufferMemoryBarrierCount = 1; + dep_info.pBufferMemoryBarriers = &barrier; + vkCmdPipelineBarrier2(cmd_buf, &dep_info); + _sg_stats_add(vk.num_cmd_pipeline_barrier, 1); + buf->vk.cur_access = new_access; +} + +_SOKOL_PRIVATE void _sg_vk_barrier_on_begin_pass(VkCommandBuffer cmd_buf, const sg_pass* pass, const _sg_attachments_ptrs_t* atts, bool is_compute_pass) { + SOKOL_ASSERT(cmd_buf); + if (is_compute_pass) { + SOKOL_ASSERT(0 == _sg.vk.track.buffers.cur_slot); + SOKOL_ASSERT(0 == _sg.vk.track.images.cur_slot); + } else { + const bool is_swapchain_pass = atts->empty; + if (is_swapchain_pass) { + const sg_vulkan_swapchain* vk_swapchain = &pass->swapchain.vulkan; + SOKOL_ASSERT(vk_swapchain->render_image); + VkImage vk_color_image = (VkImage)vk_swapchain->render_image; + _sg_vk_swapchain_beginpass_barrier(cmd_buf, vk_color_image, _SG_VK_ACCESS_COLOR_ATTACHMENT); + if (_sg.cur_pass.swapchain.sample_count > 1) { + VkImage vk_resolve_image = (VkImage)vk_swapchain->resolve_image; + SOKOL_ASSERT(vk_resolve_image); + _sg_vk_swapchain_beginpass_barrier(cmd_buf, vk_resolve_image, _SG_VK_ACCESS_RESOLVE_ATTACHMENT); + } + if (vk_swapchain->depth_stencil_image) { + VkImage vk_ds_image = (VkImage)vk_swapchain->depth_stencil_image; + const bool has_stencil = _sg_is_depth_stencil_format(_sg.cur_pass.swapchain.depth_fmt); + _sg_vk_access_t access = _SG_VK_ACCESS_DEPTH_ATTACHMENT; + if (has_stencil) { + access |= _SG_VK_ACCESS_STENCIL_ATTACHMENT; + } + _sg_vk_swapchain_beginpass_barrier(cmd_buf, vk_ds_image, access); + } + } else { + SOKOL_ASSERT(atts->num_color_views <= SG_MAX_COLOR_ATTACHMENTS); + for (int i = 0; i < atts->num_color_views; i++) { + SOKOL_ASSERT(atts->color_views[i]); + _sg_image_t* color_image = _sg_image_ref_ptr(&atts->color_views[i]->cmn.img.ref); + if (pass->action.colors[i].load_action != SG_LOADACTION_LOAD) { + // don't need to preserve image content for clear and dontcare + color_image->vk.cur_access |= _SG_VK_ACCESS_DISCARD; + } + _sg_vk_image_barrier(cmd_buf, color_image, _SG_VK_ACCESS_COLOR_ATTACHMENT); + if (atts->resolve_views[i]) { + _sg_image_t* resolve_image = _sg_image_ref_ptr(&atts->resolve_views[i]->cmn.img.ref); + // never need to preserve content for resolve image + resolve_image->vk.cur_access |= _SG_VK_ACCESS_DISCARD; + _sg_vk_image_barrier(cmd_buf, resolve_image, _SG_VK_ACCESS_RESOLVE_ATTACHMENT); + } + } + if (atts->ds_view) { + _sg_image_t* ds_image = _sg_image_ref_ptr(&atts->ds_view->cmn.img.ref); + const bool has_stencil = _sg_is_depth_stencil_format(ds_image->cmn.pixel_format); + if ((pass->action.depth.load_action != SG_LOADACTION_LOAD) && + (pass->action.stencil.load_action != SG_LOADACTION_LOAD)) + { + // don't need to preserve image content for clear and dontcare + ds_image->vk.cur_access |= _SG_VK_ACCESS_DISCARD; + } + _sg_vk_access_t dst_access = _SG_VK_ACCESS_DEPTH_ATTACHMENT; + if (has_stencil) { + dst_access |= _SG_VK_ACCESS_STENCIL_ATTACHMENT; + } + _sg_vk_image_barrier(cmd_buf, ds_image, dst_access); + } + } + } +} + +_SOKOL_PRIVATE void _sg_vk_barrier_on_apply_bindings(VkCommandBuffer cmd_buf, const _sg_bindings_ptrs_t* bnd, bool is_compute_pass) { + SOKOL_ASSERT(bnd); + if (is_compute_pass) { + SOKOL_ASSERT(bnd->pip); + for (size_t i = 0; i < SG_MAX_VIEW_BINDSLOTS; i++) { + const _sg_view_t* view = bnd->views[i]; + if (0 == view) { + continue; + } else if (view->cmn.type == SG_VIEWTYPE_STORAGEBUFFER) { + const _sg_shader_t* shd = _sg_shader_ref_ptr(&bnd->pip->cmn.shader); + _sg_buffer_t* buf = _sg_buffer_ref_ptr(&view->cmn.buf.ref); + _sg_vk_access_t new_access = shd->cmn.views[i].sbuf_readonly + ? _SG_VK_ACCESS_STORAGEBUFFER_RO + : _SG_VK_ACCESS_STORAGEBUFFER_RW; + _sg_vk_buffer_barrier(cmd_buf, buf, new_access); + _sg_track_add(&_sg.vk.track.buffers, buf->slot.id); + } else if (view->cmn.type == SG_VIEWTYPE_STORAGEIMAGE) { + _sg_image_t* img = _sg_image_ref_ptr(&view->cmn.img.ref); + _sg_vk_image_barrier(cmd_buf, img, _SG_VK_ACCESS_STORAGEIMAGE); + _sg_track_add(&_sg.vk.track.images, img->slot.id); + } else if (view->cmn.type == SG_VIEWTYPE_TEXTURE) { + _sg_image_t* img = _sg_image_ref_ptr(&view->cmn.img.ref); + _sg_vk_image_barrier(cmd_buf, img, _SG_VK_ACCESS_TEXTURE); + _sg_track_add(&_sg.vk.track.images, img->slot.id); + } else { + SOKOL_UNREACHABLE; + } + } + } else { + // no transitions allowed in render passes, but check if resources are in + // correct access state + for (size_t i = 0; i < SG_MAX_VERTEXBUFFER_BINDSLOTS; i++) { + if (bnd->vbs[i]) { + SOKOL_ASSERT(0 != (bnd->vbs[i]->vk.cur_access & _SG_VK_ACCESS_VERTEXBUFFER)); + } + } + if (bnd->ib) { + SOKOL_ASSERT(0 != (bnd->ib->vk.cur_access & _SG_VK_ACCESS_INDEXBUFFER)); + } + for (size_t i = 0; i < SG_MAX_VIEW_BINDSLOTS; i++) { + const _sg_view_t* view = bnd->views[i]; + if (0 == view) { + continue; + } + else if (view->cmn.type == SG_VIEWTYPE_STORAGEBUFFER) { + const _sg_buffer_t* buf = _sg_buffer_ref_ptr(&view->cmn.buf.ref); + _SOKOL_UNUSED(buf); + SOKOL_ASSERT(0 != (buf->vk.cur_access & _SG_VK_ACCESS_STORAGEBUFFER_RO)); + } else if (view->cmn.type == SG_VIEWTYPE_TEXTURE) { + const _sg_image_t* img = _sg_image_ref_ptr(&view->cmn.img.ref); + _SOKOL_UNUSED(img); + SOKOL_ASSERT(0 != (img->vk.cur_access & _SG_VK_ACCESS_TEXTURE)); + } else { + SOKOL_UNREACHABLE; + } + } + } +} + +_SOKOL_PRIVATE void _sg_vk_barrier_on_end_pass(VkCommandBuffer cmd_buf, const _sg_attachments_ptrs_t* atts, bool is_compute_pass) { + SOKOL_ASSERT(cmd_buf); + if (is_compute_pass) { + // transition all tracked buffers into vertex+index+sbuf-ro access + const _sg_vk_access_t new_buf_access = _SG_VK_ACCESS_VERTEXBUFFER|_SG_VK_ACCESS_INDEXBUFFER|_SG_VK_ACCESS_STORAGEBUFFER_RO; + for (int i = 0; i < _sg.vk.track.buffers.cur_slot; i++) { + const uint32_t buf_id = _sg.vk.track.buffers.slots[i]; + _sg_buffer_t* buf = _sg_lookup_buffer(buf_id); + if (buf) { + _sg_vk_buffer_barrier(cmd_buf, buf, new_buf_access); + } + } + _sg_track_reset(&_sg.vk.track.buffers); + + // transition all tracked images into texture access + const _sg_vk_access_t new_img_access = _SG_VK_ACCESS_TEXTURE; + for (int i = 0; i < _sg.vk.track.images.cur_slot; i++) { + const uint32_t img_id = _sg.vk.track.images.slots[i]; + _sg_image_t* img = _sg_lookup_image(img_id); + if (img) { + _sg_vk_image_barrier(cmd_buf, img, new_img_access); + } + } + _sg_track_reset(&_sg.vk.track.images); + } else { + const bool is_swapchain_pass = atts->empty; + if (is_swapchain_pass) { + SOKOL_ASSERT(_sg.vk.swapchain.render_image); + VkImage present_image = _sg.vk.swapchain.resolve_image + ? (VkImage)_sg.vk.swapchain.resolve_image + : (VkImage)_sg.vk.swapchain.render_image; + _sg_vk_swapchain_endpass_barrier(cmd_buf, present_image, _SG_VK_ACCESS_COLOR_ATTACHMENT, true); + } else { + for (int i = 0; i < atts->num_color_views; i++) { + if (_sg.cur_pass.action.colors[i].store_action == SG_STOREACTION_STORE) { + SOKOL_ASSERT(atts->color_views[i]); + _sg_image_t* img = _sg_image_ref_ptr(&atts->color_views[i]->cmn.img.ref); + _sg_vk_image_barrier(cmd_buf, img, _SG_VK_ACCESS_TEXTURE); + } + if (atts->resolve_views[i]) { + _sg_image_t* img = _sg_image_ref_ptr(&atts->resolve_views[i]->cmn.img.ref); + _sg_vk_image_barrier(cmd_buf, img, _SG_VK_ACCESS_TEXTURE); + } + } + if (atts->ds_view) { + _sg_image_t* img = _sg_image_ref_ptr(&atts->ds_view->cmn.img.ref); + if (_sg.cur_pass.action.depth.store_action == SG_STOREACTION_STORE) { + _sg_vk_image_barrier(cmd_buf, img, _SG_VK_ACCESS_TEXTURE); + } + } + } + } +} + +_SOKOL_PRIVATE int _sg_vk_mem_find_memory_type_index(uint32_t type_filter, VkMemoryPropertyFlags props) { + SOKOL_ASSERT(_sg.vk.phys_dev); + _SG_STRUCT(VkPhysicalDeviceMemoryProperties, mem_props); + vkGetPhysicalDeviceMemoryProperties(_sg.vk.phys_dev, &mem_props); + for (uint32_t i = 0; i < mem_props.memoryTypeCount; i++) { + if ((type_filter & (1 << i)) && ((mem_props.memoryTypes[i].propertyFlags & props) == props)) { + return (int)i; + } + } + return -1; +} + +_SOKOL_PRIVATE VkDeviceMemory _sg_vk_mem_alloc_device_memory(_sg_vk_memtype_t mem_type, const VkMemoryRequirements* mem_reqs) { + SOKOL_ASSERT(_sg.vk.dev); + SOKOL_ASSERT(mem_reqs); + + VkMemoryPropertyFlags mem_prop_flags = 0; + VkMemoryAllocateFlags mem_alloc_flags = 0; + switch (mem_type) { + case _SG_VK_MEMTYPE_GENERIC_BUFFER: + mem_prop_flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + break; + case _SG_VK_MEMTYPE_STORAGE_BUFFER: + mem_prop_flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + mem_alloc_flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT; + break; + case _SG_VK_MEMTYPE_IMAGE: + mem_prop_flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + break; + case _SG_VK_MEMTYPE_STAGING_COPY: + mem_prop_flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + break; + case _SG_VK_MEMTYPE_STAGING_STREAM: + mem_prop_flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + break; + case _SG_VK_MEMTYPE_UNIFORMS: + mem_prop_flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + mem_alloc_flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT; + break; + case _SG_VK_MEMTYPE_DESCRIPTORS: + mem_prop_flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + mem_alloc_flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT; + break; + default: + SOKOL_UNREACHABLE; + break; + } + + int mem_type_index = _sg_vk_mem_find_memory_type_index(mem_reqs->memoryTypeBits, mem_prop_flags); + if (-1 == mem_type_index) { + _SG_ERROR(VULKAN_ALLOC_DEVICE_MEMORY_NO_SUITABLE_MEMORY_TYPE); + return 0; + } + _SG_STRUCT(VkMemoryAllocateFlagsInfo, flags_info); + flags_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO; + flags_info.flags = mem_alloc_flags; + _SG_STRUCT(VkMemoryAllocateInfo, alloc_info); + alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + alloc_info.pNext = &flags_info; + alloc_info.allocationSize = mem_reqs->size; + alloc_info.memoryTypeIndex = (uint32_t) mem_type_index; + VkDeviceMemory vk_dev_mem = 0; + VkResult res = vkAllocateMemory(_sg.vk.dev, &alloc_info, 0, &vk_dev_mem); + _sg_stats_add(vk.num_allocate_memory, 1); + _sg_stats_add(vk.size_allocate_memory, mem_reqs->size); + if (res != VK_SUCCESS) { + _SG_ERROR(VULKAN_ALLOCATE_MEMORY_FAILED); + return 0; + } + SOKOL_ASSERT(vk_dev_mem); + return vk_dev_mem; +} + +_SOKOL_PRIVATE void _sg_vk_mem_free_device_memory(VkDeviceMemory vk_dev_mem) { + SOKOL_ASSERT(_sg.vk.dev); + SOKOL_ASSERT(vk_dev_mem); + vkFreeMemory(_sg.vk.dev, vk_dev_mem, 0); + _sg_stats_add(vk.num_free_memory, 1); +} + +_SOKOL_PRIVATE bool _sg_vk_mem_alloc_buffer_device_memory(_sg_buffer_t* buf) { + SOKOL_ASSERT(_sg.vk.dev); + SOKOL_ASSERT(buf); + SOKOL_ASSERT(buf->vk.buf); + SOKOL_ASSERT(0 == buf->vk.mem); + _SG_STRUCT(VkMemoryRequirements, mem_reqs); + vkGetBufferMemoryRequirements(_sg.vk.dev, buf->vk.buf, &mem_reqs); + _sg_vk_memtype_t mem_type = buf->cmn.usage.storage_buffer + ? _SG_VK_MEMTYPE_STORAGE_BUFFER + : _SG_VK_MEMTYPE_GENERIC_BUFFER; + buf->vk.mem = _sg_vk_mem_alloc_device_memory(mem_type, &mem_reqs); + if (0 == buf->vk.mem) { + _SG_ERROR(VULKAN_ALLOC_BUFFER_DEVICE_MEMORY_FAILED); + return false; + } + return true; +} + +_SOKOL_PRIVATE bool _sg_vk_mem_alloc_image_device_memory(_sg_image_t* img) { + SOKOL_ASSERT(_sg.vk.dev); + SOKOL_ASSERT(img); + SOKOL_ASSERT(img->vk.img); + SOKOL_ASSERT(0 == img->vk.mem); + _SG_STRUCT(VkMemoryRequirements, mem_reqs); + vkGetImageMemoryRequirements(_sg.vk.dev, img->vk.img, &mem_reqs); + img->vk.mem = _sg_vk_mem_alloc_device_memory(_SG_VK_MEMTYPE_IMAGE, &mem_reqs); + if (0 == img->vk.mem) { + _SG_ERROR(VULKAN_ALLOC_IMAGE_DEVICE_MEMORY_FAILED); + return false; + } + return true; +} + +_SOKOL_PRIVATE void _sg_vk_create_delete_queues(void) { + const uint32_t num_items = (uint32_t) + (2 * _sg.desc.buffer_pool_size + + 2 * _sg.desc.image_pool_size + + 1 * _sg.desc.sampler_pool_size + + 5 * _sg.desc.shader_pool_size + + 2 * _sg.desc.pipeline_pool_size + + 1 * _sg.desc.view_pool_size + + 256); + for (size_t i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { + _sg_vk_delete_queue_t* queue = &_sg.vk.frame.slot[i].delete_queue; + SOKOL_ASSERT(0 == queue->items); + SOKOL_ASSERT(0 == queue->index); + queue->num = num_items; + const size_t pool_size = num_items * sizeof(_sg_vk_delete_queue_item_t); + queue->items = (_sg_vk_delete_queue_item_t*)_sg_malloc(pool_size); + } +} + +_SOKOL_PRIVATE void _sg_vk_delete_queue_collect_items(_sg_vk_delete_queue_t* queue) { + SOKOL_ASSERT(queue && queue->items); + for (uint32_t i = 0; i < queue->index; i++) { + _sg_vk_delete_queue_item_t* item = &queue->items[i]; + SOKOL_ASSERT(item->destructor && item->obj); + item->destructor(item->obj); + item->destructor = 0; + item->obj = 0; + } + _sg_stats_add(vk.num_delete_queue_collected, queue->index); + queue->index = 0; +} + +_SOKOL_PRIVATE void _sg_vk_destroy_delete_queues(void) { + for (size_t i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { + _sg_vk_delete_queue_t* queue = &_sg.vk.frame.slot[i].delete_queue; + SOKOL_ASSERT(queue->items); + _sg_vk_delete_queue_collect_items(queue); + _sg_free(queue->items); + SOKOL_ASSERT(queue->index == 0); + queue->items = 0; + queue->num = 0; + } +} + +_SOKOL_PRIVATE _sg_vk_delete_queue_t* _sg_vk_cur_delete_queue(void) { + return &_sg.vk.frame.slot[_sg.vk.frame_slot].delete_queue; +} + +_SOKOL_PRIVATE void _sg_vk_delete_queue_collect(void) { + _sg_vk_delete_queue_t* queue = _sg_vk_cur_delete_queue(); + _sg_vk_delete_queue_collect_items(queue); +} + +_SOKOL_PRIVATE void _sg_vk_delete_queue_add(_sg_vk_delete_queue_destructor_t destructor, void* obj) { + SOKOL_ASSERT(destructor && obj); + _sg_vk_delete_queue_t* queue = _sg_vk_cur_delete_queue(); + SOKOL_ASSERT(queue->items); + if (queue->index >= queue->num) { + _SG_PANIC(VULKAN_DELETE_QUEUE_EXHAUSTED); + } + queue->items[queue->index].destructor = destructor; + queue->items[queue->index].obj = obj; + queue->index += 1; + _sg_stats_add(vk.num_delete_queue_added, 1); +} + +// double-buffer system for any non-blocking CPU => GPU data +_SOKOL_PRIVATE void _sg_vk_shared_buffer_init(_sg_vk_shared_buffer_t* shbuf, uint32_t size, uint32_t align, _sg_vk_memtype_t mem_type, const char* label) { + SOKOL_ASSERT(_sg.vk.dev); + SOKOL_ASSERT(shbuf && (size > 0) && (align > 0)); + SOKOL_ASSERT(0 == shbuf->size); + SOKOL_ASSERT(0 == shbuf->offset); + SOKOL_ASSERT(0 == shbuf->cur_buf); + SOKOL_ASSERT(false == shbuf->overflown); + VkResult res; + VkBufferUsageFlags vk_usage = 0; + bool want_device_address = false; + switch (mem_type) { + case _SG_VK_MEMTYPE_STAGING_STREAM: + vk_usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + break; + case _SG_VK_MEMTYPE_UNIFORMS: + vk_usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + vk_usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; + want_device_address = true; + break; + case _SG_VK_MEMTYPE_DESCRIPTORS: + vk_usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; + vk_usage |= VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT; + vk_usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; + want_device_address = true; + break; + default: + SOKOL_UNREACHABLE; + break; + } + + shbuf->size = _sg_roundup_u32(size, align); + shbuf->align = align; + for (size_t i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { + SOKOL_ASSERT(0 == shbuf->slots[i].buf); + SOKOL_ASSERT(0 == shbuf->slots[i].mem); + SOKOL_ASSERT(0 == shbuf->slots[i].mem_ptr); + _SG_STRUCT(VkBufferCreateInfo, buf_create_info); + buf_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buf_create_info.size = shbuf->size; + buf_create_info.usage = vk_usage; + buf_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + res = vkCreateBuffer(_sg.vk.dev, &buf_create_info, 0, &shbuf->slots[i].buf); + if (res != VK_SUCCESS) { + _SG_PANIC(VULKAN_CREATE_SHARED_BUFFER_FAILED); + } + SOKOL_ASSERT(shbuf->slots[i].buf); + _sg_vk_set_object_label(VK_OBJECT_TYPE_BUFFER, (uint64_t)shbuf->slots[i].buf, label); + + _SG_STRUCT(VkMemoryRequirements, mem_reqs); + vkGetBufferMemoryRequirements(_sg.vk.dev, shbuf->slots[i].buf, &mem_reqs); + shbuf->slots[i].mem = _sg_vk_mem_alloc_device_memory(mem_type, &mem_reqs); + if (0 == shbuf->slots[i].mem) { + _SG_PANIC(VULKAN_ALLOCATE_SHARED_BUFFER_MEMORY_FAILED); + } + res = vkBindBufferMemory(_sg.vk.dev, shbuf->slots[i].buf, shbuf->slots[i].mem, 0); + if (res != VK_SUCCESS) { + _SG_PANIC(VULKAN_BIND_SHARED_BUFFER_MEMORY_FAILED); + } + if (want_device_address) { + _SG_STRUCT(VkBufferDeviceAddressInfo, addr_info); + addr_info.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; + addr_info.buffer = shbuf->slots[i].buf; + shbuf->slots[i].dev_addr = vkGetBufferDeviceAddress(_sg.vk.dev, &addr_info); + SOKOL_ASSERT(shbuf->slots[i].dev_addr); + } + res = vkMapMemory(_sg.vk.dev, shbuf->slots[i].mem, 0, VK_WHOLE_SIZE, 0, &shbuf->slots[i].mem_ptr); + if (res != VK_SUCCESS) { + _SG_PANIC(VULKAN_MAP_SHARED_BUFFER_MEMORY_FAILED); + } + SOKOL_ASSERT(shbuf->slots[i].mem_ptr); + } +} + +_SOKOL_PRIVATE void _sg_vk_shared_buffer_discard(_sg_vk_shared_buffer_t* shbuf) { + SOKOL_ASSERT(_sg.vk.dev); + SOKOL_ASSERT(shbuf); + for (size_t i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { + SOKOL_ASSERT(shbuf->slots[i].buf); + SOKOL_ASSERT(shbuf->slots[i].mem); + SOKOL_ASSERT(shbuf->slots[i].mem_ptr); + vkUnmapMemory(_sg.vk.dev, shbuf->slots[i].mem); + shbuf->slots[i].mem_ptr = 0; + _sg_vk_mem_free_device_memory(shbuf->slots[i].mem); + shbuf->slots[i].mem = 0; + vkDestroyBuffer(_sg.vk.dev, shbuf->slots[i].buf, 0); + shbuf->slots[i].buf = 0; + shbuf->slots[i].dev_addr = 0; + } + shbuf->size = 0; + shbuf->offset = 0; + shbuf->cur_buf = 0; + shbuf->cur_dev_addr = 0; + shbuf->overflown = false; +} + +_SOKOL_PRIVATE void _sg_vk_shared_buffer_after_acquire(_sg_vk_shared_buffer_t* shbuf) { + SOKOL_ASSERT(_sg.vk.dev); + SOKOL_ASSERT(0 == shbuf->cur_buf); + SOKOL_ASSERT(0 == shbuf->cur_mem_ptr); + SOKOL_ASSERT(0 == shbuf->cur_dev_addr); + const uint32_t frame_slot = _sg.vk.frame_slot; + shbuf->offset = 0; + shbuf->cur_buf = shbuf->slots[frame_slot].buf; + shbuf->cur_mem_ptr = shbuf->slots[frame_slot].mem_ptr; + shbuf->cur_dev_addr = shbuf->slots[frame_slot].dev_addr; // NOTE: may be 0 + shbuf->overflown = false; + SOKOL_ASSERT(shbuf->cur_buf); + SOKOL_ASSERT(shbuf->cur_mem_ptr); +} + +_SOKOL_PRIVATE void _sg_vk_shared_buffer_before_submit(_sg_vk_shared_buffer_t* shbuf) { + SOKOL_ASSERT(shbuf->cur_buf); + SOKOL_ASSERT(shbuf->cur_mem_ptr); + // NOTE: if the buffer wouldn't be cache-coherent, this would be the place to do a flush + shbuf->cur_buf = 0; + shbuf->cur_mem_ptr = 0; + shbuf->cur_dev_addr = 0; +} + +_SOKOL_PRIVATE VkDeviceSize _sg_vk_shared_buffer_alloc(_sg_vk_shared_buffer_t* shbuf, uint32_t num_bytes) { + SOKOL_ASSERT(shbuf && (num_bytes > 0)); + if (shbuf->overflown) { + return _SG_VK_SHARED_BUFFER_OVERFLOW_RESULT; + } + if ((shbuf->offset + num_bytes) > shbuf->size) { + shbuf->overflown = true; + return _SG_VK_SHARED_BUFFER_OVERFLOW_RESULT; + } + SOKOL_ASSERT((shbuf->offset & (shbuf->align - 1)) == 0); + VkDeviceSize offset = shbuf->offset; + shbuf->offset = _sg_roundup_u32(shbuf->offset + num_bytes, shbuf->align); + return offset; +} + +_SOKOL_PRIVATE uint8_t* _sg_vk_shared_buffer_ptr(_sg_vk_shared_buffer_t* shbuf, VkDeviceSize offset) { + SOKOL_ASSERT(shbuf && shbuf->cur_mem_ptr); + SOKOL_ASSERT(!shbuf->overflown); + SOKOL_ASSERT(offset < shbuf->size); + return ((uint8_t*)shbuf->cur_mem_ptr) + offset; +} + +_SOKOL_PRIVATE VkDeviceSize _sg_vk_shared_buffer_memcpy(_sg_vk_shared_buffer_t* shbuf, const void* src_ptr, uint32_t num_bytes) { + SOKOL_ASSERT(shbuf && src_ptr && (num_bytes > 0)); + const VkDeviceSize offset = _sg_vk_shared_buffer_alloc(shbuf, num_bytes); + if (offset != _SG_VK_SHARED_BUFFER_OVERFLOW_RESULT) { + memcpy(_sg_vk_shared_buffer_ptr(shbuf, offset), src_ptr, num_bytes); + } + return offset; +} + +// staging system for blocking immutable and dynamic updates, can deal arbitrarily sized data +_SOKOL_PRIVATE void _sg_vk_staging_copy_init(void) { + SOKOL_ASSERT(_sg.vk.dev); + VkResult res; + + SOKOL_ASSERT(0 == _sg.vk.stage.copy.cmd_pool); + SOKOL_ASSERT(0 == _sg.vk.stage.copy.cmd_buf); + SOKOL_ASSERT(0 == _sg.vk.stage.copy.size); + SOKOL_ASSERT(0 == _sg.vk.stage.copy.buf); + SOKOL_ASSERT(0 == _sg.vk.stage.copy.mem); + SOKOL_ASSERT(_sg.desc.vulkan.copy_staging_buffer_size > 0); + + _SG_STRUCT(VkCommandPoolCreateInfo, pool_create_info); + pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT | VK_COMMAND_POOL_CREATE_TRANSIENT_BIT; + pool_create_info.queueFamilyIndex = _sg.vk.queue_family_index; + res = vkCreateCommandPool(_sg.vk.dev, &pool_create_info, 0, &_sg.vk.stage.copy.cmd_pool); + SOKOL_ASSERT((res == VK_SUCCESS && _sg.vk.stage.copy.cmd_pool)); + _sg_vk_set_object_label(VK_OBJECT_TYPE_COMMAND_POOL, (uint64_t)_sg.vk.stage.copy.cmd_pool, "copy-staging cmd pool"); + + _SG_STRUCT(VkCommandBufferAllocateInfo, cmdbuf_alloc_info); + cmdbuf_alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + cmdbuf_alloc_info.commandPool = _sg.vk.stage.copy.cmd_pool; + cmdbuf_alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + cmdbuf_alloc_info.commandBufferCount = 1; + res = vkAllocateCommandBuffers(_sg.vk.dev, &cmdbuf_alloc_info, &_sg.vk.stage.copy.cmd_buf); + SOKOL_ASSERT((res == VK_SUCCESS) && _sg.vk.stage.copy.cmd_buf); + _sg_vk_set_object_label(VK_OBJECT_TYPE_COMMAND_BUFFER, (uint64_t)_sg.vk.stage.copy.cmd_buf, "copy-staging cmd buffer"); + + _sg.vk.stage.copy.size = (uint32_t) _sg.desc.vulkan.copy_staging_buffer_size; + _SG_STRUCT(VkBufferCreateInfo, buf_create_info); + buf_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buf_create_info.size = _sg.vk.stage.copy.size; + buf_create_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + buf_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + res = vkCreateBuffer(_sg.vk.dev, &buf_create_info, 0, &_sg.vk.stage.copy.buf); + if (res != VK_SUCCESS) { + _SG_PANIC(VULKAN_STAGING_CREATE_BUFFER_FAILED); + } + SOKOL_ASSERT(_sg.vk.stage.copy.buf); + _sg_vk_set_object_label(VK_OBJECT_TYPE_BUFFER, (uint64_t)_sg.vk.stage.copy.buf, "copy-staging staging buffer"); + + _SG_STRUCT(VkMemoryRequirements, mem_reqs); + vkGetBufferMemoryRequirements(_sg.vk.dev, _sg.vk.stage.copy.buf, &mem_reqs); + _sg.vk.stage.copy.mem = _sg_vk_mem_alloc_device_memory(_SG_VK_MEMTYPE_STAGING_COPY, &mem_reqs); + if (0 == _sg.vk.stage.copy.mem) { + _SG_PANIC(VULKAN_STAGING_ALLOCATE_MEMORY_FAILED); + } + res = vkBindBufferMemory(_sg.vk.dev, _sg.vk.stage.copy.buf, _sg.vk.stage.copy.mem, 0); + if (res != VK_SUCCESS) { + _SG_PANIC(VULKAN_STAGING_BIND_BUFFER_MEMORY_FAILED); + } +} + +_SOKOL_PRIVATE void _sg_vk_staging_copy_discard(void) { + SOKOL_ASSERT(_sg.vk.dev); + SOKOL_ASSERT(_sg.vk.stage.copy.cmd_pool); + SOKOL_ASSERT(_sg.vk.stage.copy.cmd_buf); + SOKOL_ASSERT(_sg.vk.stage.copy.size); + SOKOL_ASSERT(_sg.vk.stage.copy.buf); + SOKOL_ASSERT(_sg.vk.stage.copy.mem); + + _sg_vk_mem_free_device_memory(_sg.vk.stage.copy.mem); + _sg.vk.stage.copy.mem = 0; + vkDestroyBuffer(_sg.vk.dev, _sg.vk.stage.copy.buf, 0); + _sg.vk.stage.copy.buf = 0; + vkDestroyCommandPool(_sg.vk.dev, _sg.vk.stage.copy.cmd_pool, 0); + _sg.vk.stage.copy.cmd_pool = 0; + _sg.vk.stage.copy.cmd_buf = 0; + _sg.vk.stage.copy.size = 0; +} + +_SOKOL_PRIVATE VkCommandBuffer _sg_vk_staging_copy_begin(void) { + VkCommandBuffer cmd_buf = _sg.vk.stage.copy.cmd_buf; + _SG_STRUCT(VkCommandBufferBeginInfo, cmdbuf_begin_info); + cmdbuf_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + cmdbuf_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + VkResult res = vkBeginCommandBuffer(cmd_buf, &cmdbuf_begin_info); + SOKOL_ASSERT(res == VK_SUCCESS); _SOKOL_UNUSED(res); + return cmd_buf; +} + +_SOKOL_PRIVATE void _sg_vk_staging_copy_end(VkCommandBuffer cmd_buf, VkQueue queue) { + SOKOL_ASSERT(cmd_buf && queue); + VkResult res; + _SOKOL_UNUSED(res); + vkEndCommandBuffer(cmd_buf); + _SG_STRUCT(VkSubmitInfo, submit_info); + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &cmd_buf; + res = vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE); + SOKOL_ASSERT(res == VK_SUCCESS); + res = vkQueueWaitIdle(queue); + SOKOL_ASSERT(res == VK_SUCCESS); + res = vkResetCommandBuffer(cmd_buf, 0); + SOKOL_ASSERT(res == VK_SUCCESS); +} + +_SOKOL_PRIVATE void _sg_vk_staging_map_memcpy_unmap(VkDeviceMemory mem, const void* ptr, uint32_t num_bytes) { + SOKOL_ASSERT(_sg.vk.dev); + SOKOL_ASSERT(mem); + SOKOL_ASSERT(ptr); + SOKOL_ASSERT(num_bytes > 0); + void* dst_ptr = 0; + VkResult res = vkMapMemory(_sg.vk.dev, mem, 0, VK_WHOLE_SIZE, 0, &dst_ptr); + SOKOL_ASSERT((res == VK_SUCCESS) && dst_ptr); _SOKOL_UNUSED(res); + memcpy(dst_ptr, ptr, num_bytes); + vkUnmapMemory(_sg.vk.dev, mem); +} + +_SOKOL_PRIVATE void _sg_vk_staging_copy_buffer_data(_sg_buffer_t* buf, const sg_range* src_data, size_t dst_offset, bool initial_wait) { + SOKOL_ASSERT(_sg.vk.dev); + SOKOL_ASSERT(_sg.vk.queue); + SOKOL_ASSERT(_sg.vk.stage.copy.mem); + SOKOL_ASSERT(_sg.vk.stage.copy.buf); + SOKOL_ASSERT(buf && buf->vk.buf); + SOKOL_ASSERT(src_data && src_data->ptr && (src_data->size > 0)); + SOKOL_ASSERT((dst_offset + src_data->size) <= (size_t)buf->cmn.size); + + // an inital wait is only needed for updating existing resources but not when populating a new resource + if (initial_wait) { + VkResult res = vkQueueWaitIdle(_sg.vk.queue); + SOKOL_ASSERT(res == VK_SUCCESS); _SOKOL_UNUSED(res); + } + + VkDeviceMemory dst_mem = _sg.vk.stage.copy.mem; + VkBuffer src_buf = _sg.vk.stage.copy.buf; + VkBuffer dst_buf = buf->vk.buf; + const uint8_t* src_ptr = (const uint8_t*)src_data->ptr; + uint32_t dst_size = _sg.vk.stage.copy.size; + uint32_t bytes_remaining = (uint32_t)src_data->size; + _SG_STRUCT(VkBufferCopy, region); + region.dstOffset = dst_offset; + while (bytes_remaining > 0) { + uint64_t bytes_to_copy = bytes_remaining; + if (bytes_remaining > dst_size) { + bytes_to_copy = dst_size; + bytes_remaining -= dst_size; + } else { + bytes_to_copy = bytes_remaining; + bytes_remaining = 0; + } + region.size = bytes_to_copy; + _sg_vk_staging_map_memcpy_unmap(dst_mem, src_ptr, bytes_to_copy); + VkCommandBuffer cmd_buf = _sg_vk_staging_copy_begin(); + vkCmdCopyBuffer(cmd_buf, src_buf, dst_buf, 1, ®ion); + _sg_stats_add(vk.num_cmd_copy_buffer, 1); + _sg_vk_staging_copy_end(cmd_buf, _sg.vk.queue); + src_ptr += bytes_to_copy; + region.dstOffset += bytes_to_copy; + } + buf->vk.cur_access = _SG_VK_ACCESS_VERTEXBUFFER | _SG_VK_ACCESS_INDEXBUFFER | _SG_VK_ACCESS_STORAGEBUFFER_RO; +} + +_SOKOL_PRIVATE void _sg_vk_init_vk_image_staging_structs(const _sg_image_t* img, VkBuffer vk_buf, VkBufferImageCopy2* region, VkCopyBufferToImageInfo2* copy_info) { + SOKOL_ASSERT(img && region && copy_info); + + region->sType = VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2; + if (_sg_is_depth_or_depth_stencil_format(img->cmn.pixel_format)) { + region->imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + if (_sg_is_depth_stencil_format(img->cmn.pixel_format)) { + region->imageSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; + } + } else { + region->imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + } + region->imageSubresource.layerCount = 1; + region->imageExtent.depth = 1; + + copy_info->sType = VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2; + copy_info->srcBuffer = vk_buf; + copy_info->dstImage = img->vk.img; + copy_info->dstImageLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + copy_info->regionCount = 1; + copy_info->pRegions = region; +} + +_SOKOL_PRIVATE void _sg_vk_staging_copy_image_data(_sg_image_t* img, const sg_image_data* src_data, bool initial_wait) { + SOKOL_ASSERT(_sg.vk.dev); + SOKOL_ASSERT(_sg.vk.queue); + SOKOL_ASSERT(_sg.vk.stage.copy.mem); + SOKOL_ASSERT(_sg.vk.stage.copy.buf); + SOKOL_ASSERT(img && img->vk.img); + const uint32_t block_dim = (uint32_t)_sg_block_dim(img->cmn.pixel_format); + + // an inital wait is only needed for updating existing resources but not when populating a new resource + if (initial_wait) { + VkResult res = vkQueueWaitIdle(_sg.vk.queue); + SOKOL_ASSERT(res == VK_SUCCESS); _SOKOL_UNUSED(res); + } + + VkDeviceMemory mem = _sg.vk.stage.copy.mem; + _SG_STRUCT(VkBufferImageCopy2, region); + _SG_STRUCT(VkCopyBufferToImageInfo2, copy_info); + _sg_vk_init_vk_image_staging_structs(img, _sg.vk.stage.copy.buf, ®ion, ©_info); + for (int mip_index = 0; mip_index < img->cmn.num_mipmaps; mip_index++) { + const uint8_t* src_ptr = (uint8_t*)src_data->mip_levels[mip_index].ptr; + int mip_width = _sg_miplevel_dim(img->cmn.width, mip_index); + int mip_height = _sg_miplevel_dim(img->cmn.height, mip_index); + int mip_slices = (img->cmn.type == SG_IMAGETYPE_3D) ? _sg_miplevel_dim(img->cmn.num_slices, mip_index) : img->cmn.num_slices; + const uint32_t row_pitch = (uint32_t) _sg_row_pitch(img->cmn.pixel_format, mip_width, 1); + const uint32_t num_rows = (uint32_t) _sg_num_rows(img->cmn.pixel_format, mip_height); + region.imageSubresource.mipLevel = (uint32_t)mip_index; + region.imageExtent.width = (uint32_t)mip_width; + + const uint32_t max_rows = _sg.vk.stage.copy.size / row_pitch; + for (int slice_index = 0; slice_index < mip_slices; slice_index++) { + if (img->cmn.type == SG_IMAGETYPE_3D) { + region.imageOffset.z = slice_index; + } else { + region.imageSubresource.baseArrayLayer = (uint32_t)slice_index; + } + uint32_t rows_remaining = num_rows; + uint32_t cur_row = 0; + while (rows_remaining > 0) { + uint32_t rows_to_copy = rows_remaining; + if (rows_remaining > max_rows) { + rows_to_copy = max_rows; + rows_remaining -= max_rows; + } else { + rows_to_copy = rows_remaining; + rows_remaining = 0; + } + const uint32_t bytes_to_copy = rows_to_copy * row_pitch; + SOKOL_ASSERT(bytes_to_copy <= _sg.vk.stage.copy.size); + _sg_vk_staging_map_memcpy_unmap(mem, src_ptr, bytes_to_copy); + src_ptr += bytes_to_copy; + VkCommandBuffer cmd_buf = _sg_vk_staging_copy_begin(); + _sg_vk_image_barrier(cmd_buf, img, _SG_VK_ACCESS_STAGING); + region.imageOffset.y = (int32_t)(cur_row * block_dim); + region.imageExtent.height = _sg_min((uint32_t)mip_height, rows_to_copy * block_dim); + vkCmdCopyBufferToImage2(cmd_buf, ©_info); + _sg_stats_add(vk.num_cmd_copy_buffer_to_image, 1); + _sg_vk_image_barrier(cmd_buf, img, _SG_VK_ACCESS_TEXTURE); + + _sg_vk_staging_copy_end(cmd_buf, _sg.vk.queue); + cur_row += rows_to_copy; + } + } + } +} + +// staging system for non-blocking streaming updates with a max per-frame data limit +_SOKOL_PRIVATE void _sg_vk_staging_stream_init(void) { + SOKOL_ASSERT(_sg.desc.vulkan.stream_staging_buffer_size > 0); + _sg_vk_shared_buffer_init(&_sg.vk.stage.stream, + (uint32_t)_sg.desc.vulkan.stream_staging_buffer_size, + 16, // NOTE: arbitrary alignment (FIXME?) + _SG_VK_MEMTYPE_STAGING_STREAM, + "shared-stream-buffer"); +} + +_SOKOL_PRIVATE void _sg_vk_staging_stream_discard(void) { + _sg_vk_shared_buffer_discard(&_sg.vk.stage.stream); +} + +_SOKOL_PRIVATE void _sg_vk_staging_stream_after_acquire(void) { + _sg_vk_shared_buffer_after_acquire(&_sg.vk.stage.stream); +} + +_SOKOL_PRIVATE void _sg_vk_staging_stream_before_submit(void) { + _sg_vk_shared_buffer_before_submit(&_sg.vk.stage.stream); +} + +_SOKOL_PRIVATE void _sg_vk_staging_stream_buffer_data(_sg_buffer_t* buf, const sg_range* src_data, size_t dst_offset) { + SOKOL_ASSERT(_sg.vk.dev); + SOKOL_ASSERT(_sg.vk.frame.stream_cmd_buf); + SOKOL_ASSERT(_sg.vk.stage.stream.cur_buf); + SOKOL_ASSERT(buf && buf->vk.buf); + SOKOL_ASSERT(src_data && src_data->ptr && (src_data->size > 0)); + SOKOL_ASSERT((src_data->size + dst_offset) <= (size_t)buf->cmn.size); + + const uint32_t src_offset = _sg_vk_shared_buffer_memcpy(&_sg.vk.stage.stream, src_data->ptr, src_data->size); + if (src_offset == _SG_VK_SHARED_BUFFER_OVERFLOW_RESULT) { + _SG_ERROR(VULKAN_STAGING_STREAM_BUFFER_OVERFLOW); + return; + } + VkCommandBuffer cmd_buf = _sg.vk.frame.stream_cmd_buf; + VkBuffer vk_src_buf = _sg.vk.stage.stream.cur_buf; + VkBuffer vk_dst_buf = buf->vk.buf; + _SG_STRUCT(VkBufferCopy, region); + region.srcOffset = src_offset; + region.dstOffset = dst_offset; + region.size = src_data->size; + _sg_vk_buffer_barrier(cmd_buf, buf, _SG_VK_ACCESS_STAGING); + vkCmdCopyBuffer(cmd_buf, vk_src_buf, vk_dst_buf, 1, ®ion); + _sg_stats_add(vk.num_cmd_copy_buffer, 1); + // FIXME: not great to issue a barrier right here, + // rethink buffer barrier strategy? => a single memory barrier + // at the end of the stream command buffer should be sufficient? + _sg_vk_buffer_barrier(cmd_buf, buf, _SG_VK_ACCESS_VERTEXBUFFER|_SG_VK_ACCESS_INDEXBUFFER|_SG_VK_ACCESS_STORAGEBUFFER_RO); +} + +_SOKOL_PRIVATE void _sg_vk_staging_stream_image_data(_sg_image_t* img, const sg_image_data* src_data) { + SOKOL_ASSERT(_sg.vk.dev); + SOKOL_ASSERT(_sg.vk.frame.stream_cmd_buf); + SOKOL_ASSERT(img && img->vk.img); + SOKOL_ASSERT(src_data); + VkCommandBuffer cmd_buf = _sg.vk.frame.stream_cmd_buf; + _sg_vk_image_barrier(cmd_buf, img, _SG_VK_ACCESS_STAGING); + _SG_STRUCT(VkBufferImageCopy2, region); + _SG_STRUCT(VkCopyBufferToImageInfo2, copy_info); + _sg_vk_init_vk_image_staging_structs(img, _sg.vk.stage.stream.cur_buf, ®ion, ©_info); + for (int mip_index = 0; mip_index < img->cmn.num_mipmaps; mip_index++) { + const sg_range* src_mip = &src_data->mip_levels[mip_index]; + SOKOL_ASSERT(src_mip->ptr); + SOKOL_ASSERT(src_mip->size > 0); + const uint32_t src_offset = _sg_vk_shared_buffer_memcpy(&_sg.vk.stage.stream, src_mip->ptr, src_mip->size); + if (src_offset == _SG_VK_SHARED_BUFFER_OVERFLOW_RESULT) { + _SG_ERROR(VULKAN_STAGING_STREAM_BUFFER_OVERFLOW); + _sg_vk_image_barrier(cmd_buf, img, _SG_VK_ACCESS_TEXTURE); + return; + } + region.bufferOffset = src_offset; + int mip_width = _sg_miplevel_dim(img->cmn.width, mip_index); + int mip_height = _sg_miplevel_dim(img->cmn.height, mip_index); + int mip_slices = (img->cmn.type == SG_IMAGETYPE_3D) ? _sg_miplevel_dim(img->cmn.num_slices, mip_index) : img->cmn.num_slices; + region.imageExtent.width = (uint32_t)mip_width; + region.imageExtent.height = (uint32_t)mip_height; + region.imageSubresource.mipLevel = (uint32_t)mip_index; + if (img->cmn.type == SG_IMAGETYPE_3D) { + region.imageExtent.depth = (uint32_t)mip_slices; + region.imageSubresource.layerCount = 1; + } else { + region.imageExtent.depth = 1; + region.imageSubresource.layerCount = (uint32_t)mip_slices; + } + vkCmdCopyBufferToImage2(cmd_buf, ©_info); + _sg_stats_add(vk.num_cmd_copy_buffer_to_image, 1); + } + _sg_vk_image_barrier(cmd_buf, img, _SG_VK_ACCESS_TEXTURE); +} + +// uniform data system +_SOKOL_PRIVATE void _sg_vk_uniform_init(void) { + SOKOL_ASSERT(_sg.desc.uniform_buffer_size > 0); + _sg_vk_shared_buffer_init(&_sg.vk.uniform, + (uint32_t)_sg.desc.uniform_buffer_size, + _sg.vk.dev_props.properties.limits.minUniformBufferOffsetAlignment, + _SG_VK_MEMTYPE_UNIFORMS, + "shared-uniform-buffer"); + for (size_t i = 0; i < SG_MAX_UNIFORMBLOCK_BINDSLOTS; i++) { + _sg_vk_uniform_bindinfo_t* ubi = &_sg.vk.uniform_bindinfos[i]; + ubi->addr_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_ADDRESS_INFO_EXT; + ubi->get_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_GET_INFO_EXT; + ubi->get_info.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + ubi->get_info.data.pUniformBuffer = &ubi->addr_info; + } +} + +_SOKOL_PRIVATE void _sg_vk_uniform_discard(void) { + _sg_vk_shared_buffer_discard(&_sg.vk.uniform); +} + +// called from _sg_vk_acquire_frame_command_buffer() +_SOKOL_PRIVATE void _sg_vk_uniform_after_acquire(void) { + _sg_vk_shared_buffer_after_acquire(&_sg.vk.uniform); + // reset uniform tracking data + for (size_t i = 0; i < SG_MAX_UNIFORMBLOCK_BINDSLOTS; i++) { + _sg_vk_uniform_bindinfo_t* ubi = &_sg.vk.uniform_bindinfos[i]; + ubi->addr_info.address = 0; + ubi->addr_info.range = 0; + } +} + +// called from _sg_vk_submit_frame_command_buffer() +_SOKOL_PRIVATE void _sg_vk_uniform_before_submit(void) { + _sg_vk_shared_buffer_before_submit(&_sg.vk.uniform); +} + +// called form _sg_vk_apply_uniforms, returns offset of data snippet into uniform buffer +_SOKOL_PRIVATE uint32_t _sg_vk_uniform_copy(const sg_range* data) { + SOKOL_ASSERT(data && data->ptr && (data->size > 0)); + return _sg_vk_shared_buffer_memcpy(&_sg.vk.uniform, data->ptr, data->size); +} + +// resource binding system +_SOKOL_PRIVATE void _sg_vk_bind_init(void) { + SOKOL_ASSERT(_sg.desc.vulkan.descriptor_buffer_size > 0); + _sg_vk_shared_buffer_init(&_sg.vk.bind, + (uint32_t)_sg.desc.vulkan.descriptor_buffer_size, + _sg.vk.descriptor_buffer_props.descriptorBufferOffsetAlignment, + _SG_VK_MEMTYPE_DESCRIPTORS, + "shared-descriptor-buffer"); +} + +_SOKOL_PRIVATE void _sg_vk_bind_discard(void) { + _sg_vk_shared_buffer_discard(&_sg.vk.bind); +} + +// called from _sg_vk_acquire_frame_command_buffer() +_SOKOL_PRIVATE void _sg_vk_bind_after_acquire(void) { + _sg_vk_shared_buffer_after_acquire(&_sg.vk.bind); + + // bind the current frame's descriptor buffer + SOKOL_ASSERT(_sg.vk.frame.cmd_buf); + SOKOL_ASSERT(_sg.vk.bind.cur_buf); + SOKOL_ASSERT(_sg.vk.bind.cur_dev_addr); + _SG_STRUCT(VkDescriptorBufferBindingInfoEXT, bind_info); + bind_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_BUFFER_BINDING_INFO_EXT; + bind_info.address = _sg.vk.bind.cur_dev_addr; + bind_info.usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT | + VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT; + _sg.vk.ext.cmd_bind_descriptor_buffers(_sg.vk.frame.cmd_buf, 1, &bind_info); +} + +// called from _sg_vk_submit_frame_command_buffer() +_SOKOL_PRIVATE void _sg_vk_bind_before_submit(void) { + _sg_vk_shared_buffer_before_submit(&_sg.vk.bind); +} + +_SOKOL_PRIVATE bool _sg_vk_bind_view_smp_descriptor_set(VkCommandBuffer cmd_buf, const _sg_bindings_ptrs_t* bnd, VkPipelineBindPoint vk_bind_point) { + SOKOL_ASSERT(_sg.vk.dev); + SOKOL_ASSERT(cmd_buf); + SOKOL_ASSERT(bnd && bnd->pip); + const _sg_shader_t* shd = _sg_shader_ref_ptr(&bnd->pip->cmn.shader); + + // get next pointer in descriptor buffer + const VkDeviceSize dset_size = shd->vk.view_smp_dset_size; + if (dset_size == 0) { + // nothing to bind + return true; + } + const VkDeviceSize dbuf_offset = _sg_vk_shared_buffer_alloc(&_sg.vk.bind, dset_size); + if (_sg.vk.bind.overflown) { + _SG_ERROR(VULKAN_DESCRIPTOR_BUFFER_OVERFLOW); + return false; + } + _sg_stats_add(vk.size_descriptor_buffer_writes, dset_size); + uint8_t* dbuf_ptr = _sg_vk_shared_buffer_ptr(&_sg.vk.bind, dbuf_offset); + + // copy pre-recorded descriptor data into descriptor buffer + for (size_t i = 0; i < SG_MAX_VIEW_BINDSLOTS; i++) { + if (shd->cmn.views[i].stage == SG_SHADERSTAGE_NONE) { + continue; + } + const _sg_view_t* view = bnd->views[i]; + SOKOL_ASSERT(view && (view->vk.descriptor_size > 0)); + const void* src_ptr = view->vk.descriptor_data; + size_t size = view->vk.descriptor_size; + void* dst_ptr = dbuf_ptr + shd->vk.view_dset_offsets[i]; + memcpy(dst_ptr, src_ptr, size); + } + for (size_t i = 0; i < SG_MAX_SAMPLER_BINDSLOTS; i++) { + if (shd->cmn.samplers[i].stage == SG_SHADERSTAGE_NONE) { + continue; + } + const _sg_sampler_t* smp = bnd->smps[i]; + SOKOL_ASSERT(smp && (smp->vk.descriptor_size > 0)); + const void* src_ptr = smp->vk.descriptor_data; + size_t size = smp->vk.descriptor_size; + void* dst_ptr = dbuf_ptr + shd->vk.smp_dset_offsets[i]; + memcpy(dst_ptr, src_ptr, size); + } + + // record the new descriptor buffer offset + const uint32_t dbuf_index = 0; + SOKOL_ASSERT(shd->vk.pip_layout); + _sg.vk.ext.cmd_set_descriptor_buffer_offsets( + cmd_buf, + vk_bind_point, + shd->vk.pip_layout, + _SG_VK_VIEW_SMP_DESCRIPTORSET_INDEX, // firstSet + 1, // setCount + &dbuf_index, + &dbuf_offset); + _sg_stats_add(vk.num_cmd_set_descriptor_buffer_offsets, 1); + return true; +} + +_SOKOL_PRIVATE bool _sg_vk_bind_uniform_descriptor_set(VkCommandBuffer cmd_buf) { + SOKOL_ASSERT(cmd_buf); + SOKOL_ASSERT(_sg.vk.uniforms_dirty); + _sg.vk.uniforms_dirty = false; + const _sg_pipeline_t* pip = _sg_pipeline_ref_ptr(&_sg.cur_pip); + const _sg_shader_t* shd = _sg_shader_ref_ptr(&pip->cmn.shader); + + // get next pointer in descriptor buffer + const VkDeviceSize dbuf_offset = _sg_vk_shared_buffer_alloc(&_sg.vk.bind, shd->vk.ub_dset_size); + if (_sg.vk.bind.overflown) { + _SG_ERROR(VULKAN_DESCRIPTOR_BUFFER_OVERFLOW); + return false; + } + _sg_stats_add(vk.size_descriptor_buffer_writes, shd->vk.ub_dset_size); + uint8_t* dbuf_ptr = _sg_vk_shared_buffer_ptr(&_sg.vk.bind, dbuf_offset); + + // update descriptor buffer + for (size_t i = 0; i < SG_MAX_UNIFORMBLOCK_BINDSLOTS; i++) { + if (shd->cmn.uniform_blocks[i].stage == SG_SHADERSTAGE_NONE) { + continue; + } + _sg.vk.ext.get_descriptor(_sg.vk.dev, + &_sg.vk.uniform_bindinfos[i].get_info, + _sg.vk.descriptor_buffer_props.uniformBufferDescriptorSize, + dbuf_ptr + shd->vk.ub_dset_offsets[i]); + } + + // record the descriptor buffer offset + const VkPipelineBindPoint vk_bind_point = _sg.cur_pass.is_compute + ? VK_PIPELINE_BIND_POINT_COMPUTE + : VK_PIPELINE_BIND_POINT_GRAPHICS; + const uint32_t dbuf_index = 0; + SOKOL_ASSERT(shd->vk.pip_layout); + _sg.vk.ext.cmd_set_descriptor_buffer_offsets( + cmd_buf, + vk_bind_point, + shd->vk.pip_layout, + _SG_VK_UB_DESCRIPTORSET_INDEX, // firstIndex + 1, // setCount + &dbuf_index, + &dbuf_offset); + _sg_stats_add(vk.num_cmd_set_descriptor_buffer_offsets, 1); + return true; +} + +_SOKOL_PRIVATE void _sg_vk_memory_destructor(void* obj) { + SOKOL_ASSERT(_sg.vk.dev && obj); + _sg_vk_mem_free_device_memory((VkDeviceMemory)obj); +} + +_SOKOL_PRIVATE void _sg_vk_buffer_destructor(void* obj) { + SOKOL_ASSERT(_sg.vk.dev && obj); + vkDestroyBuffer(_sg.vk.dev, (VkBuffer)obj, 0); +} + +_SOKOL_PRIVATE void _sg_vk_image_destructor(void* obj) { + SOKOL_ASSERT(_sg.vk.dev && obj); + vkDestroyImage(_sg.vk.dev, (VkImage)obj, 0); +} + +_SOKOL_PRIVATE void _sg_vk_image_view_destructor(void* obj) { + SOKOL_ASSERT(_sg.vk.dev && obj); + vkDestroyImageView(_sg.vk.dev, (VkImageView)obj, 0); +} + +_SOKOL_PRIVATE void _sg_vk_sampler_destructor(void* obj) { + SOKOL_ASSERT(_sg.vk.dev && obj); + vkDestroySampler(_sg.vk.dev, (VkSampler)obj, 0); +} + +_SOKOL_PRIVATE void _sg_vk_shader_module_destructor(void* obj) { + SOKOL_ASSERT(_sg.vk.dev && obj); + vkDestroyShaderModule(_sg.vk.dev, (VkShaderModule)obj, 0); +} + +_SOKOL_PRIVATE void _sg_vk_pipelinelayout_destructor(void* obj) { + SOKOL_ASSERT(_sg.vk.dev && obj); + vkDestroyPipelineLayout(_sg.vk.dev, (VkPipelineLayout)obj, 0); +} + +_SOKOL_PRIVATE void _sg_vk_descriptorsetlayout_destructor(void* obj) { + SOKOL_ASSERT(_sg.vk.dev && obj); + vkDestroyDescriptorSetLayout(_sg.vk.dev, (VkDescriptorSetLayout)obj, 0); +} + +_SOKOL_PRIVATE void _sg_vk_pipeline_destructor(void* obj) { + SOKOL_ASSERT(_sg.vk.dev && obj); + vkDestroyPipeline(_sg.vk.dev, (VkPipeline)obj, 0); +} + +_SOKOL_PRIVATE VkBufferUsageFlags _sg_vk_buffer_usage(const sg_buffer_usage* usg) { + VkBufferUsageFlags res = VK_BUFFER_USAGE_TRANSFER_DST_BIT; + if (usg->vertex_buffer) { + res |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + } + if (usg->index_buffer) { + res |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT; + } + if (usg->storage_buffer) { + res |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; + } + return res; +} + +_SOKOL_PRIVATE VkVertexInputRate _sg_vk_vertex_input_rate(sg_vertex_step s) { + return (s == SG_VERTEXSTEP_PER_VERTEX) ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE; +} + +_SOKOL_PRIVATE VkFormat _sg_vk_vertex_format(sg_vertex_format f) { + switch (f) { + case SG_VERTEXFORMAT_FLOAT: return VK_FORMAT_R32_SFLOAT; + case SG_VERTEXFORMAT_FLOAT2: return VK_FORMAT_R32G32_SFLOAT; + case SG_VERTEXFORMAT_FLOAT3: return VK_FORMAT_R32G32B32_SFLOAT; + case SG_VERTEXFORMAT_FLOAT4: return VK_FORMAT_R32G32B32A32_SFLOAT; + case SG_VERTEXFORMAT_INT: return VK_FORMAT_R32_SINT; + case SG_VERTEXFORMAT_INT2: return VK_FORMAT_R32G32_SINT; + case SG_VERTEXFORMAT_INT3: return VK_FORMAT_R32G32B32_SINT; + case SG_VERTEXFORMAT_INT4: return VK_FORMAT_R32G32B32A32_SINT; + case SG_VERTEXFORMAT_UINT: return VK_FORMAT_R32_UINT; + case SG_VERTEXFORMAT_UINT2: return VK_FORMAT_R32G32_UINT; + case SG_VERTEXFORMAT_UINT3: return VK_FORMAT_R32G32B32_UINT; + case SG_VERTEXFORMAT_UINT4: return VK_FORMAT_R32G32B32A32_UINT; + case SG_VERTEXFORMAT_BYTE4: return VK_FORMAT_R8G8B8A8_SINT; + case SG_VERTEXFORMAT_BYTE4N: return VK_FORMAT_R8G8B8A8_SNORM; + case SG_VERTEXFORMAT_UBYTE4: return VK_FORMAT_R8G8B8A8_UINT; + case SG_VERTEXFORMAT_UBYTE4N: return VK_FORMAT_R8G8B8A8_UNORM; + case SG_VERTEXFORMAT_SHORT2: return VK_FORMAT_R16G16_SINT; + case SG_VERTEXFORMAT_SHORT2N: return VK_FORMAT_R16G16_SNORM; + case SG_VERTEXFORMAT_USHORT2: return VK_FORMAT_R16G16_UINT; + case SG_VERTEXFORMAT_USHORT2N: return VK_FORMAT_R16G16_UNORM; + case SG_VERTEXFORMAT_SHORT4: return VK_FORMAT_R16G16B16A16_SINT; + case SG_VERTEXFORMAT_SHORT4N: return VK_FORMAT_R16G16B16A16_SNORM; + case SG_VERTEXFORMAT_USHORT4: return VK_FORMAT_R16G16B16A16_UINT; + case SG_VERTEXFORMAT_USHORT4N: return VK_FORMAT_R16G16B16A16_UNORM; + case SG_VERTEXFORMAT_UINT10_N2: return VK_FORMAT_A2R10G10B10_UNORM_PACK32; + case SG_VERTEXFORMAT_HALF2: return VK_FORMAT_R16G16_SFLOAT; + case SG_VERTEXFORMAT_HALF4: return VK_FORMAT_R16G16B16A16_SFLOAT; + default: + SOKOL_UNREACHABLE; + return VK_FORMAT_UNDEFINED; + } +} + +_SOKOL_PRIVATE VkImageCreateFlags _sg_vk_image_create_flags(sg_image_type t) { + switch (t) { + case SG_IMAGETYPE_2D: return 0; + case SG_IMAGETYPE_CUBE: return VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; + // FIXME: VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT needed for render to slice? + case SG_IMAGETYPE_3D: return 0; + case SG_IMAGETYPE_ARRAY: return 0; + default: + SOKOL_UNREACHABLE; + return 0; + } +} + +_SOKOL_PRIVATE VkImageType _sg_vk_image_type(sg_image_type t) { + return (SG_IMAGETYPE_3D == t) ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D; +} + +_SOKOL_PRIVATE VkImageUsageFlags _sg_vk_image_usage(const sg_image_usage* usg) { + VkImageUsageFlags res = VK_IMAGE_USAGE_TRANSFER_DST_BIT; + res |= VK_IMAGE_USAGE_SAMPLED_BIT; + if (usg->storage_image) { + res |= VK_IMAGE_USAGE_STORAGE_BIT; + } + if (usg->color_attachment || usg->resolve_attachment) { + res |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + } + if (usg->depth_stencil_attachment) { + res |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + } + return res; +} + +_SOKOL_PRIVATE VkFormat _sg_vk_format(sg_pixel_format fmt) { + switch (fmt) { + case SG_PIXELFORMAT_NONE: return VK_FORMAT_UNDEFINED; + case SG_PIXELFORMAT_R8: return VK_FORMAT_R8_UNORM; + case SG_PIXELFORMAT_R8SN: return VK_FORMAT_R8_SNORM; + case SG_PIXELFORMAT_R8UI: return VK_FORMAT_R8_UINT; + case SG_PIXELFORMAT_R8SI: return VK_FORMAT_R8_SINT; + case SG_PIXELFORMAT_R16: return VK_FORMAT_R16_UNORM; + case SG_PIXELFORMAT_R16SN: return VK_FORMAT_R16_SNORM; + case SG_PIXELFORMAT_R16UI: return VK_FORMAT_R16_UINT; + case SG_PIXELFORMAT_R16SI: return VK_FORMAT_R16_SINT; + case SG_PIXELFORMAT_R16F: return VK_FORMAT_R16_SFLOAT; + case SG_PIXELFORMAT_RG8: return VK_FORMAT_R8G8_UNORM; + case SG_PIXELFORMAT_RG8SN: return VK_FORMAT_R8G8_SNORM; + case SG_PIXELFORMAT_RG8UI: return VK_FORMAT_R8G8_UINT; + case SG_PIXELFORMAT_RG8SI: return VK_FORMAT_R8G8_SINT; + case SG_PIXELFORMAT_R32UI: return VK_FORMAT_R32_UINT; + case SG_PIXELFORMAT_R32SI: return VK_FORMAT_R32_SINT; + case SG_PIXELFORMAT_R32F: return VK_FORMAT_R32_SFLOAT; + case SG_PIXELFORMAT_RG16: return VK_FORMAT_R16G16_UNORM; + case SG_PIXELFORMAT_RG16SN: return VK_FORMAT_R16G16_SNORM; + case SG_PIXELFORMAT_RG16UI: return VK_FORMAT_R16G16_UINT; + case SG_PIXELFORMAT_RG16SI: return VK_FORMAT_R16G16_SINT; + case SG_PIXELFORMAT_RG16F: return VK_FORMAT_R16G16_SFLOAT; + case SG_PIXELFORMAT_RGBA8: return VK_FORMAT_R8G8B8A8_UNORM; + case SG_PIXELFORMAT_SRGB8A8: return VK_FORMAT_R8G8B8A8_SRGB; + case SG_PIXELFORMAT_RGBA8SN: return VK_FORMAT_R8G8B8A8_SNORM; + case SG_PIXELFORMAT_RGBA8UI: return VK_FORMAT_R8G8B8A8_UINT; + case SG_PIXELFORMAT_RGBA8SI: return VK_FORMAT_R8G8B8A8_SINT; + case SG_PIXELFORMAT_BGRA8: return VK_FORMAT_B8G8R8A8_UNORM; + case SG_PIXELFORMAT_RGB10A2: return VK_FORMAT_A2R10G10B10_UNORM_PACK32; + case SG_PIXELFORMAT_RG11B10F: return VK_FORMAT_B10G11R11_UFLOAT_PACK32; + case SG_PIXELFORMAT_RGB9E5: return VK_FORMAT_E5B9G9R9_UFLOAT_PACK32; + case SG_PIXELFORMAT_RG32UI: return VK_FORMAT_R32G32_UINT; + case SG_PIXELFORMAT_RG32SI: return VK_FORMAT_R32G32_SINT; + case SG_PIXELFORMAT_RG32F: return VK_FORMAT_R32G32_SFLOAT; + case SG_PIXELFORMAT_RGBA16: return VK_FORMAT_R16G16B16A16_UNORM; + case SG_PIXELFORMAT_RGBA16SN: return VK_FORMAT_R16G16B16A16_SNORM; + case SG_PIXELFORMAT_RGBA16UI: return VK_FORMAT_R16G16B16A16_UINT; + case SG_PIXELFORMAT_RGBA16SI: return VK_FORMAT_R16G16B16A16_SINT; + case SG_PIXELFORMAT_RGBA16F: return VK_FORMAT_R16G16B16A16_SFLOAT; + case SG_PIXELFORMAT_RGBA32UI: return VK_FORMAT_R32G32B32A32_UINT; + case SG_PIXELFORMAT_RGBA32SI: return VK_FORMAT_R32G32B32A32_SINT; + case SG_PIXELFORMAT_RGBA32F: return VK_FORMAT_R32G32B32A32_SFLOAT; + case SG_PIXELFORMAT_DEPTH: return VK_FORMAT_D32_SFLOAT; + case SG_PIXELFORMAT_DEPTH_STENCIL: return VK_FORMAT_D32_SFLOAT_S8_UINT; + case SG_PIXELFORMAT_BC1_RGBA: return VK_FORMAT_BC1_RGBA_UNORM_BLOCK; + case SG_PIXELFORMAT_BC2_RGBA: return VK_FORMAT_BC2_UNORM_BLOCK; + case SG_PIXELFORMAT_BC3_RGBA: return VK_FORMAT_BC3_UNORM_BLOCK; + case SG_PIXELFORMAT_BC3_SRGBA: return VK_FORMAT_BC3_SRGB_BLOCK; + case SG_PIXELFORMAT_BC4_R: return VK_FORMAT_BC4_UNORM_BLOCK; + case SG_PIXELFORMAT_BC4_RSN: return VK_FORMAT_BC4_SNORM_BLOCK; + case SG_PIXELFORMAT_BC5_RG: return VK_FORMAT_BC5_UNORM_BLOCK; + case SG_PIXELFORMAT_BC5_RGSN: return VK_FORMAT_BC5_SNORM_BLOCK; + case SG_PIXELFORMAT_BC6H_RGBF: return VK_FORMAT_BC6H_SFLOAT_BLOCK; + case SG_PIXELFORMAT_BC6H_RGBUF: return VK_FORMAT_BC6H_UFLOAT_BLOCK; + case SG_PIXELFORMAT_BC7_RGBA: return VK_FORMAT_BC7_UNORM_BLOCK; + case SG_PIXELFORMAT_BC7_SRGBA: return VK_FORMAT_BC7_SRGB_BLOCK; + case SG_PIXELFORMAT_ETC2_RGB8: return VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK; + case SG_PIXELFORMAT_ETC2_RGB8A1: return VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK; + case SG_PIXELFORMAT_ETC2_RGBA8: return VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK; + case SG_PIXELFORMAT_ETC2_SRGB8: return VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK; + case SG_PIXELFORMAT_ETC2_SRGB8A8: return VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK; + case SG_PIXELFORMAT_EAC_R11: return VK_FORMAT_EAC_R11_UNORM_BLOCK; + case SG_PIXELFORMAT_EAC_R11SN: return VK_FORMAT_EAC_R11_SNORM_BLOCK; + case SG_PIXELFORMAT_EAC_RG11: return VK_FORMAT_EAC_R11G11_UNORM_BLOCK; + case SG_PIXELFORMAT_EAC_RG11SN: return VK_FORMAT_EAC_R11G11_SNORM_BLOCK; + case SG_PIXELFORMAT_ASTC_4x4_RGBA: return VK_FORMAT_ASTC_4x4_UNORM_BLOCK; + case SG_PIXELFORMAT_ASTC_4x4_SRGBA: return VK_FORMAT_ASTC_4x4_SRGB_BLOCK; + default: return VK_FORMAT_UNDEFINED; + }; +} + +_SOKOL_PRIVATE VkPrimitiveTopology _sg_vk_primitive_topology(sg_primitive_type t) { + switch (t) { + case SG_PRIMITIVETYPE_POINTS: return VK_PRIMITIVE_TOPOLOGY_POINT_LIST; + case SG_PRIMITIVETYPE_LINES: return VK_PRIMITIVE_TOPOLOGY_LINE_LIST; + case SG_PRIMITIVETYPE_LINE_STRIP: return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP; + case SG_PRIMITIVETYPE_TRIANGLES: return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + case SG_PRIMITIVETYPE_TRIANGLE_STRIP: return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; + default: + SOKOL_UNREACHABLE; + return VK_PRIMITIVE_TOPOLOGY_MAX_ENUM; + } +} + +_SOKOL_PRIVATE VkCullModeFlags _sg_vk_cullmode(sg_cull_mode cm) { + switch (cm) { + case SG_CULLMODE_NONE: return VK_CULL_MODE_NONE; + case SG_CULLMODE_FRONT: return VK_CULL_MODE_FRONT_BIT; + case SG_CULLMODE_BACK: return VK_CULL_MODE_BACK_BIT; + default: + SOKOL_UNREACHABLE; + return VK_CULL_MODE_NONE; + } +} + +_SOKOL_PRIVATE VkFrontFace _sg_vk_frontface(sg_face_winding fw) { + return (fw == SG_FACEWINDING_CCW) ? VK_FRONT_FACE_COUNTER_CLOCKWISE : VK_FRONT_FACE_CLOCKWISE; +} + +_SOKOL_PRIVATE VkCompareOp _sg_vk_compare_op(sg_compare_func f) { + switch (f) { + case SG_COMPAREFUNC_NEVER: return VK_COMPARE_OP_NEVER; + case SG_COMPAREFUNC_LESS: return VK_COMPARE_OP_LESS; + case SG_COMPAREFUNC_EQUAL: return VK_COMPARE_OP_EQUAL; + case SG_COMPAREFUNC_LESS_EQUAL: return VK_COMPARE_OP_LESS_OR_EQUAL; + case SG_COMPAREFUNC_GREATER: return VK_COMPARE_OP_GREATER; + case SG_COMPAREFUNC_NOT_EQUAL: return VK_COMPARE_OP_NOT_EQUAL; + case SG_COMPAREFUNC_GREATER_EQUAL: return VK_COMPARE_OP_GREATER_OR_EQUAL; + case SG_COMPAREFUNC_ALWAYS: return VK_COMPARE_OP_ALWAYS; + default: + SOKOL_UNREACHABLE; + return VK_COMPARE_OP_ALWAYS; + } +} + +_SOKOL_PRIVATE VkStencilOp _sg_vk_stencil_op(sg_stencil_op op) { + switch (op) { + case SG_STENCILOP_KEEP: return VK_STENCIL_OP_KEEP; + case SG_STENCILOP_ZERO: return VK_STENCIL_OP_ZERO; + case SG_STENCILOP_REPLACE: return VK_STENCIL_OP_REPLACE; + case SG_STENCILOP_INCR_CLAMP: return VK_STENCIL_OP_INCREMENT_AND_CLAMP; + case SG_STENCILOP_DECR_CLAMP: return VK_STENCIL_OP_DECREMENT_AND_CLAMP; + case SG_STENCILOP_INVERT: return VK_STENCIL_OP_INVERT; + case SG_STENCILOP_INCR_WRAP: return VK_STENCIL_OP_INCREMENT_AND_WRAP; + case SG_STENCILOP_DECR_WRAP: return VK_STENCIL_OP_DECREMENT_AND_WRAP; + default: + SOKOL_UNREACHABLE; + return VK_STENCIL_OP_KEEP; + } +} + +_SOKOL_PRIVATE VkBlendOp _sg_vk_blend_op(sg_blend_op op) { + switch (op) { + case SG_BLENDOP_ADD: return VK_BLEND_OP_ADD; + case SG_BLENDOP_SUBTRACT: return VK_BLEND_OP_SUBTRACT; + case SG_BLENDOP_REVERSE_SUBTRACT: return VK_BLEND_OP_REVERSE_SUBTRACT; + case SG_BLENDOP_MIN: return VK_BLEND_OP_MIN; + case SG_BLENDOP_MAX: return VK_BLEND_OP_MAX; + default: + SOKOL_UNREACHABLE; + return VK_BLEND_OP_ADD; + } +} + +_SOKOL_PRIVATE VkBlendFactor _sg_vk_blend_factor(sg_blend_factor f) { + switch (f) { + case SG_BLENDFACTOR_ZERO: return VK_BLEND_FACTOR_ZERO; + case SG_BLENDFACTOR_ONE: return VK_BLEND_FACTOR_ONE; + case SG_BLENDFACTOR_SRC_COLOR: return VK_BLEND_FACTOR_SRC_COLOR; + case SG_BLENDFACTOR_ONE_MINUS_SRC_COLOR: return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR; + case SG_BLENDFACTOR_SRC_ALPHA: return VK_BLEND_FACTOR_SRC_ALPHA; + case SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA: return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + case SG_BLENDFACTOR_DST_COLOR: return VK_BLEND_FACTOR_DST_COLOR; + case SG_BLENDFACTOR_ONE_MINUS_DST_COLOR: return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR; + case SG_BLENDFACTOR_DST_ALPHA: return VK_BLEND_FACTOR_DST_ALPHA; + case SG_BLENDFACTOR_ONE_MINUS_DST_ALPHA: return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA; + case SG_BLENDFACTOR_SRC_ALPHA_SATURATED: return VK_BLEND_FACTOR_SRC_ALPHA_SATURATE; + case SG_BLENDFACTOR_BLEND_COLOR: return VK_BLEND_FACTOR_CONSTANT_COLOR; + case SG_BLENDFACTOR_ONE_MINUS_BLEND_COLOR: return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR; + case SG_BLENDFACTOR_BLEND_ALPHA: return VK_BLEND_FACTOR_CONSTANT_ALPHA; + case SG_BLENDFACTOR_ONE_MINUS_BLEND_ALPHA: return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA; + default: + SOKOL_UNREACHABLE; + return VK_BLEND_FACTOR_ONE; + } +} + +_SOKOL_PRIVATE VkColorComponentFlags _sg_vk_color_write_mask(sg_color_mask m) { + int res = 0; + if (0 != (m & SG_COLORMASK_R)) { + res |= (int)VK_COLOR_COMPONENT_R_BIT; + } + if (0 != (m & SG_COLORMASK_G)) { + res |= (int)VK_COLOR_COMPONENT_G_BIT; + } + if (0 != (m & SG_COLORMASK_B)) { + res |= (int)VK_COLOR_COMPONENT_B_BIT; + } + if (0 != (m & SG_COLORMASK_A)) { + res |= (int)VK_COLOR_COMPONENT_A_BIT; + } + return (VkColorComponentFlags)res; +} + +_SOKOL_PRIVATE VkShaderStageFlags _sg_vk_shader_stage(sg_shader_stage s) { + switch (s) { + case SG_SHADERSTAGE_VERTEX: return VK_SHADER_STAGE_VERTEX_BIT; + case SG_SHADERSTAGE_FRAGMENT: return VK_SHADER_STAGE_FRAGMENT_BIT; + case SG_SHADERSTAGE_COMPUTE: return VK_SHADER_STAGE_COMPUTE_BIT; + default: SOKOL_UNREACHABLE; return 0; + } +} + +_SOKOL_PRIVATE VkAttachmentLoadOp _sg_vk_load_op(sg_load_action a) { + switch (a) { + case SG_LOADACTION_CLEAR: + return VK_ATTACHMENT_LOAD_OP_CLEAR; + case SG_LOADACTION_DONTCARE: + return VK_ATTACHMENT_LOAD_OP_DONT_CARE; + default: + return VK_ATTACHMENT_LOAD_OP_LOAD; + } +} + +_SOKOL_PRIVATE VkAttachmentStoreOp _sg_vk_store_op(sg_store_action a) { + switch (a) { + case SG_STOREACTION_STORE: + return VK_ATTACHMENT_STORE_OP_STORE; + default: + return VK_ATTACHMENT_STORE_OP_DONT_CARE; + } +} + +_SOKOL_PRIVATE VkIndexType _sg_vk_index_type(sg_index_type t) { + return (t == SG_INDEXTYPE_UINT16) ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32; +} + +_SOKOL_PRIVATE VkImageViewType _sg_vk_texture_image_view_type(sg_image_type t) { + switch (t) { + case SG_IMAGETYPE_2D: return VK_IMAGE_VIEW_TYPE_2D; + case SG_IMAGETYPE_CUBE: return VK_IMAGE_VIEW_TYPE_CUBE; + case SG_IMAGETYPE_3D: return VK_IMAGE_VIEW_TYPE_3D; + case SG_IMAGETYPE_ARRAY: return VK_IMAGE_VIEW_TYPE_2D_ARRAY; + default: SOKOL_UNREACHABLE; return VK_IMAGE_VIEW_TYPE_2D; + } +} + +_SOKOL_PRIVATE VkImageViewType _sg_vk_attachment_image_view_type(sg_image_type t) { + switch (t) { + case SG_IMAGETYPE_2D: return VK_IMAGE_VIEW_TYPE_2D; + case SG_IMAGETYPE_CUBE: return VK_IMAGE_VIEW_TYPE_2D_ARRAY; // not a bug + case SG_IMAGETYPE_3D: return VK_IMAGE_VIEW_TYPE_2D; // not a bug + case SG_IMAGETYPE_ARRAY: return VK_IMAGE_VIEW_TYPE_2D_ARRAY; + default: SOKOL_UNREACHABLE; return VK_IMAGE_VIEW_TYPE_2D; + } +} + +_SOKOL_PRIVATE VkFilter _sg_vk_sampler_minmag_filter(sg_filter f) { + switch (f) { + case SG_FILTER_NEAREST: return VK_FILTER_NEAREST; + case SG_FILTER_LINEAR: return VK_FILTER_LINEAR; + default: SOKOL_UNREACHABLE; return VK_FILTER_NEAREST; + } +} + +_SOKOL_PRIVATE VkSamplerMipmapMode _sg_vk_sampler_mipmap_mode(sg_filter f) { + switch (f) { + case SG_FILTER_NEAREST: return VK_SAMPLER_MIPMAP_MODE_NEAREST; + case SG_FILTER_LINEAR: return VK_SAMPLER_MIPMAP_MODE_LINEAR; + default: SOKOL_UNREACHABLE; return VK_SAMPLER_MIPMAP_MODE_NEAREST; + } +} + +_SOKOL_PRIVATE VkSamplerAddressMode _sg_vk_sampler_address_mode(sg_wrap w) { + switch (w) { + case SG_WRAP_REPEAT: return VK_SAMPLER_ADDRESS_MODE_REPEAT; + case SG_WRAP_CLAMP_TO_EDGE: return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + case SG_WRAP_CLAMP_TO_BORDER: return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + case SG_WRAP_MIRRORED_REPEAT: return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; + default: SOKOL_UNREACHABLE; return VK_SAMPLER_ADDRESS_MODE_REPEAT; + } +} + +_SOKOL_PRIVATE VkBorderColor _sg_vk_sampler_border_color(sg_border_color c) { + switch (c) { + case SG_BORDERCOLOR_TRANSPARENT_BLACK: return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; + case SG_BORDERCOLOR_OPAQUE_BLACK: return VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; + case SG_BORDERCOLOR_OPAQUE_WHITE: return VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; + default: SOKOL_UNREACHABLE; return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; + } +} + +_SOKOL_PRIVATE void _sg_vk_load_ext_funcs(void) { + SOKOL_ASSERT(_sg.vk.dev); + _sg.vk.ext.get_descriptor_set_layout_size = (PFN_vkGetDescriptorSetLayoutSizeEXT)vkGetDeviceProcAddr(_sg.vk.dev, "vkGetDescriptorSetLayoutSizeEXT"); + if (0 == _sg.vk.ext.get_descriptor_set_layout_size) { + _SG_PANIC(VULKAN_REQUIRED_EXTENSION_FUNCTION_MISSING); + } + _sg.vk.ext.get_descriptor_set_layout_binding_offset = (PFN_vkGetDescriptorSetLayoutBindingOffsetEXT)vkGetDeviceProcAddr(_sg.vk.dev, "vkGetDescriptorSetLayoutBindingOffsetEXT"); + if (0 == _sg.vk.ext.get_descriptor_set_layout_binding_offset) { + _SG_PANIC(VULKAN_REQUIRED_EXTENSION_FUNCTION_MISSING); + } + _sg.vk.ext.get_descriptor = (PFN_vkGetDescriptorEXT)vkGetDeviceProcAddr(_sg.vk.dev, "vkGetDescriptorEXT"); + if (0 == _sg.vk.ext.get_descriptor) { + _SG_PANIC(VULKAN_REQUIRED_EXTENSION_FUNCTION_MISSING); + } + _sg.vk.ext.cmd_bind_descriptor_buffers = (PFN_vkCmdBindDescriptorBuffersEXT)vkGetDeviceProcAddr(_sg.vk.dev, "vkCmdBindDescriptorBuffersEXT"); + if (0 == _sg.vk.ext.cmd_bind_descriptor_buffers) { + _SG_PANIC(VULKAN_REQUIRED_EXTENSION_FUNCTION_MISSING); + } + _sg.vk.ext.cmd_set_descriptor_buffer_offsets = (PFN_vkCmdSetDescriptorBufferOffsetsEXT)vkGetDeviceProcAddr(_sg.vk.dev, "vkCmdSetDescriptorBufferOffsetsEXT"); + if (0 == _sg.vk.ext.cmd_set_descriptor_buffer_offsets) { + _SG_PANIC(VULKAN_REQUIRED_EXTENSION_FUNCTION_MISSING); + } +} + +_SOKOL_PRIVATE void _sg_vk_init_caps(void) { + _sg.backend = SG_BACKEND_VULKAN; + _sg.features.origin_top_left = true; + _sg.features.image_clamp_to_border = false; // FIXME? + _sg.features.mrt_independent_blend_state = true; + _sg.features.mrt_independent_write_mask = true; + _sg.features.compute = true; + _sg.features.msaa_texture_bindings = true; + _sg.features.draw_base_vertex = true; + _sg.features.draw_base_instance = true; + + SOKOL_ASSERT(_sg.vk.phys_dev); + _sg.vk.descriptor_buffer_props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_PROPERTIES_EXT; + _sg.vk.dev_props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + _sg.vk.dev_props.pNext = &_sg.vk.descriptor_buffer_props; + vkGetPhysicalDeviceProperties2(_sg.vk.phys_dev, &_sg.vk.dev_props); + _sg.vk.dev_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + vkGetPhysicalDeviceFeatures2(_sg.vk.phys_dev, &_sg.vk.dev_features); + + const VkPhysicalDeviceLimits* l = &_sg.vk.dev_props.properties.limits; + _sg.limits.max_image_size_2d = (int)l->maxImageDimension2D; + _sg.limits.max_image_size_cube = (int)l->maxImageDimensionCube; + _sg.limits.max_image_size_3d = (int)l->maxImageDimension3D; + _sg.limits.max_image_size_array = _sg.limits.max_image_size_2d; + _sg.limits.max_image_array_layers = (int)l->maxImageArrayLayers; + _sg.limits.max_vertex_attrs = _sg_min((int)l->maxVertexInputAttributes, SG_MAX_VERTEX_ATTRIBUTES); + _sg.limits.max_color_attachments = _sg_min((int)l->maxFragmentOutputAttachments, SG_MAX_COLOR_ATTACHMENTS); + _sg.limits.max_texture_bindings_per_stage = _sg_min((int)l->maxPerStageDescriptorSampledImages, SG_MAX_VIEW_BINDSLOTS); + _sg.limits.max_storage_buffer_bindings_per_stage = _sg_min((int)l->maxPerStageDescriptorStorageBuffers, SG_MAX_VIEW_BINDSLOTS); + _sg.limits.max_storage_image_bindings_per_stage = _sg_min((int)l->maxPerStageDescriptorStorageImages, SG_MAX_VIEW_BINDSLOTS); + _sg.limits.vk_min_uniform_buffer_offset_alignment = (int)l->minUniformBufferOffsetAlignment; + + // FIXME: currently these are the same as in the WebGPU backend + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_R8]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG8]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA8]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_SRGB8A8]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_BGRA8]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_R16F]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG16F]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA16F]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGB10A2]); + + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_R8SN]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RG8SN]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RGBA8SN]); + + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RG11B10F]); + + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_R8UI]); + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_R8SI]); + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RG8UI]); + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RG8SI]); + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RGBA8UI]); + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RGBA8SI]); + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_R16UI]); + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_R16SI]); + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RG16UI]); + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RG16SI]); + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RGBA16UI]); + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RGBA16SI]); + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_R32UI]); + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_R32SI]); + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RG32UI]); + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RG32SI]); + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RGBA32UI]); + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RGBA32SI]); + + _sg_pixelformat_sfr(&_sg.formats[SG_PIXELFORMAT_R32F]); + _sg_pixelformat_sfr(&_sg.formats[SG_PIXELFORMAT_RG32F]); + _sg_pixelformat_sfr(&_sg.formats[SG_PIXELFORMAT_RGBA32F]); + + _sg_pixelformat_srmd(&_sg.formats[SG_PIXELFORMAT_DEPTH]); + _sg_pixelformat_srmd(&_sg.formats[SG_PIXELFORMAT_DEPTH_STENCIL]); + + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RGB9E5]); + + if (_sg.vk.dev_features.features.textureCompressionBC) { + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC1_RGBA]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC2_RGBA]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC3_RGBA]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC3_SRGBA]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC4_R]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC4_RSN]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC5_RG]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC5_RGSN]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC6H_RGBF]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC6H_RGBUF]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC7_RGBA]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC7_SRGBA]); + } + + if (_sg.vk.dev_features.features.textureCompressionETC2) { + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RGB8]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_SRGB8]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RGB8A1]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RGBA8]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_SRGB8A8]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_EAC_R11]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_EAC_R11SN]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_EAC_RG11]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_EAC_RG11SN]); + } + + if (_sg.vk.dev_features.features.textureCompressionASTC_LDR) { + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ASTC_4x4_RGBA]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ASTC_4x4_SRGBA]); + } + + _sg_pixelformat_compute_all(&_sg.formats[SG_PIXELFORMAT_RGBA8]); + _sg_pixelformat_compute_all(&_sg.formats[SG_PIXELFORMAT_RGBA8SN]); + _sg_pixelformat_compute_all(&_sg.formats[SG_PIXELFORMAT_RGBA8UI]); + _sg_pixelformat_compute_all(&_sg.formats[SG_PIXELFORMAT_RGBA8SI]); + _sg_pixelformat_compute_all(&_sg.formats[SG_PIXELFORMAT_RGBA16UI]); + _sg_pixelformat_compute_all(&_sg.formats[SG_PIXELFORMAT_RGBA16SI]); + _sg_pixelformat_compute_all(&_sg.formats[SG_PIXELFORMAT_RGBA16F]); + _sg_pixelformat_compute_all(&_sg.formats[SG_PIXELFORMAT_R32UI]); + _sg_pixelformat_compute_all(&_sg.formats[SG_PIXELFORMAT_R32SI]); + _sg_pixelformat_compute_all(&_sg.formats[SG_PIXELFORMAT_R32F]); + _sg_pixelformat_compute_all(&_sg.formats[SG_PIXELFORMAT_RG32UI]); + _sg_pixelformat_compute_all(&_sg.formats[SG_PIXELFORMAT_RG32SI]); + _sg_pixelformat_compute_all(&_sg.formats[SG_PIXELFORMAT_RG32F]); + _sg_pixelformat_compute_all(&_sg.formats[SG_PIXELFORMAT_RGBA32UI]); + _sg_pixelformat_compute_all(&_sg.formats[SG_PIXELFORMAT_RGBA32SI]); + _sg_pixelformat_compute_all(&_sg.formats[SG_PIXELFORMAT_RGBA32F]); +} + +_SOKOL_PRIVATE void _sg_vk_create_fences(void) { + SOKOL_ASSERT(_sg.vk.dev); + _SG_STRUCT(VkFenceCreateInfo, create_info); + create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + create_info.flags = VK_FENCE_CREATE_SIGNALED_BIT; + for (size_t i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { + SOKOL_ASSERT(0 == _sg.vk.frame.slot[i].fence); + VkResult res = vkCreateFence(_sg.vk.dev, &create_info, 0, &_sg.vk.frame.slot[i].fence); + SOKOL_ASSERT((res == VK_SUCCESS) && _sg.vk.frame.slot[i].fence); _SOKOL_UNUSED(res); + } +} + +_SOKOL_PRIVATE void _sg_vk_destroy_fences(void) { + SOKOL_ASSERT(_sg.vk.dev); + for (size_t i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { + SOKOL_ASSERT(_sg.vk.frame.slot[i].fence); + vkDestroyFence(_sg.vk.dev, _sg.vk.frame.slot[i].fence, 0); + _sg.vk.frame.slot[i].fence = 0; + } +} + +_SOKOL_PRIVATE void _sg_vk_create_frame_command_pool_and_buffers(void) { + SOKOL_ASSERT(_sg.vk.dev); + SOKOL_ASSERT(0 == _sg.vk.frame.cmd_pool); + _SG_STRUCT(VkCommandPoolCreateInfo, pool_create_info); + pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + // FIXME: transient bit when the cmd buffers are reset each frame? + pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + pool_create_info.queueFamilyIndex = _sg.vk.queue_family_index; + VkResult res = vkCreateCommandPool(_sg.vk.dev, &pool_create_info, 0, &_sg.vk.frame.cmd_pool); + SOKOL_ASSERT((res == VK_SUCCESS) && _sg.vk.frame.cmd_pool); _SOKOL_UNUSED(res); + + for (size_t i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { + _SG_STRUCT(VkCommandBufferAllocateInfo, cmdbuf_alloc_info); + cmdbuf_alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + cmdbuf_alloc_info.commandPool = _sg.vk.frame.cmd_pool; + cmdbuf_alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + cmdbuf_alloc_info.commandBufferCount = 1; + res = vkAllocateCommandBuffers(_sg.vk.dev, &cmdbuf_alloc_info, &_sg.vk.frame.slot[i].command_buffer); + SOKOL_ASSERT((res == VK_SUCCESS) && _sg.vk.frame.slot[i].command_buffer); + res = vkAllocateCommandBuffers(_sg.vk.dev, &cmdbuf_alloc_info, &_sg.vk.frame.slot[i].stream_command_buffer); + SOKOL_ASSERT((res == VK_SUCCESS) && _sg.vk.frame.slot[i].stream_command_buffer); + } +} + +_SOKOL_PRIVATE void _sg_vk_destroy_frame_command_pool(void) { + SOKOL_ASSERT(_sg.vk.dev); + SOKOL_ASSERT(_sg.vk.frame.cmd_pool); + SOKOL_ASSERT(0 == _sg.vk.frame.cmd_buf); + SOKOL_ASSERT(0 == _sg.vk.frame.stream_cmd_buf); + // NOTE: command buffers owned by the pool will be automatically destroyed + vkDestroyCommandPool(_sg.vk.dev, _sg.vk.frame.cmd_pool, 0); + _sg.vk.frame.cmd_pool = 0; + for (size_t i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { + SOKOL_ASSERT(_sg.vk.frame.slot[i].command_buffer); + _sg.vk.frame.slot[i].command_buffer = 0; + _sg.vk.frame.slot[i].stream_command_buffer = 0; + } +} + +_SOKOL_PRIVATE void _sg_vk_acquire_frame_command_buffers(void) { + SOKOL_ASSERT(_sg.vk.dev); + VkResult res; + if (0 == _sg.vk.frame.cmd_buf) { + SOKOL_ASSERT(0 == _sg.vk.frame.stream_cmd_buf); + _sg.vk.frame_slot = (_sg.vk.frame_slot + 1) % SG_NUM_INFLIGHT_FRAMES; + // block until oldest inflight-frame has finished + do { + res = vkWaitForFences(_sg.vk.dev, + 1, + &_sg.vk.frame.slot[_sg.vk.frame_slot].fence, + VK_TRUE, + UINT64_MAX); + } while (res == VK_TIMEOUT); + if (res != VK_SUCCESS) { + _SG_WARN(VULKAN_WAIT_FOR_FENCE_FAILED); + _sg.cur_pass.valid = false; + return; + } + VkResult res = vkResetFences(_sg.vk.dev, 1, &_sg.vk.frame.slot[_sg.vk.frame_slot].fence); + SOKOL_ASSERT(res == VK_SUCCESS); _SOKOL_UNUSED(res); + + _sg_vk_delete_queue_collect(); + + _sg.vk.frame.cmd_buf = _sg.vk.frame.slot[_sg.vk.frame_slot].command_buffer; + res = vkResetCommandBuffer(_sg.vk.frame.cmd_buf, 0); + SOKOL_ASSERT(res == VK_SUCCESS); + _sg.vk.frame.stream_cmd_buf = _sg.vk.frame.slot[_sg.vk.frame_slot].stream_command_buffer; + res = vkResetCommandBuffer(_sg.vk.frame.stream_cmd_buf, 0); + SOKOL_ASSERT(res == VK_SUCCESS); + + _SG_STRUCT(VkCommandBufferBeginInfo, cmdbuf_begin_info); + cmdbuf_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + cmdbuf_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + res = vkBeginCommandBuffer(_sg.vk.frame.cmd_buf, &cmdbuf_begin_info); + SOKOL_ASSERT(res == VK_SUCCESS); + res = vkBeginCommandBuffer(_sg.vk.frame.stream_cmd_buf, &cmdbuf_begin_info); + SOKOL_ASSERT(res == VK_SUCCESS); + + _sg_vk_uniform_after_acquire(); + _sg_vk_bind_after_acquire(); + _sg_vk_staging_stream_after_acquire(); + } + SOKOL_ASSERT(_sg.vk.frame.cmd_buf); +} + +_SOKOL_PRIVATE void _sg_vk_submit_frame_command_buffers(void) { + SOKOL_ASSERT(_sg.vk.frame.cmd_buf); + SOKOL_ASSERT(_sg.vk.frame.stream_cmd_buf); + VkResult res; + _SOKOL_UNUSED(res); + + _sg_vk_staging_stream_before_submit(); + _sg_vk_bind_before_submit(); + _sg_vk_uniform_before_submit(); + + res = vkEndCommandBuffer(_sg.vk.frame.stream_cmd_buf); + SOKOL_ASSERT(res == VK_SUCCESS); + res = vkEndCommandBuffer(_sg.vk.frame.cmd_buf); + SOKOL_ASSERT(res == VK_SUCCESS); + + _SG_STRUCT(VkSubmitInfo, submit_infos[2]); + // streaming-update command buffer + submit_infos[0].sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_infos[0].commandBufferCount = 1; + submit_infos[0].pCommandBuffers = &_sg.vk.frame.stream_cmd_buf; + // render command buffer + const VkPipelineStageFlags present_wait_dst_stage_mask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + submit_infos[1].sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_infos[1].waitSemaphoreCount = 1; + submit_infos[1].pWaitSemaphores = &_sg.vk.present_complete_sem; + submit_infos[1].pWaitDstStageMask = &present_wait_dst_stage_mask; + submit_infos[1].commandBufferCount = 1; + submit_infos[1].pCommandBuffers = &_sg.vk.frame.cmd_buf; + submit_infos[1].signalSemaphoreCount = 1; + submit_infos[1].pSignalSemaphores = &_sg.vk.render_finished_sem; + res = vkQueueSubmit(_sg.vk.queue, 2, submit_infos, _sg.vk.frame.slot[_sg.vk.frame_slot].fence); + SOKOL_ASSERT(res == VK_SUCCESS); + + _sg.vk.frame.cmd_buf = 0; + _sg.vk.frame.stream_cmd_buf = 0; + + // NOTE: it's valid to register resource objects for destruction in the + // delete queue past this point (between _sg_vk_submit_frame_command_buffer() + // and the next _sg_vk_acquire_frame_command_buffer()) since resources which are + // destroyed in this 'gap' can at most have been used by the command + // buffer that was just submitted +} + +_SOKOL_PRIVATE void _sg_vk_setup_backend(const sg_desc* desc) { + SOKOL_ASSERT(desc); + SOKOL_ASSERT(desc->environment.vulkan.physical_device); + SOKOL_ASSERT(desc->environment.vulkan.device); + SOKOL_ASSERT(desc->environment.vulkan.queue); + SOKOL_ASSERT(desc->uniform_buffer_size > 0); + _sg.vk.valid = true; + _sg.vk.phys_dev = (VkPhysicalDevice) desc->environment.vulkan.physical_device; + _sg.vk.dev = (VkDevice) desc->environment.vulkan.device; + _sg.vk.queue = (VkQueue) desc->environment.vulkan.queue; + _sg.vk.queue_family_index = desc->environment.vulkan.queue_family_index; + + _sg_track_init(&_sg.vk.track.buffers, _sg.pools.buffer_pool.size); + _sg_track_init(&_sg.vk.track.images, _sg.pools.image_pool.size); + _sg_vk_load_ext_funcs(); + _sg_vk_init_caps(); + _sg_vk_create_fences(); + _sg_vk_create_frame_command_pool_and_buffers(); + _sg_vk_staging_copy_init(); + _sg_vk_staging_stream_init(); + _sg_vk_uniform_init(); + _sg_vk_bind_init(); + _sg_vk_create_delete_queues(); +} + +_SOKOL_PRIVATE void _sg_vk_discard_backend(void) { + SOKOL_ASSERT(_sg.vk.valid); + SOKOL_ASSERT(_sg.vk.dev); + vkDeviceWaitIdle(_sg.vk.dev); + _sg_vk_destroy_delete_queues(); + _sg_vk_bind_discard(); + _sg_vk_uniform_discard(); + _sg_vk_staging_stream_discard(); + _sg_vk_staging_copy_discard(); + _sg_vk_destroy_frame_command_pool(); + _sg_vk_destroy_fences(); + _sg_track_discard(&_sg.vk.track.images); + _sg_track_discard(&_sg.vk.track.buffers); + _sg.vk.valid = false; +} + +_SOKOL_PRIVATE void _sg_vk_reset_state_cache(void) { + // nothing to do here +} + +_SOKOL_PRIVATE sg_resource_state _sg_vk_create_buffer(_sg_buffer_t* buf, const sg_buffer_desc* desc) { + SOKOL_ASSERT(_sg.vk.dev); + SOKOL_ASSERT(buf && desc); + SOKOL_ASSERT(buf->cmn.size > 0); + SOKOL_ASSERT(0 == buf->vk.buf); + SOKOL_ASSERT(0 == buf->vk.mem); + SOKOL_ASSERT(0 == buf->vk.dev_addr); + VkResult res; + // FIXME: inject external buffer + + buf->vk.cur_access = _SG_VK_ACCESS_NONE; + + _SG_STRUCT(VkBufferCreateInfo, create_info); + create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + create_info.size = (VkDeviceSize)buf->cmn.size; + create_info.usage = _sg_vk_buffer_usage(&buf->cmn.usage); + create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + res = vkCreateBuffer(_sg.vk.dev, &create_info, 0, &buf->vk.buf); + if (res != VK_SUCCESS) { + _SG_ERROR(VULKAN_CREATE_BUFFER_FAILED); + return SG_RESOURCESTATE_FAILED; + } + SOKOL_ASSERT(buf->vk.buf); + _sg_vk_set_object_label(VK_OBJECT_TYPE_BUFFER, (uint64_t)buf->vk.buf, desc->label); + + if (!_sg_vk_mem_alloc_buffer_device_memory(buf)) { + return SG_RESOURCESTATE_FAILED; + } + SOKOL_ASSERT(buf->vk.mem); + res = vkBindBufferMemory(_sg.vk.dev, buf->vk.buf, buf->vk.mem, 0); + if (res != VK_SUCCESS) { + _SG_ERROR(VULKAN_BIND_BUFFER_MEMORY_FAILED); + return SG_RESOURCESTATE_FAILED; + } + if (buf->cmn.usage.storage_buffer) { + _SG_STRUCT(VkBufferDeviceAddressInfo, addr_info); + addr_info.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; + addr_info.buffer = buf->vk.buf; + buf->vk.dev_addr = vkGetBufferDeviceAddress(_sg.vk.dev, &addr_info); + SOKOL_ASSERT(buf->vk.dev_addr); + } + if (buf->cmn.usage.immutable && desc->data.ptr) { + _sg_vk_staging_copy_buffer_data(buf, &desc->data, 0, false); + } + return SG_RESOURCESTATE_VALID; +} + +_SOKOL_PRIVATE void _sg_vk_discard_buffer(_sg_buffer_t* buf) { + SOKOL_ASSERT(buf); + _sg_track_remove(&_sg.vk.track.buffers, buf->slot.id); + if (buf->vk.buf) { + _sg_vk_delete_queue_add(_sg_vk_buffer_destructor, (void*)buf->vk.buf); + buf->vk.buf = 0; + } + if (buf->vk.mem) { + _sg_vk_delete_queue_add(_sg_vk_memory_destructor, (void*)buf->vk.mem); + buf->vk.mem = 0; + } +} + +_SOKOL_PRIVATE sg_resource_state _sg_vk_create_image(_sg_image_t* img, const sg_image_desc* desc) { + SOKOL_ASSERT(img && desc); + VkResult res; + // FIXME: injected images + + img->vk.cur_access = _SG_VK_ACCESS_NONE; + + _SG_STRUCT(VkImageCreateInfo, create_info); + create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + create_info.flags = _sg_vk_image_create_flags(img->cmn.type); + create_info.imageType = _sg_vk_image_type(img->cmn.type); + create_info.format = _sg_vk_format(desc->pixel_format); + create_info.extent.width = (uint32_t)img->cmn.width; + create_info.extent.height = (uint32_t)img->cmn.height; + if (desc->type == SG_IMAGETYPE_3D) { + create_info.extent.depth = (uint32_t)img->cmn.num_slices; + create_info.arrayLayers = 1; + } else { + create_info.extent.depth = 1; + create_info.arrayLayers = (uint32_t)img->cmn.num_slices; + } + create_info.mipLevels = (uint32_t)img->cmn.num_mipmaps; + create_info.samples = (VkSampleCountFlagBits)desc->sample_count; + create_info.tiling = VK_IMAGE_TILING_OPTIMAL; + create_info.usage = _sg_vk_image_usage(&img->cmn.usage); + create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + res = vkCreateImage(_sg.vk.dev, &create_info, 0, &img->vk.img); + if (res != VK_SUCCESS) { + _SG_ERROR(VULKAN_CREATE_IMAGE_FAILED); + return SG_RESOURCESTATE_FAILED; + } + SOKOL_ASSERT(img->vk.img); + _sg_vk_set_object_label(VK_OBJECT_TYPE_IMAGE, (uint64_t)img->vk.img, desc->label); + + if (!_sg_vk_mem_alloc_image_device_memory(img)) { + return SG_RESOURCESTATE_FAILED; + } + SOKOL_ASSERT(img->vk.mem); + res = vkBindImageMemory(_sg.vk.dev, img->vk.img, img->vk.mem, 0); + if (res != VK_SUCCESS) { + _SG_ERROR(VULKAN_BIND_IMAGE_MEMORY_FAILED); + return SG_RESOURCESTATE_FAILED; + } + if (img->cmn.usage.immutable && desc->data.mip_levels[0].ptr) { + _sg_vk_staging_copy_image_data(img, &desc->data, false); + } + return SG_RESOURCESTATE_VALID; +} + +_SOKOL_PRIVATE void _sg_vk_discard_image(_sg_image_t* img) { + SOKOL_ASSERT(img); + _sg_track_remove(&_sg.vk.track.images, img->slot.id); + if (img->vk.img) { + _sg_vk_delete_queue_add(_sg_vk_image_destructor, (void*)img->vk.img); + img->vk.img = 0; + } + if (img->vk.mem) { + _sg_vk_delete_queue_add(_sg_vk_memory_destructor, (void*)img->vk.mem); + img->vk.mem = 0; + } +} + +_SOKOL_PRIVATE sg_resource_state _sg_vk_create_sampler(_sg_sampler_t* smp, const sg_sampler_desc* desc) { + SOKOL_ASSERT(smp && desc); + SOKOL_ASSERT(_sg.vk.dev); + SOKOL_ASSERT(0 == smp->vk.smp); + // FIXME: injection + + // create sampler object + _SG_STRUCT(VkSamplerCreateInfo, create_info); + create_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + create_info.magFilter = _sg_vk_sampler_minmag_filter(desc->mag_filter); + create_info.minFilter = _sg_vk_sampler_minmag_filter(desc->min_filter); + create_info.mipmapMode = _sg_vk_sampler_mipmap_mode(desc->mipmap_filter); + create_info.addressModeU = _sg_vk_sampler_address_mode(desc->wrap_u); + create_info.addressModeV = _sg_vk_sampler_address_mode(desc->wrap_v); + create_info.addressModeW = _sg_vk_sampler_address_mode(desc->wrap_w); + create_info.mipLodBias = 0.0f; + if (desc->max_anisotropy > 1) { + create_info.anisotropyEnable = VK_TRUE; + create_info.maxAnisotropy = (float)desc->max_anisotropy; + } + if (desc->compare != SG_COMPAREFUNC_NEVER) { + create_info.compareEnable = VK_TRUE; + create_info.compareOp = _sg_vk_compare_op(desc->compare); + } + create_info.minLod = desc->min_lod; + create_info.maxLod = desc->max_lod; + create_info.borderColor = _sg_vk_sampler_border_color(desc->border_color); + VkResult res = vkCreateSampler(_sg.vk.dev, &create_info, 0, &smp->vk.smp); + if (res != VK_SUCCESS) { + _SG_ERROR(VULKAN_CREATE_SAMPLER_FAILED); + return SG_RESOURCESTATE_FAILED; + } + SOKOL_ASSERT(smp->vk.smp); + _sg_vk_set_object_label(VK_OBJECT_TYPE_SAMPLER, (uint64_t)smp->vk.smp, desc->label); + + // record sampler descriptor data + smp->vk.descriptor_size = _sg.vk.descriptor_buffer_props.samplerDescriptorSize; + if (_SG_VK_MAX_DESCRIPTOR_DATA_SIZE < smp->vk.descriptor_size) { + _SG_ERROR(VULKAN_SAMPLER_MAX_DESCRIPTOR_SIZE); + return SG_RESOURCESTATE_FAILED; + } + _SG_STRUCT(VkDescriptorGetInfoEXT, get_info); + get_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_GET_INFO_EXT; + get_info.type = VK_DESCRIPTOR_TYPE_SAMPLER; + get_info.data.pSampler = &smp->vk.smp; + _sg.vk.ext.get_descriptor(_sg.vk.dev, &get_info, smp->vk.descriptor_size, &smp->vk.descriptor_data); + + return SG_RESOURCESTATE_VALID; +} + +_SOKOL_PRIVATE void _sg_vk_discard_sampler(_sg_sampler_t* smp) { + SOKOL_ASSERT(smp); + if (smp->vk.smp) { + _sg_vk_delete_queue_add(_sg_vk_sampler_destructor, (void*)smp->vk.smp); + smp->vk.smp = 0; + } +} + +_SOKOL_PRIVATE _sg_vk_shader_func_t _sg_vk_create_shader_func(const sg_shader_function* func, const char* label) { + SOKOL_ASSERT(_sg.vk.dev); + SOKOL_ASSERT(func); + SOKOL_ASSERT(func->bytecode.ptr && (func->bytecode.size > 0)); + SOKOL_ASSERT(func->entry); + + _SG_STRUCT(_sg_vk_shader_func_t, vk_func); + _sg_strcpy(&vk_func.entry, func->entry); + + _SG_STRUCT(VkShaderModuleCreateInfo, create_info); + create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + create_info.codeSize = func->bytecode.size; + create_info.pCode = (uint32_t*)func->bytecode.ptr; + VkResult res = vkCreateShaderModule(_sg.vk.dev, &create_info, 0, &vk_func.module); + if (VK_SUCCESS != res) { + _SG_ERROR(VULKAN_CREATE_SHADER_MODULE_FAILED); + } else { + SOKOL_ASSERT(vk_func.module); + _sg_vk_set_object_label(VK_OBJECT_TYPE_SHADER_MODULE, (uint64_t)vk_func.module, label); + } + return vk_func; +} + +_SOKOL_PRIVATE void _sg_vk_discard_shader_func(_sg_vk_shader_func_t* func) { + SOKOL_ASSERT(_sg.vk.dev); + SOKOL_ASSERT(func); + if (func->module) { + _sg_vk_delete_queue_add(_sg_vk_shader_module_destructor, (void*)func->module); + func->module = 0; + } +} + +_SOKOL_PRIVATE bool _sg_vk_ensure_spirv_bindslot_ranges(const sg_shader_desc* desc) { + SOKOL_ASSERT(desc); + for (size_t i = 0; i < SG_MAX_UNIFORMBLOCK_BINDSLOTS; i++) { + const sg_shader_uniform_block* ub = &desc->uniform_blocks[i]; + if (ub->stage != SG_SHADERSTAGE_NONE) { + if (ub->spirv_set0_binding_n >= _SG_VK_MAX_UB_DESCRIPTORSET_SLOTS) { + _SG_ERROR(VULKAN_UNIFORMBLOCK_SPIRV_SET0_BINDING_OUT_OF_RANGE); + return false; + } + } + } + for (size_t i = 0; i < SG_MAX_VIEW_BINDSLOTS; i++) { + const sg_shader_view* view = &desc->views[i]; + if (view->texture.stage != SG_SHADERSTAGE_NONE) { + if (view->texture.spirv_set1_binding_n >= _SG_VK_MAX_VIEW_SMP_DESCRIPTORSET_SLOTS) { + _SG_ERROR(VULKAN_TEXTURE_SPIRV_SET1_BINDING_OUT_OF_RANGE); + return false; + } + } + if (view->storage_buffer.stage != SG_SHADERSTAGE_NONE) { + if (view->storage_buffer.spirv_set1_binding_n >= _SG_VK_MAX_VIEW_SMP_DESCRIPTORSET_SLOTS) { + _SG_ERROR(VULKAN_STORAGEBUFFER_SPIRV_SET1_BINDING_OUT_OF_RANGE); + return false; + } + } + if (view->storage_image.stage != SG_SHADERSTAGE_NONE) { + if (view->storage_image.spirv_set1_binding_n >= _SG_VK_MAX_VIEW_SMP_DESCRIPTORSET_SLOTS) { + _SG_ERROR(VULKAN_STORAGEIMAGE_SPIRV_SET1_BINDING_OUT_OF_RANGE); + return false; + } + } + } + for (size_t i = 0; i < SG_MAX_SAMPLER_BINDSLOTS; i++) { + const sg_shader_sampler* smp = &desc->samplers[i]; + if (smp->stage != SG_SHADERSTAGE_NONE) { + if (smp->spirv_set1_binding_n >= _SG_VK_MAX_VIEW_SMP_DESCRIPTORSET_SLOTS) { + _SG_ERROR(VULKAN_SAMPLER_SPIRV_SET1_BINDING_OUT_OF_RANGE); + return false; + } + } + } + return true; +} + +_SOKOL_PRIVATE sg_resource_state _sg_vk_create_shader(_sg_shader_t* shd, const sg_shader_desc* desc) { + SOKOL_ASSERT(shd && desc); + SOKOL_ASSERT(_sg.vk.dev); + SOKOL_ASSERT(shd->vk.vertex_func.module == 0); + SOKOL_ASSERT(shd->vk.fragment_func.module == 0); + SOKOL_ASSERT(shd->vk.compute_func.module == 0); + SOKOL_ASSERT(shd->vk.ub_dsl == 0); + SOKOL_ASSERT(shd->vk.view_smp_dsl == 0); + + if (!_sg_vk_ensure_spirv_bindslot_ranges(desc)) { + return SG_RESOURCESTATE_FAILED; + } + + // build shader modules + bool shd_valid = true; + if (desc->vertex_func.bytecode.ptr) { + shd->vk.vertex_func = _sg_vk_create_shader_func(&desc->vertex_func, desc->label); + shd_valid &= shd->vk.vertex_func.module != 0; + } + if (desc->fragment_func.bytecode.ptr) { + shd->vk.fragment_func = _sg_vk_create_shader_func(&desc->fragment_func, desc->label); + shd_valid &= shd->vk.fragment_func.module != 0; + } + if (desc->compute_func.bytecode.ptr) { + shd->vk.compute_func = _sg_vk_create_shader_func(&desc->compute_func, desc->label); + shd_valid &= shd->vk.compute_func.module != 0; + } + if (!shd_valid) { + _sg_vk_discard_shader_func(&shd->vk.vertex_func); + _sg_vk_discard_shader_func(&shd->vk.fragment_func); + _sg_vk_discard_shader_func(&shd->vk.compute_func); + return SG_RESOURCESTATE_FAILED; + } + + // descriptor set layouts and pipeline layout + VkResult res; + _SG_STRUCT(VkDescriptorSetLayoutBinding, dsl_entries[_SG_VK_MAX_VIEW_SMP_DESCRIPTORSET_ENTRIES]); + _SG_STRUCT(VkDescriptorSetLayoutCreateInfo, dsl_create_info); + size_t dsl_index = 0; + for (size_t i = 0; i < SG_MAX_UNIFORMBLOCK_BINDSLOTS; i++) { + if (shd->cmn.uniform_blocks[i].stage == SG_SHADERSTAGE_NONE) { + continue; + } + shd->vk.ub_set0_bnd_n[i] = desc->uniform_blocks[i].spirv_set0_binding_n; + VkDescriptorSetLayoutBinding* dsl_entry = &dsl_entries[dsl_index]; + dsl_entry->binding = shd->vk.ub_set0_bnd_n[i]; + dsl_entry->descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + dsl_entry->descriptorCount = 1; + dsl_entry->stageFlags = _sg_vk_shader_stage(shd->cmn.uniform_blocks[i].stage); + dsl_index += 1; + } + dsl_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + dsl_create_info.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; + dsl_create_info.bindingCount = dsl_index; + dsl_create_info.pBindings = dsl_entries; + res = vkCreateDescriptorSetLayout(_sg.vk.dev, &dsl_create_info, 0, &shd->vk.ub_dsl); + if (res != VK_SUCCESS) { + _SG_ERROR(VULKAN_CREATE_DESCRIPTOR_SET_LAYOUT_FAILED); + return SG_RESOURCESTATE_FAILED; + } + + // store uniform descriptor set size and descriptor offsets + _sg.vk.ext.get_descriptor_set_layout_size(_sg.vk.dev, shd->vk.ub_dsl, &shd->vk.ub_dset_size); + for (size_t i = 0; i < SG_MAX_UNIFORMBLOCK_BINDSLOTS; i++) { + if (shd->cmn.uniform_blocks[i].stage == SG_SHADERSTAGE_NONE) { + continue; + } + const uint8_t vk_bnd = shd->vk.ub_set0_bnd_n[i]; + VkDeviceSize dset_offset = 0; + _sg.vk.ext.get_descriptor_set_layout_binding_offset(_sg.vk.dev, shd->vk.ub_dsl, vk_bnd, &dset_offset); + shd->vk.ub_dset_offsets[i] = dset_offset; + } + + _sg_clear(dsl_entries, sizeof(dsl_entries)); + _sg_clear(&dsl_create_info, sizeof(dsl_create_info)); + dsl_index = 0; + for (size_t i = 0; i < SG_MAX_VIEW_BINDSLOTS; i++) { + if (shd->cmn.views[i].stage == SG_SHADERSTAGE_NONE) { + continue; + } + SOKOL_ASSERT(dsl_index < _SG_VK_MAX_VIEW_SMP_DESCRIPTORSET_ENTRIES); + VkDescriptorSetLayoutBinding* dsl_entry = &dsl_entries[dsl_index]; + dsl_entry->stageFlags = _sg_vk_shader_stage(shd->cmn.views[i].stage); + if (shd->cmn.views[i].view_type == SG_VIEWTYPE_TEXTURE) { + shd->vk.view_set1_bnd_n[i] = desc->views[i].texture.spirv_set1_binding_n; + dsl_entry->descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + } else if (shd->cmn.views[i].view_type == SG_VIEWTYPE_STORAGEBUFFER) { + shd->vk.view_set1_bnd_n[i] = desc->views[i].storage_buffer.spirv_set1_binding_n; + dsl_entry->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + } else if (shd->cmn.views[i].view_type == SG_VIEWTYPE_STORAGEIMAGE) { + shd->vk.view_set1_bnd_n[i] = desc->views[i].storage_image.spirv_set1_binding_n; + dsl_entry->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + } else { + SOKOL_UNREACHABLE; + } + dsl_entry->binding = shd->vk.view_set1_bnd_n[i]; + dsl_entry->descriptorCount = 1; + dsl_index += 1; + } + for (size_t i = 0; i < SG_MAX_SAMPLER_BINDSLOTS; i++) { + if (shd->cmn.samplers[i].stage == SG_SHADERSTAGE_NONE) { + continue; + } + shd->vk.smp_set1_bnd_n[i] = desc->samplers[i].spirv_set1_binding_n; + SOKOL_ASSERT(dsl_index < _SG_VK_MAX_VIEW_SMP_DESCRIPTORSET_ENTRIES); + VkDescriptorSetLayoutBinding* dsl_entry = &dsl_entries[dsl_index]; + dsl_entry->binding = shd->vk.smp_set1_bnd_n[i]; + dsl_entry->descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; + dsl_entry->descriptorCount = 1; + dsl_entry->stageFlags = _sg_vk_shader_stage(shd->cmn.samplers[i].stage); + dsl_index += 1; + } + dsl_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + dsl_create_info.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; + dsl_create_info.bindingCount = dsl_index; + dsl_create_info.pBindings = dsl_entries; + res = vkCreateDescriptorSetLayout(_sg.vk.dev, &dsl_create_info, 0, &shd->vk.view_smp_dsl); + if (res != VK_SUCCESS) { + _SG_ERROR(VULKAN_CREATE_DESCRIPTOR_SET_LAYOUT_FAILED); + return SG_RESOURCESTATE_FAILED; + } + + // store view/smp descriptor set size and descriptor offsets + _sg.vk.ext.get_descriptor_set_layout_size(_sg.vk.dev, shd->vk.view_smp_dsl, &shd->vk.view_smp_dset_size); + for (size_t i = 0; i < SG_MAX_VIEW_BINDSLOTS; i++) { + if (shd->cmn.views[i].stage == SG_SHADERSTAGE_NONE) { + continue; + } + const uint8_t vk_bnd = shd->vk.view_set1_bnd_n[i]; + VkDeviceSize dset_offset = 0; + _sg.vk.ext.get_descriptor_set_layout_binding_offset(_sg.vk.dev, shd->vk.view_smp_dsl, vk_bnd, &dset_offset); + shd->vk.view_dset_offsets[i] = dset_offset; + } + for (size_t i = 0; i < SG_MAX_SAMPLER_BINDSLOTS; i++) { + if (shd->cmn.samplers[i].stage == SG_SHADERSTAGE_NONE) { + continue; + } + const uint8_t vk_bnd = shd->vk.smp_set1_bnd_n[i]; + VkDeviceSize dset_offset = 0; + _sg.vk.ext.get_descriptor_set_layout_binding_offset(_sg.vk.dev, shd->vk.view_smp_dsl, vk_bnd, &dset_offset); + shd->vk.smp_dset_offsets[i] = dset_offset; + } + + VkDescriptorSetLayout set_layouts[_SG_VK_NUM_DESCRIPTORSETS] = { + shd->vk.ub_dsl, + shd->vk.view_smp_dsl, + }; + _SG_STRUCT(VkPipelineLayoutCreateInfo, pl_create_info); + pl_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pl_create_info.setLayoutCount = _SG_VK_NUM_DESCRIPTORSETS; + pl_create_info.pSetLayouts = set_layouts; + res = vkCreatePipelineLayout(_sg.vk.dev, &pl_create_info, 0, &shd->vk.pip_layout); + if (res != VK_SUCCESS) { + _SG_ERROR(VULKAN_CREATE_PIPELINE_LAYOUT_FAILED); + return SG_RESOURCESTATE_FAILED; + } + return SG_RESOURCESTATE_VALID; +} + +_SOKOL_PRIVATE void _sg_vk_discard_shader(_sg_shader_t* shd) { + SOKOL_ASSERT(shd); + SOKOL_ASSERT(_sg.vk.dev); + _sg_vk_discard_shader_func(&shd->vk.vertex_func); + _sg_vk_discard_shader_func(&shd->vk.fragment_func); + _sg_vk_discard_shader_func(&shd->vk.compute_func); + if (shd->vk.pip_layout) { + _sg_vk_delete_queue_add(_sg_vk_pipelinelayout_destructor, (void*)shd->vk.pip_layout); + shd->vk.pip_layout = 0; + } + if (shd->vk.ub_dsl) { + _sg_vk_delete_queue_add(_sg_vk_descriptorsetlayout_destructor, (void*)shd->vk.ub_dsl); + shd->vk.ub_dsl = 0; + } + if (shd->vk.view_smp_dsl) { + _sg_vk_delete_queue_add(_sg_vk_descriptorsetlayout_destructor, (void*)shd->vk.view_smp_dsl); + shd->vk.view_smp_dsl = 0; + } +} + +_SOKOL_PRIVATE sg_resource_state _sg_vk_create_pipeline(_sg_pipeline_t* pip, const sg_pipeline_desc* desc) { + SOKOL_ASSERT(pip && desc); + SOKOL_ASSERT(_sg.vk.dev); + VkResult res; + + const _sg_shader_t* shd = _sg_shader_ref_ptr(&pip->cmn.shader); + SOKOL_ASSERT(shd->vk.pip_layout); + if (pip->cmn.is_compute) { + SOKOL_ASSERT(shd->vk.compute_func.module); + _SG_STRUCT(VkComputePipelineCreateInfo, pip_create_info); + pip_create_info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; + pip_create_info.flags = VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; + pip_create_info.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + pip_create_info.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT; + pip_create_info.stage.module = shd->vk.compute_func.module; + pip_create_info.stage.pName = shd->vk.compute_func.entry.buf; + pip_create_info.layout = shd->vk.pip_layout; + res = vkCreateComputePipelines(_sg.vk.dev, VK_NULL_HANDLE, 1, &pip_create_info, 0, &pip->vk.pip); + if (res != VK_SUCCESS) { + _SG_ERROR(VULKAN_CREATE_COMPUTE_PIPELINE_FAILED); + return SG_RESOURCESTATE_FAILED; + } + } else { + uint32_t num_stages = 0; + _SG_STRUCT(VkPipelineShaderStageCreateInfo, stages[2]); + if (shd->vk.vertex_func.module) { + stages[num_stages].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + stages[num_stages].stage = VK_SHADER_STAGE_VERTEX_BIT; + stages[num_stages].module = shd->vk.vertex_func.module; + stages[num_stages].pName = shd->vk.vertex_func.entry.buf; + num_stages += 1; + } + if (shd->vk.fragment_func.module) { + stages[num_stages].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + stages[num_stages].stage = VK_SHADER_STAGE_FRAGMENT_BIT; + stages[num_stages].module = shd->vk.fragment_func.module; + stages[num_stages].pName = shd->vk.fragment_func.entry.buf; + num_stages += 1; + } + + uint32_t num_vtx_bnds = 0; + _SG_STRUCT(VkVertexInputBindingDescription, vtx_bnds[SG_MAX_VERTEXBUFFER_BINDSLOTS]); + for (uint32_t vbl_idx = 0; vbl_idx < SG_MAX_VERTEXBUFFER_BINDSLOTS; vbl_idx++, num_vtx_bnds++) { + const sg_vertex_buffer_layout_state* vbl_state = &desc->layout.buffers[vbl_idx]; + if (0 == vbl_state->stride) { + break; + } + vtx_bnds[vbl_idx].binding = vbl_idx; + vtx_bnds[vbl_idx].stride = (uint32_t)vbl_state->stride; + vtx_bnds[vbl_idx].inputRate = _sg_vk_vertex_input_rate(vbl_state->step_func); + } + + uint32_t num_vtx_attrs = 0; + _SG_STRUCT(VkVertexInputAttributeDescription, vtx_attrs[SG_MAX_VERTEX_ATTRIBUTES]); + for (uint32_t va_idx = 0; va_idx < SG_MAX_VERTEX_ATTRIBUTES; va_idx++, num_vtx_attrs++) { + const sg_vertex_attr_state* va_state = &desc->layout.attrs[va_idx]; + if (SG_VERTEXFORMAT_INVALID == va_state->format) { + break; + } + const uint32_t vbl_idx = (uint32_t)va_state->buffer_index; + SOKOL_ASSERT(vbl_idx < SG_MAX_VERTEXBUFFER_BINDSLOTS); + SOKOL_ASSERT(pip->cmn.vertex_buffer_layout_active[vbl_idx]); + vtx_attrs[va_idx].location = va_idx; + vtx_attrs[va_idx].binding = vbl_idx; + vtx_attrs[va_idx].format = _sg_vk_vertex_format(va_state->format); + vtx_attrs[va_idx].offset = (uint32_t)va_state->offset; + } + + _SG_STRUCT(VkPipelineVertexInputStateCreateInfo, vi_state); + vi_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vi_state.vertexBindingDescriptionCount = num_vtx_bnds; + vi_state.pVertexBindingDescriptions = vtx_bnds; + vi_state.vertexAttributeDescriptionCount = num_vtx_attrs; + vi_state.pVertexAttributeDescriptions = vtx_attrs; + + _SG_STRUCT(VkPipelineInputAssemblyStateCreateInfo, ia_state); + ia_state.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + ia_state.topology = _sg_vk_primitive_topology(desc->primitive_type); + ia_state.primitiveRestartEnable = VK_FALSE; // FIXME: needs 'primitiveTopologyRestart feature enabled' + + _SG_STRUCT(VkPipelineViewportStateCreateInfo, vp_state); + vp_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + vp_state.viewportCount = 1; + vp_state.scissorCount = 1; + + _SG_STRUCT(VkPipelineRasterizationStateCreateInfo, rs_state); + rs_state.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rs_state.depthClampEnable = false; + rs_state.rasterizerDiscardEnable = false; + rs_state.polygonMode = VK_POLYGON_MODE_FILL; + rs_state.cullMode = _sg_vk_cullmode(desc->cull_mode); + rs_state.frontFace = _sg_vk_frontface(desc->face_winding); + rs_state.depthBiasEnable = ((int32_t)desc->depth.bias) != 0; + rs_state.depthBiasConstantFactor = desc->depth.bias; + rs_state.depthBiasClamp = desc->depth.bias_clamp; + rs_state.depthBiasSlopeFactor = desc->depth.bias_slope_scale; + rs_state.lineWidth = 1.0f; + + _SG_STRUCT(VkPipelineMultisampleStateCreateInfo, ms_state); + ms_state.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + ms_state.rasterizationSamples = (VkSampleCountFlagBits)desc->sample_count; + ms_state.alphaToCoverageEnable = desc->alpha_to_coverage_enabled; + + _SG_STRUCT(VkPipelineDepthStencilStateCreateInfo, ds_state); + ds_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + ds_state.depthTestEnable = desc->depth.compare != SG_COMPAREFUNC_ALWAYS; + ds_state.depthWriteEnable = desc->depth.write_enabled; + ds_state.depthCompareOp = _sg_vk_compare_op(desc->depth.compare); + ds_state.depthBoundsTestEnable = false; + ds_state.stencilTestEnable = desc->stencil.enabled; + ds_state.front.failOp = _sg_vk_stencil_op(desc->stencil.front.fail_op); + ds_state.front.passOp = _sg_vk_stencil_op(desc->stencil.front.pass_op); + ds_state.front.depthFailOp = _sg_vk_stencil_op(desc->stencil.front.depth_fail_op); + ds_state.front.compareOp = _sg_vk_compare_op(desc->stencil.front.compare); + ds_state.front.compareMask = desc->stencil.read_mask; + ds_state.front.writeMask = desc->stencil.write_mask; + ds_state.front.reference = desc->stencil.ref; + ds_state.back.failOp = _sg_vk_stencil_op(desc->stencil.back.fail_op); + ds_state.back.passOp = _sg_vk_stencil_op(desc->stencil.back.pass_op); + ds_state.back.depthFailOp = _sg_vk_stencil_op(desc->stencil.back.depth_fail_op); + ds_state.back.compareOp = _sg_vk_compare_op(desc->stencil.back.compare); + ds_state.back.compareMask = desc->stencil.read_mask; + ds_state.back.writeMask = desc->stencil.write_mask; + ds_state.back.reference = desc->stencil.ref; + + _SG_STRUCT(VkPipelineColorBlendAttachmentState, att_states[SG_MAX_COLOR_ATTACHMENTS]); + SOKOL_ASSERT(desc->color_count < SG_MAX_COLOR_ATTACHMENTS); + for (int i = 0; i < desc->color_count; i++) { + att_states[i].blendEnable = desc->colors[i].blend.enabled; + att_states[i].srcColorBlendFactor = _sg_vk_blend_factor(desc->colors[i].blend.src_factor_rgb); + att_states[i].dstColorBlendFactor = _sg_vk_blend_factor(desc->colors[i].blend.dst_factor_rgb); + att_states[i].colorBlendOp = _sg_vk_blend_op(desc->colors[i].blend.op_rgb); + att_states[i].srcAlphaBlendFactor = _sg_vk_blend_factor(desc->colors[i].blend.src_factor_alpha); + att_states[i].dstAlphaBlendFactor = _sg_vk_blend_factor(desc->colors[i].blend.dst_factor_alpha); + att_states[i].alphaBlendOp = _sg_vk_blend_op(desc->colors[i].blend.op_alpha); + att_states[i].colorWriteMask = _sg_vk_color_write_mask(desc->colors[i].write_mask); + } + + _SG_STRUCT(VkPipelineColorBlendStateCreateInfo, cb_state); + cb_state.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + cb_state.logicOpEnable = false; + cb_state.attachmentCount = (uint32_t)desc->color_count; + cb_state.pAttachments = att_states; + cb_state.blendConstants[0] = desc->blend_color.r; + cb_state.blendConstants[1] = desc->blend_color.g; + cb_state.blendConstants[2] = desc->blend_color.b; + cb_state.blendConstants[3] = desc->blend_color.a; + + _SG_STRUCT(VkFormat, color_formats[SG_MAX_COLOR_ATTACHMENTS]); + SOKOL_ASSERT(desc->color_count <= SG_MAX_COLOR_ATTACHMENTS); + for (int i = 0; i < desc->color_count; i++) { + color_formats[i] = _sg_vk_format(desc->colors[i].pixel_format); + } + _SG_STRUCT(VkPipelineRenderingCreateInfo, rnd_state); + rnd_state.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO; + rnd_state.colorAttachmentCount = (uint32_t)desc->color_count; + rnd_state.pColorAttachmentFormats = color_formats; + rnd_state.depthAttachmentFormat = _sg_vk_format(desc->depth.pixel_format); + if (_sg_is_depth_stencil_format(desc->depth.pixel_format)) { + rnd_state.stencilAttachmentFormat = _sg_vk_format(desc->depth.pixel_format); + } else { + rnd_state.stencilAttachmentFormat = VK_FORMAT_UNDEFINED; + } + VkDynamicState dyn_states[2] = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR, + }; + _SG_STRUCT(VkPipelineDynamicStateCreateInfo, dyn_state); + dyn_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dyn_state.dynamicStateCount = 2; + dyn_state.pDynamicStates = dyn_states; + + _SG_STRUCT(VkGraphicsPipelineCreateInfo, pip_create_info); + pip_create_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pip_create_info.pNext = &rnd_state; + pip_create_info.flags = VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; + pip_create_info.stageCount = num_stages; + pip_create_info.pStages = stages; + pip_create_info.pVertexInputState = &vi_state; + pip_create_info.pInputAssemblyState = &ia_state; + pip_create_info.pViewportState = &vp_state; + pip_create_info.pRasterizationState = &rs_state; + pip_create_info.pMultisampleState = &ms_state; + pip_create_info.pDepthStencilState = &ds_state; + pip_create_info.pColorBlendState = &cb_state; + pip_create_info.pDynamicState = &dyn_state; + pip_create_info.layout = shd->vk.pip_layout; + + res = vkCreateGraphicsPipelines(_sg.vk.dev, VK_NULL_HANDLE, 1, &pip_create_info, 0, &pip->vk.pip); + if (res != VK_SUCCESS) { + _SG_ERROR(VULKAN_CREATE_GRAPHICS_PIPELINE_FAILED); + return SG_RESOURCESTATE_FAILED; + } + } + SOKOL_ASSERT(pip->vk.pip); + _sg_vk_set_object_label(VK_OBJECT_TYPE_PIPELINE, (uint64_t)pip->vk.pip, desc->label); + return SG_RESOURCESTATE_VALID; +} + +_SOKOL_PRIVATE void _sg_vk_discard_pipeline(_sg_pipeline_t* pip) { + SOKOL_ASSERT(pip); + if (pip->vk.pip) { + _sg_vk_delete_queue_add(_sg_vk_pipeline_destructor, (void*)pip->vk.pip); + pip->vk.pip = 0; + } +} + +_SOKOL_PRIVATE sg_resource_state _sg_vk_create_view(_sg_view_t* view, const sg_view_desc* desc) { + SOKOL_ASSERT(view && desc); + SOKOL_ASSERT(_sg.vk.dev); + SOKOL_ASSERT(0 == view->vk.img_view); + VkResult res; + _SG_STRUCT(VkDescriptorGetInfoEXT, get_info); + get_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_GET_INFO_EXT; + if (view->cmn.type == SG_VIEWTYPE_STORAGEBUFFER) { + // record descriptor data for storage buffer + view->vk.descriptor_size = _sg.vk.descriptor_buffer_props.storageBufferDescriptorSize; + if (_SG_VK_MAX_DESCRIPTOR_DATA_SIZE < view->vk.descriptor_size) { + _SG_ERROR(VULKAN_VIEW_MAX_DESCRIPTOR_SIZE); + return SG_RESOURCESTATE_FAILED; + } + const _sg_buffer_t* buf = _sg_buffer_ref_ptr(&view->cmn.buf.ref); + SOKOL_ASSERT(buf->vk.dev_addr); + _SG_STRUCT(VkDescriptorAddressInfoEXT, addr_info); + addr_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_ADDRESS_INFO_EXT; + addr_info.address = buf->vk.dev_addr + (VkDeviceSize)view->cmn.buf.offset; + addr_info.range = (VkDeviceSize)(buf->cmn.size - view->cmn.buf.offset); + get_info.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + get_info.data.pStorageBuffer = &addr_info; + _sg.vk.ext.get_descriptor(_sg.vk.dev, &get_info, view->vk.descriptor_size, &view->vk.descriptor_data); + } else { + // create image view object + const _sg_image_t* img = _sg_image_ref_ptr(&view->cmn.img.ref); + SOKOL_ASSERT(img->vk.img); + SOKOL_ASSERT(view->cmn.img.mip_level_count >= 1); + SOKOL_ASSERT(view->cmn.img.slice_count >= 1); + _SG_STRUCT(VkImageViewCreateInfo, create_info); + create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + create_info.image = img->vk.img; + if (view->cmn.type == SG_VIEWTYPE_TEXTURE) { + create_info.viewType = _sg_vk_texture_image_view_type(img->cmn.type); + } else { + create_info.viewType = _sg_vk_attachment_image_view_type(img->cmn.type); + } + create_info.format = _sg_vk_format(img->cmn.pixel_format); + if (view->cmn.type == SG_VIEWTYPE_DEPTHSTENCILATTACHMENT) { + create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + if (_sg_is_depth_stencil_format(img->cmn.pixel_format)) { + create_info.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; + } + } else if (_sg_is_depth_or_depth_stencil_format(img->cmn.pixel_format)) { + create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + } else { + create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + } + create_info.subresourceRange.baseMipLevel = (uint32_t)view->cmn.img.mip_level; + create_info.subresourceRange.levelCount = (uint32_t)view->cmn.img.mip_level_count; + create_info.subresourceRange.baseArrayLayer = (uint32_t)view->cmn.img.slice; + create_info.subresourceRange.layerCount = (uint32_t)view->cmn.img.slice_count; + res = vkCreateImageView(_sg.vk.dev, &create_info, 0, &view->vk.img_view); + if (res != VK_SUCCESS) { + _SG_ERROR(VULKAN_CREATE_IMAGE_VIEW_FAILED); + return SG_RESOURCESTATE_FAILED; + } + SOKOL_ASSERT(view->vk.img_view); + _sg_vk_set_object_label(VK_OBJECT_TYPE_IMAGE_VIEW, (uint64_t)view->vk.img_view, desc->label); + + // record descriptor data for storage images and textures + if ((view->cmn.type == SG_VIEWTYPE_STORAGEIMAGE) || (view->cmn.type == SG_VIEWTYPE_TEXTURE)) { + _SG_STRUCT(VkDescriptorImageInfo, img_info); + img_info.imageView = view->vk.img_view; + if (view->cmn.type == SG_VIEWTYPE_STORAGEIMAGE) { + view->vk.descriptor_size = _sg.vk.descriptor_buffer_props.storageImageDescriptorSize; + img_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + get_info.type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + get_info.data.pStorageImage = &img_info; + } else { + view->vk.descriptor_size = _sg.vk.descriptor_buffer_props.sampledImageDescriptorSize; + img_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + get_info.type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + get_info.data.pSampledImage = &img_info; + } + if (_SG_VK_MAX_DESCRIPTOR_DATA_SIZE < view->vk.descriptor_size) { + _SG_ERROR(VULKAN_VIEW_MAX_DESCRIPTOR_SIZE); + return SG_RESOURCESTATE_FAILED; + } + _sg.vk.ext.get_descriptor(_sg.vk.dev, &get_info, view->vk.descriptor_size, &view->vk.descriptor_data); + } + } + return SG_RESOURCESTATE_VALID; +} + +_SOKOL_PRIVATE void _sg_vk_discard_view(_sg_view_t* view) { + SOKOL_ASSERT(view); + if (view->vk.img_view) { + _sg_vk_delete_queue_add(_sg_vk_image_view_destructor, (void*)view->vk.img_view); + view->vk.img_view = 0; + } +} + +_SOKOL_PRIVATE void _sg_vk_apply_viewport(int x, int y, int w, int h, bool origin_top_left) { + SOKOL_ASSERT(_sg.vk.frame.cmd_buf); + _SG_STRUCT(VkViewport, vp); + vp.x = (float) x; + vp.width = (float) w; + vp.height = (float) -h; + vp.maxDepth = 1.0f; + if (origin_top_left) { + vp.y = (float)(y + h); + } else { + vp.y = (float)(_sg.cur_pass.dim.height - y); + } + vkCmdSetViewport(_sg.vk.frame.cmd_buf, 0, 1, &vp); +} + +_SOKOL_PRIVATE void _sg_vk_apply_scissor_rect(int x, int y, int w, int h, bool origin_top_left) { + SOKOL_ASSERT(_sg.vk.frame.cmd_buf); + const _sg_recti_t clip = _sg_clipi(x, y, w, h, _sg.cur_pass.dim.width, _sg.cur_pass.dim.height); + _SG_STRUCT(VkRect2D, rect); + rect.offset.x = clip.x; + rect.offset.y = (origin_top_left ? clip.y : (_sg.cur_pass.dim.height - (clip.y + clip.h))); + rect.extent.width = (uint32_t) clip.w; + rect.extent.height = (uint32_t) clip.h; + vkCmdSetScissor(_sg.vk.frame.cmd_buf, 0, 1, &rect); +} + +_SOKOL_PRIVATE void _sg_vk_init_color_attachment_info(VkRenderingAttachmentInfo* info, const sg_color_attachment_action* action, VkImageView color_view, VkImageView resolve_view) { + info->sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO; + info->imageView = color_view; + info->imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + if (resolve_view) { + info->resolveMode = VK_RESOLVE_MODE_AVERAGE_BIT; + info->resolveImageView = resolve_view; + info->resolveImageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + } else { + info->resolveMode = VK_RESOLVE_MODE_NONE; + info->resolveImageView = 0; + info->resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED; + } + info->loadOp = _sg_vk_load_op(action->load_action); + info->storeOp = _sg_vk_store_op(action->store_action); + info->clearValue.color.float32[0] = action->clear_value.r; + info->clearValue.color.float32[1] = action->clear_value.g; + info->clearValue.color.float32[2] = action->clear_value.b; + info->clearValue.color.float32[3] = action->clear_value.a; +} + +_SOKOL_PRIVATE void _sg_vk_init_depth_attachment_info(VkRenderingAttachmentInfo* info, const sg_depth_attachment_action* action, VkImageView ds_view) { + info->sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO; + info->imageView = ds_view; + info->imageLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; + info->resolveMode = VK_RESOLVE_MODE_NONE; + info->loadOp = _sg_vk_load_op(action->load_action); + info->storeOp = _sg_vk_store_op(action->store_action); + info->clearValue.depthStencil.depth = action->clear_value; +} + +_SOKOL_PRIVATE void _sg_vk_init_stencil_attachment_info(VkRenderingAttachmentInfo* info, const sg_stencil_attachment_action* action, VkImageView ds_view) { + info->sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO; + info->imageView = ds_view; + info->imageLayout = VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL; + info->resolveMode = VK_RESOLVE_MODE_NONE; + info->loadOp = _sg_vk_load_op(action->load_action); + info->storeOp = _sg_vk_store_op(action->store_action); + info->clearValue.depthStencil.stencil = action->clear_value; +} + +_SOKOL_PRIVATE void _sg_vk_begin_compute_pass(VkCommandBuffer cmd_buf, const sg_pass* pass) { + // FIXME: nothing to do here? + _SOKOL_UNUSED(cmd_buf && pass); +} + +_SOKOL_PRIVATE void _sg_vk_begin_render_pass(VkCommandBuffer cmd_buf, const sg_pass* pass, const _sg_attachments_ptrs_t* atts) { + const sg_pass_action* action = &pass->action; + const bool is_swapchain_pass = atts->empty; + + _SG_STRUCT(VkRenderingAttachmentInfo, color_att_infos[SG_MAX_COLOR_ATTACHMENTS]); + _SG_STRUCT(VkRenderingAttachmentInfo, depth_att_info); + _SG_STRUCT(VkRenderingAttachmentInfo, stencil_att_info); + _SG_STRUCT(VkRenderingInfo, render_info); + render_info.sType = VK_STRUCTURE_TYPE_RENDERING_INFO; + render_info.renderArea.extent.width = (uint32_t)_sg.cur_pass.dim.width; + render_info.renderArea.extent.height = (uint32_t)_sg.cur_pass.dim.height; + render_info.layerCount = 1; + + if (is_swapchain_pass) { + _sg.vk.swapchain = pass->swapchain.vulkan; + SOKOL_ASSERT(_sg.vk.swapchain.render_view); + if (pass->swapchain.sample_count > 1) { + SOKOL_ASSERT(_sg.vk.swapchain.resolve_view); + } + SOKOL_ASSERT(_sg.vk.swapchain.present_complete_semaphore); + SOKOL_ASSERT(_sg.vk.swapchain.render_finished_semaphore); + // FIXME: need to support multiple present_complete_semaphores + SOKOL_ASSERT(0 == _sg.vk.present_complete_sem); + _sg.vk.present_complete_sem = (VkSemaphore)_sg.vk.swapchain.present_complete_semaphore; + if (0 == _sg.vk.render_finished_sem) { + _sg.vk.render_finished_sem = (VkSemaphore)_sg.vk.swapchain.render_finished_semaphore; + } else { + SOKOL_ASSERT(_sg.vk.render_finished_sem == _sg.vk.swapchain.render_finished_semaphore); + } + VkImageView vk_color_view = (VkImageView)_sg.vk.swapchain.render_view; + VkImageView vk_resolve_view = (VkImageView)_sg.vk.swapchain.resolve_view; + _sg_vk_init_color_attachment_info(&color_att_infos[0], &action->colors[0], vk_color_view, vk_resolve_view); + render_info.colorAttachmentCount = 1; + render_info.pColorAttachments = color_att_infos; + if (_sg.vk.swapchain.depth_stencil_view) { + VkImageView vk_ds_view = (VkImageView)_sg.vk.swapchain.depth_stencil_view; + const bool has_stencil = _sg_is_depth_stencil_format(pass->swapchain.depth_format); + _sg_vk_init_depth_attachment_info(&depth_att_info, &action->depth, vk_ds_view); + render_info.pDepthAttachment = &depth_att_info; + if (has_stencil) { + _sg_vk_init_stencil_attachment_info(&stencil_att_info, &action->stencil, vk_ds_view); + render_info.pStencilAttachment = &stencil_att_info; + } + } + } else { + SOKOL_ASSERT(atts->num_color_views <= SG_MAX_COLOR_ATTACHMENTS); + for (int i = 0; i < atts->num_color_views; i++) { + SOKOL_ASSERT(atts->color_views[i]); + const _sg_view_t* color_view = atts->color_views[i]; + VkImageView vk_color_view = color_view->vk.img_view; + const _sg_view_t* resolve_view = atts->resolve_views[i]; + VkImageView vk_resolve_view = 0; + if (resolve_view) { + vk_resolve_view = resolve_view->vk.img_view; + } + _sg_vk_init_color_attachment_info(&color_att_infos[i], &action->colors[i], vk_color_view, vk_resolve_view); + } + if (atts->num_color_views > 0) { + render_info.colorAttachmentCount = (uint32_t)atts->num_color_views; + render_info.pColorAttachments = color_att_infos; + } + if (atts->ds_view) { + const _sg_view_t* ds_view = atts->ds_view; + const _sg_image_t* ds_image = _sg_image_ref_ptr(&ds_view->cmn.img.ref); + const bool has_stencil = _sg_is_depth_stencil_format(ds_image->cmn.pixel_format); + VkImageView vk_ds_view = ds_view->vk.img_view; + _sg_vk_init_depth_attachment_info(&depth_att_info, &action->depth, vk_ds_view); + render_info.pDepthAttachment = &depth_att_info; + if (has_stencil) { + _sg_vk_init_stencil_attachment_info(&stencil_att_info, &action->stencil, vk_ds_view); + render_info.pStencilAttachment = &stencil_att_info; + } + } + } + vkCmdBeginRendering(cmd_buf, &render_info); + + _SG_STRUCT(VkViewport, vp); + vp.y = _sg.cur_pass.dim.height; + vp.width = (float)_sg.cur_pass.dim.width; + vp.height = (float)-_sg.cur_pass.dim.height; + vp.maxDepth = 1.0f; + vkCmdSetViewport(_sg.vk.frame.cmd_buf, 0, 1, &vp); + + _SG_STRUCT(VkRect2D, rect); + rect.extent.width = (uint32_t)_sg.cur_pass.dim.width; + rect.extent.height = (uint32_t)_sg.cur_pass.dim.height; + vkCmdSetScissor(_sg.vk.frame.cmd_buf, 0, 1, &rect); +} + +_SOKOL_PRIVATE void _sg_vk_begin_pass(const sg_pass* pass, const _sg_attachments_ptrs_t* atts) { + SOKOL_ASSERT(pass && atts); + _sg_vk_acquire_frame_command_buffers(); + SOKOL_ASSERT(_sg.vk.frame.cmd_buf); + _sg_vk_barrier_on_begin_pass(_sg.vk.frame.cmd_buf, pass, atts, _sg.cur_pass.is_compute); + if (_sg.cur_pass.is_compute) { + _sg_vk_begin_compute_pass(_sg.vk.frame.cmd_buf, pass); + } else { + _sg_vk_begin_render_pass(_sg.vk.frame.cmd_buf, pass, atts); + } +} + +_SOKOL_PRIVATE void _sg_vk_end_pass(const _sg_attachments_ptrs_t* atts) { + SOKOL_ASSERT(atts); + SOKOL_ASSERT(_sg.vk.frame.cmd_buf); + if (!_sg.cur_pass.is_compute) { + vkCmdEndRendering(_sg.vk.frame.cmd_buf); + } + _sg_vk_barrier_on_end_pass(_sg.vk.frame.cmd_buf, atts, _sg.cur_pass.is_compute); + _sg_clear(&_sg.vk.swapchain, sizeof(_sg.vk.swapchain)); +} + +_SOKOL_PRIVATE void _sg_vk_commit(void) { + SOKOL_ASSERT(_sg.vk.queue); + SOKOL_ASSERT(_sg.vk.frame.cmd_buf); + _sg_vk_submit_frame_command_buffers(); + _sg.vk.present_complete_sem = 0; + _sg.vk.render_finished_sem = 0; +} + +_SOKOL_PRIVATE void _sg_vk_apply_pipeline(_sg_pipeline_t* pip) { + SOKOL_ASSERT(pip); + SOKOL_ASSERT(pip->vk.pip); + SOKOL_ASSERT(_sg.vk.frame.cmd_buf); + _sg.vk.uniforms_dirty = false; + VkPipelineBindPoint bindpoint = pip->cmn.is_compute + ? VK_PIPELINE_BIND_POINT_COMPUTE + : VK_PIPELINE_BIND_POINT_GRAPHICS; + vkCmdBindPipeline(_sg.vk.frame.cmd_buf, bindpoint, pip->vk.pip); +} + +_SOKOL_PRIVATE bool _sg_vk_apply_bindings(_sg_bindings_ptrs_t* bnd) { + SOKOL_ASSERT(bnd && bnd->pip); + SOKOL_ASSERT(_sg.vk.dev); + SOKOL_ASSERT(_sg.vk.frame.cmd_buf); + VkCommandBuffer cmd_buf = _sg.vk.frame.cmd_buf; + + // track or insert pipeline barriers + _sg_vk_barrier_on_apply_bindings(cmd_buf, bnd, _sg.cur_pass.is_compute); + + if (!_sg.cur_pass.is_compute) { + // bind vertex buffers + // FIXME: could do this in a single call if buffer bindings are guaranteed + // to be continuous (currently that's not checked anywhere), or alternative + // via nullDescriptor robustness feature (which apparently may have performance downsides) + for (size_t i = 0; i < SG_MAX_VERTEXBUFFER_BINDSLOTS; i++) { + if (bnd->vbs[i]) { + VkBuffer vk_buf = bnd->vbs[i]->vk.buf; + VkDeviceSize vk_offset = (VkDeviceSize)bnd->vb_offsets[i]; + vkCmdBindVertexBuffers(cmd_buf, i, 1, &vk_buf, &vk_offset); + } + } + if (bnd->ib) { + VkBuffer vk_buf = bnd->ib->vk.buf; + VkDeviceSize vk_offset = (VkDeviceSize)bnd->ib_offset; + VkIndexType vk_index_type = _sg_vk_index_type(bnd->pip->cmn.index_type); + vkCmdBindIndexBuffer(cmd_buf, vk_buf, vk_offset, vk_index_type); + } + } + + // bind views and samplers + const VkPipelineBindPoint pip_bind_point = _sg.cur_pass.is_compute + ? VK_PIPELINE_BIND_POINT_COMPUTE + : VK_PIPELINE_BIND_POINT_GRAPHICS; + return _sg_vk_bind_view_smp_descriptor_set(cmd_buf, bnd, pip_bind_point); +} + +_SOKOL_PRIVATE void _sg_vk_apply_uniforms(int ub_slot, const sg_range* data) { + SOKOL_ASSERT(_sg.vk.uniform.cur_dev_addr); + SOKOL_ASSERT(data && data->ptr && (data->size > 0)); + SOKOL_ASSERT((ub_slot >= 0) && (ub_slot < SG_MAX_UNIFORMBLOCK_BINDSLOTS)); + + // copy data into uniform buffer and keep track of uniform bind infos + const VkDeviceSize ubuf_offset = _sg_vk_uniform_copy(data); + if (_sg.vk.uniform.overflown) { + _SG_ERROR(VULKAN_UNIFORM_BUFFER_OVERFLOW); + _sg.next_draw_valid = false; + return; + } + _sg.vk.uniform_bindinfos[ub_slot].addr_info.range = data->size; + _sg.vk.uniform_bindinfos[ub_slot].addr_info.address = _sg.vk.uniform.cur_dev_addr + ubuf_offset; + _sg.vk.uniforms_dirty = true; +} + +_SOKOL_PRIVATE void _sg_vk_draw(int base_element, int num_elements, int num_instances, int base_vertex, int base_instance) { + SOKOL_ASSERT(_sg.vk.frame.cmd_buf); + VkCommandBuffer cmd_buf = _sg.vk.frame.cmd_buf; + if (_sg.vk.uniforms_dirty) { + if (!_sg_vk_bind_uniform_descriptor_set(cmd_buf)) { + return; + } + } + if (_sg.use_indexed_draw) { + vkCmdDrawIndexed(cmd_buf, + (uint32_t)num_elements, + (uint32_t)num_instances, + (uint32_t)base_element, + base_vertex, + (uint32_t)base_instance); + } else { + vkCmdDraw(cmd_buf, + (uint32_t)num_elements, + (uint32_t)num_instances, + (uint32_t)base_element, + (uint32_t)base_instance); + } +} + +_SOKOL_PRIVATE void _sg_vk_dispatch(int num_groups_x, int num_groups_y, int num_groups_z) { + SOKOL_ASSERT(_sg.vk.frame.cmd_buf); + VkCommandBuffer cmd_buf = _sg.vk.frame.cmd_buf; + if (_sg.vk.uniforms_dirty) { + if (!_sg_vk_bind_uniform_descriptor_set(cmd_buf)) { + return; + } + } + vkCmdDispatch(cmd_buf, (uint32_t)num_groups_x, (uint32_t)num_groups_y, (uint32_t)num_groups_z); +} + +_SOKOL_PRIVATE void _sg_vk_update_buffer(_sg_buffer_t* buf, const sg_range* data) { + SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0)); + if (buf->cmn.usage.stream_update) { + _sg_vk_acquire_frame_command_buffers(); + _sg_vk_staging_stream_buffer_data(buf, data, 0); + } else { + _sg_vk_staging_copy_buffer_data(buf, data, 0, true); + } +} + +_SOKOL_PRIVATE void _sg_vk_append_buffer(_sg_buffer_t* buf, const sg_range* data, bool new_frame) { + SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0)); + _SOKOL_UNUSED(new_frame); + if (buf->cmn.usage.stream_update) { + _sg_vk_acquire_frame_command_buffers(); + _sg_vk_staging_stream_buffer_data(buf, data, (size_t)buf->cmn.append_pos); + } else { + _sg_vk_staging_copy_buffer_data(buf, data, (size_t)buf->cmn.append_pos, true); + } +} + +_SOKOL_PRIVATE void _sg_vk_update_image(_sg_image_t* img, const sg_image_data* data) { + SOKOL_ASSERT(img && data); + if (img->cmn.usage.stream_update) { + _sg_vk_acquire_frame_command_buffers(); + _sg_vk_staging_stream_image_data(img, data); + } else { + _sg_vk_staging_copy_image_data(img, data, true); + } +} + #endif // ██████ ███████ ███ ██ ███████ ██████ ██ ██████ ██████ █████ ██████ ██ ██ ███████ ███ ██ ██████ @@ -18203,6 +21756,8 @@ static inline void _sg_setup_backend(const sg_desc* desc) { _sg_d3d11_setup_backend(desc); #elif defined(SOKOL_WGPU) _sg_wgpu_setup_backend(desc); + #elif defined(SOKOL_VULKAN) + _sg_vk_setup_backend(desc); #elif defined(SOKOL_DUMMY_BACKEND) _sg_dummy_setup_backend(desc); #else @@ -18219,6 +21774,8 @@ static inline void _sg_discard_backend(void) { _sg_d3d11_discard_backend(); #elif defined(SOKOL_WGPU) _sg_wgpu_discard_backend(); + #elif defined(SOKOL_VULKAN) + _sg_vk_discard_backend(); #elif defined(SOKOL_DUMMY_BACKEND) _sg_dummy_discard_backend(); #else @@ -18235,6 +21792,8 @@ static inline void _sg_reset_state_cache(void) { _sg_d3d11_reset_state_cache(); #elif defined(SOKOL_WGPU) _sg_wgpu_reset_state_cache(); + #elif defined(SOKOL_VULKAN) + _sg_vk_reset_state_cache(); #elif defined(SOKOL_DUMMY_BACKEND) _sg_dummy_reset_state_cache(); #else @@ -18251,6 +21810,8 @@ static inline sg_resource_state _sg_create_buffer(_sg_buffer_t* buf, const sg_bu return _sg_d3d11_create_buffer(buf, desc); #elif defined(SOKOL_WGPU) return _sg_wgpu_create_buffer(buf, desc); + #elif defined(SOKOL_VULKAN) + return _sg_vk_create_buffer(buf, desc); #elif defined(SOKOL_DUMMY_BACKEND) return _sg_dummy_create_buffer(buf, desc); #else @@ -18267,6 +21828,8 @@ static inline void _sg_discard_buffer(_sg_buffer_t* buf) { _sg_d3d11_discard_buffer(buf); #elif defined(SOKOL_WGPU) _sg_wgpu_discard_buffer(buf); + #elif defined(SOKOL_VULKAN) + _sg_vk_discard_buffer(buf); #elif defined(SOKOL_DUMMY_BACKEND) _sg_dummy_discard_buffer(buf); #else @@ -18283,6 +21846,8 @@ static inline sg_resource_state _sg_create_image(_sg_image_t* img, const sg_imag return _sg_d3d11_create_image(img, desc); #elif defined(SOKOL_WGPU) return _sg_wgpu_create_image(img, desc); + #elif defined(SOKOL_VULKAN) + return _sg_vk_create_image(img, desc); #elif defined(SOKOL_DUMMY_BACKEND) return _sg_dummy_create_image(img, desc); #else @@ -18299,6 +21864,8 @@ static inline void _sg_discard_image(_sg_image_t* img) { _sg_d3d11_discard_image(img); #elif defined(SOKOL_WGPU) _sg_wgpu_discard_image(img); + #elif defined(SOKOL_VULKAN) + _sg_vk_discard_image(img); #elif defined(SOKOL_DUMMY_BACKEND) _sg_dummy_discard_image(img); #else @@ -18315,6 +21882,8 @@ static inline sg_resource_state _sg_create_sampler(_sg_sampler_t* smp, const sg_ return _sg_d3d11_create_sampler(smp, desc); #elif defined(SOKOL_WGPU) return _sg_wgpu_create_sampler(smp, desc); + #elif defined(SOKOL_VULKAN) + return _sg_vk_create_sampler(smp, desc); #elif defined(SOKOL_DUMMY_BACKEND) return _sg_dummy_create_sampler(smp, desc); #else @@ -18331,6 +21900,8 @@ static inline void _sg_discard_sampler(_sg_sampler_t* smp) { _sg_d3d11_discard_sampler(smp); #elif defined(SOKOL_WGPU) _sg_wgpu_discard_sampler(smp); + #elif defined(SOKOL_VULKAN) + _sg_vk_discard_sampler(smp); #elif defined(SOKOL_DUMMY_BACKEND) _sg_dummy_discard_sampler(smp); #else @@ -18347,6 +21918,8 @@ static inline sg_resource_state _sg_create_shader(_sg_shader_t* shd, const sg_sh return _sg_d3d11_create_shader(shd, desc); #elif defined(SOKOL_WGPU) return _sg_wgpu_create_shader(shd, desc); + #elif defined(SOKOL_VULKAN) + return _sg_vk_create_shader(shd, desc); #elif defined(SOKOL_DUMMY_BACKEND) return _sg_dummy_create_shader(shd, desc); #else @@ -18363,6 +21936,8 @@ static inline void _sg_discard_shader(_sg_shader_t* shd) { _sg_d3d11_discard_shader(shd); #elif defined(SOKOL_WGPU) _sg_wgpu_discard_shader(shd); + #elif defined(SOKOL_VULKAN) + _sg_vk_discard_shader(shd); #elif defined(SOKOL_DUMMY_BACKEND) _sg_dummy_discard_shader(shd); #else @@ -18379,6 +21954,8 @@ static inline sg_resource_state _sg_create_pipeline(_sg_pipeline_t* pip, const s return _sg_d3d11_create_pipeline(pip, desc); #elif defined(SOKOL_WGPU) return _sg_wgpu_create_pipeline(pip, desc); + #elif defined(SOKOL_VULKAN) + return _sg_vk_create_pipeline(pip, desc); #elif defined(SOKOL_DUMMY_BACKEND) return _sg_dummy_create_pipeline(pip, desc); #else @@ -18395,6 +21972,8 @@ static inline void _sg_discard_pipeline(_sg_pipeline_t* pip) { _sg_d3d11_discard_pipeline(pip); #elif defined(SOKOL_WGPU) _sg_wgpu_discard_pipeline(pip); + #elif defined(SOKOL_VULKAN) + _sg_vk_discard_pipeline(pip); #elif defined(SOKOL_DUMMY_BACKEND) _sg_dummy_discard_pipeline(pip); #else @@ -18411,6 +21990,8 @@ static inline sg_resource_state _sg_create_view(_sg_view_t* view, const sg_view_ return _sg_d3d11_create_view(view, desc); #elif defined(SOKOL_WGPU) return _sg_wgpu_create_view(view, desc); + #elif defined(SOKOL_VULKAN) + return _sg_vk_create_view(view, desc); #elif defined(SOKOL_DUMMY_BACKEND) return _sg_dummy_create_view(view, desc); #else @@ -18427,6 +22008,8 @@ static inline void _sg_discard_view(_sg_view_t* view) { _sg_d3d11_discard_view(view); #elif defined(SOKOL_WGPU) _sg_wgpu_discard_view(view); + #elif defined(SOKOL_VULKAN) + _sg_vk_discard_view(view); #elif defined(SOKOL_DUMMY_BACKEND) _sg_dummy_discard_view(view); #else @@ -18443,6 +22026,8 @@ static inline void _sg_begin_pass(const sg_pass* pass, const _sg_attachments_ptr _sg_d3d11_begin_pass(pass, atts); #elif defined(SOKOL_WGPU) _sg_wgpu_begin_pass(pass, atts); + #elif defined(SOKOL_VULKAN) + _sg_vk_begin_pass(pass, atts); #elif defined(SOKOL_DUMMY_BACKEND) _sg_dummy_begin_pass(pass, atts); #else @@ -18459,6 +22044,8 @@ static inline void _sg_end_pass(const _sg_attachments_ptrs_t* atts) { _sg_d3d11_end_pass(atts); #elif defined(SOKOL_WGPU) _sg_wgpu_end_pass(atts); + #elif defined(SOKOL_VULKAN) + _sg_vk_end_pass(atts); #elif defined(SOKOL_DUMMY_BACKEND) _sg_dummy_end_pass(atts); #else @@ -18475,6 +22062,8 @@ static inline void _sg_apply_viewport(int x, int y, int w, int h, bool origin_to _sg_d3d11_apply_viewport(x, y, w, h, origin_top_left); #elif defined(SOKOL_WGPU) _sg_wgpu_apply_viewport(x, y, w, h, origin_top_left); + #elif defined(SOKOL_VULKAN) + _sg_vk_apply_viewport(x, y, w, h, origin_top_left); #elif defined(SOKOL_DUMMY_BACKEND) _sg_dummy_apply_viewport(x, y, w, h, origin_top_left); #else @@ -18491,6 +22080,8 @@ static inline void _sg_apply_scissor_rect(int x, int y, int w, int h, bool origi _sg_d3d11_apply_scissor_rect(x, y, w, h, origin_top_left); #elif defined(SOKOL_WGPU) _sg_wgpu_apply_scissor_rect(x, y, w, h, origin_top_left); + #elif defined(SOKOL_VULKAN) + _sg_vk_apply_scissor_rect(x, y, w, h, origin_top_left); #elif defined(SOKOL_DUMMY_BACKEND) _sg_dummy_apply_scissor_rect(x, y, w, h, origin_top_left); #else @@ -18507,6 +22098,8 @@ static inline void _sg_apply_pipeline(_sg_pipeline_t* pip) { _sg_d3d11_apply_pipeline(pip); #elif defined(SOKOL_WGPU) _sg_wgpu_apply_pipeline(pip); + #elif defined(SOKOL_VULKAN) + _sg_vk_apply_pipeline(pip); #elif defined(SOKOL_DUMMY_BACKEND) _sg_dummy_apply_pipeline(pip); #else @@ -18523,6 +22116,8 @@ static inline bool _sg_apply_bindings(_sg_bindings_ptrs_t* bnd) { return _sg_d3d11_apply_bindings(bnd); #elif defined(SOKOL_WGPU) return _sg_wgpu_apply_bindings(bnd); + #elif defined(SOKOL_VULKAN) + return _sg_vk_apply_bindings(bnd); #elif defined(SOKOL_DUMMY_BACKEND) return _sg_dummy_apply_bindings(bnd); #else @@ -18539,6 +22134,8 @@ static inline void _sg_apply_uniforms(int ub_slot, const sg_range* data) { _sg_d3d11_apply_uniforms(ub_slot, data); #elif defined(SOKOL_WGPU) _sg_wgpu_apply_uniforms(ub_slot, data); + #elif defined(SOKOL_VULKAN) + _sg_vk_apply_uniforms(ub_slot, data); #elif defined(SOKOL_DUMMY_BACKEND) _sg_dummy_apply_uniforms(ub_slot, data); #else @@ -18555,6 +22152,8 @@ static inline void _sg_draw(int base_element, int num_elements, int num_instance _sg_d3d11_draw(base_element, num_elements, num_instances, base_vertex, base_index); #elif defined(SOKOL_WGPU) _sg_wgpu_draw(base_element, num_elements, num_instances, base_vertex, base_index); + #elif defined(SOKOL_VULKAN) + _sg_vk_draw(base_element, num_elements, num_instances, base_vertex, base_index); #elif defined(SOKOL_DUMMY_BACKEND) _sg_dummy_draw(base_element, num_elements, num_instances, base_vertex, base_index); #else @@ -18571,6 +22170,8 @@ static inline void _sg_dispatch(int num_groups_x, int num_groups_y, int num_grou _sg_d3d11_dispatch(num_groups_x, num_groups_y, num_groups_z); #elif defined(SOKOL_WGPU) _sg_wgpu_dispatch(num_groups_x, num_groups_y, num_groups_z); + #elif defined(SOKOL_VULKAN) + _sg_vk_dispatch(num_groups_x, num_groups_y, num_groups_z); #elif defined(SOKOL_DUMMY_BACKEND) _sg_dummy_dispatch(num_groups_x, num_groups_y, num_groups_z); #else @@ -18587,6 +22188,8 @@ static inline void _sg_commit(void) { _sg_d3d11_commit(); #elif defined(SOKOL_WGPU) _sg_wgpu_commit(); + #elif defined(SOKOL_VULKAN) + _sg_vk_commit(); #elif defined(SOKOL_DUMMY_BACKEND) _sg_dummy_commit(); #else @@ -18603,6 +22206,8 @@ static inline void _sg_update_buffer(_sg_buffer_t* buf, const sg_range* data) { _sg_d3d11_update_buffer(buf, data); #elif defined(SOKOL_WGPU) _sg_wgpu_update_buffer(buf, data); + #elif defined(SOKOL_VULKAN) + _sg_vk_update_buffer(buf, data); #elif defined(SOKOL_DUMMY_BACKEND) _sg_dummy_update_buffer(buf, data); #else @@ -18619,6 +22224,8 @@ static inline void _sg_append_buffer(_sg_buffer_t* buf, const sg_range* data, bo _sg_d3d11_append_buffer(buf, data, new_frame); #elif defined(SOKOL_WGPU) _sg_wgpu_append_buffer(buf, data, new_frame); + #elif defined(SOKOL_VULKAN) + _sg_vk_append_buffer(buf, data, new_frame); #elif defined(SOKOL_DUMMY_BACKEND) _sg_dummy_append_buffer(buf, data, new_frame); #else @@ -18635,6 +22242,8 @@ static inline void _sg_update_image(_sg_image_t* img, const sg_image_data* data) _sg_d3d11_update_image(img, data); #elif defined(SOKOL_WGPU) _sg_wgpu_update_image(img, data); + #elif defined(SOKOL_VULKAN) + _sg_vk_update_image(img, data); #elif defined(SOKOL_DUMMY_BACKEND) _sg_dummy_update_image(img, data); #else @@ -19018,6 +22627,9 @@ _SOKOL_PRIVATE bool _sg_validate_shader_desc(const sg_shader_desc* desc) { #elif defined(SOKOL_WGPU) _sg_u128_t wgsl_group0_bits = _sg_u128(); _sg_u128_t wgsl_group1_bits = _sg_u128(); + #elif defined(SOKOL_VULKAN) + _sg_u128_t spirv_set0_bits = _sg_u128(); + _sg_u128_t spirv_set1_bits = _sg_u128(); #endif for (size_t ub_idx = 0; ub_idx < SG_MAX_UNIFORMBLOCK_BINDSLOTS; ub_idx++) { const sg_shader_uniform_block* ub_desc = &desc->uniform_blocks[ub_idx]; @@ -19034,6 +22646,9 @@ _SOKOL_PRIVATE bool _sg_validate_shader_desc(const sg_shader_desc* desc) { #elif defined(SOKOL_WGPU) _SG_VALIDATE(_sg_validate_slot_bits(wgsl_group0_bits, SG_SHADERSTAGE_NONE, ub_desc->wgsl_group0_binding_n), VALIDATE_SHADERDESC_UNIFORMBLOCK_WGSL_GROUP0_BINDING_COLLISION); wgsl_group0_bits = _sg_validate_set_slot_bit(wgsl_group0_bits, SG_SHADERSTAGE_NONE, ub_desc->wgsl_group0_binding_n); + #elif defined(SOKOL_VULKAN) + _SG_VALIDATE(_sg_validate_slot_bits(spirv_set0_bits, SG_SHADERSTAGE_NONE, ub_desc->spirv_set0_binding_n), VALIDATE_SHADERDESC_UNIFORMBLOCK_SPIRV_SET0_BINDING_COLLISION); + spirv_set0_bits = _sg_validate_set_slot_bit(spirv_set0_bits, SG_SHADERSTAGE_NONE, ub_desc->spirv_set0_binding_n); #endif #if defined(_SOKOL_ANY_GL) bool uniforms_continuous = true; @@ -19084,6 +22699,9 @@ _SOKOL_PRIVATE bool _sg_validate_shader_desc(const sg_shader_desc* desc) { #elif defined(SOKOL_WGPU) _SG_VALIDATE(_sg_validate_slot_bits(wgsl_group1_bits, SG_SHADERSTAGE_NONE, tex_desc->wgsl_group1_binding_n), VALIDATE_SHADERDESC_VIEW_TEXTURE_WGSL_GROUP1_BINDING_COLLISION); wgsl_group1_bits = _sg_validate_set_slot_bit(wgsl_group1_bits, SG_SHADERSTAGE_NONE, tex_desc->wgsl_group1_binding_n); + #elif defined(SOKOL_VULKAN) + _SG_VALIDATE(_sg_validate_slot_bits(spirv_set1_bits, SG_SHADERSTAGE_NONE, tex_desc->spirv_set1_binding_n), VALIDATE_SHADERDESC_VIEW_TEXTURE_SPIRV_SET1_BINDING_COLLISION); + spirv_set1_bits = _sg_validate_set_slot_bit(spirv_set1_bits, SG_SHADERSTAGE_NONE, tex_desc->spirv_set1_binding_n); #elif defined(SOKOL_DUMMY_BACKEND) || defined(_SOKOL_ANY_GL) _SOKOL_UNUSED(tex_desc); #endif @@ -19106,6 +22724,9 @@ _SOKOL_PRIVATE bool _sg_validate_shader_desc(const sg_shader_desc* desc) { #elif defined(SOKOL_WGPU) _SG_VALIDATE(_sg_validate_slot_bits(wgsl_group1_bits, SG_SHADERSTAGE_NONE, sbuf_desc->wgsl_group1_binding_n), VALIDATE_SHADERDESC_VIEW_STORAGEBUFFER_WGSL_GROUP1_BINDING_COLLISION); wgsl_group1_bits = _sg_validate_set_slot_bit(wgsl_group1_bits, SG_SHADERSTAGE_NONE, sbuf_desc->wgsl_group1_binding_n); + #elif defined(SOKOL_VULKAN) + _SG_VALIDATE(_sg_validate_slot_bits(spirv_set1_bits, SG_SHADERSTAGE_NONE, sbuf_desc->spirv_set1_binding_n), VALIDATE_SHADERDESC_VIEW_STORAGEBUFFER_SPIRV_SET1_BINDING_COLLISION); + spirv_set1_bits = _sg_validate_set_slot_bit(spirv_set1_bits, SG_SHADERSTAGE_NONE, sbuf_desc->spirv_set1_binding_n); #elif defined(SOKOL_DUMMY_BACKEND) _SOKOL_UNUSED(sbuf_desc); #endif @@ -19124,6 +22745,9 @@ _SOKOL_PRIVATE bool _sg_validate_shader_desc(const sg_shader_desc* desc) { #elif defined(SOKOL_WGPU) _SG_VALIDATE(_sg_validate_slot_bits(wgsl_group1_bits, SG_SHADERSTAGE_NONE, simg_desc->wgsl_group1_binding_n), VALIDATE_SHADERDESC_VIEW_STORAGEIMAGE_WGSL_GROUP1_BINDING_COLLISION); wgsl_group1_bits = _sg_validate_set_slot_bit(wgsl_group1_bits, SG_SHADERSTAGE_NONE, simg_desc->wgsl_group1_binding_n); + #elif defined(SOKOL_VULKAN) + _SG_VALIDATE(_sg_validate_slot_bits(spirv_set1_bits, SG_SHADERSTAGE_NONE, simg_desc->spirv_set1_binding_n), VALIDATE_SHADERDESC_VIEW_STORAGEIMAGE_SPIRV_SET1_BINDING_COLLISION); + spirv_set1_bits = _sg_validate_set_slot_bit(spirv_set1_bits, SG_SHADERSTAGE_NONE, simg_desc->spirv_set1_binding_n); #endif } } @@ -19144,6 +22768,9 @@ _SOKOL_PRIVATE bool _sg_validate_shader_desc(const sg_shader_desc* desc) { #elif defined(SOKOL_WGPU) _SG_VALIDATE(_sg_validate_slot_bits(wgsl_group1_bits, SG_SHADERSTAGE_NONE, smp_desc->wgsl_group1_binding_n), VALIDATE_SHADERDESC_SAMPLER_WGSL_GROUP1_BINDING_COLLISION); wgsl_group1_bits = _sg_validate_set_slot_bit(wgsl_group1_bits, SG_SHADERSTAGE_NONE, smp_desc->wgsl_group1_binding_n); + #elif defined(SOKOL_VULKAN) + _SG_VALIDATE(_sg_validate_slot_bits(spirv_set1_bits, SG_SHADERSTAGE_NONE, smp_desc->spirv_set1_binding_n), VALIDATE_SHADERDESC_SAMPLER_SPIRV_SET1_BINDING_COLLISION); + spirv_set1_bits = _sg_validate_set_slot_bit(spirv_set1_bits, SG_SHADERSTAGE_NONE, smp_desc->spirv_set1_binding_n); #endif } @@ -20824,7 +24451,10 @@ _SOKOL_PRIVATE sg_desc _sg_desc_defaults(const sg_desc* desc) { res.view_pool_size = _sg_def(res.view_pool_size, _SG_DEFAULT_VIEW_POOL_SIZE); res.uniform_buffer_size = _sg_def(res.uniform_buffer_size, _SG_DEFAULT_UB_SIZE); res.max_commit_listeners = _sg_def(res.max_commit_listeners, _SG_DEFAULT_MAX_COMMIT_LISTENERS); - res.wgpu_bindgroups_cache_size = _sg_def(res.wgpu_bindgroups_cache_size, _SG_DEFAULT_WGPU_BINDGROUP_CACHE_SIZE); + res.wgpu.bindgroups_cache_size = _sg_def(res.wgpu.bindgroups_cache_size, _SG_DEFAULT_WGPU_BINDGROUP_CACHE_SIZE); + res.vulkan.copy_staging_buffer_size = _sg_def(res.vulkan.copy_staging_buffer_size, _SG_DEFAULT_VK_COPY_STAGING_SIZE); + res.vulkan.stream_staging_buffer_size = _sg_def(res.vulkan.stream_staging_buffer_size, _SG_DEFAULT_VK_STREAM_STAGING_SIZE); + res.vulkan.descriptor_buffer_size = _sg_def(res.vulkan.descriptor_buffer_size, _SG_DEFAULT_VK_DESCRIPTOR_BUFFER_SIZE); return res; } @@ -21647,6 +25277,7 @@ SOKOL_API_IMPL void sg_begin_pass(const sg_pass* pass) { _sg.cur_pass.swapchain.depth_fmt = pass_def.swapchain.depth_format; _sg.cur_pass.swapchain.sample_count = pass_def.swapchain.sample_count; } + _sg.cur_pass.action = pass_def.action; _sg.cur_pass.valid = true; // may be overruled by backend begin-pass functions _sg.cur_pass.is_compute = pass_def.compute; _sg_begin_pass(&pass_def, &atts_ptrs); diff --git a/sokol_glue.h b/sokol_glue.h index a715b174..c8f2a2ff 100644 --- a/sokol_glue.h +++ b/sokol_glue.h @@ -124,39 +124,83 @@ SOKOL_GLUE_API_DECL sg_swapchain sglue_swapchain(void); #define SOKOL_API_IMPL #endif +#ifndef _SOKOL_PRIVATE + #if defined(__GNUC__) || defined(__clang__) + #define _SOKOL_PRIVATE __attribute__((unused)) static + #else + #define _SOKOL_PRIVATE static + #endif +#endif + +#ifndef SOKOL_ASSERT + #include <assert.h> + #define SOKOL_ASSERT(c) assert(c) +#endif +#ifndef SOKOL_UNREACHABLE + #define SOKOL_UNREACHABLE SOKOL_ASSERT(false) +#endif + +_SOKOL_PRIVATE sg_pixel_format _sglue_to_sgpixelformat(sapp_pixel_format fmt) { + switch (fmt) { + case SAPP_PIXELFORMAT_NONE: return SG_PIXELFORMAT_NONE; + case SAPP_PIXELFORMAT_RGBA8: return SG_PIXELFORMAT_RGBA8; + case SAPP_PIXELFORMAT_SRGB8A8: return SG_PIXELFORMAT_SRGB8A8; + case SAPP_PIXELFORMAT_BGRA8: return SG_PIXELFORMAT_BGRA8; + case SAPP_PIXELFORMAT_DEPTH_STENCIL: return SG_PIXELFORMAT_DEPTH_STENCIL; + case SAPP_PIXELFORMAT_DEPTH: return SG_PIXELFORMAT_DEPTH; + case SAPP_PIXELFORMAT_SBGRA8: // FIXME! + default: + SOKOL_UNREACHABLE; + return SG_PIXELFORMAT_NONE; + } +} SOKOL_API_IMPL sg_environment sglue_environment(void) { - sg_environment env; - memset(&env, 0, sizeof(env)); - env.defaults.color_format = (sg_pixel_format) sapp_color_format(); - env.defaults.depth_format = (sg_pixel_format) sapp_depth_format(); - env.defaults.sample_count = sapp_sample_count(); - env.metal.device = sapp_metal_get_device(); - env.d3d11.device = sapp_d3d11_get_device(); - env.d3d11.device_context = sapp_d3d11_get_device_context(); - env.wgpu.device = sapp_wgpu_get_device(); - return env; + sg_environment res; + memset(&res, 0, sizeof(res)); + const sapp_environment env = sapp_get_environment(); + res.defaults.color_format = _sglue_to_sgpixelformat(env.defaults.color_format); + res.defaults.depth_format = _sglue_to_sgpixelformat(env.defaults.depth_format); + res.defaults.sample_count = env.defaults.sample_count; + res.metal.device = env.metal.device; + res.d3d11.device = env.d3d11.device; + res.d3d11.device_context = env.d3d11.device_context; + res.wgpu.device = env.wgpu.device; + res.vulkan.physical_device = env.vulkan.physical_device; + res.vulkan.device = env.vulkan.device; + res.vulkan.queue = env.vulkan.queue; + res.vulkan.queue_family_index = env.vulkan.queue_family_index; + return res; } SOKOL_API_IMPL sg_swapchain sglue_swapchain(void) { - sg_swapchain swapchain; - memset(&swapchain, 0, sizeof(swapchain)); - swapchain.width = sapp_width(); - swapchain.height = sapp_height(); - swapchain.sample_count = sapp_sample_count(); - swapchain.color_format = (sg_pixel_format)sapp_color_format(); - swapchain.depth_format = (sg_pixel_format)sapp_depth_format(); - swapchain.metal.current_drawable = sapp_metal_get_current_drawable(); - swapchain.metal.depth_stencil_texture = sapp_metal_get_depth_stencil_texture(); - swapchain.metal.msaa_color_texture = sapp_metal_get_msaa_color_texture(); - swapchain.d3d11.render_view = sapp_d3d11_get_render_view(); - swapchain.d3d11.resolve_view = sapp_d3d11_get_resolve_view(); - swapchain.d3d11.depth_stencil_view = sapp_d3d11_get_depth_stencil_view(); - swapchain.wgpu.render_view = sapp_wgpu_get_render_view(); - swapchain.wgpu.resolve_view = sapp_wgpu_get_resolve_view(); - swapchain.wgpu.depth_stencil_view = sapp_wgpu_get_depth_stencil_view(); - swapchain.gl.framebuffer = sapp_gl_get_framebuffer(); - return swapchain; + sg_swapchain res; + memset(&res, 0, sizeof(res)); + const sapp_swapchain sc = sapp_get_swapchain(); + res.width = sc.width; + res.height = sc.height; + res.sample_count = sc.sample_count; + res.color_format = _sglue_to_sgpixelformat(sc.color_format); + res.depth_format = _sglue_to_sgpixelformat(sc.depth_format); + res.metal.current_drawable = sc.metal.current_drawable; + res.metal.depth_stencil_texture = sc.metal.depth_stencil_texture; + res.metal.msaa_color_texture = sc.metal.msaa_color_texture; + res.d3d11.render_view = sc.d3d11.render_view; + res.d3d11.resolve_view = sc.d3d11.resolve_view; + res.d3d11.depth_stencil_view = sc.d3d11.depth_stencil_view; + res.wgpu.render_view = sc.wgpu.render_view; + res.wgpu.resolve_view = sc.wgpu.resolve_view; + res.wgpu.depth_stencil_view = sc.wgpu.depth_stencil_view; + res.vulkan.render_image = sc.vulkan.render_image; + res.vulkan.render_view = sc.vulkan.render_view; + res.vulkan.resolve_image = sc.vulkan.resolve_image; + res.vulkan.resolve_view = sc.vulkan.resolve_view; + res.vulkan.depth_stencil_image = sc.vulkan.depth_stencil_image; + res.vulkan.depth_stencil_view = sc.vulkan.depth_stencil_view; + res.vulkan.render_finished_semaphore = sc.vulkan.render_finished_semaphore; + res.vulkan.present_complete_semaphore = sc.vulkan.present_complete_semaphore; + res.gl.framebuffer = sc.gl.framebuffer; + return res; } #endif /* SOKOL_GLUE_IMPL */ diff --git a/util/sokol_debugtext.h b/util/sokol_debugtext.h index 1196b6d5..0997e65d 100644 --- a/util/sokol_debugtext.h +++ b/util/sokol_debugtext.h @@ -22,6 +22,7 @@ SOKOL_D3D11 SOKOL_METAL SOKOL_WGPU + SOKOL_VULKAN ...optionally provide the following macros to override defaults: @@ -2377,7 +2378,7 @@ static const uint8_t _sdtx_font_oric[2048] = { /* Embedded source code compiled with: - sokol-shdc -i debugtext.glsl -o debugtext.h -l glsl410:glsl300es:hlsl4:metal_macos:metal_ios:metal_sim:wgsl -b + sokol-shdc -i debugtext.glsl -o debugtext.h -l glsl410:glsl300es:hlsl4:metal_macos:metal_ios:metal_sim:wgsl:spirv_vk -b (not that for Metal and D3D11 byte code, sokol-shdc must be run on macOS and Windows) @@ -3880,6 +3881,173 @@ static const uint8_t _sdtx_fs_source_wgsl[663] = { 0x6e,0x5f,0x6f,0x75,0x74,0x28,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, 0x29,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, }; +#elif defined(SOKOL_VULKAN) +/* + #version 460 + + layout(location = 0) in vec2 position; + layout(location = 0) out vec2 uv; + layout(location = 1) in vec2 texcoord0; + layout(location = 1) out vec4 color; + layout(location = 2) in vec4 color0; + + void main() + { + gl_Position = vec4((position * vec2(2.0, -2.0)) + vec2(-1.0, 1.0), 0.0, 1.0); + uv = texcoord0; + color = color0; + } + +*/ +static const uint8_t _sdtx_vs_bytecode_spirv_vk[1248] = { + 0x03,0x02,0x23,0x07,0x00,0x04,0x01,0x00,0x0b,0x00,0x08,0x00,0x2a,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x11,0x00,0x02,0x00,0x01,0x00,0x00,0x00,0x0b,0x00,0x06,0x00, + 0x01,0x00,0x00,0x00,0x47,0x4c,0x53,0x4c,0x2e,0x73,0x74,0x64,0x2e,0x34,0x35,0x30, + 0x00,0x00,0x00,0x00,0x0e,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x0f,0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x6d,0x61,0x69,0x6e, + 0x00,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x23,0x00,0x00,0x00, + 0x24,0x00,0x00,0x00,0x26,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x03,0x00,0x03,0x00, + 0x02,0x00,0x00,0x00,0xcc,0x01,0x00,0x00,0x05,0x00,0x04,0x00,0x04,0x00,0x00,0x00, + 0x6d,0x61,0x69,0x6e,0x00,0x00,0x00,0x00,0x05,0x00,0x06,0x00,0x0b,0x00,0x00,0x00, + 0x67,0x6c,0x5f,0x50,0x65,0x72,0x56,0x65,0x72,0x74,0x65,0x78,0x00,0x00,0x00,0x00, + 0x06,0x00,0x06,0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x67,0x6c,0x5f,0x50, + 0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0x06,0x00,0x07,0x00,0x0b,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x67,0x6c,0x5f,0x50,0x6f,0x69,0x6e,0x74,0x53,0x69,0x7a,0x65, + 0x00,0x00,0x00,0x00,0x06,0x00,0x07,0x00,0x0b,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x67,0x6c,0x5f,0x43,0x6c,0x69,0x70,0x44,0x69,0x73,0x74,0x61,0x6e,0x63,0x65,0x00, + 0x06,0x00,0x07,0x00,0x0b,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x67,0x6c,0x5f,0x43, + 0x75,0x6c,0x6c,0x44,0x69,0x73,0x74,0x61,0x6e,0x63,0x65,0x00,0x05,0x00,0x03,0x00, + 0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x05,0x00,0x12,0x00,0x00,0x00, + 0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0x00,0x00,0x00,0x05,0x00,0x03,0x00, + 0x23,0x00,0x00,0x00,0x75,0x76,0x00,0x00,0x05,0x00,0x05,0x00,0x24,0x00,0x00,0x00, + 0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x00,0x00,0x00,0x05,0x00,0x04,0x00, + 0x26,0x00,0x00,0x00,0x63,0x6f,0x6c,0x6f,0x72,0x00,0x00,0x00,0x05,0x00,0x04,0x00, + 0x28,0x00,0x00,0x00,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x00,0x00,0x47,0x00,0x03,0x00, + 0x0b,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x48,0x00,0x05,0x00,0x0b,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x05,0x00, + 0x0b,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x48,0x00,0x05,0x00,0x0b,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x0b,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x48,0x00,0x05,0x00,0x0b,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x0b,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x12,0x00,0x00,0x00, + 0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x23,0x00,0x00,0x00, + 0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x24,0x00,0x00,0x00, + 0x1e,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x26,0x00,0x00,0x00, + 0x1e,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x28,0x00,0x00,0x00, + 0x1e,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x13,0x00,0x02,0x00,0x02,0x00,0x00,0x00, + 0x21,0x00,0x03,0x00,0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x16,0x00,0x03,0x00, + 0x06,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x17,0x00,0x04,0x00,0x07,0x00,0x00,0x00, + 0x06,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x15,0x00,0x04,0x00,0x08,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2b,0x00,0x04,0x00,0x08,0x00,0x00,0x00, + 0x09,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x1c,0x00,0x04,0x00,0x0a,0x00,0x00,0x00, + 0x06,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x1e,0x00,0x06,0x00,0x0b,0x00,0x00,0x00, + 0x07,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x0a,0x00,0x00,0x00, + 0x20,0x00,0x04,0x00,0x0c,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x0b,0x00,0x00,0x00, + 0x3b,0x00,0x04,0x00,0x0c,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x15,0x00,0x04,0x00,0x0e,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x2b,0x00,0x04,0x00,0x0e,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x17,0x00,0x04,0x00,0x10,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x20,0x00,0x04,0x00,0x11,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x10,0x00,0x00,0x00, + 0x3b,0x00,0x04,0x00,0x11,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x2b,0x00,0x04,0x00,0x06,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x40, + 0x2b,0x00,0x04,0x00,0x06,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0xc0, + 0x2c,0x00,0x05,0x00,0x10,0x00,0x00,0x00,0x16,0x00,0x00,0x00,0x14,0x00,0x00,0x00, + 0x15,0x00,0x00,0x00,0x2b,0x00,0x04,0x00,0x06,0x00,0x00,0x00,0x18,0x00,0x00,0x00, + 0x00,0x00,0x80,0xbf,0x2b,0x00,0x04,0x00,0x06,0x00,0x00,0x00,0x19,0x00,0x00,0x00, + 0x00,0x00,0x80,0x3f,0x2c,0x00,0x05,0x00,0x10,0x00,0x00,0x00,0x1a,0x00,0x00,0x00, + 0x18,0x00,0x00,0x00,0x19,0x00,0x00,0x00,0x2b,0x00,0x04,0x00,0x06,0x00,0x00,0x00, + 0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x22,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x22,0x00,0x00,0x00, + 0x23,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x11,0x00,0x00,0x00, + 0x24,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x20,0x00,0x00,0x00, + 0x26,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x27,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x27,0x00,0x00,0x00, + 0x28,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x36,0x00,0x05,0x00,0x02,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0xf8,0x00,0x02,0x00, + 0x05,0x00,0x00,0x00,0x3d,0x00,0x04,0x00,0x10,0x00,0x00,0x00,0x13,0x00,0x00,0x00, + 0x12,0x00,0x00,0x00,0x85,0x00,0x05,0x00,0x10,0x00,0x00,0x00,0x17,0x00,0x00,0x00, + 0x13,0x00,0x00,0x00,0x16,0x00,0x00,0x00,0x81,0x00,0x05,0x00,0x10,0x00,0x00,0x00, + 0x1b,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0x51,0x00,0x05,0x00, + 0x06,0x00,0x00,0x00,0x1d,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x51,0x00,0x05,0x00,0x06,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1b,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x50,0x00,0x07,0x00,0x07,0x00,0x00,0x00,0x1f,0x00,0x00,0x00, + 0x1d,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x19,0x00,0x00,0x00, + 0x41,0x00,0x05,0x00,0x20,0x00,0x00,0x00,0x21,0x00,0x00,0x00,0x0d,0x00,0x00,0x00, + 0x0f,0x00,0x00,0x00,0x3e,0x00,0x03,0x00,0x21,0x00,0x00,0x00,0x1f,0x00,0x00,0x00, + 0x3d,0x00,0x04,0x00,0x10,0x00,0x00,0x00,0x25,0x00,0x00,0x00,0x24,0x00,0x00,0x00, + 0x3e,0x00,0x03,0x00,0x23,0x00,0x00,0x00,0x25,0x00,0x00,0x00,0x3d,0x00,0x04,0x00, + 0x07,0x00,0x00,0x00,0x29,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x3e,0x00,0x03,0x00, + 0x26,0x00,0x00,0x00,0x29,0x00,0x00,0x00,0xfd,0x00,0x01,0x00,0x38,0x00,0x01,0x00, +}; +/* + #version 460 + + layout(set = 1, binding = 0) uniform texture2D tex; + layout(set = 1, binding = 32) uniform sampler smp; + + layout(location = 0) out vec4 frag_color; + layout(location = 0) in vec2 uv; + layout(location = 1) in vec4 color; + + void main() + { + frag_color = texture(sampler2D(tex, smp), uv).xxxx * color; + } + +*/ +static const uint8_t _sdtx_fs_bytecode_spirv_vk[816] = { + 0x03,0x02,0x23,0x07,0x00,0x04,0x01,0x00,0x0b,0x00,0x08,0x00,0x1e,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x11,0x00,0x02,0x00,0x01,0x00,0x00,0x00,0x0b,0x00,0x06,0x00, + 0x01,0x00,0x00,0x00,0x47,0x4c,0x53,0x4c,0x2e,0x73,0x74,0x64,0x2e,0x34,0x35,0x30, + 0x00,0x00,0x00,0x00,0x0e,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x0f,0x00,0x0a,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x6d,0x61,0x69,0x6e, + 0x00,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x10,0x00,0x00,0x00, + 0x16,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x10,0x00,0x03,0x00,0x04,0x00,0x00,0x00, + 0x07,0x00,0x00,0x00,0x03,0x00,0x03,0x00,0x02,0x00,0x00,0x00,0xcc,0x01,0x00,0x00, + 0x05,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x6d,0x61,0x69,0x6e,0x00,0x00,0x00,0x00, + 0x05,0x00,0x05,0x00,0x09,0x00,0x00,0x00,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c, + 0x6f,0x72,0x00,0x00,0x05,0x00,0x03,0x00,0x0c,0x00,0x00,0x00,0x74,0x65,0x78,0x00, + 0x05,0x00,0x03,0x00,0x10,0x00,0x00,0x00,0x73,0x6d,0x70,0x00,0x05,0x00,0x03,0x00, + 0x16,0x00,0x00,0x00,0x75,0x76,0x00,0x00,0x05,0x00,0x04,0x00,0x1b,0x00,0x00,0x00, + 0x63,0x6f,0x6c,0x6f,0x72,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x09,0x00,0x00,0x00, + 0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x0c,0x00,0x00,0x00, + 0x21,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x0c,0x00,0x00,0x00, + 0x22,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x10,0x00,0x00,0x00, + 0x21,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x10,0x00,0x00,0x00, + 0x22,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x16,0x00,0x00,0x00, + 0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x1b,0x00,0x00,0x00, + 0x1e,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x13,0x00,0x02,0x00,0x02,0x00,0x00,0x00, + 0x21,0x00,0x03,0x00,0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x16,0x00,0x03,0x00, + 0x06,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x17,0x00,0x04,0x00,0x07,0x00,0x00,0x00, + 0x06,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x08,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x08,0x00,0x00,0x00, + 0x09,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x19,0x00,0x09,0x00,0x0a,0x00,0x00,0x00, + 0x06,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x04,0x00, + 0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x3b,0x00,0x04,0x00, + 0x0b,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1a,0x00,0x02,0x00, + 0x0e,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x0e,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x0f,0x00,0x00,0x00,0x10,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x1b,0x00,0x03,0x00,0x12,0x00,0x00,0x00,0x0a,0x00,0x00,0x00, + 0x17,0x00,0x04,0x00,0x14,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x20,0x00,0x04,0x00,0x15,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x14,0x00,0x00,0x00, + 0x3b,0x00,0x04,0x00,0x15,0x00,0x00,0x00,0x16,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x20,0x00,0x04,0x00,0x1a,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x07,0x00,0x00,0x00, + 0x3b,0x00,0x04,0x00,0x1a,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x36,0x00,0x05,0x00,0x02,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0xf8,0x00,0x02,0x00,0x05,0x00,0x00,0x00,0x3d,0x00,0x04,0x00, + 0x0a,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x3d,0x00,0x04,0x00, + 0x0e,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x56,0x00,0x05,0x00, + 0x12,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x11,0x00,0x00,0x00, + 0x3d,0x00,0x04,0x00,0x14,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x16,0x00,0x00,0x00, + 0x57,0x00,0x05,0x00,0x07,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x13,0x00,0x00,0x00, + 0x17,0x00,0x00,0x00,0x4f,0x00,0x09,0x00,0x07,0x00,0x00,0x00,0x19,0x00,0x00,0x00, + 0x18,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3d,0x00,0x04,0x00,0x07,0x00,0x00,0x00, + 0x1c,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x85,0x00,0x05,0x00,0x07,0x00,0x00,0x00, + 0x1d,0x00,0x00,0x00,0x19,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x3e,0x00,0x03,0x00, + 0x09,0x00,0x00,0x00,0x1d,0x00,0x00,0x00,0xfd,0x00,0x01,0x00,0x38,0x00,0x01,0x00, +}; #elif defined(SOKOL_DUMMY_BACKEND) static const char* _sdtx_vs_src_dummy = ""; static const char* _sdtx_fs_src_dummy = ""; @@ -4369,17 +4537,22 @@ static void _sdtx_setup_common(void) { shd_desc.attrs[1].hlsl_sem_index = 1; shd_desc.attrs[2].hlsl_sem_name = "TEXCOORD"; shd_desc.attrs[2].hlsl_sem_index = 2; + shd_desc.attrs[0].base_type = SG_SHADERATTRBASETYPE_FLOAT; + shd_desc.attrs[1].base_type = SG_SHADERATTRBASETYPE_FLOAT; + shd_desc.attrs[2].base_type = SG_SHADERATTRBASETYPE_FLOAT; shd_desc.views[0].texture.stage = SG_SHADERSTAGE_FRAGMENT; shd_desc.views[0].texture.image_type = SG_IMAGETYPE_2D; shd_desc.views[0].texture.sample_type = SG_IMAGESAMPLETYPE_FLOAT; shd_desc.views[0].texture.hlsl_register_t_n = 0; shd_desc.views[0].texture.msl_texture_n = 0; shd_desc.views[0].texture.wgsl_group1_binding_n = 64; + shd_desc.views[0].texture.spirv_set1_binding_n = 0; shd_desc.samplers[0].stage = SG_SHADERSTAGE_FRAGMENT; shd_desc.samplers[0].sampler_type = SG_SAMPLERTYPE_FILTERING; shd_desc.samplers[0].hlsl_register_s_n = 0; shd_desc.samplers[0].msl_sampler_n = 0; shd_desc.samplers[0].wgsl_group1_binding_n = 80; + shd_desc.samplers[0].spirv_set1_binding_n = 32; shd_desc.texture_sampler_pairs[0].stage = SG_SHADERSTAGE_FRAGMENT; shd_desc.texture_sampler_pairs[0].view_slot = 0; shd_desc.texture_sampler_pairs[0].sampler_slot = 0; @@ -4413,6 +4586,11 @@ static void _sdtx_setup_common(void) { #elif defined(SOKOL_WGPU) shd_desc.vertex_func.source = (const char*)_sdtx_vs_source_wgsl; shd_desc.fragment_func.source = (const char*)_sdtx_fs_source_wgsl; + #elif defined(SOKOL_VULKAN) + shd_desc.vertex_func.bytecode = SG_RANGE(_sdtx_vs_bytecode_spirv_vk); + shd_desc.vertex_func.entry = "main"; + shd_desc.fragment_func.bytecode = SG_RANGE(_sdtx_fs_bytecode_spirv_vk); + shd_desc.fragment_func.entry = "main"; #else shd_desc.vertex_func.source = _sdtx_vs_src_dummy; shd_desc.fragment_func.source = _sdtx_fs_src_dummy; diff --git a/util/sokol_fontstash.h b/util/sokol_fontstash.h index aa8d2095..767bdf13 100644 --- a/util/sokol_fontstash.h +++ b/util/sokol_fontstash.h @@ -23,6 +23,8 @@ SOKOL_GLES3 SOKOL_D3D11 SOKOL_METAL + SOKOL_WGPU + SOKOL_VULKAN ...optionally provide the following macros to override defaults: @@ -1997,6 +1999,213 @@ static const uint8_t _sfons_fs_source_wgsl[674] = { 0x28,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x29,0x3b,0x0a,0x7d,0x0a, 0x0a,0x00, }; +#elif defined(SOKOL_VULKAN) +/* + #version 460 + + layout(set = 0, binding = 0, std140) uniform vs_params + { + mat4 mvp; + mat4 tm; + } _19; + + layout(location = 0) in vec4 position; + layout(location = 3) in float psize; + layout(location = 0) out vec4 uv; + layout(location = 1) in vec2 texcoord0; + layout(location = 1) out vec4 color; + layout(location = 2) in vec4 color0; + + void main() + { + gl_Position = _19.mvp * position; + gl_PointSize = psize; + uv = _19.tm * vec4(texcoord0, 0.0, 1.0); + color = color0; + } + +*/ +static const uint8_t _sfons_vs_bytecode_spirv_vk[1668] = { + 0x03,0x02,0x23,0x07,0x00,0x04,0x01,0x00,0x0b,0x00,0x08,0x00,0x33,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x11,0x00,0x02,0x00,0x01,0x00,0x00,0x00,0x0b,0x00,0x06,0x00, + 0x01,0x00,0x00,0x00,0x47,0x4c,0x53,0x4c,0x2e,0x73,0x74,0x64,0x2e,0x34,0x35,0x30, + 0x00,0x00,0x00,0x00,0x0e,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x0f,0x00,0x0d,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x6d,0x61,0x69,0x6e, + 0x00,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x18,0x00,0x00,0x00, + 0x1f,0x00,0x00,0x00,0x23,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x30,0x00,0x00,0x00, + 0x31,0x00,0x00,0x00,0x03,0x00,0x03,0x00,0x02,0x00,0x00,0x00,0xcc,0x01,0x00,0x00, + 0x05,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x6d,0x61,0x69,0x6e,0x00,0x00,0x00,0x00, + 0x05,0x00,0x06,0x00,0x0b,0x00,0x00,0x00,0x67,0x6c,0x5f,0x50,0x65,0x72,0x56,0x65, + 0x72,0x74,0x65,0x78,0x00,0x00,0x00,0x00,0x06,0x00,0x06,0x00,0x0b,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00, + 0x06,0x00,0x07,0x00,0x0b,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x67,0x6c,0x5f,0x50, + 0x6f,0x69,0x6e,0x74,0x53,0x69,0x7a,0x65,0x00,0x00,0x00,0x00,0x06,0x00,0x07,0x00, + 0x0b,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x67,0x6c,0x5f,0x43,0x6c,0x69,0x70,0x44, + 0x69,0x73,0x74,0x61,0x6e,0x63,0x65,0x00,0x06,0x00,0x07,0x00,0x0b,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x67,0x6c,0x5f,0x43,0x75,0x6c,0x6c,0x44,0x69,0x73,0x74,0x61, + 0x6e,0x63,0x65,0x00,0x05,0x00,0x03,0x00,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x05,0x00,0x05,0x00,0x11,0x00,0x00,0x00,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d, + 0x73,0x00,0x00,0x00,0x06,0x00,0x04,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x6d,0x76,0x70,0x00,0x06,0x00,0x04,0x00,0x11,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x74,0x6d,0x00,0x00,0x05,0x00,0x03,0x00,0x13,0x00,0x00,0x00,0x5f,0x31,0x39,0x00, + 0x05,0x00,0x05,0x00,0x18,0x00,0x00,0x00,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e, + 0x00,0x00,0x00,0x00,0x05,0x00,0x04,0x00,0x1f,0x00,0x00,0x00,0x70,0x73,0x69,0x7a, + 0x65,0x00,0x00,0x00,0x05,0x00,0x03,0x00,0x23,0x00,0x00,0x00,0x75,0x76,0x00,0x00, + 0x05,0x00,0x05,0x00,0x28,0x00,0x00,0x00,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64, + 0x30,0x00,0x00,0x00,0x05,0x00,0x04,0x00,0x30,0x00,0x00,0x00,0x63,0x6f,0x6c,0x6f, + 0x72,0x00,0x00,0x00,0x05,0x00,0x04,0x00,0x31,0x00,0x00,0x00,0x63,0x6f,0x6c,0x6f, + 0x72,0x30,0x00,0x00,0x47,0x00,0x03,0x00,0x0b,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x48,0x00,0x05,0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x48,0x00,0x05,0x00,0x0b,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x0b,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x48,0x00,0x05,0x00,0x0b,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x48,0x00,0x05,0x00, + 0x0b,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x04,0x00,0x00,0x00, + 0x47,0x00,0x03,0x00,0x11,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x48,0x00,0x04,0x00, + 0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x48,0x00,0x05,0x00, + 0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x10,0x00,0x00,0x00, + 0x48,0x00,0x05,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x23,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x48,0x00,0x04,0x00,0x11,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x05,0x00,0x00,0x00,0x48,0x00,0x05,0x00,0x11,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x07,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x48,0x00,0x05,0x00,0x11,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x23,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x47,0x00,0x04,0x00, + 0x13,0x00,0x00,0x00,0x21,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00, + 0x13,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00, + 0x18,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00, + 0x1f,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x47,0x00,0x04,0x00, + 0x23,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00, + 0x28,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x47,0x00,0x04,0x00, + 0x30,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x47,0x00,0x04,0x00, + 0x31,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x13,0x00,0x02,0x00, + 0x02,0x00,0x00,0x00,0x21,0x00,0x03,0x00,0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x16,0x00,0x03,0x00,0x06,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x17,0x00,0x04,0x00, + 0x07,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x15,0x00,0x04,0x00, + 0x08,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2b,0x00,0x04,0x00, + 0x08,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x1c,0x00,0x04,0x00, + 0x0a,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x1e,0x00,0x06,0x00, + 0x0b,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x0a,0x00,0x00,0x00, + 0x0a,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x0c,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x0b,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x0c,0x00,0x00,0x00,0x0d,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x15,0x00,0x04,0x00,0x0e,0x00,0x00,0x00,0x20,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x2b,0x00,0x04,0x00,0x0e,0x00,0x00,0x00,0x0f,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x18,0x00,0x04,0x00,0x10,0x00,0x00,0x00,0x07,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x1e,0x00,0x04,0x00,0x11,0x00,0x00,0x00,0x10,0x00,0x00,0x00, + 0x10,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x12,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x11,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x12,0x00,0x00,0x00,0x13,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x14,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x10,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x17,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x07,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x17,0x00,0x00,0x00,0x18,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x1b,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x07,0x00,0x00,0x00,0x2b,0x00,0x04,0x00,0x0e,0x00,0x00,0x00,0x1d,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x1e,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x06,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x1e,0x00,0x00,0x00,0x1f,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x21,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x06,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x1b,0x00,0x00,0x00,0x23,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x17,0x00,0x04,0x00,0x26,0x00,0x00,0x00,0x06,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x27,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x26,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x27,0x00,0x00,0x00,0x28,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x2b,0x00,0x04,0x00,0x06,0x00,0x00,0x00,0x2a,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x2b,0x00,0x04,0x00,0x06,0x00,0x00,0x00,0x2b,0x00,0x00,0x00, + 0x00,0x00,0x80,0x3f,0x3b,0x00,0x04,0x00,0x1b,0x00,0x00,0x00,0x30,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x17,0x00,0x00,0x00,0x31,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x36,0x00,0x05,0x00,0x02,0x00,0x00,0x00,0x04,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0xf8,0x00,0x02,0x00,0x05,0x00,0x00,0x00, + 0x41,0x00,0x05,0x00,0x14,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x13,0x00,0x00,0x00, + 0x0f,0x00,0x00,0x00,0x3d,0x00,0x04,0x00,0x10,0x00,0x00,0x00,0x16,0x00,0x00,0x00, + 0x15,0x00,0x00,0x00,0x3d,0x00,0x04,0x00,0x07,0x00,0x00,0x00,0x19,0x00,0x00,0x00, + 0x18,0x00,0x00,0x00,0x91,0x00,0x05,0x00,0x07,0x00,0x00,0x00,0x1a,0x00,0x00,0x00, + 0x16,0x00,0x00,0x00,0x19,0x00,0x00,0x00,0x41,0x00,0x05,0x00,0x1b,0x00,0x00,0x00, + 0x1c,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x3e,0x00,0x03,0x00, + 0x1c,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0x3d,0x00,0x04,0x00,0x06,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x41,0x00,0x05,0x00,0x21,0x00,0x00,0x00, + 0x22,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x1d,0x00,0x00,0x00,0x3e,0x00,0x03,0x00, + 0x22,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x41,0x00,0x05,0x00,0x14,0x00,0x00,0x00, + 0x24,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x1d,0x00,0x00,0x00,0x3d,0x00,0x04,0x00, + 0x10,0x00,0x00,0x00,0x25,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x3d,0x00,0x04,0x00, + 0x26,0x00,0x00,0x00,0x29,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x51,0x00,0x05,0x00, + 0x06,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0x29,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x51,0x00,0x05,0x00,0x06,0x00,0x00,0x00,0x2d,0x00,0x00,0x00,0x29,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x50,0x00,0x07,0x00,0x07,0x00,0x00,0x00,0x2e,0x00,0x00,0x00, + 0x2c,0x00,0x00,0x00,0x2d,0x00,0x00,0x00,0x2a,0x00,0x00,0x00,0x2b,0x00,0x00,0x00, + 0x91,0x00,0x05,0x00,0x07,0x00,0x00,0x00,0x2f,0x00,0x00,0x00,0x25,0x00,0x00,0x00, + 0x2e,0x00,0x00,0x00,0x3e,0x00,0x03,0x00,0x23,0x00,0x00,0x00,0x2f,0x00,0x00,0x00, + 0x3d,0x00,0x04,0x00,0x07,0x00,0x00,0x00,0x32,0x00,0x00,0x00,0x31,0x00,0x00,0x00, + 0x3e,0x00,0x03,0x00,0x30,0x00,0x00,0x00,0x32,0x00,0x00,0x00,0xfd,0x00,0x01,0x00, + 0x38,0x00,0x01,0x00, +}; +/* + #version 460 + + layout(set = 1, binding = 0) uniform texture2D tex; + layout(set = 1, binding = 32) uniform sampler smp; + + layout(location = 0) out vec4 frag_color; + layout(location = 0) in vec4 uv; + layout(location = 1) in vec4 color; + + void main() + { + frag_color = vec4(1.0, 1.0, 1.0, texture(sampler2D(tex, smp), uv.xy).x) * color; + } + +*/ +static const uint8_t _sfons_fs_bytecode_spirv_vk[888] = { + 0x03,0x02,0x23,0x07,0x00,0x04,0x01,0x00,0x0b,0x00,0x08,0x00,0x22,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x11,0x00,0x02,0x00,0x01,0x00,0x00,0x00,0x0b,0x00,0x06,0x00, + 0x01,0x00,0x00,0x00,0x47,0x4c,0x53,0x4c,0x2e,0x73,0x74,0x64,0x2e,0x34,0x35,0x30, + 0x00,0x00,0x00,0x00,0x0e,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x0f,0x00,0x0a,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x6d,0x61,0x69,0x6e, + 0x00,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x11,0x00,0x00,0x00, + 0x16,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x10,0x00,0x03,0x00,0x04,0x00,0x00,0x00, + 0x07,0x00,0x00,0x00,0x03,0x00,0x03,0x00,0x02,0x00,0x00,0x00,0xcc,0x01,0x00,0x00, + 0x05,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x6d,0x61,0x69,0x6e,0x00,0x00,0x00,0x00, + 0x05,0x00,0x05,0x00,0x09,0x00,0x00,0x00,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c, + 0x6f,0x72,0x00,0x00,0x05,0x00,0x03,0x00,0x0d,0x00,0x00,0x00,0x74,0x65,0x78,0x00, + 0x05,0x00,0x03,0x00,0x11,0x00,0x00,0x00,0x73,0x6d,0x70,0x00,0x05,0x00,0x03,0x00, + 0x16,0x00,0x00,0x00,0x75,0x76,0x00,0x00,0x05,0x00,0x04,0x00,0x1f,0x00,0x00,0x00, + 0x63,0x6f,0x6c,0x6f,0x72,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x09,0x00,0x00,0x00, + 0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x0d,0x00,0x00,0x00, + 0x21,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x0d,0x00,0x00,0x00, + 0x22,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x11,0x00,0x00,0x00, + 0x21,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x11,0x00,0x00,0x00, + 0x22,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x16,0x00,0x00,0x00, + 0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x1f,0x00,0x00,0x00, + 0x1e,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x13,0x00,0x02,0x00,0x02,0x00,0x00,0x00, + 0x21,0x00,0x03,0x00,0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x16,0x00,0x03,0x00, + 0x06,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x17,0x00,0x04,0x00,0x07,0x00,0x00,0x00, + 0x06,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x08,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x08,0x00,0x00,0x00, + 0x09,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x2b,0x00,0x04,0x00,0x06,0x00,0x00,0x00, + 0x0a,0x00,0x00,0x00,0x00,0x00,0x80,0x3f,0x19,0x00,0x09,0x00,0x0b,0x00,0x00,0x00, + 0x06,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x04,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x3b,0x00,0x04,0x00, + 0x0c,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1a,0x00,0x02,0x00, + 0x0f,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x0f,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x10,0x00,0x00,0x00,0x11,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x1b,0x00,0x03,0x00,0x13,0x00,0x00,0x00,0x0b,0x00,0x00,0x00, + 0x20,0x00,0x04,0x00,0x15,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x07,0x00,0x00,0x00, + 0x3b,0x00,0x04,0x00,0x15,0x00,0x00,0x00,0x16,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x17,0x00,0x04,0x00,0x17,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x15,0x00,0x04,0x00,0x1b,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x2b,0x00,0x04,0x00,0x1b,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x3b,0x00,0x04,0x00,0x15,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x36,0x00,0x05,0x00,0x02,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0xf8,0x00,0x02,0x00,0x05,0x00,0x00,0x00,0x3d,0x00,0x04,0x00, + 0x0b,0x00,0x00,0x00,0x0e,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x3d,0x00,0x04,0x00, + 0x0f,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x56,0x00,0x05,0x00, + 0x13,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x0e,0x00,0x00,0x00,0x12,0x00,0x00,0x00, + 0x3d,0x00,0x04,0x00,0x07,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x16,0x00,0x00,0x00, + 0x4f,0x00,0x07,0x00,0x17,0x00,0x00,0x00,0x19,0x00,0x00,0x00,0x18,0x00,0x00,0x00, + 0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x57,0x00,0x05,0x00, + 0x07,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x19,0x00,0x00,0x00, + 0x51,0x00,0x05,0x00,0x06,0x00,0x00,0x00,0x1d,0x00,0x00,0x00,0x1a,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x50,0x00,0x07,0x00,0x07,0x00,0x00,0x00,0x1e,0x00,0x00,0x00, + 0x0a,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x1d,0x00,0x00,0x00, + 0x3d,0x00,0x04,0x00,0x07,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x1f,0x00,0x00,0x00, + 0x85,0x00,0x05,0x00,0x07,0x00,0x00,0x00,0x21,0x00,0x00,0x00,0x1e,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x3e,0x00,0x03,0x00,0x09,0x00,0x00,0x00,0x21,0x00,0x00,0x00, + 0xfd,0x00,0x01,0x00,0x38,0x00,0x01,0x00, +}; #elif defined(SOKOL_DUMMY_BACKEND) static const char* _sfons_vs_source_dummy = ""; static const char* _sfons_fs_source_dummy = ""; @@ -2067,11 +2276,16 @@ static int _sfons_render_create(void* user_ptr, int width, int height) { shd_desc.attrs[2].hlsl_sem_index = 2; shd_desc.attrs[3].hlsl_sem_name = "TEXCOORD"; shd_desc.attrs[3].hlsl_sem_index = 3; + shd_desc.attrs[0].base_type = SG_SHADERATTRBASETYPE_FLOAT; + shd_desc.attrs[1].base_type = SG_SHADERATTRBASETYPE_FLOAT; + shd_desc.attrs[2].base_type = SG_SHADERATTRBASETYPE_FLOAT; + shd_desc.attrs[3].base_type = SG_SHADERATTRBASETYPE_FLOAT; shd_desc.uniform_blocks[0].stage = SG_SHADERSTAGE_VERTEX; shd_desc.uniform_blocks[0].size = 128; shd_desc.uniform_blocks[0].hlsl_register_b_n = 0; shd_desc.uniform_blocks[0].msl_buffer_n = 0; shd_desc.uniform_blocks[0].wgsl_group0_binding_n = 0; + shd_desc.uniform_blocks[0].spirv_set0_binding_n = 0; shd_desc.uniform_blocks[0].glsl_uniforms[0].glsl_name = "vs_params"; shd_desc.uniform_blocks[0].glsl_uniforms[0].type = SG_UNIFORMTYPE_FLOAT4; shd_desc.uniform_blocks[0].glsl_uniforms[0].array_count = 8; @@ -2081,11 +2295,13 @@ static int _sfons_render_create(void* user_ptr, int width, int height) { shd_desc.views[0].texture.hlsl_register_t_n = 0; shd_desc.views[0].texture.msl_texture_n = 0; shd_desc.views[0].texture.wgsl_group1_binding_n = 64; + shd_desc.views[0].texture.spirv_set1_binding_n = 0; shd_desc.samplers[0].stage = SG_SHADERSTAGE_FRAGMENT; shd_desc.samplers[0].sampler_type = SG_SAMPLERTYPE_FILTERING; shd_desc.samplers[0].hlsl_register_s_n = 0; shd_desc.samplers[0].msl_sampler_n = 0; shd_desc.samplers[0].wgsl_group1_binding_n = 80; + shd_desc.samplers[0].spirv_set1_binding_n = 32; shd_desc.texture_sampler_pairs[0].stage = SG_SHADERSTAGE_FRAGMENT; shd_desc.texture_sampler_pairs[0].glsl_name = "tex_smp"; shd_desc.texture_sampler_pairs[0].view_slot = 0; @@ -2120,6 +2336,11 @@ static int _sfons_render_create(void* user_ptr, int width, int height) { #elif defined(SOKOL_WGPU) shd_desc.vertex_func.source = (const char*)_sfons_vs_source_wgsl; shd_desc.fragment_func.source = (const char*)_sfons_fs_source_wgsl; + #elif defined(SOKOL_VULKAN) + shd_desc.vertex_func.bytecode = SG_RANGE(_sfons_vs_bytecode_spirv_vk); + shd_desc.vertex_func.entry = "main"; + shd_desc.fragment_func.bytecode = SG_RANGE(_sfons_fs_bytecode_spirv_vk); + shd_desc.fragment_func.entry = "main"; #else shd_desc.vertex_func.source = _sfons_vs_source_dummy; shd_desc.fragment_func.source = _sfons_fs_source_dummy; diff --git a/util/sokol_gfx_imgui.h b/util/sokol_gfx_imgui.h index d7e659ff..58481cee 100644 --- a/util/sokol_gfx_imgui.h +++ b/util/sokol_gfx_imgui.h @@ -1239,6 +1239,7 @@ _SOKOL_PRIVATE const char* _sgimgui_backend_string(sg_backend b) { case SG_BACKEND_METAL_MACOS: return "SG_BACKEND_METAL_MACOS"; case SG_BACKEND_METAL_SIMULATOR: return "SG_BACKEND_METAL_SIMULATOR"; case SG_BACKEND_WGPU: return "SG_BACKEND_WGPU"; + case SG_BACKEND_VULKAN: return "SG_BACKEND_VULKAN"; case SG_BACKEND_DUMMY: return "SG_BACKEND_DUMMY"; default: return "???"; } @@ -3720,6 +3721,7 @@ _SOKOL_PRIVATE void _sgimgui_draw_shader_panel(sgimgui_t* ctx, sg_shader shd) { _sgimgui_igtext(" hlsl_register_b_n: %d", ub->hlsl_register_b_n); _sgimgui_igtext(" msl_buffer_n: %d", ub->msl_buffer_n); _sgimgui_igtext(" wgsl_group0_binding_n: %d", ub->wgsl_group0_binding_n); + _sgimgui_igtext(" spirv_set0_binding_n: %d", ub->spirv_set0_binding_n); _sgimgui_igtext(" glsl_uniforms:"); for (int j = 0; j < SG_MAX_UNIFORMBLOCK_MEMBERS; j++) { const sg_glsl_shader_uniform* u = &ub->glsl_uniforms[j]; @@ -3750,6 +3752,7 @@ _SOKOL_PRIVATE void _sgimgui_draw_shader_panel(sgimgui_t* ctx, sg_shader shd) { _sgimgui_igtext(" hlsl_register_t_n: %d", tex->hlsl_register_t_n); _sgimgui_igtext(" msl_texture_n: %d", tex->msl_texture_n); _sgimgui_igtext(" wgsl_group1_binding_n: %d", tex->wgsl_group1_binding_n); + _sgimgui_igtext(" spirv_set1_binding_n: %d", tex->spirv_set1_binding_n); } else if (view->storage_buffer.stage != SG_SHADERSTAGE_NONE) { const sg_shader_storage_buffer_view* sbuf = &view->storage_buffer; _sgimgui_igtext("- slot: %d", i); @@ -3763,6 +3766,7 @@ _SOKOL_PRIVATE void _sgimgui_draw_shader_panel(sgimgui_t* ctx, sg_shader shd) { } _sgimgui_igtext(" msl_buffer_n: %d", sbuf->msl_buffer_n); _sgimgui_igtext(" wgsl_group1_binding_n: %d", sbuf->wgsl_group1_binding_n); + _sgimgui_igtext(" spirv_group1_binding_n: %d\n", sbuf->spirv_set1_binding_n); _sgimgui_igtext(" glsl_binding_n: %d", sbuf->glsl_binding_n); } else if (view->storage_image.stage != SG_SHADERSTAGE_NONE) { const sg_shader_storage_image_view* simg = &view->storage_image; @@ -3775,6 +3779,7 @@ _SOKOL_PRIVATE void _sgimgui_draw_shader_panel(sgimgui_t* ctx, sg_shader shd) { _sgimgui_igtext(" hlsl_register_u_n: %d", simg->hlsl_register_u_n); _sgimgui_igtext(" msl_texture_n: %d", simg->msl_texture_n); _sgimgui_igtext(" wgsl_group2_binding_n: %d", simg->wgsl_group1_binding_n); + _sgimgui_igtext(" spirv_set1_binding_n: %d", simg->spirv_set1_binding_n); _sgimgui_igtext(" glsl_binding_n: %d", simg->glsl_binding_n); } } @@ -3794,6 +3799,7 @@ _SOKOL_PRIVATE void _sgimgui_draw_shader_panel(sgimgui_t* ctx, sg_shader shd) { _sgimgui_igtext(" hlsl_register_s_n: %d", ssd->hlsl_register_s_n); _sgimgui_igtext(" msl_sampler_n: %d", ssd->msl_sampler_n); _sgimgui_igtext(" wgsl_group1_binding_n: %d", ssd->wgsl_group1_binding_n); + _sgimgui_igtext(" spirv_set1_binding_1: %d", ssd->spirv_set1_binding_n); } _sgimgui_igtreepop(); } @@ -4291,6 +4297,17 @@ _SOKOL_PRIVATE void _sgimgui_draw_swapchain_panel(sg_swapchain* swapchain) { _sgimgui_igtext("GL Objects:"); _sgimgui_igtext(" Framebuffer: %d", swapchain->gl.framebuffer); break; + case SG_BACKEND_VULKAN: + _sgimgui_igtext("Vulkan Objects:"); + _sgimgui_igtext(" Render Image: %p", swapchain->vulkan.render_image); + _sgimgui_igtext(" Render View: %p", swapchain->vulkan.render_view); + _sgimgui_igtext(" Resolve Image: %p", swapchain->vulkan.resolve_image); + _sgimgui_igtext(" Resolve View: %p", swapchain->vulkan.resolve_view); + _sgimgui_igtext(" Depth Stencil Image: %p", swapchain->vulkan.depth_stencil_image); + _sgimgui_igtext(" Depth Stencil View: %p", swapchain->vulkan.depth_stencil_view); + _sgimgui_igtext(" Render Finished Semaphore: %p", swapchain->vulkan.render_finished_semaphore); + _sgimgui_igtext(" Present Complete Semaphore: %p", swapchain->vulkan.present_complete_semaphore); + break; default: _sgimgui_igtext(" UNKNOWN BACKEND!"); break; @@ -4500,6 +4517,7 @@ _SOKOL_PRIVATE void _sgimgui_draw_caps_panel(void) { _sgimgui_igtext(" gl_max_vertex_uniform_components: %d", l.gl_max_vertex_uniform_components); _sgimgui_igtext(" gl_max_combined_texture_image_units: %d", l.gl_max_combined_texture_image_units); _sgimgui_igtext(" d3d11_max_unordered_access_views: %d", l.d3d11_max_unordered_access_views); + _sgimgui_igtext(" vk_min_uniform_buffer_offset_alignment: %d", l.vk_min_uniform_buffer_offset_alignment); _sgimgui_igtext("\nStruct Sizes:\n"); _sgimgui_igtext(" sg_desc: %d bytes\n", (int)sizeof(sg_desc)); _sgimgui_igtext(" sg_buffer_desc: %d bytes\n", (int)sizeof(sg_buffer_desc)); @@ -4706,6 +4724,18 @@ _SOKOL_PRIVATE void _sgimgui_draw_frame_stats_panel(sgimgui_t* ctx) { _sgimgui_frame_stats(d3d11.num_map); _sgimgui_frame_stats(d3d11.num_unmap); break; + case SG_BACKEND_VULKAN: + _sgimgui_frame_stats(vk.num_cmd_pipeline_barrier); + _sgimgui_frame_stats(vk.num_allocate_memory); + _sgimgui_frame_stats(vk.num_free_memory); + _sgimgui_frame_stats(vk.size_allocate_memory); + _sgimgui_frame_stats(vk.num_delete_queue_added); + _sgimgui_frame_stats(vk.num_delete_queue_collected); + _sgimgui_frame_stats(vk.num_cmd_copy_buffer); + _sgimgui_frame_stats(vk.num_cmd_copy_buffer_to_image); + _sgimgui_frame_stats(vk.num_cmd_set_descriptor_buffer_offsets); + _sgimgui_frame_stats(vk.size_descriptor_buffer_writes); + break; default: break; } _sgimgui_igendtable(); diff --git a/util/sokol_gl.h b/util/sokol_gl.h index afee0e29..249bb441 100644 --- a/util/sokol_gl.h +++ b/util/sokol_gl.h @@ -22,6 +22,7 @@ SOKOL_D3D11 SOKOL_METAL SOKOL_WGPU + SOKOL_VULKAN ...optionally provide the following macros to override defaults: @@ -987,7 +988,7 @@ inline sgl_pipeline sgl_context_make_pipeline(sgl_context ctx, const sg_pipeline /* Embedded source code compiled with: - sokol-shdc -i sgl.glsl -o sgl.h -l glsl410:glsl300es:hlsl4:metal_macos:metal_ios:metal_sim:wgsl -b + sokol-shdc -i sgl.glsl -o sgl.h -l glsl410:glsl300es:hlsl4:metal_macos:metal_ios:metal_sim:wgsl:spirv_vk -b (not that for Metal and D3D11 byte code, sokol-shdc must be run on macOS and Windows) @@ -2690,6 +2691,208 @@ static const uint8_t _sgl_fs_source_wgsl[647] = { 0x6e,0x5f,0x6f,0x75,0x74,0x28,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, 0x29,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, }; +#elif defined(SOKOL_VULKAN) +/* + #version 460 + + layout(set = 0, binding = 0, std140) uniform vs_params + { + mat4 mvp; + mat4 tm; + } _19; + + layout(location = 0) in vec4 position; + layout(location = 3) in float psize; + layout(location = 0) out vec4 uv; + layout(location = 1) in vec2 texcoord0; + layout(location = 1) out vec4 color; + layout(location = 2) in vec4 color0; + + void main() + { + gl_Position = _19.mvp * position; + gl_PointSize = psize; + uv = _19.tm * vec4(texcoord0, 0.0, 1.0); + color = color0; + } + +*/ +static const uint8_t _sgl_vs_bytecode_spirv_vk[1668] = { + 0x03,0x02,0x23,0x07,0x00,0x04,0x01,0x00,0x0b,0x00,0x08,0x00,0x33,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x11,0x00,0x02,0x00,0x01,0x00,0x00,0x00,0x0b,0x00,0x06,0x00, + 0x01,0x00,0x00,0x00,0x47,0x4c,0x53,0x4c,0x2e,0x73,0x74,0x64,0x2e,0x34,0x35,0x30, + 0x00,0x00,0x00,0x00,0x0e,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x0f,0x00,0x0d,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x6d,0x61,0x69,0x6e, + 0x00,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x18,0x00,0x00,0x00, + 0x1f,0x00,0x00,0x00,0x23,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x30,0x00,0x00,0x00, + 0x31,0x00,0x00,0x00,0x03,0x00,0x03,0x00,0x02,0x00,0x00,0x00,0xcc,0x01,0x00,0x00, + 0x05,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x6d,0x61,0x69,0x6e,0x00,0x00,0x00,0x00, + 0x05,0x00,0x06,0x00,0x0b,0x00,0x00,0x00,0x67,0x6c,0x5f,0x50,0x65,0x72,0x56,0x65, + 0x72,0x74,0x65,0x78,0x00,0x00,0x00,0x00,0x06,0x00,0x06,0x00,0x0b,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00, + 0x06,0x00,0x07,0x00,0x0b,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x67,0x6c,0x5f,0x50, + 0x6f,0x69,0x6e,0x74,0x53,0x69,0x7a,0x65,0x00,0x00,0x00,0x00,0x06,0x00,0x07,0x00, + 0x0b,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x67,0x6c,0x5f,0x43,0x6c,0x69,0x70,0x44, + 0x69,0x73,0x74,0x61,0x6e,0x63,0x65,0x00,0x06,0x00,0x07,0x00,0x0b,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x67,0x6c,0x5f,0x43,0x75,0x6c,0x6c,0x44,0x69,0x73,0x74,0x61, + 0x6e,0x63,0x65,0x00,0x05,0x00,0x03,0x00,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x05,0x00,0x05,0x00,0x11,0x00,0x00,0x00,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d, + 0x73,0x00,0x00,0x00,0x06,0x00,0x04,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x6d,0x76,0x70,0x00,0x06,0x00,0x04,0x00,0x11,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x74,0x6d,0x00,0x00,0x05,0x00,0x03,0x00,0x13,0x00,0x00,0x00,0x5f,0x31,0x39,0x00, + 0x05,0x00,0x05,0x00,0x18,0x00,0x00,0x00,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e, + 0x00,0x00,0x00,0x00,0x05,0x00,0x04,0x00,0x1f,0x00,0x00,0x00,0x70,0x73,0x69,0x7a, + 0x65,0x00,0x00,0x00,0x05,0x00,0x03,0x00,0x23,0x00,0x00,0x00,0x75,0x76,0x00,0x00, + 0x05,0x00,0x05,0x00,0x28,0x00,0x00,0x00,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64, + 0x30,0x00,0x00,0x00,0x05,0x00,0x04,0x00,0x30,0x00,0x00,0x00,0x63,0x6f,0x6c,0x6f, + 0x72,0x00,0x00,0x00,0x05,0x00,0x04,0x00,0x31,0x00,0x00,0x00,0x63,0x6f,0x6c,0x6f, + 0x72,0x30,0x00,0x00,0x47,0x00,0x03,0x00,0x0b,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x48,0x00,0x05,0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x48,0x00,0x05,0x00,0x0b,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x0b,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x48,0x00,0x05,0x00,0x0b,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x48,0x00,0x05,0x00, + 0x0b,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x04,0x00,0x00,0x00, + 0x47,0x00,0x03,0x00,0x11,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x48,0x00,0x04,0x00, + 0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x48,0x00,0x05,0x00, + 0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x10,0x00,0x00,0x00, + 0x48,0x00,0x05,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x23,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x48,0x00,0x04,0x00,0x11,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x05,0x00,0x00,0x00,0x48,0x00,0x05,0x00,0x11,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x07,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x48,0x00,0x05,0x00,0x11,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x23,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x47,0x00,0x04,0x00, + 0x13,0x00,0x00,0x00,0x21,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00, + 0x13,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00, + 0x18,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00, + 0x1f,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x47,0x00,0x04,0x00, + 0x23,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00, + 0x28,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x47,0x00,0x04,0x00, + 0x30,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x47,0x00,0x04,0x00, + 0x31,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x13,0x00,0x02,0x00, + 0x02,0x00,0x00,0x00,0x21,0x00,0x03,0x00,0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x16,0x00,0x03,0x00,0x06,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x17,0x00,0x04,0x00, + 0x07,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x15,0x00,0x04,0x00, + 0x08,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2b,0x00,0x04,0x00, + 0x08,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x1c,0x00,0x04,0x00, + 0x0a,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x1e,0x00,0x06,0x00, + 0x0b,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x0a,0x00,0x00,0x00, + 0x0a,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x0c,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x0b,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x0c,0x00,0x00,0x00,0x0d,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x15,0x00,0x04,0x00,0x0e,0x00,0x00,0x00,0x20,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x2b,0x00,0x04,0x00,0x0e,0x00,0x00,0x00,0x0f,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x18,0x00,0x04,0x00,0x10,0x00,0x00,0x00,0x07,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x1e,0x00,0x04,0x00,0x11,0x00,0x00,0x00,0x10,0x00,0x00,0x00, + 0x10,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x12,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x11,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x12,0x00,0x00,0x00,0x13,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x14,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x10,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x17,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x07,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x17,0x00,0x00,0x00,0x18,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x1b,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x07,0x00,0x00,0x00,0x2b,0x00,0x04,0x00,0x0e,0x00,0x00,0x00,0x1d,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x1e,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x06,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x1e,0x00,0x00,0x00,0x1f,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x21,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x06,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x1b,0x00,0x00,0x00,0x23,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x17,0x00,0x04,0x00,0x26,0x00,0x00,0x00,0x06,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x27,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x26,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x27,0x00,0x00,0x00,0x28,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x2b,0x00,0x04,0x00,0x06,0x00,0x00,0x00,0x2a,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x2b,0x00,0x04,0x00,0x06,0x00,0x00,0x00,0x2b,0x00,0x00,0x00, + 0x00,0x00,0x80,0x3f,0x3b,0x00,0x04,0x00,0x1b,0x00,0x00,0x00,0x30,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x17,0x00,0x00,0x00,0x31,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x36,0x00,0x05,0x00,0x02,0x00,0x00,0x00,0x04,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0xf8,0x00,0x02,0x00,0x05,0x00,0x00,0x00, + 0x41,0x00,0x05,0x00,0x14,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x13,0x00,0x00,0x00, + 0x0f,0x00,0x00,0x00,0x3d,0x00,0x04,0x00,0x10,0x00,0x00,0x00,0x16,0x00,0x00,0x00, + 0x15,0x00,0x00,0x00,0x3d,0x00,0x04,0x00,0x07,0x00,0x00,0x00,0x19,0x00,0x00,0x00, + 0x18,0x00,0x00,0x00,0x91,0x00,0x05,0x00,0x07,0x00,0x00,0x00,0x1a,0x00,0x00,0x00, + 0x16,0x00,0x00,0x00,0x19,0x00,0x00,0x00,0x41,0x00,0x05,0x00,0x1b,0x00,0x00,0x00, + 0x1c,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x3e,0x00,0x03,0x00, + 0x1c,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0x3d,0x00,0x04,0x00,0x06,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x41,0x00,0x05,0x00,0x21,0x00,0x00,0x00, + 0x22,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x1d,0x00,0x00,0x00,0x3e,0x00,0x03,0x00, + 0x22,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x41,0x00,0x05,0x00,0x14,0x00,0x00,0x00, + 0x24,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x1d,0x00,0x00,0x00,0x3d,0x00,0x04,0x00, + 0x10,0x00,0x00,0x00,0x25,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x3d,0x00,0x04,0x00, + 0x26,0x00,0x00,0x00,0x29,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x51,0x00,0x05,0x00, + 0x06,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0x29,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x51,0x00,0x05,0x00,0x06,0x00,0x00,0x00,0x2d,0x00,0x00,0x00,0x29,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x50,0x00,0x07,0x00,0x07,0x00,0x00,0x00,0x2e,0x00,0x00,0x00, + 0x2c,0x00,0x00,0x00,0x2d,0x00,0x00,0x00,0x2a,0x00,0x00,0x00,0x2b,0x00,0x00,0x00, + 0x91,0x00,0x05,0x00,0x07,0x00,0x00,0x00,0x2f,0x00,0x00,0x00,0x25,0x00,0x00,0x00, + 0x2e,0x00,0x00,0x00,0x3e,0x00,0x03,0x00,0x23,0x00,0x00,0x00,0x2f,0x00,0x00,0x00, + 0x3d,0x00,0x04,0x00,0x07,0x00,0x00,0x00,0x32,0x00,0x00,0x00,0x31,0x00,0x00,0x00, + 0x3e,0x00,0x03,0x00,0x30,0x00,0x00,0x00,0x32,0x00,0x00,0x00,0xfd,0x00,0x01,0x00, + 0x38,0x00,0x01,0x00, +}; +/* + #version 460 + + layout(set = 1, binding = 0) uniform texture2D tex; + layout(set = 1, binding = 32) uniform sampler smp; + + layout(location = 0) out vec4 frag_color; + layout(location = 0) in vec4 uv; + layout(location = 1) in vec4 color; + + void main() + { + frag_color = texture(sampler2D(tex, smp), uv.xy) * color; + } + +*/ +static const uint8_t _sgl_fs_bytecode_spirv_vk[792] = { + 0x03,0x02,0x23,0x07,0x00,0x04,0x01,0x00,0x0b,0x00,0x08,0x00,0x1d,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x11,0x00,0x02,0x00,0x01,0x00,0x00,0x00,0x0b,0x00,0x06,0x00, + 0x01,0x00,0x00,0x00,0x47,0x4c,0x53,0x4c,0x2e,0x73,0x74,0x64,0x2e,0x34,0x35,0x30, + 0x00,0x00,0x00,0x00,0x0e,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x0f,0x00,0x0a,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x6d,0x61,0x69,0x6e, + 0x00,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x10,0x00,0x00,0x00, + 0x15,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0x10,0x00,0x03,0x00,0x04,0x00,0x00,0x00, + 0x07,0x00,0x00,0x00,0x03,0x00,0x03,0x00,0x02,0x00,0x00,0x00,0xcc,0x01,0x00,0x00, + 0x05,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x6d,0x61,0x69,0x6e,0x00,0x00,0x00,0x00, + 0x05,0x00,0x05,0x00,0x09,0x00,0x00,0x00,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c, + 0x6f,0x72,0x00,0x00,0x05,0x00,0x03,0x00,0x0c,0x00,0x00,0x00,0x74,0x65,0x78,0x00, + 0x05,0x00,0x03,0x00,0x10,0x00,0x00,0x00,0x73,0x6d,0x70,0x00,0x05,0x00,0x03,0x00, + 0x15,0x00,0x00,0x00,0x75,0x76,0x00,0x00,0x05,0x00,0x04,0x00,0x1a,0x00,0x00,0x00, + 0x63,0x6f,0x6c,0x6f,0x72,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x09,0x00,0x00,0x00, + 0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x0c,0x00,0x00,0x00, + 0x21,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x0c,0x00,0x00,0x00, + 0x22,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x10,0x00,0x00,0x00, + 0x21,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x10,0x00,0x00,0x00, + 0x22,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x15,0x00,0x00,0x00, + 0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x1a,0x00,0x00,0x00, + 0x1e,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x13,0x00,0x02,0x00,0x02,0x00,0x00,0x00, + 0x21,0x00,0x03,0x00,0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x16,0x00,0x03,0x00, + 0x06,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x17,0x00,0x04,0x00,0x07,0x00,0x00,0x00, + 0x06,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x08,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x08,0x00,0x00,0x00, + 0x09,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x19,0x00,0x09,0x00,0x0a,0x00,0x00,0x00, + 0x06,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x04,0x00, + 0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x3b,0x00,0x04,0x00, + 0x0b,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1a,0x00,0x02,0x00, + 0x0e,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x0e,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x0f,0x00,0x00,0x00,0x10,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x1b,0x00,0x03,0x00,0x12,0x00,0x00,0x00,0x0a,0x00,0x00,0x00, + 0x20,0x00,0x04,0x00,0x14,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x07,0x00,0x00,0x00, + 0x3b,0x00,0x04,0x00,0x14,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x17,0x00,0x04,0x00,0x16,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x3b,0x00,0x04,0x00,0x14,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x36,0x00,0x05,0x00,0x02,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0xf8,0x00,0x02,0x00,0x05,0x00,0x00,0x00,0x3d,0x00,0x04,0x00, + 0x0a,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x3d,0x00,0x04,0x00, + 0x0e,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x56,0x00,0x05,0x00, + 0x12,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x11,0x00,0x00,0x00, + 0x3d,0x00,0x04,0x00,0x07,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x15,0x00,0x00,0x00, + 0x4f,0x00,0x07,0x00,0x16,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x17,0x00,0x00,0x00, + 0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x57,0x00,0x05,0x00, + 0x07,0x00,0x00,0x00,0x19,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x18,0x00,0x00,0x00, + 0x3d,0x00,0x04,0x00,0x07,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x1a,0x00,0x00,0x00, + 0x85,0x00,0x05,0x00,0x07,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x19,0x00,0x00,0x00, + 0x1b,0x00,0x00,0x00,0x3e,0x00,0x03,0x00,0x09,0x00,0x00,0x00,0x1c,0x00,0x00,0x00, + 0xfd,0x00,0x01,0x00,0x38,0x00,0x01,0x00, +}; + #elif defined(SOKOL_DUMMY_BACKEND) static const char* _sgl_vs_source_dummy = ""; static const char* _sgl_fs_source_dummy = ""; @@ -3787,11 +3990,16 @@ static void _sgl_setup_common(void) { shd_desc.attrs[2].hlsl_sem_index = 2; shd_desc.attrs[3].hlsl_sem_name = "TEXCOORD"; shd_desc.attrs[3].hlsl_sem_index = 3; + shd_desc.attrs[0].base_type = SG_SHADERATTRBASETYPE_FLOAT; + shd_desc.attrs[1].base_type = SG_SHADERATTRBASETYPE_FLOAT; + shd_desc.attrs[2].base_type = SG_SHADERATTRBASETYPE_FLOAT; + shd_desc.attrs[3].base_type = SG_SHADERATTRBASETYPE_FLOAT; shd_desc.uniform_blocks[0].stage = SG_SHADERSTAGE_VERTEX; shd_desc.uniform_blocks[0].size = sizeof(_sgl_uniform_t); shd_desc.uniform_blocks[0].hlsl_register_b_n = 0; shd_desc.uniform_blocks[0].msl_buffer_n = 0; shd_desc.uniform_blocks[0].wgsl_group0_binding_n = 0; + shd_desc.uniform_blocks[0].spirv_set0_binding_n = 0; shd_desc.uniform_blocks[0].glsl_uniforms[0].glsl_name = "vs_params"; shd_desc.uniform_blocks[0].glsl_uniforms[0].type = SG_UNIFORMTYPE_FLOAT4; shd_desc.uniform_blocks[0].glsl_uniforms[0].array_count = 8; @@ -3801,11 +4009,13 @@ static void _sgl_setup_common(void) { shd_desc.views[0].texture.hlsl_register_t_n = 0; shd_desc.views[0].texture.msl_texture_n = 0; shd_desc.views[0].texture.wgsl_group1_binding_n = 64; + shd_desc.views[0].texture.spirv_set1_binding_n = 0; shd_desc.samplers[0].stage = SG_SHADERSTAGE_FRAGMENT; shd_desc.samplers[0].sampler_type = SG_SAMPLERTYPE_FILTERING; shd_desc.samplers[0].hlsl_register_s_n = 0; shd_desc.samplers[0].msl_sampler_n = 0; shd_desc.samplers[0].wgsl_group1_binding_n = 80; + shd_desc.samplers[0].spirv_set1_binding_n = 32; shd_desc.texture_sampler_pairs[0].stage = SG_SHADERSTAGE_FRAGMENT; shd_desc.texture_sampler_pairs[0].view_slot = 0; shd_desc.texture_sampler_pairs[0].sampler_slot = 0; @@ -3840,6 +4050,11 @@ static void _sgl_setup_common(void) { #elif defined(SOKOL_WGPU) shd_desc.vertex_func.source = (const char*)_sgl_vs_source_wgsl; shd_desc.fragment_func.source = (const char*)_sgl_fs_source_wgsl; + #elif defined(SOKOL_VULKAN) + shd_desc.vertex_func.bytecode = SG_RANGE(_sgl_vs_bytecode_spirv_vk); + shd_desc.vertex_func.entry = "main"; + shd_desc.fragment_func.bytecode = SG_RANGE(_sgl_fs_bytecode_spirv_vk); + shd_desc.fragment_func.entry = "main"; #else shd_desc.vertex_func.source = _sgl_vs_source_dummy; shd_desc.fragment_func.source = _sgl_fs_source_dummy; diff --git a/util/sokol_imgui.h b/util/sokol_imgui.h index 30992d5e..89c47890 100644 --- a/util/sokol_imgui.h +++ b/util/sokol_imgui.h @@ -31,6 +31,7 @@ SOKOL_D3D11 SOKOL_METAL SOKOL_WGPU + SOKOL_VULKAN Optionally provide the following configuration define both before including the the declaration and implementation: @@ -2242,6 +2243,190 @@ static const uint8_t _simgui_fs_source_wgsl[630] = { 0x5f,0x6f,0x75,0x74,0x28,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x29, 0x3b,0x0a,0x7d,0x0a,0x0a,0x00, }; +#elif defined(SOKOL_VULKAN) +/* + #version 460 + + layout(set = 0, binding = 0, std140) uniform vs_params + { + vec2 disp_size; + } _22; + + layout(location = 0) in vec2 position; + layout(location = 0) out vec2 uv; + layout(location = 1) in vec2 texcoord0; + layout(location = 1) out vec4 color; + layout(location = 2) in vec4 color0; + + void main() + { + gl_Position = vec4(((position / _22.disp_size) - vec2(0.5)) * vec2(2.0, -2.0), 0.5, 1.0); + uv = texcoord0; + color = color0; + } + +*/ +static const uint8_t _simgui_vs_bytecode_spirv_vk[1472] = { + 0x03,0x02,0x23,0x07,0x00,0x04,0x01,0x00,0x0b,0x00,0x08,0x00,0x30,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x11,0x00,0x02,0x00,0x01,0x00,0x00,0x00,0x0b,0x00,0x06,0x00, + 0x01,0x00,0x00,0x00,0x47,0x4c,0x53,0x4c,0x2e,0x73,0x74,0x64,0x2e,0x34,0x35,0x30, + 0x00,0x00,0x00,0x00,0x0e,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x0f,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x6d,0x61,0x69,0x6e, + 0x00,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x16,0x00,0x00,0x00, + 0x29,0x00,0x00,0x00,0x2a,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0x2e,0x00,0x00,0x00, + 0x03,0x00,0x03,0x00,0x02,0x00,0x00,0x00,0xcc,0x01,0x00,0x00,0x05,0x00,0x04,0x00, + 0x04,0x00,0x00,0x00,0x6d,0x61,0x69,0x6e,0x00,0x00,0x00,0x00,0x05,0x00,0x06,0x00, + 0x0b,0x00,0x00,0x00,0x67,0x6c,0x5f,0x50,0x65,0x72,0x56,0x65,0x72,0x74,0x65,0x78, + 0x00,0x00,0x00,0x00,0x06,0x00,0x06,0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0x06,0x00,0x07,0x00, + 0x0b,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x67,0x6c,0x5f,0x50,0x6f,0x69,0x6e,0x74, + 0x53,0x69,0x7a,0x65,0x00,0x00,0x00,0x00,0x06,0x00,0x07,0x00,0x0b,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x67,0x6c,0x5f,0x43,0x6c,0x69,0x70,0x44,0x69,0x73,0x74,0x61, + 0x6e,0x63,0x65,0x00,0x06,0x00,0x07,0x00,0x0b,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x67,0x6c,0x5f,0x43,0x75,0x6c,0x6c,0x44,0x69,0x73,0x74,0x61,0x6e,0x63,0x65,0x00, + 0x05,0x00,0x03,0x00,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x05,0x00, + 0x12,0x00,0x00,0x00,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0x00,0x00,0x00, + 0x05,0x00,0x05,0x00,0x14,0x00,0x00,0x00,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d, + 0x73,0x00,0x00,0x00,0x06,0x00,0x06,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x64,0x69,0x73,0x70,0x5f,0x73,0x69,0x7a,0x65,0x00,0x00,0x00,0x05,0x00,0x03,0x00, + 0x16,0x00,0x00,0x00,0x5f,0x32,0x32,0x00,0x05,0x00,0x03,0x00,0x29,0x00,0x00,0x00, + 0x75,0x76,0x00,0x00,0x05,0x00,0x05,0x00,0x2a,0x00,0x00,0x00,0x74,0x65,0x78,0x63, + 0x6f,0x6f,0x72,0x64,0x30,0x00,0x00,0x00,0x05,0x00,0x04,0x00,0x2c,0x00,0x00,0x00, + 0x63,0x6f,0x6c,0x6f,0x72,0x00,0x00,0x00,0x05,0x00,0x04,0x00,0x2e,0x00,0x00,0x00, + 0x63,0x6f,0x6c,0x6f,0x72,0x30,0x00,0x00,0x47,0x00,0x03,0x00,0x0b,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x48,0x00,0x05,0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x05,0x00,0x0b,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x48,0x00,0x05,0x00, + 0x0b,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x48,0x00,0x05,0x00,0x0b,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x0b,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x12,0x00,0x00,0x00,0x1e,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x47,0x00,0x03,0x00,0x14,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x48,0x00,0x05,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x23,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x16,0x00,0x00,0x00,0x21,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x16,0x00,0x00,0x00,0x22,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x29,0x00,0x00,0x00,0x1e,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x2a,0x00,0x00,0x00,0x1e,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x2c,0x00,0x00,0x00,0x1e,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x2e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x13,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x21,0x00,0x03,0x00, + 0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x16,0x00,0x03,0x00,0x06,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x17,0x00,0x04,0x00,0x07,0x00,0x00,0x00,0x06,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x15,0x00,0x04,0x00,0x08,0x00,0x00,0x00,0x20,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x2b,0x00,0x04,0x00,0x08,0x00,0x00,0x00,0x09,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x1c,0x00,0x04,0x00,0x0a,0x00,0x00,0x00,0x06,0x00,0x00,0x00, + 0x09,0x00,0x00,0x00,0x1e,0x00,0x06,0x00,0x0b,0x00,0x00,0x00,0x07,0x00,0x00,0x00, + 0x06,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x20,0x00,0x04,0x00, + 0x0c,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x3b,0x00,0x04,0x00, + 0x0c,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x15,0x00,0x04,0x00, + 0x0e,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x2b,0x00,0x04,0x00, + 0x0e,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x17,0x00,0x04,0x00, + 0x10,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x20,0x00,0x04,0x00, + 0x11,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x3b,0x00,0x04,0x00, + 0x11,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x1e,0x00,0x03,0x00, + 0x14,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x15,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x15,0x00,0x00,0x00, + 0x16,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x17,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x2b,0x00,0x04,0x00,0x06,0x00,0x00,0x00, + 0x1b,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x2c,0x00,0x05,0x00,0x10,0x00,0x00,0x00, + 0x1c,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x2b,0x00,0x04,0x00, + 0x06,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x2b,0x00,0x04,0x00, + 0x06,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x2c,0x00,0x05,0x00, + 0x10,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1f,0x00,0x00,0x00, + 0x2b,0x00,0x04,0x00,0x06,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x00,0x00,0x80,0x3f, + 0x20,0x00,0x04,0x00,0x26,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x07,0x00,0x00,0x00, + 0x20,0x00,0x04,0x00,0x28,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x10,0x00,0x00,0x00, + 0x3b,0x00,0x04,0x00,0x28,0x00,0x00,0x00,0x29,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x3b,0x00,0x04,0x00,0x11,0x00,0x00,0x00,0x2a,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x3b,0x00,0x04,0x00,0x26,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x20,0x00,0x04,0x00,0x2d,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x07,0x00,0x00,0x00, + 0x3b,0x00,0x04,0x00,0x2d,0x00,0x00,0x00,0x2e,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x36,0x00,0x05,0x00,0x02,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0xf8,0x00,0x02,0x00,0x05,0x00,0x00,0x00,0x3d,0x00,0x04,0x00, + 0x10,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x41,0x00,0x05,0x00, + 0x17,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x16,0x00,0x00,0x00,0x0f,0x00,0x00,0x00, + 0x3d,0x00,0x04,0x00,0x10,0x00,0x00,0x00,0x19,0x00,0x00,0x00,0x18,0x00,0x00,0x00, + 0x88,0x00,0x05,0x00,0x10,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0x13,0x00,0x00,0x00, + 0x19,0x00,0x00,0x00,0x83,0x00,0x05,0x00,0x10,0x00,0x00,0x00,0x1d,0x00,0x00,0x00, + 0x1a,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x85,0x00,0x05,0x00,0x10,0x00,0x00,0x00, + 0x21,0x00,0x00,0x00,0x1d,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x51,0x00,0x05,0x00, + 0x06,0x00,0x00,0x00,0x23,0x00,0x00,0x00,0x21,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x51,0x00,0x05,0x00,0x06,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x21,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x50,0x00,0x07,0x00,0x07,0x00,0x00,0x00,0x25,0x00,0x00,0x00, + 0x23,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x22,0x00,0x00,0x00, + 0x41,0x00,0x05,0x00,0x26,0x00,0x00,0x00,0x27,0x00,0x00,0x00,0x0d,0x00,0x00,0x00, + 0x0f,0x00,0x00,0x00,0x3e,0x00,0x03,0x00,0x27,0x00,0x00,0x00,0x25,0x00,0x00,0x00, + 0x3d,0x00,0x04,0x00,0x10,0x00,0x00,0x00,0x2b,0x00,0x00,0x00,0x2a,0x00,0x00,0x00, + 0x3e,0x00,0x03,0x00,0x29,0x00,0x00,0x00,0x2b,0x00,0x00,0x00,0x3d,0x00,0x04,0x00, + 0x07,0x00,0x00,0x00,0x2f,0x00,0x00,0x00,0x2e,0x00,0x00,0x00,0x3e,0x00,0x03,0x00, + 0x2c,0x00,0x00,0x00,0x2f,0x00,0x00,0x00,0xfd,0x00,0x01,0x00,0x38,0x00,0x01,0x00, +}; +/* + #version 460 + + layout(set = 1, binding = 0) uniform texture2D tex; + layout(set = 1, binding = 32) uniform sampler smp; + + layout(location = 0) out vec4 frag_color; + layout(location = 0) in vec2 uv; + layout(location = 1) in vec4 color; + + void main() + { + frag_color = texture(sampler2D(tex, smp), uv) * color; + } + +*/ +static const uint8_t _simgui_fs_bytecode_spirv_vk[780] = { + 0x03,0x02,0x23,0x07,0x00,0x04,0x01,0x00,0x0b,0x00,0x08,0x00,0x1d,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x11,0x00,0x02,0x00,0x01,0x00,0x00,0x00,0x0b,0x00,0x06,0x00, + 0x01,0x00,0x00,0x00,0x47,0x4c,0x53,0x4c,0x2e,0x73,0x74,0x64,0x2e,0x34,0x35,0x30, + 0x00,0x00,0x00,0x00,0x0e,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x0f,0x00,0x0a,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x6d,0x61,0x69,0x6e, + 0x00,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x10,0x00,0x00,0x00, + 0x16,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0x10,0x00,0x03,0x00,0x04,0x00,0x00,0x00, + 0x07,0x00,0x00,0x00,0x03,0x00,0x03,0x00,0x02,0x00,0x00,0x00,0xcc,0x01,0x00,0x00, + 0x05,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x6d,0x61,0x69,0x6e,0x00,0x00,0x00,0x00, + 0x05,0x00,0x05,0x00,0x09,0x00,0x00,0x00,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c, + 0x6f,0x72,0x00,0x00,0x05,0x00,0x03,0x00,0x0c,0x00,0x00,0x00,0x74,0x65,0x78,0x00, + 0x05,0x00,0x03,0x00,0x10,0x00,0x00,0x00,0x73,0x6d,0x70,0x00,0x05,0x00,0x03,0x00, + 0x16,0x00,0x00,0x00,0x75,0x76,0x00,0x00,0x05,0x00,0x04,0x00,0x1a,0x00,0x00,0x00, + 0x63,0x6f,0x6c,0x6f,0x72,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x09,0x00,0x00,0x00, + 0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x0c,0x00,0x00,0x00, + 0x21,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x0c,0x00,0x00,0x00, + 0x22,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x10,0x00,0x00,0x00, + 0x21,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x10,0x00,0x00,0x00, + 0x22,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x16,0x00,0x00,0x00, + 0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x1a,0x00,0x00,0x00, + 0x1e,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x13,0x00,0x02,0x00,0x02,0x00,0x00,0x00, + 0x21,0x00,0x03,0x00,0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x16,0x00,0x03,0x00, + 0x06,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x17,0x00,0x04,0x00,0x07,0x00,0x00,0x00, + 0x06,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x08,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x08,0x00,0x00,0x00, + 0x09,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x19,0x00,0x09,0x00,0x0a,0x00,0x00,0x00, + 0x06,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x04,0x00, + 0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x3b,0x00,0x04,0x00, + 0x0b,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1a,0x00,0x02,0x00, + 0x0e,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x0e,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x0f,0x00,0x00,0x00,0x10,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x1b,0x00,0x03,0x00,0x12,0x00,0x00,0x00,0x0a,0x00,0x00,0x00, + 0x17,0x00,0x04,0x00,0x14,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x20,0x00,0x04,0x00,0x15,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x14,0x00,0x00,0x00, + 0x3b,0x00,0x04,0x00,0x15,0x00,0x00,0x00,0x16,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x20,0x00,0x04,0x00,0x19,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x07,0x00,0x00,0x00, + 0x3b,0x00,0x04,0x00,0x19,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x36,0x00,0x05,0x00,0x02,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0xf8,0x00,0x02,0x00,0x05,0x00,0x00,0x00,0x3d,0x00,0x04,0x00, + 0x0a,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x3d,0x00,0x04,0x00, + 0x0e,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x56,0x00,0x05,0x00, + 0x12,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x11,0x00,0x00,0x00, + 0x3d,0x00,0x04,0x00,0x14,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x16,0x00,0x00,0x00, + 0x57,0x00,0x05,0x00,0x07,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x13,0x00,0x00,0x00, + 0x17,0x00,0x00,0x00,0x3d,0x00,0x04,0x00,0x07,0x00,0x00,0x00,0x1b,0x00,0x00,0x00, + 0x1a,0x00,0x00,0x00,0x85,0x00,0x05,0x00,0x07,0x00,0x00,0x00,0x1c,0x00,0x00,0x00, + 0x18,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x3e,0x00,0x03,0x00,0x09,0x00,0x00,0x00, + 0x1c,0x00,0x00,0x00,0xfd,0x00,0x01,0x00,0x38,0x00,0x01,0x00, +}; #elif defined(SOKOL_DUMMY_BACKEND) static const char* _simgui_vs_source_dummy = ""; static const char* _simgui_fs_source_dummy = ""; @@ -2726,6 +2911,9 @@ SOKOL_API_IMPL void simgui_setup(const simgui_desc_t* desc) { shd_desc.attrs[1].hlsl_sem_index = 1; shd_desc.attrs[2].hlsl_sem_name = "TEXCOORD"; shd_desc.attrs[2].hlsl_sem_index = 2; + shd_desc.attrs[0].base_type = SG_SHADERATTRBASETYPE_FLOAT; + shd_desc.attrs[1].base_type = SG_SHADERATTRBASETYPE_FLOAT; + shd_desc.attrs[2].base_type = SG_SHADERATTRBASETYPE_FLOAT; shd_desc.uniform_blocks[0].stage = SG_SHADERSTAGE_VERTEX; shd_desc.uniform_blocks[0].size = sizeof(_simgui_vs_params_t); shd_desc.uniform_blocks[0].hlsl_register_b_n = 0; @@ -2734,17 +2922,20 @@ SOKOL_API_IMPL void simgui_setup(const simgui_desc_t* desc) { shd_desc.uniform_blocks[0].glsl_uniforms[0].glsl_name = "vs_params"; shd_desc.uniform_blocks[0].glsl_uniforms[0].type = SG_UNIFORMTYPE_FLOAT4; shd_desc.uniform_blocks[0].glsl_uniforms[0].array_count = 1; + shd_desc.uniform_blocks[0].spirv_set0_binding_n = 0; shd_desc.views[0].texture.stage = SG_SHADERSTAGE_FRAGMENT; shd_desc.views[0].texture.image_type = SG_IMAGETYPE_2D; shd_desc.views[0].texture.sample_type = SG_IMAGESAMPLETYPE_FLOAT; shd_desc.views[0].texture.hlsl_register_t_n = 0; shd_desc.views[0].texture.msl_texture_n = 0; shd_desc.views[0].texture.wgsl_group1_binding_n = 64; + shd_desc.views[0].texture.spirv_set1_binding_n = 0; shd_desc.samplers[0].stage = SG_SHADERSTAGE_FRAGMENT; shd_desc.samplers[0].sampler_type = SG_SAMPLERTYPE_FILTERING; shd_desc.samplers[0].hlsl_register_s_n = 0; shd_desc.samplers[0].msl_sampler_n = 0; shd_desc.samplers[0].wgsl_group1_binding_n = 80; + shd_desc.samplers[0].spirv_set1_binding_n = 32; shd_desc.texture_sampler_pairs[0].stage = SG_SHADERSTAGE_FRAGMENT; shd_desc.texture_sampler_pairs[0].view_slot = 0; shd_desc.texture_sampler_pairs[0].sampler_slot = 0; @@ -2779,6 +2970,11 @@ SOKOL_API_IMPL void simgui_setup(const simgui_desc_t* desc) { #elif defined(SOKOL_WGPU) shd_desc.vertex_func.source = (const char*)_simgui_vs_source_wgsl; shd_desc.fragment_func.source = (const char*)_simgui_fs_source_wgsl; + #elif defined(SOKOL_VULKAN) + shd_desc.vertex_func.bytecode = SG_RANGE(_simgui_vs_bytecode_spirv_vk); + shd_desc.vertex_func.entry = "main"; + shd_desc.fragment_func.bytecode = SG_RANGE(_simgui_fs_bytecode_spirv_vk); + shd_desc.fragment_func.entry = "main"; #else shd_desc.vertex_func.source = _simgui_vs_source_dummy; shd_desc.fragment_func.source = _simgui_fs_source_dummy; diff --git a/util/sokol_nuklear.h b/util/sokol_nuklear.h index 4a8143a3..f97cdd91 100644 --- a/util/sokol_nuklear.h +++ b/util/sokol_nuklear.h @@ -23,6 +23,7 @@ SOKOL_D3D11 SOKOL_METAL SOKOL_WGPU + SOKOL_VULKAN Optionally provide the following configuration defines before including the implementation: @@ -2194,6 +2195,190 @@ static const uint8_t _snk_fs_source_wgsl[630] = { 0x5f,0x6f,0x75,0x74,0x28,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x29, 0x3b,0x0a,0x7d,0x0a,0x0a,0x00, }; +#elif defined(SOKOL_VULKAN) +/* + #version 460 + + layout(set = 0, binding = 0, std140) uniform vs_params + { + vec2 disp_size; + } _22; + + layout(location = 0) in vec2 position; + layout(location = 0) out vec2 uv; + layout(location = 1) in vec2 texcoord0; + layout(location = 1) out vec4 color; + layout(location = 2) in vec4 color0; + + void main() + { + gl_Position = vec4(((position / _22.disp_size) - vec2(0.5)) * vec2(2.0, -2.0), 0.5, 1.0); + uv = texcoord0; + color = color0; + } + +*/ +static const uint8_t _snk_vs_bytecode_spirv_vk[1472] = { + 0x03,0x02,0x23,0x07,0x00,0x04,0x01,0x00,0x0b,0x00,0x08,0x00,0x30,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x11,0x00,0x02,0x00,0x01,0x00,0x00,0x00,0x0b,0x00,0x06,0x00, + 0x01,0x00,0x00,0x00,0x47,0x4c,0x53,0x4c,0x2e,0x73,0x74,0x64,0x2e,0x34,0x35,0x30, + 0x00,0x00,0x00,0x00,0x0e,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x0f,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x6d,0x61,0x69,0x6e, + 0x00,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x16,0x00,0x00,0x00, + 0x29,0x00,0x00,0x00,0x2a,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0x2e,0x00,0x00,0x00, + 0x03,0x00,0x03,0x00,0x02,0x00,0x00,0x00,0xcc,0x01,0x00,0x00,0x05,0x00,0x04,0x00, + 0x04,0x00,0x00,0x00,0x6d,0x61,0x69,0x6e,0x00,0x00,0x00,0x00,0x05,0x00,0x06,0x00, + 0x0b,0x00,0x00,0x00,0x67,0x6c,0x5f,0x50,0x65,0x72,0x56,0x65,0x72,0x74,0x65,0x78, + 0x00,0x00,0x00,0x00,0x06,0x00,0x06,0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0x06,0x00,0x07,0x00, + 0x0b,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x67,0x6c,0x5f,0x50,0x6f,0x69,0x6e,0x74, + 0x53,0x69,0x7a,0x65,0x00,0x00,0x00,0x00,0x06,0x00,0x07,0x00,0x0b,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x67,0x6c,0x5f,0x43,0x6c,0x69,0x70,0x44,0x69,0x73,0x74,0x61, + 0x6e,0x63,0x65,0x00,0x06,0x00,0x07,0x00,0x0b,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x67,0x6c,0x5f,0x43,0x75,0x6c,0x6c,0x44,0x69,0x73,0x74,0x61,0x6e,0x63,0x65,0x00, + 0x05,0x00,0x03,0x00,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x05,0x00, + 0x12,0x00,0x00,0x00,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0x00,0x00,0x00, + 0x05,0x00,0x05,0x00,0x14,0x00,0x00,0x00,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d, + 0x73,0x00,0x00,0x00,0x06,0x00,0x06,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x64,0x69,0x73,0x70,0x5f,0x73,0x69,0x7a,0x65,0x00,0x00,0x00,0x05,0x00,0x03,0x00, + 0x16,0x00,0x00,0x00,0x5f,0x32,0x32,0x00,0x05,0x00,0x03,0x00,0x29,0x00,0x00,0x00, + 0x75,0x76,0x00,0x00,0x05,0x00,0x05,0x00,0x2a,0x00,0x00,0x00,0x74,0x65,0x78,0x63, + 0x6f,0x6f,0x72,0x64,0x30,0x00,0x00,0x00,0x05,0x00,0x04,0x00,0x2c,0x00,0x00,0x00, + 0x63,0x6f,0x6c,0x6f,0x72,0x00,0x00,0x00,0x05,0x00,0x04,0x00,0x2e,0x00,0x00,0x00, + 0x63,0x6f,0x6c,0x6f,0x72,0x30,0x00,0x00,0x47,0x00,0x03,0x00,0x0b,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x48,0x00,0x05,0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x05,0x00,0x0b,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x48,0x00,0x05,0x00, + 0x0b,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x48,0x00,0x05,0x00,0x0b,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x0b,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x12,0x00,0x00,0x00,0x1e,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x47,0x00,0x03,0x00,0x14,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x48,0x00,0x05,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x23,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x16,0x00,0x00,0x00,0x21,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x16,0x00,0x00,0x00,0x22,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x29,0x00,0x00,0x00,0x1e,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x2a,0x00,0x00,0x00,0x1e,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x2c,0x00,0x00,0x00,0x1e,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x2e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x13,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x21,0x00,0x03,0x00, + 0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x16,0x00,0x03,0x00,0x06,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x17,0x00,0x04,0x00,0x07,0x00,0x00,0x00,0x06,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x15,0x00,0x04,0x00,0x08,0x00,0x00,0x00,0x20,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x2b,0x00,0x04,0x00,0x08,0x00,0x00,0x00,0x09,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x1c,0x00,0x04,0x00,0x0a,0x00,0x00,0x00,0x06,0x00,0x00,0x00, + 0x09,0x00,0x00,0x00,0x1e,0x00,0x06,0x00,0x0b,0x00,0x00,0x00,0x07,0x00,0x00,0x00, + 0x06,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x20,0x00,0x04,0x00, + 0x0c,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x3b,0x00,0x04,0x00, + 0x0c,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x15,0x00,0x04,0x00, + 0x0e,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x2b,0x00,0x04,0x00, + 0x0e,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x17,0x00,0x04,0x00, + 0x10,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x20,0x00,0x04,0x00, + 0x11,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x3b,0x00,0x04,0x00, + 0x11,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x1e,0x00,0x03,0x00, + 0x14,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x15,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x15,0x00,0x00,0x00, + 0x16,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x17,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x2b,0x00,0x04,0x00,0x06,0x00,0x00,0x00, + 0x1b,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x2c,0x00,0x05,0x00,0x10,0x00,0x00,0x00, + 0x1c,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x2b,0x00,0x04,0x00, + 0x06,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x2b,0x00,0x04,0x00, + 0x06,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x2c,0x00,0x05,0x00, + 0x10,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1f,0x00,0x00,0x00, + 0x2b,0x00,0x04,0x00,0x06,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x00,0x00,0x80,0x3f, + 0x20,0x00,0x04,0x00,0x26,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x07,0x00,0x00,0x00, + 0x20,0x00,0x04,0x00,0x28,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x10,0x00,0x00,0x00, + 0x3b,0x00,0x04,0x00,0x28,0x00,0x00,0x00,0x29,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x3b,0x00,0x04,0x00,0x11,0x00,0x00,0x00,0x2a,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x3b,0x00,0x04,0x00,0x26,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x20,0x00,0x04,0x00,0x2d,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x07,0x00,0x00,0x00, + 0x3b,0x00,0x04,0x00,0x2d,0x00,0x00,0x00,0x2e,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x36,0x00,0x05,0x00,0x02,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0xf8,0x00,0x02,0x00,0x05,0x00,0x00,0x00,0x3d,0x00,0x04,0x00, + 0x10,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x41,0x00,0x05,0x00, + 0x17,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x16,0x00,0x00,0x00,0x0f,0x00,0x00,0x00, + 0x3d,0x00,0x04,0x00,0x10,0x00,0x00,0x00,0x19,0x00,0x00,0x00,0x18,0x00,0x00,0x00, + 0x88,0x00,0x05,0x00,0x10,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0x13,0x00,0x00,0x00, + 0x19,0x00,0x00,0x00,0x83,0x00,0x05,0x00,0x10,0x00,0x00,0x00,0x1d,0x00,0x00,0x00, + 0x1a,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x85,0x00,0x05,0x00,0x10,0x00,0x00,0x00, + 0x21,0x00,0x00,0x00,0x1d,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x51,0x00,0x05,0x00, + 0x06,0x00,0x00,0x00,0x23,0x00,0x00,0x00,0x21,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x51,0x00,0x05,0x00,0x06,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x21,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x50,0x00,0x07,0x00,0x07,0x00,0x00,0x00,0x25,0x00,0x00,0x00, + 0x23,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x22,0x00,0x00,0x00, + 0x41,0x00,0x05,0x00,0x26,0x00,0x00,0x00,0x27,0x00,0x00,0x00,0x0d,0x00,0x00,0x00, + 0x0f,0x00,0x00,0x00,0x3e,0x00,0x03,0x00,0x27,0x00,0x00,0x00,0x25,0x00,0x00,0x00, + 0x3d,0x00,0x04,0x00,0x10,0x00,0x00,0x00,0x2b,0x00,0x00,0x00,0x2a,0x00,0x00,0x00, + 0x3e,0x00,0x03,0x00,0x29,0x00,0x00,0x00,0x2b,0x00,0x00,0x00,0x3d,0x00,0x04,0x00, + 0x07,0x00,0x00,0x00,0x2f,0x00,0x00,0x00,0x2e,0x00,0x00,0x00,0x3e,0x00,0x03,0x00, + 0x2c,0x00,0x00,0x00,0x2f,0x00,0x00,0x00,0xfd,0x00,0x01,0x00,0x38,0x00,0x01,0x00, +}; +/* + #version 460 + + layout(set = 1, binding = 0) uniform texture2D tex; + layout(set = 1, binding = 32) uniform sampler smp; + + layout(location = 0) out vec4 frag_color; + layout(location = 0) in vec2 uv; + layout(location = 1) in vec4 color; + + void main() + { + frag_color = texture(sampler2D(tex, smp), uv) * color; + } + +*/ +static const uint8_t _snk_fs_bytecode_spirv_vk[780] = { + 0x03,0x02,0x23,0x07,0x00,0x04,0x01,0x00,0x0b,0x00,0x08,0x00,0x1d,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x11,0x00,0x02,0x00,0x01,0x00,0x00,0x00,0x0b,0x00,0x06,0x00, + 0x01,0x00,0x00,0x00,0x47,0x4c,0x53,0x4c,0x2e,0x73,0x74,0x64,0x2e,0x34,0x35,0x30, + 0x00,0x00,0x00,0x00,0x0e,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x0f,0x00,0x0a,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x6d,0x61,0x69,0x6e, + 0x00,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x10,0x00,0x00,0x00, + 0x16,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0x10,0x00,0x03,0x00,0x04,0x00,0x00,0x00, + 0x07,0x00,0x00,0x00,0x03,0x00,0x03,0x00,0x02,0x00,0x00,0x00,0xcc,0x01,0x00,0x00, + 0x05,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x6d,0x61,0x69,0x6e,0x00,0x00,0x00,0x00, + 0x05,0x00,0x05,0x00,0x09,0x00,0x00,0x00,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c, + 0x6f,0x72,0x00,0x00,0x05,0x00,0x03,0x00,0x0c,0x00,0x00,0x00,0x74,0x65,0x78,0x00, + 0x05,0x00,0x03,0x00,0x10,0x00,0x00,0x00,0x73,0x6d,0x70,0x00,0x05,0x00,0x03,0x00, + 0x16,0x00,0x00,0x00,0x75,0x76,0x00,0x00,0x05,0x00,0x04,0x00,0x1a,0x00,0x00,0x00, + 0x63,0x6f,0x6c,0x6f,0x72,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x09,0x00,0x00,0x00, + 0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x0c,0x00,0x00,0x00, + 0x21,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x0c,0x00,0x00,0x00, + 0x22,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x10,0x00,0x00,0x00, + 0x21,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x10,0x00,0x00,0x00, + 0x22,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x16,0x00,0x00,0x00, + 0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x1a,0x00,0x00,0x00, + 0x1e,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x13,0x00,0x02,0x00,0x02,0x00,0x00,0x00, + 0x21,0x00,0x03,0x00,0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x16,0x00,0x03,0x00, + 0x06,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x17,0x00,0x04,0x00,0x07,0x00,0x00,0x00, + 0x06,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x08,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x08,0x00,0x00,0x00, + 0x09,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x19,0x00,0x09,0x00,0x0a,0x00,0x00,0x00, + 0x06,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x04,0x00, + 0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x3b,0x00,0x04,0x00, + 0x0b,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1a,0x00,0x02,0x00, + 0x0e,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x0e,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x0f,0x00,0x00,0x00,0x10,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x1b,0x00,0x03,0x00,0x12,0x00,0x00,0x00,0x0a,0x00,0x00,0x00, + 0x17,0x00,0x04,0x00,0x14,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x20,0x00,0x04,0x00,0x15,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x14,0x00,0x00,0x00, + 0x3b,0x00,0x04,0x00,0x15,0x00,0x00,0x00,0x16,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x20,0x00,0x04,0x00,0x19,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x07,0x00,0x00,0x00, + 0x3b,0x00,0x04,0x00,0x19,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x36,0x00,0x05,0x00,0x02,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0xf8,0x00,0x02,0x00,0x05,0x00,0x00,0x00,0x3d,0x00,0x04,0x00, + 0x0a,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x3d,0x00,0x04,0x00, + 0x0e,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x56,0x00,0x05,0x00, + 0x12,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x11,0x00,0x00,0x00, + 0x3d,0x00,0x04,0x00,0x14,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x16,0x00,0x00,0x00, + 0x57,0x00,0x05,0x00,0x07,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x13,0x00,0x00,0x00, + 0x17,0x00,0x00,0x00,0x3d,0x00,0x04,0x00,0x07,0x00,0x00,0x00,0x1b,0x00,0x00,0x00, + 0x1a,0x00,0x00,0x00,0x85,0x00,0x05,0x00,0x07,0x00,0x00,0x00,0x1c,0x00,0x00,0x00, + 0x18,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x3e,0x00,0x03,0x00,0x09,0x00,0x00,0x00, + 0x1c,0x00,0x00,0x00,0xfd,0x00,0x01,0x00,0x38,0x00,0x01,0x00, +}; #elif defined(SOKOL_DUMMY_BACKEND) static const char* _snk_vs_source_dummy = ""; static const char* _snk_fs_source_dummy = ""; @@ -2682,15 +2867,18 @@ SOKOL_API_IMPL void snk_setup(const snk_desc_t* desc) { #elif defined(SOKOL_WGPU) vs_source = (const char*)_snk_vs_source_wgsl; fs_source = (const char*)_snk_fs_source_wgsl; + #elif defined(SOKOL_VULKAN) + vs_bytecode = SG_RANGE(_snk_vs_bytecode_spirv_vk); + fs_bytecode = SG_RANGE(_snk_fs_bytecode_spirv_vk); #else vs_source = _snk_vs_source_dummy; fs_source = _snk_fs_source_dummy; #endif _snuklear.shd = sg_make_shader(&(sg_shader_desc){ .attrs = { - [0] = { .glsl_name = "position", .hlsl_sem_name = "TEXCOORD", .hlsl_sem_index = 0 }, - [1] = { .glsl_name = "texcoord0", .hlsl_sem_name = "TEXCOORD", .hlsl_sem_index = 1 }, - [2] = { .glsl_name = "color0", .hlsl_sem_name = "TEXCOORD", .hlsl_sem_index = 2 }, + [0] = { .glsl_name = "position", .hlsl_sem_name = "TEXCOORD", .hlsl_sem_index = 0, .base_type = SG_SHADERATTRBASETYPE_FLOAT }, + [1] = { .glsl_name = "texcoord0", .hlsl_sem_name = "TEXCOORD", .hlsl_sem_index = 1, .base_type = SG_SHADERATTRBASETYPE_FLOAT }, + [2] = { .glsl_name = "color0", .hlsl_sem_name = "TEXCOORD", .hlsl_sem_index = 2, .base_type = SG_SHADERATTRBASETYPE_FLOAT }, }, .vertex_func = { .source = vs_source, @@ -2710,6 +2898,7 @@ SOKOL_API_IMPL void snk_setup(const snk_desc_t* desc) { .hlsl_register_b_n = 0, .msl_buffer_n = 0, .wgsl_group0_binding_n = 0, + .spirv_set0_binding_n = 0, .glsl_uniforms[0] = { .glsl_name = "vs_params", .type = SG_UNIFORMTYPE_FLOAT4, @@ -2724,6 +2913,7 @@ SOKOL_API_IMPL void snk_setup(const snk_desc_t* desc) { .hlsl_register_t_n = 0, .msl_texture_n = 0, .wgsl_group1_binding_n = 64, + .spirv_set1_binding_n = 0, }, }, .samplers[0] = { @@ -2732,6 +2922,7 @@ SOKOL_API_IMPL void snk_setup(const snk_desc_t* desc) { .hlsl_register_s_n = 0, .msl_sampler_n = 0, .wgsl_group1_binding_n = 80, + .spirv_set1_binding_n = 32, }, .texture_sampler_pairs[0] = { .stage = SG_SHADERSTAGE_FRAGMENT, diff --git a/util/sokol_spine.h b/util/sokol_spine.h index 95afc349..ec142545 100644 --- a/util/sokol_spine.h +++ b/util/sokol_spine.h @@ -23,6 +23,8 @@ SOKOL_GLES3 SOKOL_D3D11 SOKOL_METAL + SOKOL_WGPU + SOKOL_VULKAN ...optionally provide the following macros to override defaults: @@ -1440,7 +1442,7 @@ SOKOL_SPINE_API_DECL void sspine_set_skin(sspine_instance instance, sspine_skin /* Embedded source compiled with: - sokol-shdc -i sspine.glsl -o sspine.h -l glsl410:glsl300es:hlsl4:metal_macos:metal_ios:metal_sim:wgsl -b + sokol-shdc -i sspine.glsl -o sspine.h -l glsl410:glsl300es:hlsl4:metal_macos:metal_ios:metal_sim:wgsl:spirv_vk -b @vs vs layout(binding=0) uniform vs_params { @@ -3221,6 +3223,238 @@ static const uint8_t _sspine_fs_source_wgsl[1125] = { 0x6f,0x75,0x74,0x28,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x29,0x3b, 0x0a,0x7d,0x0a,0x0a,0x00, }; +#elif defined(SOKOL_VULKAN) +/* + #version 460 + + layout(set = 0, binding = 0, std140) uniform vs_params + { + mat4 mvp; + } _19; + + layout(location = 0) in vec2 position; + layout(location = 0) out vec2 uv; + layout(location = 1) in vec2 texcoord0; + layout(location = 1) out vec4 color; + layout(location = 2) in vec4 color0; + + void main() + { + gl_Position = _19.mvp * vec4(position, 0.0, 1.0); + uv = texcoord0; + color = color0; + } + +*/ +static const uint8_t _sspine_vs_bytecode_spirv_vk[1404] = { + 0x03,0x02,0x23,0x07,0x00,0x04,0x01,0x00,0x0b,0x00,0x08,0x00,0x2b,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x11,0x00,0x02,0x00,0x01,0x00,0x00,0x00,0x0b,0x00,0x06,0x00, + 0x01,0x00,0x00,0x00,0x47,0x4c,0x53,0x4c,0x2e,0x73,0x74,0x64,0x2e,0x34,0x35,0x30, + 0x00,0x00,0x00,0x00,0x0e,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x0f,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x6d,0x61,0x69,0x6e, + 0x00,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x19,0x00,0x00,0x00, + 0x24,0x00,0x00,0x00,0x25,0x00,0x00,0x00,0x27,0x00,0x00,0x00,0x29,0x00,0x00,0x00, + 0x03,0x00,0x03,0x00,0x02,0x00,0x00,0x00,0xcc,0x01,0x00,0x00,0x05,0x00,0x04,0x00, + 0x04,0x00,0x00,0x00,0x6d,0x61,0x69,0x6e,0x00,0x00,0x00,0x00,0x05,0x00,0x06,0x00, + 0x0b,0x00,0x00,0x00,0x67,0x6c,0x5f,0x50,0x65,0x72,0x56,0x65,0x72,0x74,0x65,0x78, + 0x00,0x00,0x00,0x00,0x06,0x00,0x06,0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0x06,0x00,0x07,0x00, + 0x0b,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x67,0x6c,0x5f,0x50,0x6f,0x69,0x6e,0x74, + 0x53,0x69,0x7a,0x65,0x00,0x00,0x00,0x00,0x06,0x00,0x07,0x00,0x0b,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x67,0x6c,0x5f,0x43,0x6c,0x69,0x70,0x44,0x69,0x73,0x74,0x61, + 0x6e,0x63,0x65,0x00,0x06,0x00,0x07,0x00,0x0b,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x67,0x6c,0x5f,0x43,0x75,0x6c,0x6c,0x44,0x69,0x73,0x74,0x61,0x6e,0x63,0x65,0x00, + 0x05,0x00,0x03,0x00,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x05,0x00, + 0x11,0x00,0x00,0x00,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x00,0x00,0x00, + 0x06,0x00,0x04,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6d,0x76,0x70,0x00, + 0x05,0x00,0x03,0x00,0x13,0x00,0x00,0x00,0x5f,0x31,0x39,0x00,0x05,0x00,0x05,0x00, + 0x19,0x00,0x00,0x00,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0x00,0x00,0x00, + 0x05,0x00,0x03,0x00,0x24,0x00,0x00,0x00,0x75,0x76,0x00,0x00,0x05,0x00,0x05,0x00, + 0x25,0x00,0x00,0x00,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x00,0x00,0x00, + 0x05,0x00,0x04,0x00,0x27,0x00,0x00,0x00,0x63,0x6f,0x6c,0x6f,0x72,0x00,0x00,0x00, + 0x05,0x00,0x04,0x00,0x29,0x00,0x00,0x00,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x00,0x00, + 0x47,0x00,0x03,0x00,0x0b,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x48,0x00,0x05,0x00, + 0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x48,0x00,0x05,0x00,0x0b,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0b,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x48,0x00,0x05,0x00,0x0b,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x0b,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x48,0x00,0x05,0x00,0x0b,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x47,0x00,0x03,0x00, + 0x11,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x48,0x00,0x04,0x00,0x11,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x48,0x00,0x05,0x00,0x11,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x48,0x00,0x05,0x00, + 0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x47,0x00,0x04,0x00,0x13,0x00,0x00,0x00,0x21,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x47,0x00,0x04,0x00,0x13,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x47,0x00,0x04,0x00,0x19,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x47,0x00,0x04,0x00,0x24,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x47,0x00,0x04,0x00,0x25,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x47,0x00,0x04,0x00,0x27,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x47,0x00,0x04,0x00,0x29,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x13,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x21,0x00,0x03,0x00,0x03,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x16,0x00,0x03,0x00,0x06,0x00,0x00,0x00,0x20,0x00,0x00,0x00, + 0x17,0x00,0x04,0x00,0x07,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x04,0x00,0x00,0x00, + 0x15,0x00,0x04,0x00,0x08,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x2b,0x00,0x04,0x00,0x08,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x1c,0x00,0x04,0x00,0x0a,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x09,0x00,0x00,0x00, + 0x1e,0x00,0x06,0x00,0x0b,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x06,0x00,0x00,0x00, + 0x0a,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x0c,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x0c,0x00,0x00,0x00, + 0x0d,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x15,0x00,0x04,0x00,0x0e,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x2b,0x00,0x04,0x00,0x0e,0x00,0x00,0x00, + 0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x04,0x00,0x10,0x00,0x00,0x00, + 0x07,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x1e,0x00,0x03,0x00,0x11,0x00,0x00,0x00, + 0x10,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x12,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x11,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x12,0x00,0x00,0x00,0x13,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x14,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x10,0x00,0x00,0x00,0x17,0x00,0x04,0x00,0x17,0x00,0x00,0x00,0x06,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x18,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x17,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x18,0x00,0x00,0x00,0x19,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x2b,0x00,0x04,0x00,0x06,0x00,0x00,0x00,0x1b,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x2b,0x00,0x04,0x00,0x06,0x00,0x00,0x00,0x1c,0x00,0x00,0x00, + 0x00,0x00,0x80,0x3f,0x20,0x00,0x04,0x00,0x21,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x07,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x23,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x17,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x23,0x00,0x00,0x00,0x24,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x18,0x00,0x00,0x00,0x25,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x21,0x00,0x00,0x00,0x27,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x28,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x07,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x28,0x00,0x00,0x00,0x29,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x36,0x00,0x05,0x00,0x02,0x00,0x00,0x00,0x04,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0xf8,0x00,0x02,0x00,0x05,0x00,0x00,0x00, + 0x41,0x00,0x05,0x00,0x14,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x13,0x00,0x00,0x00, + 0x0f,0x00,0x00,0x00,0x3d,0x00,0x04,0x00,0x10,0x00,0x00,0x00,0x16,0x00,0x00,0x00, + 0x15,0x00,0x00,0x00,0x3d,0x00,0x04,0x00,0x17,0x00,0x00,0x00,0x1a,0x00,0x00,0x00, + 0x19,0x00,0x00,0x00,0x51,0x00,0x05,0x00,0x06,0x00,0x00,0x00,0x1d,0x00,0x00,0x00, + 0x1a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x51,0x00,0x05,0x00,0x06,0x00,0x00,0x00, + 0x1e,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x50,0x00,0x07,0x00, + 0x07,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x1d,0x00,0x00,0x00,0x1e,0x00,0x00,0x00, + 0x1b,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x91,0x00,0x05,0x00,0x07,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x16,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x41,0x00,0x05,0x00, + 0x21,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x0f,0x00,0x00,0x00, + 0x3e,0x00,0x03,0x00,0x22,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x3d,0x00,0x04,0x00, + 0x17,0x00,0x00,0x00,0x26,0x00,0x00,0x00,0x25,0x00,0x00,0x00,0x3e,0x00,0x03,0x00, + 0x24,0x00,0x00,0x00,0x26,0x00,0x00,0x00,0x3d,0x00,0x04,0x00,0x07,0x00,0x00,0x00, + 0x2a,0x00,0x00,0x00,0x29,0x00,0x00,0x00,0x3e,0x00,0x03,0x00,0x27,0x00,0x00,0x00, + 0x2a,0x00,0x00,0x00,0xfd,0x00,0x01,0x00,0x38,0x00,0x01,0x00, +}; +/* + #version 460 + + layout(set = 0, binding = 1, std140) uniform fs_params + { + float pma; + } _53; + + layout(set = 1, binding = 0) uniform texture2D tex; + layout(set = 1, binding = 32) uniform sampler smp; + + layout(location = 0) in vec2 uv; + layout(location = 1) in vec4 color; + layout(location = 0) out vec4 frag_color; + + void main() + { + vec4 _28 = texture(sampler2D(tex, smp), uv) * color; + float _37 = _28.w; + frag_color = mix(_28, vec4(_28.xyz * _37, _37) * color, vec4(_53.pma)); + } +*/ +static const uint8_t _sspine_fs_bytecode_spirv_vk[1520] = { + 0x03,0x02,0x23,0x07,0x00,0x04,0x01,0x00,0x0b,0x00,0x08,0x00,0x3c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x11,0x00,0x02,0x00,0x01,0x00,0x00,0x00,0x0b,0x00,0x06,0x00, + 0x01,0x00,0x00,0x00,0x47,0x4c,0x53,0x4c,0x2e,0x73,0x74,0x64,0x2e,0x34,0x35,0x30, + 0x00,0x00,0x00,0x00,0x0e,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x0f,0x00,0x0b,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x6d,0x61,0x69,0x6e, + 0x00,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x16,0x00,0x00,0x00, + 0x1a,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x34,0x00,0x00,0x00,0x10,0x00,0x03,0x00, + 0x04,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x03,0x00,0x03,0x00,0x02,0x00,0x00,0x00, + 0xcc,0x01,0x00,0x00,0x05,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x6d,0x61,0x69,0x6e, + 0x00,0x00,0x00,0x00,0x05,0x00,0x03,0x00,0x09,0x00,0x00,0x00,0x5f,0x32,0x38,0x00, + 0x05,0x00,0x03,0x00,0x0c,0x00,0x00,0x00,0x74,0x65,0x78,0x00,0x05,0x00,0x03,0x00, + 0x10,0x00,0x00,0x00,0x73,0x6d,0x70,0x00,0x05,0x00,0x03,0x00,0x16,0x00,0x00,0x00, + 0x75,0x76,0x00,0x00,0x05,0x00,0x04,0x00,0x1a,0x00,0x00,0x00,0x63,0x6f,0x6c,0x6f, + 0x72,0x00,0x00,0x00,0x05,0x00,0x03,0x00,0x1e,0x00,0x00,0x00,0x5f,0x33,0x37,0x00, + 0x05,0x00,0x05,0x00,0x24,0x00,0x00,0x00,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c, + 0x6f,0x72,0x00,0x00,0x05,0x00,0x05,0x00,0x32,0x00,0x00,0x00,0x66,0x73,0x5f,0x70, + 0x61,0x72,0x61,0x6d,0x73,0x00,0x00,0x00,0x06,0x00,0x04,0x00,0x32,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x70,0x6d,0x61,0x00,0x05,0x00,0x03,0x00,0x34,0x00,0x00,0x00, + 0x5f,0x35,0x33,0x00,0x47,0x00,0x04,0x00,0x0c,0x00,0x00,0x00,0x21,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x0c,0x00,0x00,0x00,0x22,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x10,0x00,0x00,0x00,0x21,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x10,0x00,0x00,0x00,0x22,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x16,0x00,0x00,0x00,0x1e,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x1a,0x00,0x00,0x00,0x1e,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x24,0x00,0x00,0x00,0x1e,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x47,0x00,0x03,0x00,0x32,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x48,0x00,0x05,0x00,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x23,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x34,0x00,0x00,0x00,0x21,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x34,0x00,0x00,0x00,0x22,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x13,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x21,0x00,0x03,0x00, + 0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x16,0x00,0x03,0x00,0x06,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x17,0x00,0x04,0x00,0x07,0x00,0x00,0x00,0x06,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x08,0x00,0x00,0x00,0x07,0x00,0x00,0x00, + 0x07,0x00,0x00,0x00,0x19,0x00,0x09,0x00,0x0a,0x00,0x00,0x00,0x06,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x0b,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x0b,0x00,0x00,0x00, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1a,0x00,0x02,0x00,0x0e,0x00,0x00,0x00, + 0x20,0x00,0x04,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x00,0x00,0x00, + 0x3b,0x00,0x04,0x00,0x0f,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x1b,0x00,0x03,0x00,0x12,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x17,0x00,0x04,0x00, + 0x14,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x20,0x00,0x04,0x00, + 0x15,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x3b,0x00,0x04,0x00, + 0x15,0x00,0x00,0x00,0x16,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x20,0x00,0x04,0x00, + 0x19,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x3b,0x00,0x04,0x00, + 0x19,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x20,0x00,0x04,0x00, + 0x1d,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x15,0x00,0x04,0x00, + 0x1f,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2b,0x00,0x04,0x00, + 0x1f,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x20,0x00,0x04,0x00, + 0x23,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x3b,0x00,0x04,0x00, + 0x23,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x17,0x00,0x04,0x00, + 0x26,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x1e,0x00,0x03,0x00, + 0x32,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x33,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x32,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x33,0x00,0x00,0x00, + 0x34,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x15,0x00,0x04,0x00,0x35,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x2b,0x00,0x04,0x00,0x35,0x00,0x00,0x00, + 0x36,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x37,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x36,0x00,0x05,0x00,0x02,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0xf8,0x00,0x02,0x00, + 0x05,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x08,0x00,0x00,0x00,0x09,0x00,0x00,0x00, + 0x07,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x1d,0x00,0x00,0x00,0x1e,0x00,0x00,0x00, + 0x07,0x00,0x00,0x00,0x3d,0x00,0x04,0x00,0x0a,0x00,0x00,0x00,0x0d,0x00,0x00,0x00, + 0x0c,0x00,0x00,0x00,0x3d,0x00,0x04,0x00,0x0e,0x00,0x00,0x00,0x11,0x00,0x00,0x00, + 0x10,0x00,0x00,0x00,0x56,0x00,0x05,0x00,0x12,0x00,0x00,0x00,0x13,0x00,0x00,0x00, + 0x0d,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x3d,0x00,0x04,0x00,0x14,0x00,0x00,0x00, + 0x17,0x00,0x00,0x00,0x16,0x00,0x00,0x00,0x57,0x00,0x05,0x00,0x07,0x00,0x00,0x00, + 0x18,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x3d,0x00,0x04,0x00, + 0x07,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0x85,0x00,0x05,0x00, + 0x07,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x1b,0x00,0x00,0x00, + 0x3e,0x00,0x03,0x00,0x09,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x41,0x00,0x05,0x00, + 0x1d,0x00,0x00,0x00,0x21,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x20,0x00,0x00,0x00, + 0x3d,0x00,0x04,0x00,0x06,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x21,0x00,0x00,0x00, + 0x3e,0x00,0x03,0x00,0x1e,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x3d,0x00,0x04,0x00, + 0x07,0x00,0x00,0x00,0x25,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x3d,0x00,0x04,0x00, + 0x07,0x00,0x00,0x00,0x27,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x4f,0x00,0x08,0x00, + 0x26,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x27,0x00,0x00,0x00,0x27,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x3d,0x00,0x04,0x00, + 0x06,0x00,0x00,0x00,0x29,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x8e,0x00,0x05,0x00, + 0x26,0x00,0x00,0x00,0x2a,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x29,0x00,0x00,0x00, + 0x3d,0x00,0x04,0x00,0x06,0x00,0x00,0x00,0x2b,0x00,0x00,0x00,0x1e,0x00,0x00,0x00, + 0x51,0x00,0x05,0x00,0x06,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0x2a,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x51,0x00,0x05,0x00,0x06,0x00,0x00,0x00,0x2d,0x00,0x00,0x00, + 0x2a,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x51,0x00,0x05,0x00,0x06,0x00,0x00,0x00, + 0x2e,0x00,0x00,0x00,0x2a,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x50,0x00,0x07,0x00, + 0x07,0x00,0x00,0x00,0x2f,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0x2d,0x00,0x00,0x00, + 0x2e,0x00,0x00,0x00,0x2b,0x00,0x00,0x00,0x3d,0x00,0x04,0x00,0x07,0x00,0x00,0x00, + 0x30,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0x85,0x00,0x05,0x00,0x07,0x00,0x00,0x00, + 0x31,0x00,0x00,0x00,0x2f,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x41,0x00,0x05,0x00, + 0x37,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x34,0x00,0x00,0x00,0x36,0x00,0x00,0x00, + 0x3d,0x00,0x04,0x00,0x06,0x00,0x00,0x00,0x39,0x00,0x00,0x00,0x38,0x00,0x00,0x00, + 0x50,0x00,0x07,0x00,0x07,0x00,0x00,0x00,0x3a,0x00,0x00,0x00,0x39,0x00,0x00,0x00, + 0x39,0x00,0x00,0x00,0x39,0x00,0x00,0x00,0x39,0x00,0x00,0x00,0x0c,0x00,0x08,0x00, + 0x07,0x00,0x00,0x00,0x3b,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x2e,0x00,0x00,0x00, + 0x25,0x00,0x00,0x00,0x31,0x00,0x00,0x00,0x3a,0x00,0x00,0x00,0x3e,0x00,0x03,0x00, + 0x24,0x00,0x00,0x00,0x3b,0x00,0x00,0x00,0xfd,0x00,0x01,0x00,0x38,0x00,0x01,0x00, +}; #elif defined(SOKOL_DUMMY_BACKEND) static const char* _sspine_vs_source_dummy = ""; static const char* _sspine_fs_source_dummy = ""; @@ -5178,12 +5412,16 @@ static void _sspine_init_shared(void) { shd_desc.attrs[1].hlsl_sem_index = 1; shd_desc.attrs[2].hlsl_sem_name = "TEXCOORD"; shd_desc.attrs[2].hlsl_sem_index = 2; + shd_desc.attrs[0].base_type = SG_SHADERATTRBASETYPE_FLOAT; + shd_desc.attrs[1].base_type = SG_SHADERATTRBASETYPE_FLOAT; + shd_desc.attrs[2].base_type = SG_SHADERATTRBASETYPE_FLOAT; shd_desc.uniform_blocks[0].stage = SG_SHADERSTAGE_VERTEX; shd_desc.uniform_blocks[0].size = sizeof(_sspine_vsparams_t); shd_desc.uniform_blocks[0].layout = SG_UNIFORMLAYOUT_STD140; shd_desc.uniform_blocks[0].hlsl_register_b_n = 0; shd_desc.uniform_blocks[0].msl_buffer_n = 0; shd_desc.uniform_blocks[0].wgsl_group0_binding_n = 0; + shd_desc.uniform_blocks[0].spirv_set0_binding_n = 0; shd_desc.uniform_blocks[0].glsl_uniforms[0].glsl_name = "vs_params"; shd_desc.uniform_blocks[0].glsl_uniforms[0].type = SG_UNIFORMTYPE_FLOAT4; shd_desc.uniform_blocks[0].glsl_uniforms[0].array_count = 4; @@ -5193,6 +5431,7 @@ static void _sspine_init_shared(void) { shd_desc.uniform_blocks[1].hlsl_register_b_n = 0; shd_desc.uniform_blocks[1].msl_buffer_n = 0; shd_desc.uniform_blocks[1].wgsl_group0_binding_n = 8; + shd_desc.uniform_blocks[1].spirv_set0_binding_n = 1; shd_desc.uniform_blocks[1].glsl_uniforms[0].glsl_name = "fs_params"; shd_desc.uniform_blocks[1].glsl_uniforms[0].type = SG_UNIFORMTYPE_FLOAT4; shd_desc.uniform_blocks[1].glsl_uniforms[0].array_count = 1; @@ -5202,11 +5441,13 @@ static void _sspine_init_shared(void) { shd_desc.views[0].texture.hlsl_register_t_n = 0; shd_desc.views[0].texture.msl_texture_n = 0; shd_desc.views[0].texture.wgsl_group1_binding_n = 64; + shd_desc.views[0].texture.spirv_set1_binding_n = 0; shd_desc.samplers[0].stage = SG_SHADERSTAGE_FRAGMENT; shd_desc.samplers[0].sampler_type = SG_SAMPLERTYPE_FILTERING; shd_desc.samplers[0].hlsl_register_s_n = 0; shd_desc.samplers[0].msl_sampler_n = 0; shd_desc.samplers[0].wgsl_group1_binding_n = 80; + shd_desc.samplers[0].spirv_set1_binding_n = 32; shd_desc.texture_sampler_pairs[0].stage = SG_SHADERSTAGE_FRAGMENT; shd_desc.texture_sampler_pairs[0].view_slot = 0; shd_desc.texture_sampler_pairs[0].sampler_slot = 0; @@ -5241,6 +5482,11 @@ static void _sspine_init_shared(void) { #elif defined(SOKOL_WGPU) shd_desc.vertex_func.source = (const char*)_sspine_vs_source_wgsl; shd_desc.fragment_func.source = (const char*)_sspine_fs_source_wgsl; + #elif defined(SOKOL_VULKAN) + shd_desc.vertex_func.bytecode = SG_RANGE(_sspine_vs_bytecode_spirv_vk); + shd_desc.vertex_func.entry = "main"; + shd_desc.fragment_func.bytecode = SG_RANGE(_sspine_fs_bytecode_spirv_vk); + shd_desc.fragment_func.entry = "main"; #else shd_desc.vertex_func.source = _sspine_vs_source_dummy; shd_desc.fragment_func.source = _sspine_fs_source_dummy; |