Fix leaky abstractions

This commit is contained in:
2026-07-11 01:43:34 +01:00
parent 7bd1d9f701
commit 1c7a7f6c46
8 changed files with 543 additions and 425 deletions
+1
View File
@@ -2,6 +2,7 @@ build
compile_commands.json
.vscode
*.dSYM
vendor/
scratchpad/**
!scratchpad/**/
!scratchpad/**/*.h
+20 -4
View File
@@ -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 \
+27 -161
View File
@@ -6,9 +6,6 @@
#define PR_RHI_VULKAN
#include "prism/rhi/pr_rhi.h"
#include <vulkan/vulkan_core.h>
#include <ktx.h>
#include <ktxvulkan.h>
#include <SDL3/SDL_timer.h>
#include <glm/ext/matrix_clip_space.hpp>
#include <glm/glm.hpp>
@@ -19,7 +16,6 @@
#include <SDL3/SDL_init.h>
#include <SDL3/SDL_keycode.h>
#include <SDL3/SDL_video.h>
#include <SDL3/SDL_vulkan.h>
#include <slang/slang.h>
#include <slang/slang-com-ptr.h>
#include <tiny_obj_loader.h>
@@ -27,26 +23,6 @@
#include <vector>
#include <cstdint>
// ============================================================================
// 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::IGlobalSession> 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, &copy);
}
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);
+40 -37
View File
@@ -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);
+52 -18
View File
@@ -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;
+311 -121
View File
@@ -8,6 +8,9 @@
#include "profiles/vulkan_profiles.h"
#include <volk/volk.h>
#include <vk_mem_alloc.h>
#include <SDL3/SDL_vulkan.h>
#include <ktx.h>
#include <ktxvulkan.h>
#include <string.h>
// ============================================================================
@@ -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;
+90 -82
View File
@@ -8,229 +8,237 @@
#define PR_RHI_VK_H
#include "../pr_rhi_types.h"
#include <volk/volk.h>
#include <vk_mem_alloc.h>
// ============================================================================
// 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);
+2 -2
View File
@@ -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