diff --git a/.opencode/skills/prism-rhi/SKILL.md b/.opencode/skills/prism-rhi/SKILL.md index 173854b..b1949b3 100644 --- a/.opencode/skills/prism-rhi/SKILL.md +++ b/.opencode/skills/prism-rhi/SKILL.md @@ -16,6 +16,21 @@ Use this when working on any file in `src/prism/rhi/`, or when creating a new ba ## Conventions +### Global context + +RHI functions do **not** take allocator parameters. A global `PrRhiContext` provides two allocators: +- `allocator` — for user-facing objects (buffers, textures, pipelines, etc.) +- `tmp` — for short-lived internal temporaries + +```c +extern PrRhiContext _G_RHI_CONTEXT; + +void prRhiInit(void); // sets up both allocators +void prRhiDestroy(void); // tears down context +``` + +All RHI functions access `_G_RHI_CONTEXT` directly. Do not pass allocators to RHI API calls. + ### Backend dispatch Backend selection is compile-time via `-D PR_RHI_VULKAN` / `-D PR_RHI_D3D12` / `-D PR_RHI_METAL`. The umbrella header `pr_rhi.h` includes the appropriate alias file: @@ -49,22 +64,95 @@ All descriptor structs are passed **by value**, not `const *`: ```c // correct -PrRhiDevice *prRhiCreateDevice(PrRhiPhysicalDevice *pdev, PrRhiSurface *surface, - PrRhiDeviceDesc desc, WpAllocator *alloc); +PrRhiDevice *prRhiCreateDevice(PrRhiPhysicalDevice *pdev, PrRhiSurface *surface, PrRhiDeviceDesc desc); // wrong -PrRhiDevice *prRhiCreateDevice(PrRhiPhysicalDevice *pdev, PrRhiSurface *surface, - const PrRhiDeviceDesc *desc, WpAllocator *alloc); +PrRhiDevice *prRhiCreateDevice(PrRhiPhysicalDevice *pdev, PrRhiSurface *surface, const PrRhiDeviceDesc *desc); ``` +### Frame-by-frame command batching + +Commands that run every frame must avoid arena allocation. Use stack arrays with a while-loop to batch operations: + +```c +// correct — stack array, batched submission +void prRhiCmdBindDescriptorSetsVk(PrRhiCommandBuffer *cb, PrRhiPipelineBindPoint bind_point, + PrRhiPipelineLayout *layout, u32 first_set, + PrRhiDescriptorSetArray sets) { + u32 set_count = sets ? (u32)wpArrayCount(sets) : 0; + while (set_count > 0) { + VkDescriptorSetArray vk_sets = wpArrayWithCapacity(VkDescriptorSet, 16, WP_ARRAY_INIT_FILLED); + u32 total_capacity = (u32)wpArrayCapacity(vk_sets); + u32 real_count = set_count < total_capacity ? set_count : total_capacity; + for (u32 i = 0; i < real_count; ++i) { + vk_sets[i] = sets[i]->handle; + } + vkCmdBindDescriptorSets(cb->handle, vk_bp, vk_layout, first_set, real_count, vk_sets, 0, NULL); + set_count -= real_count; + first_set += real_count; + } +} + +// wrong — allocates from arena on every call +void prRhiCmdBindDescriptorSetsBad(PrRhiCommandBuffer *cb, ...) { + VkDescriptorSetArray vk_sets = wpArrayAllocCapacity(VkDescriptorSet, &_G_RHI_CONTEXT.allocator, count, ...); + // ... this leaks every frame +} +``` + +Apply this pattern to: `prRhiCmdBindDescriptorSets`, `prRhiCmdBindVertexBuffers`, `prRhiCmdCopyBufferToImage`, and any other command that processes user-provided arrays. + +### Opaque struct handles — no casts + +Handle types in opaque structs are already the correct Vulkan type. Do not cast: + +```c +// correct +vk_device = device->handle; +vk_buffer = buffer->handle; + +// wrong +vk_device = (VkDevice)device->handle; +vk_buffer = (VkBuffer)buffer->handle; +``` + +### Vulkan struct initialisation — designated initializers + +Always use C99 designated initializers for Vulkan info structs: + +```c +// correct +VkBufferCreateInfo buf_info = { + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .size = desc.size, + .usage = _toVkBufferUsage(desc.usage), +}; + +// wrong +VkBufferCreateInfo buf_info = {}; +buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; +buf_info.size = desc.size; +buf_info.usage = _toVkBufferUsage(desc.usage); +``` + +### API patterns + +- **`prRhiCreateCommandPool`**: Takes only `PrRhiDevice *device` (uses `device->queue_family_index` internally) +- **`prRhiFreeCommandBuffers`**: Takes `PrRhiCommandBufferArray buffers` (count derived from `wpArrayCount`) +- **`prRhiAllocateDescriptorSet`**: Takes `WpU32Array variable_descriptor_counts` for variable descriptor support +- **`prRhiCmdBindVertexBuffers`**: Takes `WpU64Array offsets` (count matched to buffers internally) +- **Shader entry points**: Configurable via `vertex_shader_entry_point` / `fragment_shader_entry_point` in pipeline desc (not hardcoded to "main") + ### File layout ``` src/prism/rhi/ ├── pr_rhi.h ← umbrella header (API declarations + backend dispatch) +├── pr_rhi.c ← global context definition (prRhiInit, prRhiDestroy) ├── pr_rhi_types.h ← shared types (enums, element types, array aliases, desc structs, opaque handles) ├── vulkan/ │ ├── pr_rhi_vk.h ← Vulkan backend header (opaque struct defs + Vk-suffixed decls) +│ ├── pr_rhi_vk.c ← Vulkan backend implementation │ ├── pr_rhi_vk_aliases.h ← #define alias mapping │ └── profiles/ ← generated Vulkan Profiles library ├── d3d12/ diff --git a/AGENTS.md b/AGENTS.md index 39e457a..c1645ae 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -36,6 +36,16 @@ All code follows the patterns established in `src/wapp/`. The project prefix is - **Tabs for indentation**, 8-column tab width. - **Braces** on the same line as control statements (Attach style). +- **Braces on single-line if statements**: Always use braces, even for single-line bodies: + ```c + // correct + if (!buffer) { return; } + if (!texture) { _abort("alloc failed"); } + + // wrong + if (!buffer) return; + if (!texture) _abort("alloc failed"); + ``` - **Pointers**: `*` against the name, not the type (`PrRhiBuffer *buf`, not `PrRhiBuffer* buf`). - **Line width**: 120 columns. - **Continuation lines** align to the opening parenthesis. @@ -117,6 +127,24 @@ prefer SoA layouts, batch processing, and minimise pointer chasing. Keep the DAG in contiguous arrays (e.g. adjacency lists packed in flat buffers) rather than individually allocated linked structures. +### Frame-by-frame command batching + +Commands that execute every frame must avoid arena allocation. Use stack +arrays with a while-loop to batch operations in fixed-size chunks: + +```c +while (count > 0) { + VkTypeArray batch = wpArrayWithCapacity(VkType, 16, WP_ARRAY_INIT_FILLED); + u32 batch_size = count < wpArrayCapacity(batch) ? count : (u32)wpArrayCapacity(batch); + // ... process batch ... + vkCmd*(cb->handle, ...); + count -= batch_size; + first += batch_size; +} +``` + +This avoids per-frame arena churn while handling arbitrarily large inputs. + ### Graph / adjacency lists Adjacency list nodes must be **separately allocated from the vertex array**. diff --git a/justfile b/justfile index b897139..f1d2988 100644 --- a/justfile +++ b/justfile @@ -43,7 +43,7 @@ build: vendor bear -a -- {{CC}} -g -c {{VK_FLAGS}} src/prism/rhi/pr_rhi.c -o {{BUILDDIR}}/pr_rhi.o bear -a -- {{CC}} -g -c {{VK_FLAGS}} src/prism/rhi/vulkan/pr_rhi_vk.c -o {{BUILDDIR}}/pr_rhi_vk.o bear -a -- {{CC}} -g -c src/wapp/wapp.c -o {{BUILDDIR}}/wapp.o - bear -a -- {{CXX}} -g -c -Wno-nullability-completeness -DVK_NO_PROTOTYPES \ + bear -a -- {{CXX}} -g -c {{VK_FLAGS}} -Wno-nullability-completeness -DVK_NO_PROTOTYPES \ {{APP_INC}} \ src/main.cpp \ -o {{BUILDDIR}}/main.o @@ -55,6 +55,9 @@ build: vendor -o {{BUILDDIR}}/prism @echo "--- build done: {{BUILDDIR}}/prism ---" +run: + ./{{BUILDDIR}}/prism + # Clean clean: rm -rf {{BUILDDIR}} diff --git a/src/main.cpp b/src/main.cpp index 3628152..5c3d55e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,8 +3,7 @@ // Prism port of how-to-vulkan's main.cpp — uses the RHI API instead of // direct Vulkan calls. -#define PR_RHI_VULKAN - +#include "prism/rhi/pr_rhi_types.h" #include "prism/rhi/pr_rhi.h" #include #include @@ -95,6 +94,8 @@ struct AppState { PrRhiSurface *surface; PrRhiSwapchain *swapchain; + PrRhiFormat swapchain_format; + PrRhiBuffer *vert_index_buf; u64 vertex_buf_size; u64 index_count; @@ -136,9 +137,10 @@ struct AppState { int main() { AppState app = {}; WpAllocator arena = wpMemArenaAllocatorInitZero(MiB(128)); - prRhiInit(); // {{{ Initialisation + prRhiInit(); + check(SDL_Init(SDL_INIT_VIDEO), EXIT_CODE_SDL_INIT_FAILED); f32 display_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay()); @@ -149,8 +151,7 @@ int main() { // }}} // {{{ Instance creation - PrRhiInstanceDesc inst_desc = {}; - app.inst = prRhiCreateInstance(inst_desc); + app.inst = prRhiCreateInstance(PrRhiInstanceDesc{}); // }}} // {{{ Physical device selection @@ -159,8 +160,7 @@ int main() { i32 selected = -1; for (u32 i = 0; i < wpArrayCount(pdevs); ++i) { - PrRhiPhysicalDeviceProperties props; - prRhiGetPhysicalDeviceProperties(pdevs[i], &props); + PrRhiPhysicalDeviceProperties props = prRhiGetPhysicalDeviceProperties(pdevs[i]); switch (props.device_type) { case PR_RHI_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: selected = (i32)i; @@ -176,7 +176,8 @@ int main() { app.pdev = pdevs[selected]; // Print device info - WpStr8 dev_name, driver_info; + WpStr8 dev_name = wpStr8Buf(512); + WpStr8 driver_info = wpStr8Buf(512); prRhiGetPhysicalDeviceName(app.pdev, &dev_name); prRhiGetPhysicalDeviceDriverInfo(app.pdev, &driver_info); std::cout << "Selected GPU: " << std::string_view((const char *)dev_name.buf, dev_name.size) << '\n' @@ -186,26 +187,26 @@ int main() { // {{{ Surface creation check(SDL_GetWindowSize(app.window, &app.window_size.x, &app.window_size.y), EXIT_CODE_GET_WINDOW_SIZE_FAILED); - app.surface = prRhiCreateSurfaceFromWindow(app.inst, (void *)app.window); + app.surface = prRhiCreateSurfaceFromWindow(app.inst, app.window); // }}} // {{{ Device creation PrRhiDeviceDesc dev_desc = {}; - dev_desc.present_mode = PR_RHI_PRESENT_MODE_FIFO; + dev_desc.present_mode = PR_RHI_PRESENT_MODE_FIFO; + app.device = prRhiCreateDevice(app.pdev, app.surface, dev_desc); - u32 qfi = prRhiGetQueueFamilyIndex(app.device); // }}} // {{{ Swapchain creation PrRhiSwapchainDesc swap_desc = {}; - swap_desc.surface = app.surface; - swap_desc.width = (u32)app.window_size.x; - swap_desc.height = (u32)app.window_size.y; - swap_desc.has_depth = true; - swap_desc.depth_format = PR_RHI_FORMAT_D24_UNORM_S8_UINT; - app.swapchain = prRhiCreateSwapchain(app.device, swap_desc); + swap_desc.surface = app.surface; + swap_desc.width = (u32)app.window_size.x; + swap_desc.height = (u32)app.window_size.y; + swap_desc.has_depth = true; + swap_desc.depth_format = PR_RHI_FORMAT_D24_UNORM_S8_UINT; - PrRhiFormat swapchain_format = prRhiGetSwapchainFormat(app.swapchain); + app.swapchain = prRhiCreateSwapchain(app.device, swap_desc); + app.swapchain_format = prRhiGetSwapchainFormat(app.swapchain); // }}} // {{{ Vertex/Index buffers @@ -227,19 +228,19 @@ int main() { -attrib.vertices[idx.vertex_index * 3 + 1], attrib.vertices[idx.vertex_index * 3 + 2] }; - v.normal = { + v.normal = { attrib.normals[idx.normal_index * 3], -attrib.normals[idx.normal_index * 3 + 1], attrib.normals[idx.normal_index * 3 + 2] }; - v.uv = { + v.uv = { attrib.texcoords[idx.texcoord_index * 2], 1.0f - attrib.texcoords[idx.texcoord_index * 2 + 1] }; u16 index = (u16)wpArrayCount(indices); - vertices = wpArrayAppendAlloc(Vertex, &arena, vertices, &v, WP_ARRAY_INIT_NONE); - indices = wpArrayAppendAlloc(u16, &arena, indices, &index, WP_ARRAY_INIT_NONE); + vertices = wpArrayAppendAlloc(Vertex, &arena, vertices, &v, WP_ARRAY_INIT_NONE); + indices = wpArrayAppendAlloc(u16, &arena, indices, &index, WP_ARRAY_INIT_NONE); } app.vertex_buf_size = sizeof(Vertex) * wpArrayCount(vertices); @@ -249,9 +250,10 @@ int main() { // {{{ Create GPU buffer PrRhiBufferDesc vert_desc = {}; - vert_desc.size = app.vertex_buf_size + index_buf_size; - vert_desc.usage = (PrRhiBufferUsage)(PR_RHI_BUFFER_USAGE_VERTEX | PR_RHI_BUFFER_USAGE_INDEX); - vert_desc.memory = PR_RHI_MEMORY_CPU_TO_GPU; + vert_desc.size = app.vertex_buf_size + index_buf_size; + vert_desc.usage = (PrRhiBufferUsage)(PR_RHI_BUFFER_USAGE_VERTEX | PR_RHI_BUFFER_USAGE_INDEX); + vert_desc.memory = PR_RHI_MEMORY_CPU_TO_GPU; + app.vert_index_buf = prRhiCreateBuffer(app.device, vert_desc); void *mapped = prRhiBufferMap(app.device, app.vert_index_buf); @@ -263,14 +265,15 @@ int main() { // {{{ Shader data buffers app.shader_data_bufs = wpArrayAllocCapacity(PrRhiBuffer *, &arena, - AppState::max_frames_in_flight, - WP_ARRAY_INIT_FILLED); + AppState::max_frames_in_flight, + WP_ARRAY_INIT_FILLED); for (u32 i = 0; i < AppState::max_frames_in_flight; ++i) { PrRhiBufferDesc buf_desc = {}; - buf_desc.size = sizeof(ShaderData); - buf_desc.usage = (PrRhiBufferUsage)(PR_RHI_BUFFER_USAGE_STORAGE | - PR_RHI_BUFFER_USAGE_SHADER_DEVICE_ADDRESS); - buf_desc.memory = PR_RHI_MEMORY_CPU_TO_GPU; + buf_desc.size = sizeof(ShaderData); + buf_desc.usage = (PrRhiBufferUsage)(PR_RHI_BUFFER_USAGE_STORAGE | + PR_RHI_BUFFER_USAGE_SHADER_DEVICE_ADDRESS); + buf_desc.memory = PR_RHI_MEMORY_CPU_TO_GPU; + app.shader_data_bufs[i] = prRhiCreateBuffer(app.device, buf_desc); } // }}} @@ -278,7 +281,7 @@ int main() { // {{{ Synchronisation objects // Fences app.fences = wpArrayAllocCapacity(PrRhiFence *, &arena, AppState::max_frames_in_flight, - WP_ARRAY_INIT_FILLED); + WP_ARRAY_INIT_FILLED); for (u32 i = 0; i < AppState::max_frames_in_flight; ++i) { PrRhiFenceDesc fd = {}; fd.signaled = true; @@ -287,37 +290,34 @@ int main() { // Image acquired semaphores (per frame) app.image_acquired_semaphores = wpArrayAllocCapacity(PrRhiSemaphore *, &arena, - AppState::max_frames_in_flight, - WP_ARRAY_INIT_FILLED); + AppState::max_frames_in_flight, + WP_ARRAY_INIT_FILLED); for (u32 i = 0; i < AppState::max_frames_in_flight; ++i) { app.image_acquired_semaphores[i] = prRhiCreateSemaphore(app.device); } // Render completed semaphores (per swapchain image) - u32 swapchain_image_count = app.swapchain->image_count; + u32 swapchain_image_count = prRhiGetSwapchainImageCount(app.swapchain); app.render_completed_semaphores = wpArrayAllocCapacity(PrRhiSemaphore *, &arena, - swapchain_image_count, - WP_ARRAY_INIT_FILLED); + swapchain_image_count, + WP_ARRAY_INIT_FILLED); for (u32 i = 0; i < swapchain_image_count; ++i) { app.render_completed_semaphores[i] = prRhiCreateSemaphore(app.device); } // }}} // {{{ Command pool and buffers - PrRhiCommandPoolDesc pool_desc = {}; - pool_desc.queue_family_index = qfi; - app.cmd_pool = prRhiCreateCommandPool(app.device, pool_desc); - + app.cmd_pool = prRhiCreateCommandPool(app.device); app.cmd_buffers = prRhiAllocateCommandBuffers(app.device, app.cmd_pool, - AppState::max_frames_in_flight); + AppState::max_frames_in_flight); // }}} // {{{ Texture loading app.textures = wpArrayAllocCapacity(TextureResources, &arena, AppState::texture_count, - WP_ARRAY_INIT_FILLED); + WP_ARRAY_INIT_FILLED); PrRhiCommandBufferArray upload_cbs = prRhiAllocateCommandBuffers(app.device, app.cmd_pool, 1); - PrRhiCommandBuffer *upload_cb = upload_cbs[0]; + PrRhiCommandBuffer *upload_cb = upload_cbs[0]; for (u32 i = 0; i < AppState::texture_count; ++i) { char buf[2048] = {}; @@ -326,67 +326,69 @@ int main() { // Create sampler PrRhiSamplerDesc samp_desc = {}; - samp_desc.mag_filter = PR_RHI_FILTER_LINEAR; - 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 = PR_RHI_LOD_CLAMP_NONE; + samp_desc.mag_filter = PR_RHI_FILTER_LINEAR; + 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 = PR_RHI_LOD_CLAMP_NONE; + PrRhiSampler *sampler = prRhiCreateSampler(app.device, samp_desc); app.textures[i].texture = tex; app.textures[i].sampler = sampler; } - prRhiFreeCommandBuffers(app.device, app.cmd_pool, 1, upload_cbs); - wpArrayDealloc(PrRhiCommandBuffer *, &arena, &upload_cbs); + prRhiFreeCommandBuffers(app.device, app.cmd_pool, upload_cbs); // }}} // {{{ Descriptor set layout, pool, set - PrRhiDescriptorSetLayoutBinding bindings[1] = {}; - bindings[0].type = PR_RHI_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - bindings[0].descriptor_count = AppState::texture_count; - bindings[0].stage_flags = PR_RHI_SHADER_STAGE_FRAGMENT; - bindings[0].binding_flags = PR_RHI_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT; + PrRhiDescriptorSetLayoutBindingArray ds_layouts = wpArray( + PrRhiDescriptorSetLayoutBinding, + PrRhiDescriptorSetLayoutBinding{ + PR_RHI_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + AppState::texture_count, + PR_RHI_SHADER_STAGE_FRAGMENT, + PR_RHI_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT, + } + ); - PrRhiDescriptorSetLayoutBindingArray ds_layouts = wpArray(PrRhiDescriptorSetLayoutBinding, bindings[0]); - - PrRhiDescriptorSetLayoutDesc layout_desc = {}; - layout_desc.bindings = ds_layouts; - app.desc_set_layout = prRhiCreateDescriptorSetLayout(app.device, layout_desc); + PrRhiDescriptorSetLayoutDesc layout_desc = { ds_layouts }; + app.desc_set_layout = prRhiCreateDescriptorSetLayout(app.device, layout_desc); // Pool PrRhiDescriptorPoolSize pool_size = {}; - pool_size.type = PR_RHI_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - pool_size.descriptor_count = AppState::texture_count; + pool_size.type = PR_RHI_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + pool_size.descriptor_count = AppState::texture_count; - PrRhiDescriptorPoolDesc pool_desc2 = {}; - pool_desc2.max_sets = 1; - pool_desc2.pool_sizes = wpArray(PrRhiDescriptorPoolSize, pool_size); - app.desc_pool = prRhiCreateDescriptorPool(app.device, pool_desc2); + PrRhiDescriptorPoolDesc ds_pool_desc = {}; + ds_pool_desc.max_sets = 1; + ds_pool_desc.pool_sizes = wpArray(PrRhiDescriptorPoolSize, pool_size); + + app.desc_pool = prRhiCreateDescriptorPool(app.device, ds_pool_desc); // Allocate descriptor set (variable count) - app.desc_set = prRhiAllocateDescriptorSet(app.device, app.desc_pool, - app.desc_set_layout, - AppState::texture_count); + WpU32Array var_counts = wpArray(u32, AppState::texture_count); + app.desc_set = prRhiAllocateDescriptorSet(app.device, app.desc_pool, app.desc_set_layout, + var_counts); // Write descriptor set PrRhiDescriptorImageInfoArray img_infos = wpArrayAllocCapacity(PrRhiDescriptorImageInfo, - &arena, - AppState::texture_count, - WP_ARRAY_INIT_NONE); + &arena, + AppState::texture_count, + WP_ARRAY_INIT_NONE); for (u32 i = 0; i < AppState::texture_count; ++i) { PrRhiDescriptorImageInfo info = {}; - info.texture = app.textures[i].texture; - info.sampler = app.textures[i].sampler; - info.layout = PR_RHI_LAYOUT_READ_ONLY_OPTIMAL; + info.texture = app.textures[i].texture; + info.sampler = app.textures[i].sampler; + info.layout = PR_RHI_LAYOUT_READ_ONLY_OPTIMAL; wpArrayAppendCapped(PrRhiDescriptorImageInfo, img_infos, &info); } PrRhiWriteDescriptorSet write = {}; - write.dst_set = app.desc_set; - write.dst_binding = 0; - write.type = PR_RHI_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - write.image_info = img_infos; + write.dst_set = app.desc_set; + write.dst_binding = 0; + write.type = PR_RHI_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + write.image_info = img_infos; PrRhiWriteDescriptorSetArray writes = wpArray(PrRhiWriteDescriptorSet, write); prRhiUpdateDescriptorSet(app.device, writes); @@ -415,73 +417,74 @@ int main() { // {{{ Create shader module PrRhiShaderDesc shader_desc = {}; - shader_desc.spirv_code = spirv->getBufferPointer(); - shader_desc.spirv_size = spirv->getBufferSize(); + shader_desc.spirv_code = spirv->getBufferPointer(); + shader_desc.spirv_size = spirv->getBufferSize(); + app.shader = prRhiCreateShader(app.device, shader_desc); // }}} // {{{ Pipeline layout PrRhiPushConstantRange pc_range = {}; - pc_range.stage_flags = PR_RHI_SHADER_STAGE_VERTEX; - pc_range.size = sizeof(u64); + pc_range.stage_flags = PR_RHI_SHADER_STAGE_VERTEX; + pc_range.size = sizeof(u64); - PrRhiDescriptorSetLayout *set_layouts_pl[] = { app.desc_set_layout }; - PrRhiDescriptorSetLayoutArray pl_layouts = wpArray(PrRhiDescriptorSetLayout *, set_layouts_pl[0]); + PrRhiDescriptorSetLayoutArray pl_layouts = wpArray(PrRhiDescriptorSetLayout *, app.desc_set_layout); PrRhiPipelineLayoutDesc pl_desc = {}; - pl_desc.set_layouts = pl_layouts; - pl_desc.push_constant_ranges = wpArray(PrRhiPushConstantRange, pc_range); + pl_desc.set_layouts = pl_layouts; + pl_desc.push_constant_ranges = wpArray(PrRhiPushConstantRange, pc_range); + app.pipeline_layout = prRhiCreatePipelineLayout(app.device, pl_desc); // }}} // {{{ Graphics pipeline - PrRhiVertexInputBinding vertex_binding = {}; - vertex_binding.binding = 0; - vertex_binding.stride = sizeof(Vertex); + PrRhiVertexInputBindingArray vertex_bindings = wpArray( + PrRhiVertexInputBinding, + PrRhiVertexInputBinding{ 0, sizeof(Vertex) } + ); - PrRhiVertexAttribute vertex_attrs[3] = {}; - vertex_attrs[0].location = 0; - vertex_attrs[0].binding = 0; - vertex_attrs[0].format = PR_RHI_FORMAT_R32G32B32_SFLOAT; - vertex_attrs[0].offset = 0; - vertex_attrs[1].location = 1; - vertex_attrs[1].binding = 0; - vertex_attrs[1].format = PR_RHI_FORMAT_R32G32B32_SFLOAT; - vertex_attrs[1].offset = offsetof(Vertex, normal); - vertex_attrs[2].location = 2; - vertex_attrs[2].binding = 0; - vertex_attrs[2].format = PR_RHI_FORMAT_R32G32_SFLOAT; - vertex_attrs[2].offset = offsetof(Vertex, uv); + PrRhiVertexAttributeArray vertex_attrs = wpArray( + PrRhiVertexAttribute, + PrRhiVertexAttribute{ 0, 0, PR_RHI_FORMAT_R32G32B32_SFLOAT, 0 }, + PrRhiVertexAttribute{ 1, 0, PR_RHI_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, normal) }, + PrRhiVertexAttribute{ 2, 0, PR_RHI_FORMAT_R32G32_SFLOAT, offsetof(Vertex, uv) } + ); - PrRhiColorBlendAttachment blend_attachment = {}; - blend_attachment.color_write_mask = 0xf; + PrRhiColorBlendAttachmentArray blend_attachments = wpArray( + PrRhiColorBlendAttachment, + PrRhiColorBlendAttachment{ 0xf } + ); - PrRhiFormat color_fmts[] = { swapchain_format }; - PrRhiFormatArray color_fmt_array = wpArray(PrRhiFormat, color_fmts[0]); + PrRhiFormatArray color_fmt_array = wpArray(PrRhiFormat, app.swapchain_format); + + PrRhiGraphicsPipelineDesc pipe_desc = {}; + pipe_desc.vertex_shader = app.shader; + pipe_desc.vertex_shader_entry_point = "main"; + pipe_desc.fragment_shader = app.shader; + pipe_desc.fragment_shader_entry_point = "main"; + pipe_desc.vertex_bindings = vertex_bindings; + pipe_desc.vertex_attributes = vertex_attrs; + pipe_desc.topology = PR_RHI_TOPOLOGY_TRIANGLE_LIST; + pipe_desc.color_attachment_formats = color_fmt_array; + pipe_desc.depth_attachment_format = swap_desc.depth_format; + pipe_desc.depth_test_enable = true; + pipe_desc.depth_write_enable = true; + pipe_desc.depth_compare_op = PR_RHI_COMPARE_OP_LESS_OR_EQUAL; + pipe_desc.blend_attachments = blend_attachments; + pipe_desc.dynamic_viewport = true; + pipe_desc.dynamic_scissor = true; + pipe_desc.cull_mode = PR_RHI_CULL_MODE_BACK; + pipe_desc.front_face = PR_RHI_FRONT_FACE_COUNTER_CLOCKWISE; + pipe_desc.line_width = 1.0f; + pipe_desc.layout = app.pipeline_layout; - PrRhiGraphicsPipelineDesc pipe_desc = {}; - pipe_desc.vertex_shader = app.shader; - pipe_desc.fragment_shader = app.shader; - pipe_desc.vertex_bindings = wpArray(PrRhiVertexInputBinding, vertex_binding); - pipe_desc.vertex_attributes = wpArray(PrRhiVertexAttribute, vertex_attrs[0], - vertex_attrs[1], vertex_attrs[2]); - pipe_desc.topology = PR_RHI_TOPOLOGY_TRIANGLE_LIST; - pipe_desc.color_attachment_formats = color_fmt_array; - pipe_desc.depth_attachment_format = swap_desc.depth_format; - pipe_desc.depth_test_enable = true; - pipe_desc.depth_write_enable = true; - pipe_desc.depth_compare_op = PR_RHI_COMPARE_OP_LESS_OR_EQUAL; - pipe_desc.blend_attachments = wpArray(PrRhiColorBlendAttachment, blend_attachment); - pipe_desc.dynamic_viewport = true; - pipe_desc.dynamic_scissor = true; - pipe_desc.layout = app.pipeline_layout; app.pipeline = prRhiCreateGraphicsPipeline(app.device, pipe_desc); // }}} // {{{ Render loop app.object_rotations = wpArrayAllocCapacity(glm::vec3, &arena, AppState::instance_count, - WP_ARRAY_INIT_FILLED); - u64 last_time = SDL_GetTicks(); + WP_ARRAY_INIT_FILLED); + u64 last_time = SDL_GetTicks(); SDL_Event event = {}; app.frame_index = 0; u32 image_index = 0; @@ -495,8 +498,8 @@ int main() { // {{{ Acquire next image PrRhiSwapchainResult acq = prRhiAcquireNextImage(app.device, app.swapchain, - app.image_acquired_semaphores[app.frame_index], - &image_index); + app.image_acquired_semaphores[app.frame_index], + &image_index); if (acq == PR_RHI_SWAPCHAIN_OUT_OF_DATE) { app.update_swapchain = true; } @@ -507,8 +510,8 @@ int main() { } else { // {{{ Update shader data app.shader_data.projection = glm::perspective(glm::radians(45.0f), - (f32)app.window_size.x / (f32)app.window_size.y, - 0.1f, 32.0f); + (f32)app.window_size.x / (f32)app.window_size.y, + 0.1f, 32.0f); app.shader_data.view = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -6.0f)); for (i32 i = 0; i < (i32)AppState::instance_count; ++i) { glm::vec3 instance_pos = glm::vec3((f32)(i - 1) * 3.0f, 0.0f, 0.0f); @@ -516,8 +519,7 @@ int main() { glm::mat4_cast(glm::quat(app.object_rotations[i])); } - void *shader_data_ptr = prRhiBufferMap(app.device, - app.shader_data_bufs[app.frame_index]); + void *shader_data_ptr = prRhiBufferMap(app.device, app.shader_data_bufs[app.frame_index]); memcpy(shader_data_ptr, &app.shader_data, sizeof(ShaderData)); prRhiBufferUnmap(app.device, app.shader_data_bufs[app.frame_index]); // }}} @@ -529,51 +531,50 @@ int main() { // Transition images to attachment optimal { - PrRhiImageMemoryBarrier img_barriers[2] = {}; + PrRhiImageMemoryBarrierArray barriers_arr = + wpArrayWithCapacity(PrRhiImageMemoryBarrier, 2, WP_ARRAY_INIT_FILLED); // Color attachment - PrRhiTexture *color_tex = prRhiGetSwapchainTexture(app.swapchain, image_index); - 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 = 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); + PrRhiTexture *color_tex = prRhiGetSwapchainTexture(app.swapchain, image_index); + barriers_arr[0].texture = color_tex; + barriers_arr[0].old_layout = PR_RHI_LAYOUT_UNDEFINED; + barriers_arr[0].new_layout = PR_RHI_LAYOUT_ATTACHMENT_OPTIMAL; + barriers_arr[0].src_stage_mask = PR_RHI_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT; + barriers_arr[0].src_access_mask = PR_RHI_ACCESS_NONE; + barriers_arr[0].dst_stage_mask = PR_RHI_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT; + barriers_arr[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 = 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; + PrRhiTexture *depth_tex = prRhiGetSwapchainDepthTexture(app.swapchain); + barriers_arr[1].texture = depth_tex; + barriers_arr[1].old_layout = PR_RHI_LAYOUT_UNDEFINED; + barriers_arr[1].new_layout = PR_RHI_LAYOUT_ATTACHMENT_OPTIMAL; + barriers_arr[1].src_stage_mask = PR_RHI_PIPELINE_STAGE_LATE_FRAGMENT_TESTS; + barriers_arr[1].src_access_mask = PR_RHI_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE; + barriers_arr[1].dst_stage_mask = PR_RHI_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS; + barriers_arr[1].dst_access_mask = PR_RHI_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE; - PrRhiImageMemoryBarrierArray barriers_arr = wpArray(PrRhiImageMemoryBarrier, - img_barriers[0], img_barriers[1]); prRhiCmdPipelineBarrier(cb, barriers_arr, NULL); } // Rendering { - PrRhiColorAttachment color_att = {}; - color_att.texture = prRhiGetSwapchainTexture(app.swapchain, image_index); - color_att.layout = PR_RHI_LAYOUT_ATTACHMENT_OPTIMAL; - color_att.clear = true; - color_att.clear_color[0] = 0.0f; - color_att.clear_color[1] = 0.0f; - color_att.clear_color[2] = 0.0f; - color_att.clear_color[3] = 0.0f; + PrRhiColorAttachmentArray color_arr = + wpArrayWithCapacity(PrRhiColorAttachment, 1, WP_ARRAY_INIT_FILLED); + color_arr[0].texture = prRhiGetSwapchainTexture(app.swapchain, image_index); + color_arr[0].layout = PR_RHI_LAYOUT_ATTACHMENT_OPTIMAL; + color_arr[0].clear = true; + color_arr[0].clear_color[0] = 0.0f; + color_arr[0].clear_color[1] = 0.0f; + color_arr[0].clear_color[2] = 0.0f; + color_arr[0].clear_color[3] = 0.0f; PrRhiDepthAttachment depth_att = {}; - depth_att.texture = prRhiGetSwapchainDepthTexture(app.swapchain); - depth_att.layout = PR_RHI_LAYOUT_ATTACHMENT_OPTIMAL; - depth_att.clear = true; - depth_att.clear_depth = 1.0f; + depth_att.texture = prRhiGetSwapchainDepthTexture(app.swapchain); + depth_att.layout = PR_RHI_LAYOUT_ATTACHMENT_OPTIMAL; + depth_att.clear = true; + depth_att.clear_depth = 1.0f; - PrRhiColorAttachmentArray color_arr = wpArray(PrRhiColorAttachment, color_att); prRhiCmdBeginRendering(cb, color_arr, &depth_att); } @@ -584,51 +585,46 @@ int main() { PrRhiDescriptorSetArray sets = wpArray(PrRhiDescriptorSet *, app.desc_set); prRhiCmdBindDescriptorSets(cb, PR_RHI_PIPELINE_BIND_POINT_GRAPHICS, - app.pipeline_layout, 0, sets); + app.pipeline_layout, 0, sets); - PrRhiBuffer *vert_bufs[] = { app.vert_index_buf }; - u64 vert_offsets[] = { 0 }; - PrRhiBufferArray vert_buf_arr = wpArray(PrRhiBuffer *, vert_bufs[0]); - prRhiCmdBindVertexBuffers(cb, 0, vert_buf_arr, vert_offsets, 1); - prRhiCmdBindIndexBuffer(cb, app.vert_index_buf, app.vertex_buf_size, - PR_RHI_INDEX_TYPE_UINT16); + PrRhiBufferArray vert_buf_arr = wpArray(PrRhiBuffer *, app.vert_index_buf); + WpU64Array vert_offsets = wpArray(u64, 0); + prRhiCmdBindVertexBuffers(cb, 0, vert_buf_arr, vert_offsets); + prRhiCmdBindIndexBuffer(cb, app.vert_index_buf, app.vertex_buf_size, PR_RHI_INDEX_TYPE_UINT16); // Push shader data buffer device address - u64 buf_addr = prRhiGetBufferDeviceAddress(app.device, - app.shader_data_bufs[app.frame_index]); - prRhiCmdPushConstants(cb, app.pipeline_layout, PR_RHI_SHADER_STAGE_VERTEX, - 0, sizeof(u64), &buf_addr); + u64 buf_addr = prRhiGetBufferDeviceAddress(app.device, app.shader_data_bufs[app.frame_index]); + prRhiCmdPushConstants(cb, app.pipeline_layout, PR_RHI_SHADER_STAGE_VERTEX, 0, sizeof(u64), &buf_addr); prRhiCmdDrawIndexed(cb, (u32)app.index_count, AppState::instance_count, 0, 0, 0); prRhiCmdEndRendering(cb); // Transition to present { - PrRhiImageMemoryBarrier present_barrier = {}; - 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 = 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; + PrRhiImageMemoryBarrierArray present_barriers = + wpArrayWithCapacity(PrRhiImageMemoryBarrier, 1, WP_ARRAY_INIT_FILLED); + present_barriers[0].texture = prRhiGetSwapchainTexture(app.swapchain, image_index); + present_barriers[0].old_layout = PR_RHI_LAYOUT_ATTACHMENT_OPTIMAL; + present_barriers[0].new_layout = PR_RHI_LAYOUT_PRESENT_SRC; + present_barriers[0].src_stage_mask = PR_RHI_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT; + present_barriers[0].src_access_mask = PR_RHI_ACCESS_COLOR_ATTACHMENT_WRITE; + present_barriers[0].dst_stage_mask = PR_RHI_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT; + present_barriers[0].dst_access_mask = PR_RHI_ACCESS_NONE; - prRhiCmdPipelineBarrier(cb, wpArray(PrRhiImageMemoryBarrier, present_barrier), NULL); + prRhiCmdPipelineBarrier(cb, present_barriers, NULL); } prRhiEndCommandBuffer(cb); // }}} // {{{ Submit - prRhiQueueSubmit(app.device, cb, - app.image_acquired_semaphores[app.frame_index], - app.render_completed_semaphores[image_index], - app.fences[app.frame_index]); + prRhiQueueSubmit(app.device, cb, app.image_acquired_semaphores[app.frame_index], + app.render_completed_semaphores[image_index], app.fences[app.frame_index]); // }}} // {{{ Present PrRhiSwapchainResult pres = prRhiPresent(app.device, app.swapchain, - app.render_completed_semaphores[image_index]); + app.render_completed_semaphores[image_index]); if (pres == PR_RHI_SWAPCHAIN_OUT_OF_DATE) { app.update_swapchain = true; } @@ -709,8 +705,7 @@ int main() { prRhiDestroyTexture(app.device, app.textures[i].texture); } - prRhiFreeCommandBuffers(app.device, app.cmd_pool, AppState::max_frames_in_flight, - app.cmd_buffers); + prRhiFreeCommandBuffers(app.device, app.cmd_pool, app.cmd_buffers); prRhiDestroyCommandPool(app.device, app.cmd_pool); for (u32 i = 0; i < swapchain_image_count; ++i) { diff --git a/src/prism/rhi/pr_rhi.c b/src/prism/rhi/pr_rhi.c index 80c02da..db1850a 100644 --- a/src/prism/rhi/pr_rhi.c +++ b/src/prism/rhi/pr_rhi.c @@ -7,11 +7,9 @@ PrRhiContext _G_RHI_CONTEXT; void prRhiInit(void) { - _G_RHI_CONTEXT.main = wpMemArenaAllocatorInit(MiB(64)); - _G_RHI_CONTEXT.scratch = wpMemArenaAllocatorInit(MiB(32)); + _G_RHI_CONTEXT.allocator = wpMemArenaAllocatorInit(MiB(64)); } void prRhiDestroy(void) { - wpMemArenaAllocatorDestroy(&_G_RHI_CONTEXT.scratch); - wpMemArenaAllocatorDestroy(&_G_RHI_CONTEXT.main); + wpMemArenaAllocatorDestroy(&_G_RHI_CONTEXT.allocator); } diff --git a/src/prism/rhi/pr_rhi.h b/src/prism/rhi/pr_rhi.h index 4b228a2..ae4bcdd 100644 --- a/src/prism/rhi/pr_rhi.h +++ b/src/prism/rhi/pr_rhi.h @@ -24,6 +24,7 @@ #define PR_RHI_H #include "pr_rhi_types.h" +#include #ifdef __cplusplus extern "C" { @@ -45,17 +46,16 @@ void prRhiDestroyInstance(PrRhiInstance *inst); // Physical device enumeration // ====================================================================== -PrRhiPhysicalDeviceArray prRhiGetPhysicalDevices(PrRhiInstance *inst); -void prRhiGetPhysicalDeviceName(PrRhiPhysicalDevice *pdev, WpStr8 *out); -void prRhiGetPhysicalDeviceDriverInfo(PrRhiPhysicalDevice *pdev, WpStr8 *out); -void prRhiGetPhysicalDeviceProperties(PrRhiPhysicalDevice *pdev, - PrRhiPhysicalDeviceProperties *out); +PrRhiPhysicalDeviceArray prRhiGetPhysicalDevices(PrRhiInstance *inst); +void prRhiGetPhysicalDeviceName(PrRhiPhysicalDevice *pdev, WpStr8 *out); +void prRhiGetPhysicalDeviceDriverInfo(PrRhiPhysicalDevice *pdev, WpStr8 *out); +PrRhiPhysicalDeviceProperties prRhiGetPhysicalDeviceProperties(PrRhiPhysicalDevice *pdev); // ====================================================================== // Surface (platform-specific) // ====================================================================== -PrRhiSurface *prRhiCreateSurfaceFromWindow(PrRhiInstance *inst, void *window_handle); +PrRhiSurface *prRhiCreateSurfaceFromWindow(PrRhiInstance *inst, SDL_Window *window); void prRhiDestroySurface(PrRhiInstance *inst, PrRhiSurface *surface); PrRhiSurfaceCapabilities prRhiGetSurfaceCapabilities(PrRhiPhysicalDevice *pdev, PrRhiSurface *surface); @@ -77,6 +77,7 @@ u32 prRhiGetQueueFamilyIndex(PrRhiDevice *device); PrRhiSwapchain *prRhiCreateSwapchain(PrRhiDevice *device, PrRhiSwapchainDesc desc); void prRhiDestroySwapchain(PrRhiDevice *device, PrRhiSwapchain *swapchain); +u32 prRhiGetSwapchainImageCount(PrRhiSwapchain *swapchain); PrRhiSwapchainResult prRhiAcquireNextImage(PrRhiDevice *device, PrRhiSwapchain *swapchain, PrRhiSemaphore *signal_semaphore, u32 *out_image_index); @@ -167,8 +168,8 @@ void prRhiDestroyDescriptorPool(PrRhiDevice *device, // ====================================================================== PrRhiDescriptorSet *prRhiAllocateDescriptorSet(PrRhiDevice *device, PrRhiDescriptorPool *pool, - PrRhiDescriptorSetLayout *layout, - u32 variable_count); + PrRhiDescriptorSetLayout *layout, + WpU32Array variable_descriptor_counts); void prRhiFreeDescriptorSet(PrRhiDevice *device, PrRhiDescriptorPool *pool, PrRhiDescriptorSet *set); void prRhiUpdateDescriptorSet(PrRhiDevice *device, PrRhiWriteDescriptorSetArray writes); @@ -191,13 +192,14 @@ void prRhiDestroySemaphore(PrRhiDevice *device, PrRhiSemaphore *semap // Command pools and command buffers // ====================================================================== -PrRhiCommandPool *prRhiCreateCommandPool(PrRhiDevice *device, PrRhiCommandPoolDesc desc); +PrRhiCommandPool *prRhiCreateCommandPool(PrRhiDevice *device); void prRhiDestroyCommandPool(PrRhiDevice *device, PrRhiCommandPool *pool); PrRhiCommandBufferArray prRhiAllocateCommandBuffers(PrRhiDevice *device, PrRhiCommandPool *pool, u32 count); + void prRhiFreeCommandBuffers(PrRhiDevice *device, PrRhiCommandPool *pool, - u32 count, PrRhiCommandBufferArray buffers); + PrRhiCommandBufferArray buffers); // ====================================================================== // Command buffer recording @@ -238,8 +240,8 @@ void prRhiCmdPushConstants(PrRhiCommandBuffer *cb, PrRhiPipelineLayout *layout, // --- Vertex / index buffers --- -void prRhiCmdBindVertexBuffers(PrRhiCommandBuffer *cb, u32 first_binding, - PrRhiBufferArray buffers, const u64 *offsets, u32 count); +void prRhiCmdBindVertexBuffers(PrRhiCommandBuffer *cb, u32 first_binding, PrRhiBufferArray buffers, + WpU64Array offsets); void prRhiCmdBindIndexBuffer(PrRhiCommandBuffer *cb, PrRhiBuffer *buffer, u64 offset, PrRhiIndexType index_type); diff --git a/src/prism/rhi/pr_rhi_types.h b/src/prism/rhi/pr_rhi_types.h index 63d81ea..ff26745 100644 --- a/src/prism/rhi/pr_rhi_types.h +++ b/src/prism/rhi/pr_rhi_types.h @@ -357,9 +357,40 @@ typedef struct PrRhiPipelineLayoutDesc { PrRhiPushConstantRangeArray push_constant_ranges; } PrRhiPipelineLayoutDesc; +typedef enum PrRhiPolygonMode { + PR_RHI_POLYGON_MODE_FILL = 0, + PR_RHI_POLYGON_MODE_LINE = 1, + PR_RHI_POLYGON_MODE_POINT = 2, +} PrRhiPolygonMode; + +typedef enum PrRhiCullMode { + PR_RHI_CULL_MODE_NONE = 0, + PR_RHI_CULL_MODE_FRONT = 0x00000001, + PR_RHI_CULL_MODE_BACK = 0x00000002, + PR_RHI_CULL_MODE_FRONT_AND_BACK = 0x00000003, +} PrRhiCullMode; + +typedef enum PrRhiFrontFace { + PR_RHI_FRONT_FACE_COUNTER_CLOCKWISE = 0, + PR_RHI_FRONT_FACE_CLOCKWISE = 1, +} PrRhiFrontFace; + +typedef enum PrRhiMultisampleCount { + PR_RHI_SAMPLE_COUNT_1 = 0x00000001, + PR_RHI_SAMPLE_COUNT_2 = 0x00000002, + PR_RHI_SAMPLE_COUNT_4 = 0x00000004, + PR_RHI_SAMPLE_COUNT_8 = 0x00000008, + PR_RHI_SAMPLE_COUNT_16 = 0x00000010, + PR_RHI_SAMPLE_COUNT_32 = 0x00000020, + PR_RHI_SAMPLE_COUNT_64 = 0x00000040, +} PrRhiMultisampleCount; + typedef struct PrRhiGraphicsPipelineDesc { PrRhiShader *vertex_shader; + const char *vertex_shader_entry_point; + PrRhiShader *fragment_shader; + const char *fragment_shader_entry_point; PrRhiVertexInputBindingArray vertex_bindings; PrRhiVertexAttributeArray vertex_attributes; @@ -378,11 +409,22 @@ typedef struct PrRhiGraphicsPipelineDesc { b8 dynamic_viewport; b8 dynamic_scissor; + PrRhiPolygonMode polygon_mode; + + PrRhiCullMode cull_mode; + + PrRhiFrontFace front_face; + + f32 line_width; + + PrRhiMultisampleCount multisample_count; + PrRhiPipelineLayout *layout; } PrRhiGraphicsPipelineDesc; typedef struct PrRhiComputePipelineDesc { PrRhiShader *shader; + const char *shader_entry_point; PrRhiPipelineLayout *layout; } PrRhiComputePipelineDesc; @@ -408,10 +450,6 @@ typedef struct PrRhiFenceDesc { b8 signaled; } PrRhiFenceDesc; -typedef struct PrRhiCommandPoolDesc { - u32 queue_family_index; -} PrRhiCommandPoolDesc; - typedef struct PrRhiSwapchainDesc { PrRhiSurface *surface; u32 width; @@ -432,7 +470,7 @@ typedef struct PrRhiSurfaceCapabilities { } PrRhiSurfaceCapabilities; typedef struct PrRhiPhysicalDeviceProperties { - u32 api_version; + u32 api_version; PrRhiPhysicalDeviceType device_type; } PrRhiPhysicalDeviceProperties; @@ -443,8 +481,7 @@ typedef u64 PrRhiDeviceAddress; // ============================================================================ typedef struct PrRhiContext { - WpAllocator main; - WpAllocator scratch; + WpAllocator allocator; } PrRhiContext; // --- Command buffer types --- diff --git a/src/prism/rhi/vulkan/pr_rhi_vk.c b/src/prism/rhi/vulkan/pr_rhi_vk.c index 4371416..60b9cdd 100644 --- a/src/prism/rhi/vulkan/pr_rhi_vk.c +++ b/src/prism/rhi/vulkan/pr_rhi_vk.c @@ -7,6 +7,7 @@ #include "pr_rhi_vk.h" #include "profiles/vulkan_profiles.h" #include "../pr_rhi.h" +#include "vulkan/vulkan_core.h" #include #include #include @@ -14,17 +15,34 @@ #include #include +#define TEMP_FENCE_MAX_COUNT 64 + // ============================================================================ // Typedefs for wapp arrays of Vulkan handle types // ============================================================================ -typedef VkPhysicalDevice *VkPhysicalDeviceArray; -typedef VkQueueFamilyProperties2 *VkQueueFamilyProperties2Array; -typedef VkImage *VkImageArray; -typedef VkImageView *VkImageViewArray; -typedef VkDescriptorSetLayout *VkDescriptorSetLayoutArray; -typedef VkPushConstantRange *VkPushConstantRangeArray; -typedef VkCommandBuffer *VkCommandBufferArray; +typedef VkPhysicalDevice *VkPhysicalDeviceArray; +typedef VkQueueFamilyProperties2 *VkQueueFamilyProperties2Array; +typedef VkFormat *VkFormatArray; +typedef VkBufferImageCopy *VkBufferImageCopyArray; +typedef VkBuffer *VkBufferArray; +typedef VkImage *VkImageArray; +typedef VkImageView *VkImageViewArray; +typedef VkDescriptorSetLayoutBinding *VkDescriptorSetLayoutBindingArray; +typedef VkDescriptorBindingFlags *VkDescriptorBindingFlagsArray; +typedef VkDescriptorSetLayout *VkDescriptorSetLayoutArray; +typedef VkDescriptorPoolSize *VkDescriptorPoolSizeArray; +typedef VkDescriptorImageInfo *VkDescriptorImageInfoArray; +typedef VkDescriptorBufferInfo *VkDescriptorBufferInfoArray; +typedef VkDescriptorSetLayout *VkDescriptorSetLayoutArray; +typedef VkDescriptorSet *VkDescriptorSetArray; +typedef VkPushConstantRange *VkPushConstantRangeArray; +typedef VkCommandBuffer *VkCommandBufferArray; +typedef VkVertexInputBindingDescription *VkVertexInputBindingDescriptionArray; +typedef VkVertexInputAttributeDescription *VkVertexInputAttributeDescriptionArray; +typedef VkDynamicState *VkDynamicStateArray; +typedef VkPipelineColorBlendAttachmentState *VkPipelineColorBlendAttachmentStateArray; +typedef VkRenderingAttachmentInfo *VkRenderingAttachmentInfoArray; // ============================================================================ // Helpers @@ -318,7 +336,7 @@ PrRhiInstance *prRhiCreateInstanceVk(PrRhiInstanceDesc desc) { VkBool32 supported = VK_FALSE; _checkVk(vpGetInstanceProfileSupport(NULL, &_profile, &supported), "vpGetInstanceProfileSupport"); - if (!supported) _abort("VP_PRISM_DESKTOP_2026 not supported at instance level"); + 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); @@ -326,29 +344,32 @@ PrRhiInstance *prRhiCreateInstanceVk(PrRhiInstanceDesc desc) { _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"; - app_info.applicationVersion = desc.app_version; - app_info.apiVersion = VP_PRISM_DESKTOP_2026_MIN_API_VERSION; + VkApplicationInfo app_info = { + .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, + .pApplicationName = desc.app_name ? desc.app_name : "Prism", + .applicationVersion = desc.app_version, + .apiVersion = VP_PRISM_DESKTOP_2026_MIN_API_VERSION, + }; - VkInstanceCreateInfo instance_info = {}; - instance_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - instance_info.pApplicationInfo = &app_info; - instance_info.enabledExtensionCount = sdl_ext_count; - instance_info.ppEnabledExtensionNames = sdl_exts; + VkInstanceCreateInfo instance_info = { + .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + .pApplicationInfo = &app_info, + .enabledExtensionCount = sdl_ext_count, + .ppEnabledExtensionNames = sdl_exts, + }; - VpInstanceCreateInfo vp_instance_info = {}; - vp_instance_info.pCreateInfo = &instance_info; - vp_instance_info.enabledFullProfileCount = 1; - vp_instance_info.pEnabledFullProfiles = &_profile; + VpInstanceCreateInfo vp_instance_info = { + .pCreateInfo = &instance_info, + .enabledFullProfileCount = 1, + .pEnabledFullProfiles = &_profile, + }; VkInstance vk_instance = VK_NULL_HANDLE; _checkVk(vpCreateInstance(&vp_instance_info, NULL, &vk_instance), "vpCreateInstance"); volkLoadInstance(vk_instance); - PrRhiInstance *inst = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.main, sizeof(PrRhiInstance)); + PrRhiInstance *inst = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.allocator, sizeof(PrRhiInstance)); if (!inst) { _abort("alloc failed for PrRhiInstance"); } inst->handle = vk_instance; inst->debug_messenger = NULL; @@ -359,7 +380,7 @@ PrRhiInstance *prRhiCreateInstanceVk(PrRhiInstanceDesc desc) { void prRhiDestroyInstanceVk(PrRhiInstance *inst) { if (!inst) { return; } vkDestroyInstance((VkInstance)inst->handle, NULL); - wpMemAllocatorFree(&_G_RHI_CONTEXT.main, (void**)&inst, sizeof(PrRhiInstance)); + wpMemAllocatorFree(&_G_RHI_CONTEXT.allocator, (void**)&inst, sizeof(PrRhiInstance)); } // ============================================================================ @@ -371,26 +392,34 @@ PrRhiPhysicalDeviceArray prRhiGetPhysicalDevicesVk(PrRhiInstance *inst) { u32 count = 0; _checkVk(vkEnumeratePhysicalDevices(vk_inst, &count, NULL), "vkEnumeratePhysicalDevices"); - if (count == 0) _abort("no physical devices"); + if (count == 0) { _abort("no physical devices"); } - VkPhysicalDeviceArray vk_devices = wpArrayAllocCapacity(VkPhysicalDevice, &_G_RHI_CONTEXT.scratch, count, WP_ARRAY_INIT_FILLED); - if (!vk_devices) _abort("alloc failed for physical device array"); + VkPhysicalDeviceArray vk_devices = wpArrayAllocCapacity(VkPhysicalDevice, &_G_RHI_CONTEXT.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 *, &_G_RHI_CONTEXT.main, count, WP_ARRAY_INIT_NONE); - if (!pdevs) _abort("alloc failed for PrRhiPhysicalDevice array"); + PrRhiPhysicalDeviceArray pdevs = wpArrayAllocCapacity(PrRhiPhysicalDevice *, &_G_RHI_CONTEXT.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(&_G_RHI_CONTEXT.main, sizeof(PrRhiPhysicalDevice)); - if (!pdev) _abort("alloc failed for PrRhiPhysicalDevice"); + VkBool32 supported = VK_TRUE; + VkResult result = vpGetPhysicalDeviceProfileSupport(vk_inst, vk_devices[i], &_profile, &supported); + if (result != VK_SUCCESS || !supported) { continue; } + + PrRhiPhysicalDevice *pdev = (PrRhiPhysicalDevice *)wpMemAllocatorAlloc(&_G_RHI_CONTEXT.allocator, sizeof(PrRhiPhysicalDevice)); + if (!pdev) { _abort("alloc failed for PrRhiPhysicalDevice"); } pdev->handle = vk_devices[i]; pdev->instance = inst; - VkPhysicalDeviceProperties2 props = { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 }; VkPhysicalDeviceDriverProperties driver = { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES }; - props.pNext = &driver; + VkPhysicalDeviceProperties2 props = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, + .pNext = &driver, + }; vkGetPhysicalDeviceProperties2(vk_devices[i], &props); memcpy(pdev->device_name, props.properties.deviceName, sizeof(pdev->device_name)); memcpy(pdev->driver_info, driver.driverInfo, sizeof(pdev->driver_info)); @@ -402,53 +431,57 @@ PrRhiPhysicalDeviceArray prRhiGetPhysicalDevicesVk(PrRhiInstance *inst) { } void prRhiGetPhysicalDeviceNameVk(PrRhiPhysicalDevice *pdev, WpStr8 *out) { + u64 name_len = strlen((const char *)pdev->device_name); + u64 count = name_len <= out->capacity ? name_len : out->capacity; out->buf = pdev->device_name; - out->size = strlen((const char *)pdev->device_name); - out->capacity = 0; + out->size = count; + out->capacity = count; } void prRhiGetPhysicalDeviceDriverInfoVk(PrRhiPhysicalDevice *pdev, WpStr8 *out) { + u64 name_len = strlen((const char *)pdev->driver_info); + u64 count = name_len <= out->capacity ? name_len : out->capacity; out->buf = pdev->driver_info; - out->size = strlen((const char *)pdev->driver_info); - out->capacity = 0; + out->size = count; + out->capacity = count; } -void prRhiGetPhysicalDevicePropertiesVk(PrRhiPhysicalDevice *pdev, - PrRhiPhysicalDeviceProperties *out) { +PrRhiPhysicalDeviceProperties 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 = (PrRhiPhysicalDeviceType)props.properties.deviceType; + return (PrRhiPhysicalDeviceProperties) { + .api_version = props.properties.apiVersion, + .device_type = (PrRhiPhysicalDeviceType)props.properties.deviceType, + }; } // ============================================================================ // Surface // ============================================================================ -PrRhiSurface *prRhiCreateSurfaceFromWindowVk(PrRhiInstance *inst, void *window_handle) { - SDL_Window *window = (SDL_Window *)window_handle; - VkInstance vk_inst = (VkInstance)inst->handle; +PrRhiSurface *prRhiCreateSurfaceFromWindowVk(PrRhiInstance *inst, SDL_Window *window) { + VkInstance vk_inst = inst->handle; VkSurfaceKHR vk_surface = VK_NULL_HANDLE; - if (!SDL_Vulkan_CreateSurface(window, vk_inst, NULL, &vk_surface)) + if (!SDL_Vulkan_CreateSurface(window, vk_inst, NULL, &vk_surface)) { _abort("SDL_Vulkan_CreateSurface failed"); + } - PrRhiSurface *surface = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.main, sizeof(PrRhiSurface)); - if (!surface) _abort("alloc failed for PrRhiSurface"); - surface->handle = (void *)vk_surface; + PrRhiSurface *surface = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.allocator, sizeof(PrRhiSurface)); + if (!surface) { _abort("alloc failed for PrRhiSurface"); } + surface->handle = vk_surface; return surface; } void prRhiDestroySurfaceVk(PrRhiInstance *inst, PrRhiSurface *surface) { - if (!surface) return; - vkDestroySurfaceKHR((VkInstance)inst->handle, (VkSurfaceKHR)surface->handle, NULL); - wpMemAllocatorFree(&_G_RHI_CONTEXT.main, (void**)&surface, sizeof(PrRhiSurface)); + if (!surface) { return; } + vkDestroySurfaceKHR(inst->handle, surface->handle, NULL); + wpMemAllocatorFree(&_G_RHI_CONTEXT.allocator, (void**)&surface, sizeof(PrRhiSurface)); } PrRhiSurfaceCapabilities prRhiGetSurfaceCapabilitiesVk(PrRhiPhysicalDevice *pdev, PrRhiSurface *surface) { VkSurfaceCapabilitiesKHR caps = {}; - _checkVk(vkGetPhysicalDeviceSurfaceCapabilitiesKHR((VkPhysicalDevice)pdev->handle, - (VkSurfaceKHR)surface->handle, &caps), + _checkVk(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(pdev->handle, surface->handle, &caps), "vkGetPhysicalDeviceSurfaceCapabilitiesKHR"); PrRhiSurfaceCapabilities out = { @@ -469,19 +502,20 @@ PrRhiSurfaceCapabilities prRhiGetSurfaceCapabilitiesVk(PrRhiPhysicalDevice *pdev // ============================================================================ PrRhiDevice *prRhiCreateDeviceVk(PrRhiPhysicalDevice *pdev, PrRhiSurface *surface, - PrRhiDeviceDesc desc) { - VkInstance vk_inst = (VkInstance)pdev->instance->handle; - VkPhysicalDevice vk_pdev = (VkPhysicalDevice)pdev->handle; - VkSurfaceKHR vk_surface = (VkSurfaceKHR)surface->handle; + PrRhiDeviceDesc desc) { + VkInstance vk_inst = pdev->instance->handle; + VkPhysicalDevice vk_pdev = pdev->handle; + VkSurfaceKHR vk_surface = surface->handle; // Select queue family u32 queue_family_count = 0; vkGetPhysicalDeviceQueueFamilyProperties2(vk_pdev, &queue_family_count, NULL); - if (queue_family_count == 0) _abort("no queue families"); + if (queue_family_count == 0) { _abort("no queue families"); } VkQueueFamilyProperties2Array qf_props = - wpArrayAllocCapacity(VkQueueFamilyProperties2, &_G_RHI_CONTEXT.scratch, queue_family_count, WP_ARRAY_INIT_FILLED); - if (!qf_props) _abort("alloc failed for queue family props"); + wpArrayAllocCapacity(VkQueueFamilyProperties2, &_G_RHI_CONTEXT.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) { qf_props[i].sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2; @@ -497,39 +531,35 @@ PrRhiDevice *prRhiCreateDeviceVk(PrRhiPhysicalDevice *pdev, PrRhiSurface *surfac break; } } - if (family_index == UINT32_MAX) _abort("no suitable queue family"); + if (family_index == UINT32_MAX) { _abort("no suitable queue family"); } // Check presentation support - VkBool32 present_supported = VK_FALSE; - _checkVk(vkGetPhysicalDeviceSurfaceSupportKHR(vk_pdev, family_index, vk_surface, &present_supported), - "vkGetPhysicalDeviceSurfaceSupportKHR"); - if (!present_supported) _abort("no presentation support"); + if (!SDL_Vulkan_GetPresentationSupport(pdev->instance->handle, pdev->handle, family_index)) { + _abort("No presentation support"); + } - wpArrayDealloc(VkQueueFamilyProperties2, &_G_RHI_CONTEXT.scratch, &qf_props); - - // Check device profile support - VkBool32 profile_supported = VK_FALSE; - _checkVk(vpGetPhysicalDeviceProfileSupport(vk_inst, vk_pdev, &_profile, &profile_supported), - "vpGetPhysicalDeviceProfileSupport"); - if (!profile_supported) _abort("device does not support profile"); + wpArrayDealloc(VkQueueFamilyProperties2, &_G_RHI_CONTEXT.allocator, &qf_props); // Create device f32 queue_priority = 1.0f; - VkDeviceQueueCreateInfo queue_create_info = {}; - queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queue_create_info.queueCount = 1; - queue_create_info.queueFamilyIndex = family_index; - queue_create_info.pQueuePriorities = &queue_priority; + VkDeviceQueueCreateInfo queue_create_info = { + .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + .queueCount = 1, + .queueFamilyIndex = family_index, + .pQueuePriorities = &queue_priority, + }; - VkDeviceCreateInfo device_info = {}; - device_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - device_info.queueCreateInfoCount = 1; - device_info.pQueueCreateInfos = &queue_create_info; + VkDeviceCreateInfo device_info = { + .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + .queueCreateInfoCount = 1, + .pQueueCreateInfos = &queue_create_info, + }; - VpDeviceCreateInfo vp_device_info = {}; - vp_device_info.pCreateInfo = &device_info; - vp_device_info.enabledFullProfileCount = 1; - vp_device_info.pEnabledFullProfiles = &_profile; + VpDeviceCreateInfo vp_device_info = { + .pCreateInfo = &device_info, + .enabledFullProfileCount = 1, + .pEnabledFullProfiles = &_profile, + }; VkDevice vk_device = VK_NULL_HANDLE; _checkVk(vpCreateDevice(vk_pdev, &vp_device_info, NULL, &vk_device), "vpCreateDevice"); @@ -540,41 +570,43 @@ PrRhiDevice *prRhiCreateDeviceVk(PrRhiPhysicalDevice *pdev, PrRhiSurface *surfac vkGetDeviceQueue(vk_device, family_index, 0, &vk_queue); // Create VMA allocator - VmaVulkanFunctions vk_functions = {}; - vk_functions.vkGetInstanceProcAddr = vkGetInstanceProcAddr; - vk_functions.vkGetDeviceProcAddr = vkGetDeviceProcAddr; - vk_functions.vkCreateImage = vkCreateImage; + VmaVulkanFunctions vk_functions = { + .vkGetInstanceProcAddr = vkGetInstanceProcAddr, + .vkGetDeviceProcAddr = vkGetDeviceProcAddr, + .vkCreateImage = vkCreateImage, + }; - VmaAllocatorCreateInfo vma_info = {}; - vma_info.flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT | - VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT | - VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT; - vma_info.instance = vk_inst; - vma_info.physicalDevice = vk_pdev; - vma_info.device = vk_device; - vma_info.pVulkanFunctions = &vk_functions; + VmaAllocatorCreateInfo vma_info = { + .flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT | + VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT | + VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT, + .instance = vk_inst, + .physicalDevice = vk_pdev, + .device = vk_device, + .pVulkanFunctions = &vk_functions, + }; VmaAllocator vma_allocator = VK_NULL_HANDLE; _checkVk(vmaCreateAllocator(&vma_info, &vma_allocator), "vmaCreateAllocator"); - PrRhiDevice *device = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.main, sizeof(PrRhiDevice)); - if (!device) _abort("alloc failed for PrRhiDevice"); - device->handle = vk_device; - device->queue = vk_queue; + PrRhiDevice *device = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.allocator, sizeof(PrRhiDevice)); + if (!device) { _abort("alloc failed for PrRhiDevice"); } + device->handle = vk_device; + device->queue = vk_queue; device->queue_family_index = family_index; - device->present_mode = _toVkPresentMode(desc.present_mode); - device->physical_device = vk_pdev; - device->allocator = vma_allocator; + device->present_mode = _toVkPresentMode(desc.present_mode); + device->physical_device = vk_pdev; + device->allocator = vma_allocator; return device; } void prRhiDestroyDeviceVk(PrRhiDevice *device) { - if (!device) return; - vkDeviceWaitIdle((VkDevice)device->handle); - vmaDestroyAllocator((VmaAllocator)device->allocator); - vkDestroyDevice((VkDevice)device->handle, NULL); - wpMemAllocatorFree(&_G_RHI_CONTEXT.main, (void**)&device, sizeof(PrRhiDevice)); + if (!device) { return; } + vkDeviceWaitIdle(device->handle); + vmaDestroyAllocator(device->allocator); + vkDestroyDevice(device->handle, NULL); + wpMemAllocatorFree(&_G_RHI_CONTEXT.allocator, (void**)&device, sizeof(PrRhiDevice)); } void prRhiDeviceWaitIdleVk(PrRhiDevice *device) { @@ -590,10 +622,10 @@ u32 prRhiGetQueueFamilyIndexVk(PrRhiDevice *device) { // ============================================================================ static PrRhiTexture *_createSwapchainTexture(PrRhiDevice *device, VkImage vk_image, - VkFormat vk_format, u32 width, u32 height, - VkImageView vk_view) { - PrRhiTexture *tex = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.main, sizeof(PrRhiTexture)); - if (!tex) _abort("alloc failed for swapchain texture"); + VkFormat vk_format, u32 width, u32 height, + VkImageView vk_view) { + PrRhiTexture *tex = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.allocator, sizeof(PrRhiTexture)); + if (!tex) { _abort("alloc failed for swapchain texture"); } tex->image = vk_image; tex->view = vk_view; tex->allocation = NULL; @@ -604,8 +636,8 @@ static PrRhiTexture *_createSwapchainTexture(PrRhiDevice *device, VkImage vk_ima } static VkFormat _pickDepthFormat(VkPhysicalDevice vk_pdev) { - const VkFormat candidates[] = { VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT }; - for (u32 i = 0; i < (u32)(sizeof(candidates) / sizeof(candidates[0])); ++i) { + const VkFormatArray candidates = wpArray(VkFormat, VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT); + for (u32 i = 0; i < wpArrayCount(candidates); ++i) { VkFormatProperties2 props = { .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2 }; vkGetPhysicalDeviceFormatProperties2(vk_pdev, candidates[i], &props); if (props.formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) { @@ -616,9 +648,9 @@ static VkFormat _pickDepthFormat(VkPhysicalDevice vk_pdev) { } PrRhiSwapchain *prRhiCreateSwapchainVk(PrRhiDevice *device, PrRhiSwapchainDesc desc) { - VkDevice vk_device = (VkDevice)device->handle; - VkPhysicalDevice vk_pdev = (VkPhysicalDevice)device->physical_device; - VkSurfaceKHR vk_surface = (VkSurfaceKHR)desc.surface->handle; + VkDevice vk_device = device->handle; + VkPhysicalDevice vk_pdev = device->physical_device; + VkSurfaceKHR vk_surface = desc.surface->handle; VkSurfaceCapabilitiesKHR caps = {}; _checkVk(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vk_pdev, vk_surface, &caps), @@ -630,18 +662,22 @@ PrRhiSwapchain *prRhiCreateSwapchainVk(PrRhiDevice *device, PrRhiSwapchainDesc d extent.height = desc.height; } - VkSwapchainCreateInfoKHR swapchain_info = {}; - swapchain_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - swapchain_info.surface = vk_surface; - swapchain_info.minImageCount = caps.minImageCount; - swapchain_info.imageFormat = _default_image_format; - swapchain_info.imageColorSpace = _default_colorspace; - swapchain_info.imageExtent = extent; - swapchain_info.imageArrayLayers = 1; - swapchain_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - swapchain_info.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; - swapchain_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - swapchain_info.presentMode = (VkPresentModeKHR)device->present_mode; + VkSwapchainCreateInfoKHR swapchain_info = { + .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, + .surface = vk_surface, + .minImageCount = caps.minImageCount, + .imageFormat = _default_image_format, + .imageColorSpace = _default_colorspace, + .imageExtent = extent, + .imageArrayLayers = 1, + .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 1, + .pQueueFamilyIndices = &device->queue_family_index, + .preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR, + .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + .presentMode = device->present_mode, + }; VkSwapchainKHR vk_swapchain = VK_NULL_HANDLE; _checkVk(vkCreateSwapchainKHR(vk_device, &swapchain_info, NULL, &vk_swapchain), @@ -651,37 +687,38 @@ PrRhiSwapchain *prRhiCreateSwapchainVk(PrRhiDevice *device, PrRhiSwapchainDesc d _checkVk(vkGetSwapchainImagesKHR(vk_device, vk_swapchain, &image_count, NULL), "vkGetSwapchainImagesKHR"); - VkImageArray vk_images = wpArrayAllocCapacity(VkImage, &_G_RHI_CONTEXT.scratch, image_count, WP_ARRAY_INIT_FILLED); - if (!vk_images) _abort("alloc failed for swapchain VkImage array"); + VkImageArray vk_images = wpArrayAllocCapacity(VkImage, &_G_RHI_CONTEXT.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 *, &_G_RHI_CONTEXT.main, image_count, WP_ARRAY_INIT_NONE); - if (!images) _abort("alloc failed for swapchain image array"); + PrRhiTextureArray images = wpArrayAllocCapacity(PrRhiTexture *, &_G_RHI_CONTEXT.allocator, image_count, WP_ARRAY_INIT_NONE); + if (!images) { _abort("alloc failed for swapchain image array"); } for (u32 i = 0; i < image_count; ++i) { - VkImageViewCreateInfo view_info = {}; - view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - view_info.image = vk_images[i]; - view_info.viewType = VK_IMAGE_VIEW_TYPE_2D; - view_info.format = _default_image_format; - view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - view_info.subresourceRange.levelCount = 1; - view_info.subresourceRange.layerCount = 1; + VkImageViewCreateInfo view_info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .image = vk_images[i], + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = _default_image_format, + .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .subresourceRange.levelCount = 1, + .subresourceRange.layerCount = 1, + }; VkImageView vk_view = VK_NULL_HANDLE; _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); + extent.width, extent.height, vk_view); wpArrayAppendCapped(PrRhiTexture *, images, &tex); } - wpArrayDealloc(VkImage, &_G_RHI_CONTEXT.scratch, &vk_images); + wpArrayDealloc(VkImage, &_G_RHI_CONTEXT.allocator, &vk_images); - PrRhiSwapchain *swapchain = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.main, sizeof(PrRhiSwapchain)); - if (!swapchain) _abort("alloc failed for PrRhiSwapchain"); + PrRhiSwapchain *swapchain = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.allocator, sizeof(PrRhiSwapchain)); + if (!swapchain) { _abort("alloc failed for PrRhiSwapchain"); } swapchain->device = device; swapchain->handle = vk_swapchain; swapchain->surface = desc.surface; @@ -702,46 +739,52 @@ PrRhiSwapchain *prRhiCreateSwapchainVk(PrRhiDevice *device, PrRhiSwapchainDesc d } else { depth_pick_fmt = _pickDepthFormat(vk_pdev); } - if (depth_pick_fmt == VK_FORMAT_UNDEFINED) _abort("no suitable depth format"); + if (depth_pick_fmt == VK_FORMAT_UNDEFINED) { _abort("no suitable depth format"); } - VkImageCreateInfo depth_img_info = {}; - depth_img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - depth_img_info.imageType = VK_IMAGE_TYPE_2D; - depth_img_info.format = depth_pick_fmt; - depth_img_info.extent.width = extent.width; - depth_img_info.extent.height = extent.height; - depth_img_info.extent.depth = 1; - depth_img_info.mipLevels = 1; - depth_img_info.arrayLayers = 1; - depth_img_info.samples = VK_SAMPLE_COUNT_1_BIT; - depth_img_info.tiling = VK_IMAGE_TILING_OPTIMAL; - depth_img_info.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; - depth_img_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + VkImageCreateInfo depth_img_info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .imageType = VK_IMAGE_TYPE_2D, + .format = depth_pick_fmt, + .extent.width = extent.width, + .extent.height = extent.height, + .extent.depth = 1, + .mipLevels = 1, + .arrayLayers = 1, + .samples = VK_SAMPLE_COUNT_1_BIT, + .tiling = VK_IMAGE_TILING_OPTIMAL, + .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 1, + .pQueueFamilyIndices = &device->queue_family_index, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + }; - VmaAllocationCreateInfo depth_alloc_info = {}; - depth_alloc_info.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; - depth_alloc_info.usage = VMA_MEMORY_USAGE_AUTO; + VmaAllocationCreateInfo depth_alloc_info = { + .flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT, + .usage = VMA_MEMORY_USAGE_AUTO, + }; - VkImage depth_image = VK_NULL_HANDLE; + VkImage depth_image = VK_NULL_HANDLE; VmaAllocation depth_allocation = VK_NULL_HANDLE; _checkVk(vmaCreateImage((VmaAllocator)device->allocator, &depth_img_info, &depth_alloc_info, - &depth_image, &depth_allocation, NULL), + &depth_image, &depth_allocation, NULL), "vmaCreateImage (depth)"); - VkImageViewCreateInfo depth_view_info = {}; - depth_view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - depth_view_info.image = depth_image; - depth_view_info.viewType = VK_IMAGE_VIEW_TYPE_2D; - depth_view_info.format = depth_pick_fmt; - depth_view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - depth_view_info.subresourceRange.levelCount = 1; - depth_view_info.subresourceRange.layerCount = 1; + VkImageViewCreateInfo depth_view_info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .image = depth_image, + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = depth_pick_fmt, + .subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT, + .subresourceRange.levelCount = 1, + .subresourceRange.layerCount = 1, + }; VkImageView depth_view = VK_NULL_HANDLE; _checkVk(vkCreateImageView(vk_device, &depth_view_info, NULL, &depth_view), "vkCreateImageView (depth)"); - PrRhiTexture *depth_tex = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.main, sizeof(PrRhiTexture)); - if (!depth_tex) _abort("alloc failed for depth texture"); + PrRhiTexture *depth_tex = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.allocator, sizeof(PrRhiTexture)); + if (!depth_tex) { _abort("alloc failed for depth texture"); } depth_tex->image = depth_image; depth_tex->view = depth_view; depth_tex->allocation = depth_allocation; @@ -757,86 +800,89 @@ PrRhiSwapchain *prRhiCreateSwapchainVk(PrRhiDevice *device, PrRhiSwapchainDesc d } void prRhiDestroySwapchainVk(PrRhiDevice *device, PrRhiSwapchain *swapchain) { - if (!swapchain) return; + if (!swapchain) { return; } - VkDevice vk_device = (VkDevice)device->handle; + VkDevice vk_device = device->handle; // Destroy per-image views and PrRhiTexture structs for (u32 i = 0; i < swapchain->image_count; ++i) { PrRhiTexture *tex = swapchain->images[i]; - vkDestroyImageView(vk_device, (VkImageView)tex->view, NULL); + vkDestroyImageView(vk_device, tex->view, NULL); // VkImage is owned by swapchain — skip vmaDestroyImage - wpMemAllocatorFree(&_G_RHI_CONTEXT.main, (void**)&tex, sizeof(PrRhiTexture)); + wpMemAllocatorFree(&_G_RHI_CONTEXT.allocator, (void**)&tex, sizeof(PrRhiTexture)); } - wpArrayDealloc(PrRhiTexture *, &_G_RHI_CONTEXT.main, &swapchain->images); + wpArrayDealloc(PrRhiTexture *, &_G_RHI_CONTEXT.allocator, &swapchain->images); // Destroy depth if (swapchain->depth) { PrRhiTexture *depth = swapchain->depth; - vkDestroyImageView(vk_device, (VkImageView)depth->view, NULL); - vmaDestroyImage((VmaAllocator)device->allocator, (VkImage)depth->image, - (VmaAllocation)depth->allocation); - wpMemAllocatorFree(&_G_RHI_CONTEXT.main, (void**)&depth, sizeof(PrRhiTexture)); + vkDestroyImageView(vk_device, depth->view, NULL); + vmaDestroyImage(device->allocator, depth->image, depth->allocation); + wpMemAllocatorFree(&_G_RHI_CONTEXT.allocator, (void**)&depth, sizeof(PrRhiTexture)); } - vkDestroySwapchainKHR(vk_device, (VkSwapchainKHR)swapchain->handle, NULL); - wpMemAllocatorFree(&_G_RHI_CONTEXT.main, (void**)&swapchain, sizeof(PrRhiSwapchain)); + vkDestroySwapchainKHR(vk_device, swapchain->handle, NULL); + wpMemAllocatorFree(&_G_RHI_CONTEXT.allocator, (void**)&swapchain, sizeof(PrRhiSwapchain)); +} + +u32 prRhiGetSwapchainImageCountVk(PrRhiSwapchain *swapchain) { + return swapchain->image_count; } PrRhiSwapchainResult prRhiAcquireNextImageVk(PrRhiDevice *device, PrRhiSwapchain *swapchain, - PrRhiSemaphore *signal_semaphore, u32 *out_image_index) { - VkSemaphore vk_semaphore = signal_semaphore ? (VkSemaphore)signal_semaphore->handle : VK_NULL_HANDLE; - VkResult res = vkAcquireNextImageKHR((VkDevice)device->handle, - (VkSwapchainKHR)swapchain->handle, - UINT64_MAX, vk_semaphore, VK_NULL_HANDLE, - &swapchain->current_image_index); - if (res == VK_ERROR_OUT_OF_DATE_KHR) return PR_RHI_SWAPCHAIN_OUT_OF_DATE; + PrRhiSemaphore *signal_semaphore, u32 *out_image_index) { + VkSemaphore vk_semaphore = signal_semaphore ? signal_semaphore->handle : VK_NULL_HANDLE; + VkResult res = vkAcquireNextImageKHR(device->handle, swapchain->handle, UINT64_MAX, vk_semaphore, + VK_NULL_HANDLE, &swapchain->current_image_index); + if (res == VK_ERROR_OUT_OF_DATE_KHR) { return PR_RHI_SWAPCHAIN_OUT_OF_DATE; } _checkVk(res, "vkAcquireNextImageKHR"); - if (out_image_index) *out_image_index = swapchain->current_image_index; + if (out_image_index) { *out_image_index = swapchain->current_image_index; } return PR_RHI_SWAPCHAIN_SUCCESS; } PrRhiSwapchainResult prRhiPresentVk(PrRhiDevice *device, PrRhiSwapchain *swapchain, - PrRhiSemaphore *wait_semaphore) { - VkSemaphore vk_semaphore = wait_semaphore ? (VkSemaphore)wait_semaphore->handle : VK_NULL_HANDLE; + PrRhiSemaphore *wait_semaphore) { + VkSemaphore vk_semaphore = wait_semaphore ? wait_semaphore->handle : VK_NULL_HANDLE; - VkPresentInfoKHR present_info = {}; - present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; - present_info.waitSemaphoreCount = wait_semaphore ? 1 : 0; - present_info.pWaitSemaphores = &vk_semaphore; - present_info.swapchainCount = 1; - present_info.pSwapchains = (VkSwapchainKHR *)&swapchain->handle; - present_info.pImageIndices = &swapchain->current_image_index; + VkPresentInfoKHR present_info = { + .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, + .waitSemaphoreCount = wait_semaphore ? 1 : 0, + .pWaitSemaphores = &vk_semaphore, + .swapchainCount = 1, + .pSwapchains = &swapchain->handle, + .pImageIndices = &swapchain->current_image_index, + }; - VkResult res = vkQueuePresentKHR((VkQueue)device->queue, &present_info); - if (res == VK_ERROR_OUT_OF_DATE_KHR) return PR_RHI_SWAPCHAIN_OUT_OF_DATE; + VkResult res = vkQueuePresentKHR(device->queue, &present_info); + if (res == VK_ERROR_OUT_OF_DATE_KHR) { return PR_RHI_SWAPCHAIN_OUT_OF_DATE; } _checkVk(res, "vkQueuePresentKHR"); return PR_RHI_SWAPCHAIN_SUCCESS; } void prRhiRecreateSwapchainVk(PrRhiDevice *device, PrRhiSwapchain **swapchain, - u32 width, u32 height) { + u32 width, u32 height) { PrRhiSwapchain *old = *swapchain; - if (!old) return; + if (!old) { return; } - VkDevice vk_device = (VkDevice)device->handle; - VkPhysicalDevice vk_pdev = (VkPhysicalDevice)device->physical_device; + VkDevice vk_device = device->handle; + VkPhysicalDevice vk_pdev = device->physical_device; VkExtent2D extent = { width, height }; - VkSwapchainCreateInfoKHR swapchain_info = {}; - swapchain_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - swapchain_info.oldSwapchain = (VkSwapchainKHR)old->handle; - swapchain_info.surface = (VkSurfaceKHR)((PrRhiSurface *)old->surface)->handle; - swapchain_info.minImageCount = old->image_count; - swapchain_info.imageFormat = (VkFormat)old->format; - swapchain_info.imageColorSpace = _default_colorspace; - swapchain_info.imageExtent = extent; - swapchain_info.imageArrayLayers = 1; - swapchain_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - swapchain_info.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; - swapchain_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - swapchain_info.presentMode = (VkPresentModeKHR)device->present_mode; + VkSwapchainCreateInfoKHR swapchain_info = { + .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, + .oldSwapchain = old->handle, + .surface = ((PrRhiSurface *)old->surface)->handle, + .minImageCount = old->image_count, + .imageFormat = (VkFormat)old->format, + .imageColorSpace = _default_colorspace, + .imageExtent = extent, + .imageArrayLayers = 1, + .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + .preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR, + .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + .presentMode = (VkPresentModeKHR)device->present_mode, + }; VkSwapchainKHR vk_new_swapchain = VK_NULL_HANDLE; _checkVk(vkCreateSwapchainKHR(vk_device, &swapchain_info, NULL, &vk_new_swapchain), @@ -845,108 +891,111 @@ void prRhiRecreateSwapchainVk(PrRhiDevice *device, PrRhiSwapchain **swapchain, // Destroy old image views and PrRhiTexture structs (but not VkImages — owned by old swapchain) for (u32 i = 0; i < old->image_count; ++i) { PrRhiTexture *tex = old->images[i]; - vkDestroyImageView(vk_device, (VkImageView)tex->view, NULL); - wpMemAllocatorFree(&_G_RHI_CONTEXT.main, (void**)&tex, sizeof(PrRhiTexture)); + vkDestroyImageView(vk_device, tex->view, NULL); + wpMemAllocatorFree(&_G_RHI_CONTEXT.allocator, (void**)&tex, sizeof(PrRhiTexture)); } - wpArrayDealloc(PrRhiTexture *, &_G_RHI_CONTEXT.main, &old->images); + wpArrayDealloc(PrRhiTexture *, &_G_RHI_CONTEXT.allocator, &old->images); // Destroy old depth if (old->depth) { PrRhiTexture *depth = old->depth; - vkDestroyImageView(vk_device, (VkImageView)depth->view, NULL); - vmaDestroyImage((VmaAllocator)device->allocator, (VkImage)depth->image, - (VmaAllocation)depth->allocation); - wpMemAllocatorFree(&_G_RHI_CONTEXT.main, (void**)&depth, sizeof(PrRhiTexture)); + vkDestroyImageView(vk_device, depth->view, NULL); + vmaDestroyImage(device->allocator, depth->image, depth->allocation); + wpMemAllocatorFree(&_G_RHI_CONTEXT.allocator, (void**)&depth, sizeof(PrRhiTexture)); } // Destroy old swapchain - vkDestroySwapchainKHR(vk_device, (VkSwapchainKHR)old->handle, NULL); + vkDestroySwapchainKHR(vk_device, old->handle, NULL); // Get new swapchain images u32 new_image_count = 0; _checkVk(vkGetSwapchainImagesKHR(vk_device, vk_new_swapchain, &new_image_count, NULL), "vkGetSwapchainImagesKHR (recreate)"); - VkImageArray vk_images = wpArrayAllocCapacity(VkImage, &_G_RHI_CONTEXT.scratch, new_image_count, WP_ARRAY_INIT_FILLED); - if (!vk_images) _abort("alloc failed for swapchain VkImage array (recreate)"); + VkImageArray vk_images = wpArrayAllocCapacity(VkImage, &_G_RHI_CONTEXT.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 *, &_G_RHI_CONTEXT.main, new_image_count, WP_ARRAY_INIT_NONE); - if (!new_images) _abort("alloc failed for swapchain image array (recreate)"); + PrRhiTextureArray new_images = wpArrayAllocCapacity(PrRhiTexture *, &_G_RHI_CONTEXT.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) { - VkImageViewCreateInfo view_info = {}; - view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - view_info.image = vk_images[i]; - view_info.viewType = VK_IMAGE_VIEW_TYPE_2D; - view_info.format = (VkFormat)old->format; - view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - view_info.subresourceRange.levelCount = 1; - view_info.subresourceRange.layerCount = 1; + VkImageViewCreateInfo view_info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .image = vk_images[i], + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = (VkFormat)old->format, + .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .subresourceRange.levelCount = 1, + .subresourceRange.layerCount = 1, + }; VkImageView vk_view = VK_NULL_HANDLE; _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); + PrRhiTexture *tex = _createSwapchainTexture(device, vk_images[i], old->format, extent.width, + extent.height, vk_view); wpArrayAppendCapped(PrRhiTexture *, new_images, &tex); } - wpArrayDealloc(VkImage, &_G_RHI_CONTEXT.scratch, &vk_images); + wpArrayDealloc(VkImage, &_G_RHI_CONTEXT.allocator, &vk_images); // Recreate depth PrRhiTexture *new_depth = NULL; { - VkFormat depth_fmt = old->depth_format ? (VkFormat)old->depth_format : _pickDepthFormat(vk_pdev); - if (depth_fmt == VK_FORMAT_UNDEFINED) _abort("no suitable depth format (recreate)"); + VkFormat depth_fmt = old->depth_format ? old->depth_format : _pickDepthFormat(vk_pdev); + if (depth_fmt == VK_FORMAT_UNDEFINED) { _abort("no suitable depth format (recreate)"); } - VkImageCreateInfo depth_img_info = {}; - depth_img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - depth_img_info.imageType = VK_IMAGE_TYPE_2D; - depth_img_info.format = depth_fmt; - depth_img_info.extent.width = extent.width; - depth_img_info.extent.height = extent.height; - depth_img_info.extent.depth = 1; - depth_img_info.mipLevels = 1; - depth_img_info.arrayLayers = 1; - depth_img_info.samples = VK_SAMPLE_COUNT_1_BIT; - depth_img_info.tiling = VK_IMAGE_TILING_OPTIMAL; - depth_img_info.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; - depth_img_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + VkImageCreateInfo depth_img_info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .imageType = VK_IMAGE_TYPE_2D, + .format = depth_fmt, + .extent.width = extent.width, + .extent.height = extent.height, + .extent.depth = 1, + .mipLevels = 1, + .arrayLayers = 1, + .samples = VK_SAMPLE_COUNT_1_BIT, + .tiling = VK_IMAGE_TILING_OPTIMAL, + .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + }; - VmaAllocationCreateInfo depth_alloc_info = {}; - depth_alloc_info.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; - depth_alloc_info.usage = VMA_MEMORY_USAGE_AUTO; + VmaAllocationCreateInfo depth_alloc_info = { + .flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT, + .usage = VMA_MEMORY_USAGE_AUTO, + }; VkImage depth_image = VK_NULL_HANDLE; VmaAllocation depth_allocation = VK_NULL_HANDLE; - _checkVk(vmaCreateImage((VmaAllocator)device->allocator, &depth_img_info, &depth_alloc_info, - &depth_image, &depth_allocation, NULL), + _checkVk(vmaCreateImage(device->allocator, &depth_img_info, &depth_alloc_info, &depth_image, + &depth_allocation, NULL), "vmaCreateImage (depth recreate)"); - VkImageViewCreateInfo depth_view_info = {}; - depth_view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - depth_view_info.image = depth_image; - depth_view_info.viewType = VK_IMAGE_VIEW_TYPE_2D; - depth_view_info.format = depth_fmt; - depth_view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - depth_view_info.subresourceRange.levelCount = 1; - depth_view_info.subresourceRange.layerCount = 1; + VkImageViewCreateInfo depth_view_info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .image = depth_image, + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = depth_fmt, + .subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT, + .subresourceRange.levelCount = 1, + .subresourceRange.layerCount = 1, + }; VkImageView depth_view = VK_NULL_HANDLE; _checkVk(vkCreateImageView(vk_device, &depth_view_info, NULL, &depth_view), "vkCreateImageView (depth recreate)"); - new_depth = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.main, sizeof(PrRhiTexture)); - if (!new_depth) _abort("alloc failed for depth texture (recreate)"); + new_depth = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.allocator, sizeof(PrRhiTexture)); + if (!new_depth) { _abort("alloc failed for depth texture (recreate)"); } new_depth->image = depth_image; new_depth->view = depth_view; new_depth->allocation = depth_allocation; - new_depth->width = extent.width; - new_depth->height = extent.height; - new_depth->format = depth_fmt; - old->depth_format = depth_fmt; + new_depth->width = extent.width; + new_depth->height = extent.height; + new_depth->format = depth_fmt; + old->depth_format = depth_fmt; } // Update old swapchain in-place @@ -962,7 +1011,7 @@ void prRhiRecreateSwapchainVk(PrRhiDevice *device, PrRhiSwapchain **swapchain, } PrRhiTexture *prRhiGetSwapchainTextureVk(PrRhiSwapchain *swapchain, u32 image_index) { - if (image_index >= swapchain->image_count) return NULL; + if (image_index >= swapchain->image_count) { return NULL; } return swapchain->images[image_index]; } @@ -979,10 +1028,11 @@ PrRhiFormat prRhiGetSwapchainFormatVk(PrRhiSwapchain *swapchain) { // ============================================================================ PrRhiBuffer *prRhiCreateBufferVk(PrRhiDevice *device, PrRhiBufferDesc desc) { - VkBufferCreateInfo buf_info = {}; - buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - buf_info.size = desc.size; - buf_info.usage = _toVkBufferUsage(desc.usage); + VkBufferCreateInfo buf_info = { + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .size = desc.size, + .usage = _toVkBufferUsage(desc.usage), + }; // For device address, we need VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT VkBufferUsageFlags2CreateInfo usage_flags2 = {}; @@ -992,41 +1042,41 @@ PrRhiBuffer *prRhiCreateBufferVk(PrRhiDevice *device, PrRhiBufferDesc desc) { buf_info.pNext = &usage_flags2; } - VmaAllocationCreateInfo alloc_info = {}; - alloc_info.flags = _toVmaFlags(desc.memory); - alloc_info.usage = VMA_MEMORY_USAGE_AUTO; + VmaAllocationCreateInfo alloc_info = { + .flags = _toVmaFlags(desc.memory), + .usage = VMA_MEMORY_USAGE_AUTO, + }; - VkBuffer vk_buffer = VK_NULL_HANDLE; - VmaAllocation vma_alloc = VK_NULL_HANDLE; + VkBuffer vk_buffer = VK_NULL_HANDLE; + VmaAllocation vma_alloc = VK_NULL_HANDLE; VmaAllocationInfo vma_alloc_info = {}; - _checkVk(vmaCreateBuffer((VmaAllocator)device->allocator, &buf_info, &alloc_info, - &vk_buffer, &vma_alloc, &vma_alloc_info), + _checkVk(vmaCreateBuffer(device->allocator, &buf_info, &alloc_info, &vk_buffer, &vma_alloc, &vma_alloc_info), "vmaCreateBuffer"); - PrRhiBuffer *buffer = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.main, sizeof(PrRhiBuffer)); - if (!buffer) _abort("alloc failed for PrRhiBuffer"); + PrRhiBuffer *buffer = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.allocator, sizeof(PrRhiBuffer)); + if (!buffer) { _abort("alloc failed for PrRhiBuffer"); } buffer->handle = vk_buffer; buffer->allocation = vma_alloc; - buffer->size = desc.size; + buffer->size = vma_alloc_info.size; buffer->mapped_data = vma_alloc_info.pMappedData; buffer->device_address = 0; // Query device address if needed if (desc.usage & PR_RHI_BUFFER_USAGE_SHADER_DEVICE_ADDRESS) { - VkBufferDeviceAddressInfo addr_info = {}; - addr_info.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; - addr_info.buffer = vk_buffer; - buffer->device_address = vkGetBufferDeviceAddress((VkDevice)device->handle, &addr_info); + VkBufferDeviceAddressInfo addr_info = { + .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, + .buffer = vk_buffer, + }; + buffer->device_address = vkGetBufferDeviceAddress(device->handle, &addr_info); } return buffer; } void prRhiDestroyBufferVk(PrRhiDevice *device, PrRhiBuffer *buffer) { - if (!buffer) return; - vmaDestroyBuffer((VmaAllocator)device->allocator, (VkBuffer)buffer->handle, - (VmaAllocation)buffer->allocation); - wpMemAllocatorFree(&_G_RHI_CONTEXT.main, (void**)&buffer, sizeof(PrRhiBuffer)); + if (!buffer) { return; } + vmaDestroyBuffer(device->allocator, buffer->handle, buffer->allocation); + wpMemAllocatorFree(&_G_RHI_CONTEXT.allocator, (void**)&buffer, sizeof(PrRhiBuffer)); } void *prRhiBufferMapVk(PrRhiDevice *device, PrRhiBuffer *buffer) { @@ -1050,22 +1100,22 @@ PrRhiDeviceAddress prRhiGetBufferDeviceAddressVk(PrRhiDevice *device, PrRhiBuffe // ============================================================================ PrRhiTexture *prRhiCreateTextureVk(PrRhiDevice *device, PrRhiTextureDesc desc) { - VkImageCreateInfo img_info = {}; - img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - img_info.imageType = VK_IMAGE_TYPE_2D; - img_info.format = _toVkFormat(desc.format); - img_info.extent.width = desc.width; - img_info.extent.height = desc.height; - img_info.extent.depth = 1; - img_info.mipLevels = desc.mip_levels; - img_info.arrayLayers = 1; - img_info.samples = VK_SAMPLE_COUNT_1_BIT; - img_info.tiling = VK_IMAGE_TILING_OPTIMAL; - img_info.usage = _toVkTextureUsage(desc.usage); - img_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + VkImageCreateInfo img_info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .imageType = VK_IMAGE_TYPE_2D, + .format = _toVkFormat(desc.format), + .extent.width = desc.width, + .extent.height = desc.height, + .extent.depth = 1, + .mipLevels = desc.mip_levels, + .arrayLayers = 1, + .samples = VK_SAMPLE_COUNT_1_BIT, + .tiling = VK_IMAGE_TILING_OPTIMAL, + .usage = _toVkTextureUsage(desc.usage), + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + }; - VmaAllocationCreateInfo alloc_info = {}; - alloc_info.usage = VMA_MEMORY_USAGE_AUTO; + VmaAllocationCreateInfo alloc_info = { .usage = VMA_MEMORY_USAGE_AUTO }; VkImage vk_image = VK_NULL_HANDLE; VmaAllocation vma_alloc = VK_NULL_HANDLE; @@ -1078,21 +1128,22 @@ PrRhiTexture *prRhiCreateTextureVk(PrRhiDevice *device, PrRhiTextureDesc desc) { aspect_mask = VK_IMAGE_ASPECT_DEPTH_BIT; } - 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 = _toVkFormat(desc.format); - view_info.subresourceRange.aspectMask = aspect_mask; - view_info.subresourceRange.levelCount = desc.mip_levels; - view_info.subresourceRange.layerCount = 1; + VkImageViewCreateInfo view_info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .image = vk_image, + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = _toVkFormat(desc.format), + .subresourceRange.aspectMask = aspect_mask, + .subresourceRange.levelCount = desc.mip_levels, + .subresourceRange.layerCount = 1, + }; VkImageView vk_view = VK_NULL_HANDLE; _checkVk(vkCreateImageView((VkDevice)device->handle, &view_info, NULL, &vk_view), "vkCreateImageView"); - PrRhiTexture *texture = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.main, sizeof(PrRhiTexture)); - if (!texture) _abort("alloc failed for PrRhiTexture"); + PrRhiTexture *texture = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.allocator, sizeof(PrRhiTexture)); + if (!texture) { _abort("alloc failed for PrRhiTexture"); } texture->image = vk_image; texture->view = vk_view; texture->allocation = vma_alloc; @@ -1104,56 +1155,56 @@ PrRhiTexture *prRhiCreateTextureVk(PrRhiDevice *device, PrRhiTextureDesc desc) { } PrRhiTexture *prRhiCreateTextureFromKtxVk(PrRhiDevice *device, const char *path, - PrRhiCommandPool *pool, PrRhiCommandBuffer *cb) { - VkDevice vk_device = (VkDevice)device->handle; + PrRhiCommandPool *pool, PrRhiCommandBuffer *cb) { + VkDevice vk_device = 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"); + 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; + 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); + void *data = ktxTexture_GetData(ktx); PrRhiBufferDesc buf_desc = { - .size = data_size, - .usage = PR_RHI_BUFFER_USAGE_TRANSFER_SRC, + .size = data_size, + .usage = PR_RHI_BUFFER_USAGE_TRANSFER_SRC, .memory = PR_RHI_MEMORY_CPU_TO_GPU, }; PrRhiBuffer *staging = prRhiCreateBufferVk(device, buf_desc); 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; + VkImageCreateInfo img_info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .imageType = VK_IMAGE_TYPE_2D, + .format = vk_format, + .extent.width = width, + .extent.height = height, + .extent.depth = 1, + .mipLevels = mip_levels, + .arrayLayers = 1, + .samples = VK_SAMPLE_COUNT_1_BIT, + .tiling = VK_IMAGE_TILING_OPTIMAL, + .usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + }; - VmaAllocationCreateInfo alloc_info = {}; - alloc_info.usage = VMA_MEMORY_USAGE_AUTO; + VmaAllocationCreateInfo alloc_info = { .usage = VMA_MEMORY_USAGE_AUTO }; - VkImage vk_image = VK_NULL_HANDLE; + 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), + _checkVk(vmaCreateImage(device->allocator, &img_info, &alloc_info, &vk_image, &vma_alloc, NULL), "vmaCreateImage"); // Record copy commands - VkCommandBuffer vk_cb = (VkCommandBuffer)cb->handle; + VkCommandBuffer vk_cb = cb->handle; vkBeginCommandBuffer(vk_cb, &(VkCommandBufferBeginInfo){ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, @@ -1161,44 +1212,66 @@ PrRhiTexture *prRhiCreateTextureFromKtxVk(PrRhiDevice *device, const char *path, // Transition to TRANSFER_DST vkCmdPipelineBarrier2(vk_cb, &(VkDependencyInfo){ - .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .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, + .pImageMemoryBarriers = &(VkImageMemoryBarrier2){ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, + .srcStageMask = VK_PIPELINE_STAGE_2_NONE, + .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 }, - }); + VkBufferImageCopyArray copy_regions = wpArrayAllocCapacity(VkBufferImageCopy, &_G_RHI_CONTEXT.allocator, + mip_levels, WP_ARRAY_INIT_NONE); + for (u32 i = 0; i < mip_levels; ++i) { + ktx_size_t mip_offset = 0; + KTX_error_code ret = ktxTexture_GetImageOffset(ktx, i, 0, 0, &mip_offset); + + VkBufferImageCopy copy_region = { + .bufferOffset = mip_offset, + .imageSubresource = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .mipLevel = i, + .layerCount = 1, + }, + .imageExtent = { + .width = width >> i, + .height = height >>i, + .depth = 1, + }, + }; + + wpArrayAppendCapped(VkBufferImageCopy, copy_regions, ©_region); + } + + vkCmdCopyBufferToImage(vk_cb, staging->handle, vk_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + wpArrayCount(copy_regions), copy_regions); // Transition to SHADER_READ_ONLY vkCmdPipelineBarrier2(vk_cb, &(VkDependencyInfo){ - .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .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 }, + .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_READ_ONLY_OPTIMAL, + .image = vk_image, + .subresourceRange = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .levelCount = mip_levels, + .layerCount = 1, + }, }, }); @@ -1206,28 +1279,28 @@ PrRhiTexture *prRhiCreateTextureFromKtxVk(PrRhiDevice *device, const char *path, // Submit and wait PrRhiFenceDesc fence_desc = { .signaled = false }; - PrRhiFence *fence = prRhiCreateFenceVk(device, fence_desc); + PrRhiFence *fence = prRhiCreateFenceVk(device, fence_desc); prRhiQueueSubmitVk(device, cb, NULL, NULL, fence); - prRhiWaitForFencesVk(device, &(PrRhiFence *){ fence }, 1, VK_TRUE, UINT64_MAX); + prRhiWaitForFencesVk(device, &fence, 1, VK_TRUE, UINT64_MAX); prRhiDestroyFenceVk(device, fence); 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; + VkImageViewCreateInfo view_info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .image = vk_image, + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = vk_format, + .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .subresourceRange.levelCount = mip_levels, + .subresourceRange.layerCount = 1, + }; VkImageView vk_view = VK_NULL_HANDLE; - _checkVk(vkCreateImageView(vk_device, &view_info, NULL, &vk_view), - "vkCreateImageView"); + _checkVk(vkCreateImageView(vk_device, &view_info, NULL, &vk_view), "vkCreateImageView"); - PrRhiTexture *texture = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.main, sizeof(PrRhiTexture)); - if (!texture) _abort("alloc failed for PrRhiTexture"); + PrRhiTexture *texture = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.allocator, sizeof(PrRhiTexture)); + if (!texture) { _abort("alloc failed for PrRhiTexture"); } texture->image = vk_image; texture->view = vk_view; texture->allocation = vma_alloc; @@ -1243,15 +1316,14 @@ PrRhiTexture *prRhiCreateTextureFromKtxVk(PrRhiDevice *device, const char *path, } void prRhiDestroyTextureVk(PrRhiDevice *device, PrRhiTexture *texture) { - if (!texture) return; - VkDevice vk_device = (VkDevice)device->handle; + if (!texture) { return; } + VkDevice vk_device = device->handle; - vkDestroyImageView(vk_device, (VkImageView)texture->view, NULL); + vkDestroyImageView(vk_device, texture->view, NULL); if (texture->allocation) { - vmaDestroyImage((VmaAllocator)device->allocator, (VkImage)texture->image, - (VmaAllocation)texture->allocation); + vmaDestroyImage(device->allocator, texture->image, texture->allocation); } - wpMemAllocatorFree(&_G_RHI_CONTEXT.main, (void**)&texture, sizeof(PrRhiTexture)); + wpMemAllocatorFree(&_G_RHI_CONTEXT.allocator, (void**)&texture, sizeof(PrRhiTexture)); } // ============================================================================ @@ -1259,34 +1331,34 @@ void prRhiDestroyTextureVk(PrRhiDevice *device, PrRhiTexture *texture) { // ============================================================================ PrRhiSampler *prRhiCreateSamplerVk(PrRhiDevice *device, PrRhiSamplerDesc desc) { - VkSamplerCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; - info.magFilter = _toVkFilter(desc.mag_filter); - info.minFilter = _toVkFilter(desc.min_filter); - info.mipmapMode = _toVkMipmapMode(desc.mipmap_mode); - info.addressModeU = _toVkAddressMode(desc.address_mode_u); - info.addressModeV = _toVkAddressMode(desc.address_mode_v); - info.addressModeW = _toVkAddressMode(desc.address_mode_w); - info.anisotropyEnable = desc.max_anisotropy > 0.0f ? VK_TRUE : VK_FALSE; - info.maxAnisotropy = desc.max_anisotropy; - info.minLod = desc.min_lod; - info.maxLod = desc.max_lod; - info.mipLodBias = 0.0f; + VkSamplerCreateInfo info = { + .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, + .magFilter = _toVkFilter(desc.mag_filter), + .minFilter = _toVkFilter(desc.min_filter), + .mipmapMode = _toVkMipmapMode(desc.mipmap_mode), + .addressModeU = _toVkAddressMode(desc.address_mode_u), + .addressModeV = _toVkAddressMode(desc.address_mode_v), + .addressModeW = _toVkAddressMode(desc.address_mode_w), + .anisotropyEnable = desc.max_anisotropy > 0.0f ? VK_TRUE : VK_FALSE, + .maxAnisotropy = desc.max_anisotropy, + .minLod = desc.min_lod, + .maxLod = desc.max_lod, + .mipLodBias = 0.0f, + }; VkSampler vk_sampler = VK_NULL_HANDLE; - _checkVk(vkCreateSampler((VkDevice)device->handle, &info, NULL, &vk_sampler), - "vkCreateSampler"); + _checkVk(vkCreateSampler(device->handle, &info, NULL, &vk_sampler), "vkCreateSampler"); - PrRhiSampler *sampler = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.main, sizeof(PrRhiSampler)); - if (!sampler) _abort("alloc failed for PrRhiSampler"); + PrRhiSampler *sampler = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.allocator, sizeof(PrRhiSampler)); + if (!sampler) { _abort("alloc failed for PrRhiSampler"); } sampler->handle = vk_sampler; return sampler; } void prRhiDestroySamplerVk(PrRhiDevice *device, PrRhiSampler *sampler) { - if (!sampler) return; - vkDestroySampler((VkDevice)device->handle, (VkSampler)sampler->handle, NULL); - wpMemAllocatorFree(&_G_RHI_CONTEXT.main, (void**)&sampler, sizeof(PrRhiSampler)); + if (!sampler) { return; } + vkDestroySampler(device->handle, sampler->handle, NULL); + wpMemAllocatorFree(&_G_RHI_CONTEXT.allocator, (void**)&sampler, sizeof(PrRhiSampler)); } // ============================================================================ @@ -1294,25 +1366,25 @@ void prRhiDestroySamplerVk(PrRhiDevice *device, PrRhiSampler *sampler) { // ============================================================================ PrRhiShader *prRhiCreateShaderVk(PrRhiDevice *device, PrRhiShaderDesc desc) { - VkShaderModuleCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - info.codeSize = desc.spirv_size; - info.pCode = (const u32 *)desc.spirv_code; + VkShaderModuleCreateInfo info = { + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .codeSize = desc.spirv_size, + .pCode = (const u32 *)desc.spirv_code, + }; VkShaderModule vk_module = VK_NULL_HANDLE; - _checkVk(vkCreateShaderModule((VkDevice)device->handle, &info, NULL, &vk_module), - "vkCreateShaderModule"); + _checkVk(vkCreateShaderModule(device->handle, &info, NULL, &vk_module), "vkCreateShaderModule"); - PrRhiShader *shader = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.main, sizeof(PrRhiShader)); - if (!shader) _abort("alloc failed for PrRhiShader"); + PrRhiShader *shader = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.allocator, sizeof(PrRhiShader)); + if (!shader) { _abort("alloc failed for PrRhiShader"); } shader->handle = vk_module; return shader; } void prRhiDestroyShaderVk(PrRhiDevice *device, PrRhiShader *shader) { - if (!shader) return; - vkDestroyShaderModule((VkDevice)device->handle, (VkShaderModule)shader->handle, NULL); - wpMemAllocatorFree(&_G_RHI_CONTEXT.main, (void**)&shader, sizeof(PrRhiShader)); + if (!shader) { return; } + vkDestroyShaderModule(device->handle, shader->handle, NULL); + wpMemAllocatorFree(&_G_RHI_CONTEXT.allocator, (void**)&shader, sizeof(PrRhiShader)); } // ============================================================================ @@ -1320,67 +1392,60 @@ void prRhiDestroyShaderVk(PrRhiDevice *device, PrRhiShader *shader) { // ============================================================================ PrRhiPipelineLayout *prRhiCreatePipelineLayoutVk(PrRhiDevice *device, - PrRhiPipelineLayoutDesc desc) { - VkDevice vk_device = (VkDevice)device->handle; + PrRhiPipelineLayoutDesc desc) { + VkDevice vk_device = device->handle; // Gather descriptor set layouts u32 layout_count = (desc.set_layouts && wpArrayCount(desc.set_layouts) > 0) ? (u32)wpArrayCount(desc.set_layouts) : 0; - VkDescriptorSetLayout vk_layouts_stack[8] = {0}; - VkDescriptorSetLayout *vk_layouts = vk_layouts_stack; - if (layout_count > 8) { - vk_layouts = wpArrayAllocCapacity(VkDescriptorSetLayout, &_G_RHI_CONTEXT.scratch, layout_count, WP_ARRAY_INIT_NONE); - if (!vk_layouts) _abort("alloc failed for VkDescriptorSetLayout array"); - } + VkDescriptorSetLayoutArray vk_layouts = + wpArrayAllocCapacity(VkDescriptorSetLayout, &_G_RHI_CONTEXT.allocator, layout_count, + WP_ARRAY_INIT_FILLED); + if (!vk_layouts) { _abort("alloc failed for VkDescriptorSetLayout array"); } + for (u32 i = 0; i < layout_count; ++i) { - vk_layouts[i] = (VkDescriptorSetLayout)desc.set_layouts[i]->handle; + vk_layouts[i] = desc.set_layouts[i]->handle; } // Gather push constant ranges u32 pc_count = (desc.push_constant_ranges && wpArrayCount(desc.push_constant_ranges) > 0) ? (u32)wpArrayCount(desc.push_constant_ranges) : 0; - VkPushConstantRange pc_ranges_stack[8] = {0}; - VkPushConstantRange *pc_ranges = pc_ranges_stack; - if (pc_count > 8) { - pc_ranges = wpArrayAllocCapacity(VkPushConstantRange, &_G_RHI_CONTEXT.scratch, pc_count, WP_ARRAY_INIT_NONE); - if (!pc_ranges) _abort("alloc failed for VkPushConstantRange array"); - } + VkPushConstantRangeArray pc_ranges = + wpArrayAllocCapacity(VkPushConstantRange, &_G_RHI_CONTEXT.allocator, pc_count, WP_ARRAY_INIT_NONE); + if (!pc_ranges) { _abort("alloc failed for VkPushConstantRange array"); } + for (u32 i = 0; i < pc_count; ++i) { pc_ranges[i].stageFlags = _toVkShaderStage(desc.push_constant_ranges[i].stage_flags); pc_ranges[i].offset = desc.push_constant_ranges[i].offset; pc_ranges[i].size = desc.push_constant_ranges[i].size; } - VkPipelineLayoutCreateInfo pl_info = {}; - pl_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - pl_info.setLayoutCount = layout_count; - pl_info.pSetLayouts = vk_layouts; - pl_info.pushConstantRangeCount = pc_count; - pl_info.pPushConstantRanges = pc_ranges; + VkPipelineLayoutCreateInfo pl_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .setLayoutCount = layout_count, + .pSetLayouts = vk_layouts, + .pushConstantRangeCount = pc_count, + .pPushConstantRanges = pc_ranges, + }; VkPipelineLayout vk_layout = VK_NULL_HANDLE; - _checkVk(vkCreatePipelineLayout(vk_device, &pl_info, NULL, &vk_layout), - "vkCreatePipelineLayout"); + _checkVk(vkCreatePipelineLayout(vk_device, &pl_info, NULL, &vk_layout), "vkCreatePipelineLayout"); - if (layout_count > 8) { - wpArrayDealloc(VkDescriptorSetLayout, &_G_RHI_CONTEXT.scratch, &vk_layouts); - } - if (pc_count > 8) { - wpArrayDealloc(VkPushConstantRange, &_G_RHI_CONTEXT.scratch, &pc_ranges); - } + wpArrayDealloc(VkDescriptorSetLayout, &_G_RHI_CONTEXT.allocator, &vk_layouts); + wpArrayDealloc(VkPushConstantRange, &_G_RHI_CONTEXT.allocator, &pc_ranges); - PrRhiPipelineLayout *layout = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.main, sizeof(PrRhiPipelineLayout)); - if (!layout) _abort("alloc failed for PrRhiPipelineLayout"); + PrRhiPipelineLayout *layout = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.allocator, sizeof(PrRhiPipelineLayout)); + if (!layout) { _abort("alloc failed for PrRhiPipelineLayout"); } layout->handle = vk_layout; return layout; } void prRhiDestroyPipelineLayoutVk(PrRhiDevice *device, PrRhiPipelineLayout *layout) { - if (!layout) return; - vkDestroyPipelineLayout((VkDevice)device->handle, (VkPipelineLayout)layout->handle, NULL); - wpMemAllocatorFree(&_G_RHI_CONTEXT.main, (void**)&layout, sizeof(PrRhiPipelineLayout)); + if (!layout) { return; } + vkDestroyPipelineLayout(device->handle, layout->handle, NULL); + wpMemAllocatorFree(&_G_RHI_CONTEXT.allocator, (void**)&layout, sizeof(PrRhiPipelineLayout)); } // ============================================================================ @@ -1388,8 +1453,8 @@ void prRhiDestroyPipelineLayoutVk(PrRhiDevice *device, PrRhiPipelineLayout *layo // ============================================================================ PrRhiPipeline *prRhiCreateGraphicsPipelineVk(PrRhiDevice *device, - PrRhiGraphicsPipelineDesc desc) { - VkDevice vk_device = (VkDevice)device->handle; + PrRhiGraphicsPipelineDesc desc) { + VkDevice vk_device = device->handle; // Shader stages VkPipelineShaderStageCreateInfo stages[2] = {}; @@ -1398,35 +1463,39 @@ PrRhiPipeline *prRhiCreateGraphicsPipelineVk(PrRhiDevice *device, if (desc.vertex_shader) { stages[stage_count].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; stages[stage_count].stage = VK_SHADER_STAGE_VERTEX_BIT; - stages[stage_count].module = (VkShaderModule)desc.vertex_shader->handle; - stages[stage_count].pName = "main"; + stages[stage_count].module = desc.vertex_shader->handle; + stages[stage_count].pName = desc.vertex_shader_entry_point; ++stage_count; } if (desc.fragment_shader) { stages[stage_count].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; stages[stage_count].stage = VK_SHADER_STAGE_FRAGMENT_BIT; - stages[stage_count].module = (VkShaderModule)desc.fragment_shader->handle; - stages[stage_count].pName = "main"; + stages[stage_count].module = desc.fragment_shader->handle; + stages[stage_count].pName = desc.fragment_shader_entry_point; ++stage_count; } // Vertex input state - VkVertexInputBindingDescription vk_bindings[8] = {0}; + VkVertexInputBindingDescriptionArray vk_bindings = NULL; u32 binding_count = 0; if (desc.vertex_bindings && wpArrayCount(desc.vertex_bindings) > 0) { binding_count = (u32)wpArrayCount(desc.vertex_bindings); - for (u32 i = 0; i < binding_count && i < 8; ++i) { + vk_bindings = wpArrayAllocCapacity(VkVertexInputBindingDescription, &_G_RHI_CONTEXT.allocator, binding_count, + WP_ARRAY_INIT_FILLED); + for (u32 i = 0; i < binding_count; ++i) { vk_bindings[i].binding = desc.vertex_bindings[i].binding; vk_bindings[i].stride = desc.vertex_bindings[i].stride; vk_bindings[i].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; } } - VkVertexInputAttributeDescription vk_attrs[16] = {0}; + VkVertexInputAttributeDescriptionArray vk_attrs = NULL; u32 attr_count = 0; if (desc.vertex_attributes && wpArrayCount(desc.vertex_attributes) > 0) { attr_count = (u32)wpArrayCount(desc.vertex_attributes); - for (u32 i = 0; i < attr_count && i < 16; ++i) { + vk_attrs = wpArrayAllocCapacity(VkVertexInputAttributeDescription, &_G_RHI_CONTEXT.allocator, + attr_count, WP_ARRAY_INIT_FILLED); + for (u32 i = 0; i < attr_count; ++i) { vk_attrs[i].location = desc.vertex_attributes[i].location; vk_attrs[i].binding = desc.vertex_attributes[i].binding; vk_attrs[i].format = _toVkFormat(desc.vertex_attributes[i].format); @@ -1434,69 +1503,78 @@ PrRhiPipeline *prRhiCreateGraphicsPipelineVk(PrRhiDevice *device, } } - VkPipelineVertexInputStateCreateInfo vertex_input = {}; - vertex_input.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - vertex_input.vertexBindingDescriptionCount = binding_count; - vertex_input.pVertexBindingDescriptions = vk_bindings; - vertex_input.vertexAttributeDescriptionCount = attr_count; - vertex_input.pVertexAttributeDescriptions = vk_attrs; + VkPipelineVertexInputStateCreateInfo vertex_input = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .vertexBindingDescriptionCount = binding_count, + .pVertexBindingDescriptions = vk_bindings, + .vertexAttributeDescriptionCount = attr_count, + .pVertexAttributeDescriptions = vk_attrs, + }; // Input assembly - VkPipelineInputAssemblyStateCreateInfo input_assembly = {}; - input_assembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - input_assembly.topology = _toVkTopology(desc.topology); + VkPipelineInputAssemblyStateCreateInfo input_assembly = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .topology = _toVkTopology(desc.topology), + }; // Viewport & scissor dynamic states - VkPipelineViewportStateCreateInfo viewport_state = {}; - viewport_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - viewport_state.viewportCount = 1; - viewport_state.scissorCount = 1; + VkPipelineViewportStateCreateInfo viewport_state = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .viewportCount = 1, + .scissorCount = 1, + }; - VkDynamicState dynamic_states_stack[2] = {0}; - u32 dynamic_count = 0; + VkDynamicStateArray dynamic_states_stack = wpArrayWithCapacity(VkDynamicState, 2, WP_ARRAY_INIT_NONE); if (desc.dynamic_viewport) { - dynamic_states_stack[dynamic_count++] = VK_DYNAMIC_STATE_VIEWPORT; + VkDynamicState viewport = VK_DYNAMIC_STATE_VIEWPORT; + wpArrayAppendCapped(VkDynamicState, dynamic_states_stack, &viewport); } if (desc.dynamic_scissor) { - dynamic_states_stack[dynamic_count++] = VK_DYNAMIC_STATE_SCISSOR; + VkDynamicState scissor = VK_DYNAMIC_STATE_SCISSOR; + wpArrayAppendCapped(VkDynamicState, dynamic_states_stack, &scissor); } - VkPipelineDynamicStateCreateInfo dynamic_state = {}; - dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - dynamic_state.dynamicStateCount = dynamic_count; - dynamic_state.pDynamicStates = dynamic_states_stack; + VkPipelineDynamicStateCreateInfo dynamic_state = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, + .dynamicStateCount = wpArrayCount(dynamic_states_stack), + .pDynamicStates = dynamic_states_stack, + }; // Depth/stencil - VkPipelineDepthStencilStateCreateInfo depth_stencil = {}; - depth_stencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; - depth_stencil.depthTestEnable = desc.depth_test_enable ? VK_TRUE : VK_FALSE; - depth_stencil.depthWriteEnable = desc.depth_write_enable ? VK_TRUE : VK_FALSE; - depth_stencil.depthCompareOp = _toVkCompareOp(desc.depth_compare_op); - depth_stencil.depthBoundsTestEnable = VK_FALSE; - depth_stencil.stencilTestEnable = VK_FALSE; + VkPipelineDepthStencilStateCreateInfo depth_stencil = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, + .depthTestEnable = desc.depth_test_enable ? VK_TRUE : VK_FALSE, + .depthWriteEnable = desc.depth_write_enable ? VK_TRUE : VK_FALSE, + .depthCompareOp = _toVkCompareOp(desc.depth_compare_op), + .depthBoundsTestEnable = VK_FALSE, + .stencilTestEnable = VK_FALSE, + }; // Dynamic rendering - VkPipelineRenderingCreateInfo rendering_info = {}; - rendering_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO; - rendering_info.depthAttachmentFormat = _toVkFormat(desc.depth_attachment_format); - - VkFormat vk_color_formats[8] = {0}; - u32 color_format_count = 0; - if (desc.color_attachment_formats && wpArrayCount(desc.color_attachment_formats) > 0) { - color_format_count = (u32)wpArrayCount(desc.color_attachment_formats); - for (u32 i = 0; i < color_format_count && i < 8; ++i) { + VkFormatArray vk_color_formats = NULL; + u64 attachment_count = wpArrayCount(desc.color_attachment_formats); + if (desc.color_attachment_formats && attachment_count > 0) { + vk_color_formats = wpArrayAllocCapacity(VkFormat, &_G_RHI_CONTEXT.allocator, attachment_count, + WP_ARRAY_INIT_FILLED); + for (u32 i = 0; i < wpArrayCount(vk_color_formats); ++i) { vk_color_formats[i] = _toVkFormat(desc.color_attachment_formats[i]); } } - rendering_info.colorAttachmentCount = color_format_count; - rendering_info.pColorAttachmentFormats = vk_color_formats; + + VkPipelineRenderingCreateInfo rendering_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO, + .depthAttachmentFormat = _toVkFormat(desc.depth_attachment_format), + .colorAttachmentCount = wpArrayCount(vk_color_formats), + .pColorAttachmentFormats = vk_color_formats, + }; // Blending - VkPipelineColorBlendAttachmentState blend_attachments[8] = {0}; - u32 blend_count = 0; - if (desc.blend_attachments && wpArrayCount(desc.blend_attachments) > 0) { - blend_count = (u32)wpArrayCount(desc.blend_attachments); - for (u32 i = 0; i < blend_count && i < 8; ++i) { + u64 blend_count = wpArrayCount(desc.blend_attachments); + VkPipelineColorBlendAttachmentStateArray blend_attachments = + wpArrayAllocCapacity(VkPipelineColorBlendAttachmentState, &_G_RHI_CONTEXT.allocator, blend_count, + WP_ARRAY_INIT_FILLED); + if (desc.blend_attachments && blend_count > 0) { + for (u32 i = 0; i < blend_count; ++i) { blend_attachments[i].blendEnable = VK_FALSE; blend_attachments[i].colorWriteMask = desc.blend_attachments[i].color_write_mask; blend_attachments[i].srcColorBlendFactor = VK_BLEND_FACTOR_ONE; @@ -1508,75 +1586,80 @@ PrRhiPipeline *prRhiCreateGraphicsPipelineVk(PrRhiDevice *device, } } - VkPipelineColorBlendStateCreateInfo blend_state = {}; - blend_state.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - blend_state.attachmentCount = blend_count; - blend_state.pAttachments = blend_attachments; + VkPipelineColorBlendStateCreateInfo blend_state = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + .attachmentCount = wpArrayCount(blend_attachments), + .pAttachments = blend_attachments, + }; // Rasterization - VkPipelineRasterizationStateCreateInfo raster = {}; - raster.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - raster.lineWidth = 1.0f; - raster.cullMode = VK_CULL_MODE_BACK_BIT; - raster.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + VkPipelineRasterizationStateCreateInfo raster = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + .polygonMode = (VkPolygonMode)desc.polygon_mode, + .cullMode = (VkCullModeFlags)desc.cull_mode, + .frontFace = (VkFrontFace)desc.front_face, + .lineWidth = desc.line_width, + }; // Multisampling - VkPipelineMultisampleStateCreateInfo multisample = {}; - multisample.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - multisample.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + VkPipelineMultisampleStateCreateInfo multisample = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + .rasterizationSamples = (VkSampleCountFlagBits)desc.multisample_count, + }; // Create pipeline - VkGraphicsPipelineCreateInfo pi = {}; - pi.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - pi.pNext = &rendering_info; - pi.stageCount = stage_count; - pi.pStages = stages; - pi.pVertexInputState = &vertex_input; - pi.pInputAssemblyState = &input_assembly; - pi.pViewportState = &viewport_state; - pi.pRasterizationState = &raster; - pi.pMultisampleState = &multisample; - pi.pDepthStencilState = &depth_stencil; - pi.pColorBlendState = &blend_state; - pi.pDynamicState = &dynamic_state; - pi.layout = desc.layout ? (VkPipelineLayout)desc.layout->handle : VK_NULL_HANDLE; + VkGraphicsPipelineCreateInfo pi = { + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .pNext = &rendering_info, + .stageCount = stage_count, + .pStages = stages, + .pVertexInputState = &vertex_input, + .pInputAssemblyState = &input_assembly, + .pViewportState = &viewport_state, + .pRasterizationState = &raster, + .pMultisampleState = &multisample, + .pDepthStencilState = &depth_stencil, + .pColorBlendState = &blend_state, + .pDynamicState = &dynamic_state, + .layout = desc.layout ? (VkPipelineLayout)desc.layout->handle : VK_NULL_HANDLE, + }; VkPipeline vk_pipeline = VK_NULL_HANDLE; _checkVk(vkCreateGraphicsPipelines(vk_device, VK_NULL_HANDLE, 1, &pi, NULL, &vk_pipeline), "vkCreateGraphicsPipelines"); - PrRhiPipeline *pipeline = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.main, sizeof(PrRhiPipeline)); - if (!pipeline) _abort("alloc failed for PrRhiPipeline"); + PrRhiPipeline *pipeline = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.allocator, sizeof(PrRhiPipeline)); + if (!pipeline) { _abort("alloc failed for PrRhiPipeline"); } pipeline->handle = vk_pipeline; return pipeline; } -PrRhiPipeline *prRhiCreateComputePipelineVk(PrRhiDevice *device, - PrRhiComputePipelineDesc desc) { - VkComputePipelineCreateInfo pi = {}; - pi.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; - pi.stage = (VkPipelineShaderStageCreateInfo){ - .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, - .stage = VK_SHADER_STAGE_COMPUTE_BIT, - .module = desc.shader ? (VkShaderModule)desc.shader->handle : VK_NULL_HANDLE, - .pName = "main", +PrRhiPipeline *prRhiCreateComputePipelineVk(PrRhiDevice *device, PrRhiComputePipelineDesc desc) { + VkComputePipelineCreateInfo pi = { + .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, + .stage = (VkPipelineShaderStageCreateInfo){ + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_COMPUTE_BIT, + .module = desc.shader ? desc.shader->handle : VK_NULL_HANDLE, + .pName = desc.shader_entry_point, + }, + .layout = desc.layout ? desc.layout->handle : VK_NULL_HANDLE, }; - pi.layout = desc.layout ? (VkPipelineLayout)desc.layout->handle : VK_NULL_HANDLE; VkPipeline vk_pipeline = VK_NULL_HANDLE; - _checkVk(vkCreateComputePipelines((VkDevice)device->handle, VK_NULL_HANDLE, 1, &pi, NULL, &vk_pipeline), + _checkVk(vkCreateComputePipelines(device->handle, VK_NULL_HANDLE, 1, &pi, NULL, &vk_pipeline), "vkCreateComputePipelines"); - PrRhiPipeline *pipeline = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.main, sizeof(PrRhiPipeline)); - if (!pipeline) _abort("alloc failed for PrRhiPipeline"); + PrRhiPipeline *pipeline = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.allocator, sizeof(PrRhiPipeline)); + if (!pipeline) { _abort("alloc failed for PrRhiPipeline"); } pipeline->handle = vk_pipeline; return pipeline; } void prRhiDestroyPipelineVk(PrRhiDevice *device, PrRhiPipeline *pipeline) { - if (!pipeline) return; + if (!pipeline) { return; } vkDestroyPipeline((VkDevice)device->handle, (VkPipeline)pipeline->handle, NULL); - wpMemAllocatorFree(&_G_RHI_CONTEXT.main, (void**)&pipeline, sizeof(PrRhiPipeline)); + wpMemAllocatorFree(&_G_RHI_CONTEXT.allocator, (void**)&pipeline, sizeof(PrRhiPipeline)); } // ============================================================================ @@ -1584,16 +1667,20 @@ void prRhiDestroyPipelineVk(PrRhiDevice *device, PrRhiPipeline *pipeline) { // ============================================================================ PrRhiDescriptorSetLayout *prRhiCreateDescriptorSetLayoutVk(PrRhiDevice *device, - PrRhiDescriptorSetLayoutDesc desc) { - VkDevice vk_device = (VkDevice)device->handle; + PrRhiDescriptorSetLayoutDesc desc) { + VkDevice vk_device = device->handle; u32 binding_count = (desc.bindings && wpArrayCount(desc.bindings) > 0) ? (u32)wpArrayCount(desc.bindings) : 0; - VkDescriptorSetLayoutBinding vk_bindings[16] = {0}; - VkDescriptorBindingFlags vk_flags[16] = {0}; + VkDescriptorSetLayoutBindingArray vk_bindings = + wpArrayAllocCapacity(VkDescriptorSetLayoutBinding, &_G_RHI_CONTEXT.allocator, binding_count, + WP_ARRAY_INIT_FILLED); + VkDescriptorBindingFlagsArray vk_flags = + wpArrayAllocCapacity(VkDescriptorBindingFlags, &_G_RHI_CONTEXT.allocator, binding_count, + WP_ARRAY_INIT_FILLED); - for (u32 i = 0; i < binding_count && i < 16; ++i) { + for (u32 i = 0; i < binding_count; ++i) { vk_bindings[i].binding = i; vk_bindings[i].descriptorType = _toVkDescriptorType(desc.bindings[i].type); vk_bindings[i].descriptorCount = desc.bindings[i].descriptor_count; @@ -1602,31 +1689,32 @@ PrRhiDescriptorSetLayout *prRhiCreateDescriptorSetLayoutVk(PrRhiDevice *device, vk_flags[i] = _toVkBindingFlags(desc.bindings[i].binding_flags); } - VkDescriptorSetLayoutBindingFlagsCreateInfo flags_info = {}; - flags_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO; - flags_info.bindingCount = binding_count; - flags_info.pBindingFlags = vk_flags; + VkDescriptorSetLayoutBindingFlagsCreateInfo flags_info = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO, + .bindingCount = binding_count, + .pBindingFlags = vk_flags, + }; - VkDescriptorSetLayoutCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - info.pNext = &flags_info; - info.bindingCount = binding_count; - info.pBindings = vk_bindings; + VkDescriptorSetLayoutCreateInfo info = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .pNext = &flags_info, + .bindingCount = binding_count, + .pBindings = vk_bindings, + }; VkDescriptorSetLayout vk_layout = VK_NULL_HANDLE; - _checkVk(vkCreateDescriptorSetLayout(vk_device, &info, NULL, &vk_layout), - "vkCreateDescriptorSetLayout"); + _checkVk(vkCreateDescriptorSetLayout(vk_device, &info, NULL, &vk_layout), "vkCreateDescriptorSetLayout"); - PrRhiDescriptorSetLayout *layout = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.main, sizeof(PrRhiDescriptorSetLayout)); - if (!layout) _abort("alloc failed for PrRhiDescriptorSetLayout"); + PrRhiDescriptorSetLayout *layout = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.allocator, sizeof(PrRhiDescriptorSetLayout)); + if (!layout) { _abort("alloc failed for PrRhiDescriptorSetLayout"); } layout->handle = vk_layout; return layout; } void prRhiDestroyDescriptorSetLayoutVk(PrRhiDevice *device, PrRhiDescriptorSetLayout *layout) { - if (!layout) return; - vkDestroyDescriptorSetLayout((VkDevice)device->handle, (VkDescriptorSetLayout)layout->handle, NULL); - wpMemAllocatorFree(&_G_RHI_CONTEXT.main, (void**)&layout, sizeof(PrRhiDescriptorSetLayout)); + if (!layout) { return; } + vkDestroyDescriptorSetLayout(device->handle, layout->handle, NULL); + wpMemAllocatorFree(&_G_RHI_CONTEXT.allocator, (void**)&layout, sizeof(PrRhiDescriptorSetLayout)); } // ============================================================================ @@ -1634,38 +1722,40 @@ void prRhiDestroyDescriptorSetLayoutVk(PrRhiDevice *device, PrRhiDescriptorSetLa // ============================================================================ PrRhiDescriptorPool *prRhiCreateDescriptorPoolVk(PrRhiDevice *device, - PrRhiDescriptorPoolDesc desc) { - VkDevice vk_device = (VkDevice)device->handle; + PrRhiDescriptorPoolDesc desc) { + VkDevice vk_device = device->handle; u32 pool_size_count = (desc.pool_sizes && wpArrayCount(desc.pool_sizes) > 0) ? (u32)wpArrayCount(desc.pool_sizes) : 0; - VkDescriptorPoolSize vk_sizes[8] = {0}; - for (u32 i = 0; i < pool_size_count && i < 8; ++i) { + VkDescriptorPoolSizeArray vk_sizes = + wpArrayAllocCapacity(VkDescriptorPoolSize, &_G_RHI_CONTEXT.allocator, pool_size_count, + WP_ARRAY_INIT_FILLED); + for (u32 i = 0; i < pool_size_count; ++i) { vk_sizes[i].type = _toVkDescriptorType(desc.pool_sizes[i].type); vk_sizes[i].descriptorCount = desc.pool_sizes[i].descriptor_count; } - VkDescriptorPoolCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - info.maxSets = desc.max_sets; - info.poolSizeCount = pool_size_count; - info.pPoolSizes = vk_sizes; + VkDescriptorPoolCreateInfo info = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + .maxSets = desc.max_sets, + .poolSizeCount = pool_size_count, + .pPoolSizes = vk_sizes, + }; VkDescriptorPool vk_pool = VK_NULL_HANDLE; - _checkVk(vkCreateDescriptorPool(vk_device, &info, NULL, &vk_pool), - "vkCreateDescriptorPool"); + _checkVk(vkCreateDescriptorPool(vk_device, &info, NULL, &vk_pool), "vkCreateDescriptorPool"); - PrRhiDescriptorPool *pool = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.main, sizeof(PrRhiDescriptorPool)); - if (!pool) _abort("alloc failed for PrRhiDescriptorPool"); + PrRhiDescriptorPool *pool = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.allocator, sizeof(PrRhiDescriptorPool)); + if (!pool) { _abort("alloc failed for PrRhiDescriptorPool"); } pool->handle = vk_pool; return pool; } void prRhiDestroyDescriptorPoolVk(PrRhiDevice *device, PrRhiDescriptorPool *pool) { - if (!pool) return; - vkDestroyDescriptorPool((VkDevice)device->handle, (VkDescriptorPool)pool->handle, NULL); - wpMemAllocatorFree(&_G_RHI_CONTEXT.main, (void**)&pool, sizeof(PrRhiDescriptorPool)); + if (!pool) { return; } + vkDestroyDescriptorPool(device->handle, pool->handle, NULL); + wpMemAllocatorFree(&_G_RHI_CONTEXT.allocator, (void**)&pool, sizeof(PrRhiDescriptorPool)); } // ============================================================================ @@ -1673,98 +1763,106 @@ void prRhiDestroyDescriptorPoolVk(PrRhiDevice *device, PrRhiDescriptorPool *pool // ============================================================================ PrRhiDescriptorSet *prRhiAllocateDescriptorSetVk(PrRhiDevice *device, - PrRhiDescriptorPool *pool, - PrRhiDescriptorSetLayout *layout, - u32 variable_count) { - VkDevice vk_device = (VkDevice)device->handle; + PrRhiDescriptorPool *pool, + PrRhiDescriptorSetLayout *layout, + WpU32Array variable_descriptor_counts) { + VkDevice vk_device = device->handle; - VkDescriptorSetVariableDescriptorCountAllocateInfo var_info = {}; - var_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO; - var_info.descriptorSetCount = 1; - var_info.pDescriptorCounts = &variable_count; + VkDescriptorSetVariableDescriptorCountAllocateInfo var_info = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO, + .descriptorSetCount = variable_descriptor_counts ? wpArrayCount(variable_descriptor_counts) : 0, + .pDescriptorCounts = variable_descriptor_counts, + }; - VkDescriptorSetLayout vk_layout = (VkDescriptorSetLayout)layout->handle; + VkDescriptorSetLayout vk_layout = layout->handle; - VkDescriptorSetAllocateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - info.pNext = &var_info; - info.descriptorPool = (VkDescriptorPool)pool->handle; - info.descriptorSetCount = 1; - info.pSetLayouts = &vk_layout; + VkDescriptorSetAllocateInfo info = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .pNext = &var_info, + .descriptorPool = pool->handle, + .descriptorSetCount = 1, + .pSetLayouts = &vk_layout, + }; VkDescriptorSet vk_set = VK_NULL_HANDLE; - _checkVk(vkAllocateDescriptorSets(vk_device, &info, &vk_set), - "vkAllocateDescriptorSets"); + _checkVk(vkAllocateDescriptorSets(vk_device, &info, &vk_set), "vkAllocateDescriptorSets"); - PrRhiDescriptorSet *set = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.main, sizeof(PrRhiDescriptorSet)); - if (!set) _abort("alloc failed for PrRhiDescriptorSet"); + PrRhiDescriptorSet *set = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.allocator, sizeof(PrRhiDescriptorSet)); + if (!set) { _abort("alloc failed for PrRhiDescriptorSet"); } set->handle = vk_set; return set; } void prRhiFreeDescriptorSetVk(PrRhiDevice *device, PrRhiDescriptorPool *pool, - PrRhiDescriptorSet *set) { - 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(&_G_RHI_CONTEXT.main, (void**)&set, sizeof(PrRhiDescriptorSet)); + PrRhiDescriptorSet *set) { + if (!set) { return; } + VkDevice vk_device = device->handle; + VkDescriptorSet vk_set = set->handle; + _checkVk(vkFreeDescriptorSets(vk_device, pool->handle, 1, &vk_set), "vkFreeDescriptorSets"); + wpMemAllocatorFree(&_G_RHI_CONTEXT.allocator, (void**)&set, sizeof(PrRhiDescriptorSet)); } void prRhiUpdateDescriptorSetVk(PrRhiDevice *device, PrRhiWriteDescriptorSetArray writes) { - VkDevice vk_device = (VkDevice)device->handle; - (void)vk_device; + VkDevice vk_device = device->handle; u32 count = writes ? (u32)wpArrayCount(writes) : 0; - if (count == 0) return; + if (count == 0) { return; } // We process each write individually because we need to expand image_info/buffer_info arrays for (u32 i = 0; i < count; ++i) { PrRhiWriteDescriptorSet *w = &writes[i]; - VkDescriptorType vk_type = _toVkDescriptorType(w->type); + VkDescriptorType vk_type = _toVkDescriptorType(w->type); if (w->image_info && wpArrayCount(w->image_info) > 0) { u32 img_count = (u32)wpArrayCount(w->image_info); - VkDescriptorImageInfo vk_img_info[16] = {0}; - u32 img_max = img_count > 16 ? 16 : img_count; - for (u32 j = 0; j < img_max; ++j) { + + VkDescriptorImageInfoArray vk_img_info = + wpArrayAllocCapacity(VkDescriptorImageInfo, &_G_RHI_CONTEXT.allocator, img_count, + WP_ARRAY_INIT_FILLED); + for (u32 j = 0; j < img_count; ++j) { PrRhiDescriptorImageInfo *src = &w->image_info[j]; - vk_img_info[j].sampler = src->sampler ? (VkSampler)src->sampler->handle : VK_NULL_HANDLE; - vk_img_info[j].imageView = src->texture ? (VkImageView)src->texture->view : VK_NULL_HANDLE; - vk_img_info[j].imageLayout = _toVkImageLayout(src->layout); + vk_img_info[j].sampler = src->sampler ? src->sampler->handle : VK_NULL_HANDLE; + vk_img_info[j].imageView = src->texture ? src->texture->view : VK_NULL_HANDLE; + vk_img_info[j].imageLayout = _toVkImageLayout(src->layout); } - VkWriteDescriptorSet vk_write = {}; - vk_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - vk_write.dstSet = (VkDescriptorSet)w->dst_set->handle; - vk_write.dstBinding = w->dst_binding; - vk_write.dstArrayElement = w->dst_array_element; - vk_write.descriptorCount = img_max; - vk_write.descriptorType = vk_type; - vk_write.pImageInfo = vk_img_info; + VkWriteDescriptorSet vk_write = { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = w->dst_set->handle, + .dstBinding = w->dst_binding, + .dstArrayElement = w->dst_array_element, + .descriptorCount = img_count, + .descriptorType = vk_type, + .pImageInfo = vk_img_info, + }; + vkUpdateDescriptorSets(vk_device, 1, &vk_write, 0, NULL); } if (w->buffer_info && wpArrayCount(w->buffer_info) > 0) { u32 buf_count = (u32)wpArrayCount(w->buffer_info); - VkDescriptorBufferInfo vk_buf_info[16] = {0}; - u32 buf_max = buf_count > 16 ? 16 : buf_count; - for (u32 j = 0; j < buf_max; ++j) { + + + VkDescriptorBufferInfoArray vk_buf_info = + wpArrayAllocCapacity(VkDescriptorBufferInfo, &_G_RHI_CONTEXT.allocator, buf_count, + WP_ARRAY_INIT_FILLED); + for (u32 j = 0; j < buf_count; ++j) { PrRhiDescriptorBufferInfo *src = &w->buffer_info[j]; - vk_buf_info[j].buffer = src->buffer ? (VkBuffer)src->buffer->handle : VK_NULL_HANDLE; - vk_buf_info[j].offset = src->offset; - vk_buf_info[j].range = src->range; + vk_buf_info[j].buffer = src->buffer ? src->buffer->handle : VK_NULL_HANDLE; + vk_buf_info[j].offset = src->offset; + vk_buf_info[j].range = src->range; } - VkWriteDescriptorSet vk_write = {}; - vk_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - vk_write.dstSet = (VkDescriptorSet)w->dst_set->handle; - vk_write.dstBinding = w->dst_binding; - vk_write.dstArrayElement = w->dst_array_element; - vk_write.descriptorCount = buf_max; - vk_write.descriptorType = vk_type; - vk_write.pBufferInfo = vk_buf_info; + VkWriteDescriptorSet vk_write = { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = w->dst_set->handle, + .dstBinding = w->dst_binding, + .dstArrayElement = w->dst_array_element, + .descriptorCount = buf_count, + .descriptorType = vk_type, + .pBufferInfo = vk_buf_info, + }; + vkUpdateDescriptorSets(vk_device, 1, &vk_write, 0, NULL); } } @@ -1775,46 +1873,45 @@ void prRhiUpdateDescriptorSetVk(PrRhiDevice *device, PrRhiWriteDescriptorSetArra // ============================================================================ PrRhiFence *prRhiCreateFenceVk(PrRhiDevice *device, PrRhiFenceDesc desc) { - VkFenceCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - info.flags = desc.signaled ? VK_FENCE_CREATE_SIGNALED_BIT : 0; + VkFenceCreateInfo info = { + .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + .flags = desc.signaled ? VK_FENCE_CREATE_SIGNALED_BIT : 0, + }; VkFence vk_fence = VK_NULL_HANDLE; - _checkVk(vkCreateFence((VkDevice)device->handle, &info, NULL, &vk_fence), - "vkCreateFence"); + _checkVk(vkCreateFence(device->handle, &info, NULL, &vk_fence), "vkCreateFence"); - PrRhiFence *fence = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.main, sizeof(PrRhiFence)); - if (!fence) _abort("alloc failed for PrRhiFence"); + PrRhiFence *fence = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.allocator, sizeof(PrRhiFence)); + if (!fence) { _abort("alloc failed for PrRhiFence"); } fence->handle = vk_fence; return fence; } void prRhiDestroyFenceVk(PrRhiDevice *device, PrRhiFence *fence) { - if (!fence) return; - vkDestroyFence((VkDevice)device->handle, (VkFence)fence->handle, NULL); - wpMemAllocatorFree(&_G_RHI_CONTEXT.main, (void**)&fence, sizeof(PrRhiFence)); + if (!fence) { return; } + vkDestroyFence(device->handle, fence->handle, NULL); + wpMemAllocatorFree(&_G_RHI_CONTEXT.allocator, (void**)&fence, sizeof(PrRhiFence)); } void prRhiWaitForFencesVk(PrRhiDevice *device, PrRhiFenceArray fences, u32 count, - b8 wait_all, u64 timeout_ns) { - VkFence vk_fences[16] = {0}; - u32 real_count = count < 16 ? count : 16; + b8 wait_all, u64 timeout_ns) { + VkFence vk_fences[TEMP_FENCE_MAX_COUNT] = {0}; + u32 real_count = count < TEMP_FENCE_MAX_COUNT ? count : TEMP_FENCE_MAX_COUNT; for (u32 i = 0; i < real_count; ++i) { - vk_fences[i] = (VkFence)fences[i]->handle; + vk_fences[i] = fences[i]->handle; } - _checkVk(vkWaitForFences((VkDevice)device->handle, real_count, vk_fences, - wait_all ? VK_TRUE : VK_FALSE, timeout_ns), + _checkVk(vkWaitForFences(device->handle, real_count, vk_fences, + wait_all ? VK_TRUE : VK_FALSE, timeout_ns), "vkWaitForFences"); } void prRhiResetFencesVk(PrRhiDevice *device, PrRhiFenceArray fences, u32 count) { - VkFence vk_fences[16] = {0}; - u32 real_count = count < 16 ? count : 16; + VkFence vk_fences[TEMP_FENCE_MAX_COUNT] = {0}; + u32 real_count = count < TEMP_FENCE_MAX_COUNT ? count : TEMP_FENCE_MAX_COUNT; for (u32 i = 0; i < real_count; ++i) { - vk_fences[i] = (VkFence)fences[i]->handle; + vk_fences[i] = fences[i]->handle; } - _checkVk(vkResetFences((VkDevice)device->handle, real_count, vk_fences), - "vkResetFences"); + _checkVk(vkResetFences(device->handle, real_count, vk_fences), "vkResetFences"); } // ============================================================================ @@ -1822,101 +1919,94 @@ void prRhiResetFencesVk(PrRhiDevice *device, PrRhiFenceArray fences, u32 count) // ============================================================================ PrRhiSemaphore *prRhiCreateSemaphoreVk(PrRhiDevice *device) { - VkSemaphoreCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + VkSemaphoreCreateInfo info = { .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO }; VkSemaphore vk_semaphore = VK_NULL_HANDLE; - _checkVk(vkCreateSemaphore((VkDevice)device->handle, &info, NULL, &vk_semaphore), - "vkCreateSemaphore"); + _checkVk(vkCreateSemaphore(device->handle, &info, NULL, &vk_semaphore), "vkCreateSemaphore"); - PrRhiSemaphore *semaphore = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.main, sizeof(PrRhiSemaphore)); - if (!semaphore) _abort("alloc failed for PrRhiSemaphore"); + PrRhiSemaphore *semaphore = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.allocator, sizeof(PrRhiSemaphore)); + if (!semaphore) { _abort("alloc failed for PrRhiSemaphore"); } semaphore->handle = vk_semaphore; return semaphore; } void prRhiDestroySemaphoreVk(PrRhiDevice *device, PrRhiSemaphore *semaphore) { - if (!semaphore) return; - vkDestroySemaphore((VkDevice)device->handle, (VkSemaphore)semaphore->handle, NULL); - wpMemAllocatorFree(&_G_RHI_CONTEXT.main, (void**)&semaphore, sizeof(PrRhiSemaphore)); + if (!semaphore) { return; } + vkDestroySemaphore(device->handle, semaphore->handle, NULL); + wpMemAllocatorFree(&_G_RHI_CONTEXT.allocator, (void**)&semaphore, sizeof(PrRhiSemaphore)); } // ============================================================================ // Command pools // ============================================================================ -PrRhiCommandPool *prRhiCreateCommandPoolVk(PrRhiDevice *device, PrRhiCommandPoolDesc desc) { - VkCommandPoolCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - info.queueFamilyIndex = desc.queue_family_index; +PrRhiCommandPool *prRhiCreateCommandPoolVk(PrRhiDevice *device) { + VkCommandPoolCreateInfo info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, + .queueFamilyIndex = device->queue_family_index, + }; VkCommandPool vk_pool = VK_NULL_HANDLE; - _checkVk(vkCreateCommandPool((VkDevice)device->handle, &info, NULL, &vk_pool), - "vkCreateCommandPool"); + _checkVk(vkCreateCommandPool(device->handle, &info, NULL, &vk_pool), "vkCreateCommandPool"); - PrRhiCommandPool *pool = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.main, sizeof(PrRhiCommandPool)); - if (!pool) _abort("alloc failed for PrRhiCommandPool"); + PrRhiCommandPool *pool = wpMemAllocatorAlloc(&_G_RHI_CONTEXT.allocator, sizeof(PrRhiCommandPool)); + if (!pool) { _abort("alloc failed for PrRhiCommandPool"); } pool->handle = vk_pool; return pool; } void prRhiDestroyCommandPoolVk(PrRhiDevice *device, PrRhiCommandPool *pool) { - if (!pool) return; - vkDestroyCommandPool((VkDevice)device->handle, (VkCommandPool)pool->handle, NULL); - wpMemAllocatorFree(&_G_RHI_CONTEXT.main, (void**)&pool, sizeof(PrRhiCommandPool)); + if (!pool) { return; } + vkDestroyCommandPool(device->handle, pool->handle, NULL); + wpMemAllocatorFree(&_G_RHI_CONTEXT.allocator, (void**)&pool, sizeof(PrRhiCommandPool)); } PrRhiCommandBufferArray prRhiAllocateCommandBuffersVk(PrRhiDevice *device, PrRhiCommandPool *pool, - u32 count) { - VkCommandBufferAllocateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - info.commandPool = (VkCommandPool)pool->handle; - info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - info.commandBufferCount = count; + u32 count) { + VkCommandBufferAllocateInfo info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .commandPool = pool->handle, + .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, + .commandBufferCount = count, + }; - VkCommandBuffer vk_cbs[16] = {0}; - u32 real_count = count < 16 ? count : 16; - - VkCommandBufferArray vk_cb_array = wpArrayAllocCapacity(VkCommandBuffer, &_G_RHI_CONTEXT.scratch, real_count, WP_ARRAY_INIT_NONE); - if (!vk_cb_array) _abort("alloc failed for VkCommandBuffer array"); + VkCommandBufferArray vk_cbs = wpArrayAllocCapacity(VkCommandBuffer, &_G_RHI_CONTEXT.allocator, count, WP_ARRAY_INIT_FILLED); + if (!vk_cbs) { _abort("alloc failed for VkCommandBuffer array"); } _checkVk(vkAllocateCommandBuffers((VkDevice)device->handle, &info, vk_cbs), "vkAllocateCommandBuffers"); - for (u32 i = 0; i < real_count; ++i) { - wpArrayAppendCapped(VkCommandBuffer, vk_cb_array, &vk_cbs[i]); - } + PrRhiCommandBufferArray cbs = wpArrayAllocCapacity(PrRhiCommandBuffer *, &_G_RHI_CONTEXT.allocator, count, WP_ARRAY_INIT_NONE); + if (!cbs) { _abort("alloc failed for PrRhiCommandBuffer array"); } - PrRhiCommandBufferArray cbs = wpArrayAllocCapacity(PrRhiCommandBuffer *, &_G_RHI_CONTEXT.main, 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(&_G_RHI_CONTEXT.main, sizeof(PrRhiCommandBuffer)); - if (!cb) _abort("alloc failed for PrRhiCommandBuffer"); - cb->handle = vk_cb_array[i]; + for (u32 i = 0; i < count; ++i) { + PrRhiCommandBuffer *cb = (PrRhiCommandBuffer *)wpMemAllocatorAlloc(&_G_RHI_CONTEXT.allocator, sizeof(PrRhiCommandBuffer)); + if (!cb) { _abort("alloc failed for PrRhiCommandBuffer"); } + cb->handle = vk_cbs[i]; wpArrayAppendCapped(PrRhiCommandBuffer *, cbs, &cb); } - wpArrayDealloc(VkCommandBuffer, &_G_RHI_CONTEXT.scratch, &vk_cb_array); + wpArrayDealloc(VkCommandBuffer, &_G_RHI_CONTEXT.allocator, &vk_cbs); return cbs; } -void prRhiFreeCommandBuffersVk(PrRhiDevice *device, PrRhiCommandPool *pool, - u32 count, PrRhiCommandBufferArray buffers) { - if (!buffers || count == 0) return; +void prRhiFreeCommandBuffersVk(PrRhiDevice *device, PrRhiCommandPool *pool, PrRhiCommandBufferArray buffers) { + u64 count = wpArrayCount(buffers); - VkDevice vk_device = (VkDevice)device->handle; - VkCommandPool vk_pool = (VkCommandPool)pool->handle; + if (!buffers || count == 0) { return; } - VkCommandBuffer vk_cbs[16] = {0}; - u32 real_count = count < 16 ? count : 16; - for (u32 i = 0; i < real_count; ++i) { - vk_cbs[i] = (VkCommandBuffer)buffers[i]->handle; + VkDevice vk_device = device->handle; + VkCommandPool vk_pool = pool->handle; + + VkCommandBufferArray vk_cbs = wpArrayAllocCapacity(VkCommandBuffer, &_G_RHI_CONTEXT.allocator, count, + WP_ARRAY_INIT_FILLED); + for (u32 i = 0; i < count; ++i) { + vk_cbs[i] = buffers[i]->handle; } - vkFreeCommandBuffers(vk_device, vk_pool, real_count, vk_cbs); + vkFreeCommandBuffers(vk_device, vk_pool, count, vk_cbs); } // ============================================================================ @@ -1924,9 +2014,11 @@ void prRhiFreeCommandBuffersVk(PrRhiDevice *device, PrRhiCommandPool *pool, // ============================================================================ void prRhiBeginCommandBufferVk(PrRhiCommandBuffer *cb) { - VkCommandBufferBeginInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + VkCommandBufferBeginInfo info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, + }; + _checkVk(vkBeginCommandBuffer((VkCommandBuffer)cb->handle, &info), "vkBeginCommandBuffer"); } @@ -1960,8 +2052,8 @@ void prRhiCmdPipelineBarrierVk(PrRhiCommandBuffer *cb, VkImageMemoryBarrier2 vk_img_barriers[16] = {0}; for (u32 i = 0; i < img_count && i < 16; ++i) { PrRhiImageMemoryBarrier *src = &image_barriers[i]; - VkImageLayout old_layout = _toVkImageLayout(src->old_layout); - VkImageLayout new_layout = _toVkImageLayout(src->new_layout); + VkImageLayout old_layout = _toVkImageLayout(src->old_layout); + VkImageLayout new_layout = _toVkImageLayout(src->new_layout); VkImageAspectFlags aspect = VK_IMAGE_ASPECT_COLOR_BIT; if (src->texture) { @@ -1970,11 +2062,11 @@ void prRhiCmdPipelineBarrierVk(PrRhiCommandBuffer *cb, aspect = VK_IMAGE_ASPECT_DEPTH_BIT; } - vk_img_barriers[i].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2; - 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].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2; + 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; @@ -1997,12 +2089,13 @@ void prRhiCmdPipelineBarrierVk(PrRhiCommandBuffer *cb, vk_buf_barriers[i].size = src->size; } - VkDependencyInfo dep = {}; - dep.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; - dep.imageMemoryBarrierCount = img_count; - dep.pImageMemoryBarriers = vk_img_barriers; - dep.bufferMemoryBarrierCount = buf_count; - dep.pBufferMemoryBarriers = vk_buf_barriers; + VkDependencyInfo dep = { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .imageMemoryBarrierCount = img_count, + .pImageMemoryBarriers = vk_img_barriers, + .bufferMemoryBarrierCount = buf_count, + .pBufferMemoryBarriers = vk_buf_barriers, + }; vkCmdPipelineBarrier2(vk_cb, &dep); } @@ -2011,21 +2104,21 @@ void prRhiCmdPipelineBarrierVk(PrRhiCommandBuffer *cb, // Dynamic rendering // ============================================================================ -void prRhiCmdBeginRenderingVk(PrRhiCommandBuffer *cb, - PrRhiColorAttachmentArray color_attachments, - const PrRhiDepthAttachment *depth_attachment) { - VkCommandBuffer vk_cb = (VkCommandBuffer)cb->handle; +void prRhiCmdBeginRenderingVk(PrRhiCommandBuffer *cb, PrRhiColorAttachmentArray color_attachments, + const PrRhiDepthAttachment *depth_attachment) { + VkCommandBuffer vk_cb = cb->handle; u32 color_count = (color_attachments && wpArrayCount(color_attachments) > 0) ? (u32)wpArrayCount(color_attachments) : 0; - VkRenderingAttachmentInfo vk_color[8] = {0}; + VkRenderingAttachmentInfoArray vk_color = + wpArrayAllocCapacity(VkRenderingAttachmentInfo, &_G_RHI_CONTEXT.allocator, color_count, WP_ARRAY_INIT_FILLED); u32 width = 0, height = 0; - for (u32 i = 0; i < color_count && i < 8; ++i) { + for (u32 i = 0; i < color_count; ++i) { PrRhiColorAttachment *src = &color_attachments[i]; vk_color[i].sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO; - vk_color[i].imageView = src->texture ? (VkImageView)src->texture->view : VK_NULL_HANDLE; + vk_color[i].imageView = src->texture ? src->texture->view : VK_NULL_HANDLE; vk_color[i].imageLayout = _toVkImageLayout(src->layout); vk_color[i].loadOp = src->clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD; vk_color[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE; @@ -2042,14 +2135,12 @@ void prRhiCmdBeginRenderingVk(PrRhiCommandBuffer *cb, } VkRenderingAttachmentInfo vk_depth = {}; - VkRenderingAttachmentInfo *p_depth = NULL; if (depth_attachment && depth_attachment->texture) { - p_depth = &vk_depth; - vk_depth.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO; - vk_depth.imageView = (VkImageView)depth_attachment->texture->view; - vk_depth.imageLayout = _toVkImageLayout(depth_attachment->layout); - vk_depth.loadOp = depth_attachment->clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD; - vk_depth.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + vk_depth.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO; + vk_depth.imageView = depth_attachment->texture->view; + vk_depth.imageLayout = _toVkImageLayout(depth_attachment->layout); + vk_depth.loadOp = depth_attachment->clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD; + vk_depth.storeOp = VK_ATTACHMENT_STORE_OP_STORE; vk_depth.clearValue.depthStencil.depth = depth_attachment->clear_depth; if (!width || !height) { width = depth_attachment->texture->width; @@ -2057,23 +2148,25 @@ void prRhiCmdBeginRenderingVk(PrRhiCommandBuffer *cb, } } - VkRect2D render_area = {}; - render_area.extent.width = width; - render_area.extent.height = height; + VkRect2D render_area = { + .extent.width = width, + .extent.height = height, + }; - VkRenderingInfo render_info = {}; - render_info.sType = VK_STRUCTURE_TYPE_RENDERING_INFO; - render_info.renderArea = render_area; - render_info.layerCount = 1; - render_info.colorAttachmentCount = color_count; - render_info.pColorAttachments = vk_color; - render_info.pDepthAttachment = p_depth; + VkRenderingInfo render_info = { + .sType = VK_STRUCTURE_TYPE_RENDERING_INFO, + .renderArea = render_area, + .layerCount = 1, + .colorAttachmentCount = color_count, + .pColorAttachments = vk_color, + .pDepthAttachment = &vk_depth, + }; vkCmdBeginRendering(vk_cb, &render_info); } void prRhiCmdEndRenderingVk(PrRhiCommandBuffer *cb) { - vkCmdEndRendering((VkCommandBuffer)cb->handle); + vkCmdEndRendering(cb->handle); } // ============================================================================ @@ -2081,13 +2174,25 @@ void prRhiCmdEndRenderingVk(PrRhiCommandBuffer *cb) { // ============================================================================ void prRhiCmdSetViewportVk(PrRhiCommandBuffer *cb, f32 x, f32 y, f32 width, f32 height) { - VkViewport vp = { x, y, width, height, 0.0f, 1.0f }; - vkCmdSetViewport((VkCommandBuffer)cb->handle, 0, 1, &vp); + VkViewport vp = { + .x = x, + .y = y, + .width = width, + .height = height, + .minDepth = 0.0f, + .maxDepth = 1.0f + }; + vkCmdSetViewport(cb->handle, 0, 1, &vp); } void prRhiCmdSetScissorVk(PrRhiCommandBuffer *cb, i32 x, i32 y, u32 width, u32 height) { - VkRect2D scissor = { { x, y }, { width, height } }; - vkCmdSetScissor((VkCommandBuffer)cb->handle, 0, 1, &scissor); + VkRect2D scissor = { + .offset.x = x, + .offset.y = y, + .extent.width = width, + .extent.height = height, + }; + vkCmdSetScissor(cb->handle, 0, 1, &scissor); } // ============================================================================ @@ -2095,54 +2200,73 @@ void prRhiCmdSetScissorVk(PrRhiCommandBuffer *cb, i32 x, i32 y, u32 width, u32 h // ============================================================================ void prRhiCmdBindPipelineVk(PrRhiCommandBuffer *cb, PrRhiPipelineBindPoint bind_point, - PrRhiPipeline *pipeline) { + PrRhiPipeline *pipeline) { VkPipelineBindPoint vk_bp = (bind_point == PR_RHI_PIPELINE_BIND_POINT_COMPUTE) ? VK_PIPELINE_BIND_POINT_COMPUTE : VK_PIPELINE_BIND_POINT_GRAPHICS; - vkCmdBindPipeline((VkCommandBuffer)cb->handle, vk_bp, (VkPipeline)pipeline->handle); + vkCmdBindPipeline(cb->handle, vk_bp, pipeline->handle); } void prRhiCmdBindDescriptorSetsVk(PrRhiCommandBuffer *cb, PrRhiPipelineBindPoint bind_point, - PrRhiPipelineLayout *layout, u32 first_set, - PrRhiDescriptorSetArray sets) { + PrRhiPipelineLayout *layout, u32 first_set, + PrRhiDescriptorSetArray sets) { VkPipelineBindPoint vk_bp = (bind_point == PR_RHI_PIPELINE_BIND_POINT_COMPUTE) ? VK_PIPELINE_BIND_POINT_COMPUTE : VK_PIPELINE_BIND_POINT_GRAPHICS; - VkPipelineLayout vk_layout = layout ? (VkPipelineLayout)layout->handle : VK_NULL_HANDLE; + VkPipelineLayout vk_layout = layout ? layout->handle : VK_NULL_HANDLE; u32 set_count = sets ? (u32)wpArrayCount(sets) : 0; - VkDescriptorSet vk_sets[16] = {0}; - u32 real_count = set_count < 16 ? set_count : 16; - for (u32 i = 0; i < real_count; ++i) { - vk_sets[i] = (VkDescriptorSet)sets[i]->handle; - } - vkCmdBindDescriptorSets((VkCommandBuffer)cb->handle, vk_bp, vk_layout, - first_set, real_count, vk_sets, 0, NULL); + // NOTE (Abdelrahman): Commands run frequently and since we're using arena allocator, which means + // that we would be allocating an array over and over. We could use a local arena allocator, but + // that means we would pay the cost of creating and destorying it every frame. This is why we use + // this while loop with a stack array instead, submitting a series of commands instead of one. + while (set_count > 0) { + VkDescriptorSetArray vk_sets = wpArrayWithCapacity(VkDescriptorSet, 16, WP_ARRAY_INIT_FILLED); + u32 total_capacity = (u32)wpArrayCapacity(vk_sets); + u32 real_count = set_count < total_capacity ? set_count : total_capacity; + for (u32 i = 0; i < real_count; ++i) { + vk_sets[i] = sets[i]->handle; + } + + vkCmdBindDescriptorSets(cb->handle, vk_bp, vk_layout, first_set, real_count, vk_sets, 0, NULL); + + set_count -= real_count; + first_set += real_count; + } } void prRhiCmdPushConstantsVk(PrRhiCommandBuffer *cb, PrRhiPipelineLayout *layout, - PrRhiShaderStage stage_flags, u32 offset, u32 size, - const void *data) { - vkCmdPushConstants((VkCommandBuffer)cb->handle, - layout ? (VkPipelineLayout)layout->handle : VK_NULL_HANDLE, + PrRhiShaderStage stage_flags, u32 offset, u32 size, + const void *data) { + vkCmdPushConstants(cb->handle, layout ? layout->handle : VK_NULL_HANDLE, _toVkShaderStage(stage_flags), offset, size, data); } -void prRhiCmdBindVertexBuffersVk(PrRhiCommandBuffer *cb, u32 first_binding, - PrRhiBufferArray buffers, const u64 *offsets, u32 count) { - VkBuffer vk_bufs[16] = {0}; - u32 real_count = count < 16 ? count : 16; - for (u32 i = 0; i < real_count; ++i) { - vk_bufs[i] = (VkBuffer)buffers[i]->handle; +void prRhiCmdBindVertexBuffersVk(PrRhiCommandBuffer *cb, u32 first_binding, PrRhiBufferArray buffers, + WpU64Array offsets) { + u32 buf_count = buffers ? (u32)wpArrayCount(buffers) : 0; + u32 off_count = offsets ? (u32)wpArrayCount(offsets) : 0; + if (buf_count != off_count) { _abort("Mismatched buffer and offset count"); } + + u32 count = buf_count; + + while (count > 0) { + VkBufferArray vk_bufs = wpArrayWithCapacity(VkBuffer, 16, WP_ARRAY_INIT_FILLED); + u32 total_capacity = (u32)wpArrayCapacity(vk_bufs); + u32 real_count = count < total_capacity ? count : total_capacity; + for (u32 i = 0; i < real_count; ++i) { + vk_bufs[i] = buffers[i]->handle; + } + + vkCmdBindVertexBuffers(cb->handle, first_binding, real_count, vk_bufs, (const VkDeviceSize *)offsets); + + count -= real_count; + first_binding += real_count; } - vkCmdBindVertexBuffers((VkCommandBuffer)cb->handle, first_binding, - real_count, vk_bufs, (const VkDeviceSize *)offsets); } void prRhiCmdBindIndexBufferVk(PrRhiCommandBuffer *cb, PrRhiBuffer *buffer, u64 offset, - PrRhiIndexType index_type) { - vkCmdBindIndexBuffer((VkCommandBuffer)cb->handle, - (VkBuffer)buffer->handle, - offset, _toVkIndexType(index_type)); + PrRhiIndexType index_type) { + vkCmdBindIndexBuffer(cb->handle, buffer->handle, offset, _toVkIndexType(index_type)); } // ============================================================================ @@ -2150,14 +2274,13 @@ void prRhiCmdBindIndexBufferVk(PrRhiCommandBuffer *cb, PrRhiBuffer *buffer, u64 // ============================================================================ void prRhiCmdDrawVk(PrRhiCommandBuffer *cb, u32 vertex_count, u32 instance_count, - u32 first_vertex, u32 first_instance) { - vkCmdDraw((VkCommandBuffer)cb->handle, vertex_count, instance_count, first_vertex, first_instance); + u32 first_vertex, u32 first_instance) { + vkCmdDraw(cb->handle, vertex_count, instance_count, first_vertex, first_instance); } void prRhiCmdDrawIndexedVk(PrRhiCommandBuffer *cb, u32 index_count, u32 instance_count, - u32 first_index, i32 vertex_offset, u32 first_instance) { - vkCmdDrawIndexed((VkCommandBuffer)cb->handle, index_count, instance_count, - first_index, vertex_offset, first_instance); + u32 first_index, i32 vertex_offset, u32 first_instance) { + vkCmdDrawIndexed(cb->handle, index_count, instance_count, first_index, vertex_offset, first_instance); } // ============================================================================ @@ -2165,67 +2288,71 @@ void prRhiCmdDrawIndexedVk(PrRhiCommandBuffer *cb, u32 index_count, u32 instance // ============================================================================ void prRhiCmdCopyBufferToImageVk(PrRhiCommandBuffer *cb, PrRhiBuffer *src, PrRhiTexture *dst, - PrRhiBufferImageCopyArray copies) { + PrRhiBufferImageCopyArray copies) { u32 copy_count = (copies && wpArrayCount(copies) > 0) ? (u32)wpArrayCount(copies) : 0; - if (copy_count == 0) return; + if (copy_count == 0) { return; } - VkBufferImageCopy vk_regions[16] = {0}; - u32 real_count = copy_count < 16 ? copy_count : 16; - for (u32 i = 0; i < real_count; ++i) { - vk_regions[i].bufferOffset = copies[i].buffer_offset; - vk_regions[i].bufferRowLength = 0; - vk_regions[i].bufferImageHeight = 0; - vk_regions[i].imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - vk_regions[i].imageSubresource.mipLevel = copies[i].mip_level; - vk_regions[i].imageSubresource.baseArrayLayer = 0; - vk_regions[i].imageSubresource.layerCount = 1; - vk_regions[i].imageExtent.width = copies[i].width; - vk_regions[i].imageExtent.height = copies[i].height; - vk_regions[i].imageExtent.depth = 1; + u32 start_index = 0; + + while (copy_count > 0) { + VkBufferImageCopyArray vk_regions = wpArrayWithCapacity(VkBufferImageCopy, 16, WP_ARRAY_INIT_FILLED); + u32 total_capacity = (u32)wpArrayCapacity(vk_regions); + u32 real_count = copy_count < total_capacity ? copy_count : total_capacity; + for (u32 j = start_index, i = j - start_index; i < real_count; ++i, ++j) { + vk_regions[i].bufferOffset = copies[j].buffer_offset; + vk_regions[i].bufferRowLength = 0; + vk_regions[i].bufferImageHeight = 0; + vk_regions[i].imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + vk_regions[i].imageSubresource.mipLevel = copies[j].mip_level; + vk_regions[i].imageSubresource.baseArrayLayer = 0; + vk_regions[i].imageSubresource.layerCount = 1; + vk_regions[i].imageExtent.width = copies[j].width; + vk_regions[i].imageExtent.height = copies[j].height; + vk_regions[i].imageExtent.depth = 1; + } + + vkCmdCopyBufferToImage(cb->handle, src->handle, dst->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + real_count, vk_regions); + + copy_count -= real_count; + start_index += real_count; } - - vkCmdCopyBufferToImage((VkCommandBuffer)cb->handle, - (VkBuffer)src->handle, - (VkImage)dst->image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - real_count, vk_regions); } // ============================================================================ // Queue submission // ============================================================================ -void prRhiQueueSubmitVk(PrRhiDevice *device, PrRhiCommandBuffer *cb, - PrRhiSemaphore *wait_semaphore, - PrRhiSemaphore *signal_semaphore, PrRhiFence *fence) { - VkCommandBuffer vk_cb = (VkCommandBuffer)cb->handle; +void prRhiQueueSubmitVk(PrRhiDevice *device, PrRhiCommandBuffer *cb, PrRhiSemaphore *wait_semaphore, + PrRhiSemaphore *signal_semaphore, PrRhiFence *fence) { + VkCommandBuffer vk_cb = cb->handle; - VkSemaphore wait_sems[1] = {}; + VkSemaphore wait_sems[1] = {}; VkPipelineStageFlags wait_stages[1] = { VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT }; - u32 wait_count = 0; + u32 wait_count = 0; if (wait_semaphore) { - wait_sems[0] = (VkSemaphore)wait_semaphore->handle; + wait_sems[0] = wait_semaphore->handle; wait_count = 1; } VkSemaphore signal_sems[1] = {}; u32 signal_count = 0; if (signal_semaphore) { - signal_sems[0] = (VkSemaphore)signal_semaphore->handle; + signal_sems[0] = signal_semaphore->handle; signal_count = 1; } - VkSubmitInfo submit = {}; - submit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit.waitSemaphoreCount = wait_count; - submit.pWaitSemaphores = wait_sems; - submit.pWaitDstStageMask = wait_stages; - submit.commandBufferCount = 1; - submit.pCommandBuffers = &vk_cb; - submit.signalSemaphoreCount = signal_count; - submit.pSignalSemaphores = signal_sems; + VkSubmitInfo submit = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .waitSemaphoreCount = wait_count, + .pWaitSemaphores = wait_sems, + .pWaitDstStageMask = wait_stages, + .commandBufferCount = 1, + .pCommandBuffers = &vk_cb, + .signalSemaphoreCount = signal_count, + .pSignalSemaphores = signal_sems, + }; - _checkVk(vkQueueSubmit((VkQueue)device->queue, 1, &submit, - fence ? (VkFence)fence->handle : VK_NULL_HANDLE), + _checkVk(vkQueueSubmit(device->queue, 1, &submit, fence ? fence->handle : VK_NULL_HANDLE), "vkQueueSubmit"); } diff --git a/src/prism/rhi/vulkan/pr_rhi_vk.h b/src/prism/rhi/vulkan/pr_rhi_vk.h index 0daf442..b601723 100644 --- a/src/prism/rhi/vulkan/pr_rhi_vk.h +++ b/src/prism/rhi/vulkan/pr_rhi_vk.h @@ -8,6 +8,7 @@ #define PR_RHI_VK_H #include "../pr_rhi_types.h" +#include #include #include @@ -128,10 +129,9 @@ void prRhiDestroyInstanceVk(PrRhiInstance *inst); PrRhiPhysicalDeviceArray prRhiGetPhysicalDevicesVk(PrRhiInstance *inst); void prRhiGetPhysicalDeviceNameVk(PrRhiPhysicalDevice *pdev, WpStr8 *out); void prRhiGetPhysicalDeviceDriverInfoVk(PrRhiPhysicalDevice *pdev, WpStr8 *out); -void prRhiGetPhysicalDevicePropertiesVk(PrRhiPhysicalDevice *pdev, - PrRhiPhysicalDeviceProperties *out); +PrRhiPhysicalDeviceProperties prRhiGetPhysicalDevicePropertiesVk(PrRhiPhysicalDevice *pdev); -PrRhiSurface *prRhiCreateSurfaceFromWindowVk(PrRhiInstance *inst, void *window_handle); +PrRhiSurface *prRhiCreateSurfaceFromWindowVk(PrRhiInstance *inst, SDL_Window *window); void prRhiDestroySurfaceVk(PrRhiInstance *inst, PrRhiSurface *surface); PrRhiSurfaceCapabilities prRhiGetSurfaceCapabilitiesVk(PrRhiPhysicalDevice *pdev, @@ -145,6 +145,7 @@ u32 prRhiGetQueueFamilyIndexVk(PrRhiDevice *device); PrRhiSwapchain *prRhiCreateSwapchainVk(PrRhiDevice *device, PrRhiSwapchainDesc desc); void prRhiDestroySwapchainVk(PrRhiDevice *device, PrRhiSwapchain *swapchain); +u32 prRhiGetSwapchainImageCountVk(PrRhiSwapchain *swapchain); PrRhiSwapchainResult prRhiAcquireNextImageVk(PrRhiDevice *device, PrRhiSwapchain *swapchain, PrRhiSemaphore *signal_semaphore, u32 *out_image_index); PrRhiSwapchainResult prRhiPresentVk(PrRhiDevice *device, PrRhiSwapchain *swapchain, @@ -196,7 +197,7 @@ void prRhiDestroyDescriptorPoolVk(PrRhiDevice *device, PrRhiDescriptorSet *prRhiAllocateDescriptorSetVk(PrRhiDevice *device, PrRhiDescriptorPool *pool, PrRhiDescriptorSetLayout *layout, - u32 variable_count); + WpU32Array variable_descriptor_counts); void prRhiFreeDescriptorSetVk(PrRhiDevice *device, PrRhiDescriptorPool *pool, PrRhiDescriptorSet *set); void prRhiUpdateDescriptorSetVk(PrRhiDevice *device, PrRhiWriteDescriptorSetArray writes); @@ -211,13 +212,12 @@ void prRhiResetFencesVk(PrRhiDevice *device, PrRhiFenceArray fences, u32 count); PrRhiSemaphore *prRhiCreateSemaphoreVk(PrRhiDevice *device); void prRhiDestroySemaphoreVk(PrRhiDevice *device, PrRhiSemaphore *semaphore); -PrRhiCommandPool *prRhiCreateCommandPoolVk(PrRhiDevice *device, - PrRhiCommandPoolDesc desc); +PrRhiCommandPool *prRhiCreateCommandPoolVk(PrRhiDevice *device); void prRhiDestroyCommandPoolVk(PrRhiDevice *device, PrRhiCommandPool *pool); PrRhiCommandBufferArray prRhiAllocateCommandBuffersVk(PrRhiDevice *device, PrRhiCommandPool *pool, u32 count); -void prRhiFreeCommandBuffersVk(PrRhiDevice *device, PrRhiCommandPool *pool, - u32 count, PrRhiCommandBufferArray buffers); + +void prRhiFreeCommandBuffersVk(PrRhiDevice *device, PrRhiCommandPool *pool, PrRhiCommandBufferArray buffers); void prRhiBeginCommandBufferVk(PrRhiCommandBuffer *cb); void prRhiEndCommandBufferVk(PrRhiCommandBuffer *cb); @@ -243,8 +243,8 @@ void prRhiCmdBindDescriptorSetsVk(PrRhiCommandBuffer *cb, PrRhiPipelineBindPoint void prRhiCmdPushConstantsVk(PrRhiCommandBuffer *cb, PrRhiPipelineLayout *layout, PrRhiShaderStage stage_flags, u32 offset, u32 size, const void *data); -void prRhiCmdBindVertexBuffersVk(PrRhiCommandBuffer *cb, u32 first_binding, - PrRhiBufferArray buffers, const u64 *offsets, u32 count); +void prRhiCmdBindVertexBuffersVk(PrRhiCommandBuffer *cb, u32 first_binding, PrRhiBufferArray buffers, + WpU64Array offsets); void prRhiCmdBindIndexBufferVk(PrRhiCommandBuffer *cb, PrRhiBuffer *buffer, u64 offset, PrRhiIndexType index_type); diff --git a/src/prism/rhi/vulkan/pr_rhi_vk_aliases.h b/src/prism/rhi/vulkan/pr_rhi_vk_aliases.h index 51f5f81..4f0b38d 100644 --- a/src/prism/rhi/vulkan/pr_rhi_vk_aliases.h +++ b/src/prism/rhi/vulkan/pr_rhi_vk_aliases.h @@ -17,9 +17,10 @@ #define prRhiCreateDevice prRhiCreateDeviceVk #define prRhiDestroyDevice prRhiDestroyDeviceVk #define prRhiDeviceWaitIdle prRhiDeviceWaitIdleVk -#define prRhiGetQueueFamilyIndex prRhiGetQueueFamilyIndexVk +#define prRhiGetQueueFamilyIndex prRhiGetQueueFamilyIndexVk #define prRhiCreateSwapchain prRhiCreateSwapchainVk #define prRhiDestroySwapchain prRhiDestroySwapchainVk +#define prRhiGetSwapchainImageCount prRhiGetSwapchainImageCountVk #define prRhiAcquireNextImage prRhiAcquireNextImageVk #define prRhiPresent prRhiPresentVk #define prRhiRecreateSwapchain prRhiRecreateSwapchainVk