diff --git a/assets/textures/cheesoid.png b/assets/textures/cheesoid.png old mode 100755 new mode 100644 diff --git a/build.sh b/build.sh index 51239ff..a51444c 100755 --- a/build.sh +++ b/build.sh @@ -121,15 +121,17 @@ fi # Packer Codegen $compile $codegen_source_files $compile_link $link_os_gfx $codegen_flags $packer_include_flags $out $codegen_out_name +./Codegen + # 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 ] || ! [ -f assets.sgp ]; then -# ./Packer -#fi +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 +if ! [ -v packer ]; then + $compile $source_files $compile_link $link_os_gfx $out $out_name +fi diff --git a/src/assets.c b/src/assets.c index deca81c..5fb1475 100644 --- a/src/assets.c +++ b/src/assets.c @@ -36,19 +36,8 @@ const u32 M3D_LABEL = CreateMagicValue('L', 'B', 'L', 'S'); static FileHeader File_Header = {0}; -static AssetFile Texture_Assets[TEXTURE_ASSET_MAX]; -static Asset Texture_Asset_Lookup[TEXTURE_ASSET_MAX]; - -static AssetFile Shader_Assets[SHADER_ASSET_MAX]; -static Asset Shader_Asset_Lookup[SHADER_ASSET_MAX]; - -static AssetFile Model_Assets[MODEL_ASSET_MAX]; -static Asset Model_Asset_Lookup[MODEL_ASSET_MAX]; - -// TODO(MA): Implement async asset handling -static u32 Shader_Asset_Ref_Count[SHADER_ASSET_MAX]; -static u32 Texture_Asset_Ref_Count[TEXTURE_ASSET_MAX]; -static u32 Model_Asset_Ref_Count[MODEL_ASSET_MAX]; +static AssetFile Asset_Info[ASSET_MAX]; +static Asset Asset_Data[ASSET_MAX]; static b32 ASSET_HEADER_LOADED = false; @@ -64,8 +53,9 @@ static void apInit() MemCpy(&File_Header, ASSET_PACK, sizeof(FileHeader)); Assert(File_Header.magic_num == CreateMagicValue('s', 't', 'e', 'g'), "Magic value is incorrect"); + Assert(File_Header.version == FILE_VERSION, "Asset file version mismatch"); - MemCpy(Texture_Assets, &ASSET_PACK[File_Header.asset_offset], sizeof(AssetFile) * File_Header.asset_counts); + MemCpy(Asset_Info, &ASSET_PACK[File_Header.asset_offset], sizeof(AssetFile) * File_Header.asset_counts); ASSET_HEADER_LOADED = true; } @@ -76,12 +66,81 @@ static void apInit() // ::Assets::Loading::Functions::Start:: +static Asset * +apAssetSearch(u64 hash) +{ + Asset *asset = NULL; + + for (u64 i = 0; i < ASSET_MAX; i++) + { + if (asset == NULL && Asset_Data[i].hash == 0) + { + asset = Asset_Data + i; + } + + if (hash == Asset_Data[i].hash) + { + asset = Asset_Data + i; + break; + } + } + + return asset; +} + +static Asset +apLoadWithHash(u64 hash) +{ + if (!ASSET_HEADER_LOADED) + { + apInit(); + } + + Asset *asset = apAssetSearch(hash); + AssetFile file_info = {0}; + + if (asset->bytes == NULL) + { + for (u64 i = 0; i < ASSET_MAX; i++) + { + if (hash == Asset_Info[i].hash) + { + file_info = Asset_Info[i]; + break; + } + } + + if (file_info.hash != 0) + { + asset->hash = hash; + asset->type = file_info.type; + + u8 *bytes = FLMemAlloc(file_info.len); + MemCpy(bytes, &ASSET_PACK[file_info.data_offset], file_info.len); + + if (file_info.type == AT_MODEL) + { + asset->model = apParseModel(bytes); + asset->model_meta = file_info.model_meta; + FLMemFree(bytes); + } + else + { + asset->len = file_info.len; + asset->bytes = bytes; + asset->texture_meta = file_info.texture_meta; + } + } + } + + return *asset; +} + static Asset apLoad(c8 *str) { - Asset asset = {0}; - - return asset; + u64 hash = HashFromString(String8CStr(str)); + return apLoadWithHash(hash); } static Asset @@ -90,10 +149,34 @@ apLoadS8(String8 str) return apLoad(str.value); } +static void +apUnloadWithHash(u64 hash) +{ + Asset *asset = apAssetSearch(hash); + + if (asset->bytes != NULL) + { + if (asset->type == AT_MODEL) + { + apFreeModel(asset->model); + } + else + { + FLMemFree(asset->bytes); + } + + asset->bytes = NULL; + asset->type = AT_NONE; + asset->len = 0; + asset->hash = 0; + } +} + static void apUnload(c8 *str) { - + u64 hash = HashFromString(String8CStr(str)); + apUnloadWithHash(hash); } static void @@ -288,5 +371,12 @@ static m3dModel *apParseModel(rawptr data) return model; } +static void apFreeModel(m3dModel *model) +{ + FLMemFree(model->vertices); + FLMemFree(model->indices); + FLMemFree(model); +} + // ::Assets::Models::Functions::End:: diff --git a/src/assets.h b/src/assets.h index e07d32b..bac7432 100644 --- a/src/assets.h +++ b/src/assets.h @@ -2,7 +2,7 @@ // ::Assets::Macros::Header:: -#define FILE_VERSION 1 +#define FILE_VERSION 3U #define CreateMagicValue(a, b, c, d) ((u32)(d << 24) | (u32)(c << 16) | (u32)(b << 8) | (u32)(a)) @@ -37,25 +37,6 @@ typedef struct ModelMeta u64 i_count; } ModelMeta; -typedef struct AssetMeta -{ - union - { - TexMeta texture; - ModelMeta model; - }; -} AssetMeta; - -typedef struct Asset -{ - union - { - u8 *bytes; - m3dModel *model; - }; - u64 len; -} Asset; - typedef struct AssetTag { u32 tag_id; @@ -70,6 +51,23 @@ typedef enum AssetType_e AT_MODEL, } AssetType; +typedef struct Asset +{ + union + { + u8 *bytes; + m3dModel *model; + }; + union + { + TexMeta texture_meta; + ModelMeta model_meta; + }; + u64 hash; + u64 len; + AssetType type; +} Asset; + typedef struct AssetFile { union @@ -99,9 +97,12 @@ static void apInit(); static Asset apLoad(c8 *str); static Asset apLoadS8(String8 str); +static Asset apLoadWithHash(u64 hash); static void apUnload(c8 *str); static void apUnloadS8(String8 str); +static void apUnloadWithHash(u64 hash); static u64 apAssetIndex(c8 *str); +static Asset *apAssetSearch(u64 hash); // ::Assets::Util::Functions::Header:: @@ -112,3 +113,4 @@ static inline void apMarkLoaded(c8 *str); // ::Assets::Models::Functions::Header:: static m3dModel *apParseModel(rawptr data); +static void apFreeModel(m3dModel *model); diff --git a/src/codegen.c b/src/codegen.c index 105c8b3..19833eb 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -1,5 +1,7 @@ #include "codegen.h" +#include "xxhash/xxhash.c" + u64 WriteArrayToFile(Arena *arena, pFile file, String8 array_name, rawptr elements, u32 count, String8 type, u64 offset) { @@ -89,6 +91,7 @@ CodeGenAssetLookups(Arena *arena) }, }; + u64 total_assets = 0; u64 offset = 0; u32 dir_count = sizeof(dirs) / sizeof(struct AssetDirInfo); for (u32 i = 0; i < dir_count; i += 1) @@ -104,7 +107,7 @@ CodeGenAssetLookups(Arena *arena) { strs[j] = String8Concat(arena, String8CStr(dirs[i].prefix), strs[j]); i64 offset = String8FindLast(strs[j], '.'); - hashes[j] = XXH3_64bits_withSeed(strs[j].value, strs[j].len - offset, HASH_SEED); + hashes[j] = XXH3_64bits_withSeed(strs[j].value, offset, HASH_SEED); } offset += WriteArrayToFile( @@ -128,10 +131,18 @@ CodeGenAssetLookups(Arena *arena) ); c8 buf[256]; - i32 decl_len = SPrintf(buf, 256, "#define %s_MAX %llu\n\n#define %s %d\n\n", dirs[i].define, count, dirs[i].define, i); + i32 decl_len = SPrintf(buf, 256, "#define %s_MAX %lluU\n\n#define %s %dU\n\n", dirs[i].define, count, dirs[i].define, i); offset += pFileWrite(file, offset, buf, decl_len); + total_assets += count; + + if (i == dir_count-1) + { + decl_len = SPrintf(buf, 256, "#define ASSET_MAX %lluU\n\n#define RENDERER_ASSET_MAX (ASSET_MAX - SHADER_ASSET_MAX)\n\n#define ASSET_TYPE_MAX %dU\n\n", total_assets, i+1); + pFileWrite(file, offset, buf, decl_len); + } + Assert(pDirNavigate("..") == 0, "CodeGenAssetLookups failure: unable to move back to build directory"); } diff --git a/src/codegen_assets.h b/src/codegen_assets.h index ff7e5d0..3ec92b5 100644 --- a/src/codegen_assets.h +++ b/src/codegen_assets.h @@ -12,17 +12,17 @@ g_Shader_Asset_Names[] = static u64 g_Shader_Asset_Hashes[] = { - 12100337026595633089U, - 12100337026595633089U, - 12100337026595633089U, - 12100337026595633089U, - 12100337026595633089U, - 12100337026595633089U, + 15780387719315455808U, + 2230071466542309169U, + 14797956403837654625U, + 8430018914716708078U, + 14432191255225961360U, + 8518761701216801634U, }; -#define SHADER_ASSET_MAX 6 +#define SHADER_ASSET_MAX 6U -#define SHADER_ASSET 0 +#define SHADER_ASSET 0U static c8 * g_Model_Asset_Names[] = @@ -34,13 +34,13 @@ g_Model_Asset_Names[] = static u64 g_Model_Asset_Hashes[] = { - 2356409063604999112U, - 2356409063604999112U, + 13826959199295087925U, + 4559395153940738542U, }; -#define MODEL_ASSET_MAX 2 +#define MODEL_ASSET_MAX 2U -#define MODEL_ASSET 1 +#define MODEL_ASSET 1U static c8 * g_Texture_Asset_Names[] = @@ -57,16 +57,22 @@ g_Texture_Asset_Names[] = static u64 g_Texture_Asset_Hashes[] = { - 5461253849680765905U, - 5461253849680765905U, - 5461253849680765905U, - 5461253849680765905U, - 5461253849680765905U, - 5461253849680765905U, - 5461253849680765905U, + 15457434128510259736U, + 12443444479937967236U, + 5538438794723924882U, + 16650761267170532297U, + 11718504567089932798U, + 7627422980398294448U, + 14316598952102237724U, }; -#define TEXTURE_ASSET_MAX 7 +#define TEXTURE_ASSET_MAX 7U -#define TEXTURE_ASSET 2 +#define TEXTURE_ASSET 2U + +#define ASSET_MAX 15U + +#define RENDERER_ASSET_MAX (ASSET_MAX - SHADER_ASSET_MAX) + +#define ASSET_TYPE_MAX 3U diff --git a/src/game.c b/src/game.c index 017e7c1..7c1e7d2 100644 --- a/src/game.c +++ b/src/game.c @@ -72,14 +72,9 @@ gRunCycle(gGameCtx *ctx, pGameInput *inputs, u32 i_count) rFrameBegin(); - vTextureCleanUp(); - u64 index = vFrameIndex(); - /* - rDescHandle yoder = rMeshLoad(MODEL_YODA); - ctx->pc.mesh_index = yoder.desc_index; - */ + rDescHandle yoder = rGetAsset("models/yoda"); rViewportSize(&ctx->pc.res); ctx->pc.time = (f32)pCPUTimerRead(); @@ -90,19 +85,16 @@ gRunCycle(gGameCtx *ctx, pGameInput *inputs, u32 i_count) MemCpy(vert_buffer, ctx->gui.vertices, sizeof(rUIVertex) * ctx->gui.vertices_len); MemCpy(idx_buffer, ctx->gui.indices, sizeof(u32) * ctx->gui.indices_len); - vBufferQueueWait(); - rPipelineBind(rPIPELINE_PBR, rPT_GRAPHICS); - rPushConstantsSet(&ctx->pc); //rBufferBindGUIVertex(); //rBufferBindGUIIndex(); - //rBufferBindMesh(&ctx->pc, yoder); + rBufferBindMesh(&ctx->pc, yoder); - //rDrawIndexed(model_meta.i_count, 1); + rDrawMesh(yoder); rFrameFinish(); diff --git a/src/packer.c b/src/packer.c index 372936e..100f4a4 100644 --- a/src/packer.c +++ b/src/packer.c @@ -56,24 +56,24 @@ InitHeader(FileHeader *header) void PackFiles(Arena *arena, FileHeader *header) { - pFile file = pFileOpen("assets.sgp", pFS_WRITE | pFS_TRUNC); + pFile file = pFileOpen("assets.sgp", pFS_WRITE | pFS_TRUNC | pFS_CREATE); u64 file_pos = pFileWrite(file, 0, header, sizeof(FileHeader)); - c8 *return_dir = "."; Assert(pDirNavigate("../assets") == 0, "Unable to move to assets directory"); u64 total_assets = SHADER_ASSET_MAX + TEXTURE_ASSET_MAX + MODEL_ASSET_MAX; u64 asset_count = 0; AssetFile *assets = MakeArray(arena, AssetFile, total_assets); - u64 data_offset = header->asset_offset + (sizeof(AssetFile) + total_assets); + u64 data_offset = header->asset_offset + (sizeof(AssetFile) * total_assets); + Printfln("%llu %d", data_offset, sizeof(FileHeader)); for (u32 i = 0; i < SHADER_ASSET_MAX; i++, asset_count++) { c8 *asset_name = g_Shader_Asset_Names[i]; - Printfln("Packing file: %s...", asset_name); + Printfln("Packing file: %s at offset %llu...", asset_name, data_offset); pFile asset_file = pFileOpen(asset_name, pFS_READ); u64 file_size = pFileLength(asset_file); @@ -82,13 +82,14 @@ PackFiles(Arena *arena, FileHeader *header) pFileRead(asset_file, 0, file_data, file_size); u64 prev_offset = data_offset; - data_offset += pFileWrite(file, data_offset, file_data, file_size); + data_offset += pFileWrite(file, prev_offset, file_data, file_size); Assert((data_offset - prev_offset) == file_size, "File write size invalid"); assets[asset_count].data_offset = prev_offset; assets[asset_count].len = file_size; assets[asset_count].type = AT_SHADER; + assets[asset_count].hash = g_Shader_Asset_Hashes[i]; pFileClose(asset_file); } @@ -97,7 +98,7 @@ PackFiles(Arena *arena, FileHeader *header) { c8 *asset_name = g_Texture_Asset_Names[i]; - Printfln("Packing file: %s...", asset_name); + Printfln("Packing file: %s at offset %llu...", asset_name, data_offset); pFile asset_file = pFileOpen(asset_name, pFS_READ); u64 file_size = pFileLength(asset_file); @@ -124,6 +125,7 @@ PackFiles(Arena *arena, FileHeader *header) assets[asset_count].data_offset = prev_offset; assets[asset_count].len = loaded_length; assets[asset_count].type = AT_TEXTURE; + assets[asset_count].hash = g_Texture_Asset_Hashes[i]; assets[asset_count].texture_meta.w = u32(w); assets[asset_count].texture_meta.h = u32(h); assets[asset_count].texture_meta.ch = u32(ch); @@ -131,13 +133,14 @@ PackFiles(Arena *arena, FileHeader *header) stbi_image_free(image_bytes); pFileClose(asset_file); + } for (u32 i = 0; i < MODEL_ASSET_MAX; i++, asset_count++) { c8 *asset_name = g_Model_Asset_Names[i]; - Printfln("Packing file: %s...", asset_name); + Printfln("Packing file: %s at offset %llu...", asset_name, data_offset); pFile asset_file = pFileOpen(asset_name, pFS_READ); u64 file_size = pFileLength(asset_file); @@ -155,12 +158,19 @@ PackFiles(Arena *arena, FileHeader *header) assets[asset_count].data_offset = prev_offset; assets[asset_count].type = AT_MODEL; assets[asset_count].len = file_size; + assets[asset_count].hash = g_Model_Asset_Hashes[i]; assets[asset_count].model_meta.i_count = u64(model->numface * 3); + m3d_free(model); + pFileClose(asset_file); } pFileWrite(file, header->asset_offset, assets, sizeof(AssetFile)*asset_count); + + pFileClose(file); + + Assert(pDirNavigate("../build") == 0, "Unable to navigate back to build directory"); } // ::Packer::Packing::Functions::End:: @@ -218,6 +228,8 @@ TestAssetPack(Arena *arena) { pFile file = pFileOpen("assets.sgp", pFS_READ); + Assert(pDirNavigate("../assets") == 0, "Unable to navigate back to assets directory"); + FileHeader header; i64 offset = pFileRead(file, 0, &header, sizeof(FileHeader)); @@ -235,16 +247,19 @@ TestAssetPack(Arena *arena) for (u32 i = 0; i < SHADER_ASSET_MAX; i++, current_asset++) { TestAssetIsCorrect(arena, g_Shader_Asset_Names[i], files + current_asset, file); + Assert(files[current_asset].hash == g_Shader_Asset_Hashes[i], "Shader asset hash mismatch"); } for (u32 i = 0; i < TEXTURE_ASSET_MAX; i++, current_asset++) { TestAssetIsCorrect(arena, g_Texture_Asset_Names[i], files + current_asset, file); + Assert(files[current_asset].hash == g_Texture_Asset_Hashes[i], "Texture asset hash mismatch"); } for (u32 i = 0; i < MODEL_ASSET_MAX; i++, current_asset++) { TestAssetIsCorrect(arena, g_Model_Asset_Names[i], files + current_asset, file); + Assert(files[current_asset].hash == g_Model_Asset_Hashes[i], "Model asset hash mismatch"); } } @@ -271,15 +286,10 @@ main(int argc, c8 **argv) void *mem = pMemAllocZeroed(GB(1)); Arena *arena = ArenaInitDebug(mem, GB(1), __LINE__); - pFile file = pFileOpen("assets.sgp", pFS_WRITE | pFS_TRUNC | pFS_CREATE); - Assert(file > 0, "File is null"); - FileHeader header = {0}; InitHeader(&header); PackFiles(arena, &header); - - pFileClose(file); TestAssetPack(arena); } diff --git a/src/renderer.h b/src/renderer.h index 537edd1..997ca25 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -110,12 +110,6 @@ void rDestroy(); // ::Renderer::Buffers::Header:: static b32 rBufferMap(); -static rDescHandle rAssetLoad(c8 *name); -static void rAssetUnload(rDescHandle handle); -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(); @@ -141,6 +135,11 @@ static b32 rFrameBegin(); static b32 rFrameFinish(); static void rDrawIndexed(u32 index_count, u32 instance_count); static void rPipelineBind(rPipelineHandle handle, rPipelineType type); +static void rDrawMesh(rDescHandle handle); + +// ::Renderer::Assets::Header:: + +static rDescHandle rGetAsset(c8 *asset_name); // ::Renderer::Includes::Header:: diff --git a/src/renderer_vulkan.c b/src/renderer_vulkan.c index c42f6c7..1bdfd07 100644 --- a/src/renderer_vulkan.c +++ b/src/renderer_vulkan.c @@ -80,25 +80,7 @@ vFrameRenderSem() static inline VkSemaphore vFrameSwapSem() { - return v_Renderer.frame_handles[vFrameIndex()].sc_sem; -} - -static inline vBufferPtrArray * -vFrameBuffers() -{ - return v_Renderer.buffers.frame_buffers + vFrameIndex(); -} - -static inline b8 * -vFrameTexDestroyQueue() -{ - return v_Renderer.buffers.tex_destroy_queue.data[vFrameIndex()]; -} - -static inline b8 * -vFrameNextTexDestroyQueue() -{ - return v_Renderer.buffers.tex_destroy_queue.data[vFrameNextIndex()]; + return v_Renderer.handles.sc_sems[v_Renderer.state.vk.image_idx]; } static inline void @@ -316,6 +298,7 @@ vImmSubmitFinish(VkDevice device, VkFence fence, VkCommandBuffer cmd, VkQueue qu if (success) { result = vkWaitForFences(device, 1, &f, true, 9999999999); + Printfln("fence waited"); if (result != VK_SUCCESS) { Printfln("vkWaitForFences imm failure: %s", vVkResultStr(result)); @@ -512,6 +495,41 @@ vDescIndexPop(vDescType type) +// ::Vulkan::Assets::Functions::Start:: + +static vAsset * +vAssetSearch(c8 *asset_name) +{ + vAsset *asset = NULL; + + u64 hash = HashFromString(String8CStr(asset_name)); + Printfln("hash %llu", hash); + vAssetArray assets = v_Renderer.buffers.assets; + for (u64 i = 0; i < assets.length; i += 1) + { + Printfln("asset_hash %llu", assets.data[i].hash); + if (hash == assets.data[i].hash) + { + asset = assets.data + i; + break; + } + } + + return asset; +} + +static vAsset * +vAssetLookupIndex(u32 asset_idx) +{ + Printfln("asset_idx %llu", asset_idx); + Assert(asset_idx < ASSET_MAX, "asset index is out of range"); + return v_Renderer.buffers.assets.data + asset_idx; +} + +// ::Vulkan::Assets::Functions::End:: + + + // ::Vulkan::Buffers::Functions::Start:: static VkResult @@ -1152,15 +1170,9 @@ vFrameStructuresInit() if (result != VK_SUCCESS) success = false; - result = vkCreateSemaphore(device, &g_Semaphore_Create_info, NULL, &handles->r_sem); + result = vkCreateSemaphore(device, &g_Semaphore_Create_Info, NULL, &handles->r_sem); if (result != VK_SUCCESS) success = false; - - result = vkCreateSemaphore(device, &g_Semaphore_Create_info, NULL, &handles->sc_sem); - if (result != VK_SUCCESS) - success = false; - - //renderer.vk.frame.buffer_destroy_queues[i] = ArenaAlloc(v_Renderer.mem.perm_arena, sizeof(rRenderBuffer) * 64); } return success; @@ -1291,6 +1303,17 @@ vSwapchainInit() v_Renderer.state.swapchain.extent.height = extent.height; v_Renderer.state.swapchain.extent.depth = 1; + v_Renderer.handles.sc_sems = MakeArray(arena, VkSemaphore, image_count); + for (u32 i = 0; i < image_count; i++) + { + result = vkCreateSemaphore(device, &g_Semaphore_Create_Info, NULL, v_Renderer.handles.sc_sems + i); + if (result != VK_SUCCESS) + { + Printfln("vkCreateSemaphore failure: failed to create swapchain semaphore %s", vVkResultStr(result)); + success = false; + } + } + return success; } @@ -1664,37 +1687,146 @@ vShaderModuleInit(u8 *bytes, u32 len, VkShaderModule *module) return success; } +static b32 +vAssetsInit() +{ + vRBuffers *buf = &v_Renderer.buffers; + Arena *arena = v_Renderer.mem.perm_arena; + VkDevice device = v_Renderer.handles.device; + VkFence fence = v_Renderer.imm.fence; + VkQueue queue = v_Renderer.handles.tfer_queue; + VkCommandBuffer cmd = v_Renderer.imm.buffer; + vMappedBuffer *transfer = &v_Renderer.buffers.transfer; + + InitArrayType(buf->assets, arena, vAsset, RENDERER_ASSET_MAX); + + Assert(vImmSubmitBegin(device, fence, cmd), "Unable to begin immediate submit"); + + u64 asset_index = 0; + for (u64 i = 0; i < TEXTURE_ASSET_MAX; i++, asset_index++) + { + u64 hash = g_Texture_Asset_Hashes[i]; + Asset asset = apLoadWithHash(hash); + vImageView *view = vImageViewCreate(asset.texture_meta); + Assert(view != NULL, "Unable to create vImageView"); + + + VkBufferImageCopy copy = { + .bufferRowLength = asset.texture_meta.w, + .bufferImageHeight = asset.texture_meta.h, + .imageSubresource = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .layerCount = 1, + }, + .imageExtent = { + .width = asset.texture_meta.w, + .height = asset.texture_meta.h, + .depth = 1, + }, + .bufferOffset = 0, + }; + + MemCpy(transfer->ptr, asset.bytes, asset.len); + + vImageTransitionLayout(cmd, view->image.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + vkCmdCopyBufferToImage(cmd, transfer->alloc.buffer, view->image.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©); + vImageTransitionLayout(cmd, view->image.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + vAsset *asset_data = buf->assets.data + asset_index; + asset_data->hash = hash; + asset_data->handle.asset_index = asset_index; + asset_data->handle.desc_index = vDescPushImageDesc(view); + asset_data->texture_meta = asset.texture_meta; + asset_data->texture = view; + + apUnloadWithHash(hash); + } + + for (u64 i = 0; i < MODEL_ASSET_MAX; i++, asset_index++) + { + u64 hash = g_Model_Asset_Hashes[i]; + Asset asset = apLoadWithHash(hash); + + vMeshAsset *buffer = FLMemAlloc(sizeof(vMeshAsset)); + Assert(vBufferCreate(&buffer->mesh.mesh, rRBT_ADDR | rRBT_STORAGE, sizeof(Vertex) * asset.model->v_count) == VK_SUCCESS, "Unable to create mesh buffer"); + Assert(vBufferCreate(&buffer->mesh.uniform, rRBT_UNIFORM, sizeof(vMesh)) == VK_SUCCESS, "Unable to create uniform buffer"); + Assert(vBufferCreate(&buffer->index, rRBT_INDEX, sizeof(u32) * asset.model->i_count) == VK_SUCCESS, "Unable to create index buffer"); + + VkBufferDeviceAddressInfo addr_info = { + .sType = STYPE(BUFFER_DEVICE_ADDRESS_INFO), + .buffer = buffer->mesh.mesh.buffer, + }; + + vMesh mesh = { + .vertices = vkGetBufferDeviceAddress(device, &addr_info), + }; + + VkBufferCopy uniform_copy = { + .srcOffset = 0, + .dstOffset = 0, + .size = sizeof(vMesh), + }; + + rawptr ptr = transfer->ptr; + + MemCpy(ptr, &mesh, sizeof(vMesh)); + + ptr = PtrAdd(ptr, sizeof(vMesh)); + u64 offset = sizeof(vMesh); + + u64 vertex_size = sizeof(Vertex) * asset.model->v_count; + VkBufferCopy mesh_copy = { + .srcOffset = offset, + .dstOffset = 0, + .size = vertex_size, + }; + + MemCpy(ptr, asset.model->vertices, vertex_size); + + ptr = PtrAdd(ptr, vertex_size); + offset += vertex_size; + + u64 index_size = sizeof(u32) * asset.model->i_count; + VkBufferCopy index_copy = { + .srcOffset = offset, + .dstOffset = 0, + .size = index_size, + }; + + offset += sizeof(Vertex) * asset.model->v_count; + MemCpy(ptr, asset.model->indices, index_size); + + vkCmdCopyBuffer(cmd, transfer->alloc.buffer, buffer->mesh.uniform.buffer, 1, &uniform_copy); + vkCmdCopyBuffer(cmd, transfer->alloc.buffer, buffer->mesh.mesh.buffer, 1, &mesh_copy); + vkCmdCopyBuffer(cmd, transfer->alloc.buffer, buffer->index.buffer, 1, &index_copy); + + vAsset *asset_data = buf->assets.data + asset_index; + asset_data->hash = hash; + asset_data->handle.asset_index = asset_index; + asset_data->handle.desc_index = vDescPushMeshDesc(&buffer->mesh); + asset_data->model_meta = asset.model_meta; + asset_data->mesh = buffer; + + apUnloadWithHash(hash); + } + + Assert(vImmSubmitFinish(device, fence, cmd, queue), "Unable to finish immediate submit"); + + return true; +} + static b32 vBuffersInit() { vRBuffers *buf = &v_Renderer.buffers; Arena *arena = v_Renderer.mem.perm_arena; - HashTableInit(&buf->buffers, 8); - HashTableInit(&buf->images, 8); - - buf->tex_destroy_queue.data = MakeArray(arena, b8 *, FRAME_OVERLAP); - buf->tex_destroy_queue.length = FRAME_OVERLAP; - - for (u32 i = 0; i < FRAME_OVERLAP; i++) - { - 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); - MemZero(buf->tex_destroy_queue.data[i], sizeof(b8) * TEXTURE_ASSET_MAX); - } - - b32 success = true; VkResult result; - if (success) - { - result = vBufferCreate(&buf->gui_vert.alloc, rRBT_VERTEX | rRBT_HOST, VERTEX_BUFFER_CAP); - if (result != VK_SUCCESS) - success = false; - } + result = vBufferCreate(&buf->gui_vert.alloc, rRBT_VERTEX | rRBT_HOST, VERTEX_BUFFER_CAP); + if (result != VK_SUCCESS) + success = false; if (success) { @@ -1872,7 +2004,7 @@ vTransferUpload(vTransfer **transfers, u32 count) } else if (transfers[i]->type == vTT_BUFFER || transfers[i]->type == vTT_MESH) { - VkBuffer target_buf; + VkBuffer target_buf = 0; if (transfers[i]->type == vTT_BUFFER) target_buf = transfers[i]->buffer; else if (transfers[i]->type == vTT_MESH) diff --git a/src/renderer_vulkan.h b/src/renderer_vulkan.h index b6a76fa..7c69cd8 100644 --- a/src/renderer_vulkan.h +++ b/src/renderer_vulkan.h @@ -185,7 +185,7 @@ typedef enum DescType_e typedef struct rDescHandle { - u32 asset_id; + u32 asset_index; u32 desc_index; } rDescHandle; @@ -193,11 +193,7 @@ typedef struct vAssetInfo { rDescHandle handle; vDescType type; - union - { - u64 asset_id; - TextureAsset texture_id; - }; + u64 asset_id; } vAssetInfo; typedef struct vDeviceQueues @@ -263,8 +259,8 @@ typedef struct vMeshBuffer typedef struct vMeshAsset { - vMeshBuffer *mesh; - vBuffer *index; + vMeshBuffer mesh; + vBuffer index; } vMeshAsset; typedef enum vAssetType_e @@ -276,14 +272,18 @@ typedef enum vAssetType_e typedef struct vAsset { - u64 hash; - rDescHandle handle; + union + { + TexMeta texture_meta; + ModelMeta model_meta; + }; union { vMeshAsset *mesh; vImageView *texture; }; - AssetMeta meta; + u64 hash; + rDescHandle handle; } vAsset; ArrayType(vAsset); @@ -310,6 +310,8 @@ typedef struct vRendererState rPipelineHandle pipeline; u32 width; u32 height; + u32 curr_vert_buf; + u32 curr_index_buf; } vRendererState; typedef struct vState @@ -332,7 +334,6 @@ typedef struct vFrameHandles { VkCommandPool pool; VkCommandBuffer buffer; - VkSemaphore sc_sem; VkSemaphore r_sem; VkFence r_fence; } vFrameHandles; @@ -361,6 +362,7 @@ typedef struct vRHandles VkQueue gfx_queue; VkQueue tfer_queue; VkSampler nearest_sampler; + VkSemaphore *sc_sems; #ifdef BUILD_DEBUG VkDebugUtilsMessengerEXT debug; #endif @@ -529,6 +531,7 @@ static b32 vShaderModuleInit(u8 *bytes, u32 len, VkShaderModule *module); static void vUploadQueuesInit(); static void vLoaderStartThreads(); static b32 vBuffersInit(); +static b32 vAssetsInit(); static b32 vRenderDocInit(); // ::Vulkan::Util::Functions::Header:: @@ -541,9 +544,6 @@ static inline VkSemaphore vFrameRenderSem(); static inline VkSemaphore vFrameSwapSem(); static inline u32 vFrameIndex(); static inline VkImage vFrameSwapImage(); -static inline b8 *vFrameTexDestroyQueue(); -static inline b8 *vFrameNextTexDestroyQueue(); -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); @@ -578,7 +578,6 @@ static void vSwapchainResize(); 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(); // ::Vulkan::Descriptors::Functions::Header:: @@ -592,10 +591,13 @@ static rDescHandle vDescHandlePop(vDescType type, u32 asset_id); static u32 vDescPushImageDesc(vImageView *view); static u32 vDescPushMeshDesc(vMeshBuffer *buffer); +// ::Vulkan::Assets::Functions::Header:: + +static vAsset *vAssetSearch(c8 *asset_name); +static vAsset *vAssetLookupIndex(u32 asset_idx); + // ::Vulkan::Buffers::Functions::Header:: -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); diff --git a/src/renderer_vulkan_public.c b/src/renderer_vulkan_public.c index 1029b76..98a0fb3 100644 --- a/src/renderer_vulkan_public.c +++ b/src/renderer_vulkan_public.c @@ -26,6 +26,7 @@ rInit() Assert(vDescriptorsInit(), "Unable to initialize descriptors."); Assert(vPipelinesInit(), "Unable to initialize pipelines."); Assert(vBuffersInit(), "Unable to initialize buffers."); + Assert(vAssetsInit(), "Unable to initialize assets."); vUploadQueuesInit(); vLoaderStartThreads(); @@ -40,7 +41,6 @@ rDestroy() { VkDevice device = v_Renderer.handles.device; VkInstance instance = v_Renderer.handles.inst; - 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; @@ -78,13 +78,9 @@ rDestroy() vFrameHandles fh = v_Renderer.frame_handles[i]; vkDestroySemaphore(device, fh.r_sem, NULL); - vkDestroySemaphore(device, fh.sc_sem, NULL); vkDestroyFence(device, fh.r_fence, NULL); vkFreeCommandBuffers(device, fh.pool, 1, &fh.buffer); vkDestroyCommandPool(device, fh.pool, NULL); - - for (u32 j = 0; j < frame_buffers[i].length; j++) - vmaDestroyBuffer(vma_alloc, frame_buffers[i].data[j]->buffer, frame_buffers[i].data[j]->alloc); } vmaUnmapMemory(vma_alloc, v_Renderer.buffers.transfer.alloc.alloc); @@ -121,95 +117,6 @@ rDestroy() // ::Vulkan::Renderer::Buffers::Functions::Start:: -static rDescHandle -rTextureLoad(TextureAsset asset_id) -{ - rDescHandle handle = vDescHandleSearch(vDT_SAMPLED_IMAGE, asset_id); - - if (handle.asset_id == UINT32_MAX) - { - vImageView *view = FLMemAlloc(sizeof(vImageView)); - - Asset asset = apLoadTexture(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 = vDescPushImageDesc(view); - - vTransfer *transfer = vTextureTransferInit(vFrameArena(), asset_id, view->image.image, asset.bytes, &meta); - - TicketMutLock(&v_Renderer.upload.mut); - - u32 job_idx = JobQueueAdd(&v_Renderer.upload.job_queue, 1); - v_Renderer.upload.transfers[job_idx] = transfer; - vDescPushImageAndHandle(handle, view); - - TicketMutUnlock(&v_Renderer.upload.mut); - - vLoaderWake(); - } - - 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); - - if (handle.asset_id != UINT32_MAX) - { - b8 *queue = vFrameTexDestroyQueue(); - - queue[current_handle.asset_id] = true; - } -} - static void rBufferBindVertex(rRenderBuffer *buffer) { @@ -275,10 +182,15 @@ rBufferBindGUIIndex() static void rBufferBindMesh(rPushConst *pc, rDescHandle handle) { - vModelBuffers *buffers = vModelSearch(handle.asset_id); - if (buffers != NULL) + if (v_Renderer.state.renderer.curr_vert_buf != handle.asset_index) { - vkCmdBindIndexBuffer(vFrameCmdBuf(), buffers->index->buffer, 0, VK_INDEX_TYPE_UINT32); + vAsset *asset = vAssetLookupIndex(handle.asset_index); + if (asset != NULL) + { + vkCmdBindIndexBuffer(vFrameCmdBuf(), asset->mesh->index.buffer, 0, VK_INDEX_TYPE_UINT32); + pc->mesh_index = asset->handle.desc_index; + v_Renderer.state.renderer.curr_vert_buf = handle.asset_index; + } } } @@ -358,7 +270,7 @@ rFrameBegin() result = vkWaitForFences(device, 1, &fence, VK_TRUE, 1000000000); if (result != VK_SUCCESS) { - Printf("vkWaitForFences failure: %s", vVkResultStr(result)); + Printfln("vkWaitForFences failure: %s", vVkResultStr(result)); success = false; } @@ -528,6 +440,22 @@ rDrawIndexed(u32 index_count, u32 instance_count) vkCmdDrawIndexed(cmd, index_count, instance_count, 0, 0, 0); } +static void +rDrawMesh(rDescHandle handle) +{ + VkCommandBuffer cmd = vFrameCmdBuf(); + + if (v_Renderer.state.renderer.curr_index_buf != handle.asset_index) + { + vAsset *asset = vAssetLookupIndex(handle.asset_index); + if (asset != NULL) + { + vkCmdDrawIndexed(cmd, asset->model_meta.i_count, 1, 0, 0, 0); + v_Renderer.state.renderer.curr_index_buf = handle.asset_index; + } + } +} + static void rPipelineBind(rPipelineHandle handle, rPipelineType type) { @@ -554,3 +482,24 @@ rPipelineBind(rPipelineHandle handle, rPipelineType type) } // ::Vulkan::Renderer::Rendering::Functions::End:: + + + +// ::Vulkan::Renderer::Assets::Start:: + +static rDescHandle +rGetAsset(c8 *asset_name) +{ + rDescHandle handle = {UINT32_MAX}; + vAsset *asset = vAssetSearch(asset_name); + if (asset != NULL) + { + handle = asset->handle; + } + + Assert(handle.asset_index != UINT32_MAX, "invalid descriptor handle"); + + return handle; +} + +// ::Vulkan::Renderer::Assets::End:: diff --git a/src/stglib.h b/src/stglib.h index ac3d517..d71a4b5 100644 --- a/src/stglib.h +++ b/src/stglib.h @@ -381,6 +381,7 @@ typedef enum KeyboardInput_e # include # include # include +# include // ::Platform::Linux::Defines::Header:: @@ -741,7 +742,6 @@ typedef struct T##Array \ { \ T *data; \ u64 length; \ - u64 cap; \ } T##Array #define PtrArrayType(T) \ @@ -749,13 +749,11 @@ typedef struct T##PtrArray \ { \ T **data; \ u64 length; \ - u64 cap; \ } T##PtrArray #define InitArrayType(arr, arena, T, len) \ arr.data = MakeArray(arena, T, len); \ -arr.length = 0; \ -arr.cap = len +arr.length = len // ::Util::LinkedList::Macros:: @@ -1298,27 +1296,39 @@ static void HashTableDeleteU64(HashTable *table, u64 key); if (BitEq(acc, pFS_CREATE)) flags |= O_CREAT; - return open(file_name, flags, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); + i64 file = open(file_name, flags, S_IRUSR|S_IWUSR|S_IRGRP); + if (file < 0) + { + Printfln("errno: %d", errno); + Assert(false, "failed to open file"); + } + + return file; } static void pFileClose(pFile file) { + fsync(file); close(file); } - // TODO: make these more resilient static u64 pFileRead(pFile file, u64 offset, void * buf, u64 len) { - lseek(file, (ssize_t)offset, SEEK_SET); + i64 new_offset = lseek(file, offset, SEEK_SET); + if (new_offset < 0) + { + Printfln("errno: %d", errno); + Assert(false, "failed to read file"); + } return read(file, buf, (size_t)len); } static u64 pFileWrite(pFile file, u64 offset, void * buf, u64 len) { - lseek(file, (ssize_t)offset, SEEK_SET); + lseek(file, offset, SEEK_SET); return write(file, buf, (size_t)len); } diff --git a/src/vulkan_config.c b/src/vulkan_config.c index a935606..f3d89b6 100644 --- a/src/vulkan_config.c +++ b/src/vulkan_config.c @@ -154,7 +154,7 @@ g_Fence_Create_Info = }; static VkSemaphoreCreateInfo -g_Semaphore_Create_info = +g_Semaphore_Create_Info = { .sType = STYPE(SEMAPHORE_CREATE_INFO), }; @@ -259,10 +259,11 @@ g_Depth_View_Info = static VkDescriptorPoolSize g_Desc_Pool_Sizes[] = { - { .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .descriptorCount = 4096 }, + { .type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, .descriptorCount = 4096 }, { .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, .descriptorCount = 4096}, { .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, .descriptorCount = 4096}, { .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, .descriptorCount = 4096}, + { .type = VK_DESCRIPTOR_TYPE_SAMPLER, .descriptorCount = 4096 }, }; static VkDescriptorPoolCreateInfo