RHI vulkan updates

This commit is contained in:
2026-07-12 13:43:59 +01:00
parent bffe9b8174
commit 45a34bb151
10 changed files with 1361 additions and 1082 deletions
+92 -4
View File
@@ -16,6 +16,21 @@ Use this when working on any file in `src/prism/rhi/`, or when creating a new ba
## Conventions ## 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 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: 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 ```c
// correct // correct
PrRhiDevice *prRhiCreateDevice(PrRhiPhysicalDevice *pdev, PrRhiSurface *surface, PrRhiDevice *prRhiCreateDevice(PrRhiPhysicalDevice *pdev, PrRhiSurface *surface, PrRhiDeviceDesc desc);
PrRhiDeviceDesc desc, WpAllocator *alloc);
// wrong // wrong
PrRhiDevice *prRhiCreateDevice(PrRhiPhysicalDevice *pdev, PrRhiSurface *surface, PrRhiDevice *prRhiCreateDevice(PrRhiPhysicalDevice *pdev, PrRhiSurface *surface, const PrRhiDeviceDesc *desc);
const PrRhiDeviceDesc *desc, WpAllocator *alloc);
``` ```
### 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 ### File layout
``` ```
src/prism/rhi/ src/prism/rhi/
├── pr_rhi.h ← umbrella header (API declarations + backend dispatch) ├── 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) ├── pr_rhi_types.h ← shared types (enums, element types, array aliases, desc structs, opaque handles)
├── vulkan/ ├── vulkan/
│ ├── pr_rhi_vk.h ← Vulkan backend header (opaque struct defs + Vk-suffixed decls) │ ├── 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 │ ├── pr_rhi_vk_aliases.h ← #define alias mapping
│ └── profiles/ ← generated Vulkan Profiles library │ └── profiles/ ← generated Vulkan Profiles library
├── d3d12/ ├── d3d12/
+28
View File
@@ -36,6 +36,16 @@ All code follows the patterns established in `src/wapp/`. The project prefix is
- **Tabs for indentation**, 8-column tab width. - **Tabs for indentation**, 8-column tab width.
- **Braces** on the same line as control statements (Attach style). - **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`). - **Pointers**: `*` against the name, not the type (`PrRhiBuffer *buf`, not `PrRhiBuffer* buf`).
- **Line width**: 120 columns. - **Line width**: 120 columns.
- **Continuation lines** align to the opening parenthesis. - **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) the DAG in contiguous arrays (e.g. adjacency lists packed in flat buffers)
rather than individually allocated linked structures. 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 ### Graph / adjacency lists
Adjacency list nodes must be **separately allocated from the vertex array**. Adjacency list nodes must be **separately allocated from the vertex array**.
+4 -1
View File
@@ -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/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 {{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 -- {{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}} \ {{APP_INC}} \
src/main.cpp \ src/main.cpp \
-o {{BUILDDIR}}/main.o -o {{BUILDDIR}}/main.o
@@ -55,6 +55,9 @@ build: vendor
-o {{BUILDDIR}}/prism -o {{BUILDDIR}}/prism
@echo "--- build done: {{BUILDDIR}}/prism ---" @echo "--- build done: {{BUILDDIR}}/prism ---"
run:
./{{BUILDDIR}}/prism
# Clean # Clean
clean: clean:
rm -rf {{BUILDDIR}} rm -rf {{BUILDDIR}}
+186 -191
View File
@@ -3,8 +3,7 @@
// Prism port of how-to-vulkan's main.cpp — uses the RHI API instead of // Prism port of how-to-vulkan's main.cpp — uses the RHI API instead of
// direct Vulkan calls. // direct Vulkan calls.
#define PR_RHI_VULKAN #include "prism/rhi/pr_rhi_types.h"
#include "prism/rhi/pr_rhi.h" #include "prism/rhi/pr_rhi.h"
#include <SDL3/SDL_timer.h> #include <SDL3/SDL_timer.h>
#include <glm/ext/matrix_clip_space.hpp> #include <glm/ext/matrix_clip_space.hpp>
@@ -95,6 +94,8 @@ struct AppState {
PrRhiSurface *surface; PrRhiSurface *surface;
PrRhiSwapchain *swapchain; PrRhiSwapchain *swapchain;
PrRhiFormat swapchain_format;
PrRhiBuffer *vert_index_buf; PrRhiBuffer *vert_index_buf;
u64 vertex_buf_size; u64 vertex_buf_size;
u64 index_count; u64 index_count;
@@ -136,9 +137,10 @@ struct AppState {
int main() { int main() {
AppState app = {}; AppState app = {};
WpAllocator arena = wpMemArenaAllocatorInitZero(MiB(128)); WpAllocator arena = wpMemArenaAllocatorInitZero(MiB(128));
prRhiInit();
// {{{ Initialisation // {{{ Initialisation
prRhiInit();
check(SDL_Init(SDL_INIT_VIDEO), EXIT_CODE_SDL_INIT_FAILED); check(SDL_Init(SDL_INIT_VIDEO), EXIT_CODE_SDL_INIT_FAILED);
f32 display_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay()); f32 display_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay());
@@ -149,8 +151,7 @@ int main() {
// }}} // }}}
// {{{ Instance creation // {{{ Instance creation
PrRhiInstanceDesc inst_desc = {}; app.inst = prRhiCreateInstance(PrRhiInstanceDesc{});
app.inst = prRhiCreateInstance(inst_desc);
// }}} // }}}
// {{{ Physical device selection // {{{ Physical device selection
@@ -159,8 +160,7 @@ int main() {
i32 selected = -1; i32 selected = -1;
for (u32 i = 0; i < wpArrayCount(pdevs); ++i) { for (u32 i = 0; i < wpArrayCount(pdevs); ++i) {
PrRhiPhysicalDeviceProperties props; PrRhiPhysicalDeviceProperties props = prRhiGetPhysicalDeviceProperties(pdevs[i]);
prRhiGetPhysicalDeviceProperties(pdevs[i], &props);
switch (props.device_type) { switch (props.device_type) {
case PR_RHI_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: case PR_RHI_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
selected = (i32)i; selected = (i32)i;
@@ -176,7 +176,8 @@ int main() {
app.pdev = pdevs[selected]; app.pdev = pdevs[selected];
// Print device info // Print device info
WpStr8 dev_name, driver_info; WpStr8 dev_name = wpStr8Buf(512);
WpStr8 driver_info = wpStr8Buf(512);
prRhiGetPhysicalDeviceName(app.pdev, &dev_name); prRhiGetPhysicalDeviceName(app.pdev, &dev_name);
prRhiGetPhysicalDeviceDriverInfo(app.pdev, &driver_info); prRhiGetPhysicalDeviceDriverInfo(app.pdev, &driver_info);
std::cout << "Selected GPU: " << std::string_view((const char *)dev_name.buf, dev_name.size) << '\n' std::cout << "Selected GPU: " << std::string_view((const char *)dev_name.buf, dev_name.size) << '\n'
@@ -186,26 +187,26 @@ int main() {
// {{{ Surface creation // {{{ Surface creation
check(SDL_GetWindowSize(app.window, &app.window_size.x, &app.window_size.y), check(SDL_GetWindowSize(app.window, &app.window_size.x, &app.window_size.y),
EXIT_CODE_GET_WINDOW_SIZE_FAILED); EXIT_CODE_GET_WINDOW_SIZE_FAILED);
app.surface = prRhiCreateSurfaceFromWindow(app.inst, (void *)app.window); app.surface = prRhiCreateSurfaceFromWindow(app.inst, app.window);
// }}} // }}}
// {{{ Device creation // {{{ Device creation
PrRhiDeviceDesc dev_desc = {}; 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); app.device = prRhiCreateDevice(app.pdev, app.surface, dev_desc);
u32 qfi = prRhiGetQueueFamilyIndex(app.device);
// }}} // }}}
// {{{ Swapchain creation // {{{ Swapchain creation
PrRhiSwapchainDesc swap_desc = {}; PrRhiSwapchainDesc swap_desc = {};
swap_desc.surface = app.surface; swap_desc.surface = app.surface;
swap_desc.width = (u32)app.window_size.x; swap_desc.width = (u32)app.window_size.x;
swap_desc.height = (u32)app.window_size.y; swap_desc.height = (u32)app.window_size.y;
swap_desc.has_depth = true; swap_desc.has_depth = true;
swap_desc.depth_format = PR_RHI_FORMAT_D24_UNORM_S8_UINT; swap_desc.depth_format = PR_RHI_FORMAT_D24_UNORM_S8_UINT;
app.swapchain = prRhiCreateSwapchain(app.device, swap_desc);
PrRhiFormat swapchain_format = prRhiGetSwapchainFormat(app.swapchain); app.swapchain = prRhiCreateSwapchain(app.device, swap_desc);
app.swapchain_format = prRhiGetSwapchainFormat(app.swapchain);
// }}} // }}}
// {{{ Vertex/Index buffers // {{{ Vertex/Index buffers
@@ -227,19 +228,19 @@ int main() {
-attrib.vertices[idx.vertex_index * 3 + 1], -attrib.vertices[idx.vertex_index * 3 + 1],
attrib.vertices[idx.vertex_index * 3 + 2] attrib.vertices[idx.vertex_index * 3 + 2]
}; };
v.normal = { v.normal = {
attrib.normals[idx.normal_index * 3], attrib.normals[idx.normal_index * 3],
-attrib.normals[idx.normal_index * 3 + 1], -attrib.normals[idx.normal_index * 3 + 1],
attrib.normals[idx.normal_index * 3 + 2] attrib.normals[idx.normal_index * 3 + 2]
}; };
v.uv = { v.uv = {
attrib.texcoords[idx.texcoord_index * 2], attrib.texcoords[idx.texcoord_index * 2],
1.0f - attrib.texcoords[idx.texcoord_index * 2 + 1] 1.0f - attrib.texcoords[idx.texcoord_index * 2 + 1]
}; };
u16 index = (u16)wpArrayCount(indices); u16 index = (u16)wpArrayCount(indices);
vertices = wpArrayAppendAlloc(Vertex, &arena, vertices, &v, WP_ARRAY_INIT_NONE); vertices = wpArrayAppendAlloc(Vertex, &arena, vertices, &v, WP_ARRAY_INIT_NONE);
indices = wpArrayAppendAlloc(u16, &arena, indices, &index, WP_ARRAY_INIT_NONE); indices = wpArrayAppendAlloc(u16, &arena, indices, &index, WP_ARRAY_INIT_NONE);
} }
app.vertex_buf_size = sizeof(Vertex) * wpArrayCount(vertices); app.vertex_buf_size = sizeof(Vertex) * wpArrayCount(vertices);
@@ -249,9 +250,10 @@ int main() {
// {{{ Create GPU buffer // {{{ Create GPU buffer
PrRhiBufferDesc vert_desc = {}; PrRhiBufferDesc vert_desc = {};
vert_desc.size = app.vertex_buf_size + index_buf_size; 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.usage = (PrRhiBufferUsage)(PR_RHI_BUFFER_USAGE_VERTEX | PR_RHI_BUFFER_USAGE_INDEX);
vert_desc.memory = PR_RHI_MEMORY_CPU_TO_GPU; vert_desc.memory = PR_RHI_MEMORY_CPU_TO_GPU;
app.vert_index_buf = prRhiCreateBuffer(app.device, vert_desc); app.vert_index_buf = prRhiCreateBuffer(app.device, vert_desc);
void *mapped = prRhiBufferMap(app.device, app.vert_index_buf); void *mapped = prRhiBufferMap(app.device, app.vert_index_buf);
@@ -263,14 +265,15 @@ int main() {
// {{{ Shader data buffers // {{{ Shader data buffers
app.shader_data_bufs = wpArrayAllocCapacity(PrRhiBuffer *, &arena, app.shader_data_bufs = wpArrayAllocCapacity(PrRhiBuffer *, &arena,
AppState::max_frames_in_flight, AppState::max_frames_in_flight,
WP_ARRAY_INIT_FILLED); WP_ARRAY_INIT_FILLED);
for (u32 i = 0; i < AppState::max_frames_in_flight; ++i) { for (u32 i = 0; i < AppState::max_frames_in_flight; ++i) {
PrRhiBufferDesc buf_desc = {}; PrRhiBufferDesc buf_desc = {};
buf_desc.size = sizeof(ShaderData); buf_desc.size = sizeof(ShaderData);
buf_desc.usage = (PrRhiBufferUsage)(PR_RHI_BUFFER_USAGE_STORAGE | buf_desc.usage = (PrRhiBufferUsage)(PR_RHI_BUFFER_USAGE_STORAGE |
PR_RHI_BUFFER_USAGE_SHADER_DEVICE_ADDRESS); PR_RHI_BUFFER_USAGE_SHADER_DEVICE_ADDRESS);
buf_desc.memory = PR_RHI_MEMORY_CPU_TO_GPU; buf_desc.memory = PR_RHI_MEMORY_CPU_TO_GPU;
app.shader_data_bufs[i] = prRhiCreateBuffer(app.device, buf_desc); app.shader_data_bufs[i] = prRhiCreateBuffer(app.device, buf_desc);
} }
// }}} // }}}
@@ -278,7 +281,7 @@ int main() {
// {{{ Synchronisation objects // {{{ Synchronisation objects
// Fences // Fences
app.fences = wpArrayAllocCapacity(PrRhiFence *, &arena, AppState::max_frames_in_flight, 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) { for (u32 i = 0; i < AppState::max_frames_in_flight; ++i) {
PrRhiFenceDesc fd = {}; PrRhiFenceDesc fd = {};
fd.signaled = true; fd.signaled = true;
@@ -287,37 +290,34 @@ int main() {
// Image acquired semaphores (per frame) // Image acquired semaphores (per frame)
app.image_acquired_semaphores = wpArrayAllocCapacity(PrRhiSemaphore *, &arena, app.image_acquired_semaphores = wpArrayAllocCapacity(PrRhiSemaphore *, &arena,
AppState::max_frames_in_flight, AppState::max_frames_in_flight,
WP_ARRAY_INIT_FILLED); WP_ARRAY_INIT_FILLED);
for (u32 i = 0; i < AppState::max_frames_in_flight; ++i) { for (u32 i = 0; i < AppState::max_frames_in_flight; ++i) {
app.image_acquired_semaphores[i] = prRhiCreateSemaphore(app.device); app.image_acquired_semaphores[i] = prRhiCreateSemaphore(app.device);
} }
// Render completed semaphores (per swapchain image) // 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, app.render_completed_semaphores = wpArrayAllocCapacity(PrRhiSemaphore *, &arena,
swapchain_image_count, swapchain_image_count,
WP_ARRAY_INIT_FILLED); WP_ARRAY_INIT_FILLED);
for (u32 i = 0; i < swapchain_image_count; ++i) { for (u32 i = 0; i < swapchain_image_count; ++i) {
app.render_completed_semaphores[i] = prRhiCreateSemaphore(app.device); app.render_completed_semaphores[i] = prRhiCreateSemaphore(app.device);
} }
// }}} // }}}
// {{{ Command pool and buffers // {{{ Command pool and buffers
PrRhiCommandPoolDesc pool_desc = {}; app.cmd_pool = prRhiCreateCommandPool(app.device);
pool_desc.queue_family_index = qfi;
app.cmd_pool = prRhiCreateCommandPool(app.device, pool_desc);
app.cmd_buffers = prRhiAllocateCommandBuffers(app.device, app.cmd_pool, app.cmd_buffers = prRhiAllocateCommandBuffers(app.device, app.cmd_pool,
AppState::max_frames_in_flight); AppState::max_frames_in_flight);
// }}} // }}}
// {{{ Texture loading // {{{ Texture loading
app.textures = wpArrayAllocCapacity(TextureResources, &arena, AppState::texture_count, 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); 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) { for (u32 i = 0; i < AppState::texture_count; ++i) {
char buf[2048] = {}; char buf[2048] = {};
@@ -326,67 +326,69 @@ int main() {
// Create sampler // Create sampler
PrRhiSamplerDesc samp_desc = {}; PrRhiSamplerDesc samp_desc = {};
samp_desc.mag_filter = PR_RHI_FILTER_LINEAR; samp_desc.mag_filter = PR_RHI_FILTER_LINEAR;
samp_desc.min_filter = PR_RHI_FILTER_LINEAR; samp_desc.min_filter = PR_RHI_FILTER_LINEAR;
samp_desc.mipmap_mode = PR_RHI_MIPMAP_MODE_LINEAR; samp_desc.mipmap_mode = PR_RHI_MIPMAP_MODE_LINEAR;
samp_desc.max_anisotropy = 8.0f; samp_desc.max_anisotropy = 8.0f;
samp_desc.max_lod = PR_RHI_LOD_CLAMP_NONE; samp_desc.max_lod = PR_RHI_LOD_CLAMP_NONE;
PrRhiSampler *sampler = prRhiCreateSampler(app.device, samp_desc); PrRhiSampler *sampler = prRhiCreateSampler(app.device, samp_desc);
app.textures[i].texture = tex; app.textures[i].texture = tex;
app.textures[i].sampler = sampler; app.textures[i].sampler = sampler;
} }
prRhiFreeCommandBuffers(app.device, app.cmd_pool, 1, upload_cbs); prRhiFreeCommandBuffers(app.device, app.cmd_pool, upload_cbs);
wpArrayDealloc(PrRhiCommandBuffer *, &arena, &upload_cbs);
// }}} // }}}
// {{{ Descriptor set layout, pool, set // {{{ Descriptor set layout, pool, set
PrRhiDescriptorSetLayoutBinding bindings[1] = {}; PrRhiDescriptorSetLayoutBindingArray ds_layouts = wpArray(
bindings[0].type = PR_RHI_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; PrRhiDescriptorSetLayoutBinding,
bindings[0].descriptor_count = AppState::texture_count; PrRhiDescriptorSetLayoutBinding{
bindings[0].stage_flags = PR_RHI_SHADER_STAGE_FRAGMENT; PR_RHI_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
bindings[0].binding_flags = PR_RHI_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT; 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 = { ds_layouts };
app.desc_set_layout = prRhiCreateDescriptorSetLayout(app.device, layout_desc);
PrRhiDescriptorSetLayoutDesc layout_desc = {};
layout_desc.bindings = ds_layouts;
app.desc_set_layout = prRhiCreateDescriptorSetLayout(app.device, layout_desc);
// Pool // Pool
PrRhiDescriptorPoolSize pool_size = {}; PrRhiDescriptorPoolSize pool_size = {};
pool_size.type = PR_RHI_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; pool_size.type = PR_RHI_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
pool_size.descriptor_count = AppState::texture_count; pool_size.descriptor_count = AppState::texture_count;
PrRhiDescriptorPoolDesc pool_desc2 = {}; PrRhiDescriptorPoolDesc ds_pool_desc = {};
pool_desc2.max_sets = 1; ds_pool_desc.max_sets = 1;
pool_desc2.pool_sizes = wpArray(PrRhiDescriptorPoolSize, pool_size); ds_pool_desc.pool_sizes = wpArray(PrRhiDescriptorPoolSize, pool_size);
app.desc_pool = prRhiCreateDescriptorPool(app.device, pool_desc2);
app.desc_pool = prRhiCreateDescriptorPool(app.device, ds_pool_desc);
// Allocate descriptor set (variable count) // Allocate descriptor set (variable count)
app.desc_set = prRhiAllocateDescriptorSet(app.device, app.desc_pool, WpU32Array var_counts = wpArray(u32, AppState::texture_count);
app.desc_set_layout, app.desc_set = prRhiAllocateDescriptorSet(app.device, app.desc_pool, app.desc_set_layout,
AppState::texture_count); var_counts);
// Write descriptor set // Write descriptor set
PrRhiDescriptorImageInfoArray img_infos = wpArrayAllocCapacity(PrRhiDescriptorImageInfo, PrRhiDescriptorImageInfoArray img_infos = wpArrayAllocCapacity(PrRhiDescriptorImageInfo,
&arena, &arena,
AppState::texture_count, AppState::texture_count,
WP_ARRAY_INIT_NONE); WP_ARRAY_INIT_NONE);
for (u32 i = 0; i < AppState::texture_count; ++i) { for (u32 i = 0; i < AppState::texture_count; ++i) {
PrRhiDescriptorImageInfo info = {}; PrRhiDescriptorImageInfo info = {};
info.texture = app.textures[i].texture; info.texture = app.textures[i].texture;
info.sampler = app.textures[i].sampler; info.sampler = app.textures[i].sampler;
info.layout = PR_RHI_LAYOUT_READ_ONLY_OPTIMAL; info.layout = PR_RHI_LAYOUT_READ_ONLY_OPTIMAL;
wpArrayAppendCapped(PrRhiDescriptorImageInfo, img_infos, &info); wpArrayAppendCapped(PrRhiDescriptorImageInfo, img_infos, &info);
} }
PrRhiWriteDescriptorSet write = {}; PrRhiWriteDescriptorSet write = {};
write.dst_set = app.desc_set; write.dst_set = app.desc_set;
write.dst_binding = 0; write.dst_binding = 0;
write.type = PR_RHI_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; write.type = PR_RHI_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
write.image_info = img_infos; write.image_info = img_infos;
PrRhiWriteDescriptorSetArray writes = wpArray(PrRhiWriteDescriptorSet, write); PrRhiWriteDescriptorSetArray writes = wpArray(PrRhiWriteDescriptorSet, write);
prRhiUpdateDescriptorSet(app.device, writes); prRhiUpdateDescriptorSet(app.device, writes);
@@ -415,73 +417,74 @@ int main() {
// {{{ Create shader module // {{{ Create shader module
PrRhiShaderDesc shader_desc = {}; PrRhiShaderDesc shader_desc = {};
shader_desc.spirv_code = spirv->getBufferPointer(); shader_desc.spirv_code = spirv->getBufferPointer();
shader_desc.spirv_size = spirv->getBufferSize(); shader_desc.spirv_size = spirv->getBufferSize();
app.shader = prRhiCreateShader(app.device, shader_desc); app.shader = prRhiCreateShader(app.device, shader_desc);
// }}} // }}}
// {{{ Pipeline layout // {{{ Pipeline layout
PrRhiPushConstantRange pc_range = {}; PrRhiPushConstantRange pc_range = {};
pc_range.stage_flags = PR_RHI_SHADER_STAGE_VERTEX; pc_range.stage_flags = PR_RHI_SHADER_STAGE_VERTEX;
pc_range.size = sizeof(u64); pc_range.size = sizeof(u64);
PrRhiDescriptorSetLayout *set_layouts_pl[] = { app.desc_set_layout }; PrRhiDescriptorSetLayoutArray pl_layouts = wpArray(PrRhiDescriptorSetLayout *, app.desc_set_layout);
PrRhiDescriptorSetLayoutArray pl_layouts = wpArray(PrRhiDescriptorSetLayout *, set_layouts_pl[0]);
PrRhiPipelineLayoutDesc pl_desc = {}; PrRhiPipelineLayoutDesc pl_desc = {};
pl_desc.set_layouts = pl_layouts; pl_desc.set_layouts = pl_layouts;
pl_desc.push_constant_ranges = wpArray(PrRhiPushConstantRange, pc_range); pl_desc.push_constant_ranges = wpArray(PrRhiPushConstantRange, pc_range);
app.pipeline_layout = prRhiCreatePipelineLayout(app.device, pl_desc); app.pipeline_layout = prRhiCreatePipelineLayout(app.device, pl_desc);
// }}} // }}}
// {{{ Graphics pipeline // {{{ Graphics pipeline
PrRhiVertexInputBinding vertex_binding = {}; PrRhiVertexInputBindingArray vertex_bindings = wpArray(
vertex_binding.binding = 0; PrRhiVertexInputBinding,
vertex_binding.stride = sizeof(Vertex); PrRhiVertexInputBinding{ 0, sizeof(Vertex) }
);
PrRhiVertexAttribute vertex_attrs[3] = {}; PrRhiVertexAttributeArray vertex_attrs = wpArray(
vertex_attrs[0].location = 0; PrRhiVertexAttribute,
vertex_attrs[0].binding = 0; PrRhiVertexAttribute{ 0, 0, PR_RHI_FORMAT_R32G32B32_SFLOAT, 0 },
vertex_attrs[0].format = PR_RHI_FORMAT_R32G32B32_SFLOAT; PrRhiVertexAttribute{ 1, 0, PR_RHI_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, normal) },
vertex_attrs[0].offset = 0; PrRhiVertexAttribute{ 2, 0, PR_RHI_FORMAT_R32G32_SFLOAT, offsetof(Vertex, uv) }
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);
PrRhiColorBlendAttachment blend_attachment = {}; PrRhiColorBlendAttachmentArray blend_attachments = wpArray(
blend_attachment.color_write_mask = 0xf; PrRhiColorBlendAttachment,
PrRhiColorBlendAttachment{ 0xf }
);
PrRhiFormat color_fmts[] = { swapchain_format }; PrRhiFormatArray color_fmt_array = wpArray(PrRhiFormat, app.swapchain_format);
PrRhiFormatArray color_fmt_array = wpArray(PrRhiFormat, color_fmts[0]);
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); app.pipeline = prRhiCreateGraphicsPipeline(app.device, pipe_desc);
// }}} // }}}
// {{{ Render loop // {{{ Render loop
app.object_rotations = wpArrayAllocCapacity(glm::vec3, &arena, AppState::instance_count, app.object_rotations = wpArrayAllocCapacity(glm::vec3, &arena, AppState::instance_count,
WP_ARRAY_INIT_FILLED); WP_ARRAY_INIT_FILLED);
u64 last_time = SDL_GetTicks(); u64 last_time = SDL_GetTicks();
SDL_Event event = {}; SDL_Event event = {};
app.frame_index = 0; app.frame_index = 0;
u32 image_index = 0; u32 image_index = 0;
@@ -495,8 +498,8 @@ int main() {
// {{{ Acquire next image // {{{ Acquire next image
PrRhiSwapchainResult acq = prRhiAcquireNextImage(app.device, app.swapchain, PrRhiSwapchainResult acq = prRhiAcquireNextImage(app.device, app.swapchain,
app.image_acquired_semaphores[app.frame_index], app.image_acquired_semaphores[app.frame_index],
&image_index); &image_index);
if (acq == PR_RHI_SWAPCHAIN_OUT_OF_DATE) { if (acq == PR_RHI_SWAPCHAIN_OUT_OF_DATE) {
app.update_swapchain = true; app.update_swapchain = true;
} }
@@ -507,8 +510,8 @@ int main() {
} else { } else {
// {{{ Update shader data // {{{ Update shader data
app.shader_data.projection = glm::perspective(glm::radians(45.0f), app.shader_data.projection = glm::perspective(glm::radians(45.0f),
(f32)app.window_size.x / (f32)app.window_size.y, (f32)app.window_size.x / (f32)app.window_size.y,
0.1f, 32.0f); 0.1f, 32.0f);
app.shader_data.view = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -6.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) { 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); 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])); glm::mat4_cast(glm::quat(app.object_rotations[i]));
} }
void *shader_data_ptr = prRhiBufferMap(app.device, void *shader_data_ptr = prRhiBufferMap(app.device, app.shader_data_bufs[app.frame_index]);
app.shader_data_bufs[app.frame_index]);
memcpy(shader_data_ptr, &app.shader_data, sizeof(ShaderData)); memcpy(shader_data_ptr, &app.shader_data, sizeof(ShaderData));
prRhiBufferUnmap(app.device, app.shader_data_bufs[app.frame_index]); prRhiBufferUnmap(app.device, app.shader_data_bufs[app.frame_index]);
// }}} // }}}
@@ -529,51 +531,50 @@ int main() {
// Transition images to attachment optimal // Transition images to attachment optimal
{ {
PrRhiImageMemoryBarrier img_barriers[2] = {}; PrRhiImageMemoryBarrierArray barriers_arr =
wpArrayWithCapacity(PrRhiImageMemoryBarrier, 2, WP_ARRAY_INIT_FILLED);
// Color attachment // Color attachment
PrRhiTexture *color_tex = prRhiGetSwapchainTexture(app.swapchain, image_index); PrRhiTexture *color_tex = prRhiGetSwapchainTexture(app.swapchain, image_index);
img_barriers[0].texture = color_tex; barriers_arr[0].texture = color_tex;
img_barriers[0].old_layout = PR_RHI_LAYOUT_UNDEFINED; barriers_arr[0].old_layout = PR_RHI_LAYOUT_UNDEFINED;
img_barriers[0].new_layout = PR_RHI_LAYOUT_ATTACHMENT_OPTIMAL; barriers_arr[0].new_layout = PR_RHI_LAYOUT_ATTACHMENT_OPTIMAL;
img_barriers[0].src_stage_mask = PR_RHI_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT; barriers_arr[0].src_stage_mask = PR_RHI_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT;
img_barriers[0].src_access_mask = PR_RHI_ACCESS_NONE; barriers_arr[0].src_access_mask = PR_RHI_ACCESS_NONE;
img_barriers[0].dst_stage_mask = PR_RHI_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT; barriers_arr[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); barriers_arr[0].dst_access_mask = (PrRhiAccess)(PR_RHI_ACCESS_COLOR_ATTACHMENT_READ | PR_RHI_ACCESS_COLOR_ATTACHMENT_WRITE);
// Depth attachment // Depth attachment
PrRhiTexture *depth_tex = prRhiGetSwapchainDepthTexture(app.swapchain); PrRhiTexture *depth_tex = prRhiGetSwapchainDepthTexture(app.swapchain);
img_barriers[1].texture = depth_tex; barriers_arr[1].texture = depth_tex;
img_barriers[1].old_layout = PR_RHI_LAYOUT_UNDEFINED; barriers_arr[1].old_layout = PR_RHI_LAYOUT_UNDEFINED;
img_barriers[1].new_layout = PR_RHI_LAYOUT_ATTACHMENT_OPTIMAL; barriers_arr[1].new_layout = PR_RHI_LAYOUT_ATTACHMENT_OPTIMAL;
img_barriers[1].src_stage_mask = PR_RHI_PIPELINE_STAGE_LATE_FRAGMENT_TESTS; barriers_arr[1].src_stage_mask = PR_RHI_PIPELINE_STAGE_LATE_FRAGMENT_TESTS;
img_barriers[1].src_access_mask = PR_RHI_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE; barriers_arr[1].src_access_mask = PR_RHI_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE;
img_barriers[1].dst_stage_mask = PR_RHI_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS; barriers_arr[1].dst_stage_mask = PR_RHI_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS;
img_barriers[1].dst_access_mask = PR_RHI_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE; 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); prRhiCmdPipelineBarrier(cb, barriers_arr, NULL);
} }
// Rendering // Rendering
{ {
PrRhiColorAttachment color_att = {}; PrRhiColorAttachmentArray color_arr =
color_att.texture = prRhiGetSwapchainTexture(app.swapchain, image_index); wpArrayWithCapacity(PrRhiColorAttachment, 1, WP_ARRAY_INIT_FILLED);
color_att.layout = PR_RHI_LAYOUT_ATTACHMENT_OPTIMAL; color_arr[0].texture = prRhiGetSwapchainTexture(app.swapchain, image_index);
color_att.clear = true; color_arr[0].layout = PR_RHI_LAYOUT_ATTACHMENT_OPTIMAL;
color_att.clear_color[0] = 0.0f; color_arr[0].clear = true;
color_att.clear_color[1] = 0.0f; color_arr[0].clear_color[0] = 0.0f;
color_att.clear_color[2] = 0.0f; color_arr[0].clear_color[1] = 0.0f;
color_att.clear_color[3] = 0.0f; color_arr[0].clear_color[2] = 0.0f;
color_arr[0].clear_color[3] = 0.0f;
PrRhiDepthAttachment depth_att = {}; PrRhiDepthAttachment depth_att = {};
depth_att.texture = prRhiGetSwapchainDepthTexture(app.swapchain); depth_att.texture = prRhiGetSwapchainDepthTexture(app.swapchain);
depth_att.layout = PR_RHI_LAYOUT_ATTACHMENT_OPTIMAL; depth_att.layout = PR_RHI_LAYOUT_ATTACHMENT_OPTIMAL;
depth_att.clear = true; depth_att.clear = true;
depth_att.clear_depth = 1.0f; depth_att.clear_depth = 1.0f;
PrRhiColorAttachmentArray color_arr = wpArray(PrRhiColorAttachment, color_att);
prRhiCmdBeginRendering(cb, color_arr, &depth_att); prRhiCmdBeginRendering(cb, color_arr, &depth_att);
} }
@@ -584,51 +585,46 @@ int main() {
PrRhiDescriptorSetArray sets = wpArray(PrRhiDescriptorSet *, app.desc_set); PrRhiDescriptorSetArray sets = wpArray(PrRhiDescriptorSet *, app.desc_set);
prRhiCmdBindDescriptorSets(cb, PR_RHI_PIPELINE_BIND_POINT_GRAPHICS, 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 }; PrRhiBufferArray vert_buf_arr = wpArray(PrRhiBuffer *, app.vert_index_buf);
u64 vert_offsets[] = { 0 }; WpU64Array vert_offsets = wpArray(u64, 0);
PrRhiBufferArray vert_buf_arr = wpArray(PrRhiBuffer *, vert_bufs[0]); prRhiCmdBindVertexBuffers(cb, 0, vert_buf_arr, vert_offsets);
prRhiCmdBindVertexBuffers(cb, 0, vert_buf_arr, vert_offsets, 1); prRhiCmdBindIndexBuffer(cb, app.vert_index_buf, app.vertex_buf_size, PR_RHI_INDEX_TYPE_UINT16);
prRhiCmdBindIndexBuffer(cb, app.vert_index_buf, app.vertex_buf_size,
PR_RHI_INDEX_TYPE_UINT16);
// Push shader data buffer device address // Push shader data buffer device address
u64 buf_addr = prRhiGetBufferDeviceAddress(app.device, u64 buf_addr = prRhiGetBufferDeviceAddress(app.device, app.shader_data_bufs[app.frame_index]);
app.shader_data_bufs[app.frame_index]); prRhiCmdPushConstants(cb, app.pipeline_layout, PR_RHI_SHADER_STAGE_VERTEX, 0, sizeof(u64), &buf_addr);
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); prRhiCmdDrawIndexed(cb, (u32)app.index_count, AppState::instance_count, 0, 0, 0);
prRhiCmdEndRendering(cb); prRhiCmdEndRendering(cb);
// Transition to present // Transition to present
{ {
PrRhiImageMemoryBarrier present_barrier = {}; PrRhiImageMemoryBarrierArray present_barriers =
present_barrier.texture = prRhiGetSwapchainTexture(app.swapchain, image_index); wpArrayWithCapacity(PrRhiImageMemoryBarrier, 1, WP_ARRAY_INIT_FILLED);
present_barrier.old_layout = PR_RHI_LAYOUT_ATTACHMENT_OPTIMAL; present_barriers[0].texture = prRhiGetSwapchainTexture(app.swapchain, image_index);
present_barrier.new_layout = PR_RHI_LAYOUT_PRESENT_SRC; present_barriers[0].old_layout = PR_RHI_LAYOUT_ATTACHMENT_OPTIMAL;
present_barrier.src_stage_mask = PR_RHI_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT; present_barriers[0].new_layout = PR_RHI_LAYOUT_PRESENT_SRC;
present_barrier.src_access_mask = PR_RHI_ACCESS_COLOR_ATTACHMENT_WRITE; present_barriers[0].src_stage_mask = PR_RHI_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT;
present_barrier.dst_stage_mask = PR_RHI_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT; present_barriers[0].src_access_mask = PR_RHI_ACCESS_COLOR_ATTACHMENT_WRITE;
present_barrier.dst_access_mask = PR_RHI_ACCESS_NONE; 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); prRhiEndCommandBuffer(cb);
// }}} // }}}
// {{{ Submit // {{{ Submit
prRhiQueueSubmit(app.device, cb, prRhiQueueSubmit(app.device, cb, app.image_acquired_semaphores[app.frame_index],
app.image_acquired_semaphores[app.frame_index], app.render_completed_semaphores[image_index], app.fences[app.frame_index]);
app.render_completed_semaphores[image_index],
app.fences[app.frame_index]);
// }}} // }}}
// {{{ Present // {{{ Present
PrRhiSwapchainResult pres = prRhiPresent(app.device, app.swapchain, 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) { if (pres == PR_RHI_SWAPCHAIN_OUT_OF_DATE) {
app.update_swapchain = true; app.update_swapchain = true;
} }
@@ -709,8 +705,7 @@ int main() {
prRhiDestroyTexture(app.device, app.textures[i].texture); prRhiDestroyTexture(app.device, app.textures[i].texture);
} }
prRhiFreeCommandBuffers(app.device, app.cmd_pool, AppState::max_frames_in_flight, prRhiFreeCommandBuffers(app.device, app.cmd_pool, app.cmd_buffers);
app.cmd_buffers);
prRhiDestroyCommandPool(app.device, app.cmd_pool); prRhiDestroyCommandPool(app.device, app.cmd_pool);
for (u32 i = 0; i < swapchain_image_count; ++i) { for (u32 i = 0; i < swapchain_image_count; ++i) {
+2 -4
View File
@@ -7,11 +7,9 @@
PrRhiContext _G_RHI_CONTEXT; PrRhiContext _G_RHI_CONTEXT;
void prRhiInit(void) { void prRhiInit(void) {
_G_RHI_CONTEXT.main = wpMemArenaAllocatorInit(MiB(64)); _G_RHI_CONTEXT.allocator = wpMemArenaAllocatorInit(MiB(64));
_G_RHI_CONTEXT.scratch = wpMemArenaAllocatorInit(MiB(32));
} }
void prRhiDestroy(void) { void prRhiDestroy(void) {
wpMemArenaAllocatorDestroy(&_G_RHI_CONTEXT.scratch); wpMemArenaAllocatorDestroy(&_G_RHI_CONTEXT.allocator);
wpMemArenaAllocatorDestroy(&_G_RHI_CONTEXT.main);
} }
+14 -12
View File
@@ -24,6 +24,7 @@
#define PR_RHI_H #define PR_RHI_H
#include "pr_rhi_types.h" #include "pr_rhi_types.h"
#include <SDL3/SDL_video.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -45,17 +46,16 @@ void prRhiDestroyInstance(PrRhiInstance *inst);
// Physical device enumeration // Physical device enumeration
// ====================================================================== // ======================================================================
PrRhiPhysicalDeviceArray prRhiGetPhysicalDevices(PrRhiInstance *inst); PrRhiPhysicalDeviceArray prRhiGetPhysicalDevices(PrRhiInstance *inst);
void prRhiGetPhysicalDeviceName(PrRhiPhysicalDevice *pdev, WpStr8 *out); void prRhiGetPhysicalDeviceName(PrRhiPhysicalDevice *pdev, WpStr8 *out);
void prRhiGetPhysicalDeviceDriverInfo(PrRhiPhysicalDevice *pdev, WpStr8 *out); void prRhiGetPhysicalDeviceDriverInfo(PrRhiPhysicalDevice *pdev, WpStr8 *out);
void prRhiGetPhysicalDeviceProperties(PrRhiPhysicalDevice *pdev, PrRhiPhysicalDeviceProperties prRhiGetPhysicalDeviceProperties(PrRhiPhysicalDevice *pdev);
PrRhiPhysicalDeviceProperties *out);
// ====================================================================== // ======================================================================
// Surface (platform-specific) // Surface (platform-specific)
// ====================================================================== // ======================================================================
PrRhiSurface *prRhiCreateSurfaceFromWindow(PrRhiInstance *inst, void *window_handle); PrRhiSurface *prRhiCreateSurfaceFromWindow(PrRhiInstance *inst, SDL_Window *window);
void prRhiDestroySurface(PrRhiInstance *inst, PrRhiSurface *surface); void prRhiDestroySurface(PrRhiInstance *inst, PrRhiSurface *surface);
PrRhiSurfaceCapabilities prRhiGetSurfaceCapabilities(PrRhiPhysicalDevice *pdev, PrRhiSurfaceCapabilities prRhiGetSurfaceCapabilities(PrRhiPhysicalDevice *pdev,
PrRhiSurface *surface); PrRhiSurface *surface);
@@ -77,6 +77,7 @@ u32 prRhiGetQueueFamilyIndex(PrRhiDevice *device);
PrRhiSwapchain *prRhiCreateSwapchain(PrRhiDevice *device, PrRhiSwapchainDesc desc); PrRhiSwapchain *prRhiCreateSwapchain(PrRhiDevice *device, PrRhiSwapchainDesc desc);
void prRhiDestroySwapchain(PrRhiDevice *device, PrRhiSwapchain *swapchain); void prRhiDestroySwapchain(PrRhiDevice *device, PrRhiSwapchain *swapchain);
u32 prRhiGetSwapchainImageCount(PrRhiSwapchain *swapchain);
PrRhiSwapchainResult prRhiAcquireNextImage(PrRhiDevice *device, PrRhiSwapchain *swapchain, PrRhiSwapchainResult prRhiAcquireNextImage(PrRhiDevice *device, PrRhiSwapchain *swapchain,
PrRhiSemaphore *signal_semaphore, u32 *out_image_index); PrRhiSemaphore *signal_semaphore, u32 *out_image_index);
@@ -167,8 +168,8 @@ void prRhiDestroyDescriptorPool(PrRhiDevice *device,
// ====================================================================== // ======================================================================
PrRhiDescriptorSet *prRhiAllocateDescriptorSet(PrRhiDevice *device, PrRhiDescriptorPool *pool, PrRhiDescriptorSet *prRhiAllocateDescriptorSet(PrRhiDevice *device, PrRhiDescriptorPool *pool,
PrRhiDescriptorSetLayout *layout, PrRhiDescriptorSetLayout *layout,
u32 variable_count); WpU32Array variable_descriptor_counts);
void prRhiFreeDescriptorSet(PrRhiDevice *device, PrRhiDescriptorPool *pool, void prRhiFreeDescriptorSet(PrRhiDevice *device, PrRhiDescriptorPool *pool,
PrRhiDescriptorSet *set); PrRhiDescriptorSet *set);
void prRhiUpdateDescriptorSet(PrRhiDevice *device, PrRhiWriteDescriptorSetArray writes); void prRhiUpdateDescriptorSet(PrRhiDevice *device, PrRhiWriteDescriptorSetArray writes);
@@ -191,13 +192,14 @@ void prRhiDestroySemaphore(PrRhiDevice *device, PrRhiSemaphore *semap
// Command pools and command buffers // Command pools and command buffers
// ====================================================================== // ======================================================================
PrRhiCommandPool *prRhiCreateCommandPool(PrRhiDevice *device, PrRhiCommandPoolDesc desc); PrRhiCommandPool *prRhiCreateCommandPool(PrRhiDevice *device);
void prRhiDestroyCommandPool(PrRhiDevice *device, PrRhiCommandPool *pool); void prRhiDestroyCommandPool(PrRhiDevice *device, PrRhiCommandPool *pool);
PrRhiCommandBufferArray prRhiAllocateCommandBuffers(PrRhiDevice *device, PrRhiCommandPool *pool, PrRhiCommandBufferArray prRhiAllocateCommandBuffers(PrRhiDevice *device, PrRhiCommandPool *pool,
u32 count); u32 count);
void prRhiFreeCommandBuffers(PrRhiDevice *device, PrRhiCommandPool *pool, void prRhiFreeCommandBuffers(PrRhiDevice *device, PrRhiCommandPool *pool,
u32 count, PrRhiCommandBufferArray buffers); PrRhiCommandBufferArray buffers);
// ====================================================================== // ======================================================================
// Command buffer recording // Command buffer recording
@@ -238,8 +240,8 @@ void prRhiCmdPushConstants(PrRhiCommandBuffer *cb, PrRhiPipelineLayout *layout,
// --- Vertex / index buffers --- // --- Vertex / index buffers ---
void prRhiCmdBindVertexBuffers(PrRhiCommandBuffer *cb, u32 first_binding, void prRhiCmdBindVertexBuffers(PrRhiCommandBuffer *cb, u32 first_binding, PrRhiBufferArray buffers,
PrRhiBufferArray buffers, const u64 *offsets, u32 count); WpU64Array offsets);
void prRhiCmdBindIndexBuffer(PrRhiCommandBuffer *cb, PrRhiBuffer *buffer, u64 offset, void prRhiCmdBindIndexBuffer(PrRhiCommandBuffer *cb, PrRhiBuffer *buffer, u64 offset,
PrRhiIndexType index_type); PrRhiIndexType index_type);
+44 -7
View File
@@ -357,9 +357,40 @@ typedef struct PrRhiPipelineLayoutDesc {
PrRhiPushConstantRangeArray push_constant_ranges; PrRhiPushConstantRangeArray push_constant_ranges;
} PrRhiPipelineLayoutDesc; } 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 { typedef struct PrRhiGraphicsPipelineDesc {
PrRhiShader *vertex_shader; PrRhiShader *vertex_shader;
const char *vertex_shader_entry_point;
PrRhiShader *fragment_shader; PrRhiShader *fragment_shader;
const char *fragment_shader_entry_point;
PrRhiVertexInputBindingArray vertex_bindings; PrRhiVertexInputBindingArray vertex_bindings;
PrRhiVertexAttributeArray vertex_attributes; PrRhiVertexAttributeArray vertex_attributes;
@@ -378,11 +409,22 @@ typedef struct PrRhiGraphicsPipelineDesc {
b8 dynamic_viewport; b8 dynamic_viewport;
b8 dynamic_scissor; b8 dynamic_scissor;
PrRhiPolygonMode polygon_mode;
PrRhiCullMode cull_mode;
PrRhiFrontFace front_face;
f32 line_width;
PrRhiMultisampleCount multisample_count;
PrRhiPipelineLayout *layout; PrRhiPipelineLayout *layout;
} PrRhiGraphicsPipelineDesc; } PrRhiGraphicsPipelineDesc;
typedef struct PrRhiComputePipelineDesc { typedef struct PrRhiComputePipelineDesc {
PrRhiShader *shader; PrRhiShader *shader;
const char *shader_entry_point;
PrRhiPipelineLayout *layout; PrRhiPipelineLayout *layout;
} PrRhiComputePipelineDesc; } PrRhiComputePipelineDesc;
@@ -408,10 +450,6 @@ typedef struct PrRhiFenceDesc {
b8 signaled; b8 signaled;
} PrRhiFenceDesc; } PrRhiFenceDesc;
typedef struct PrRhiCommandPoolDesc {
u32 queue_family_index;
} PrRhiCommandPoolDesc;
typedef struct PrRhiSwapchainDesc { typedef struct PrRhiSwapchainDesc {
PrRhiSurface *surface; PrRhiSurface *surface;
u32 width; u32 width;
@@ -432,7 +470,7 @@ typedef struct PrRhiSurfaceCapabilities {
} PrRhiSurfaceCapabilities; } PrRhiSurfaceCapabilities;
typedef struct PrRhiPhysicalDeviceProperties { typedef struct PrRhiPhysicalDeviceProperties {
u32 api_version; u32 api_version;
PrRhiPhysicalDeviceType device_type; PrRhiPhysicalDeviceType device_type;
} PrRhiPhysicalDeviceProperties; } PrRhiPhysicalDeviceProperties;
@@ -443,8 +481,7 @@ typedef u64 PrRhiDeviceAddress;
// ============================================================================ // ============================================================================
typedef struct PrRhiContext { typedef struct PrRhiContext {
WpAllocator main; WpAllocator allocator;
WpAllocator scratch;
} PrRhiContext; } PrRhiContext;
// --- Command buffer types --- // --- Command buffer types ---
File diff suppressed because it is too large Load Diff
+10 -10
View File
@@ -8,6 +8,7 @@
#define PR_RHI_VK_H #define PR_RHI_VK_H
#include "../pr_rhi_types.h" #include "../pr_rhi_types.h"
#include <SDL3/SDL_video.h>
#include <volk/volk.h> #include <volk/volk.h>
#include <vk_mem_alloc.h> #include <vk_mem_alloc.h>
@@ -128,10 +129,9 @@ void prRhiDestroyInstanceVk(PrRhiInstance *inst);
PrRhiPhysicalDeviceArray prRhiGetPhysicalDevicesVk(PrRhiInstance *inst); PrRhiPhysicalDeviceArray prRhiGetPhysicalDevicesVk(PrRhiInstance *inst);
void prRhiGetPhysicalDeviceNameVk(PrRhiPhysicalDevice *pdev, WpStr8 *out); void prRhiGetPhysicalDeviceNameVk(PrRhiPhysicalDevice *pdev, WpStr8 *out);
void prRhiGetPhysicalDeviceDriverInfoVk(PrRhiPhysicalDevice *pdev, WpStr8 *out); void prRhiGetPhysicalDeviceDriverInfoVk(PrRhiPhysicalDevice *pdev, WpStr8 *out);
void prRhiGetPhysicalDevicePropertiesVk(PrRhiPhysicalDevice *pdev, PrRhiPhysicalDeviceProperties prRhiGetPhysicalDevicePropertiesVk(PrRhiPhysicalDevice *pdev);
PrRhiPhysicalDeviceProperties *out);
PrRhiSurface *prRhiCreateSurfaceFromWindowVk(PrRhiInstance *inst, void *window_handle); PrRhiSurface *prRhiCreateSurfaceFromWindowVk(PrRhiInstance *inst, SDL_Window *window);
void prRhiDestroySurfaceVk(PrRhiInstance *inst, PrRhiSurface *surface); void prRhiDestroySurfaceVk(PrRhiInstance *inst, PrRhiSurface *surface);
PrRhiSurfaceCapabilities prRhiGetSurfaceCapabilitiesVk(PrRhiPhysicalDevice *pdev, PrRhiSurfaceCapabilities prRhiGetSurfaceCapabilitiesVk(PrRhiPhysicalDevice *pdev,
@@ -145,6 +145,7 @@ u32 prRhiGetQueueFamilyIndexVk(PrRhiDevice *device);
PrRhiSwapchain *prRhiCreateSwapchainVk(PrRhiDevice *device, PrRhiSwapchainDesc desc); PrRhiSwapchain *prRhiCreateSwapchainVk(PrRhiDevice *device, PrRhiSwapchainDesc desc);
void prRhiDestroySwapchainVk(PrRhiDevice *device, PrRhiSwapchain *swapchain); void prRhiDestroySwapchainVk(PrRhiDevice *device, PrRhiSwapchain *swapchain);
u32 prRhiGetSwapchainImageCountVk(PrRhiSwapchain *swapchain);
PrRhiSwapchainResult prRhiAcquireNextImageVk(PrRhiDevice *device, PrRhiSwapchain *swapchain, PrRhiSwapchainResult prRhiAcquireNextImageVk(PrRhiDevice *device, PrRhiSwapchain *swapchain,
PrRhiSemaphore *signal_semaphore, u32 *out_image_index); PrRhiSemaphore *signal_semaphore, u32 *out_image_index);
PrRhiSwapchainResult prRhiPresentVk(PrRhiDevice *device, PrRhiSwapchain *swapchain, PrRhiSwapchainResult prRhiPresentVk(PrRhiDevice *device, PrRhiSwapchain *swapchain,
@@ -196,7 +197,7 @@ void prRhiDestroyDescriptorPoolVk(PrRhiDevice *device,
PrRhiDescriptorSet *prRhiAllocateDescriptorSetVk(PrRhiDevice *device, PrRhiDescriptorSet *prRhiAllocateDescriptorSetVk(PrRhiDevice *device,
PrRhiDescriptorPool *pool, PrRhiDescriptorPool *pool,
PrRhiDescriptorSetLayout *layout, PrRhiDescriptorSetLayout *layout,
u32 variable_count); WpU32Array variable_descriptor_counts);
void prRhiFreeDescriptorSetVk(PrRhiDevice *device, PrRhiDescriptorPool *pool, void prRhiFreeDescriptorSetVk(PrRhiDevice *device, PrRhiDescriptorPool *pool,
PrRhiDescriptorSet *set); PrRhiDescriptorSet *set);
void prRhiUpdateDescriptorSetVk(PrRhiDevice *device, PrRhiWriteDescriptorSetArray writes); void prRhiUpdateDescriptorSetVk(PrRhiDevice *device, PrRhiWriteDescriptorSetArray writes);
@@ -211,13 +212,12 @@ void prRhiResetFencesVk(PrRhiDevice *device, PrRhiFenceArray fences, u32 count);
PrRhiSemaphore *prRhiCreateSemaphoreVk(PrRhiDevice *device); PrRhiSemaphore *prRhiCreateSemaphoreVk(PrRhiDevice *device);
void prRhiDestroySemaphoreVk(PrRhiDevice *device, PrRhiSemaphore *semaphore); void prRhiDestroySemaphoreVk(PrRhiDevice *device, PrRhiSemaphore *semaphore);
PrRhiCommandPool *prRhiCreateCommandPoolVk(PrRhiDevice *device, PrRhiCommandPool *prRhiCreateCommandPoolVk(PrRhiDevice *device);
PrRhiCommandPoolDesc desc);
void prRhiDestroyCommandPoolVk(PrRhiDevice *device, PrRhiCommandPool *pool); void prRhiDestroyCommandPoolVk(PrRhiDevice *device, PrRhiCommandPool *pool);
PrRhiCommandBufferArray prRhiAllocateCommandBuffersVk(PrRhiDevice *device, PrRhiCommandPool *pool, PrRhiCommandBufferArray prRhiAllocateCommandBuffersVk(PrRhiDevice *device, PrRhiCommandPool *pool,
u32 count); 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 prRhiBeginCommandBufferVk(PrRhiCommandBuffer *cb);
void prRhiEndCommandBufferVk(PrRhiCommandBuffer *cb); void prRhiEndCommandBufferVk(PrRhiCommandBuffer *cb);
@@ -243,8 +243,8 @@ void prRhiCmdBindDescriptorSetsVk(PrRhiCommandBuffer *cb, PrRhiPipelineBindPoint
void prRhiCmdPushConstantsVk(PrRhiCommandBuffer *cb, PrRhiPipelineLayout *layout, void prRhiCmdPushConstantsVk(PrRhiCommandBuffer *cb, PrRhiPipelineLayout *layout,
PrRhiShaderStage stage_flags, u32 offset, u32 size, PrRhiShaderStage stage_flags, u32 offset, u32 size,
const void *data); const void *data);
void prRhiCmdBindVertexBuffersVk(PrRhiCommandBuffer *cb, u32 first_binding, void prRhiCmdBindVertexBuffersVk(PrRhiCommandBuffer *cb, u32 first_binding, PrRhiBufferArray buffers,
PrRhiBufferArray buffers, const u64 *offsets, u32 count); WpU64Array offsets);
void prRhiCmdBindIndexBufferVk(PrRhiCommandBuffer *cb, PrRhiBuffer *buffer, u64 offset, void prRhiCmdBindIndexBufferVk(PrRhiCommandBuffer *cb, PrRhiBuffer *buffer, u64 offset,
PrRhiIndexType index_type); PrRhiIndexType index_type);
+2 -1
View File
@@ -17,9 +17,10 @@
#define prRhiCreateDevice prRhiCreateDeviceVk #define prRhiCreateDevice prRhiCreateDeviceVk
#define prRhiDestroyDevice prRhiDestroyDeviceVk #define prRhiDestroyDevice prRhiDestroyDeviceVk
#define prRhiDeviceWaitIdle prRhiDeviceWaitIdleVk #define prRhiDeviceWaitIdle prRhiDeviceWaitIdleVk
#define prRhiGetQueueFamilyIndex prRhiGetQueueFamilyIndexVk #define prRhiGetQueueFamilyIndex prRhiGetQueueFamilyIndexVk
#define prRhiCreateSwapchain prRhiCreateSwapchainVk #define prRhiCreateSwapchain prRhiCreateSwapchainVk
#define prRhiDestroySwapchain prRhiDestroySwapchainVk #define prRhiDestroySwapchain prRhiDestroySwapchainVk
#define prRhiGetSwapchainImageCount prRhiGetSwapchainImageCountVk
#define prRhiAcquireNextImage prRhiAcquireNextImageVk #define prRhiAcquireNextImage prRhiAcquireNextImageVk
#define prRhiPresent prRhiPresentVk #define prRhiPresent prRhiPresentVk
#define prRhiRecreateSwapchain prRhiRecreateSwapchainVk #define prRhiRecreateSwapchain prRhiRecreateSwapchainVk