diff --git a/.gitignore b/.gitignore index 9e85bf4..00dc692 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ build compile_commands.json .vscode *.dSYM +vendor/ scratchpad/** !scratchpad/**/ !scratchpad/**/*.h diff --git a/justfile b/justfile index bea3caf..7f9a811 100644 --- a/justfile +++ b/justfile @@ -9,13 +9,29 @@ BUILDDIR := "build" # Resolve VULKAN_SDK once via backtick VK_SDK := `echo $VULKAN_SDK` -VENDOR_LIB := "/home/abdelrahman/Sources/programming/how-to-vulkan/vendor/lib" +VENDOR_INC := "vendor/include" +VENDOR_LIB := "vendor/lib" -VK_FLAGS := "-DVK_NO_PROTOTYPES -I" + VK_SDK + "/include -I" + VK_SDK + "/include/vma" -APP_INC := "-I" + VK_SDK + "/include -I" + VK_SDK + "/include/vma -I" + VK_SDK + "/include/slang -I/home/abdelrahman/Sources/programming/how-to-vulkan/vendor/include -Isrc" +VK_FLAGS := "-DVK_NO_PROTOTYPES -I" + VK_SDK + "/include -I" + VK_SDK + "/include/vma -I" + VENDOR_INC +APP_INC := "-I" + VK_SDK + "/include -I" + VK_SDK + "/include/vma -I" + VK_SDK + "/include/slang -I" + VENDOR_INC + " -Isrc" + +# Build KTX from source +vendor: + mkdir -p vendor/ktx/build + cmake vendor/ktx -B vendor/ktx/build \ + -D KTX_FEATURE_LOADTEST_APPS=OFF \ + -D KTX_FEATURE_DOC=OFF \ + -D CMAKE_EXPORT_COMPILE_COMMANDS=1 \ + -D CMAKE_BUILD_TYPE=Release \ + -D CMAKE_INSTALL_PREFIX=$(pwd)/vendor \ + -D CMAKE_CXX_STANDARD=17 \ + -D CMAKE_CXX_FLAGS="-msse4.1" \ + -G Ninja + cmake --build vendor/ktx/build --config Release + cmake --install vendor/ktx/build # Build all objects, then link -build: +build: vendor mkdir -p {{BUILDDIR}} bear -- {{CXX}} -g -c -Wno-nullability-completeness {{VK_FLAGS}} \ src/prism/rhi/vulkan/profiles/vulkan_profiles.cpp \ diff --git a/src/main.cpp b/src/main.cpp index 68b69b0..47d92cb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,9 +6,6 @@ #define PR_RHI_VULKAN #include "prism/rhi/pr_rhi.h" -#include -#include -#include #include #include #include @@ -19,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -27,26 +23,6 @@ #include #include -// ============================================================================ -// Helpers -// ============================================================================ - -static PrRhiFormat _fromVkFormat(VkFormat fmt) { - switch (fmt) { - case VK_FORMAT_R8G8B8A8_SRGB: return PR_RHI_FORMAT_R8G8B8A8_SRGB; - case VK_FORMAT_R8G8B8A8_UNORM: return PR_RHI_FORMAT_R8G8B8A8_UNORM; - case VK_FORMAT_R16G16B16A16_SFLOAT: return PR_RHI_FORMAT_R16G16B16A16_SFLOAT; - case VK_FORMAT_R32G32B32A32_SFLOAT: return PR_RHI_FORMAT_R32G32B32A32_SFLOAT; - case VK_FORMAT_R32G32B32_SFLOAT: return PR_RHI_FORMAT_R32G32B32_SFLOAT; - case VK_FORMAT_R32G32_SFLOAT: return PR_RHI_FORMAT_R32G32_SFLOAT; - case VK_FORMAT_R32_SFLOAT: return PR_RHI_FORMAT_R32_SFLOAT; - case VK_FORMAT_D24_UNORM_S8_UINT: return PR_RHI_FORMAT_D24_UNORM_S8_UINT; - case VK_FORMAT_D32_SFLOAT_S8_UINT: return PR_RHI_FORMAT_D32_SFLOAT_S8_UINT; - case VK_FORMAT_B8G8R8A8_SRGB: return PR_RHI_FORMAT_B8G8R8A8_SRGB; - default: return PR_RHI_FORMAT_UNDEFINED; - } -} - // ============================================================================ // Exit codes // ============================================================================ @@ -153,88 +129,6 @@ struct AppState { Slang::ComPtr slang_session; }; -// ============================================================================ -// Helpers -// ============================================================================ - -static void _uploadTexture(AppState *app, PrRhiTexture *tex, - ktxTexture *ktx_tex, WpAllocator *scratch) { - // Create staging buffer - PrRhiBufferDesc staging_desc = {}; - staging_desc.size = (u32)ktx_tex->dataSize; - staging_desc.usage = PR_RHI_BUFFER_USAGE_TRANSFER_SRC; - staging_desc.memory = PR_RHI_MEMORY_CPU_TO_GPU; - - PrRhiBuffer *staging = prRhiCreateBuffer(app->device, staging_desc, scratch); - void *data = prRhiBufferMap(app->device, staging); - memcpy(data, ktx_tex->pData, ktx_tex->dataSize); - prRhiBufferUnmap(app->device, staging); - - // Create fence - PrRhiFenceDesc fence_desc = {}; - fence_desc.signaled = false; - PrRhiFence *fence = prRhiCreateFence(app->device, fence_desc, scratch); - - // Allocate temporary command buffer - PrRhiCommandBufferArray tmp_cbs = prRhiAllocateCommandBuffers(app->device, - app->cmd_pool, 1, scratch); - PrRhiCommandBuffer *cb = tmp_cbs[0]; - - prRhiBeginCommandBuffer(cb); - - // Transition UNDEFINED → TRANSFER_DST - PrRhiImageMemoryBarrier barrier_to_transfer = {}; - barrier_to_transfer.texture = tex; - barrier_to_transfer.old_layout = PR_RHI_LAYOUT_UNDEFINED; - barrier_to_transfer.new_layout = PR_RHI_LAYOUT_TRANSFER_DST_OPTIMAL; - barrier_to_transfer.src_stage_mask = (u64)VK_PIPELINE_STAGE_2_NONE; - barrier_to_transfer.src_access_mask = 0; - barrier_to_transfer.dst_stage_mask = (u64)VK_PIPELINE_STAGE_2_TRANSFER_BIT; - barrier_to_transfer.dst_access_mask = (u64)VK_ACCESS_2_TRANSFER_WRITE_BIT; - prRhiCmdPipelineBarrier(cb, wpArray(PrRhiImageMemoryBarrier, barrier_to_transfer), NULL); - - // Copy all mip levels - PrRhiBufferImageCopyArray copies = wpArrayAllocCapacity(PrRhiBufferImageCopy, scratch, - ktx_tex->numLevels, WP_ARRAY_INIT_NONE); - for (u32 j = 0; j < ktx_tex->numLevels; ++j) { - ktx_size_t mip_offset = 0; - ktxTexture_GetImageOffset(ktx_tex, j, 0, 0, &mip_offset); - - PrRhiBufferImageCopy copy = {}; - copy.buffer_offset = mip_offset; - copy.mip_level = j; - copy.width = ktx_tex->baseWidth >> j; - copy.height = ktx_tex->baseHeight >> j; - wpArrayAppendCapped(PrRhiBufferImageCopy, copies, ©); - } - - prRhiCmdCopyBufferToImage(cb, staging, tex, copies); - wpArrayDealloc(PrRhiBufferImageCopy, scratch, &copies); - - // Transition TRANSFER_DST → READ_ONLY - PrRhiImageMemoryBarrier barrier_to_read = {}; - barrier_to_read.texture = tex; - barrier_to_read.old_layout = PR_RHI_LAYOUT_TRANSFER_DST_OPTIMAL; - barrier_to_read.new_layout = PR_RHI_LAYOUT_READ_ONLY_OPTIMAL; - barrier_to_read.src_stage_mask = (u64)VK_PIPELINE_STAGE_2_TRANSFER_BIT; - barrier_to_read.src_access_mask = (u64)VK_ACCESS_2_TRANSFER_WRITE_BIT; - barrier_to_read.dst_stage_mask = (u64)VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - barrier_to_read.dst_access_mask = (u64)VK_ACCESS_2_SHADER_READ_BIT; - prRhiCmdPipelineBarrier(cb, wpArray(PrRhiImageMemoryBarrier, barrier_to_read), NULL); - - prRhiEndCommandBuffer(cb); - - // Submit and wait - prRhiQueueSubmit(app->device, cb, NULL, NULL, fence); - prRhiWaitForFences(app->device, wpArray(PrRhiFence *, fence), 1, true, UINT64_MAX); - - // Cleanup - prRhiDestroyFence(app->device, fence, scratch); - prRhiFreeCommandBuffers(app->device, app->cmd_pool, 1, tmp_cbs); - wpArrayDealloc(PrRhiCommandBuffer *, scratch, &tmp_cbs); - prRhiDestroyBuffer(app->device, staging, scratch); -} - // ============================================================================ // Main // ============================================================================ @@ -245,7 +139,6 @@ int main() { // {{{ Initialisation check(SDL_Init(SDL_INIT_VIDEO), EXIT_CODE_SDL_INIT_FAILED); - check(SDL_Vulkan_LoadLibrary(nullptr), EXIT_CODE_VULKAN_LIB_LOAD_FAILED); f32 display_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay()); app.window = SDL_CreateWindow("How To Vulkan (Prism)", (i32)(display_scale * 1920), @@ -255,18 +148,9 @@ int main() { // }}} // {{{ Instance creation - u32 ext_count = 0; - const char *const *exts = SDL_Vulkan_GetInstanceExtensions(&ext_count); - WpAllocator scratch = wpMemArenaAllocatorInitZero(MiB(64)); - PrRhiExtensionArray extensions = wpArrayAllocCapacity(const char *, &scratch, ext_count, WP_ARRAY_INIT_NONE); - for (u32 i = 0; i < ext_count; ++i) { - wpArrayAppendCapped(const char *, extensions, &exts[i]); - } - PrRhiInstanceDesc inst_desc = {}; - inst_desc.extra_extensions = extensions; app.inst = prRhiCreateInstance(inst_desc, &arena); // }}} @@ -279,11 +163,12 @@ int main() { PrRhiPhysicalDeviceProperties props; prRhiGetPhysicalDeviceProperties(pdevs[i], &props); switch (props.device_type) { - case 1: // VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU - case 2: // VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU - if (props.api_version >= VK_API_VERSION_1_3) { + case PR_RHI_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: + selected = (i32)i; + break; + case PR_RHI_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: + if (selected == -1) selected = (i32)i; - } break; default: continue; } @@ -300,13 +185,9 @@ int main() { // }}} // {{{ Surface creation - VkSurfaceKHR vk_surface = VK_NULL_HANDLE; - VkInstance vk_inst = (VkInstance)prRhiGetNativeInstanceHandle(app.inst); - check(SDL_Vulkan_CreateSurface(app.window, vk_inst, nullptr, &vk_surface), - EXIT_CODE_SURFACE_CREATION_FAILED); check(SDL_GetWindowSize(app.window, &app.window_size.x, &app.window_size.y), EXIT_CODE_GET_WINDOW_SIZE_FAILED); - app.surface = prRhiCreateSurface(app.inst, (void *)vk_surface, &arena); + app.surface = prRhiCreateSurfaceFromWindow(app.inst, (void *)app.window, &arena); // }}} // {{{ Device creation @@ -441,28 +322,13 @@ int main() { app.textures = wpArrayAllocCapacity(TextureResources, &arena, AppState::texture_count, WP_ARRAY_INIT_FILLED); + PrRhiCommandBufferArray upload_cbs = prRhiAllocateCommandBuffers(app.device, app.cmd_pool, 1, &scratch); + PrRhiCommandBuffer *upload_cb = upload_cbs[0]; + for (u32 i = 0; i < AppState::texture_count; ++i) { - // Load KTX - ktxTexture *ktx_tex = nullptr; char buf[2048] = {}; snprintf(buf, sizeof(buf), "assets/suzanne%u.ktx", i); - ktxTexture_CreateFromNamedFile(buf, KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT, &ktx_tex); - - VkFormat vk_fmt = ktxTexture_GetVkFormat(ktx_tex); - - // Create texture - PrRhiTextureDesc tex_desc = {}; - tex_desc.format = _fromVkFormat(vk_fmt); - tex_desc.width = (u32)ktx_tex->baseWidth; - tex_desc.height = (u32)ktx_tex->baseHeight; - tex_desc.mip_levels = (u32)ktx_tex->numLevels; - tex_desc.usage = (PrRhiTextureUsage)(PR_RHI_TEXTURE_USAGE_TRANSFER_DST | - PR_RHI_TEXTURE_USAGE_SAMPLED); - - PrRhiTexture *tex = prRhiCreateTexture(app.device, tex_desc, &arena); - - // Upload texture data - _uploadTexture(&app, tex, ktx_tex, &scratch); + PrRhiTexture *tex = prRhiCreateTextureFromKtx(app.device, buf, app.cmd_pool, upload_cb, &arena); // Create sampler PrRhiSamplerDesc samp_desc = {}; @@ -470,14 +336,15 @@ int main() { samp_desc.min_filter = PR_RHI_FILTER_LINEAR; samp_desc.mipmap_mode = PR_RHI_MIPMAP_MODE_LINEAR; samp_desc.max_anisotropy = 8.0f; - samp_desc.max_lod = VK_LOD_CLAMP_NONE; + samp_desc.max_lod = PR_RHI_LOD_CLAMP_NONE; PrRhiSampler *sampler = prRhiCreateSampler(app.device, samp_desc, &arena); app.textures[i].texture = tex; app.textures[i].sampler = sampler; - - ktxTexture_Destroy(ktx_tex); } + + prRhiFreeCommandBuffers(app.device, app.cmd_pool, 1, upload_cbs); + wpArrayDealloc(PrRhiCommandBuffer *, &scratch, &upload_cbs); // }}} // {{{ Descriptor set layout, pool, set @@ -564,7 +431,7 @@ int main() { // {{{ Pipeline layout PrRhiPushConstantRange pc_range = {}; pc_range.stage_flags = PR_RHI_SHADER_STAGE_VERTEX; - pc_range.size = sizeof(u64); // VkDeviceAddress + pc_range.size = sizeof(u64); PrRhiDescriptorSetLayout *set_layouts_pl[] = { app.desc_set_layout }; PrRhiDescriptorSetLayoutArray pl_layouts = wpArray(PrRhiDescriptorSetLayout *, set_layouts_pl[0]); @@ -677,20 +544,20 @@ int main() { img_barriers[0].texture = color_tex; img_barriers[0].old_layout = PR_RHI_LAYOUT_UNDEFINED; img_barriers[0].new_layout = PR_RHI_LAYOUT_ATTACHMENT_OPTIMAL; - img_barriers[0].src_stage_mask = (u64)VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT; - img_barriers[0].src_access_mask = 0; - img_barriers[0].dst_stage_mask = (u64)VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT; - img_barriers[0].dst_access_mask = (u64)(VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT); + img_barriers[0].src_stage_mask = PR_RHI_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT; + img_barriers[0].src_access_mask = PR_RHI_ACCESS_NONE; + img_barriers[0].dst_stage_mask = PR_RHI_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT; + img_barriers[0].dst_access_mask = (PrRhiAccess)(PR_RHI_ACCESS_COLOR_ATTACHMENT_READ | PR_RHI_ACCESS_COLOR_ATTACHMENT_WRITE); // Depth attachment PrRhiTexture *depth_tex = prRhiGetSwapchainDepthTexture(app.swapchain); img_barriers[1].texture = depth_tex; img_barriers[1].old_layout = PR_RHI_LAYOUT_UNDEFINED; img_barriers[1].new_layout = PR_RHI_LAYOUT_ATTACHMENT_OPTIMAL; - img_barriers[1].src_stage_mask = (u64)VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT; - img_barriers[1].src_access_mask = (u64)VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - img_barriers[1].dst_stage_mask = (u64)VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT; - img_barriers[1].dst_access_mask = (u64)VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + img_barriers[1].src_stage_mask = PR_RHI_PIPELINE_STAGE_LATE_FRAGMENT_TESTS; + img_barriers[1].src_access_mask = PR_RHI_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE; + img_barriers[1].dst_stage_mask = PR_RHI_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS; + img_barriers[1].dst_access_mask = PR_RHI_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE; PrRhiImageMemoryBarrierArray barriers_arr = wpArray(PrRhiImageMemoryBarrier, img_barriers[0], img_barriers[1]); @@ -749,10 +616,10 @@ int main() { present_barrier.texture = prRhiGetSwapchainTexture(app.swapchain, image_index); present_barrier.old_layout = PR_RHI_LAYOUT_ATTACHMENT_OPTIMAL; present_barrier.new_layout = PR_RHI_LAYOUT_PRESENT_SRC; - present_barrier.src_stage_mask = (u64)VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT; - present_barrier.src_access_mask = (u64)VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT; - present_barrier.dst_stage_mask = (u64)VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT; - present_barrier.dst_access_mask = 0; + present_barrier.src_stage_mask = PR_RHI_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT; + present_barrier.src_access_mask = PR_RHI_ACCESS_COLOR_ATTACHMENT_WRITE; + present_barrier.dst_stage_mask = PR_RHI_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT; + present_barrier.dst_access_mask = PR_RHI_ACCESS_NONE; prRhiCmdPipelineBarrier(cb, wpArray(PrRhiImageMemoryBarrier, present_barrier), NULL); } @@ -870,7 +737,6 @@ int main() { prRhiDestroyInstance(app.inst, &arena); SDL_DestroyWindow(app.window); - SDL_Vulkan_UnloadLibrary(); SDL_Quit(); wpMemArenaAllocatorDestroy(&arena); diff --git a/src/prism/rhi/pr_rhi.h b/src/prism/rhi/pr_rhi.h index 801becd..678e65f 100644 --- a/src/prism/rhi/pr_rhi.h +++ b/src/prism/rhi/pr_rhi.h @@ -33,15 +33,14 @@ extern "C" { // Instance // ====================================================================== -PrRhiInstance *prRhiCreateInstance(PrRhiInstanceDesc desc, WpAllocator *alloc); -void prRhiDestroyInstance(PrRhiInstance *inst, WpAllocator *alloc); -void *prRhiGetNativeInstanceHandle(PrRhiInstance *inst); +PrRhiInstance *prRhiCreateInstance(PrRhiInstanceDesc desc, WpAllocator *allocator); +void prRhiDestroyInstance(PrRhiInstance *inst, WpAllocator *allocator); // ====================================================================== // Physical device enumeration // ====================================================================== -PrRhiPhysicalDeviceArray prRhiGetPhysicalDevices(PrRhiInstance *inst, const WpAllocator *scratch); +PrRhiPhysicalDeviceArray prRhiGetPhysicalDevices(PrRhiInstance *inst, const WpAllocator *allocator); void prRhiGetPhysicalDeviceName(PrRhiPhysicalDevice *pdev, WpStr8 *out); void prRhiGetPhysicalDeviceDriverInfo(PrRhiPhysicalDevice *pdev, WpStr8 *out); void prRhiGetPhysicalDeviceProperties(PrRhiPhysicalDevice *pdev, @@ -51,8 +50,9 @@ void prRhiGetPhysicalDeviceProperties(PrRhiPhysicalDevice *p // Surface (platform-specific) // ====================================================================== -PrRhiSurface *prRhiCreateSurface(PrRhiInstance *inst, void *window_handle, WpAllocator *alloc); -void prRhiDestroySurface(PrRhiInstance *inst, PrRhiSurface *surface, WpAllocator *alloc); +PrRhiSurface *prRhiCreateSurfaceFromWindow(PrRhiInstance *inst, void *window_handle, + WpAllocator *allocator); +void prRhiDestroySurface(PrRhiInstance *inst, PrRhiSurface *surface, WpAllocator *allocator); PrRhiSurfaceCapabilities prRhiGetSurfaceCapabilities(PrRhiPhysicalDevice *pdev, PrRhiSurface *surface); @@ -61,8 +61,8 @@ PrRhiSurfaceCapabilities prRhiGetSurfaceCapabilities(PrRhiPhysicalDevice *pdev, // ====================================================================== PrRhiDevice *prRhiCreateDevice(PrRhiPhysicalDevice *pdev, PrRhiSurface *surface, - PrRhiDeviceDesc desc, WpAllocator *alloc); -void prRhiDestroyDevice(PrRhiDevice *device, WpAllocator *alloc); + PrRhiDeviceDesc desc, WpAllocator *allocator); +void prRhiDestroyDevice(PrRhiDevice *device, WpAllocator *allocator); void prRhiDeviceWaitIdle(PrRhiDevice *device); u32 prRhiGetQueueFamilyIndex(PrRhiDevice *device); @@ -71,9 +71,9 @@ u32 prRhiGetQueueFamilyIndex(PrRhiDevice *device); // ====================================================================== PrRhiSwapchain *prRhiCreateSwapchain(PrRhiDevice *device, PrRhiSwapchainDesc desc, - WpAllocator *alloc); + WpAllocator *allocator); void prRhiDestroySwapchain(PrRhiDevice *device, PrRhiSwapchain *swapchain, - WpAllocator *alloc); + WpAllocator *allocator); PrRhiSwapchainResult prRhiAcquireNextImage(PrRhiDevice *device, PrRhiSwapchain *swapchain, PrRhiSemaphore *signal_semaphore, u32 *out_image_index); @@ -82,7 +82,7 @@ PrRhiSwapchainResult prRhiPresent(PrRhiDevice *device, PrRhiSwapchain *swapchain PrRhiSemaphore *wait_semaphore); void prRhiRecreateSwapchain(PrRhiDevice *device, PrRhiSwapchain **swapchain, - u32 width, u32 height, WpAllocator *alloc); + u32 width, u32 height, WpAllocator *allocator); PrRhiTexture *prRhiGetSwapchainTexture(PrRhiSwapchain *swapchain, u32 image_index); PrRhiTexture *prRhiGetSwapchainDepthTexture(PrRhiSwapchain *swapchain); @@ -93,8 +93,8 @@ PrRhiFormat prRhiGetSwapchainFormat(PrRhiSwapchain *swapchain); // ====================================================================== PrRhiBuffer *prRhiCreateBuffer(PrRhiDevice *device, PrRhiBufferDesc desc, - WpAllocator *alloc); -void prRhiDestroyBuffer(PrRhiDevice *device, PrRhiBuffer *buffer, WpAllocator *alloc); + WpAllocator *allocator); +void prRhiDestroyBuffer(PrRhiDevice *device, PrRhiBuffer *buffer, WpAllocator *allocator); void *prRhiBufferMap(PrRhiDevice *device, PrRhiBuffer *buffer); void prRhiBufferUnmap(PrRhiDevice *device, PrRhiBuffer *buffer); @@ -106,26 +106,29 @@ PrRhiDeviceAddress prRhiGetBufferDeviceAddress(PrRhiDevice *device, PrRhiBuffer // ====================================================================== PrRhiTexture *prRhiCreateTexture(PrRhiDevice *device, PrRhiTextureDesc desc, - WpAllocator *alloc); + WpAllocator *allocator); +PrRhiTexture *prRhiCreateTextureFromKtx(PrRhiDevice *device, const char *path, + PrRhiCommandPool *pool, PrRhiCommandBuffer *cb, + WpAllocator *allocator); void prRhiDestroyTexture(PrRhiDevice *device, PrRhiTexture *texture, - WpAllocator *alloc); + WpAllocator *allocator); // ====================================================================== // Samplers // ====================================================================== PrRhiSampler *prRhiCreateSampler(PrRhiDevice *device, PrRhiSamplerDesc desc, - WpAllocator *alloc); + WpAllocator *allocator); void prRhiDestroySampler(PrRhiDevice *device, PrRhiSampler *sampler, - WpAllocator *alloc); + WpAllocator *allocator); // ====================================================================== // Shaders (from SPIR-V) // ====================================================================== PrRhiShader *prRhiCreateShader(PrRhiDevice *device, PrRhiShaderDesc desc, - WpAllocator *alloc); -void prRhiDestroyShader(PrRhiDevice *device, PrRhiShader *shader, WpAllocator *alloc); + WpAllocator *allocator); +void prRhiDestroyShader(PrRhiDevice *device, PrRhiShader *shader, WpAllocator *allocator); // ====================================================================== // Pipeline layouts @@ -133,10 +136,10 @@ void prRhiDestroyShader(PrRhiDevice *device, PrRhiShader *shader, WpAllo PrRhiPipelineLayout *prRhiCreatePipelineLayout(PrRhiDevice *device, PrRhiPipelineLayoutDesc desc, - WpAllocator *alloc); + WpAllocator *allocator); void prRhiDestroyPipelineLayout(PrRhiDevice *device, PrRhiPipelineLayout *layout, - WpAllocator *alloc); + WpAllocator *allocator); // ====================================================================== // Pipelines @@ -144,12 +147,12 @@ void prRhiDestroyPipelineLayout(PrRhiDevice *device, PrRhiPipeline *prRhiCreateGraphicsPipeline(PrRhiDevice *device, PrRhiGraphicsPipelineDesc desc, - WpAllocator *alloc); + WpAllocator *allocator); PrRhiPipeline *prRhiCreateComputePipeline(PrRhiDevice *device, PrRhiComputePipelineDesc desc, - WpAllocator *alloc); + WpAllocator *allocator); void prRhiDestroyPipeline(PrRhiDevice *device, PrRhiPipeline *pipeline, - WpAllocator *alloc); + WpAllocator *allocator); // ====================================================================== // Descriptor set layouts @@ -157,10 +160,10 @@ void prRhiDestroyPipeline(PrRhiDevice *device, PrRhiPipeline *pipeline PrRhiDescriptorSetLayout *prRhiCreateDescriptorSetLayout(PrRhiDevice *device, PrRhiDescriptorSetLayoutDesc desc, - WpAllocator *alloc); + WpAllocator *allocator); void prRhiDestroyDescriptorSetLayout(PrRhiDevice *device, PrRhiDescriptorSetLayout *layout, - WpAllocator *alloc); + WpAllocator *allocator); // ====================================================================== // Descriptor pools @@ -168,10 +171,10 @@ void prRhiDestroyDescriptorSetLayout(PrRhiDevice *device, PrRhiDescriptorPool *prRhiCreateDescriptorPool(PrRhiDevice *device, PrRhiDescriptorPoolDesc desc, - WpAllocator *alloc); + WpAllocator *allocator); void prRhiDestroyDescriptorPool(PrRhiDevice *device, PrRhiDescriptorPool *pool, - WpAllocator *alloc); + WpAllocator *allocator); // ====================================================================== // Descriptor sets @@ -179,9 +182,9 @@ void prRhiDestroyDescriptorPool(PrRhiDevice *device, PrRhiDescriptorSet *prRhiAllocateDescriptorSet(PrRhiDevice *device, PrRhiDescriptorPool *pool, PrRhiDescriptorSetLayout *layout, - u32 variable_count, WpAllocator *alloc); + u32 variable_count, WpAllocator *allocator); void prRhiFreeDescriptorSet(PrRhiDevice *device, PrRhiDescriptorPool *pool, - PrRhiDescriptorSet *set, WpAllocator *alloc); + PrRhiDescriptorSet *set, WpAllocator *allocator); void prRhiUpdateDescriptorSet(PrRhiDevice *device, PrRhiWriteDescriptorSetArray writes); // ====================================================================== @@ -189,28 +192,28 @@ void prRhiUpdateDescriptorSet(PrRhiDevice *device, PrRhiWriteDesc // ====================================================================== PrRhiFence *prRhiCreateFence(PrRhiDevice *device, PrRhiFenceDesc desc, - WpAllocator *alloc); -void prRhiDestroyFence(PrRhiDevice *device, PrRhiFence *fence, WpAllocator *alloc); + WpAllocator *allocator); +void prRhiDestroyFence(PrRhiDevice *device, PrRhiFence *fence, WpAllocator *allocator); void prRhiWaitForFences(PrRhiDevice *device, PrRhiFenceArray fences, u32 count, b8 wait_all, u64 timeout_ns); void prRhiResetFences(PrRhiDevice *device, PrRhiFenceArray fences, u32 count); -PrRhiSemaphore *prRhiCreateSemaphore(PrRhiDevice *device, WpAllocator *alloc); +PrRhiSemaphore *prRhiCreateSemaphore(PrRhiDevice *device, WpAllocator *allocator); void prRhiDestroySemaphore(PrRhiDevice *device, PrRhiSemaphore *semaphore, - WpAllocator *alloc); + WpAllocator *allocator); // ====================================================================== // Command pools and command buffers // ====================================================================== PrRhiCommandPool *prRhiCreateCommandPool(PrRhiDevice *device, PrRhiCommandPoolDesc desc, - WpAllocator *alloc); + WpAllocator *allocator); void prRhiDestroyCommandPool(PrRhiDevice *device, PrRhiCommandPool *pool, - WpAllocator *alloc); + WpAllocator *allocator); PrRhiCommandBufferArray prRhiAllocateCommandBuffers(PrRhiDevice *device, PrRhiCommandPool *pool, - u32 count, WpAllocator *alloc); + u32 count, WpAllocator *allocator); void prRhiFreeCommandBuffers(PrRhiDevice *device, PrRhiCommandPool *pool, u32 count, PrRhiCommandBufferArray buffers); diff --git a/src/prism/rhi/pr_rhi_types.h b/src/prism/rhi/pr_rhi_types.h index 43ea65e..d29f5d5 100644 --- a/src/prism/rhi/pr_rhi_types.h +++ b/src/prism/rhi/pr_rhi_types.h @@ -9,6 +9,8 @@ #include "../../wapp/wapp.h" +#define PR_RHI_LOD_CLAMP_NONE 1000.0f + // ============================================================================ // Opaque handle types // ============================================================================ @@ -36,6 +38,14 @@ typedef struct PrRhiSemaphore PrRhiSemaphore; // Enums and flags // ============================================================================ +typedef enum PrRhiPhysicalDeviceType { + PR_RHI_PHYSICAL_DEVICE_TYPE_OTHER = 0, + PR_RHI_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU = 1, + PR_RHI_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU = 2, + PR_RHI_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU = 3, + PR_RHI_PHYSICAL_DEVICE_TYPE_CPU = 4, +} PrRhiPhysicalDeviceType; + typedef enum PrRhiSwapchainResult { PR_RHI_SWAPCHAIN_SUCCESS = 0, PR_RHI_SWAPCHAIN_OUT_OF_DATE, @@ -96,6 +106,33 @@ typedef enum PrRhiShaderStage { PR_RHI_SHADER_STAGE_COMPUTE = 1 << 2, } PrRhiShaderStage; +typedef enum PrRhiPipelineStage { + PR_RHI_PIPELINE_STAGE_NONE = 0, + PR_RHI_PIPELINE_STAGE_TOP_OF_PIPE = 1 << 0, + PR_RHI_PIPELINE_STAGE_TRANSFER = 1 << 1, + PR_RHI_PIPELINE_STAGE_VERTEX_SHADER = 1 << 2, + PR_RHI_PIPELINE_STAGE_FRAGMENT_SHADER = 1 << 3, + PR_RHI_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS = 1 << 4, + PR_RHI_PIPELINE_STAGE_LATE_FRAGMENT_TESTS = 1 << 5, + PR_RHI_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT = 1 << 6, + PR_RHI_PIPELINE_STAGE_COMPUTE_SHADER = 1 << 7, + PR_RHI_PIPELINE_STAGE_BOTTOM_OF_PIPE = 1 << 8, +} PrRhiPipelineStage; + +typedef enum PrRhiAccess { + PR_RHI_ACCESS_NONE = 0, + PR_RHI_ACCESS_TRANSFER_READ = 1 << 0, + PR_RHI_ACCESS_TRANSFER_WRITE = 1 << 1, + PR_RHI_ACCESS_SHADER_READ = 1 << 2, + PR_RHI_ACCESS_SHADER_WRITE = 1 << 3, + PR_RHI_ACCESS_COLOR_ATTACHMENT_READ = 1 << 4, + PR_RHI_ACCESS_COLOR_ATTACHMENT_WRITE = 1 << 5, + PR_RHI_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ = 1 << 6, + PR_RHI_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE = 1 << 7, + PR_RHI_ACCESS_MEMORY_READ = 1 << 8, + PR_RHI_ACCESS_MEMORY_WRITE = 1 << 9, +} PrRhiAccess; + typedef enum PrRhiDescriptorType { PR_RHI_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, PR_RHI_DESCRIPTOR_TYPE_STORAGE_IMAGE, @@ -212,20 +249,20 @@ typedef struct PrRhiImageMemoryBarrier { PrRhiTexture *texture; PrRhiImageLayout old_layout; PrRhiImageLayout new_layout; - u64 src_stage_mask; - u64 src_access_mask; - u64 dst_stage_mask; - u64 dst_access_mask; + PrRhiPipelineStage src_stage_mask; + PrRhiAccess src_access_mask; + PrRhiPipelineStage dst_stage_mask; + PrRhiAccess dst_access_mask; } PrRhiImageMemoryBarrier; typedef struct PrRhiBufferMemoryBarrier { - PrRhiBuffer *buffer; - u64 offset; - u64 size; - u64 src_stage_mask; - u64 src_access_mask; - u64 dst_stage_mask; - u64 dst_access_mask; + PrRhiBuffer *buffer; + u64 offset; + u64 size; + PrRhiPipelineStage src_stage_mask; + PrRhiAccess src_access_mask; + PrRhiPipelineStage dst_stage_mask; + PrRhiAccess dst_access_mask; } PrRhiBufferMemoryBarrier; typedef struct PrRhiBufferImageCopy { @@ -255,8 +292,6 @@ typedef PrRhiSemaphore **PrRhiSemaphoreArray; typedef PrRhiCommandBuffer **PrRhiCommandBufferArray; typedef PrRhiDescriptorSetLayout **PrRhiDescriptorSetLayoutArray; typedef PrRhiDescriptorSet **PrRhiDescriptorSetArray; -typedef const char **PrRhiExtensionArray; - // Value type arrays (contiguous structs/enums) typedef PrRhiPushConstantRange *PrRhiPushConstantRangeArray; typedef PrRhiVertexInputBinding *PrRhiVertexInputBindingArray; @@ -278,9 +313,8 @@ typedef struct PrRhiWriteDescriptorSet *PrRhiWriteDescriptorSetArray; // ============================================================================ typedef struct PrRhiInstanceDesc { - const char *app_name; - u32 app_version; - PrRhiExtensionArray extra_extensions; + const char *app_name; + u32 app_version; } PrRhiInstanceDesc; typedef struct PrRhiDeviceDesc { @@ -398,8 +432,8 @@ typedef struct PrRhiSurfaceCapabilities { } PrRhiSurfaceCapabilities; typedef struct PrRhiPhysicalDeviceProperties { - u32 api_version; - u32 device_type; // VkPhysicalDeviceType + u32 api_version; + PrRhiPhysicalDeviceType device_type; } PrRhiPhysicalDeviceProperties; typedef u64 PrRhiDeviceAddress; diff --git a/src/prism/rhi/vulkan/pr_rhi_vk.c b/src/prism/rhi/vulkan/pr_rhi_vk.c index 28e6822..8d6bcd1 100644 --- a/src/prism/rhi/vulkan/pr_rhi_vk.c +++ b/src/prism/rhi/vulkan/pr_rhi_vk.c @@ -8,6 +8,9 @@ #include "profiles/vulkan_profiles.h" #include #include +#include +#include +#include #include // ============================================================================ @@ -45,6 +48,9 @@ wp_intern VkPresentModeKHR _toVkPresentMode(PrRhiPresentMode mode); wp_intern VkFilter _toVkFilter(PrRhiFilter f); wp_intern VkSamplerMipmapMode _toVkMipmapMode(PrRhiMipmapMode m); wp_intern VkSamplerAddressMode _toVkAddressMode(PrRhiAddressMode m); +wp_intern VkPipelineStageFlags2 _toVkPipelineStage2(PrRhiPipelineStage stage); +wp_intern VkAccessFlags2 _toVkAccess2(PrRhiAccess access); +wp_intern VkPhysicalDeviceType _toVkPhysicalDeviceType(PrRhiPhysicalDeviceType type); wp_persist const VpProfileProperties _profile = { .profileName = VP_PRISM_DESKTOP_2026_NAME, @@ -262,11 +268,51 @@ VkSamplerAddressMode _toVkAddressMode(PrRhiAddressMode m) { } } +VkPipelineStageFlags2 _toVkPipelineStage2(PrRhiPipelineStage stage) { + VkPipelineStageFlags2 flags = VK_PIPELINE_STAGE_2_NONE; + if (stage & PR_RHI_PIPELINE_STAGE_TOP_OF_PIPE) flags |= VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT; + if (stage & PR_RHI_PIPELINE_STAGE_TRANSFER) flags |= VK_PIPELINE_STAGE_2_TRANSFER_BIT; + if (stage & PR_RHI_PIPELINE_STAGE_VERTEX_SHADER) flags |= VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT; + if (stage & PR_RHI_PIPELINE_STAGE_FRAGMENT_SHADER) flags |= VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT; + if (stage & PR_RHI_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS) flags |= VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT; + if (stage & PR_RHI_PIPELINE_STAGE_LATE_FRAGMENT_TESTS) flags |= VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT; + if (stage & PR_RHI_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT) flags |= VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT; + if (stage & PR_RHI_PIPELINE_STAGE_COMPUTE_SHADER) flags |= VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT; + if (stage & PR_RHI_PIPELINE_STAGE_BOTTOM_OF_PIPE) flags |= VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT; + return flags; +} + +VkAccessFlags2 _toVkAccess2(PrRhiAccess access) { + VkAccessFlags2 flags = VK_ACCESS_2_NONE; + if (access & PR_RHI_ACCESS_TRANSFER_READ) flags |= VK_ACCESS_2_TRANSFER_READ_BIT; + if (access & PR_RHI_ACCESS_TRANSFER_WRITE) flags |= VK_ACCESS_2_TRANSFER_WRITE_BIT; + if (access & PR_RHI_ACCESS_SHADER_READ) flags |= VK_ACCESS_2_SHADER_READ_BIT; + if (access & PR_RHI_ACCESS_SHADER_WRITE) flags |= VK_ACCESS_2_SHADER_WRITE_BIT; + if (access & PR_RHI_ACCESS_COLOR_ATTACHMENT_READ) flags |= VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT; + if (access & PR_RHI_ACCESS_COLOR_ATTACHMENT_WRITE) flags |= VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT; + if (access & PR_RHI_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ) flags |= VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT; + if (access & PR_RHI_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE) flags |= VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + if (access & PR_RHI_ACCESS_MEMORY_READ) flags |= VK_ACCESS_2_MEMORY_READ_BIT; + if (access & PR_RHI_ACCESS_MEMORY_WRITE) flags |= VK_ACCESS_2_MEMORY_WRITE_BIT; + return flags; +} + +VkPhysicalDeviceType _toVkPhysicalDeviceType(PrRhiPhysicalDeviceType type) { + switch (type) { + case PR_RHI_PHYSICAL_DEVICE_TYPE_OTHER: return VK_PHYSICAL_DEVICE_TYPE_OTHER; + case PR_RHI_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: return VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU; + case PR_RHI_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: return VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU; + case PR_RHI_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: return VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU; + case PR_RHI_PHYSICAL_DEVICE_TYPE_CPU: return VK_PHYSICAL_DEVICE_TYPE_CPU; + default: return VK_PHYSICAL_DEVICE_TYPE_OTHER; + } +} + // ============================================================================ // Instance // ============================================================================ -PrRhiInstance *prRhiCreateInstanceVk(PrRhiInstanceDesc desc, WpAllocator *alloc) { +PrRhiInstance *prRhiCreateInstanceVk(PrRhiInstanceDesc desc, WpAllocator *allocator) { (void)desc; volkInitialize(); @@ -275,6 +321,11 @@ PrRhiInstance *prRhiCreateInstanceVk(PrRhiInstanceDesc desc, WpAllocator *alloc) _checkVk(vpGetInstanceProfileSupport(NULL, &_profile, &supported), "vpGetInstanceProfileSupport"); if (!supported) _abort("VP_PRISM_DESKTOP_2026 not supported at instance level"); + u32 sdl_ext_count = 0; + const char *const *sdl_exts = SDL_Vulkan_GetInstanceExtensions(&sdl_ext_count); + if (!sdl_exts || sdl_ext_count == 0) + _abort("SDL_Vulkan_GetInstanceExtensions failed"); + VkApplicationInfo app_info = {}; app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; app_info.pApplicationName = desc.app_name ? desc.app_name : "Prism"; @@ -284,11 +335,8 @@ PrRhiInstance *prRhiCreateInstanceVk(PrRhiInstanceDesc desc, WpAllocator *alloc) VkInstanceCreateInfo instance_info = {}; instance_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; instance_info.pApplicationInfo = &app_info; - - if (desc.extra_extensions && wpArrayCount(desc.extra_extensions) > 0) { - instance_info.enabledExtensionCount = (u32)wpArrayCount(desc.extra_extensions); - instance_info.ppEnabledExtensionNames = (const char *const *)desc.extra_extensions; - } + instance_info.enabledExtensionCount = sdl_ext_count; + instance_info.ppEnabledExtensionNames = sdl_exts; VpInstanceCreateInfo vp_instance_info = {}; vp_instance_info.pCreateInfo = &instance_info; @@ -300,7 +348,7 @@ PrRhiInstance *prRhiCreateInstanceVk(PrRhiInstanceDesc desc, WpAllocator *alloc) volkLoadInstance(vk_instance); - PrRhiInstance *inst = wpMemAllocatorAlloc(alloc, sizeof(PrRhiInstance)); + PrRhiInstance *inst = wpMemAllocatorAlloc(allocator, sizeof(PrRhiInstance)); if (!inst) _abort("alloc failed for PrRhiInstance"); inst->handle = vk_instance; inst->debug_messenger = NULL; @@ -308,38 +356,34 @@ PrRhiInstance *prRhiCreateInstanceVk(PrRhiInstanceDesc desc, WpAllocator *alloc) return inst; } -void prRhiDestroyInstanceVk(PrRhiInstance *inst, WpAllocator *alloc) { +void prRhiDestroyInstanceVk(PrRhiInstance *inst, WpAllocator *allocator) { if (!inst) return; vkDestroyInstance((VkInstance)inst->handle, NULL); - wpMemAllocatorFree(alloc, (void**)&inst, sizeof(PrRhiInstance)); -} - -void *prRhiGetNativeInstanceHandleVk(PrRhiInstance *inst) { - return inst->handle; + wpMemAllocatorFree(allocator, (void**)&inst, sizeof(PrRhiInstance)); } // ============================================================================ // Physical device enumeration // ============================================================================ -PrRhiPhysicalDeviceArray prRhiGetPhysicalDevicesVk(PrRhiInstance *inst, const WpAllocator *scratch) { +PrRhiPhysicalDeviceArray prRhiGetPhysicalDevicesVk(PrRhiInstance *inst, const WpAllocator *allocator) { VkInstance vk_inst = (VkInstance)inst->handle; u32 count = 0; _checkVk(vkEnumeratePhysicalDevices(vk_inst, &count, NULL), "vkEnumeratePhysicalDevices"); if (count == 0) _abort("no physical devices"); - VkPhysicalDeviceArray vk_devices = wpArrayAllocCapacity(VkPhysicalDevice, scratch, count, WP_ARRAY_INIT_FILLED); + VkPhysicalDeviceArray vk_devices = wpArrayAllocCapacity(VkPhysicalDevice, allocator, count, WP_ARRAY_INIT_FILLED); if (!vk_devices) _abort("alloc failed for physical device array"); _checkVk(vkEnumeratePhysicalDevices(vk_inst, &count, vk_devices), "vkEnumeratePhysicalDevices"); wpArraySetCount(vk_devices, count); - PrRhiPhysicalDeviceArray pdevs = wpArrayAllocCapacity(PrRhiPhysicalDevice *, scratch, count, WP_ARRAY_INIT_NONE); + PrRhiPhysicalDeviceArray pdevs = wpArrayAllocCapacity(PrRhiPhysicalDevice *, allocator, count, WP_ARRAY_INIT_NONE); if (!pdevs) _abort("alloc failed for PrRhiPhysicalDevice array"); for (u32 i = 0; i < count; ++i) { - PrRhiPhysicalDevice *pdev = (PrRhiPhysicalDevice *)wpMemAllocatorAlloc(scratch, sizeof(PrRhiPhysicalDevice)); + PrRhiPhysicalDevice *pdev = (PrRhiPhysicalDevice *)wpMemAllocatorAlloc(allocator, sizeof(PrRhiPhysicalDevice)); if (!pdev) _abort("alloc failed for PrRhiPhysicalDevice"); pdev->handle = vk_devices[i]; pdev->instance = inst; @@ -374,26 +418,32 @@ void prRhiGetPhysicalDevicePropertiesVk(PrRhiPhysicalDevice *pdev, VkPhysicalDeviceProperties2 props = { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 }; vkGetPhysicalDeviceProperties2((VkPhysicalDevice)pdev->handle, &props); out->api_version = props.properties.apiVersion; - out->device_type = (u32)props.properties.deviceType; + out->device_type = (PrRhiPhysicalDeviceType)props.properties.deviceType; } // ============================================================================ // Surface // ============================================================================ -PrRhiSurface *prRhiCreateSurfaceVk(PrRhiInstance *inst, void *window_handle, WpAllocator *alloc) { - (void)inst; - // window_handle is already a VkSurfaceKHR created by the caller (e.g. via SDL). - PrRhiSurface *surface = wpMemAllocatorAlloc(alloc, sizeof(PrRhiSurface)); +PrRhiSurface *prRhiCreateSurfaceFromWindowVk(PrRhiInstance *inst, void *window_handle, + WpAllocator *allocator) { + SDL_Window *window = (SDL_Window *)window_handle; + VkInstance vk_inst = (VkInstance)inst->handle; + + VkSurfaceKHR vk_surface = VK_NULL_HANDLE; + if (!SDL_Vulkan_CreateSurface(window, vk_inst, NULL, &vk_surface)) + _abort("SDL_Vulkan_CreateSurface failed"); + + PrRhiSurface *surface = wpMemAllocatorAlloc(allocator, sizeof(PrRhiSurface)); if (!surface) _abort("alloc failed for PrRhiSurface"); - surface->handle = window_handle; + surface->handle = (void *)vk_surface; return surface; } -void prRhiDestroySurfaceVk(PrRhiInstance *inst, PrRhiSurface *surface, WpAllocator *alloc) { +void prRhiDestroySurfaceVk(PrRhiInstance *inst, PrRhiSurface *surface, WpAllocator *allocator) { if (!surface) return; vkDestroySurfaceKHR((VkInstance)inst->handle, (VkSurfaceKHR)surface->handle, NULL); - wpMemAllocatorFree(alloc, (void**)&surface, sizeof(PrRhiSurface)); + wpMemAllocatorFree(allocator, (void**)&surface, sizeof(PrRhiSurface)); } PrRhiSurfaceCapabilities prRhiGetSurfaceCapabilitiesVk(PrRhiPhysicalDevice *pdev, PrRhiSurface *surface) { @@ -420,7 +470,7 @@ PrRhiSurfaceCapabilities prRhiGetSurfaceCapabilitiesVk(PrRhiPhysicalDevice *pdev // ============================================================================ PrRhiDevice *prRhiCreateDeviceVk(PrRhiPhysicalDevice *pdev, PrRhiSurface *surface, - PrRhiDeviceDesc desc, WpAllocator *alloc) { + PrRhiDeviceDesc desc, WpAllocator *allocator) { VkInstance vk_inst = (VkInstance)pdev->instance->handle; VkPhysicalDevice vk_pdev = (VkPhysicalDevice)pdev->handle; VkSurfaceKHR vk_surface = (VkSurfaceKHR)surface->handle; @@ -431,7 +481,7 @@ PrRhiDevice *prRhiCreateDeviceVk(PrRhiPhysicalDevice *pdev, PrRhiSurface *surfac if (queue_family_count == 0) _abort("no queue families"); VkQueueFamilyProperties2Array qf_props = - wpArrayAllocCapacity(VkQueueFamilyProperties2, alloc, queue_family_count, WP_ARRAY_INIT_FILLED); + wpArrayAllocCapacity(VkQueueFamilyProperties2, allocator, queue_family_count, WP_ARRAY_INIT_FILLED); if (!qf_props) _abort("alloc failed for queue family props"); for (u32 i = 0; i < queue_family_count; ++i) { @@ -456,7 +506,7 @@ PrRhiDevice *prRhiCreateDeviceVk(PrRhiPhysicalDevice *pdev, PrRhiSurface *surfac "vkGetPhysicalDeviceSurfaceSupportKHR"); if (!present_supported) _abort("no presentation support"); - wpArrayDealloc(VkQueueFamilyProperties2, alloc, &qf_props); + wpArrayDealloc(VkQueueFamilyProperties2, allocator, &qf_props); // Check device profile support VkBool32 profile_supported = VK_FALSE; @@ -508,7 +558,7 @@ PrRhiDevice *prRhiCreateDeviceVk(PrRhiPhysicalDevice *pdev, PrRhiSurface *surfac VmaAllocator vma_allocator = VK_NULL_HANDLE; _checkVk(vmaCreateAllocator(&vma_info, &vma_allocator), "vmaCreateAllocator"); - PrRhiDevice *device = wpMemAllocatorAlloc(alloc, sizeof(PrRhiDevice)); + PrRhiDevice *device = wpMemAllocatorAlloc(allocator, sizeof(PrRhiDevice)); if (!device) _abort("alloc failed for PrRhiDevice"); device->handle = vk_device; device->queue = vk_queue; @@ -520,12 +570,12 @@ PrRhiDevice *prRhiCreateDeviceVk(PrRhiPhysicalDevice *pdev, PrRhiSurface *surfac return device; } -void prRhiDestroyDeviceVk(PrRhiDevice *device, WpAllocator *alloc) { +void prRhiDestroyDeviceVk(PrRhiDevice *device, WpAllocator *allocator) { if (!device) return; vkDeviceWaitIdle((VkDevice)device->handle); vmaDestroyAllocator((VmaAllocator)device->allocator); vkDestroyDevice((VkDevice)device->handle, NULL); - wpMemAllocatorFree(alloc, (void**)&device, sizeof(PrRhiDevice)); + wpMemAllocatorFree(allocator, (void**)&device, sizeof(PrRhiDevice)); } void prRhiDeviceWaitIdleVk(PrRhiDevice *device) { @@ -542,8 +592,8 @@ u32 prRhiGetQueueFamilyIndexVk(PrRhiDevice *device) { static PrRhiTexture *_createSwapchainTexture(PrRhiDevice *device, VkImage vk_image, VkFormat vk_format, u32 width, u32 height, - VkImageView vk_view, WpAllocator *alloc) { - PrRhiTexture *tex = wpMemAllocatorAlloc(alloc, sizeof(PrRhiTexture)); + VkImageView vk_view, WpAllocator *allocator) { + PrRhiTexture *tex = wpMemAllocatorAlloc(allocator, sizeof(PrRhiTexture)); if (!tex) _abort("alloc failed for swapchain texture"); tex->image = vk_image; tex->view = vk_view; @@ -567,7 +617,7 @@ static VkFormat _pickDepthFormat(VkPhysicalDevice vk_pdev) { } PrRhiSwapchain *prRhiCreateSwapchainVk(PrRhiDevice *device, PrRhiSwapchainDesc desc, - WpAllocator *alloc) { + WpAllocator *allocator) { VkDevice vk_device = (VkDevice)device->handle; VkPhysicalDevice vk_pdev = (VkPhysicalDevice)device->physical_device; VkSurfaceKHR vk_surface = (VkSurfaceKHR)desc.surface->handle; @@ -603,13 +653,13 @@ PrRhiSwapchain *prRhiCreateSwapchainVk(PrRhiDevice *device, PrRhiSwapchainDesc d _checkVk(vkGetSwapchainImagesKHR(vk_device, vk_swapchain, &image_count, NULL), "vkGetSwapchainImagesKHR"); - VkImageArray vk_images = wpArrayAllocCapacity(VkImage, alloc, image_count, WP_ARRAY_INIT_FILLED); + VkImageArray vk_images = wpArrayAllocCapacity(VkImage, allocator, image_count, WP_ARRAY_INIT_FILLED); if (!vk_images) _abort("alloc failed for swapchain VkImage array"); _checkVk(vkGetSwapchainImagesKHR(vk_device, vk_swapchain, &image_count, vk_images), "vkGetSwapchainImagesKHR"); wpArraySetCount(vk_images, image_count); - PrRhiTextureArray images = wpArrayAllocCapacity(PrRhiTexture *, alloc, image_count, WP_ARRAY_INIT_NONE); + PrRhiTextureArray images = wpArrayAllocCapacity(PrRhiTexture *, allocator, image_count, WP_ARRAY_INIT_NONE); if (!images) _abort("alloc failed for swapchain image array"); for (u32 i = 0; i < image_count; ++i) { @@ -626,13 +676,13 @@ PrRhiSwapchain *prRhiCreateSwapchainVk(PrRhiDevice *device, PrRhiSwapchainDesc d _checkVk(vkCreateImageView(vk_device, &view_info, NULL, &vk_view), "vkCreateImageView"); PrRhiTexture *tex = _createSwapchainTexture(device, vk_images[i], _default_image_format, - extent.width, extent.height, vk_view, alloc); + extent.width, extent.height, vk_view, allocator); wpArrayAppendCapped(PrRhiTexture *, images, &tex); } - wpArrayDealloc(VkImage, alloc, &vk_images); + wpArrayDealloc(VkImage, allocator, &vk_images); - PrRhiSwapchain *swapchain = wpMemAllocatorAlloc(alloc, sizeof(PrRhiSwapchain)); + PrRhiSwapchain *swapchain = wpMemAllocatorAlloc(allocator, sizeof(PrRhiSwapchain)); if (!swapchain) _abort("alloc failed for PrRhiSwapchain"); swapchain->device = device; swapchain->handle = vk_swapchain; @@ -692,7 +742,7 @@ PrRhiSwapchain *prRhiCreateSwapchainVk(PrRhiDevice *device, PrRhiSwapchainDesc d VkImageView depth_view = VK_NULL_HANDLE; _checkVk(vkCreateImageView(vk_device, &depth_view_info, NULL, &depth_view), "vkCreateImageView (depth)"); - PrRhiTexture *depth_tex = wpMemAllocatorAlloc(alloc, sizeof(PrRhiTexture)); + PrRhiTexture *depth_tex = wpMemAllocatorAlloc(allocator, sizeof(PrRhiTexture)); if (!depth_tex) _abort("alloc failed for depth texture"); depth_tex->image = depth_image; depth_tex->view = depth_view; @@ -708,7 +758,7 @@ PrRhiSwapchain *prRhiCreateSwapchainVk(PrRhiDevice *device, PrRhiSwapchainDesc d return swapchain; } -void prRhiDestroySwapchainVk(PrRhiDevice *device, PrRhiSwapchain *swapchain, WpAllocator *alloc) { +void prRhiDestroySwapchainVk(PrRhiDevice *device, PrRhiSwapchain *swapchain, WpAllocator *allocator) { if (!swapchain) return; VkDevice vk_device = (VkDevice)device->handle; @@ -718,9 +768,9 @@ void prRhiDestroySwapchainVk(PrRhiDevice *device, PrRhiSwapchain *swapchain, WpA PrRhiTexture *tex = swapchain->images[i]; vkDestroyImageView(vk_device, (VkImageView)tex->view, NULL); // VkImage is owned by swapchain — skip vmaDestroyImage - wpMemAllocatorFree(alloc, (void**)&tex, sizeof(PrRhiTexture)); + wpMemAllocatorFree(allocator, (void**)&tex, sizeof(PrRhiTexture)); } - wpArrayDealloc(PrRhiTexture *, alloc, &swapchain->images); + wpArrayDealloc(PrRhiTexture *, allocator, &swapchain->images); // Destroy depth if (swapchain->depth) { @@ -728,11 +778,11 @@ void prRhiDestroySwapchainVk(PrRhiDevice *device, PrRhiSwapchain *swapchain, WpA vkDestroyImageView(vk_device, (VkImageView)depth->view, NULL); vmaDestroyImage((VmaAllocator)device->allocator, (VkImage)depth->image, (VmaAllocation)depth->allocation); - wpMemAllocatorFree(alloc, (void**)&depth, sizeof(PrRhiTexture)); + wpMemAllocatorFree(allocator, (void**)&depth, sizeof(PrRhiTexture)); } vkDestroySwapchainKHR(vk_device, (VkSwapchainKHR)swapchain->handle, NULL); - wpMemAllocatorFree(alloc, (void**)&swapchain, sizeof(PrRhiSwapchain)); + wpMemAllocatorFree(allocator, (void**)&swapchain, sizeof(PrRhiSwapchain)); } PrRhiSwapchainResult prRhiAcquireNextImageVk(PrRhiDevice *device, PrRhiSwapchain *swapchain, @@ -767,7 +817,7 @@ PrRhiSwapchainResult prRhiPresentVk(PrRhiDevice *device, PrRhiSwapchain *swapcha } void prRhiRecreateSwapchainVk(PrRhiDevice *device, PrRhiSwapchain **swapchain, - u32 width, u32 height, WpAllocator *alloc) { + u32 width, u32 height, WpAllocator *allocator) { PrRhiSwapchain *old = *swapchain; if (!old) return; @@ -798,9 +848,9 @@ void prRhiRecreateSwapchainVk(PrRhiDevice *device, PrRhiSwapchain **swapchain, for (u32 i = 0; i < old->image_count; ++i) { PrRhiTexture *tex = old->images[i]; vkDestroyImageView(vk_device, (VkImageView)tex->view, NULL); - wpMemAllocatorFree(alloc, (void**)&tex, sizeof(PrRhiTexture)); + wpMemAllocatorFree(allocator, (void**)&tex, sizeof(PrRhiTexture)); } - wpArrayDealloc(PrRhiTexture *, alloc, &old->images); + wpArrayDealloc(PrRhiTexture *, allocator, &old->images); // Destroy old depth if (old->depth) { @@ -808,7 +858,7 @@ void prRhiRecreateSwapchainVk(PrRhiDevice *device, PrRhiSwapchain **swapchain, vkDestroyImageView(vk_device, (VkImageView)depth->view, NULL); vmaDestroyImage((VmaAllocator)device->allocator, (VkImage)depth->image, (VmaAllocation)depth->allocation); - wpMemAllocatorFree(alloc, (void**)&depth, sizeof(PrRhiTexture)); + wpMemAllocatorFree(allocator, (void**)&depth, sizeof(PrRhiTexture)); } // Destroy old swapchain @@ -819,13 +869,13 @@ void prRhiRecreateSwapchainVk(PrRhiDevice *device, PrRhiSwapchain **swapchain, _checkVk(vkGetSwapchainImagesKHR(vk_device, vk_new_swapchain, &new_image_count, NULL), "vkGetSwapchainImagesKHR (recreate)"); - VkImageArray vk_images = wpArrayAllocCapacity(VkImage, alloc, new_image_count, WP_ARRAY_INIT_FILLED); + VkImageArray vk_images = wpArrayAllocCapacity(VkImage, allocator, new_image_count, WP_ARRAY_INIT_FILLED); if (!vk_images) _abort("alloc failed for swapchain VkImage array (recreate)"); _checkVk(vkGetSwapchainImagesKHR(vk_device, vk_new_swapchain, &new_image_count, vk_images), "vkGetSwapchainImagesKHR (recreate)"); wpArraySetCount(vk_images, new_image_count); - PrRhiTextureArray new_images = wpArrayAllocCapacity(PrRhiTexture *, alloc, new_image_count, WP_ARRAY_INIT_NONE); + PrRhiTextureArray new_images = wpArrayAllocCapacity(PrRhiTexture *, allocator, new_image_count, WP_ARRAY_INIT_NONE); if (!new_images) _abort("alloc failed for swapchain image array (recreate)"); for (u32 i = 0; i < new_image_count; ++i) { @@ -842,11 +892,11 @@ void prRhiRecreateSwapchainVk(PrRhiDevice *device, PrRhiSwapchain **swapchain, _checkVk(vkCreateImageView(vk_device, &view_info, NULL, &vk_view), "vkCreateImageView (recreate)"); PrRhiTexture *tex = _createSwapchainTexture(device, vk_images[i], (VkFormat)old->format, - extent.width, extent.height, vk_view, alloc); + extent.width, extent.height, vk_view, allocator); wpArrayAppendCapped(PrRhiTexture *, new_images, &tex); } - wpArrayDealloc(VkImage, alloc, &vk_images); + wpArrayDealloc(VkImage, allocator, &vk_images); // Recreate depth PrRhiTexture *new_depth = NULL; @@ -890,7 +940,7 @@ void prRhiRecreateSwapchainVk(PrRhiDevice *device, PrRhiSwapchain **swapchain, VkImageView depth_view = VK_NULL_HANDLE; _checkVk(vkCreateImageView(vk_device, &depth_view_info, NULL, &depth_view), "vkCreateImageView (depth recreate)"); - new_depth = wpMemAllocatorAlloc(alloc, sizeof(PrRhiTexture)); + new_depth = wpMemAllocatorAlloc(allocator, sizeof(PrRhiTexture)); if (!new_depth) _abort("alloc failed for depth texture (recreate)"); new_depth->image = depth_image; new_depth->view = depth_view; @@ -931,7 +981,7 @@ PrRhiFormat prRhiGetSwapchainFormatVk(PrRhiSwapchain *swapchain) { // ============================================================================ PrRhiBuffer *prRhiCreateBufferVk(PrRhiDevice *device, PrRhiBufferDesc desc, - WpAllocator *alloc) { + WpAllocator *allocator) { VkBufferCreateInfo buf_info = {}; buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; buf_info.size = desc.size; @@ -956,7 +1006,7 @@ PrRhiBuffer *prRhiCreateBufferVk(PrRhiDevice *device, PrRhiBufferDesc desc, &vk_buffer, &vma_alloc, &vma_alloc_info), "vmaCreateBuffer"); - PrRhiBuffer *buffer = wpMemAllocatorAlloc(alloc, sizeof(PrRhiBuffer)); + PrRhiBuffer *buffer = wpMemAllocatorAlloc(allocator, sizeof(PrRhiBuffer)); if (!buffer) _abort("alloc failed for PrRhiBuffer"); buffer->handle = vk_buffer; buffer->allocation = vma_alloc; @@ -975,11 +1025,11 @@ PrRhiBuffer *prRhiCreateBufferVk(PrRhiDevice *device, PrRhiBufferDesc desc, return buffer; } -void prRhiDestroyBufferVk(PrRhiDevice *device, PrRhiBuffer *buffer, WpAllocator *alloc) { +void prRhiDestroyBufferVk(PrRhiDevice *device, PrRhiBuffer *buffer, WpAllocator *allocator) { if (!buffer) return; vmaDestroyBuffer((VmaAllocator)device->allocator, (VkBuffer)buffer->handle, (VmaAllocation)buffer->allocation); - wpMemAllocatorFree(alloc, (void**)&buffer, sizeof(PrRhiBuffer)); + wpMemAllocatorFree(allocator, (void**)&buffer, sizeof(PrRhiBuffer)); } void *prRhiBufferMapVk(PrRhiDevice *device, PrRhiBuffer *buffer) { @@ -1003,7 +1053,7 @@ PrRhiDeviceAddress prRhiGetBufferDeviceAddressVk(PrRhiDevice *device, PrRhiBuffe // ============================================================================ PrRhiTexture *prRhiCreateTextureVk(PrRhiDevice *device, PrRhiTextureDesc desc, - WpAllocator *alloc) { + WpAllocator *allocator) { VkImageCreateInfo img_info = {}; img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; img_info.imageType = VK_IMAGE_TYPE_2D; @@ -1045,7 +1095,7 @@ PrRhiTexture *prRhiCreateTextureVk(PrRhiDevice *device, PrRhiTextureDesc desc, _checkVk(vkCreateImageView((VkDevice)device->handle, &view_info, NULL, &vk_view), "vkCreateImageView"); - PrRhiTexture *texture = wpMemAllocatorAlloc(alloc, sizeof(PrRhiTexture)); + PrRhiTexture *texture = wpMemAllocatorAlloc(allocator, sizeof(PrRhiTexture)); if (!texture) _abort("alloc failed for PrRhiTexture"); texture->image = vk_image; texture->view = vk_view; @@ -1057,7 +1107,147 @@ PrRhiTexture *prRhiCreateTextureVk(PrRhiDevice *device, PrRhiTextureDesc desc, return texture; } -void prRhiDestroyTextureVk(PrRhiDevice *device, PrRhiTexture *texture, WpAllocator *alloc) { +PrRhiTexture *prRhiCreateTextureFromKtxVk(PrRhiDevice *device, const char *path, + PrRhiCommandPool *pool, PrRhiCommandBuffer *cb, + WpAllocator *allocator) { + VkDevice vk_device = (VkDevice)device->handle; + + ktxTexture *ktx = NULL; + ktxResult result = ktxTexture_CreateFromNamedFile(path, KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT, &ktx); + if (result != KTX_SUCCESS) _abort("ktxTexture_CreateFromNamedFile failed"); + + VkFormat vk_format = ktxTexture_GetVkFormat(ktx); + u32 width = ktx->baseWidth; + u32 height = ktx->baseHeight; + u32 mip_levels = ktx->numLevels; + + // Create staging buffer + ktx_size_t data_size = ktxTexture_GetDataSize(ktx); + void *data = ktxTexture_GetData(ktx); + + PrRhiBufferDesc buf_desc = { + .size = data_size, + .usage = PR_RHI_BUFFER_USAGE_TRANSFER_SRC, + .memory = PR_RHI_MEMORY_CPU_TO_GPU, + }; + PrRhiBuffer *staging = prRhiCreateBufferVk(device, buf_desc, allocator); + memcpy(prRhiBufferMapVk(device, staging), data, data_size); + + // Create the destination image + VkImageCreateInfo img_info = {}; + img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + img_info.imageType = VK_IMAGE_TYPE_2D; + img_info.format = vk_format; + img_info.extent.width = width; + img_info.extent.height = height; + img_info.extent.depth = 1; + img_info.mipLevels = mip_levels; + img_info.arrayLayers = 1; + img_info.samples = VK_SAMPLE_COUNT_1_BIT; + img_info.tiling = VK_IMAGE_TILING_OPTIMAL; + img_info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + img_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + + VmaAllocationCreateInfo alloc_info = {}; + alloc_info.usage = VMA_MEMORY_USAGE_AUTO; + + VkImage vk_image = VK_NULL_HANDLE; + VmaAllocation vma_alloc = VK_NULL_HANDLE; + _checkVk(vmaCreateImage((VmaAllocator)device->allocator, &img_info, &alloc_info, + &vk_image, &vma_alloc, NULL), + "vmaCreateImage"); + + // Record copy commands + VkCommandBuffer vk_cb = (VkCommandBuffer)cb->handle; + vkBeginCommandBuffer(vk_cb, &(VkCommandBufferBeginInfo){ + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, + }); + + // Transition to TRANSFER_DST + vkCmdPipelineBarrier2(vk_cb, &(VkDependencyInfo){ + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .imageMemoryBarrierCount = 1, + .pImageMemoryBarriers = &(VkImageMemoryBarrier2){ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, + .srcStageMask = VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT, + .srcAccessMask = VK_ACCESS_2_NONE, + .dstStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT, + .dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT, + .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .image = vk_image, + .subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, mip_levels, 0, 1 }, + }, + }); + + // Copy buffer to image + vkCmdCopyBufferToImage(vk_cb, (VkBuffer)staging->handle, vk_image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, &(VkBufferImageCopy){ + .bufferOffset = 0, + .imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }, + .imageExtent = { width, height, 1 }, + }); + + // Transition to SHADER_READ_ONLY + vkCmdPipelineBarrier2(vk_cb, &(VkDependencyInfo){ + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .imageMemoryBarrierCount = 1, + .pImageMemoryBarriers = &(VkImageMemoryBarrier2){ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, + .srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT, + .srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT, + .dstStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT, + .dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + .image = vk_image, + .subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, mip_levels, 0, 1 }, + }, + }); + + vkEndCommandBuffer(vk_cb); + + // Submit and wait + PrRhiFenceDesc fence_desc = { .signaled = VK_TRUE }; + PrRhiFence *fence = prRhiCreateFenceVk(device, fence_desc, allocator); + prRhiQueueSubmitVk(device, cb, NULL, NULL, fence); + prRhiWaitForFencesVk(device, &(PrRhiFence *){ fence }, 1, VK_TRUE, UINT64_MAX); + prRhiDestroyFenceVk(device, fence, allocator); + vkResetCommandBuffer(vk_cb, 0); + + // Create image view + VkImageViewCreateInfo view_info = {}; + view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + view_info.image = vk_image; + view_info.viewType = VK_IMAGE_VIEW_TYPE_2D; + view_info.format = vk_format; + view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + view_info.subresourceRange.levelCount = mip_levels; + view_info.subresourceRange.layerCount = 1; + + VkImageView vk_view = VK_NULL_HANDLE; + _checkVk(vkCreateImageView(vk_device, &view_info, NULL, &vk_view), + "vkCreateImageView"); + + PrRhiTexture *texture = wpMemAllocatorAlloc(allocator, sizeof(PrRhiTexture)); + if (!texture) _abort("alloc failed for PrRhiTexture"); + texture->image = vk_image; + texture->view = vk_view; + texture->allocation = vma_alloc; + texture->width = width; + texture->height = height; + texture->format = vk_format; + + // Cleanup staging + prRhiDestroyBufferVk(device, staging, allocator); + ktxTexture_Destroy(ktx); + + return texture; +} + +void prRhiDestroyTextureVk(PrRhiDevice *device, PrRhiTexture *texture, WpAllocator *allocator) { if (!texture) return; VkDevice vk_device = (VkDevice)device->handle; @@ -1066,7 +1256,7 @@ void prRhiDestroyTextureVk(PrRhiDevice *device, PrRhiTexture *texture, WpAllocat vmaDestroyImage((VmaAllocator)device->allocator, (VkImage)texture->image, (VmaAllocation)texture->allocation); } - wpMemAllocatorFree(alloc, (void**)&texture, sizeof(PrRhiTexture)); + wpMemAllocatorFree(allocator, (void**)&texture, sizeof(PrRhiTexture)); } // ============================================================================ @@ -1074,7 +1264,7 @@ void prRhiDestroyTextureVk(PrRhiDevice *device, PrRhiTexture *texture, WpAllocat // ============================================================================ PrRhiSampler *prRhiCreateSamplerVk(PrRhiDevice *device, PrRhiSamplerDesc desc, - WpAllocator *alloc) { + WpAllocator *allocator) { VkSamplerCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; info.magFilter = _toVkFilter(desc.mag_filter); @@ -1093,16 +1283,16 @@ PrRhiSampler *prRhiCreateSamplerVk(PrRhiDevice *device, PrRhiSamplerDesc desc, _checkVk(vkCreateSampler((VkDevice)device->handle, &info, NULL, &vk_sampler), "vkCreateSampler"); - PrRhiSampler *sampler = wpMemAllocatorAlloc(alloc, sizeof(PrRhiSampler)); + PrRhiSampler *sampler = wpMemAllocatorAlloc(allocator, sizeof(PrRhiSampler)); if (!sampler) _abort("alloc failed for PrRhiSampler"); sampler->handle = vk_sampler; return sampler; } -void prRhiDestroySamplerVk(PrRhiDevice *device, PrRhiSampler *sampler, WpAllocator *alloc) { +void prRhiDestroySamplerVk(PrRhiDevice *device, PrRhiSampler *sampler, WpAllocator *allocator) { if (!sampler) return; vkDestroySampler((VkDevice)device->handle, (VkSampler)sampler->handle, NULL); - wpMemAllocatorFree(alloc, (void**)&sampler, sizeof(PrRhiSampler)); + wpMemAllocatorFree(allocator, (void**)&sampler, sizeof(PrRhiSampler)); } // ============================================================================ @@ -1110,7 +1300,7 @@ void prRhiDestroySamplerVk(PrRhiDevice *device, PrRhiSampler *sampler, WpAllocat // ============================================================================ PrRhiShader *prRhiCreateShaderVk(PrRhiDevice *device, PrRhiShaderDesc desc, - WpAllocator *alloc) { + WpAllocator *allocator) { VkShaderModuleCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; info.codeSize = desc.spirv_size; @@ -1120,16 +1310,16 @@ PrRhiShader *prRhiCreateShaderVk(PrRhiDevice *device, PrRhiShaderDesc desc, _checkVk(vkCreateShaderModule((VkDevice)device->handle, &info, NULL, &vk_module), "vkCreateShaderModule"); - PrRhiShader *shader = wpMemAllocatorAlloc(alloc, sizeof(PrRhiShader)); + PrRhiShader *shader = wpMemAllocatorAlloc(allocator, sizeof(PrRhiShader)); if (!shader) _abort("alloc failed for PrRhiShader"); shader->handle = vk_module; return shader; } -void prRhiDestroyShaderVk(PrRhiDevice *device, PrRhiShader *shader, WpAllocator *alloc) { +void prRhiDestroyShaderVk(PrRhiDevice *device, PrRhiShader *shader, WpAllocator *allocator) { if (!shader) return; vkDestroyShaderModule((VkDevice)device->handle, (VkShaderModule)shader->handle, NULL); - wpMemAllocatorFree(alloc, (void**)&shader, sizeof(PrRhiShader)); + wpMemAllocatorFree(allocator, (void**)&shader, sizeof(PrRhiShader)); } // ============================================================================ @@ -1138,7 +1328,7 @@ void prRhiDestroyShaderVk(PrRhiDevice *device, PrRhiShader *shader, WpAllocator PrRhiPipelineLayout *prRhiCreatePipelineLayoutVk(PrRhiDevice *device, PrRhiPipelineLayoutDesc desc, - WpAllocator *alloc) { + WpAllocator *allocator) { VkDevice vk_device = (VkDevice)device->handle; // Gather descriptor set layouts @@ -1148,7 +1338,7 @@ PrRhiPipelineLayout *prRhiCreatePipelineLayoutVk(PrRhiDevice *device, VkDescriptorSetLayout *vk_layouts = vk_layouts_stack; if (layout_count > 8) { - vk_layouts = wpArrayAllocCapacity(VkDescriptorSetLayout, alloc, layout_count, WP_ARRAY_INIT_NONE); + vk_layouts = wpArrayAllocCapacity(VkDescriptorSetLayout, allocator, layout_count, WP_ARRAY_INIT_NONE); if (!vk_layouts) _abort("alloc failed for VkDescriptorSetLayout array"); } for (u32 i = 0; i < layout_count; ++i) { @@ -1162,7 +1352,7 @@ PrRhiPipelineLayout *prRhiCreatePipelineLayoutVk(PrRhiDevice *device, VkPushConstantRange *pc_ranges = pc_ranges_stack; if (pc_count > 8) { - pc_ranges = wpArrayAllocCapacity(VkPushConstantRange, alloc, pc_count, WP_ARRAY_INIT_NONE); + pc_ranges = wpArrayAllocCapacity(VkPushConstantRange, allocator, pc_count, WP_ARRAY_INIT_NONE); if (!pc_ranges) _abort("alloc failed for VkPushConstantRange array"); } for (u32 i = 0; i < pc_count; ++i) { @@ -1183,23 +1373,23 @@ PrRhiPipelineLayout *prRhiCreatePipelineLayoutVk(PrRhiDevice *device, "vkCreatePipelineLayout"); if (layout_count > 8) { - wpArrayDealloc(VkDescriptorSetLayout, alloc, &vk_layouts); + wpArrayDealloc(VkDescriptorSetLayout, allocator, &vk_layouts); } if (pc_count > 8) { - wpArrayDealloc(VkPushConstantRange, alloc, &pc_ranges); + wpArrayDealloc(VkPushConstantRange, allocator, &pc_ranges); } - PrRhiPipelineLayout *layout = wpMemAllocatorAlloc(alloc, sizeof(PrRhiPipelineLayout)); + PrRhiPipelineLayout *layout = wpMemAllocatorAlloc(allocator, sizeof(PrRhiPipelineLayout)); if (!layout) _abort("alloc failed for PrRhiPipelineLayout"); layout->handle = vk_layout; return layout; } void prRhiDestroyPipelineLayoutVk(PrRhiDevice *device, PrRhiPipelineLayout *layout, - WpAllocator *alloc) { + WpAllocator *allocator) { if (!layout) return; vkDestroyPipelineLayout((VkDevice)device->handle, (VkPipelineLayout)layout->handle, NULL); - wpMemAllocatorFree(alloc, (void**)&layout, sizeof(PrRhiPipelineLayout)); + wpMemAllocatorFree(allocator, (void**)&layout, sizeof(PrRhiPipelineLayout)); } // ============================================================================ @@ -1208,7 +1398,7 @@ void prRhiDestroyPipelineLayoutVk(PrRhiDevice *device, PrRhiPipelineLayout *layo PrRhiPipeline *prRhiCreateGraphicsPipelineVk(PrRhiDevice *device, PrRhiGraphicsPipelineDesc desc, - WpAllocator *alloc) { + WpAllocator *allocator) { VkDevice vk_device = (VkDevice)device->handle; // Shader stages @@ -1365,7 +1555,7 @@ PrRhiPipeline *prRhiCreateGraphicsPipelineVk(PrRhiDevice *device, _checkVk(vkCreateGraphicsPipelines(vk_device, VK_NULL_HANDLE, 1, &pi, NULL, &vk_pipeline), "vkCreateGraphicsPipelines"); - PrRhiPipeline *pipeline = wpMemAllocatorAlloc(alloc, sizeof(PrRhiPipeline)); + PrRhiPipeline *pipeline = wpMemAllocatorAlloc(allocator, sizeof(PrRhiPipeline)); if (!pipeline) _abort("alloc failed for PrRhiPipeline"); pipeline->handle = vk_pipeline; return pipeline; @@ -1373,7 +1563,7 @@ PrRhiPipeline *prRhiCreateGraphicsPipelineVk(PrRhiDevice *device, PrRhiPipeline *prRhiCreateComputePipelineVk(PrRhiDevice *device, PrRhiComputePipelineDesc desc, - WpAllocator *alloc) { + WpAllocator *allocator) { VkComputePipelineCreateInfo pi = {}; pi.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; pi.stage = (VkPipelineShaderStageCreateInfo){ @@ -1388,16 +1578,16 @@ PrRhiPipeline *prRhiCreateComputePipelineVk(PrRhiDevice *device, _checkVk(vkCreateComputePipelines((VkDevice)device->handle, VK_NULL_HANDLE, 1, &pi, NULL, &vk_pipeline), "vkCreateComputePipelines"); - PrRhiPipeline *pipeline = wpMemAllocatorAlloc(alloc, sizeof(PrRhiPipeline)); + PrRhiPipeline *pipeline = wpMemAllocatorAlloc(allocator, sizeof(PrRhiPipeline)); if (!pipeline) _abort("alloc failed for PrRhiPipeline"); pipeline->handle = vk_pipeline; return pipeline; } -void prRhiDestroyPipelineVk(PrRhiDevice *device, PrRhiPipeline *pipeline, WpAllocator *alloc) { +void prRhiDestroyPipelineVk(PrRhiDevice *device, PrRhiPipeline *pipeline, WpAllocator *allocator) { if (!pipeline) return; vkDestroyPipeline((VkDevice)device->handle, (VkPipeline)pipeline->handle, NULL); - wpMemAllocatorFree(alloc, (void**)&pipeline, sizeof(PrRhiPipeline)); + wpMemAllocatorFree(allocator, (void**)&pipeline, sizeof(PrRhiPipeline)); } // ============================================================================ @@ -1406,7 +1596,7 @@ void prRhiDestroyPipelineVk(PrRhiDevice *device, PrRhiPipeline *pipeline, WpAllo PrRhiDescriptorSetLayout *prRhiCreateDescriptorSetLayoutVk(PrRhiDevice *device, PrRhiDescriptorSetLayoutDesc desc, - WpAllocator *alloc) { + WpAllocator *allocator) { VkDevice vk_device = (VkDevice)device->handle; u32 binding_count = (desc.bindings && wpArrayCount(desc.bindings) > 0) @@ -1439,17 +1629,17 @@ PrRhiDescriptorSetLayout *prRhiCreateDescriptorSetLayoutVk(PrRhiDevice *device, _checkVk(vkCreateDescriptorSetLayout(vk_device, &info, NULL, &vk_layout), "vkCreateDescriptorSetLayout"); - PrRhiDescriptorSetLayout *layout = wpMemAllocatorAlloc(alloc, sizeof(PrRhiDescriptorSetLayout)); + PrRhiDescriptorSetLayout *layout = wpMemAllocatorAlloc(allocator, sizeof(PrRhiDescriptorSetLayout)); if (!layout) _abort("alloc failed for PrRhiDescriptorSetLayout"); layout->handle = vk_layout; return layout; } void prRhiDestroyDescriptorSetLayoutVk(PrRhiDevice *device, PrRhiDescriptorSetLayout *layout, - WpAllocator *alloc) { + WpAllocator *allocator) { if (!layout) return; vkDestroyDescriptorSetLayout((VkDevice)device->handle, (VkDescriptorSetLayout)layout->handle, NULL); - wpMemAllocatorFree(alloc, (void**)&layout, sizeof(PrRhiDescriptorSetLayout)); + wpMemAllocatorFree(allocator, (void**)&layout, sizeof(PrRhiDescriptorSetLayout)); } // ============================================================================ @@ -1458,7 +1648,7 @@ void prRhiDestroyDescriptorSetLayoutVk(PrRhiDevice *device, PrRhiDescriptorSetLa PrRhiDescriptorPool *prRhiCreateDescriptorPoolVk(PrRhiDevice *device, PrRhiDescriptorPoolDesc desc, - WpAllocator *alloc) { + WpAllocator *allocator) { VkDevice vk_device = (VkDevice)device->handle; u32 pool_size_count = (desc.pool_sizes && wpArrayCount(desc.pool_sizes) > 0) @@ -1480,17 +1670,17 @@ PrRhiDescriptorPool *prRhiCreateDescriptorPoolVk(PrRhiDevice *device, _checkVk(vkCreateDescriptorPool(vk_device, &info, NULL, &vk_pool), "vkCreateDescriptorPool"); - PrRhiDescriptorPool *pool = wpMemAllocatorAlloc(alloc, sizeof(PrRhiDescriptorPool)); + PrRhiDescriptorPool *pool = wpMemAllocatorAlloc(allocator, sizeof(PrRhiDescriptorPool)); if (!pool) _abort("alloc failed for PrRhiDescriptorPool"); pool->handle = vk_pool; return pool; } void prRhiDestroyDescriptorPoolVk(PrRhiDevice *device, PrRhiDescriptorPool *pool, - WpAllocator *alloc) { + WpAllocator *allocator) { if (!pool) return; vkDestroyDescriptorPool((VkDevice)device->handle, (VkDescriptorPool)pool->handle, NULL); - wpMemAllocatorFree(alloc, (void**)&pool, sizeof(PrRhiDescriptorPool)); + wpMemAllocatorFree(allocator, (void**)&pool, sizeof(PrRhiDescriptorPool)); } // ============================================================================ @@ -1500,7 +1690,7 @@ void prRhiDestroyDescriptorPoolVk(PrRhiDevice *device, PrRhiDescriptorPool *pool PrRhiDescriptorSet *prRhiAllocateDescriptorSetVk(PrRhiDevice *device, PrRhiDescriptorPool *pool, PrRhiDescriptorSetLayout *layout, - u32 variable_count, WpAllocator *alloc) { + u32 variable_count, WpAllocator *allocator) { VkDevice vk_device = (VkDevice)device->handle; VkDescriptorSetVariableDescriptorCountAllocateInfo var_info = {}; @@ -1521,20 +1711,20 @@ PrRhiDescriptorSet *prRhiAllocateDescriptorSetVk(PrRhiDevice *device, _checkVk(vkAllocateDescriptorSets(vk_device, &info, &vk_set), "vkAllocateDescriptorSets"); - PrRhiDescriptorSet *set = wpMemAllocatorAlloc(alloc, sizeof(PrRhiDescriptorSet)); + PrRhiDescriptorSet *set = wpMemAllocatorAlloc(allocator, sizeof(PrRhiDescriptorSet)); if (!set) _abort("alloc failed for PrRhiDescriptorSet"); set->handle = vk_set; return set; } void prRhiFreeDescriptorSetVk(PrRhiDevice *device, PrRhiDescriptorPool *pool, - PrRhiDescriptorSet *set, WpAllocator *alloc) { + PrRhiDescriptorSet *set, WpAllocator *allocator) { if (!set) return; VkDevice vk_device = (VkDevice)device->handle; VkDescriptorSet vk_set = (VkDescriptorSet)set->handle; _checkVk(vkFreeDescriptorSets(vk_device, (VkDescriptorPool)pool->handle, 1, &vk_set), "vkFreeDescriptorSets"); - wpMemAllocatorFree(alloc, (void**)&set, sizeof(PrRhiDescriptorSet)); + wpMemAllocatorFree(allocator, (void**)&set, sizeof(PrRhiDescriptorSet)); } void prRhiUpdateDescriptorSetVk(PrRhiDevice *device, PrRhiWriteDescriptorSetArray writes) { @@ -1600,7 +1790,7 @@ void prRhiUpdateDescriptorSetVk(PrRhiDevice *device, PrRhiWriteDescriptorSetArra // ============================================================================ PrRhiFence *prRhiCreateFenceVk(PrRhiDevice *device, PrRhiFenceDesc desc, - WpAllocator *alloc) { + WpAllocator *allocator) { VkFenceCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; info.flags = desc.signaled ? VK_FENCE_CREATE_SIGNALED_BIT : 0; @@ -1609,16 +1799,16 @@ PrRhiFence *prRhiCreateFenceVk(PrRhiDevice *device, PrRhiFenceDesc desc, _checkVk(vkCreateFence((VkDevice)device->handle, &info, NULL, &vk_fence), "vkCreateFence"); - PrRhiFence *fence = wpMemAllocatorAlloc(alloc, sizeof(PrRhiFence)); + PrRhiFence *fence = wpMemAllocatorAlloc(allocator, sizeof(PrRhiFence)); if (!fence) _abort("alloc failed for PrRhiFence"); fence->handle = vk_fence; return fence; } -void prRhiDestroyFenceVk(PrRhiDevice *device, PrRhiFence *fence, WpAllocator *alloc) { +void prRhiDestroyFenceVk(PrRhiDevice *device, PrRhiFence *fence, WpAllocator *allocator) { if (!fence) return; vkDestroyFence((VkDevice)device->handle, (VkFence)fence->handle, NULL); - wpMemAllocatorFree(alloc, (void**)&fence, sizeof(PrRhiFence)); + wpMemAllocatorFree(allocator, (void**)&fence, sizeof(PrRhiFence)); } void prRhiWaitForFencesVk(PrRhiDevice *device, PrRhiFenceArray fences, u32 count, @@ -1647,7 +1837,7 @@ void prRhiResetFencesVk(PrRhiDevice *device, PrRhiFenceArray fences, u32 count) // Semaphores // ============================================================================ -PrRhiSemaphore *prRhiCreateSemaphoreVk(PrRhiDevice *device, WpAllocator *alloc) { +PrRhiSemaphore *prRhiCreateSemaphoreVk(PrRhiDevice *device, WpAllocator *allocator) { VkSemaphoreCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; @@ -1655,16 +1845,16 @@ PrRhiSemaphore *prRhiCreateSemaphoreVk(PrRhiDevice *device, WpAllocator *alloc) _checkVk(vkCreateSemaphore((VkDevice)device->handle, &info, NULL, &vk_semaphore), "vkCreateSemaphore"); - PrRhiSemaphore *semaphore = wpMemAllocatorAlloc(alloc, sizeof(PrRhiSemaphore)); + PrRhiSemaphore *semaphore = wpMemAllocatorAlloc(allocator, sizeof(PrRhiSemaphore)); if (!semaphore) _abort("alloc failed for PrRhiSemaphore"); semaphore->handle = vk_semaphore; return semaphore; } -void prRhiDestroySemaphoreVk(PrRhiDevice *device, PrRhiSemaphore *semaphore, WpAllocator *alloc) { +void prRhiDestroySemaphoreVk(PrRhiDevice *device, PrRhiSemaphore *semaphore, WpAllocator *allocator) { if (!semaphore) return; vkDestroySemaphore((VkDevice)device->handle, (VkSemaphore)semaphore->handle, NULL); - wpMemAllocatorFree(alloc, (void**)&semaphore, sizeof(PrRhiSemaphore)); + wpMemAllocatorFree(allocator, (void**)&semaphore, sizeof(PrRhiSemaphore)); } // ============================================================================ @@ -1672,7 +1862,7 @@ void prRhiDestroySemaphoreVk(PrRhiDevice *device, PrRhiSemaphore *semaphore, WpA // ============================================================================ PrRhiCommandPool *prRhiCreateCommandPoolVk(PrRhiDevice *device, PrRhiCommandPoolDesc desc, - WpAllocator *alloc) { + WpAllocator *allocator) { VkCommandPoolCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; @@ -1682,20 +1872,20 @@ PrRhiCommandPool *prRhiCreateCommandPoolVk(PrRhiDevice *device, PrRhiCommandPool _checkVk(vkCreateCommandPool((VkDevice)device->handle, &info, NULL, &vk_pool), "vkCreateCommandPool"); - PrRhiCommandPool *pool = wpMemAllocatorAlloc(alloc, sizeof(PrRhiCommandPool)); + PrRhiCommandPool *pool = wpMemAllocatorAlloc(allocator, sizeof(PrRhiCommandPool)); if (!pool) _abort("alloc failed for PrRhiCommandPool"); pool->handle = vk_pool; return pool; } -void prRhiDestroyCommandPoolVk(PrRhiDevice *device, PrRhiCommandPool *pool, WpAllocator *alloc) { +void prRhiDestroyCommandPoolVk(PrRhiDevice *device, PrRhiCommandPool *pool, WpAllocator *allocator) { if (!pool) return; vkDestroyCommandPool((VkDevice)device->handle, (VkCommandPool)pool->handle, NULL); - wpMemAllocatorFree(alloc, (void**)&pool, sizeof(PrRhiCommandPool)); + wpMemAllocatorFree(allocator, (void**)&pool, sizeof(PrRhiCommandPool)); } PrRhiCommandBufferArray prRhiAllocateCommandBuffersVk(PrRhiDevice *device, PrRhiCommandPool *pool, - u32 count, WpAllocator *alloc) { + u32 count, WpAllocator *allocator) { VkCommandBufferAllocateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; info.commandPool = (VkCommandPool)pool->handle; @@ -1705,7 +1895,7 @@ PrRhiCommandBufferArray prRhiAllocateCommandBuffersVk(PrRhiDevice *device, PrRhi VkCommandBuffer vk_cbs[16] = {0}; u32 real_count = count < 16 ? count : 16; - VkCommandBufferArray vk_cb_array = wpArrayAllocCapacity(VkCommandBuffer, alloc, real_count, WP_ARRAY_INIT_NONE); + VkCommandBufferArray vk_cb_array = wpArrayAllocCapacity(VkCommandBuffer, allocator, real_count, WP_ARRAY_INIT_NONE); if (!vk_cb_array) _abort("alloc failed for VkCommandBuffer array"); _checkVk(vkAllocateCommandBuffers((VkDevice)device->handle, &info, vk_cbs), @@ -1715,17 +1905,17 @@ PrRhiCommandBufferArray prRhiAllocateCommandBuffersVk(PrRhiDevice *device, PrRhi wpArrayAppendCapped(VkCommandBuffer, vk_cb_array, &vk_cbs[i]); } - PrRhiCommandBufferArray cbs = wpArrayAllocCapacity(PrRhiCommandBuffer *, alloc, real_count, WP_ARRAY_INIT_NONE); + PrRhiCommandBufferArray cbs = wpArrayAllocCapacity(PrRhiCommandBuffer *, allocator, real_count, WP_ARRAY_INIT_NONE); if (!cbs) _abort("alloc failed for PrRhiCommandBuffer array"); for (u32 i = 0; i < real_count; ++i) { - PrRhiCommandBuffer *cb = (PrRhiCommandBuffer *)wpMemAllocatorAlloc(alloc, sizeof(PrRhiCommandBuffer)); + PrRhiCommandBuffer *cb = (PrRhiCommandBuffer *)wpMemAllocatorAlloc(allocator, sizeof(PrRhiCommandBuffer)); if (!cb) _abort("alloc failed for PrRhiCommandBuffer"); cb->handle = vk_cb_array[i]; wpArrayAppendCapped(PrRhiCommandBuffer *, cbs, &cb); } - wpArrayDealloc(VkCommandBuffer, alloc, &vk_cb_array); + wpArrayDealloc(VkCommandBuffer, allocator, &vk_cb_array); return cbs; } @@ -1804,10 +1994,10 @@ void prRhiCmdPipelineBarrierVk(PrRhiCommandBuffer *cb, } vk_img_barriers[i].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2; - vk_img_barriers[i].srcStageMask = (VkPipelineStageFlags2)src->src_stage_mask; - vk_img_barriers[i].srcAccessMask = (VkAccessFlags2)src->src_access_mask; - vk_img_barriers[i].dstStageMask = (VkPipelineStageFlags2)src->dst_stage_mask; - vk_img_barriers[i].dstAccessMask = (VkAccessFlags2)src->dst_access_mask; + vk_img_barriers[i].srcStageMask = _toVkPipelineStage2(src->src_stage_mask); + vk_img_barriers[i].srcAccessMask = _toVkAccess2(src->src_access_mask); + vk_img_barriers[i].dstStageMask = _toVkPipelineStage2(src->dst_stage_mask); + vk_img_barriers[i].dstAccessMask = _toVkAccess2(src->dst_access_mask); vk_img_barriers[i].oldLayout = old_layout; vk_img_barriers[i].newLayout = new_layout; vk_img_barriers[i].image = src->texture ? (VkImage)src->texture->image : VK_NULL_HANDLE; @@ -1821,10 +2011,10 @@ void prRhiCmdPipelineBarrierVk(PrRhiCommandBuffer *cb, PrRhiBufferMemoryBarrier *src = &buffer_barriers[i]; vk_buf_barriers[i].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2; - vk_buf_barriers[i].srcStageMask = (VkPipelineStageFlags2)src->src_stage_mask; - vk_buf_barriers[i].srcAccessMask = (VkAccessFlags2)src->src_access_mask; - vk_buf_barriers[i].dstStageMask = (VkPipelineStageFlags2)src->dst_stage_mask; - vk_buf_barriers[i].dstAccessMask = (VkAccessFlags2)src->dst_access_mask; + vk_buf_barriers[i].srcStageMask = _toVkPipelineStage2(src->src_stage_mask); + vk_buf_barriers[i].srcAccessMask = _toVkAccess2(src->src_access_mask); + vk_buf_barriers[i].dstStageMask = _toVkPipelineStage2(src->dst_stage_mask); + vk_buf_barriers[i].dstAccessMask = _toVkAccess2(src->dst_access_mask); vk_buf_barriers[i].buffer = src->buffer ? (VkBuffer)src->buffer->handle : VK_NULL_HANDLE; vk_buf_barriers[i].offset = src->offset; vk_buf_barriers[i].size = src->size; diff --git a/src/prism/rhi/vulkan/pr_rhi_vk.h b/src/prism/rhi/vulkan/pr_rhi_vk.h index da45f09..2b45680 100644 --- a/src/prism/rhi/vulkan/pr_rhi_vk.h +++ b/src/prism/rhi/vulkan/pr_rhi_vk.h @@ -8,229 +8,237 @@ #define PR_RHI_VK_H #include "../pr_rhi_types.h" +#include +#include // ============================================================================ // Opaque struct definitions — visible only to the backend implementation. // ============================================================================ +#define PR_RHI_VK_PHYSICAL_DEVICE_NAME_LENGTH 256 +#define PR_RHI_VK_PHYSICAL_DRIVER_INFO_LENGTH 256 + struct PrRhiInstance { - void *handle; // VkInstance - void *debug_messenger; // VkDebugUtilsMessengerEXT + VkInstance handle; // VkInstance + VkDebugUtilsMessengerEXT *debug_messenger; // VkDebugUtilsMessengerEXT }; struct PrRhiPhysicalDevice { - void *handle; // VkPhysicalDevice + VkPhysicalDevice handle; PrRhiInstance *instance; - c8 device_name[256]; - c8 driver_info[256]; + c8 device_name[PR_RHI_VK_PHYSICAL_DEVICE_NAME_LENGTH]; + c8 driver_info[PR_RHI_VK_PHYSICAL_DRIVER_INFO_LENGTH]; }; struct PrRhiDevice { - void *handle; // VkDevice - void *queue; // VkQueue - u32 queue_family_index; - u32 present_mode; // VkPresentModeKHR - void *physical_device; // VkPhysicalDevice - void *allocator; // VmaAllocator + VkDevice handle; + VkQueue queue; + u32 queue_family_index; + VkPresentModeKHR present_mode; + VkPhysicalDevice physical_device; + VmaAllocator allocator; }; struct PrRhiSurface { - void *handle; // VkSurfaceKHR + VkSurfaceKHR handle; }; struct PrRhiSwapchain { - PrRhiDevice *device; - void *handle; // VkSwapchainKHR - void *surface; // PrRhiSurface * - u32 image_count; - PrRhiTexture **images; - PrRhiTexture *depth; - u32 format; // VkFormat (color) - u32 depth_format; // VkFormat (depth) - u32 width; - u32 height; - u32 current_image_index; + PrRhiDevice *device; + VkSwapchainKHR handle; + PrRhiSurface *surface; + u32 image_count; + PrRhiTexture **images; + PrRhiTexture *depth; + VkFormat format; + VkFormat depth_format; + u32 width; + u32 height; + u32 current_image_index; }; struct PrRhiBuffer { - void *handle; // VkBuffer - void *allocation; // VmaAllocation - u64 device_address; - u64 size; - void *mapped_data; + VkBuffer handle; + VmaAllocation allocation; + u64 device_address; + u64 size; + void *mapped_data; }; struct PrRhiTexture { - void *image; // VkImage - void *view; // VkImageView - void *allocation; // VmaAllocation - u32 width; - u32 height; - u32 format; // VkFormat + VkImage image; + VkImageView view; + VmaAllocation allocation; + u32 width; + u32 height; + VkFormat format; }; struct PrRhiSampler { - void *handle; // VkSampler + VkSampler handle; }; struct PrRhiShader { - void *handle; // VkShaderModule + VkShaderModule handle; }; struct PrRhiPipelineLayout { - void *handle; // VkPipelineLayout + VkPipelineLayout handle; }; struct PrRhiPipeline { - void *handle; // VkPipeline + VkPipeline handle; }; struct PrRhiDescriptorSetLayout { - void *handle; // VkDescriptorSetLayout + VkDescriptorSetLayout handle; }; struct PrRhiDescriptorPool { - void *handle; // VkDescriptorPool + VkDescriptorPool handle; }; struct PrRhiDescriptorSet { - void *handle; // VkDescriptorSet + VkDescriptorSet handle; }; struct PrRhiCommandPool { - void *handle; // VkCommandPool + VkCommandPool handle; }; struct PrRhiCommandBuffer { - void *handle; // VkCommandBuffer + VkCommandBuffer handle; }; struct PrRhiFence { - void *handle; // VkFence + VkFence handle; }; struct PrRhiSemaphore { - void *handle; // VkSemaphore + VkSemaphore handle; }; // ============================================================================ // Function declarations // ============================================================================ -PrRhiInstance *prRhiCreateInstanceVk(PrRhiInstanceDesc desc, WpAllocator *alloc); -void prRhiDestroyInstanceVk(PrRhiInstance *inst, WpAllocator *alloc); -void *prRhiGetNativeInstanceHandleVk(PrRhiInstance *inst); +PrRhiInstance *prRhiCreateInstanceVk(PrRhiInstanceDesc desc, WpAllocator *allocator); +void prRhiDestroyInstanceVk(PrRhiInstance *inst, WpAllocator *allocator); -PrRhiPhysicalDeviceArray prRhiGetPhysicalDevicesVk(PrRhiInstance *inst, const WpAllocator *scratch); +PrRhiPhysicalDeviceArray prRhiGetPhysicalDevicesVk(PrRhiInstance *inst, const WpAllocator *allocator); void prRhiGetPhysicalDeviceNameVk(PrRhiPhysicalDevice *pdev, WpStr8 *out); void prRhiGetPhysicalDeviceDriverInfoVk(PrRhiPhysicalDevice *pdev, WpStr8 *out); void prRhiGetPhysicalDevicePropertiesVk(PrRhiPhysicalDevice *pdev, PrRhiPhysicalDeviceProperties *out); -PrRhiSurface *prRhiCreateSurfaceVk(PrRhiInstance *inst, void *window_handle, WpAllocator *alloc); -void prRhiDestroySurfaceVk(PrRhiInstance *inst, PrRhiSurface *surface, WpAllocator *alloc); +PrRhiSurface *prRhiCreateSurfaceFromWindowVk(PrRhiInstance *inst, void *window_handle, + WpAllocator *allocator); +void prRhiDestroySurfaceVk(PrRhiInstance *inst, PrRhiSurface *surface, WpAllocator *allocator); PrRhiSurfaceCapabilities prRhiGetSurfaceCapabilitiesVk(PrRhiPhysicalDevice *pdev, PrRhiSurface *surface); PrRhiDevice *prRhiCreateDeviceVk(PrRhiPhysicalDevice *pdev, PrRhiSurface *surface, - PrRhiDeviceDesc desc, WpAllocator *alloc); -void prRhiDestroyDeviceVk(PrRhiDevice *device, WpAllocator *alloc); + PrRhiDeviceDesc desc, WpAllocator *allocator); +void prRhiDestroyDeviceVk(PrRhiDevice *device, WpAllocator *allocator); void prRhiDeviceWaitIdleVk(PrRhiDevice *device); u32 prRhiGetQueueFamilyIndexVk(PrRhiDevice *device); PrRhiSwapchain *prRhiCreateSwapchainVk(PrRhiDevice *device, PrRhiSwapchainDesc desc, - WpAllocator *alloc); + WpAllocator *allocator); void prRhiDestroySwapchainVk(PrRhiDevice *device, PrRhiSwapchain *swapchain, - WpAllocator *alloc); + WpAllocator *allocator); PrRhiSwapchainResult prRhiAcquireNextImageVk(PrRhiDevice *device, PrRhiSwapchain *swapchain, PrRhiSemaphore *signal_semaphore, u32 *out_image_index); PrRhiSwapchainResult prRhiPresentVk(PrRhiDevice *device, PrRhiSwapchain *swapchain, PrRhiSemaphore *wait_semaphore); void prRhiRecreateSwapchainVk(PrRhiDevice *device, PrRhiSwapchain **swapchain, - u32 width, u32 height, WpAllocator *alloc); + u32 width, u32 height, WpAllocator *allocator); PrRhiTexture *prRhiGetSwapchainTextureVk(PrRhiSwapchain *swapchain, u32 image_index); PrRhiTexture *prRhiGetSwapchainDepthTextureVk(PrRhiSwapchain *swapchain); PrRhiFormat prRhiGetSwapchainFormatVk(PrRhiSwapchain *swapchain); PrRhiBuffer *prRhiCreateBufferVk(PrRhiDevice *device, PrRhiBufferDesc desc, - WpAllocator *alloc); -void prRhiDestroyBufferVk(PrRhiDevice *device, PrRhiBuffer *buffer, WpAllocator *alloc); + WpAllocator *allocator); +void prRhiDestroyBufferVk(PrRhiDevice *device, PrRhiBuffer *buffer, WpAllocator *allocator); void *prRhiBufferMapVk(PrRhiDevice *device, PrRhiBuffer *buffer); void prRhiBufferUnmapVk(PrRhiDevice *device, PrRhiBuffer *buffer); PrRhiDeviceAddress prRhiGetBufferDeviceAddressVk(PrRhiDevice *device, PrRhiBuffer *buffer); PrRhiTexture *prRhiCreateTextureVk(PrRhiDevice *device, PrRhiTextureDesc desc, - WpAllocator *alloc); + WpAllocator *allocator); +PrRhiTexture *prRhiCreateTextureFromKtxVk(PrRhiDevice *device, const char *path, + PrRhiCommandPool *pool, PrRhiCommandBuffer *cb, + WpAllocator *allocator); void prRhiDestroyTextureVk(PrRhiDevice *device, PrRhiTexture *texture, - WpAllocator *alloc); + WpAllocator *allocator); PrRhiSampler *prRhiCreateSamplerVk(PrRhiDevice *device, PrRhiSamplerDesc desc, - WpAllocator *alloc); + WpAllocator *allocator); void prRhiDestroySamplerVk(PrRhiDevice *device, PrRhiSampler *sampler, - WpAllocator *alloc); + WpAllocator *allocator); PrRhiShader *prRhiCreateShaderVk(PrRhiDevice *device, PrRhiShaderDesc desc, - WpAllocator *alloc); -void prRhiDestroyShaderVk(PrRhiDevice *device, PrRhiShader *shader, WpAllocator *alloc); + WpAllocator *allocator); +void prRhiDestroyShaderVk(PrRhiDevice *device, PrRhiShader *shader, WpAllocator *allocator); PrRhiPipelineLayout *prRhiCreatePipelineLayoutVk(PrRhiDevice *device, PrRhiPipelineLayoutDesc desc, - WpAllocator *alloc); + WpAllocator *allocator); void prRhiDestroyPipelineLayoutVk(PrRhiDevice *device, PrRhiPipelineLayout *layout, - WpAllocator *alloc); + WpAllocator *allocator); PrRhiPipeline *prRhiCreateGraphicsPipelineVk(PrRhiDevice *device, PrRhiGraphicsPipelineDesc desc, - WpAllocator *alloc); + WpAllocator *allocator); PrRhiPipeline *prRhiCreateComputePipelineVk(PrRhiDevice *device, PrRhiComputePipelineDesc desc, - WpAllocator *alloc); + WpAllocator *allocator); void prRhiDestroyPipelineVk(PrRhiDevice *device, PrRhiPipeline *pipeline, - WpAllocator *alloc); + WpAllocator *allocator); PrRhiDescriptorSetLayout *prRhiCreateDescriptorSetLayoutVk(PrRhiDevice *device, PrRhiDescriptorSetLayoutDesc desc, - WpAllocator *alloc); + WpAllocator *allocator); void prRhiDestroyDescriptorSetLayoutVk(PrRhiDevice *device, PrRhiDescriptorSetLayout *layout, - WpAllocator *alloc); + WpAllocator *allocator); PrRhiDescriptorPool *prRhiCreateDescriptorPoolVk(PrRhiDevice *device, PrRhiDescriptorPoolDesc desc, - WpAllocator *alloc); + WpAllocator *allocator); void prRhiDestroyDescriptorPoolVk(PrRhiDevice *device, PrRhiDescriptorPool *pool, - WpAllocator *alloc); + WpAllocator *allocator); PrRhiDescriptorSet *prRhiAllocateDescriptorSetVk(PrRhiDevice *device, PrRhiDescriptorPool *pool, PrRhiDescriptorSetLayout *layout, - u32 variable_count, WpAllocator *alloc); + u32 variable_count, WpAllocator *allocator); void prRhiFreeDescriptorSetVk(PrRhiDevice *device, PrRhiDescriptorPool *pool, - PrRhiDescriptorSet *set, WpAllocator *alloc); + PrRhiDescriptorSet *set, WpAllocator *allocator); void prRhiUpdateDescriptorSetVk(PrRhiDevice *device, PrRhiWriteDescriptorSetArray writes); PrRhiFence *prRhiCreateFenceVk(PrRhiDevice *device, PrRhiFenceDesc desc, - WpAllocator *alloc); -void prRhiDestroyFenceVk(PrRhiDevice *device, PrRhiFence *fence, WpAllocator *alloc); + WpAllocator *allocator); +void prRhiDestroyFenceVk(PrRhiDevice *device, PrRhiFence *fence, WpAllocator *allocator); void prRhiWaitForFencesVk(PrRhiDevice *device, PrRhiFenceArray fences, u32 count, b8 wait_all, u64 timeout_ns); void prRhiResetFencesVk(PrRhiDevice *device, PrRhiFenceArray fences, u32 count); -PrRhiSemaphore *prRhiCreateSemaphoreVk(PrRhiDevice *device, WpAllocator *alloc); +PrRhiSemaphore *prRhiCreateSemaphoreVk(PrRhiDevice *device, WpAllocator *allocator); void prRhiDestroySemaphoreVk(PrRhiDevice *device, PrRhiSemaphore *semaphore, - WpAllocator *alloc); + WpAllocator *allocator); PrRhiCommandPool *prRhiCreateCommandPoolVk(PrRhiDevice *device, PrRhiCommandPoolDesc desc, - WpAllocator *alloc); + WpAllocator *allocator); void prRhiDestroyCommandPoolVk(PrRhiDevice *device, PrRhiCommandPool *pool, - WpAllocator *alloc); + WpAllocator *allocator); PrRhiCommandBufferArray prRhiAllocateCommandBuffersVk(PrRhiDevice *device, PrRhiCommandPool *pool, - u32 count, WpAllocator *alloc); + u32 count, WpAllocator *allocator); void prRhiFreeCommandBuffersVk(PrRhiDevice *device, PrRhiCommandPool *pool, u32 count, PrRhiCommandBufferArray buffers); diff --git a/src/prism/rhi/vulkan/pr_rhi_vk_aliases.h b/src/prism/rhi/vulkan/pr_rhi_vk_aliases.h index 88dc04b..51f5f81 100644 --- a/src/prism/rhi/vulkan/pr_rhi_vk_aliases.h +++ b/src/prism/rhi/vulkan/pr_rhi_vk_aliases.h @@ -7,12 +7,11 @@ #define prRhiCreateInstance prRhiCreateInstanceVk #define prRhiDestroyInstance prRhiDestroyInstanceVk -#define prRhiGetNativeInstanceHandle prRhiGetNativeInstanceHandleVk #define prRhiGetPhysicalDevices prRhiGetPhysicalDevicesVk #define prRhiGetPhysicalDeviceName prRhiGetPhysicalDeviceNameVk #define prRhiGetPhysicalDeviceDriverInfo prRhiGetPhysicalDeviceDriverInfoVk #define prRhiGetPhysicalDeviceProperties prRhiGetPhysicalDevicePropertiesVk -#define prRhiCreateSurface prRhiCreateSurfaceVk +#define prRhiCreateSurfaceFromWindow prRhiCreateSurfaceFromWindowVk #define prRhiDestroySurface prRhiDestroySurfaceVk #define prRhiGetSurfaceCapabilities prRhiGetSurfaceCapabilitiesVk #define prRhiCreateDevice prRhiCreateDeviceVk @@ -33,6 +32,7 @@ #define prRhiBufferUnmap prRhiBufferUnmapVk #define prRhiGetBufferDeviceAddress prRhiGetBufferDeviceAddressVk #define prRhiCreateTexture prRhiCreateTextureVk +#define prRhiCreateTextureFromKtx prRhiCreateTextureFromKtxVk #define prRhiDestroyTexture prRhiDestroyTextureVk #define prRhiCreateSampler prRhiCreateSamplerVk #define prRhiDestroySampler prRhiDestroySamplerVk