diff --git a/.gitignore b/.gitignore index 28757d3..6360c1c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ build/ +old_build/ external/dxvk +assets/shaders diff --git a/build.ps1 b/build.ps1 index 3764020..3a2ea7e 100644 --- a/build.ps1 +++ b/build.ps1 @@ -120,9 +120,7 @@ if ($Global:vulkan) if ($Global:pack) { - Pop-Location - Invoke-Expression ".\build\$($packer_out_name)" - Push-Location build + Invoke-Expression ".\$($packer_out_name)" } if (-not (Test-Path -Path ".\$($vma_out_name)" -PathType "Leaf")) diff --git a/build.sh b/build.sh index 4cca518..d22b610 100755 --- a/build.sh +++ b/build.sh @@ -16,15 +16,12 @@ if [ -v test ]; then test_build=1; echo "[test build]"; fi # source files source_files="../src/entry_linux.c" -packer_source_files="../src/packer.c" # includes include_flags="-I../src/ -I../external/ -L. -I../external/dxvk/include/ -L../external/dxvk/lib/" -packer_include_flags="-I../src/ -I../external/" # executable name out_name="Gears" -packer_out_name="Packer" # vma flags vma_source_files="../external/vma/vma.cpp" @@ -32,6 +29,12 @@ vma_compile_flags="-std=c++20 -D_USE_MATH_DEFINES -I../external/vma -c -Wno-ever vma_out="-o" vma_obj="vma.o" +# packer +packer_source_files="../src/packer.c" +packer_include_flags="-I../src/ -I../external/" +packer_out_name="Packer" +packer_flags="-DBUILD_PACKER" + # glslc glsl_compile="glslc" glsl_flags="--target-spv=spv1.6 -std=460" @@ -41,7 +44,7 @@ glsl_stage_tesc="-fshader-stage=tesc" glsl_stage_tese="-fshader-stage=tese" glsl_stage_geom="-fshader-stage=geom" glsl_stage_comp="-fshader-stage=comp" -glsl_out="-o./shaders/glsl/" +glsl_out="-o../assets/shaders/" # clang clang_common="${include_flags} ${render_flag} -DCOMPILER_CLANG -std=c23 -fuse-ld=mold -Xclang -flto-visibility-public-std -Wno-unknown-warning-option -fdiagnostics-absolute-paths -Wall -Wno-missing-braces -Wno-unused-function -Wno-writable-strings -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-for-loop-analysis -DVMA_STATIC_VULKAN_FUNCTIONS=0 -ferror-limit=60" @@ -83,44 +86,40 @@ mkdir -p build cd build -if [ ! -v packer ]; then +# SPIR-V +mkdir -p ../assets/shaders -if [ -v vulkan ]; then - mkdir -p ./shaders/glsl - - for file in ../src/shaders/glsl/*.glsl; do - base_name=$(basename -- "$file" .glsl) +for file in ../src/shaders/glsl/*.glsl; do + base_name=$(basename -- "$file" .glsl) - case "$base_name" in - *.vert) glsl_stage="${glsl_stage_vert}" ;; - *.frag) glsl_stage="${glsl_stage_frag}" ;; - *.tesc) glsl_stage="${glsl_stage_tesc}" ;; - *.tese) glsl_stage="${glsl_stage_tese}" ;; - *.geom) glsl_stage="${glsl_stage_geom}" ;; - *.comp) glsl_stage="${glsl_stage_comp}" ;; - *) continue ;; - esac + case "$base_name" in + *.vert) glsl_stage="${glsl_stage_vert}" ;; + *.frag) glsl_stage="${glsl_stage_frag}" ;; + *.tesc) glsl_stage="${glsl_stage_tesc}" ;; + *.tese) glsl_stage="${glsl_stage_tese}" ;; + *.geom) glsl_stage="${glsl_stage_geom}" ;; + *.comp) glsl_stage="${glsl_stage_comp}" ;; + *) continue ;; + esac - $glsl_compile $glsl_flags $glsl_stage $file "${glsl_out}${base_name}.spv" - done -fi + $glsl_compile $glsl_flags $glsl_stage $file "${glsl_out}${base_name}.spv" +done +# VMA if ! [ -f libvma.a ]; then $cpp_compiler $vma_compile_flags $vma_source_files $vma_out $vma_obj ar rcs libvma.a vma.o + rm vma.o fi -elif [ -v packer ] || ! [ -f Packer ]; then - $compile $packer_source_files $compile_link $link_os_gfx $packer_include_flags $out $packer_out_name +# Packer +if [ -v packer ] || ! [ -f Packer ]; then + $compile $packer_source_files $compile_link $link_os_gfx $packer_flags $packer_include_flags $out $packer_out_name fi -if [ -v pack ]; then - cd .. - ./build/Packer - cd build +if [ -v pack ] || ! [ -f assets.sgp ]; then + ./Packer fi -if ! [ -v packer ]; then - $compile $source_files $compile_link $link_os_gfx $out $out_name -fi +$compile $source_files $compile_link $link_os_gfx $out $out_name diff --git a/src/assets.c b/src/assets.c index 12baff2..76715d7 100644 --- a/src/assets.c +++ b/src/assets.c @@ -25,10 +25,14 @@ const u32 M3D_LABEL = CreateMagicValue('L', 'B', 'L', 'S'); // ::Assets::Globals::Start:: -u8 ASSET_PACK[] = -{ - #embed "../assets.sgp" -}; +#ifndef BUILD_PACKER + u8 ASSET_PACK[] = + { + #embed "../build/assets.sgp" + }; +#else + u8 ASSET_PACK[] = {}; +#endif static FileHeader File_Header = {0}; @@ -139,21 +143,41 @@ static Asset apLoadModel(ModelAsset asset_id) { AssetFile *asset_info = Model_Assets + asset_id; - asset.bytes = FLMemAlloc(asset_info->len); - MemCpy(asset.bytes, &ASSET_PACK[asset_info->data_offset], asset_info->len); - asset.len = asset_info->len; + u8 *bytes = FLMemAlloc(asset_info->len); + MemCpy(bytes, &ASSET_PACK[asset_info->data_offset], asset_info->len); + asset.model = apParseModel(bytes); + + FLMemFree(bytes); + Model_Asset_Lookup[asset_id] = asset; } return asset; } -static TextureAssetMeta apGetTextureMeta(TextureAsset asset_id) +static TexMeta apGetTextureMeta(TextureAsset asset_id) { AssetFile *asset_file = Texture_Assets + asset_id; return asset_file->texture_meta; } +static ModelMeta apGetModelMeta(ModelAsset asset_id) +{ + /* + AssetFile *asset_file = Model_Assets + asset_id; + return asset_file->model_meta; + */ + + ModelMeta meta = {0}; + Asset asset = Model_Asset_Lookup[asset_id]; + if (asset.model != NULL) + { + meta.i_count = asset.model->i_count; + } + + return meta; +} + static void apUnloadTexture(TextureAsset asset_id) { Asset *asset = Texture_Asset_Lookup + asset_id; @@ -236,3 +260,4 @@ static m3dModel *apParseModel(rawptr data) } // ::Assets::Models::Functions::End:: + diff --git a/src/assets.h b/src/assets.h index 1c6ccaa..b345921 100644 --- a/src/assets.h +++ b/src/assets.h @@ -70,22 +70,25 @@ typedef enum ModelAssetTag_e : u32 MODEL_ASSET_TAG_MAX, } ModelAssetTag; -typedef struct TextureAssetMeta +typedef struct TexMeta { u32 w; u32 h; u32 ch; -} TextureAssetMeta; +} TexMeta; -typedef struct ModelAssetMeta +typedef struct ModelMeta { - u32 vert_count; - u32 idx_count; -} ModelAssetMeta; + u32 i_count; +} ModelMeta; typedef struct Asset { - u8 *bytes; + union + { + u8 *bytes; + m3dModel *model; + }; u64 len; } Asset; @@ -101,8 +104,8 @@ typedef struct AssetFile u64 len; union { - TextureAssetMeta texture_meta; - ModelAssetMeta model_meta; + TexMeta texture_meta; + ModelMeta model_meta; }; } AssetFile; @@ -127,7 +130,8 @@ static void apInit(); static Asset apLoadTexture(TextureAsset asset_id); static Asset apLoadShader(ShaderAsset asset_id); static Asset apLoadModel(ModelAsset asset_id); -static TextureAssetMeta apGetTextureMeta(TextureAsset asset_id); +static TexMeta apGetTextureMeta(TextureAsset asset_id); +static ModelMeta apGetModelMeta(ModelAsset asset_id); static void apUnloadTexture(TextureAsset asset_id); static void apUnloadShader(ShaderAsset asset_id); static void apUnloadModel(ModelAsset asset_id); diff --git a/src/entry_linux.h b/src/entry_linux.h index 0f986cb..e46b2a5 100644 --- a/src/entry_linux.h +++ b/src/entry_linux.h @@ -24,6 +24,7 @@ #include "stb/stb_image.h" #include "xxhash/xxhash.h" #include "fastlz/fastlz.h" +#include "m3d/m3d.h" #include "renderer.h" #include "game.h" diff --git a/src/game.c b/src/game.c index 349881b..01c2c6a 100644 --- a/src/game.c +++ b/src/game.c @@ -63,37 +63,16 @@ static void gRunCycle(gGameCtx *ctx, pGameInput *inputs, u32 i_count) vTextureCleanUp(); - /* - if (gButton(ctx, "Show 2", 150.0f, 150.0f, 200.0f, 200.0f)) - { - gWindow(ctx, "Window 2", 500.0f, 500.0f, 600.0f, 600.0f); - } - - if (gButton(ctx, "Show 1", 50.0f, 50.0f, 100.0f, 100.0f)) - { - gWindow(ctx, "Window 1", 200.0f, 200.0f, 400.0f, 400.0f); - } - - if (gButton(ctx, "Show 3", 150.0f, 300.0f, 200.0f, 350.0f)) - { - gWindow(ctx, "Window 3", 250.0f, 500.0f, 400.0f, 650.0f); - } - */ - u64 index = vFrameIndex(); - rDescHandle texture; - if (index == 0) - texture = rTextureLoad(HAMSMOKER); - else - texture = rTextureLoad(HOG); - - rTextureUnload(texture); + + rDescHandle yoder = rMeshLoad(MODEL_YODA); + ctx->pc.mesh_index = yoder.desc_index; + ModelMeta model_meta = apGetModelMeta(MODEL_YODA); + rViewportSize(&ctx->pc.res); ctx->pc.time = (f32)pCPUTimerRead(); - gWindow(ctx, "texture", 100.0f, 100.0f, 300.0f, 300.0f, texture); - rawptr vert_buffer = rBufferGUIVertMapping(); rawptr idx_buffer = rBufferGUIIdxMapping(); @@ -102,14 +81,17 @@ static void gRunCycle(gGameCtx *ctx, pGameInput *inputs, u32 i_count) vBufferQueueWait(); - rPipelineBind(rPIPELINE_GUI, rPT_GRAPHICS); + rPipelineBind(rPIPELINE_PBR, rPT_GRAPHICS); + rPushConstantsSet(&ctx->pc); - rBufferBindGUIVertex(); - rBufferBindGUIIndex(); + //rBufferBindGUIVertex(); + //rBufferBindGUIIndex(); - rDrawIndexed(6, ctx->gui.instance_count); + rBufferBindMesh(&ctx->pc, yoder); + + rDrawIndexed(model_meta.i_count, 1); rFrameFinish(); diff --git a/src/packer.c b/src/packer.c index 2074b6c..36eaa5e 100644 --- a/src/packer.c +++ b/src/packer.c @@ -102,60 +102,20 @@ i32 WriteHeader(pFile file, FileHeader *header) void MoveToShaderDir(c8 **return_dir) { - if (pDirIsVisible("build")) - { - Assert(pDirNavigate("build/shaders/glsl") == 0, "Unable to change to shader directory"); - *return_dir = "../../.."; - } - else if (pDirIsVisible("shaders")) - { - Assert(pDirNavigate("shaders/glsl") == 0 , "Unable to change to shader directory"); - *return_dir = "../.."; - } - else - Assert(false, "Unable to find shader directory"); + Assert(pDirNavigate("../assets/shaders") == 0, "Unable to change to shader directory"); + *return_dir = "../../build"; } void MoveToTextureDir(c8 **return_dir) { - if (pDirIsVisible("textures")) - { - Assert(pDirNavigate("./textures") == 0, "Unable to change to textures directory"); - *return_dir = ".."; - } - else if (pDirIsVisible("assets")) - { - Assert(pDirNavigate("./assets/textures") == 0, "Unable to change to assets directory"); - *return_dir = "../.."; - } - else if (pDirIsVisible("shaders")) - { - Assert(pDirNavigate("../assets/textures") == 0, "Unable to change to assets directory"); - *return_dir = "../build"; - } - else - Assert(false, "Unable to find assets directory"); + Assert(pDirNavigate("../assets/textures") == 0, "Unable to change to assets directory"); + *return_dir = "../../build"; } void MoveToModelDir(c8 **return_dir) { - if (pDirIsVisible("models")) - { - Assert(pDirNavigate("./models") == 0, "Unable to change to models directory"); - *return_dir = ".."; - } - else if (pDirIsVisible("assets")) - { - Assert(pDirNavigate("./assets/models") == 0, "Unable to change to assets directory"); - *return_dir = "../.."; - } - else if (pDirIsVisible("shaders")) - { - Assert(pDirNavigate("../assets/models") == 0, "Unable to change to assets directory"); - *return_dir = "../build"; - } - else - Assert(false, "Unable to find assets directory"); + Assert(pDirNavigate("../assets/models") == 0, "Unable to change to assets directory"); + *return_dir = "../../build"; } void InitHeader(FileHeader *header) @@ -450,12 +410,17 @@ int main(int argc, c8 **argv) } #endif + if (pDirIsVisible("build")) + { + Assert(pDirNavigate("./build") == 0, "Unable to change to build directory"); + } + SetArrayLookups(); void *mem = pMemAllocZeroed(GB(1)); Arena *arena = ArenaInitDebug(mem, GB(1), __LINE__); - pFile file = pFileOpen("assets.sgp", pFS_WRITE | pFS_TRUNC); + pFile file = pFileOpen("assets.sgp", pFS_WRITE | pFS_TRUNC | pFS_CREATE); Assert(file > 0, "File is null"); FileHeader header = {0}; diff --git a/src/platform/platform.h b/src/platform/platform.h index aeb4afe..58bc805 100644 --- a/src/platform/platform.h +++ b/src/platform/platform.h @@ -123,6 +123,7 @@ typedef enum e_pFSAccess pFS_WRITE = 0x02, pFS_TRUNC = 0x04, pFS_APPEND = 0x08, + pFS_CREATE = 0x10, } pFSAccess; b32 pDirNavigate(c8 *dir); diff --git a/src/platform/platform_linux_public.c b/src/platform/platform_linux_public.c index e5e8492..24c5a5f 100644 --- a/src/platform/platform_linux_public.c +++ b/src/platform/platform_linux_public.c @@ -243,11 +243,16 @@ static pFile pFileOpen(c8 *file_name, pFSAccess acc) flags = O_WRONLY; if (BitEq(acc, pFS_TRUNC)) + { flags |= O_TRUNC; + } else if (BitEq(acc, pFS_APPEND)) flags |= O_APPEND; + + if (BitEq(acc, pFS_CREATE)) + flags |= O_CREAT; - return open(file_name, flags); + return open(file_name, flags, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); } static void pFileClose(pFile file) diff --git a/src/renderer.h b/src/renderer.h index 9f6bff4..666395a 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -44,6 +44,7 @@ typedef enum RenderBufferType_e rRBT_STORAGE = 0x0008, rRBT_HOST = 0x0010, rRBT_STAGING = 0x0020, + rRBT_ADDR = 0x0040, rRBT_HOST_VERTEX = rRBT_HOST | rRBT_VERTEX, rRBT_HOST_INDEX = rRBT_HOST | rRBT_INDEX, rRBT_HOST_UNIFORM = rRBT_HOST | rRBT_UNIFORM, @@ -110,13 +111,16 @@ void rDestroy(); static b32 rBufferMap(); static rDescHandle rTextureLoad(TextureAsset asset_id); +static rDescHandle rMeshLoad(ModelAsset asset_id); static void rTextureUnload(rDescHandle handle); +static void rMeshUnload(rDescHandle handle); static void rBufferBindVertex(rRenderBuffer *buffer); static void rBufferBindIndex(rRenderBuffer *buffer); static rawptr rBufferGUIVertMapping(); static rawptr rBufferGUIIdxMapping(); static void rBufferBindGUIVertex(); static void rBufferBindGUIIndex(); +static void rBufferBindMesh(rPushConst *pc, rDescHandle handle); // ::Renderer::Uniforms::Header:: // ::Renderer::PushConstants::Header:: diff --git a/src/renderer_vulkan.c b/src/renderer_vulkan.c index 51ee4da..ae30a72 100644 --- a/src/renderer_vulkan.c +++ b/src/renderer_vulkan.c @@ -75,7 +75,7 @@ static inline VkSemaphore vFrameSwapSem() return v_Renderer.frame_handles[vFrameIndex()].sc_sem; } -static inline vBufferAllocPtrArray *vFrameBuffers() +static inline vBufferPtrArray *vFrameBuffers() { return v_Renderer.buffers.frame_buffers + vFrameIndex(); } @@ -337,14 +337,14 @@ static void vSwapchainResize() // ::Vulkan::Images::Functions::Start:: -static vImageView *vImageViewCreate(TextureAssetMeta meta) +static vImageView *vImageViewCreate(TexMeta meta) { vImageView *view = FLMemAlloc(sizeof(vImageView)); Assert(vImageViewInit(view, meta.w, meta.h, meta.ch), "vImageViewCreate failure: vImage"); return view; } -static vTransfer *vTextureTransferInit(Arena *arena, u32 asset_id, VkImage image, u8 *bytes, TextureAssetMeta *meta) +static vTransfer *vTextureTransferInit(Arena *arena, u32 asset_id, VkImage image, rawptr bytes, TexMeta *meta) { vTransfer *transfer = MakeArray(arena, vTransfer, 1); @@ -491,7 +491,14 @@ static void vDescPushImageAndHandle(rDescHandle handle, vImageView *view) vImagePush(handle.asset_id, view); } -static u32 vDescPushImage(vImageView *view) +static void vDescPushModelAndHandle(rDescHandle handle, vModelBuffers *buffer) +{ + vDescHandlePush(vDT_MESH, handle); + vModelPush(handle.asset_id, buffer); +} + +// TODO: batch descriptor writes +static u32 vDescPushImageDesc(vImageView *view) { u32 index = vDescIndexPop(vDT_SAMPLED_IMAGE); @@ -515,6 +522,31 @@ static u32 vDescPushImage(vImageView *view) return index; } +static u32 vDescPushMeshDesc(vMeshBuffer *buffer) +{ + u32 index = vDescIndexPop(vDT_MESH); + + VkDescriptorBufferInfo buffer_info = { + .buffer = buffer->uniform.buffer, + .offset = 0, + .range = VK_WHOLE_SIZE, + }; + + VkWriteDescriptorSet desc_write = { + .sType = STYPE(WRITE_DESCRIPTOR_SET), + .dstSet = v_Renderer.handles.desc_sets[vDT_MESH], + .dstBinding = 0, + .descriptorCount = 1, + .dstArrayElement = index, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .pBufferInfo = &buffer_info, + }; + + vkUpdateDescriptorSets(v_Renderer.handles.device, 1, &desc_write, 0, NULL); + + return index; +} + static void vDescIndexPush(vDescType type, u32 index) { vDescBindings *bindings = v_Renderer.desc_bindings + type; @@ -586,8 +618,33 @@ static void vDescHandleDelete(vDescType type, u32 asset_id) // ::Vulkan::Buffers::Functions::Start:: +static vTransfer *vMeshTransferInit(Arena *arena, u32 asset_id, vMeshBuffer *mesh, rawptr bytes, u64 size) +{ + vTransfer *transfer = MakeArray(arena, vTransfer, 1); -static VkResult vBufferCreate(vBufferAlloc* buf, rRenderBufferType type, u64 size) + transfer->type = vTT_MESH; + transfer->data = bytes; + transfer->size = size; + transfer->mesh = mesh; + transfer->asset_id = asset_id; + + return transfer; +} + +static vTransfer *vBufferTransferInit(Arena *arena, u32 asset_id, vBuffer *index, rawptr bytes, u64 size) +{ + vTransfer *transfer = MakeArray(arena, vTransfer, 1); + + transfer->type = vTT_BUFFER; + transfer->data = bytes; + transfer->asset_id = asset_id; + transfer->size = size; + transfer->buffer = index->buffer; + + return transfer; +} + +static VkResult vBufferCreate(vBuffer* buf, rRenderBufferType type, u64 size) { Assert(type != rRBT_NONE, "vBufferCreate: rRenderBufferType must not be rRBT_NONE"); @@ -628,6 +685,12 @@ static VkResult vBufferCreate(vBufferAlloc* buf, rRenderBufferType type, u64 siz buffer_info.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; } + + if (BitEq(type, rRBT_ADDR)) + { + buffer_info.usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; + } + if ((type & rRBT_HOST) == rRBT_HOST || type == rRBT_STAGING) { alloc_info.requiredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; @@ -663,7 +726,30 @@ static rawptr vMapBuffer(VmaAllocation alloc) return ptr; } -// ::Vulkan::Buffers::Functions::Start:: +static void vModelPush(ModelAsset asset_id, vModelBuffers *buffer) +{ + HashTablePushU64Rawptr(&v_Renderer.buffers.buffers, asset_id, buffer); +} + +static vModelBuffers *vModelPop(ModelAsset asset_id) +{ + return (vModelBuffers *)HashTableDeleteU64Rawptr(&v_Renderer.buffers.buffers, asset_id); +} + +static vModelBuffers *vModelSearch(ModelAsset asset_id) +{ + vModelBuffers *buffers = NULL; + + KeyValuePair *pair = HashTableSearchU64(&v_Renderer.buffers.buffers, asset_id); + if (pair != NULL) + { + buffers = (vModelBuffers *)pair->value_rawptr; + } + + return buffers; +} + +// ::Vulkan::Buffers::Functions::End:: @@ -885,6 +971,7 @@ static b32 vDeviceCheckFeatureSupport(VkPhysicalDevice device) result &= (b32)features_12.descriptorBindingPartiallyBound; result &= (b32)features_12.runtimeDescriptorArray; result &= (b32)features_12.shaderSampledImageArrayNonUniformIndexing; + result &= (b32)features_12.shaderUniformBufferArrayNonUniformIndexing; result &= (b32)features_13.synchronization2; result &= (b32)features_13.dynamicRendering; @@ -1106,6 +1193,7 @@ static b32 vDeviceFunctionsInit() { INIT_DEV_FN(vkCmdClearColorImage); INIT_DEV_FN(vkCreateSampler); INIT_DEV_FN(vkDestroySampler); + INIT_DEV_FN(vkGetBufferDeviceAddress); return true; } @@ -1714,7 +1802,7 @@ static b32 vBuffersInit() for (u32 i = 0; i < FRAME_OVERLAP; i++) { - InitArrayType(buf->frame_buffers[i], arena, vBufferAlloc *, 128); + InitArrayType(buf->frame_buffers[i], arena, vBuffer *, 128); InitArrayType(buf->frame_images[i], arena, vImageView *, 128); buf->tex_destroy_queue.data[i] = MakeArray(arena, b8, TEXTURE_ASSET_MAX); @@ -1784,6 +1872,7 @@ static void vTransferUpload(vTransfer **transfers, u32 count) u64 transfer_size = 0; VkDeviceSize offset = 0; b32 imm_started = false; + b32 mesh_uniform_uploaded = false; u32 i = 0; for (;;) { @@ -1820,6 +1909,34 @@ static void vTransferUpload(vTransfer **transfers, u32 count) imm_started = true; } + if (!mesh_uniform_uploaded && transfers[i]->type == vTT_MESH) + { + VkBufferDeviceAddressInfo addr_info = { + .sType = STYPE(BUFFER_DEVICE_ADDRESS_INFO), + .buffer = transfers[i]->mesh->mesh.buffer, + }; + + vMesh mesh = { + .vertices = vkGetBufferDeviceAddress(device, &addr_info), + }; + + VkBufferCopy copy = { + .srcOffset = offset, + .dstOffset = cast(VkDeviceSize, 0), + .size = sizeof(vMesh), + }; + + MemCpy(ptr, &mesh, sizeof(vMesh)); + + ptr = PtrAdd(ptr, sizeof(vMesh)); + ptr_pos += sizeof(vMesh); + offset += sizeof(vMesh); + + vkCmdCopyBuffer(buffer, transfer->alloc.buffer, transfers[i]->mesh->uniform.buffer, 1, ©); + + mesh_uniform_uploaded = true; + } + if (transfers[i]->type != vTT_NONE) { u64 remaining = Diff(TRANSFER_BUFFER_CAP, ptr_pos); @@ -1827,25 +1944,34 @@ static void vTransferUpload(vTransfer **transfers, u32 count) if (transfer_size > remaining) transfer_size = remaining; - MemCpy(ptr, transfers[i]->data, transfer_size); + MemCpy(ptr, data_ptr, transfer_size); ptr = PtrAdd(ptr, transfer_size); PtrAddAdjustLen(data_ptr, data_len, transfer_size); ptr_pos += transfer_size; } + // TODO: + /* == Transfers == + * - offsets for target buffer + * - batch copy commands where possible + */ if (transfers[i]->type == vTT_IMAGE) { - MemZero(&transfers[i]->image_copy, sizeof(VkBufferImageCopy)); - - transfers[i]->image_copy.bufferRowLength = transfers[i]->w; - transfers[i]->image_copy.bufferImageHeight = transfers[i]->h; - transfers[i]->image_copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - transfers[i]->image_copy.imageSubresource.layerCount = 1; - transfers[i]->image_copy.imageExtent.width = transfers[i]->w; - transfers[i]->image_copy.imageExtent.height = transfers[i]->h; - transfers[i]->image_copy.imageExtent.depth = 1; - transfers[i]->image_copy.bufferOffset = offset; + VkBufferImageCopy copy = { + .bufferRowLength = transfers[i]->w, + .bufferImageHeight = transfers[i]->h, + .imageSubresource = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .layerCount = 1, + }, + .imageExtent = { + .width = transfers[i]->w, + .height = transfers[i]->h, + .depth = 1, + }, + .bufferOffset = offset, + }; vImageTransitionLayout(buffer, transfers[i]->image, @@ -1857,7 +1983,7 @@ static void vTransferUpload(vTransfer **transfers, u32 count) transfers[i]->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, - &transfers[i]->image_copy); + ©); vImageTransitionLayout(buffer, transfers[i]->image, @@ -1866,14 +1992,23 @@ static void vTransferUpload(vTransfer **transfers, u32 count) offset += (VkDeviceSize)transfer_size; } - else if (transfers[i]->type == vTT_BUFFER) + else if (transfers[i]->type == vTT_BUFFER || transfers[i]->type == vTT_MESH) { - transfers[i]->buffer_copy.srcOffset = offset; - transfers[i]->buffer_copy.dstOffset = cast(VkDeviceSize, 0); - transfers[i]->buffer_copy.size = transfer_size; + VkBuffer target_buf; + if (transfers[i]->type == vTT_BUFFER) + target_buf = transfers[i]->buffer; + else if (transfers[i]->type == vTT_MESH) + target_buf = transfers[i]->mesh->mesh.buffer; - // TODO: batch buffer types into one vulkan command - vkCmdCopyBuffer(buffer, transfer->alloc.buffer, transfers[i]->buffer, 1, &transfers[i]->buffer_copy); + VkBufferCopy copy = { + .srcOffset = offset, + .dstOffset = 0, + .size = transfer_size, + }; + + Printfln("transfer size %llu", transfer_size); + + vkCmdCopyBuffer(buffer, transfer->alloc.buffer, target_buf, 1, ©); offset += cast(VkDeviceSize, transfer_size); } @@ -1884,6 +2019,7 @@ static void vTransferUpload(vTransfer **transfers, u32 count) data_len = 0; transfer_size = 0; i += 1; + mesh_uniform_uploaded = false; } } diff --git a/src/renderer_vulkan.h b/src/renderer_vulkan.h index 00a9747..1c5f3d6 100644 --- a/src/renderer_vulkan.h +++ b/src/renderer_vulkan.h @@ -160,6 +160,7 @@ VK_DECLARE(vkDeviceWaitIdle); VK_DECLARE(vkCmdClearColorImage); VK_DECLARE(vkCreateSampler); VK_DECLARE(vkDestroySampler); +VK_DECLARE(vkGetBufferDeviceAddress); #include "vma/vk_mem_alloc.h" @@ -177,6 +178,7 @@ typedef enum DescType_e vDT_SHARED, vDT_SAMPLED_IMAGE, // DO NOT MOVE FROM POSITION 1 !! vDT_MATERIAL, + vDT_MESH, vDT_MAX, } vDescType; @@ -230,6 +232,11 @@ PtrArrayType(vImageView); ArrayType(vImageView); PtrArrayType(b8); +typedef struct vMesh +{ + VkDeviceAddress vertices; +} vMesh; + typedef struct vSampler { vImage image; @@ -237,14 +244,19 @@ typedef struct vSampler VkSampler sampler; } vSampler; -typedef struct vBufferAlloc +typedef struct vBuffer { VkBuffer buffer; VmaAllocation alloc; -} vBufferAlloc; +} vBuffer; -PtrArrayType(vBufferAlloc); -ArrayType(vBufferAlloc); +PtrArrayType(vBuffer); +ArrayType(vBuffer); + +typedef struct vMeshBuffer +{ + vBuffer mesh, uniform; +} vMeshBuffer; typedef struct vSwapchainState { @@ -339,7 +351,7 @@ typedef struct vRImages typedef struct vMappedBuffer { - vBufferAlloc alloc; + vBuffer alloc; rawptr ptr; u64 cap; } vMappedBuffer; @@ -347,7 +359,7 @@ typedef struct vMappedBuffer typedef struct vRBuffers { HashTable buffers; - vBufferAllocPtrArray frame_buffers[FRAME_OVERLAP]; + vBufferPtrArray frame_buffers[FRAME_OVERLAP]; HashTable images; vImageViewPtrArray frame_images[FRAME_OVERLAP]; @@ -358,10 +370,17 @@ typedef struct vRBuffers vMappedBuffer gui_idx; } vRBuffers; +typedef struct vModelBuffers +{ + vMeshBuffer *mesh; + vBuffer *index; +} vModelBuffers; + typedef enum vTransferType : u32 { vTT_NONE, vTT_BUFFER, + vTT_MESH, vTT_IMAGE, } vTransferType; @@ -382,14 +401,10 @@ typedef struct vTransfer }; union { + vMeshBuffer *mesh; VkBuffer buffer; VkImage image; }; - union - { - VkBufferCopy buffer_copy; - VkBufferImageCopy image_copy; - }; } vTransfer; typedef struct vUploadQueue @@ -444,6 +459,7 @@ typedef struct rPushConst { Vec2 res; f32 time; + u32 mesh_index; } rPushConst; typedef struct rGlobalUniforms @@ -503,7 +519,7 @@ static inline u32 vFrameIndex(); static inline VkImage vFrameSwapImage(); static inline b8 *vFrameTexDestroyQueue(); static inline b8 *vFrameNextTexDestroyQueue(); -static inline vBufferAllocPtrArray *vFrameBuffers(); +static inline vBufferPtrArray *vFrameBuffers(); static inline void vImageTransition(VkCommandBuffer cmd, vImage *img, VkImageLayout new); static inline void vImageTransitionLayout(VkCommandBuffer cmd, VkImage img, VkImageLayout curr, VkImageLayout new); static inline void vImageCopyToImage(VkCommandBuffer cmd, VkImage src, VkImage dst, VkExtent2D src_ext, VkExtent2D dst_ext); @@ -535,8 +551,8 @@ static void vSwapchainResize(); // ::Vulkan::Images::Functions::Header:: -static vTransfer *vTextureTransferInit(Arena *arena, u32 asset_id, VkImage image, u8 *bytes, TextureAssetMeta *meta); -static vImageView *vImageViewCreate(TextureAssetMeta meta); +static vTransfer *vTextureTransferInit(Arena *arena, u32 asset_id, VkImage image, rawptr bytes, TexMeta *meta); +static vImageView *vImageViewCreate(TexMeta meta); static b32 vImageViewInit(vImageView *view, u32 width, u32 height, u32 channels); static void vTextureCleanUp(); static void vImagePush(TextureAsset asset_id, vImageView *view); @@ -546,18 +562,25 @@ static vImageView *vImageSearch(TextureAsset asset_id); // ::Vulkan::Descriptors::Functions::Header:: static void vDescPushImageAndHandle(rDescHandle handle, vImageView *view); +static void vDescPushModelAndHandle(rDescHandle handle, vModelBuffers *buffer); static void vDescIndexPush(vDescType type, u32 index); static u32 vDescIndexPop(vDescType type); static rDescHandle vDescHandleSearch(vDescType type, u32 asset_id); static void vDescHandlePush(vDescType type, rDescHandle handle); static rDescHandle vDescHandlePop(vDescType type, u32 asset_id); static void vDescHandleDelete(vDescType type, u32 asset_id); -static u32 vDescPushImage(vImageView *view); +static u32 vDescPushImageDesc(vImageView *view); +static u32 vDescPushMeshDesc(vMeshBuffer *buffer); // ::Vulkan::Buffers::Functions::Header:: -static VkResult vBufferCreate(vBufferAlloc* buf, rRenderBufferType type, u64 size); +static vTransfer *vMeshTransferInit(Arena *arena, u32 asset_id, vMeshBuffer *mesh, rawptr bytes, u64 size); +static vTransfer *vBufferTransferInit(Arena *arena, u32 asset_id, vBuffer *index, rawptr bytes, u64 size); +static VkResult vBufferCreate(vBuffer* buf, rRenderBufferType type, u64 size); static rawptr vMapBuffer(VmaAllocation alloc); +static void vModelPush(ModelAsset asset_id, vModelBuffers *buffer); +static vModelBuffers *vModelPop(ModelAsset asset_id); +static vModelBuffers *vModelSearch(ModelAsset asset_id); // ::Vulkan::CleanUp::Functions::Header:: diff --git a/src/renderer_vulkan_public.c b/src/renderer_vulkan_public.c index 0eff72a..626e006 100644 --- a/src/renderer_vulkan_public.c +++ b/src/renderer_vulkan_public.c @@ -38,7 +38,7 @@ void rDestroy() { VkDevice device = v_Renderer.handles.device; VkInstance instance = v_Renderer.handles.inst; - vBufferAllocPtrArray *frame_buffers = v_Renderer.buffers.frame_buffers; + vBufferPtrArray *frame_buffers = v_Renderer.buffers.frame_buffers; vImmHandles imm = v_Renderer.imm; VmaAllocator vma_alloc = v_Renderer.handles.vma_alloc; VkSwapchainKHR swapchain = v_Renderer.handles.swapchain; @@ -128,17 +128,18 @@ static rDescHandle rTextureLoad(TextureAsset asset_id) vImageView *view = FLMemAlloc(sizeof(vImageView)); Asset asset = apLoadTexture(asset_id); - TextureAssetMeta meta = apGetTextureMeta(asset_id); + TexMeta meta = apGetTextureMeta(asset_id); // TODO: handle errors instead of failing Assert(vImageViewInit(view, meta.w, meta.h, meta.ch), "rTextureLoad failure: vImageViewInit failed"); handle.asset_id = asset_id; - handle.desc_index = vDescPushImage(view); + handle.desc_index = vDescPushImageDesc(view); + + vTransfer *transfer = vTextureTransferInit(vFrameArena(), asset_id, view->image.image, asset.bytes, &meta); TicketMutLock(&v_Renderer.upload.mut); - vTransfer *transfer = vTextureTransferInit(vFrameArena(), asset_id, view->image.image, asset.bytes, &meta); u32 job_idx = JobQueueAdd(&v_Renderer.upload.job_queue, 1); v_Renderer.upload.transfers[job_idx] = transfer; vDescPushImageAndHandle(handle, view); @@ -151,6 +152,47 @@ static rDescHandle rTextureLoad(TextureAsset asset_id) return handle; } +static rDescHandle rMeshLoad(ModelAsset asset_id) +{ + rDescHandle handle = vDescHandleSearch(vDT_MESH, asset_id); + + if (handle.asset_id == UINT32_MAX) + { + vMeshBuffer *buffer = FLMemAlloc(sizeof(vMeshBuffer)); + vBuffer *index_buffer = FLMemAlloc(sizeof(vBuffer)); + vModelBuffers *model_buffer = FLMemAlloc(sizeof(vModelBuffers)); + + model_buffer->mesh = buffer; + model_buffer->index = index_buffer; + + Asset asset = apLoadModel(asset_id); + + // TODO: handle errors + Assert(vBufferCreate(&buffer->mesh, rRBT_STORAGE | rRBT_ADDR, sizeof(rPBRVertex) * asset.model->v_count) == VK_SUCCESS, "rMeshLoad failure: vBufferCreate didn't return VK_SUCCESS"); + Assert(vBufferCreate(&buffer->uniform, rRBT_UNIFORM, sizeof(vMesh)) == VK_SUCCESS, "rMeshLoad failure: vBufferCreate didn't return VK_SUCCESS"); + Assert(vBufferCreate(index_buffer, rRBT_INDEX, sizeof(u32) * asset.model->i_count) == VK_SUCCESS, "rMeshLoad failure: vBufferCreate didn't return VK_SUCCESS"); + + handle.asset_id = asset_id; + handle.desc_index = vDescPushMeshDesc(buffer); + + vTransfer *transfer = vMeshTransferInit(vFrameArena(), asset_id, buffer, asset.model->vertices, asset.model->v_count * sizeof(rPBRVertex)); + vTransfer *index_transfer = vBufferTransferInit(vFrameArena(), asset_id, index_buffer, asset.model->indices, asset.model->i_count * sizeof(u32)); + + TicketMutLock(&v_Renderer.upload.mut); + + u32 job_idx = JobQueueAdd(&v_Renderer.upload.job_queue, 2); + v_Renderer.upload.transfers[job_idx] = transfer; + v_Renderer.upload.transfers[job_idx + 1] = index_transfer; + vDescPushModelAndHandle(handle, model_buffer); + + TicketMutUnlock(&v_Renderer.upload.mut); + + vLoaderWake(); + } + + return handle; +} + static void rTextureUnload(rDescHandle current_handle) { rDescHandle handle = vDescHandleSearch(vDT_SAMPLED_IMAGE, current_handle.asset_id); @@ -218,6 +260,16 @@ static void rBufferBindGUIIndex() vkCmdBindIndexBuffer(cmd, buffer, 0, VK_INDEX_TYPE_UINT32); } +static void rBufferBindMesh(rPushConst *pc, rDescHandle handle) +{ + vModelBuffers *buffers = vModelSearch(handle.asset_id); + if (buffers != NULL) + { + Printfln("binding index buffer"); + vkCmdBindIndexBuffer(vFrameCmdBuf(), buffers->index->buffer, 0, VK_INDEX_TYPE_UINT32); + } +} + // ::Vulkan::Renderer::Buffers::Functions::End:: diff --git a/src/shaders/glsl/pbr.vert.glsl b/src/shaders/glsl/pbr.vert.glsl index 0b3848d..6055dc3 100644 --- a/src/shaders/glsl/pbr.vert.glsl +++ b/src/shaders/glsl/pbr.vert.glsl @@ -6,13 +6,11 @@ #include "structures.glsl" -layout (location = 0) in vec4 in_pos; -layout (location = 1) in vec4 in_col; - layout (location = 0) out vec4 out_col; void main() { - out_col = in_col; - gl_Position = in_pos; + Vertex v = Meshes[nonuniformEXT(PC.mesh_index)].buf.vertices[gl_VertexIndex]; + gl_Position = v.pos; + out_col = v.col; } diff --git a/src/shaders/glsl/structures.glsl b/src/shaders/glsl/structures.glsl index c67a950..3ff86a9 100644 --- a/src/shaders/glsl/structures.glsl +++ b/src/shaders/glsl/structures.glsl @@ -3,9 +3,8 @@ // ========================================== struct Vertex { - float uv_x; - float uv_y; - float x, y, z; + vec4 pos; + vec4 col; }; struct GUIVertex { @@ -14,6 +13,10 @@ struct GUIVertex { vec4 col; }; +layout (buffer_reference, std430) readonly buffer VertexBuffer { + Vertex vertices[]; +}; + layout (set = 0, binding = 0) uniform GlobalUniform { vec2 res; } Globals; @@ -36,15 +39,12 @@ layout (set = 2, binding = 0) uniform PBRMaterials { float ao; } Materials[]; -layout (std430, buffer_reference) readonly buffer VertexBuffer { - Vertex vertices[]; -}; - -layout (std430, buffer_reference) readonly buffer GUIVertexBuffer { - GUIVertex vertices[]; -}; +layout (set = 3, binding = 0) uniform ModelMeshes { + VertexBuffer buf; +} Meshes[]; layout (push_constant) uniform Constants { - vec2 res; + vec2 res; float time; + uint mesh_index; } PC; diff --git a/src/vulkan_config.c b/src/vulkan_config.c index 5635add..e72b5b8 100644 --- a/src/vulkan_config.c +++ b/src/vulkan_config.c @@ -82,6 +82,7 @@ static VkPhysicalDeviceVulkan12Features vk_12_features = { .descriptorBindingStorageBufferUpdateAfterBind = VK_TRUE, .descriptorBindingPartiallyBound = VK_TRUE, .shaderSampledImageArrayNonUniformIndexing = VK_TRUE, + .shaderUniformBufferArrayNonUniformIndexing = VK_TRUE, .runtimeDescriptorArray = VK_TRUE, }; @@ -258,6 +259,7 @@ static VkDescriptorSetLayoutCreateInfo shared_layout_create_info = { static VkDescriptorType desc_type_map[vDT_MAX] = { [vDT_SAMPLED_IMAGE] = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, [vDT_MATERIAL] = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + [vDT_MESH] = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, }; static VkDescriptorBindingFlags bindless_desc_binding_flags = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT | VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT; @@ -460,17 +462,10 @@ VkVertexInputBindingDescription pbr_input_bind_desc = { .inputRate = VK_VERTEX_INPUT_RATE_VERTEX, }; -VkVertexInputAttributeDescription pbr_input_descriptions[] = { - { .binding = 0, .location = 0, .format = VK_FORMAT_R32G32B32A32_SFLOAT, .offset = 0 }, - { .binding = 1, .location = 1, .format = VK_FORMAT_R32G32B32A32_SFLOAT, .offset = offsetof(rPBRVertex, col) }, -}; - VkPipelineVertexInputStateCreateInfo pbr_vertex_input_info = { .sType = STYPE(PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO), .vertexBindingDescriptionCount = 1, .pVertexBindingDescriptions = &pbr_input_bind_desc, - .vertexAttributeDescriptionCount = Len(pbr_input_descriptions), - .pVertexAttributeDescriptions = pbr_input_descriptions, }; VkPipelineInputAssemblyStateCreateInfo pbr_assembly_info = {