Initial RHI implementation
This commit is contained in:
@@ -0,0 +1,61 @@
|
|||||||
|
/* Copyright (c) 2025-2026, Sascha Willems
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct VSInput {
|
||||||
|
float3 Pos;
|
||||||
|
float3 Normal;
|
||||||
|
float2 UV;
|
||||||
|
};
|
||||||
|
|
||||||
|
Sampler2D textures[];
|
||||||
|
|
||||||
|
struct ShaderData {
|
||||||
|
float4x4 projection;
|
||||||
|
float4x4 view;
|
||||||
|
float4x4 model[3];
|
||||||
|
float4 lightPos;
|
||||||
|
uint32_t selected;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VSOutput {
|
||||||
|
float4 Pos : SV_POSITION;
|
||||||
|
float3 Normal;
|
||||||
|
float2 UV;
|
||||||
|
float3 Factor;
|
||||||
|
float3 LightVec;
|
||||||
|
float3 ViewVec;
|
||||||
|
uint32_t InstanceIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
[shader("vertex")]
|
||||||
|
VSOutput main(VSInput input, uniform ShaderData *shaderData, uint instanceIndex : SV_VulkanInstanceID) {
|
||||||
|
VSOutput output;
|
||||||
|
float4x4 modelMat = shaderData->model[instanceIndex];
|
||||||
|
output.Normal = mul((float3x3)mul(shaderData->view, modelMat), input.Normal);
|
||||||
|
output.UV = input.UV;
|
||||||
|
output.Pos = mul(shaderData->projection, mul(shaderData->view, mul(modelMat, float4(input.Pos.xyz, 1.0))));
|
||||||
|
output.Factor = (shaderData->selected == instanceIndex ? 3.0f : 1.0f);
|
||||||
|
output.InstanceIndex = instanceIndex;
|
||||||
|
// Calculate view vectors required for lighting
|
||||||
|
float4 fragPos = mul(mul(shaderData->view, modelMat), float4(input.Pos.xyz, 1.0));
|
||||||
|
output.LightVec = shaderData->lightPos.xyz - fragPos.xyz;
|
||||||
|
output.ViewVec = -fragPos.xyz;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
[shader("fragment")]
|
||||||
|
float4 main(VSOutput input) {
|
||||||
|
// Phong lighting
|
||||||
|
float3 N = normalize(input.Normal);
|
||||||
|
float3 L = normalize(input.LightVec);
|
||||||
|
float3 V = normalize(input.ViewVec);
|
||||||
|
float3 R = reflect(-L, N);
|
||||||
|
float3 diffuse = max(dot(N, L), 0.0025);
|
||||||
|
float3 specular = pow(max(dot(R, V), 0.0), 16.0) * 0.75;
|
||||||
|
// Sample from texture
|
||||||
|
float3 color = textures[NonUniformResourceIndex(input.InstanceIndex)].Sample(input.UV).rgb * input.Factor;
|
||||||
|
return float4(diffuse * color.rgb + specular, 1.0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
# Blender 5.0.1 MTL File: 'suzanne4.blend'
|
||||||
|
# www.blender.org
|
||||||
|
|
||||||
|
newmtl Material
|
||||||
|
Ns 250.000000
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.800000 0.800000 0.800000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.500000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl Material.001
|
||||||
|
Ns 250.000000
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.127605 0.127605 0.127605
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.500000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl Material.002
|
||||||
|
Ns 250.000000
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.000000 0.000000 0.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.500000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl Material.003
|
||||||
|
Ns 250.000000
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.800000 0.800000 0.800000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.500000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl Material.004
|
||||||
|
Ns 250.000000
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.800007 0.200800 0.327761
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.500000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl Material.005
|
||||||
|
Ns 250.000000
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 1.000000 1.000000 1.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.500000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
+8150
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -5,28 +5,44 @@ default: build
|
|||||||
|
|
||||||
CC := "clang"
|
CC := "clang"
|
||||||
CXX := "clang++"
|
CXX := "clang++"
|
||||||
VK_FLAGS := "-DVK_NO_PROTOTYPES -I$VULKAN_SDK/include -I$VULKAN_SDK/include/vma"
|
|
||||||
BUILDDIR := "build"
|
BUILDDIR := "build"
|
||||||
|
|
||||||
# Build the project (object files only — no entry point yet)
|
# Resolve VULKAN_SDK once via backtick
|
||||||
|
VK_SDK := `echo $VULKAN_SDK`
|
||||||
|
VENDOR_LIB := "/home/abdelrahman/Sources/programming/how-to-vulkan/vendor/lib"
|
||||||
|
|
||||||
|
VK_FLAGS := "-DVK_NO_PROTOTYPES -I" + VK_SDK + "/include -I" + VK_SDK + "/include/vma"
|
||||||
|
APP_INC := "-I" + VK_SDK + "/include -I" + VK_SDK + "/include/vma -I" + VK_SDK + "/include/slang -I/home/abdelrahman/Sources/programming/how-to-vulkan/vendor/include -Isrc"
|
||||||
|
|
||||||
|
# Build all objects, then link
|
||||||
build:
|
build:
|
||||||
mkdir -p {{BUILDDIR}}
|
mkdir -p {{BUILDDIR}}
|
||||||
{{CXX}} -g -c -Wno-nullability-completeness {{VK_FLAGS}} \
|
bear -- {{CXX}} -g -c -Wno-nullability-completeness {{VK_FLAGS}} \
|
||||||
src/prism/rhi/vulkan/profiles/vulkan_profiles.cpp \
|
src/prism/rhi/vulkan/profiles/vulkan_profiles.cpp \
|
||||||
-o {{BUILDDIR}}/vulkan_profiles.o
|
-o {{BUILDDIR}}/vulkan_profiles.o
|
||||||
{{CXX}} -g -c -Wno-nullability-completeness {{VK_FLAGS}} \
|
bear -a -- {{CXX}} -g -c -Wno-nullability-completeness {{VK_FLAGS}} \
|
||||||
src/prism/rhi/vulkan/pr_rhi_vk_vma.cpp \
|
src/prism/rhi/vulkan/pr_rhi_vk_vma.cpp \
|
||||||
-o {{BUILDDIR}}/pr_rhi_vk_vma.o
|
-o {{BUILDDIR}}/pr_rhi_vk_vma.o
|
||||||
{{CC}} -g -c {{VK_FLAGS}} $VULKAN_SDK/include/volk/volk.c -o {{BUILDDIR}}/volk.o
|
bear -a -- {{CC}} -g -c {{VK_FLAGS}} {{VK_SDK}}/include/volk/volk.c -o {{BUILDDIR}}/volk.o
|
||||||
{{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
|
||||||
{{CC}} -g -c src/wapp/wapp.c -o {{BUILDDIR}}/wapp.o
|
bear -a -- {{CC}} -g -c src/wapp/wapp.c -o {{BUILDDIR}}/wapp.o
|
||||||
@echo "--- build done (objects in {{BUILDDIR}}/) ---"
|
bear -a -- {{CXX}} -g -c -Wno-nullability-completeness -DVK_NO_PROTOTYPES \
|
||||||
|
{{APP_INC}} \
|
||||||
|
src/main.cpp \
|
||||||
|
-o {{BUILDDIR}}/main.o
|
||||||
|
bear -a -- {{CXX}} -g -DVK_NO_PROTOTYPES \
|
||||||
|
-L{{VK_SDK}}/lib -L{{VENDOR_LIB}} \
|
||||||
|
build/*.o \
|
||||||
|
-lSDL3 -lglm -ltinyobjloader -lktx -lslang -lvulkan \
|
||||||
|
-Wl,-rpath,{{VENDOR_LIB}} -Wl,-rpath,{{VK_SDK}}/lib \
|
||||||
|
-o {{BUILDDIR}}/prism
|
||||||
|
@echo "--- build done: {{BUILDDIR}}/prism ---"
|
||||||
|
|
||||||
# Clean object files
|
# Clean
|
||||||
clean:
|
clean:
|
||||||
rm -rf {{BUILDDIR}}
|
rm -rf {{BUILDDIR}}
|
||||||
|
|
||||||
# Run linter / typecheck
|
# Run linter
|
||||||
lint:
|
lint:
|
||||||
@echo "TODO: implement linter"
|
@echo "TODO: implement linter"
|
||||||
|
|
||||||
|
|||||||
+880
@@ -0,0 +1,880 @@
|
|||||||
|
// vim:fileencoding=utf-8:foldmethod=marker
|
||||||
|
//
|
||||||
|
// 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.h"
|
||||||
|
#include <vulkan/vulkan_core.h>
|
||||||
|
#include <ktx.h>
|
||||||
|
#include <ktxvulkan.h>
|
||||||
|
#include <SDL3/SDL_timer.h>
|
||||||
|
#include <glm/ext/matrix_clip_space.hpp>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
#include <glm/gtc/quaternion.hpp>
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
#include <SDL3/SDL_events.h>
|
||||||
|
#include <SDL3/SDL_init.h>
|
||||||
|
#include <SDL3/SDL_keycode.h>
|
||||||
|
#include <SDL3/SDL_video.h>
|
||||||
|
#include <SDL3/SDL_vulkan.h>
|
||||||
|
#include <slang/slang.h>
|
||||||
|
#include <slang/slang-com-ptr.h>
|
||||||
|
#include <tiny_obj_loader.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Helpers
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
static PrRhiFormat _fromVkFormat(VkFormat fmt) {
|
||||||
|
switch (fmt) {
|
||||||
|
case VK_FORMAT_R8G8B8A8_SRGB: return PR_RHI_FORMAT_R8G8B8A8_SRGB;
|
||||||
|
case VK_FORMAT_R8G8B8A8_UNORM: return PR_RHI_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
case VK_FORMAT_R16G16B16A16_SFLOAT: return PR_RHI_FORMAT_R16G16B16A16_SFLOAT;
|
||||||
|
case VK_FORMAT_R32G32B32A32_SFLOAT: return PR_RHI_FORMAT_R32G32B32A32_SFLOAT;
|
||||||
|
case VK_FORMAT_R32G32B32_SFLOAT: return PR_RHI_FORMAT_R32G32B32_SFLOAT;
|
||||||
|
case VK_FORMAT_R32G32_SFLOAT: return PR_RHI_FORMAT_R32G32_SFLOAT;
|
||||||
|
case VK_FORMAT_R32_SFLOAT: return PR_RHI_FORMAT_R32_SFLOAT;
|
||||||
|
case VK_FORMAT_D24_UNORM_S8_UINT: return PR_RHI_FORMAT_D24_UNORM_S8_UINT;
|
||||||
|
case VK_FORMAT_D32_SFLOAT_S8_UINT: return PR_RHI_FORMAT_D32_SFLOAT_S8_UINT;
|
||||||
|
case VK_FORMAT_B8G8R8A8_SRGB: return PR_RHI_FORMAT_B8G8R8A8_SRGB;
|
||||||
|
default: return PR_RHI_FORMAT_UNDEFINED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Exit codes
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
enum ExitCode {
|
||||||
|
EXIT_CODE_SUCCESS,
|
||||||
|
EXIT_CODE_SDL_INIT_FAILED,
|
||||||
|
EXIT_CODE_VULKAN_LIB_LOAD_FAILED,
|
||||||
|
EXIT_CODE_WINDOW_CREATION_FAILED,
|
||||||
|
EXIT_CODE_SURFACE_CREATION_FAILED,
|
||||||
|
EXIT_CODE_GET_WINDOW_SIZE_FAILED,
|
||||||
|
EXIT_CODE_NO_INSTANCE_SUPPORT,
|
||||||
|
EXIT_CODE_NO_PHYSICAL_DEVICES,
|
||||||
|
EXIT_CODE_ALLOCATION_FAILURE,
|
||||||
|
EXIT_CODE_NO_SUITABLE_PHYSICAL_DEVICE,
|
||||||
|
EXIT_CODE_NO_PRESENTATION_SUPPORT,
|
||||||
|
EXIT_CODE_NO_SUITABLE_DEPTH_FORMAT,
|
||||||
|
EXIT_CODE_MESH_LOAD_FAILED,
|
||||||
|
EXIT_CODE_SYNC_OBJ_CREATE_FAILED,
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void check(bool result, i32 code) {
|
||||||
|
if (!result) {
|
||||||
|
std::cerr << "Call returned an error\n";
|
||||||
|
exit(code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Types
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
struct Vertex {
|
||||||
|
glm::vec3 pos;
|
||||||
|
glm::vec3 normal;
|
||||||
|
glm::vec2 uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ShaderData {
|
||||||
|
glm::mat4 projection;
|
||||||
|
glm::mat4 view;
|
||||||
|
glm::mat4 model[3];
|
||||||
|
glm::vec4 light_pos{ 0.0f, -10.0f, 10.0f, 0.0f };
|
||||||
|
u32 selected{ 1 };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TextureResources {
|
||||||
|
PrRhiTexture *texture;
|
||||||
|
PrRhiSampler *sampler;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Typedefs for wapp arrays of our types
|
||||||
|
typedef Vertex *VertexArray;
|
||||||
|
typedef u16 *U16Array;
|
||||||
|
typedef glm::vec3 *GlmVec3Array;
|
||||||
|
typedef TextureResources *TextureResourcesArray;
|
||||||
|
typedef PrRhiBuffer **PrRhiBufferArray;
|
||||||
|
typedef PrRhiFence **PrRhiFenceArray;
|
||||||
|
typedef PrRhiSemaphore **PrRhiSemaphoreArray;
|
||||||
|
typedef PrRhiCommandBuffer **PrRhiCommandBufferArray;
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Global state
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
struct AppState {
|
||||||
|
PrRhiInstance *inst;
|
||||||
|
PrRhiPhysicalDevice *pdev;
|
||||||
|
PrRhiDevice *device;
|
||||||
|
PrRhiSurface *surface;
|
||||||
|
PrRhiSwapchain *swapchain;
|
||||||
|
|
||||||
|
PrRhiBuffer *vert_index_buf;
|
||||||
|
u64 vertex_buf_size;
|
||||||
|
u64 index_count;
|
||||||
|
|
||||||
|
static constexpr u32 max_frames_in_flight = 2;
|
||||||
|
static constexpr u32 instance_count = 3;
|
||||||
|
static constexpr u32 texture_count = 3;
|
||||||
|
|
||||||
|
PrRhiBufferArray shader_data_bufs;
|
||||||
|
PrRhiFenceArray fences;
|
||||||
|
PrRhiSemaphoreArray image_acquired_semaphores;
|
||||||
|
PrRhiSemaphoreArray render_completed_semaphores;
|
||||||
|
PrRhiCommandPool *cmd_pool;
|
||||||
|
PrRhiCommandBufferArray cmd_buffers;
|
||||||
|
|
||||||
|
TextureResourcesArray textures;
|
||||||
|
PrRhiDescriptorSetLayout *desc_set_layout;
|
||||||
|
PrRhiDescriptorPool *desc_pool;
|
||||||
|
PrRhiDescriptorSet *desc_set;
|
||||||
|
|
||||||
|
PrRhiShader *shader;
|
||||||
|
PrRhiPipelineLayout *pipeline_layout;
|
||||||
|
PrRhiPipeline *pipeline;
|
||||||
|
|
||||||
|
ShaderData shader_data;
|
||||||
|
u32 frame_index;
|
||||||
|
glm::ivec2 window_size;
|
||||||
|
GlmVec3Array object_rotations;
|
||||||
|
bool update_swapchain;
|
||||||
|
|
||||||
|
SDL_Window *window;
|
||||||
|
Slang::ComPtr<slang::IGlobalSession> slang_session;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Helpers
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
static void _uploadTexture(AppState *app, PrRhiTexture *tex,
|
||||||
|
ktxTexture *ktx_tex, WpAllocator *scratch) {
|
||||||
|
// Create staging buffer
|
||||||
|
PrRhiBufferDesc staging_desc = {};
|
||||||
|
staging_desc.size = (u32)ktx_tex->dataSize;
|
||||||
|
staging_desc.usage = PR_RHI_BUFFER_USAGE_TRANSFER_SRC;
|
||||||
|
staging_desc.memory = PR_RHI_MEMORY_CPU_TO_GPU;
|
||||||
|
|
||||||
|
PrRhiBuffer *staging = prRhiCreateBuffer(app->device, staging_desc, scratch);
|
||||||
|
void *data = prRhiBufferMap(app->device, staging);
|
||||||
|
memcpy(data, ktx_tex->pData, ktx_tex->dataSize);
|
||||||
|
prRhiBufferUnmap(app->device, staging);
|
||||||
|
|
||||||
|
// Create fence
|
||||||
|
PrRhiFenceDesc fence_desc = {};
|
||||||
|
fence_desc.signaled = false;
|
||||||
|
PrRhiFence *fence = prRhiCreateFence(app->device, fence_desc, scratch);
|
||||||
|
|
||||||
|
// Allocate temporary command buffer
|
||||||
|
PrRhiCommandBufferArray tmp_cbs = prRhiAllocateCommandBuffers(app->device,
|
||||||
|
app->cmd_pool, 1, scratch);
|
||||||
|
PrRhiCommandBuffer *cb = tmp_cbs[0];
|
||||||
|
|
||||||
|
prRhiBeginCommandBuffer(cb);
|
||||||
|
|
||||||
|
// Transition UNDEFINED → TRANSFER_DST
|
||||||
|
PrRhiImageMemoryBarrier barrier_to_transfer = {};
|
||||||
|
barrier_to_transfer.texture = tex;
|
||||||
|
barrier_to_transfer.old_layout = PR_RHI_LAYOUT_UNDEFINED;
|
||||||
|
barrier_to_transfer.new_layout = PR_RHI_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||||
|
barrier_to_transfer.src_stage_mask = (u64)VK_PIPELINE_STAGE_2_NONE;
|
||||||
|
barrier_to_transfer.src_access_mask = 0;
|
||||||
|
barrier_to_transfer.dst_stage_mask = (u64)VK_PIPELINE_STAGE_2_TRANSFER_BIT;
|
||||||
|
barrier_to_transfer.dst_access_mask = (u64)VK_ACCESS_2_TRANSFER_WRITE_BIT;
|
||||||
|
prRhiCmdPipelineBarrier(cb, wpArray(PrRhiImageMemoryBarrier, barrier_to_transfer), NULL);
|
||||||
|
|
||||||
|
// Copy all mip levels
|
||||||
|
PrRhiBufferImageCopyArray copies = wpArrayAllocCapacity(PrRhiBufferImageCopy, scratch,
|
||||||
|
ktx_tex->numLevels, WP_ARRAY_INIT_NONE);
|
||||||
|
for (u32 j = 0; j < ktx_tex->numLevels; ++j) {
|
||||||
|
ktx_size_t mip_offset = 0;
|
||||||
|
ktxTexture_GetImageOffset(ktx_tex, j, 0, 0, &mip_offset);
|
||||||
|
|
||||||
|
PrRhiBufferImageCopy copy = {};
|
||||||
|
copy.buffer_offset = mip_offset;
|
||||||
|
copy.mip_level = j;
|
||||||
|
copy.width = ktx_tex->baseWidth >> j;
|
||||||
|
copy.height = ktx_tex->baseHeight >> j;
|
||||||
|
wpArrayAppendCapped(PrRhiBufferImageCopy, copies, ©);
|
||||||
|
}
|
||||||
|
|
||||||
|
prRhiCmdCopyBufferToImage(cb, staging, tex, copies);
|
||||||
|
wpArrayDealloc(PrRhiBufferImageCopy, scratch, &copies);
|
||||||
|
|
||||||
|
// Transition TRANSFER_DST → READ_ONLY
|
||||||
|
PrRhiImageMemoryBarrier barrier_to_read = {};
|
||||||
|
barrier_to_read.texture = tex;
|
||||||
|
barrier_to_read.old_layout = PR_RHI_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||||
|
barrier_to_read.new_layout = PR_RHI_LAYOUT_READ_ONLY_OPTIMAL;
|
||||||
|
barrier_to_read.src_stage_mask = (u64)VK_PIPELINE_STAGE_2_TRANSFER_BIT;
|
||||||
|
barrier_to_read.src_access_mask = (u64)VK_ACCESS_2_TRANSFER_WRITE_BIT;
|
||||||
|
barrier_to_read.dst_stage_mask = (u64)VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||||
|
barrier_to_read.dst_access_mask = (u64)VK_ACCESS_2_SHADER_READ_BIT;
|
||||||
|
prRhiCmdPipelineBarrier(cb, wpArray(PrRhiImageMemoryBarrier, barrier_to_read), NULL);
|
||||||
|
|
||||||
|
prRhiEndCommandBuffer(cb);
|
||||||
|
|
||||||
|
// Submit and wait
|
||||||
|
prRhiQueueSubmit(app->device, cb, NULL, NULL, fence);
|
||||||
|
prRhiWaitForFences(app->device, wpArray(PrRhiFence *, fence), 1, true, UINT64_MAX);
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
prRhiDestroyFence(app->device, fence, scratch);
|
||||||
|
prRhiFreeCommandBuffers(app->device, app->cmd_pool, 1, tmp_cbs);
|
||||||
|
wpArrayDealloc(PrRhiCommandBuffer *, scratch, &tmp_cbs);
|
||||||
|
prRhiDestroyBuffer(app->device, staging, scratch);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Main
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
AppState app = {};
|
||||||
|
WpAllocator arena = wpMemArenaAllocatorInitZero(MiB(64));
|
||||||
|
|
||||||
|
// {{{ Initialisation
|
||||||
|
check(SDL_Init(SDL_INIT_VIDEO), EXIT_CODE_SDL_INIT_FAILED);
|
||||||
|
check(SDL_Vulkan_LoadLibrary(nullptr), EXIT_CODE_VULKAN_LIB_LOAD_FAILED);
|
||||||
|
|
||||||
|
f32 display_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay());
|
||||||
|
app.window = SDL_CreateWindow("How To Vulkan (Prism)", (i32)(display_scale * 1920),
|
||||||
|
(i32)(display_scale * 1080),
|
||||||
|
SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE);
|
||||||
|
check(app.window != nullptr, EXIT_CODE_WINDOW_CREATION_FAILED);
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
// {{{ Instance creation
|
||||||
|
u32 ext_count = 0;
|
||||||
|
const char *const *exts = SDL_Vulkan_GetInstanceExtensions(&ext_count);
|
||||||
|
|
||||||
|
WpAllocator scratch = wpMemArenaAllocatorInitZero(MiB(64));
|
||||||
|
|
||||||
|
PrRhiExtensionArray extensions = wpArrayAllocCapacity(const char *, &scratch, ext_count, WP_ARRAY_INIT_NONE);
|
||||||
|
for (u32 i = 0; i < ext_count; ++i) {
|
||||||
|
wpArrayAppendCapped(const char *, extensions, &exts[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
PrRhiInstanceDesc inst_desc = {};
|
||||||
|
inst_desc.extra_extensions = extensions;
|
||||||
|
app.inst = prRhiCreateInstance(inst_desc, &arena);
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
// {{{ Physical device selection
|
||||||
|
PrRhiPhysicalDeviceArray pdevs = prRhiGetPhysicalDevices(app.inst, &scratch);
|
||||||
|
check(wpArrayCount(pdevs) > 0, EXIT_CODE_NO_PHYSICAL_DEVICES);
|
||||||
|
|
||||||
|
i32 selected = -1;
|
||||||
|
for (u32 i = 0; i < wpArrayCount(pdevs); ++i) {
|
||||||
|
PrRhiPhysicalDeviceProperties props;
|
||||||
|
prRhiGetPhysicalDeviceProperties(pdevs[i], &props);
|
||||||
|
switch (props.device_type) {
|
||||||
|
case 1: // VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU
|
||||||
|
case 2: // VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU
|
||||||
|
if (props.api_version >= VK_API_VERSION_1_3) {
|
||||||
|
selected = (i32)i;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
check(selected != -1, EXIT_CODE_NO_SUITABLE_PHYSICAL_DEVICE);
|
||||||
|
app.pdev = pdevs[selected];
|
||||||
|
|
||||||
|
// Print device info
|
||||||
|
WpStr8 dev_name, driver_info;
|
||||||
|
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'
|
||||||
|
<< "Driver version: " << std::string_view((const char *)driver_info.buf, driver_info.size) << '\n';
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
// {{{ Surface creation
|
||||||
|
VkSurfaceKHR vk_surface = VK_NULL_HANDLE;
|
||||||
|
VkInstance vk_inst = (VkInstance)prRhiGetNativeInstanceHandle(app.inst);
|
||||||
|
check(SDL_Vulkan_CreateSurface(app.window, vk_inst, nullptr, &vk_surface),
|
||||||
|
EXIT_CODE_SURFACE_CREATION_FAILED);
|
||||||
|
check(SDL_GetWindowSize(app.window, &app.window_size.x, &app.window_size.y),
|
||||||
|
EXIT_CODE_GET_WINDOW_SIZE_FAILED);
|
||||||
|
app.surface = prRhiCreateSurface(app.inst, (void *)vk_surface, &arena);
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
// {{{ Device creation
|
||||||
|
PrRhiDeviceDesc dev_desc = {};
|
||||||
|
dev_desc.present_mode = PR_RHI_PRESENT_MODE_FIFO;
|
||||||
|
app.device = prRhiCreateDevice(app.pdev, app.surface, dev_desc, &arena);
|
||||||
|
u32 qfi = prRhiGetQueueFamilyIndex(app.device);
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
wpMemArenaAllocatorDestroy(&scratch);
|
||||||
|
scratch = wpMemArenaAllocatorInitZero(MiB(64));
|
||||||
|
|
||||||
|
// {{{ 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, &arena);
|
||||||
|
|
||||||
|
PrRhiFormat swapchain_format = prRhiGetSwapchainFormat(app.swapchain);
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
// {{{ Vertex/Index buffers
|
||||||
|
// {{{ Load mesh
|
||||||
|
tinyobj::attrib_t attrib;
|
||||||
|
std::vector<tinyobj::shape_t> shapes;
|
||||||
|
std::vector<tinyobj::material_t> materials;
|
||||||
|
|
||||||
|
check(tinyobj::LoadObj(&attrib, &shapes, &materials, nullptr, nullptr, "assets/suzanne.obj"),
|
||||||
|
EXIT_CODE_MESH_LOAD_FAILED);
|
||||||
|
|
||||||
|
VertexArray vertices = wpArrayAllocCapacity(Vertex, &scratch, 128, WP_ARRAY_INIT_NONE);
|
||||||
|
U16Array indices = wpArrayAllocCapacity(u16, &scratch, 128, WP_ARRAY_INIT_NONE);
|
||||||
|
|
||||||
|
for (auto &idx : shapes[0].mesh.indices) {
|
||||||
|
Vertex v = {};
|
||||||
|
v.pos = {
|
||||||
|
attrib.vertices[idx.vertex_index * 3],
|
||||||
|
-attrib.vertices[idx.vertex_index * 3 + 1],
|
||||||
|
attrib.vertices[idx.vertex_index * 3 + 2]
|
||||||
|
};
|
||||||
|
v.normal = {
|
||||||
|
attrib.normals[idx.normal_index * 3],
|
||||||
|
-attrib.normals[idx.normal_index * 3 + 1],
|
||||||
|
attrib.normals[idx.normal_index * 3 + 2]
|
||||||
|
};
|
||||||
|
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, &scratch, vertices, &v, WP_ARRAY_INIT_NONE);
|
||||||
|
indices = wpArrayAppendAlloc(u16, &scratch, indices, &index, WP_ARRAY_INIT_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
app.vertex_buf_size = sizeof(Vertex) * wpArrayCount(vertices);
|
||||||
|
app.index_count = wpArrayCount(indices);
|
||||||
|
u64 index_buf_size = sizeof(u16) * app.index_count;
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
// {{{ 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;
|
||||||
|
app.vert_index_buf = prRhiCreateBuffer(app.device, vert_desc, &arena);
|
||||||
|
|
||||||
|
void *mapped = prRhiBufferMap(app.device, app.vert_index_buf);
|
||||||
|
memcpy(mapped, vertices, app.vertex_buf_size);
|
||||||
|
memcpy((u8 *)mapped + app.vertex_buf_size, indices, index_buf_size);
|
||||||
|
prRhiBufferUnmap(app.device, app.vert_index_buf);
|
||||||
|
// }}}
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
// {{{ Shader data buffers
|
||||||
|
app.shader_data_bufs = wpArrayAllocCapacity(PrRhiBuffer *, &arena,
|
||||||
|
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;
|
||||||
|
app.shader_data_bufs[i] = prRhiCreateBuffer(app.device, buf_desc, &arena);
|
||||||
|
}
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
// {{{ Synchronisation objects
|
||||||
|
// Fences
|
||||||
|
app.fences = wpArrayAllocCapacity(PrRhiFence *, &arena, AppState::max_frames_in_flight,
|
||||||
|
WP_ARRAY_INIT_FILLED);
|
||||||
|
for (u32 i = 0; i < AppState::max_frames_in_flight; ++i) {
|
||||||
|
PrRhiFenceDesc fd = {};
|
||||||
|
fd.signaled = true;
|
||||||
|
app.fences[i] = prRhiCreateFence(app.device, fd, &arena);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Image acquired semaphores (per frame)
|
||||||
|
app.image_acquired_semaphores = wpArrayAllocCapacity(PrRhiSemaphore *, &arena,
|
||||||
|
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, &arena);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render completed semaphores (per swapchain image)
|
||||||
|
u32 swapchain_image_count = app.swapchain->image_count;
|
||||||
|
app.render_completed_semaphores = wpArrayAllocCapacity(PrRhiSemaphore *, &arena,
|
||||||
|
swapchain_image_count,
|
||||||
|
WP_ARRAY_INIT_FILLED);
|
||||||
|
for (u32 i = 0; i < swapchain_image_count; ++i) {
|
||||||
|
app.render_completed_semaphores[i] = prRhiCreateSemaphore(app.device, &arena);
|
||||||
|
}
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
// {{{ Command pool and buffers
|
||||||
|
PrRhiCommandPoolDesc pool_desc = {};
|
||||||
|
pool_desc.queue_family_index = qfi;
|
||||||
|
app.cmd_pool = prRhiCreateCommandPool(app.device, pool_desc, &arena);
|
||||||
|
|
||||||
|
app.cmd_buffers = prRhiAllocateCommandBuffers(app.device, app.cmd_pool,
|
||||||
|
AppState::max_frames_in_flight, &arena);
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
wpMemArenaAllocatorTempBegin(&scratch);
|
||||||
|
|
||||||
|
// {{{ Texture loading
|
||||||
|
app.textures = wpArrayAllocCapacity(TextureResources, &arena, AppState::texture_count,
|
||||||
|
WP_ARRAY_INIT_FILLED);
|
||||||
|
|
||||||
|
for (u32 i = 0; i < AppState::texture_count; ++i) {
|
||||||
|
// Load KTX
|
||||||
|
ktxTexture *ktx_tex = nullptr;
|
||||||
|
char buf[2048] = {};
|
||||||
|
snprintf(buf, sizeof(buf), "assets/suzanne%u.ktx", i);
|
||||||
|
ktxTexture_CreateFromNamedFile(buf, KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT, &ktx_tex);
|
||||||
|
|
||||||
|
VkFormat vk_fmt = ktxTexture_GetVkFormat(ktx_tex);
|
||||||
|
|
||||||
|
// Create texture
|
||||||
|
PrRhiTextureDesc tex_desc = {};
|
||||||
|
tex_desc.format = _fromVkFormat(vk_fmt);
|
||||||
|
tex_desc.width = (u32)ktx_tex->baseWidth;
|
||||||
|
tex_desc.height = (u32)ktx_tex->baseHeight;
|
||||||
|
tex_desc.mip_levels = (u32)ktx_tex->numLevels;
|
||||||
|
tex_desc.usage = (PrRhiTextureUsage)(PR_RHI_TEXTURE_USAGE_TRANSFER_DST |
|
||||||
|
PR_RHI_TEXTURE_USAGE_SAMPLED);
|
||||||
|
|
||||||
|
PrRhiTexture *tex = prRhiCreateTexture(app.device, tex_desc, &arena);
|
||||||
|
|
||||||
|
// Upload texture data
|
||||||
|
_uploadTexture(&app, tex, ktx_tex, &scratch);
|
||||||
|
|
||||||
|
// 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 = VK_LOD_CLAMP_NONE;
|
||||||
|
PrRhiSampler *sampler = prRhiCreateSampler(app.device, samp_desc, &arena);
|
||||||
|
|
||||||
|
app.textures[i].texture = tex;
|
||||||
|
app.textures[i].sampler = sampler;
|
||||||
|
|
||||||
|
ktxTexture_Destroy(ktx_tex);
|
||||||
|
}
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
// {{{ 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, bindings[0]);
|
||||||
|
|
||||||
|
PrRhiDescriptorSetLayoutDesc layout_desc = {};
|
||||||
|
layout_desc.bindings = ds_layouts;
|
||||||
|
app.desc_set_layout = prRhiCreateDescriptorSetLayout(app.device, layout_desc, &arena);
|
||||||
|
|
||||||
|
// Pool
|
||||||
|
PrRhiDescriptorPoolSize pool_size = {};
|
||||||
|
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, &arena);
|
||||||
|
|
||||||
|
// Allocate descriptor set (variable count)
|
||||||
|
app.desc_set = prRhiAllocateDescriptorSet(app.device, app.desc_pool,
|
||||||
|
app.desc_set_layout,
|
||||||
|
AppState::texture_count, &arena);
|
||||||
|
|
||||||
|
// Write descriptor set
|
||||||
|
PrRhiDescriptorImageInfoArray img_infos = wpArrayAllocCapacity(PrRhiDescriptorImageInfo,
|
||||||
|
&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;
|
||||||
|
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;
|
||||||
|
|
||||||
|
PrRhiWriteDescriptorSetArray writes = wpArray(PrRhiWriteDescriptorSet, write);
|
||||||
|
prRhiUpdateDescriptorSet(app.device, writes);
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
wpMemArenaAllocatorTempEnd(&scratch);
|
||||||
|
|
||||||
|
// {{{ Shader compilation (Slang)
|
||||||
|
slang::createGlobalSession(app.slang_session.writeRef());
|
||||||
|
|
||||||
|
slang::TargetDesc target = {};
|
||||||
|
target.format = SLANG_SPIRV;
|
||||||
|
target.profile = {app.slang_session->findProfile("spirv_1_4")};
|
||||||
|
|
||||||
|
Slang::ComPtr<slang::ISession> slang_session;
|
||||||
|
slang::SessionDesc session_desc = {};
|
||||||
|
session_desc.targets = ⌖
|
||||||
|
session_desc.targetCount = 1;
|
||||||
|
session_desc.defaultMatrixLayoutMode = SLANG_MATRIX_LAYOUT_COLUMN_MAJOR;
|
||||||
|
app.slang_session->createSession(session_desc, slang_session.writeRef());
|
||||||
|
|
||||||
|
Slang::ComPtr<slang::IModule> slang_module {
|
||||||
|
slang_session->loadModuleFromSource("triangle", "assets/shader.slang", nullptr, nullptr),
|
||||||
|
};
|
||||||
|
Slang::ComPtr<slang::IBlob> spirv;
|
||||||
|
slang_module->getTargetCode(0, spirv.writeRef());
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
// {{{ Create shader module
|
||||||
|
PrRhiShaderDesc shader_desc = {};
|
||||||
|
shader_desc.spirv_code = spirv->getBufferPointer();
|
||||||
|
shader_desc.spirv_size = spirv->getBufferSize();
|
||||||
|
app.shader = prRhiCreateShader(app.device, shader_desc, &arena);
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
// {{{ Pipeline layout
|
||||||
|
PrRhiPushConstantRange pc_range = {};
|
||||||
|
pc_range.stage_flags = PR_RHI_SHADER_STAGE_VERTEX;
|
||||||
|
pc_range.size = sizeof(u64); // VkDeviceAddress
|
||||||
|
|
||||||
|
PrRhiDescriptorSetLayout *set_layouts_pl[] = { app.desc_set_layout };
|
||||||
|
PrRhiDescriptorSetLayoutArray pl_layouts = wpArray(PrRhiDescriptorSetLayout *, set_layouts_pl[0]);
|
||||||
|
|
||||||
|
PrRhiPipelineLayoutDesc pl_desc = {};
|
||||||
|
pl_desc.set_layouts = pl_layouts;
|
||||||
|
pl_desc.push_constant_ranges = wpArray(PrRhiPushConstantRange, pc_range);
|
||||||
|
app.pipeline_layout = prRhiCreatePipelineLayout(app.device, pl_desc, &arena);
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
// {{{ Graphics pipeline
|
||||||
|
PrRhiVertexInputBinding vertex_binding = {};
|
||||||
|
vertex_binding.binding = 0;
|
||||||
|
vertex_binding.stride = 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);
|
||||||
|
|
||||||
|
PrRhiColorBlendAttachment blend_attachment = {};
|
||||||
|
blend_attachment.color_write_mask = 0xf;
|
||||||
|
|
||||||
|
PrRhiFormat color_fmts[] = { swapchain_format };
|
||||||
|
PrRhiFormatArray color_fmt_array = wpArray(PrRhiFormat, color_fmts[0]);
|
||||||
|
|
||||||
|
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, &arena);
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
// {{{ Render loop
|
||||||
|
app.object_rotations = wpArrayAllocCapacity(glm::vec3, &arena, AppState::instance_count,
|
||||||
|
WP_ARRAY_INIT_FILLED);
|
||||||
|
u64 last_time = SDL_GetTicks();
|
||||||
|
SDL_Event event = {};
|
||||||
|
app.frame_index = 0;
|
||||||
|
u32 image_index = 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
// {{{ Wait on fence
|
||||||
|
PrRhiFence *wait_fence = app.fences[app.frame_index];
|
||||||
|
prRhiWaitForFences(app.device, wpArray(PrRhiFence *, wait_fence), 1, true, UINT64_MAX);
|
||||||
|
prRhiResetFences(app.device, wpArray(PrRhiFence *, wait_fence), 1);
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
// {{{ Acquire next image
|
||||||
|
PrRhiSwapchainResult acq = prRhiAcquireNextImage(app.device, app.swapchain,
|
||||||
|
app.image_acquired_semaphores[app.frame_index],
|
||||||
|
&image_index);
|
||||||
|
if (acq == PR_RHI_SWAPCHAIN_OUT_OF_DATE) {
|
||||||
|
app.update_swapchain = true;
|
||||||
|
}
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
if (app.update_swapchain) {
|
||||||
|
// Skip this frame — will recreate below
|
||||||
|
} 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);
|
||||||
|
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);
|
||||||
|
app.shader_data.model[i] = glm::translate(glm::mat4(1.0f), instance_pos) *
|
||||||
|
glm::mat4_cast(glm::quat(app.object_rotations[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
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]);
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
// {{{ Record command buffer
|
||||||
|
PrRhiCommandBuffer *cb = app.cmd_buffers[app.frame_index];
|
||||||
|
prRhiResetCommandBuffer(cb);
|
||||||
|
prRhiBeginCommandBuffer(cb);
|
||||||
|
|
||||||
|
// Transition images to attachment optimal
|
||||||
|
{
|
||||||
|
PrRhiImageMemoryBarrier img_barriers[2] = {};
|
||||||
|
|
||||||
|
// 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 = (u64)VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||||
|
img_barriers[0].src_access_mask = 0;
|
||||||
|
img_barriers[0].dst_stage_mask = (u64)VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||||
|
img_barriers[0].dst_access_mask = (u64)(VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT);
|
||||||
|
|
||||||
|
// Depth attachment
|
||||||
|
PrRhiTexture *depth_tex = prRhiGetSwapchainDepthTexture(app.swapchain);
|
||||||
|
img_barriers[1].texture = depth_tex;
|
||||||
|
img_barriers[1].old_layout = PR_RHI_LAYOUT_UNDEFINED;
|
||||||
|
img_barriers[1].new_layout = PR_RHI_LAYOUT_ATTACHMENT_OPTIMAL;
|
||||||
|
img_barriers[1].src_stage_mask = (u64)VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT;
|
||||||
|
img_barriers[1].src_access_mask = (u64)VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||||
|
img_barriers[1].dst_stage_mask = (u64)VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT;
|
||||||
|
img_barriers[1].dst_access_mask = (u64)VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
PrRhiColorAttachmentArray color_arr = wpArray(PrRhiColorAttachment, color_att);
|
||||||
|
prRhiCmdBeginRendering(cb, color_arr, &depth_att);
|
||||||
|
}
|
||||||
|
|
||||||
|
prRhiCmdSetViewport(cb, 0.0f, 0.0f, (f32)app.window_size.x, (f32)app.window_size.y);
|
||||||
|
prRhiCmdSetScissor(cb, 0, 0, (u32)app.window_size.x, (u32)app.window_size.y);
|
||||||
|
|
||||||
|
prRhiCmdBindPipeline(cb, PR_RHI_PIPELINE_BIND_POINT_GRAPHICS, app.pipeline);
|
||||||
|
|
||||||
|
PrRhiDescriptorSetArray sets = wpArray(PrRhiDescriptorSet *, app.desc_set);
|
||||||
|
prRhiCmdBindDescriptorSets(cb, PR_RHI_PIPELINE_BIND_POINT_GRAPHICS,
|
||||||
|
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);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
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 = (u64)VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||||
|
present_barrier.src_access_mask = (u64)VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT;
|
||||||
|
present_barrier.dst_stage_mask = (u64)VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||||
|
present_barrier.dst_access_mask = 0;
|
||||||
|
|
||||||
|
prRhiCmdPipelineBarrier(cb, wpArray(PrRhiImageMemoryBarrier, present_barrier), 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]);
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
// {{{ Present
|
||||||
|
PrRhiSwapchainResult pres = prRhiPresent(app.device, app.swapchain,
|
||||||
|
app.render_completed_semaphores[image_index]);
|
||||||
|
if (pres == PR_RHI_SWAPCHAIN_OUT_OF_DATE) {
|
||||||
|
app.update_swapchain = true;
|
||||||
|
}
|
||||||
|
// }}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// {{{ Poll events
|
||||||
|
f32 elapsed_time = (SDL_GetTicks() - last_time) / 1000.0f;
|
||||||
|
last_time = SDL_GetTicks();
|
||||||
|
while (SDL_PollEvent(&event)) {
|
||||||
|
switch (event.type) {
|
||||||
|
case SDL_EVENT_QUIT:
|
||||||
|
app.update_swapchain = false; // signal exit — use update_swapchain flag
|
||||||
|
goto done;
|
||||||
|
case SDL_EVENT_KEY_DOWN:
|
||||||
|
if (event.key.key == SDLK_ESCAPE) goto done;
|
||||||
|
if (event.key.key == SDLK_PLUS || event.key.key == SDLK_KP_PLUS || event.key.key == SDLK_EQUALS) {
|
||||||
|
app.shader_data.selected = (app.shader_data.selected < 2) ? app.shader_data.selected + 1 : 0;
|
||||||
|
}
|
||||||
|
if (event.key.key == SDLK_MINUS || event.key.key == SDLK_KP_MINUS) {
|
||||||
|
app.shader_data.selected = (app.shader_data.selected > 0) ? app.shader_data.selected - 1 : 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SDL_EVENT_MOUSE_MOTION:
|
||||||
|
if (event.button.button == SDL_BUTTON_LEFT) {
|
||||||
|
app.object_rotations[app.shader_data.selected].x -= (f32)event.motion.yrel * elapsed_time;
|
||||||
|
app.object_rotations[app.shader_data.selected].y += (f32)event.motion.xrel * elapsed_time;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SDL_EVENT_MOUSE_WHEEL:
|
||||||
|
// Camera position handled via shader_data update in loop
|
||||||
|
break;
|
||||||
|
case SDL_EVENT_WINDOW_RESIZED:
|
||||||
|
check(SDL_GetWindowSize(app.window, &app.window_size.x, &app.window_size.y),
|
||||||
|
EXIT_CODE_GET_WINDOW_SIZE_FAILED);
|
||||||
|
app.update_swapchain = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
// {{{ Swapchain recreate
|
||||||
|
if (app.update_swapchain) {
|
||||||
|
prRhiDeviceWaitIdle(app.device);
|
||||||
|
prRhiRecreateSwapchain(app.device, &app.swapchain,
|
||||||
|
(u32)app.window_size.x, (u32)app.window_size.y, &arena);
|
||||||
|
|
||||||
|
// Re-create render completed semaphores for new image count
|
||||||
|
// TODO: proper cleanup — for now, just leak old ones
|
||||||
|
u32 new_count = 0;
|
||||||
|
prRhiAcquireNextImage(app.device, app.swapchain, NULL, &new_count);
|
||||||
|
app.render_completed_semaphores = wpArrayAllocCapacity(PrRhiSemaphore *, &arena,
|
||||||
|
new_count, WP_ARRAY_INIT_FILLED);
|
||||||
|
for (u32 i = 0; i < new_count; ++i) {
|
||||||
|
app.render_completed_semaphores[i] = prRhiCreateSemaphore(app.device, &arena);
|
||||||
|
}
|
||||||
|
|
||||||
|
app.update_swapchain = false;
|
||||||
|
}
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
app.frame_index = (app.frame_index + 1) % AppState::max_frames_in_flight;
|
||||||
|
}
|
||||||
|
done:
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
// {{{ Cleanup
|
||||||
|
prRhiDeviceWaitIdle(app.device);
|
||||||
|
|
||||||
|
prRhiDestroyPipeline(app.device, app.pipeline, &arena);
|
||||||
|
prRhiDestroyPipelineLayout(app.device, app.pipeline_layout, &arena);
|
||||||
|
prRhiDestroyShader(app.device, app.shader, &arena);
|
||||||
|
prRhiDestroyDescriptorPool(app.device, app.desc_pool, &arena);
|
||||||
|
prRhiDestroyDescriptorSetLayout(app.device, app.desc_set_layout, &arena);
|
||||||
|
|
||||||
|
for (u32 i = 0; i < AppState::texture_count; ++i) {
|
||||||
|
prRhiDestroySampler(app.device, app.textures[i].sampler, &arena);
|
||||||
|
prRhiDestroyTexture(app.device, app.textures[i].texture, &arena);
|
||||||
|
}
|
||||||
|
|
||||||
|
prRhiFreeCommandBuffers(app.device, app.cmd_pool, AppState::max_frames_in_flight,
|
||||||
|
app.cmd_buffers);
|
||||||
|
prRhiDestroyCommandPool(app.device, app.cmd_pool, &arena);
|
||||||
|
|
||||||
|
for (u32 i = 0; i < swapchain_image_count; ++i) {
|
||||||
|
prRhiDestroySemaphore(app.device, app.render_completed_semaphores[i], &arena);
|
||||||
|
}
|
||||||
|
for (u32 i = 0; i < AppState::max_frames_in_flight; ++i) {
|
||||||
|
prRhiDestroySemaphore(app.device, app.image_acquired_semaphores[i], &arena);
|
||||||
|
prRhiDestroyFence(app.device, app.fences[i], &arena);
|
||||||
|
prRhiDestroyBuffer(app.device, app.shader_data_bufs[i], &arena);
|
||||||
|
}
|
||||||
|
prRhiDestroyBuffer(app.device, app.vert_index_buf, &arena);
|
||||||
|
|
||||||
|
prRhiDestroySwapchain(app.device, app.swapchain, &arena);
|
||||||
|
prRhiDestroyDevice(app.device, &arena);
|
||||||
|
prRhiDestroySurface(app.inst, app.surface, &arena);
|
||||||
|
prRhiDestroyInstance(app.inst, &arena);
|
||||||
|
|
||||||
|
SDL_DestroyWindow(app.window);
|
||||||
|
SDL_Vulkan_UnloadLibrary();
|
||||||
|
SDL_Quit();
|
||||||
|
|
||||||
|
wpMemArenaAllocatorDestroy(&arena);
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
return EXIT_CODE_SUCCESS;
|
||||||
|
}
|
||||||
+15
-1
@@ -25,12 +25,17 @@
|
|||||||
|
|
||||||
#include "pr_rhi_types.h"
|
#include "pr_rhi_types.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
// ======================================================================
|
// ======================================================================
|
||||||
// Instance
|
// Instance
|
||||||
// ======================================================================
|
// ======================================================================
|
||||||
|
|
||||||
PrRhiInstance *prRhiCreateInstance(PrRhiInstanceDesc desc, WpAllocator *alloc);
|
PrRhiInstance *prRhiCreateInstance(PrRhiInstanceDesc desc, WpAllocator *alloc);
|
||||||
void prRhiDestroyInstance(PrRhiInstance *inst, WpAllocator *alloc);
|
void prRhiDestroyInstance(PrRhiInstance *inst, WpAllocator *alloc);
|
||||||
|
void *prRhiGetNativeInstanceHandle(PrRhiInstance *inst);
|
||||||
|
|
||||||
// ======================================================================
|
// ======================================================================
|
||||||
// Physical device enumeration
|
// Physical device enumeration
|
||||||
@@ -39,6 +44,8 @@ void prRhiDestroyInstance(PrRhiInstance *inst, WpAllocator *alloc);
|
|||||||
PrRhiPhysicalDeviceArray prRhiGetPhysicalDevices(PrRhiInstance *inst, const WpAllocator *scratch);
|
PrRhiPhysicalDeviceArray prRhiGetPhysicalDevices(PrRhiInstance *inst, const WpAllocator *scratch);
|
||||||
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 *out);
|
||||||
|
|
||||||
// ======================================================================
|
// ======================================================================
|
||||||
// Surface (platform-specific)
|
// Surface (platform-specific)
|
||||||
@@ -57,6 +64,7 @@ PrRhiDevice *prRhiCreateDevice(PrRhiPhysicalDevice *pdev, PrRhiSurface *surface,
|
|||||||
PrRhiDeviceDesc desc, WpAllocator *alloc);
|
PrRhiDeviceDesc desc, WpAllocator *alloc);
|
||||||
void prRhiDestroyDevice(PrRhiDevice *device, WpAllocator *alloc);
|
void prRhiDestroyDevice(PrRhiDevice *device, WpAllocator *alloc);
|
||||||
void prRhiDeviceWaitIdle(PrRhiDevice *device);
|
void prRhiDeviceWaitIdle(PrRhiDevice *device);
|
||||||
|
u32 prRhiGetQueueFamilyIndex(PrRhiDevice *device);
|
||||||
|
|
||||||
// ======================================================================
|
// ======================================================================
|
||||||
// Swapchain
|
// Swapchain
|
||||||
@@ -78,6 +86,7 @@ void prRhiRecreateSwapchain(PrRhiDevice *device, PrRhiSwapchain
|
|||||||
|
|
||||||
PrRhiTexture *prRhiGetSwapchainTexture(PrRhiSwapchain *swapchain, u32 image_index);
|
PrRhiTexture *prRhiGetSwapchainTexture(PrRhiSwapchain *swapchain, u32 image_index);
|
||||||
PrRhiTexture *prRhiGetSwapchainDepthTexture(PrRhiSwapchain *swapchain);
|
PrRhiTexture *prRhiGetSwapchainDepthTexture(PrRhiSwapchain *swapchain);
|
||||||
|
PrRhiFormat prRhiGetSwapchainFormat(PrRhiSwapchain *swapchain);
|
||||||
|
|
||||||
// ======================================================================
|
// ======================================================================
|
||||||
// Buffers
|
// Buffers
|
||||||
@@ -258,7 +267,8 @@ void prRhiCmdDrawIndexed(PrRhiCommandBuffer *cb, u32 index_count, u32 instance_c
|
|||||||
|
|
||||||
// --- Copy ---
|
// --- Copy ---
|
||||||
|
|
||||||
void prRhiCmdCopyBufferToImage(PrRhiCommandBuffer *cb, PrRhiBuffer *src, PrRhiTexture *dst);
|
void prRhiCmdCopyBufferToImage(PrRhiCommandBuffer *cb, PrRhiBuffer *src, PrRhiTexture *dst,
|
||||||
|
PrRhiBufferImageCopyArray copies);
|
||||||
|
|
||||||
// ======================================================================
|
// ======================================================================
|
||||||
// Queue submission
|
// Queue submission
|
||||||
@@ -282,5 +292,9 @@ void prRhiQueueSubmit(PrRhiDevice *device, PrRhiCommandBuffer *cb,
|
|||||||
# error "Define one of: PR_RHI_VULKAN, PR_RHI_D3D12, PR_RHI_METAL"
|
# error "Define one of: PR_RHI_VULKAN, PR_RHI_D3D12, PR_RHI_METAL"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -212,14 +212,29 @@ typedef struct PrRhiImageMemoryBarrier {
|
|||||||
PrRhiTexture *texture;
|
PrRhiTexture *texture;
|
||||||
PrRhiImageLayout old_layout;
|
PrRhiImageLayout old_layout;
|
||||||
PrRhiImageLayout new_layout;
|
PrRhiImageLayout new_layout;
|
||||||
|
u64 src_stage_mask;
|
||||||
|
u64 src_access_mask;
|
||||||
|
u64 dst_stage_mask;
|
||||||
|
u64 dst_access_mask;
|
||||||
} PrRhiImageMemoryBarrier;
|
} PrRhiImageMemoryBarrier;
|
||||||
|
|
||||||
typedef struct PrRhiBufferMemoryBarrier {
|
typedef struct PrRhiBufferMemoryBarrier {
|
||||||
PrRhiBuffer *buffer;
|
PrRhiBuffer *buffer;
|
||||||
u64 offset;
|
u64 offset;
|
||||||
u64 size;
|
u64 size;
|
||||||
|
u64 src_stage_mask;
|
||||||
|
u64 src_access_mask;
|
||||||
|
u64 dst_stage_mask;
|
||||||
|
u64 dst_access_mask;
|
||||||
} PrRhiBufferMemoryBarrier;
|
} PrRhiBufferMemoryBarrier;
|
||||||
|
|
||||||
|
typedef struct PrRhiBufferImageCopy {
|
||||||
|
u64 buffer_offset;
|
||||||
|
u32 mip_level;
|
||||||
|
u32 width;
|
||||||
|
u32 height;
|
||||||
|
} PrRhiBufferImageCopy;
|
||||||
|
|
||||||
typedef struct PrRhiColorAttachment {
|
typedef struct PrRhiColorAttachment {
|
||||||
PrRhiTexture *texture;
|
PrRhiTexture *texture;
|
||||||
PrRhiImageLayout layout;
|
PrRhiImageLayout layout;
|
||||||
@@ -255,6 +270,7 @@ typedef PrRhiDescriptorBufferInfo *PrRhiDescriptorBufferInfoArray;
|
|||||||
typedef PrRhiImageMemoryBarrier *PrRhiImageMemoryBarrierArray;
|
typedef PrRhiImageMemoryBarrier *PrRhiImageMemoryBarrierArray;
|
||||||
typedef PrRhiBufferMemoryBarrier *PrRhiBufferMemoryBarrierArray;
|
typedef PrRhiBufferMemoryBarrier *PrRhiBufferMemoryBarrierArray;
|
||||||
typedef PrRhiColorAttachment *PrRhiColorAttachmentArray;
|
typedef PrRhiColorAttachment *PrRhiColorAttachmentArray;
|
||||||
|
typedef PrRhiBufferImageCopy *PrRhiBufferImageCopyArray;
|
||||||
typedef struct PrRhiWriteDescriptorSet *PrRhiWriteDescriptorSetArray;
|
typedef struct PrRhiWriteDescriptorSet *PrRhiWriteDescriptorSetArray;
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@@ -367,6 +383,7 @@ typedef struct PrRhiSwapchainDesc {
|
|||||||
u32 width;
|
u32 width;
|
||||||
u32 height;
|
u32 height;
|
||||||
b8 has_depth;
|
b8 has_depth;
|
||||||
|
PrRhiFormat depth_format; // PR_RHI_FORMAT_UNDEFINED = auto-pick
|
||||||
} PrRhiSwapchainDesc;
|
} PrRhiSwapchainDesc;
|
||||||
|
|
||||||
typedef struct PrRhiSurfaceCapabilities {
|
typedef struct PrRhiSurfaceCapabilities {
|
||||||
@@ -380,6 +397,11 @@ typedef struct PrRhiSurfaceCapabilities {
|
|||||||
u32 max_height;
|
u32 max_height;
|
||||||
} PrRhiSurfaceCapabilities;
|
} PrRhiSurfaceCapabilities;
|
||||||
|
|
||||||
|
typedef struct PrRhiPhysicalDeviceProperties {
|
||||||
|
u32 api_version;
|
||||||
|
u32 device_type; // VkPhysicalDeviceType
|
||||||
|
} PrRhiPhysicalDeviceProperties;
|
||||||
|
|
||||||
typedef u64 PrRhiDeviceAddress;
|
typedef u64 PrRhiDeviceAddress;
|
||||||
|
|
||||||
// --- Command buffer types ---
|
// --- Command buffer types ---
|
||||||
|
|||||||
@@ -71,6 +71,22 @@ void _checkVkBool(VkResult res, const char *site) {
|
|||||||
if (res < VK_SUCCESS) _abort(site);
|
if (res < VK_SUCCESS) _abort(site);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PrRhiFormat _fromVkFormat(VkFormat fmt) {
|
||||||
|
switch (fmt) {
|
||||||
|
case VK_FORMAT_R8G8B8A8_SRGB: return PR_RHI_FORMAT_R8G8B8A8_SRGB;
|
||||||
|
case VK_FORMAT_R8G8B8A8_UNORM: return PR_RHI_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
case VK_FORMAT_R16G16B16A16_SFLOAT: return PR_RHI_FORMAT_R16G16B16A16_SFLOAT;
|
||||||
|
case VK_FORMAT_R32G32B32A32_SFLOAT: return PR_RHI_FORMAT_R32G32B32A32_SFLOAT;
|
||||||
|
case VK_FORMAT_R32G32B32_SFLOAT: return PR_RHI_FORMAT_R32G32B32_SFLOAT;
|
||||||
|
case VK_FORMAT_R32G32_SFLOAT: return PR_RHI_FORMAT_R32G32_SFLOAT;
|
||||||
|
case VK_FORMAT_R32_SFLOAT: return PR_RHI_FORMAT_R32_SFLOAT;
|
||||||
|
case VK_FORMAT_D24_UNORM_S8_UINT: return PR_RHI_FORMAT_D24_UNORM_S8_UINT;
|
||||||
|
case VK_FORMAT_D32_SFLOAT_S8_UINT: return PR_RHI_FORMAT_D32_SFLOAT_S8_UINT;
|
||||||
|
case VK_FORMAT_B8G8R8A8_SRGB: return PR_RHI_FORMAT_B8G8R8A8_SRGB;
|
||||||
|
default: return PR_RHI_FORMAT_UNDEFINED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
VkFormat _toVkFormat(PrRhiFormat fmt) {
|
VkFormat _toVkFormat(PrRhiFormat fmt) {
|
||||||
switch (fmt) {
|
switch (fmt) {
|
||||||
case PR_RHI_FORMAT_R8G8B8A8_SRGB: return VK_FORMAT_R8G8B8A8_SRGB;
|
case PR_RHI_FORMAT_R8G8B8A8_SRGB: return VK_FORMAT_R8G8B8A8_SRGB;
|
||||||
@@ -253,6 +269,8 @@ VkSamplerAddressMode _toVkAddressMode(PrRhiAddressMode m) {
|
|||||||
PrRhiInstance *prRhiCreateInstanceVk(PrRhiInstanceDesc desc, WpAllocator *alloc) {
|
PrRhiInstance *prRhiCreateInstanceVk(PrRhiInstanceDesc desc, WpAllocator *alloc) {
|
||||||
(void)desc;
|
(void)desc;
|
||||||
|
|
||||||
|
volkInitialize();
|
||||||
|
|
||||||
VkBool32 supported = VK_FALSE;
|
VkBool32 supported = VK_FALSE;
|
||||||
_checkVk(vpGetInstanceProfileSupport(NULL, &_profile, &supported), "vpGetInstanceProfileSupport");
|
_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");
|
||||||
@@ -296,6 +314,10 @@ void prRhiDestroyInstanceVk(PrRhiInstance *inst, WpAllocator *alloc) {
|
|||||||
wpMemAllocatorFree(alloc, (void**)&inst, sizeof(PrRhiInstance));
|
wpMemAllocatorFree(alloc, (void**)&inst, sizeof(PrRhiInstance));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *prRhiGetNativeInstanceHandleVk(PrRhiInstance *inst) {
|
||||||
|
return inst->handle;
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Physical device enumeration
|
// Physical device enumeration
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@@ -321,6 +343,14 @@ PrRhiPhysicalDeviceArray prRhiGetPhysicalDevicesVk(PrRhiInstance *inst, const Wp
|
|||||||
if (!pdev) _abort("alloc failed for PrRhiPhysicalDevice");
|
if (!pdev) _abort("alloc failed for PrRhiPhysicalDevice");
|
||||||
pdev->handle = vk_devices[i];
|
pdev->handle = vk_devices[i];
|
||||||
pdev->instance = inst;
|
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;
|
||||||
|
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));
|
||||||
|
|
||||||
wpArrayAppendCapped(PrRhiPhysicalDevice *, pdevs, &pdev);
|
wpArrayAppendCapped(PrRhiPhysicalDevice *, pdevs, &pdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,24 +358,25 @@ PrRhiPhysicalDeviceArray prRhiGetPhysicalDevicesVk(PrRhiInstance *inst, const Wp
|
|||||||
}
|
}
|
||||||
|
|
||||||
void prRhiGetPhysicalDeviceNameVk(PrRhiPhysicalDevice *pdev, WpStr8 *out) {
|
void prRhiGetPhysicalDeviceNameVk(PrRhiPhysicalDevice *pdev, WpStr8 *out) {
|
||||||
VkPhysicalDeviceProperties2 props = { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 };
|
out->buf = pdev->device_name;
|
||||||
vkGetPhysicalDeviceProperties2((VkPhysicalDevice)pdev->handle, &props);
|
out->size = strlen((const char *)pdev->device_name);
|
||||||
const char *name = props.properties.deviceName;
|
|
||||||
out->buf = (c8*)name;
|
|
||||||
out->size = strlen(name);
|
|
||||||
out->capacity = 0;
|
out->capacity = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void prRhiGetPhysicalDeviceDriverInfoVk(PrRhiPhysicalDevice *pdev, WpStr8 *out) {
|
void prRhiGetPhysicalDeviceDriverInfoVk(PrRhiPhysicalDevice *pdev, WpStr8 *out) {
|
||||||
VkPhysicalDeviceDriverProperties driver_props = { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES };
|
out->buf = pdev->driver_info;
|
||||||
VkPhysicalDeviceProperties2 props = { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, .pNext = &driver_props };
|
out->size = strlen((const char *)pdev->driver_info);
|
||||||
vkGetPhysicalDeviceProperties2((VkPhysicalDevice)pdev->handle, &props);
|
|
||||||
const char *info = driver_props.driverInfo;
|
|
||||||
out->buf = (c8*)info;
|
|
||||||
out->size = strlen(info);
|
|
||||||
out->capacity = 0;
|
out->capacity = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void prRhiGetPhysicalDevicePropertiesVk(PrRhiPhysicalDevice *pdev,
|
||||||
|
PrRhiPhysicalDeviceProperties *out) {
|
||||||
|
VkPhysicalDeviceProperties2 props = { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 };
|
||||||
|
vkGetPhysicalDeviceProperties2((VkPhysicalDevice)pdev->handle, &props);
|
||||||
|
out->api_version = props.properties.apiVersion;
|
||||||
|
out->device_type = (u32)props.properties.deviceType;
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Surface
|
// Surface
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@@ -501,6 +532,10 @@ void prRhiDeviceWaitIdleVk(PrRhiDevice *device) {
|
|||||||
_checkVk(vkDeviceWaitIdle((VkDevice)device->handle), "vkDeviceWaitIdle");
|
_checkVk(vkDeviceWaitIdle((VkDevice)device->handle), "vkDeviceWaitIdle");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 prRhiGetQueueFamilyIndexVk(PrRhiDevice *device) {
|
||||||
|
return device->queue_family_index;
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Swapchain
|
// Swapchain
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@@ -606,19 +641,25 @@ PrRhiSwapchain *prRhiCreateSwapchainVk(PrRhiDevice *device, PrRhiSwapchainDesc d
|
|||||||
swapchain->images = images;
|
swapchain->images = images;
|
||||||
swapchain->depth = NULL;
|
swapchain->depth = NULL;
|
||||||
swapchain->format = _default_image_format;
|
swapchain->format = _default_image_format;
|
||||||
|
swapchain->depth_format = VK_FORMAT_UNDEFINED;
|
||||||
swapchain->width = extent.width;
|
swapchain->width = extent.width;
|
||||||
swapchain->height = extent.height;
|
swapchain->height = extent.height;
|
||||||
swapchain->current_image_index = 0;
|
swapchain->current_image_index = 0;
|
||||||
|
|
||||||
// Create depth texture if requested
|
// Create depth texture if requested
|
||||||
|
VkFormat depth_pick_fmt = VK_FORMAT_UNDEFINED;
|
||||||
if (desc.has_depth) {
|
if (desc.has_depth) {
|
||||||
VkFormat depth_fmt = _pickDepthFormat(vk_pdev);
|
if (desc.depth_format != PR_RHI_FORMAT_UNDEFINED) {
|
||||||
if (depth_fmt == VK_FORMAT_UNDEFINED) _abort("no suitable depth format");
|
depth_pick_fmt = _toVkFormat(desc.depth_format);
|
||||||
|
} else {
|
||||||
|
depth_pick_fmt = _pickDepthFormat(vk_pdev);
|
||||||
|
}
|
||||||
|
if (depth_pick_fmt == VK_FORMAT_UNDEFINED) _abort("no suitable depth format");
|
||||||
|
|
||||||
VkImageCreateInfo depth_img_info = {};
|
VkImageCreateInfo depth_img_info = {};
|
||||||
depth_img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
depth_img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||||
depth_img_info.imageType = VK_IMAGE_TYPE_2D;
|
depth_img_info.imageType = VK_IMAGE_TYPE_2D;
|
||||||
depth_img_info.format = depth_fmt;
|
depth_img_info.format = depth_pick_fmt;
|
||||||
depth_img_info.extent.width = extent.width;
|
depth_img_info.extent.width = extent.width;
|
||||||
depth_img_info.extent.height = extent.height;
|
depth_img_info.extent.height = extent.height;
|
||||||
depth_img_info.extent.depth = 1;
|
depth_img_info.extent.depth = 1;
|
||||||
@@ -643,7 +684,7 @@ PrRhiSwapchain *prRhiCreateSwapchainVk(PrRhiDevice *device, PrRhiSwapchainDesc d
|
|||||||
depth_view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
depth_view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||||
depth_view_info.image = depth_image;
|
depth_view_info.image = depth_image;
|
||||||
depth_view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
depth_view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||||
depth_view_info.format = depth_fmt;
|
depth_view_info.format = depth_pick_fmt;
|
||||||
depth_view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
depth_view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||||
depth_view_info.subresourceRange.levelCount = 1;
|
depth_view_info.subresourceRange.levelCount = 1;
|
||||||
depth_view_info.subresourceRange.layerCount = 1;
|
depth_view_info.subresourceRange.layerCount = 1;
|
||||||
@@ -658,9 +699,10 @@ PrRhiSwapchain *prRhiCreateSwapchainVk(PrRhiDevice *device, PrRhiSwapchainDesc d
|
|||||||
depth_tex->allocation = depth_allocation;
|
depth_tex->allocation = depth_allocation;
|
||||||
depth_tex->width = extent.width;
|
depth_tex->width = extent.width;
|
||||||
depth_tex->height = extent.height;
|
depth_tex->height = extent.height;
|
||||||
depth_tex->format = depth_fmt;
|
depth_tex->format = depth_pick_fmt;
|
||||||
|
|
||||||
swapchain->depth = depth_tex;
|
swapchain->depth = depth_tex;
|
||||||
|
swapchain->depth_format = depth_pick_fmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
return swapchain;
|
return swapchain;
|
||||||
@@ -809,7 +851,7 @@ void prRhiRecreateSwapchainVk(PrRhiDevice *device, PrRhiSwapchain **swapchain,
|
|||||||
// Recreate depth
|
// Recreate depth
|
||||||
PrRhiTexture *new_depth = NULL;
|
PrRhiTexture *new_depth = NULL;
|
||||||
{
|
{
|
||||||
VkFormat depth_fmt = _pickDepthFormat(vk_pdev);
|
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)");
|
if (depth_fmt == VK_FORMAT_UNDEFINED) _abort("no suitable depth format (recreate)");
|
||||||
|
|
||||||
VkImageCreateInfo depth_img_info = {};
|
VkImageCreateInfo depth_img_info = {};
|
||||||
@@ -856,6 +898,7 @@ void prRhiRecreateSwapchainVk(PrRhiDevice *device, PrRhiSwapchain **swapchain,
|
|||||||
new_depth->width = extent.width;
|
new_depth->width = extent.width;
|
||||||
new_depth->height = extent.height;
|
new_depth->height = extent.height;
|
||||||
new_depth->format = depth_fmt;
|
new_depth->format = depth_fmt;
|
||||||
|
old->depth_format = depth_fmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update old swapchain in-place
|
// Update old swapchain in-place
|
||||||
@@ -879,6 +922,10 @@ PrRhiTexture *prRhiGetSwapchainDepthTextureVk(PrRhiSwapchain *swapchain) {
|
|||||||
return swapchain->depth;
|
return swapchain->depth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PrRhiFormat prRhiGetSwapchainFormatVk(PrRhiSwapchain *swapchain) {
|
||||||
|
return _fromVkFormat((VkFormat)swapchain->format);
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Buffers
|
// Buffers
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@@ -1097,7 +1144,7 @@ PrRhiPipelineLayout *prRhiCreatePipelineLayoutVk(PrRhiDevice *device,
|
|||||||
// Gather descriptor set layouts
|
// Gather descriptor set layouts
|
||||||
u32 layout_count = (desc.set_layouts && wpArrayCount(desc.set_layouts) > 0)
|
u32 layout_count = (desc.set_layouts && wpArrayCount(desc.set_layouts) > 0)
|
||||||
? (u32)wpArrayCount(desc.set_layouts) : 0;
|
? (u32)wpArrayCount(desc.set_layouts) : 0;
|
||||||
VkDescriptorSetLayout vk_layouts_stack[8];
|
VkDescriptorSetLayout vk_layouts_stack[8] = {0};
|
||||||
VkDescriptorSetLayout *vk_layouts = vk_layouts_stack;
|
VkDescriptorSetLayout *vk_layouts = vk_layouts_stack;
|
||||||
|
|
||||||
if (layout_count > 8) {
|
if (layout_count > 8) {
|
||||||
@@ -1111,7 +1158,7 @@ PrRhiPipelineLayout *prRhiCreatePipelineLayoutVk(PrRhiDevice *device,
|
|||||||
// Gather push constant ranges
|
// Gather push constant ranges
|
||||||
u32 pc_count = (desc.push_constant_ranges && wpArrayCount(desc.push_constant_ranges) > 0)
|
u32 pc_count = (desc.push_constant_ranges && wpArrayCount(desc.push_constant_ranges) > 0)
|
||||||
? (u32)wpArrayCount(desc.push_constant_ranges) : 0;
|
? (u32)wpArrayCount(desc.push_constant_ranges) : 0;
|
||||||
VkPushConstantRange pc_ranges_stack[8];
|
VkPushConstantRange pc_ranges_stack[8] = {0};
|
||||||
VkPushConstantRange *pc_ranges = pc_ranges_stack;
|
VkPushConstantRange *pc_ranges = pc_ranges_stack;
|
||||||
|
|
||||||
if (pc_count > 8) {
|
if (pc_count > 8) {
|
||||||
@@ -1184,7 +1231,7 @@ PrRhiPipeline *prRhiCreateGraphicsPipelineVk(PrRhiDevice *device,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Vertex input state
|
// Vertex input state
|
||||||
VkVertexInputBindingDescription vk_bindings[8];
|
VkVertexInputBindingDescription vk_bindings[8] = {0};
|
||||||
u32 binding_count = 0;
|
u32 binding_count = 0;
|
||||||
if (desc.vertex_bindings && wpArrayCount(desc.vertex_bindings) > 0) {
|
if (desc.vertex_bindings && wpArrayCount(desc.vertex_bindings) > 0) {
|
||||||
binding_count = (u32)wpArrayCount(desc.vertex_bindings);
|
binding_count = (u32)wpArrayCount(desc.vertex_bindings);
|
||||||
@@ -1195,7 +1242,7 @@ PrRhiPipeline *prRhiCreateGraphicsPipelineVk(PrRhiDevice *device,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VkVertexInputAttributeDescription vk_attrs[16];
|
VkVertexInputAttributeDescription vk_attrs[16] = {0};
|
||||||
u32 attr_count = 0;
|
u32 attr_count = 0;
|
||||||
if (desc.vertex_attributes && wpArrayCount(desc.vertex_attributes) > 0) {
|
if (desc.vertex_attributes && wpArrayCount(desc.vertex_attributes) > 0) {
|
||||||
attr_count = (u32)wpArrayCount(desc.vertex_attributes);
|
attr_count = (u32)wpArrayCount(desc.vertex_attributes);
|
||||||
@@ -1225,7 +1272,7 @@ PrRhiPipeline *prRhiCreateGraphicsPipelineVk(PrRhiDevice *device,
|
|||||||
viewport_state.viewportCount = 1;
|
viewport_state.viewportCount = 1;
|
||||||
viewport_state.scissorCount = 1;
|
viewport_state.scissorCount = 1;
|
||||||
|
|
||||||
VkDynamicState dynamic_states_stack[2];
|
VkDynamicState dynamic_states_stack[2] = {0};
|
||||||
u32 dynamic_count = 0;
|
u32 dynamic_count = 0;
|
||||||
if (desc.dynamic_viewport) {
|
if (desc.dynamic_viewport) {
|
||||||
dynamic_states_stack[dynamic_count++] = VK_DYNAMIC_STATE_VIEWPORT;
|
dynamic_states_stack[dynamic_count++] = VK_DYNAMIC_STATE_VIEWPORT;
|
||||||
@@ -1253,7 +1300,7 @@ PrRhiPipeline *prRhiCreateGraphicsPipelineVk(PrRhiDevice *device,
|
|||||||
rendering_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO;
|
rendering_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO;
|
||||||
rendering_info.depthAttachmentFormat = _toVkFormat(desc.depth_attachment_format);
|
rendering_info.depthAttachmentFormat = _toVkFormat(desc.depth_attachment_format);
|
||||||
|
|
||||||
VkFormat vk_color_formats[8];
|
VkFormat vk_color_formats[8] = {0};
|
||||||
u32 color_format_count = 0;
|
u32 color_format_count = 0;
|
||||||
if (desc.color_attachment_formats && wpArrayCount(desc.color_attachment_formats) > 0) {
|
if (desc.color_attachment_formats && wpArrayCount(desc.color_attachment_formats) > 0) {
|
||||||
color_format_count = (u32)wpArrayCount(desc.color_attachment_formats);
|
color_format_count = (u32)wpArrayCount(desc.color_attachment_formats);
|
||||||
@@ -1265,7 +1312,7 @@ PrRhiPipeline *prRhiCreateGraphicsPipelineVk(PrRhiDevice *device,
|
|||||||
rendering_info.pColorAttachmentFormats = vk_color_formats;
|
rendering_info.pColorAttachmentFormats = vk_color_formats;
|
||||||
|
|
||||||
// Blending
|
// Blending
|
||||||
VkPipelineColorBlendAttachmentState blend_attachments[8];
|
VkPipelineColorBlendAttachmentState blend_attachments[8] = {0};
|
||||||
u32 blend_count = 0;
|
u32 blend_count = 0;
|
||||||
if (desc.blend_attachments && wpArrayCount(desc.blend_attachments) > 0) {
|
if (desc.blend_attachments && wpArrayCount(desc.blend_attachments) > 0) {
|
||||||
blend_count = (u32)wpArrayCount(desc.blend_attachments);
|
blend_count = (u32)wpArrayCount(desc.blend_attachments);
|
||||||
@@ -1365,8 +1412,8 @@ PrRhiDescriptorSetLayout *prRhiCreateDescriptorSetLayoutVk(PrRhiDevice *device,
|
|||||||
u32 binding_count = (desc.bindings && wpArrayCount(desc.bindings) > 0)
|
u32 binding_count = (desc.bindings && wpArrayCount(desc.bindings) > 0)
|
||||||
? (u32)wpArrayCount(desc.bindings) : 0;
|
? (u32)wpArrayCount(desc.bindings) : 0;
|
||||||
|
|
||||||
VkDescriptorSetLayoutBinding vk_bindings[16];
|
VkDescriptorSetLayoutBinding vk_bindings[16] = {0};
|
||||||
VkDescriptorBindingFlags vk_flags[16];
|
VkDescriptorBindingFlags vk_flags[16] = {0};
|
||||||
|
|
||||||
for (u32 i = 0; i < binding_count && i < 16; ++i) {
|
for (u32 i = 0; i < binding_count && i < 16; ++i) {
|
||||||
vk_bindings[i].binding = i;
|
vk_bindings[i].binding = i;
|
||||||
@@ -1417,7 +1464,7 @@ PrRhiDescriptorPool *prRhiCreateDescriptorPoolVk(PrRhiDevice *device,
|
|||||||
u32 pool_size_count = (desc.pool_sizes && wpArrayCount(desc.pool_sizes) > 0)
|
u32 pool_size_count = (desc.pool_sizes && wpArrayCount(desc.pool_sizes) > 0)
|
||||||
? (u32)wpArrayCount(desc.pool_sizes) : 0;
|
? (u32)wpArrayCount(desc.pool_sizes) : 0;
|
||||||
|
|
||||||
VkDescriptorPoolSize vk_sizes[8];
|
VkDescriptorPoolSize vk_sizes[8] = {0};
|
||||||
for (u32 i = 0; i < pool_size_count && i < 8; ++i) {
|
for (u32 i = 0; i < pool_size_count && i < 8; ++i) {
|
||||||
vk_sizes[i].type = _toVkDescriptorType(desc.pool_sizes[i].type);
|
vk_sizes[i].type = _toVkDescriptorType(desc.pool_sizes[i].type);
|
||||||
vk_sizes[i].descriptorCount = desc.pool_sizes[i].descriptor_count;
|
vk_sizes[i].descriptorCount = desc.pool_sizes[i].descriptor_count;
|
||||||
@@ -1504,7 +1551,7 @@ void prRhiUpdateDescriptorSetVk(PrRhiDevice *device, PrRhiWriteDescriptorSetArra
|
|||||||
|
|
||||||
if (w->image_info && wpArrayCount(w->image_info) > 0) {
|
if (w->image_info && wpArrayCount(w->image_info) > 0) {
|
||||||
u32 img_count = (u32)wpArrayCount(w->image_info);
|
u32 img_count = (u32)wpArrayCount(w->image_info);
|
||||||
VkDescriptorImageInfo vk_img_info[16];
|
VkDescriptorImageInfo vk_img_info[16] = {0};
|
||||||
u32 img_max = img_count > 16 ? 16 : img_count;
|
u32 img_max = img_count > 16 ? 16 : img_count;
|
||||||
for (u32 j = 0; j < img_max; ++j) {
|
for (u32 j = 0; j < img_max; ++j) {
|
||||||
PrRhiDescriptorImageInfo *src = &w->image_info[j];
|
PrRhiDescriptorImageInfo *src = &w->image_info[j];
|
||||||
@@ -1526,7 +1573,7 @@ void prRhiUpdateDescriptorSetVk(PrRhiDevice *device, PrRhiWriteDescriptorSetArra
|
|||||||
|
|
||||||
if (w->buffer_info && wpArrayCount(w->buffer_info) > 0) {
|
if (w->buffer_info && wpArrayCount(w->buffer_info) > 0) {
|
||||||
u32 buf_count = (u32)wpArrayCount(w->buffer_info);
|
u32 buf_count = (u32)wpArrayCount(w->buffer_info);
|
||||||
VkDescriptorBufferInfo vk_buf_info[16];
|
VkDescriptorBufferInfo vk_buf_info[16] = {0};
|
||||||
u32 buf_max = buf_count > 16 ? 16 : buf_count;
|
u32 buf_max = buf_count > 16 ? 16 : buf_count;
|
||||||
for (u32 j = 0; j < buf_max; ++j) {
|
for (u32 j = 0; j < buf_max; ++j) {
|
||||||
PrRhiDescriptorBufferInfo *src = &w->buffer_info[j];
|
PrRhiDescriptorBufferInfo *src = &w->buffer_info[j];
|
||||||
@@ -1576,7 +1623,7 @@ void prRhiDestroyFenceVk(PrRhiDevice *device, PrRhiFence *fence, WpAllocator *al
|
|||||||
|
|
||||||
void prRhiWaitForFencesVk(PrRhiDevice *device, PrRhiFenceArray fences, u32 count,
|
void prRhiWaitForFencesVk(PrRhiDevice *device, PrRhiFenceArray fences, u32 count,
|
||||||
b8 wait_all, u64 timeout_ns) {
|
b8 wait_all, u64 timeout_ns) {
|
||||||
VkFence vk_fences[16];
|
VkFence vk_fences[16] = {0};
|
||||||
u32 real_count = count < 16 ? count : 16;
|
u32 real_count = count < 16 ? count : 16;
|
||||||
for (u32 i = 0; i < real_count; ++i) {
|
for (u32 i = 0; i < real_count; ++i) {
|
||||||
vk_fences[i] = (VkFence)fences[i]->handle;
|
vk_fences[i] = (VkFence)fences[i]->handle;
|
||||||
@@ -1587,7 +1634,7 @@ void prRhiWaitForFencesVk(PrRhiDevice *device, PrRhiFenceArray fences, u32 count
|
|||||||
}
|
}
|
||||||
|
|
||||||
void prRhiResetFencesVk(PrRhiDevice *device, PrRhiFenceArray fences, u32 count) {
|
void prRhiResetFencesVk(PrRhiDevice *device, PrRhiFenceArray fences, u32 count) {
|
||||||
VkFence vk_fences[16];
|
VkFence vk_fences[16] = {0};
|
||||||
u32 real_count = count < 16 ? count : 16;
|
u32 real_count = count < 16 ? count : 16;
|
||||||
for (u32 i = 0; i < real_count; ++i) {
|
for (u32 i = 0; i < real_count; ++i) {
|
||||||
vk_fences[i] = (VkFence)fences[i]->handle;
|
vk_fences[i] = (VkFence)fences[i]->handle;
|
||||||
@@ -1655,7 +1702,7 @@ PrRhiCommandBufferArray prRhiAllocateCommandBuffersVk(PrRhiDevice *device, PrRhi
|
|||||||
info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||||
info.commandBufferCount = count;
|
info.commandBufferCount = count;
|
||||||
|
|
||||||
VkCommandBuffer vk_cbs[16];
|
VkCommandBuffer vk_cbs[16] = {0};
|
||||||
u32 real_count = count < 16 ? count : 16;
|
u32 real_count = count < 16 ? count : 16;
|
||||||
|
|
||||||
VkCommandBufferArray vk_cb_array = wpArrayAllocCapacity(VkCommandBuffer, alloc, real_count, WP_ARRAY_INIT_NONE);
|
VkCommandBufferArray vk_cb_array = wpArrayAllocCapacity(VkCommandBuffer, alloc, real_count, WP_ARRAY_INIT_NONE);
|
||||||
@@ -1690,7 +1737,7 @@ void prRhiFreeCommandBuffersVk(PrRhiDevice *device, PrRhiCommandPool *pool,
|
|||||||
VkDevice vk_device = (VkDevice)device->handle;
|
VkDevice vk_device = (VkDevice)device->handle;
|
||||||
VkCommandPool vk_pool = (VkCommandPool)pool->handle;
|
VkCommandPool vk_pool = (VkCommandPool)pool->handle;
|
||||||
|
|
||||||
VkCommandBuffer vk_cbs[16];
|
VkCommandBuffer vk_cbs[16] = {0};
|
||||||
u32 real_count = count < 16 ? count : 16;
|
u32 real_count = count < 16 ? count : 16;
|
||||||
for (u32 i = 0; i < real_count; ++i) {
|
for (u32 i = 0; i < real_count; ++i) {
|
||||||
vk_cbs[i] = (VkCommandBuffer)buffers[i]->handle;
|
vk_cbs[i] = (VkCommandBuffer)buffers[i]->handle;
|
||||||
@@ -1743,7 +1790,7 @@ void prRhiCmdPipelineBarrierVk(PrRhiCommandBuffer *cb,
|
|||||||
|
|
||||||
if (img_count == 0 && buf_count == 0) return;
|
if (img_count == 0 && buf_count == 0) return;
|
||||||
|
|
||||||
VkImageMemoryBarrier2 vk_img_barriers[16];
|
VkImageMemoryBarrier2 vk_img_barriers[16] = {0};
|
||||||
for (u32 i = 0; i < img_count && i < 16; ++i) {
|
for (u32 i = 0; i < img_count && i < 16; ++i) {
|
||||||
PrRhiImageMemoryBarrier *src = &image_barriers[i];
|
PrRhiImageMemoryBarrier *src = &image_barriers[i];
|
||||||
VkImageLayout old_layout = _toVkImageLayout(src->old_layout);
|
VkImageLayout old_layout = _toVkImageLayout(src->old_layout);
|
||||||
@@ -1756,16 +1803,11 @@ void prRhiCmdPipelineBarrierVk(PrRhiCommandBuffer *cb,
|
|||||||
aspect = VK_IMAGE_ASPECT_DEPTH_BIT;
|
aspect = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkPipelineStageFlags2 src_stage = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;
|
|
||||||
VkPipelineStageFlags2 dst_stage = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;
|
|
||||||
VkAccessFlags2 src_access = 0;
|
|
||||||
VkAccessFlags2 dst_access = 0;
|
|
||||||
|
|
||||||
vk_img_barriers[i].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2;
|
vk_img_barriers[i].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2;
|
||||||
vk_img_barriers[i].srcStageMask = src_stage;
|
vk_img_barriers[i].srcStageMask = (VkPipelineStageFlags2)src->src_stage_mask;
|
||||||
vk_img_barriers[i].srcAccessMask = src_access;
|
vk_img_barriers[i].srcAccessMask = (VkAccessFlags2)src->src_access_mask;
|
||||||
vk_img_barriers[i].dstStageMask = dst_stage;
|
vk_img_barriers[i].dstStageMask = (VkPipelineStageFlags2)src->dst_stage_mask;
|
||||||
vk_img_barriers[i].dstAccessMask = dst_access;
|
vk_img_barriers[i].dstAccessMask = (VkAccessFlags2)src->dst_access_mask;
|
||||||
vk_img_barriers[i].oldLayout = old_layout;
|
vk_img_barriers[i].oldLayout = old_layout;
|
||||||
vk_img_barriers[i].newLayout = new_layout;
|
vk_img_barriers[i].newLayout = new_layout;
|
||||||
vk_img_barriers[i].image = src->texture ? (VkImage)src->texture->image : VK_NULL_HANDLE;
|
vk_img_barriers[i].image = src->texture ? (VkImage)src->texture->image : VK_NULL_HANDLE;
|
||||||
@@ -1774,15 +1816,15 @@ void prRhiCmdPipelineBarrierVk(PrRhiCommandBuffer *cb,
|
|||||||
vk_img_barriers[i].subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
|
vk_img_barriers[i].subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkBufferMemoryBarrier2 vk_buf_barriers[16];
|
VkBufferMemoryBarrier2 vk_buf_barriers[16] = {0};
|
||||||
for (u32 i = 0; i < buf_count && i < 16; ++i) {
|
for (u32 i = 0; i < buf_count && i < 16; ++i) {
|
||||||
PrRhiBufferMemoryBarrier *src = &buffer_barriers[i];
|
PrRhiBufferMemoryBarrier *src = &buffer_barriers[i];
|
||||||
|
|
||||||
vk_buf_barriers[i].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2;
|
vk_buf_barriers[i].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2;
|
||||||
vk_buf_barriers[i].srcStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;
|
vk_buf_barriers[i].srcStageMask = (VkPipelineStageFlags2)src->src_stage_mask;
|
||||||
vk_buf_barriers[i].srcAccessMask = 0;
|
vk_buf_barriers[i].srcAccessMask = (VkAccessFlags2)src->src_access_mask;
|
||||||
vk_buf_barriers[i].dstStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;
|
vk_buf_barriers[i].dstStageMask = (VkPipelineStageFlags2)src->dst_stage_mask;
|
||||||
vk_buf_barriers[i].dstAccessMask = 0;
|
vk_buf_barriers[i].dstAccessMask = (VkAccessFlags2)src->dst_access_mask;
|
||||||
vk_buf_barriers[i].buffer = src->buffer ? (VkBuffer)src->buffer->handle : VK_NULL_HANDLE;
|
vk_buf_barriers[i].buffer = src->buffer ? (VkBuffer)src->buffer->handle : VK_NULL_HANDLE;
|
||||||
vk_buf_barriers[i].offset = src->offset;
|
vk_buf_barriers[i].offset = src->offset;
|
||||||
vk_buf_barriers[i].size = src->size;
|
vk_buf_barriers[i].size = src->size;
|
||||||
@@ -1810,7 +1852,7 @@ void prRhiCmdBeginRenderingVk(PrRhiCommandBuffer *cb,
|
|||||||
u32 color_count = (color_attachments && wpArrayCount(color_attachments) > 0)
|
u32 color_count = (color_attachments && wpArrayCount(color_attachments) > 0)
|
||||||
? (u32)wpArrayCount(color_attachments) : 0;
|
? (u32)wpArrayCount(color_attachments) : 0;
|
||||||
|
|
||||||
VkRenderingAttachmentInfo vk_color[8];
|
VkRenderingAttachmentInfo vk_color[8] = {0};
|
||||||
u32 width = 0, height = 0;
|
u32 width = 0, height = 0;
|
||||||
|
|
||||||
for (u32 i = 0; i < color_count && i < 8; ++i) {
|
for (u32 i = 0; i < color_count && i < 8; ++i) {
|
||||||
@@ -1900,7 +1942,7 @@ void prRhiCmdBindDescriptorSetsVk(PrRhiCommandBuffer *cb, PrRhiPipelineBindPoint
|
|||||||
VkPipelineLayout vk_layout = layout ? (VkPipelineLayout)layout->handle : VK_NULL_HANDLE;
|
VkPipelineLayout vk_layout = layout ? (VkPipelineLayout)layout->handle : VK_NULL_HANDLE;
|
||||||
|
|
||||||
u32 set_count = sets ? (u32)wpArrayCount(sets) : 0;
|
u32 set_count = sets ? (u32)wpArrayCount(sets) : 0;
|
||||||
VkDescriptorSet vk_sets[16];
|
VkDescriptorSet vk_sets[16] = {0};
|
||||||
u32 real_count = set_count < 16 ? set_count : 16;
|
u32 real_count = set_count < 16 ? set_count : 16;
|
||||||
for (u32 i = 0; i < real_count; ++i) {
|
for (u32 i = 0; i < real_count; ++i) {
|
||||||
vk_sets[i] = (VkDescriptorSet)sets[i]->handle;
|
vk_sets[i] = (VkDescriptorSet)sets[i]->handle;
|
||||||
@@ -1920,7 +1962,7 @@ void prRhiCmdPushConstantsVk(PrRhiCommandBuffer *cb, PrRhiPipelineLayout *layout
|
|||||||
|
|
||||||
void prRhiCmdBindVertexBuffersVk(PrRhiCommandBuffer *cb, u32 first_binding,
|
void prRhiCmdBindVertexBuffersVk(PrRhiCommandBuffer *cb, u32 first_binding,
|
||||||
PrRhiBufferArray buffers, const u64 *offsets, u32 count) {
|
PrRhiBufferArray buffers, const u64 *offsets, u32 count) {
|
||||||
VkBuffer vk_bufs[16];
|
VkBuffer vk_bufs[16] = {0};
|
||||||
u32 real_count = count < 16 ? count : 16;
|
u32 real_count = count < 16 ? count : 16;
|
||||||
for (u32 i = 0; i < real_count; ++i) {
|
for (u32 i = 0; i < real_count; ++i) {
|
||||||
vk_bufs[i] = (VkBuffer)buffers[i]->handle;
|
vk_bufs[i] = (VkBuffer)buffers[i]->handle;
|
||||||
@@ -1955,23 +1997,31 @@ void prRhiCmdDrawIndexedVk(PrRhiCommandBuffer *cb, u32 index_count, u32 instance
|
|||||||
// Copy
|
// Copy
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
void prRhiCmdCopyBufferToImageVk(PrRhiCommandBuffer *cb, PrRhiBuffer *src, PrRhiTexture *dst) {
|
void prRhiCmdCopyBufferToImageVk(PrRhiCommandBuffer *cb, PrRhiBuffer *src, PrRhiTexture *dst,
|
||||||
VkBufferImageCopy region = {};
|
PrRhiBufferImageCopyArray copies) {
|
||||||
region.bufferOffset = 0;
|
u32 copy_count = (copies && wpArrayCount(copies) > 0) ? (u32)wpArrayCount(copies) : 0;
|
||||||
region.bufferRowLength = 0;
|
if (copy_count == 0) return;
|
||||||
region.bufferImageHeight = 0;
|
|
||||||
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
VkBufferImageCopy vk_regions[16] = {0};
|
||||||
region.imageSubresource.mipLevel = 0;
|
u32 real_count = copy_count < 16 ? copy_count : 16;
|
||||||
region.imageSubresource.layerCount = 1;
|
for (u32 i = 0; i < real_count; ++i) {
|
||||||
region.imageExtent.width = dst->width;
|
vk_regions[i].bufferOffset = copies[i].buffer_offset;
|
||||||
region.imageExtent.height = dst->height;
|
vk_regions[i].bufferRowLength = 0;
|
||||||
region.imageExtent.depth = 1;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
vkCmdCopyBufferToImage((VkCommandBuffer)cb->handle,
|
vkCmdCopyBufferToImage((VkCommandBuffer)cb->handle,
|
||||||
(VkBuffer)src->handle,
|
(VkBuffer)src->handle,
|
||||||
(VkImage)dst->image,
|
(VkImage)dst->image,
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
1, ®ion);
|
real_count, vk_regions);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ struct PrRhiInstance {
|
|||||||
struct PrRhiPhysicalDevice {
|
struct PrRhiPhysicalDevice {
|
||||||
void *handle; // VkPhysicalDevice
|
void *handle; // VkPhysicalDevice
|
||||||
PrRhiInstance *instance;
|
PrRhiInstance *instance;
|
||||||
|
c8 device_name[256];
|
||||||
|
c8 driver_info[256];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PrRhiDevice {
|
struct PrRhiDevice {
|
||||||
@@ -43,7 +45,8 @@ struct PrRhiSwapchain {
|
|||||||
u32 image_count;
|
u32 image_count;
|
||||||
PrRhiTexture **images;
|
PrRhiTexture **images;
|
||||||
PrRhiTexture *depth;
|
PrRhiTexture *depth;
|
||||||
u32 format; // VkFormat
|
u32 format; // VkFormat (color)
|
||||||
|
u32 depth_format; // VkFormat (depth)
|
||||||
u32 width;
|
u32 width;
|
||||||
u32 height;
|
u32 height;
|
||||||
u32 current_image_index;
|
u32 current_image_index;
|
||||||
@@ -116,10 +119,13 @@ struct PrRhiSemaphore {
|
|||||||
|
|
||||||
PrRhiInstance *prRhiCreateInstanceVk(PrRhiInstanceDesc desc, WpAllocator *alloc);
|
PrRhiInstance *prRhiCreateInstanceVk(PrRhiInstanceDesc desc, WpAllocator *alloc);
|
||||||
void prRhiDestroyInstanceVk(PrRhiInstance *inst, WpAllocator *alloc);
|
void prRhiDestroyInstanceVk(PrRhiInstance *inst, WpAllocator *alloc);
|
||||||
|
void *prRhiGetNativeInstanceHandleVk(PrRhiInstance *inst);
|
||||||
|
|
||||||
PrRhiPhysicalDeviceArray prRhiGetPhysicalDevicesVk(PrRhiInstance *inst, const WpAllocator *scratch);
|
PrRhiPhysicalDeviceArray prRhiGetPhysicalDevicesVk(PrRhiInstance *inst, const WpAllocator *scratch);
|
||||||
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 *out);
|
||||||
|
|
||||||
PrRhiSurface *prRhiCreateSurfaceVk(PrRhiInstance *inst, void *window_handle, WpAllocator *alloc);
|
PrRhiSurface *prRhiCreateSurfaceVk(PrRhiInstance *inst, void *window_handle, WpAllocator *alloc);
|
||||||
void prRhiDestroySurfaceVk(PrRhiInstance *inst, PrRhiSurface *surface, WpAllocator *alloc);
|
void prRhiDestroySurfaceVk(PrRhiInstance *inst, PrRhiSurface *surface, WpAllocator *alloc);
|
||||||
@@ -131,6 +137,7 @@ PrRhiDevice *prRhiCreateDeviceVk(PrRhiPhysicalDevice *pdev, PrRhiSurface *surfac
|
|||||||
PrRhiDeviceDesc desc, WpAllocator *alloc);
|
PrRhiDeviceDesc desc, WpAllocator *alloc);
|
||||||
void prRhiDestroyDeviceVk(PrRhiDevice *device, WpAllocator *alloc);
|
void prRhiDestroyDeviceVk(PrRhiDevice *device, WpAllocator *alloc);
|
||||||
void prRhiDeviceWaitIdleVk(PrRhiDevice *device);
|
void prRhiDeviceWaitIdleVk(PrRhiDevice *device);
|
||||||
|
u32 prRhiGetQueueFamilyIndexVk(PrRhiDevice *device);
|
||||||
|
|
||||||
PrRhiSwapchain *prRhiCreateSwapchainVk(PrRhiDevice *device, PrRhiSwapchainDesc desc,
|
PrRhiSwapchain *prRhiCreateSwapchainVk(PrRhiDevice *device, PrRhiSwapchainDesc desc,
|
||||||
WpAllocator *alloc);
|
WpAllocator *alloc);
|
||||||
@@ -144,6 +151,7 @@ void prRhiRecreateSwapchainVk(PrRhiDevice *device, PrRhiSwapchain **swapchain,
|
|||||||
u32 width, u32 height, WpAllocator *alloc);
|
u32 width, u32 height, WpAllocator *alloc);
|
||||||
PrRhiTexture *prRhiGetSwapchainTextureVk(PrRhiSwapchain *swapchain, u32 image_index);
|
PrRhiTexture *prRhiGetSwapchainTextureVk(PrRhiSwapchain *swapchain, u32 image_index);
|
||||||
PrRhiTexture *prRhiGetSwapchainDepthTextureVk(PrRhiSwapchain *swapchain);
|
PrRhiTexture *prRhiGetSwapchainDepthTextureVk(PrRhiSwapchain *swapchain);
|
||||||
|
PrRhiFormat prRhiGetSwapchainFormatVk(PrRhiSwapchain *swapchain);
|
||||||
|
|
||||||
PrRhiBuffer *prRhiCreateBufferVk(PrRhiDevice *device, PrRhiBufferDesc desc,
|
PrRhiBuffer *prRhiCreateBufferVk(PrRhiDevice *device, PrRhiBufferDesc desc,
|
||||||
WpAllocator *alloc);
|
WpAllocator *alloc);
|
||||||
@@ -260,7 +268,8 @@ void prRhiCmdDrawVk(PrRhiCommandBuffer *cb, u32 vertex_count, u32 instance_count
|
|||||||
void prRhiCmdDrawIndexedVk(PrRhiCommandBuffer *cb, u32 index_count, u32 instance_count,
|
void prRhiCmdDrawIndexedVk(PrRhiCommandBuffer *cb, u32 index_count, u32 instance_count,
|
||||||
u32 first_index, i32 vertex_offset, u32 first_instance);
|
u32 first_index, i32 vertex_offset, u32 first_instance);
|
||||||
|
|
||||||
void prRhiCmdCopyBufferToImageVk(PrRhiCommandBuffer *cb, PrRhiBuffer *src, PrRhiTexture *dst);
|
void prRhiCmdCopyBufferToImageVk(PrRhiCommandBuffer *cb, PrRhiBuffer *src, PrRhiTexture *dst,
|
||||||
|
PrRhiBufferImageCopyArray copies);
|
||||||
|
|
||||||
void prRhiQueueSubmitVk(PrRhiDevice *device, PrRhiCommandBuffer *cb,
|
void prRhiQueueSubmitVk(PrRhiDevice *device, PrRhiCommandBuffer *cb,
|
||||||
PrRhiSemaphore *wait_semaphore,
|
PrRhiSemaphore *wait_semaphore,
|
||||||
|
|||||||
@@ -7,15 +7,18 @@
|
|||||||
|
|
||||||
#define prRhiCreateInstance prRhiCreateInstanceVk
|
#define prRhiCreateInstance prRhiCreateInstanceVk
|
||||||
#define prRhiDestroyInstance prRhiDestroyInstanceVk
|
#define prRhiDestroyInstance prRhiDestroyInstanceVk
|
||||||
|
#define prRhiGetNativeInstanceHandle prRhiGetNativeInstanceHandleVk
|
||||||
#define prRhiGetPhysicalDevices prRhiGetPhysicalDevicesVk
|
#define prRhiGetPhysicalDevices prRhiGetPhysicalDevicesVk
|
||||||
#define prRhiGetPhysicalDeviceName prRhiGetPhysicalDeviceNameVk
|
#define prRhiGetPhysicalDeviceName prRhiGetPhysicalDeviceNameVk
|
||||||
#define prRhiGetPhysicalDeviceDriverInfo prRhiGetPhysicalDeviceDriverInfoVk
|
#define prRhiGetPhysicalDeviceDriverInfo prRhiGetPhysicalDeviceDriverInfoVk
|
||||||
|
#define prRhiGetPhysicalDeviceProperties prRhiGetPhysicalDevicePropertiesVk
|
||||||
#define prRhiCreateSurface prRhiCreateSurfaceVk
|
#define prRhiCreateSurface prRhiCreateSurfaceVk
|
||||||
#define prRhiDestroySurface prRhiDestroySurfaceVk
|
#define prRhiDestroySurface prRhiDestroySurfaceVk
|
||||||
#define prRhiGetSurfaceCapabilities prRhiGetSurfaceCapabilitiesVk
|
#define prRhiGetSurfaceCapabilities prRhiGetSurfaceCapabilitiesVk
|
||||||
#define prRhiCreateDevice prRhiCreateDeviceVk
|
#define prRhiCreateDevice prRhiCreateDeviceVk
|
||||||
#define prRhiDestroyDevice prRhiDestroyDeviceVk
|
#define prRhiDestroyDevice prRhiDestroyDeviceVk
|
||||||
#define prRhiDeviceWaitIdle prRhiDeviceWaitIdleVk
|
#define prRhiDeviceWaitIdle prRhiDeviceWaitIdleVk
|
||||||
|
#define prRhiGetQueueFamilyIndex prRhiGetQueueFamilyIndexVk
|
||||||
#define prRhiCreateSwapchain prRhiCreateSwapchainVk
|
#define prRhiCreateSwapchain prRhiCreateSwapchainVk
|
||||||
#define prRhiDestroySwapchain prRhiDestroySwapchainVk
|
#define prRhiDestroySwapchain prRhiDestroySwapchainVk
|
||||||
#define prRhiAcquireNextImage prRhiAcquireNextImageVk
|
#define prRhiAcquireNextImage prRhiAcquireNextImageVk
|
||||||
@@ -23,6 +26,7 @@
|
|||||||
#define prRhiRecreateSwapchain prRhiRecreateSwapchainVk
|
#define prRhiRecreateSwapchain prRhiRecreateSwapchainVk
|
||||||
#define prRhiGetSwapchainTexture prRhiGetSwapchainTextureVk
|
#define prRhiGetSwapchainTexture prRhiGetSwapchainTextureVk
|
||||||
#define prRhiGetSwapchainDepthTexture prRhiGetSwapchainDepthTextureVk
|
#define prRhiGetSwapchainDepthTexture prRhiGetSwapchainDepthTextureVk
|
||||||
|
#define prRhiGetSwapchainFormat prRhiGetSwapchainFormatVk
|
||||||
#define prRhiCreateBuffer prRhiCreateBufferVk
|
#define prRhiCreateBuffer prRhiCreateBufferVk
|
||||||
#define prRhiDestroyBuffer prRhiDestroyBufferVk
|
#define prRhiDestroyBuffer prRhiDestroyBufferVk
|
||||||
#define prRhiBufferMap prRhiBufferMapVk
|
#define prRhiBufferMap prRhiBufferMapVk
|
||||||
|
|||||||
Reference in New Issue
Block a user