diff options
| author | Jonathan Bradley <jcb@pikum.xyz> | 2025-01-23 21:57:31 -0500 |
|---|---|---|
| committer | Jonathan Bradley <jcb@pikum.xyz> | 2025-01-23 21:57:31 -0500 |
| commit | e93eb289ca44e98967482ab80fd5329f85ccd03e (patch) | |
| tree | 4164b6d5b9ac2e40d18ec3eea52730c9f9606ccb /src | |
| parent | 846a6e1185417ee3e187edc06ef327d180bf0d9b (diff) | |
pke: first-pass 2d overlay render pass scaffolding
Diffstat (limited to 'src')
| -rw-r--r-- | src/asset-manager.cpp | 4 | ||||
| -rw-r--r-- | src/asset-manager.hpp | 2 | ||||
| -rw-r--r-- | src/components.hpp | 5 | ||||
| -rw-r--r-- | src/ecs.cpp | 2 | ||||
| -rw-r--r-- | src/entities.cpp | 72 | ||||
| -rw-r--r-- | src/font.cpp | 638 | ||||
| -rw-r--r-- | src/font.hpp | 74 | ||||
| -rw-r--r-- | src/static-plane.cpp | 21 | ||||
| -rw-r--r-- | src/static-plane.hpp | 15 | ||||
| -rw-r--r-- | src/window.cpp | 97 | ||||
| -rw-r--r-- | src/window.hpp | 24 |
11 files changed, 868 insertions, 86 deletions
diff --git a/src/asset-manager.cpp b/src/asset-manager.cpp index b280361..d12d860 100644 --- a/src/asset-manager.cpp +++ b/src/asset-manager.cpp @@ -20,6 +20,8 @@ AssetKey EngineDefinedAssets[EngineDefinedAssetCount] = { "pke_prsnt_frg\0\0", "pke_txtr_vrt\0\0\0", "pke_txtr_frg\0\0\0", + "pke_glyph_vrt\0\0", + "pke_glyph_frg\0\0", }; void AM_Init() { @@ -29,6 +31,8 @@ void AM_Init() { AM_Register(EngineDefinedAssets[1], PKE_ASSET_TYPE_SHADER, "assets/shaders/present.frag.spv"); AM_Register(EngineDefinedAssets[2], PKE_ASSET_TYPE_SHADER, "assets/shaders/vertex.vert.spv"); AM_Register(EngineDefinedAssets[3], PKE_ASSET_TYPE_SHADER, "assets/shaders/texture.frag.spv"); + AM_Register(EngineDefinedAssets[4], PKE_ASSET_TYPE_SHADER, "assets/shaders/glyph.vert.spv"); + AM_Register(EngineDefinedAssets[5], PKE_ASSET_TYPE_SHADER, "assets/shaders/glyph.frag.spv"); } void AM_Load_Task(Asset &asset) { diff --git a/src/asset-manager.hpp b/src/asset-manager.hpp index 0a7cd5c..fb922e9 100644 --- a/src/asset-manager.hpp +++ b/src/asset-manager.hpp @@ -29,7 +29,7 @@ const AssetType PKE_ASSET_TYPE_AUDIO = AssetType {0x08}; const AssetType PKE_ASSET_TYPE_FONT = AssetType {0x10}; const AssetType PKE_ASSET_TYPE_ALL = AssetType {0xFF}; -constexpr int64_t EngineDefinedAssetCount = 4; +constexpr int64_t EngineDefinedAssetCount = 6; extern AssetKey EngineDefinedAssets[EngineDefinedAssetCount]; struct Asset { diff --git a/src/components.hpp b/src/components.hpp index eb891a4..cf86099 100644 --- a/src/components.hpp +++ b/src/components.hpp @@ -42,17 +42,14 @@ struct CompGrBinds { BufferBindingDetails normalsBD; BufferBindingDetails uvBD; BufferBindingDetails indexBD; + BufferBindingDetails instanceBD; BufferBindingDetails physVertBD; BufferBindingDetails physNormBD; BufferBindingDetails physUvBD; BufferBindingDetails physIndxBD; - VkBuffer instanceBuffer = VK_NULL_HANDLE; uint32_t indexCount; - uint32_t instanceFirstBinding = 0; - uint32_t instanceBindingCount = 0; uint32_t instanceCounter = 0; uint32_t instanceBufferMaxCount = 0; - VkDeviceSize instanceOffsets = 0; PkeCallback collisionCallback{}; }; diff --git a/src/ecs.cpp b/src/ecs.cpp index 09eb725..c5f221a 100644 --- a/src/ecs.cpp +++ b/src/ecs.cpp @@ -336,7 +336,7 @@ void ECS_Tick_Late(double delta) { vkBeginCommandBuffer(transferCommandBuffer, &cbbi); for (long i = 0; i < ibc.chunks->Count(); ++i) { - vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, ibc.grBinds->instanceBuffer, 1, &(*ibc.chunks)[i].dstBufferCopy); + vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, ibc.grBinds->instanceBD.buffer, 1, &(*ibc.chunks)[i].dstBufferCopy); } vkEndCommandBuffer(transferCommandBuffer); diff --git a/src/entities.cpp b/src/entities.cpp index 179ce4b..123c095 100644 --- a/src/entities.cpp +++ b/src/entities.cpp @@ -133,40 +133,6 @@ EntityType *EntityType_FindByEntityHandle(EntityHandle handle) { return nullptr; } -void CalculateCombinedMemReqs(uint64_t memReqsCount, VkMemoryRequirements *memReqs, VkMemoryRequirements &combinedMemReqs) { - combinedMemReqs.size = 0; - combinedMemReqs.alignment = memReqs[0].alignment; - combinedMemReqs.memoryTypeBits = memReqs[0].memoryTypeBits; - for (uint64_t i = 1; i < memReqsCount; ++i) { - combinedMemReqs.memoryTypeBits |= memReqs[i].memoryTypeBits; - if (combinedMemReqs.alignment == memReqs[i].alignment) { - continue; - } - VkDeviceSize larger, smaller; - if (combinedMemReqs.alignment > memReqs[i].alignment) { - larger = combinedMemReqs.alignment; - smaller = memReqs[i].alignment; - } else { - larger = memReqs[i].alignment; - smaller = combinedMemReqs.alignment; - } - if (larger % smaller == 0) { - combinedMemReqs.alignment = larger; - continue; - } - int combined = larger * smaller; - while ((combined / 2) % 2 == 0 && (combined / 2) % larger == 0) { - combined /= 2; - } - combinedMemReqs.alignment = combined; - } - for (uint64_t i = 0; i < memReqsCount; ++i) { - uint32_t alignmentPadding = memReqs[i].size % combinedMemReqs.alignment; - memReqs[i].size += (alignmentPadding == 0 ? 0 : combinedMemReqs.alignment - alignmentPadding); - combinedMemReqs.size += memReqs[i].size; - } -} - struct EntityTypeDetails_LoadHelperStruct { EntityTypeDetails *etd = nullptr; AssetHandle textureAssetHandle = AssetHandle_MAX; @@ -644,7 +610,7 @@ void EntityType_LoadTexture(EntityType_LoadHelperStruct &helper, const int64_t i VkDescriptorSetLayout descriptorSets[MAX_FRAMES_IN_FLIGHT]; for (long i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) { - descriptorSets[i] = pkePipelines.vkDescriptorSetLayout_Texture; + descriptorSets[i] = pkePipelines.descr_layouts.named.texture; } VkDescriptorSetAllocateInfo vkDescriptorSetAllocateInfo; vkDescriptorSetAllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; @@ -773,8 +739,8 @@ void EntityType_LoadMesh(EntityType_LoadHelperStruct &helper, const int64_t mesh // 2023-09-27 - JCB // I don't know where else to put this - etdHelper.etd->grBinds->instanceFirstBinding = index; - etdHelper.etd->grBinds->instanceBindingCount = 1; + etdHelper.etd->grBinds->instanceBD.firstBinding = index; + etdHelper.etd->grBinds->instanceBD.bindingCount = 1; // no index += 1 because index just happens to be the right value here for // the binding index, whereas binding the IndexBuffer doesn't need a binding index. @@ -878,8 +844,8 @@ void EntityType_LoadMesh(EntityType_LoadHelperStruct &helper, const int64_t mesh etdHelper.etd->grBinds->instanceBufferMaxCount = etdHelper.etd->grBinds->instanceBufferMaxCount < 1 ? 1 : etdHelper.etd->grBinds->instanceBufferMaxCount; bufferCI.size = sizeof(glm::mat4) * etdHelper.etd->grBinds->instanceBufferMaxCount; bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; - vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &etdHelper.etd->grBinds->instanceBuffer); - vkBindBufferMemory(vkDevice, etdHelper.etd->grBinds->instanceBuffer, helper.et.deviceMemoryInst, 0); + vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &etdHelper.etd->grBinds->instanceBD.buffer); + vkBindBufferMemory(vkDevice, etdHelper.etd->grBinds->instanceBD.buffer, helper.et.deviceMemoryInst, 0); // bullet @@ -1094,8 +1060,8 @@ void EntityType_Load(EntityType &et) { * I don't like that we're just copying this. * This should be moved to window.cpp. */ - etdHelper.etd->grBinds->vkPipelineLayout = pkePipelines.vkPipelineLayout_Texture; - etdHelper.etd->grBinds->graphicsPipeline = pkePipelines.pipelines.named.Texture; + etdHelper.etd->grBinds->vkPipelineLayout = pkePipelines.pipe_layouts.named.texture; + etdHelper.etd->grBinds->graphicsPipeline = pkePipelines.pipelines.named.texture; // handle texture EntityType_LoadTexture(helper, i); @@ -1185,14 +1151,14 @@ void EntityType_Unload(EntityType &et, CompGrBinds *grBindsArr[1]) { grBinds->physIndxBD.bindingCount = 0; grBinds->physIndxBD.offsets[0] = 0; - if (grBinds->instanceBuffer != VK_NULL_HANDLE) - vkDestroyBuffer(vkDevice, grBinds->instanceBuffer, vkAllocator); - grBinds->instanceBuffer = VK_NULL_HANDLE; - grBinds->instanceFirstBinding = 0; - grBinds->instanceBindingCount = 0; + if (grBinds->instanceBD.buffer != VK_NULL_HANDLE) + vkDestroyBuffer(vkDevice, grBinds->instanceBD.buffer, vkAllocator); + grBinds->instanceBD.buffer = VK_NULL_HANDLE; + grBinds->instanceBD.firstBinding = 0; + grBinds->instanceBD.bindingCount = 0; grBinds->instanceCounter = 0; grBinds->instanceBufferMaxCount = 0; - grBinds->instanceOffsets = 0; + grBinds->instanceBD.offsets[0] = 0; } if (etd.textureImageView != VK_NULL_HANDLE) @@ -1277,7 +1243,7 @@ void EntityType_RolloverInstances(EntityType &et, CompGrBinds &grBinds) { uint32_t oldSize = sizeof(glm::mat4) * oldCount; VkDeviceMemory oldMemory(et.deviceMemoryInst); - VkBuffer oldBuffer(grBinds.instanceBuffer); + VkBuffer oldBuffer(grBinds.instanceBD.buffer); VkBufferCreateInfo vkBufferCreateInfo{}; vkBufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; @@ -1288,10 +1254,10 @@ void EntityType_RolloverInstances(EntityType &et, CompGrBinds &grBinds) { vkBufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; vkBufferCreateInfo.queueFamilyIndexCount = 1; vkBufferCreateInfo.pQueueFamilyIndices = &graphicsFamilyIndex; - vkCreateBuffer(vkDevice, &vkBufferCreateInfo, vkAllocator, &grBinds.instanceBuffer); + vkCreateBuffer(vkDevice, &vkBufferCreateInfo, vkAllocator, &grBinds.instanceBD.buffer); VkMemoryRequirements vkMemoryRequirementsInst; - vkGetBufferMemoryRequirements(vkDevice, grBinds.instanceBuffer, &vkMemoryRequirementsInst); + vkGetBufferMemoryRequirements(vkDevice, grBinds.instanceBD.buffer, &vkMemoryRequirementsInst); VkMemoryAllocateInfo vkMemoryAllocateInfo; vkMemoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; @@ -1300,7 +1266,7 @@ void EntityType_RolloverInstances(EntityType &et, CompGrBinds &grBinds) { vkMemoryAllocateInfo.memoryTypeIndex = FindMemoryTypeIndex(vkMemoryRequirementsInst.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); vkAllocateMemory(vkDevice, &vkMemoryAllocateInfo, vkAllocator, &et.deviceMemoryInst); - vkBindBufferMemory(vkDevice, grBinds.instanceBuffer, et.deviceMemoryInst, 0); + vkBindBufferMemory(vkDevice, grBinds.instanceBD.buffer, et.deviceMemoryInst, 0); // copy data { @@ -1323,7 +1289,7 @@ void EntityType_RolloverInstances(EntityType &et, CompGrBinds &grBinds) { memBarriers[1].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; memBarriers[1].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; memBarriers[1].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - memBarriers[1].buffer = grBinds.instanceBuffer; + memBarriers[1].buffer = grBinds.instanceBD.buffer; memBarriers[1].offset = 0; memBarriers[1].size = vkMemoryRequirementsInst.size; @@ -1341,7 +1307,7 @@ void EntityType_RolloverInstances(EntityType &et, CompGrBinds &grBinds) { vkBufferCopy.srcOffset = 0; vkBufferCopy.dstOffset = 0; vkBufferCopy.size = oldSize; - vkCmdCopyBuffer(graphicsCommandBuffer, oldBuffer, grBinds.instanceBuffer, 1, &vkBufferCopy); + vkCmdCopyBuffer(graphicsCommandBuffer, oldBuffer, grBinds.instanceBD.buffer, 1, &vkBufferCopy); vkEndCommandBuffer(graphicsCommandBuffer); diff --git a/src/font.cpp b/src/font.cpp new file mode 100644 index 0000000..d218430 --- /dev/null +++ b/src/font.cpp @@ -0,0 +1,638 @@ + +#include "font.hpp" +#include "asset-manager.hpp" +#include "pk.h" +#include "window.hpp" +#include "static-plane.hpp" +#include "vendor-stb-image-include.h" +// #include "bucketed-array.hpp" + +// TODO threading + +TypeSafeInt_B(FontTypeIndex); +TypeSafeInt_B(FontRenderIndex); + +struct FontTypeData { + FontType *arr_ft; + FontTypeIndex n_ft{0}; + FontTypeIndex h_ft{0}; +} ftd; + +// BucketContainer<FontType, TextRenderHandle, 2> bktFont; + +void FontType_Init() { + ftd.h_ft = FontTypeIndex{5}; + ftd.arr_ft = pk_new<FontType>(5); +} + +void FontType_Teardown() { + FontTypeIndex i; + FontType *ft; + for (i = FontTypeIndex{0}; i < ftd.h_ft; ++i) { + FontType_Unload(i); + ft = &ftd.arr_ft[(FontTypeIndex_T)i]; + pk_delete<FontRender>(ft->renders, (FontTypeIndex_T)ft->n_render); + } + pk_delete(ftd.arr_ft, (FontTypeIndex_T)ftd.n_ft); +} + +FontType* FontType_GetFonts(FontTypeIndex &count) +{ + count = ftd.h_ft; + return ftd.arr_ft; +} + +FontTypeIndex FontType_RegisterFont(pk_cstr title, AssetHandle fontTextureHandle, AssetHandle glyphsHandle) { + VkResult vkResult; + pk_arr arr_vert_mem_reqs; + memset(&arr_vert_mem_reqs, 0, sizeof(pk_arr)); + arr_vert_mem_reqs.alignment = alignof(VkMemoryRequirements); + arr_vert_mem_reqs.stride = sizeof(VkMemoryRequirements); + pk_arr arr_inst_mem_reqs(arr_vert_mem_reqs); + pk_arr arr_texture_mem_reqs(arr_vert_mem_reqs); + VkDeviceSize index; + constexpr VkDeviceSize expectedBufferCount = 3; + constexpr VkDeviceSize startingGlyphCount = 4; + + VkMemoryRequirements combined_vert_mem_reqs; + VkMemoryRequirements combined_inst_mem_reqs; + VkMemoryRequirements combined_texture_mem_reqs; + + const Asset *fontTexture = AM_Get(fontTextureHandle); + const Asset *glyphs = AM_Get(glyphsHandle); + if (ftd.h_ft > ftd.n_ft) { + index = (VkDeviceSize)ftd.n_ft; + ftd.n_ft += FontTypeIndex{5}; + FontType *arr = pk_new<FontType>((FontTypeIndex_T)ftd.n_ft); + memcpy(arr, ftd.arr_ft, sizeof(FontType) * index); + pk_delete<FontType>(ftd.arr_ft, index); + ftd.arr_ft = arr; + } + + FontTypeIndex idx = ftd.h_ft++; + FontTypeIndex_T idx_t = (FontTypeIndex_T)idx; + FontType *ft = &ftd.arr_ft[idx_t]; + ft->title = title; + ft->fontTextureAssetKey = fontTextureHandle; + ft->glyphDetailsAssetKey = glyphsHandle; + ft->renders = pk_new<FontRender>(startingGlyphCount); + ft->n_render = FontRenderIndex{startingGlyphCount}; + + int txtr_x, txtr_y, txtr_chan; + stbi_uc *txtr_bytes = stbi_load_from_memory((unsigned char*)fontTexture->ptr, fontTexture->size, &txtr_x, &txtr_y, &txtr_chan, 4); + assert(txtr_chan == 4); + + /* + * vulkan setup + */ + VkBuffer buffer; + VkBufferCreateInfo bufferCI; + bufferCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferCI.pNext = nullptr; + bufferCI.flags = {}; + bufferCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + bufferCI.queueFamilyIndexCount = 1; + bufferCI.pQueueFamilyIndices = &graphicsFamilyIndex; + + /* + * Vulkan resource setup + */ + // vertex + { + for (uint64_t index = 0; index < expectedBufferCount; ++index) { + if (index == 0) { + bufferCI.size = sizeof(glm::vec2) * 4; + } else if (index == 1) { + bufferCI.size = sizeof(glm::vec2) * 4; + } else if (index == 2) { + bufferCI.size = sizeof(uint16_t) * 6; + } + if (index == 2) { + bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT; + } else { + bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + } + vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &buffer); + VkMemoryRequirements tmp; + vkGetBufferMemoryRequirements(vkDevice, buffer, &tmp); + pk_arr_append(&arr_vert_mem_reqs, &tmp); + vkDestroyBuffer(vkDevice, buffer, vkAllocator); + } + } + // instance + { + bufferCI.size = 0; + bufferCI.size += sizeof(glm::vec4); // fgColor + bufferCI.size += sizeof(glm::vec4); // bgColor + bufferCI.size += sizeof(glm::vec4); // sprite_region + bufferCI.size += sizeof(float); // width + bufferCI.size *= startingGlyphCount; + bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &buffer); + VkMemoryRequirements tmp; + vkGetBufferMemoryRequirements(vkDevice, buffer, &tmp); + pk_arr_append(&arr_inst_mem_reqs, &tmp); + vkDestroyBuffer(vkDevice, buffer, vkAllocator); + } + // texture + VkImageCreateInfo imageCreateInfo{}; + VkImageSubresourceRange vkImageSubresourceRange; + { + imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageCreateInfo.pNext = nullptr; + imageCreateInfo.flags = 0; + imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; + imageCreateInfo.format = VK_FORMAT_R8G8B8A8_SRGB; + imageCreateInfo.extent.width = txtr_x; + imageCreateInfo.extent.height = txtr_y; + imageCreateInfo.extent.depth = 1; + imageCreateInfo.mipLevels = 1; + imageCreateInfo.arrayLayers = 1; + imageCreateInfo.samples = renderSampleCount; + imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + imageCreateInfo.queueFamilyIndexCount = 0; + imageCreateInfo.pQueueFamilyIndices = nullptr; + imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + + vkImageSubresourceRange.aspectMask = VkImageAspectFlagBits::VK_IMAGE_ASPECT_COLOR_BIT; + vkImageSubresourceRange.baseMipLevel = 0u; + vkImageSubresourceRange.levelCount = 1u; + vkImageSubresourceRange.baseArrayLayer = 0u; + vkImageSubresourceRange.layerCount = 1u; + + VkImageViewCreateInfo vkImageViewCreateInfo; + vkImageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + vkImageViewCreateInfo.pNext = nullptr; + vkImageViewCreateInfo.flags = 0; + vkImageViewCreateInfo.image = ft->textureImage; + vkImageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + vkImageViewCreateInfo.format = imageCreateInfo.format; + vkImageViewCreateInfo.components = VkComponentMapping { + .r = VK_COMPONENT_SWIZZLE_IDENTITY, + .g = VK_COMPONENT_SWIZZLE_IDENTITY, + .b = VK_COMPONENT_SWIZZLE_IDENTITY, + .a = VK_COMPONENT_SWIZZLE_IDENTITY, + }; + vkImageViewCreateInfo.subresourceRange = vkImageSubresourceRange; + + VkImage tmpImage; + vkResult = vkCreateImage(vkDevice, &imageCreateInfo, vkAllocator, &tmpImage); + assert(vkResult == VK_SUCCESS); + + VkMemoryRequirements imageMemoryRequirements; + vkGetImageMemoryRequirements(vkDevice, tmpImage, &imageMemoryRequirements); + + VkDeviceSize paddedImageSize = imageMemoryRequirements.size + (imageMemoryRequirements.alignment - (imageMemoryRequirements.size % imageMemoryRequirements.alignment)); + assert(paddedImageSize % imageMemoryRequirements.alignment == 0); + + vkDestroyImage(vkDevice, tmpImage, vkAllocator); + + VkMemoryAllocateInfo vkMemoryAllocateInfo{}; + vkMemoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + vkMemoryAllocateInfo.pNext = nullptr; + vkMemoryAllocateInfo.allocationSize = paddedImageSize * MAX_FRAMES_IN_FLIGHT; + vkMemoryAllocateInfo.memoryTypeIndex = FindMemoryTypeIndex(imageMemoryRequirements.memoryTypeBits, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + + vkResult = vkAllocateMemory(vkDevice, &vkMemoryAllocateInfo, vkAllocator, &ft->deviceMemoryTexture); + assert(vkResult == VK_SUCCESS); + + vkResult = vkCreateImage(vkDevice, &imageCreateInfo, vkAllocator, &ft->textureImage); + assert(vkResult == VK_SUCCESS); + vkResult = vkBindImageMemory(vkDevice, ft->textureImage, ft->deviceMemoryTexture, 0); + assert(vkResult == VK_SUCCESS); + + vkImageViewCreateInfo.image = ft->textureImage; + vkResult = vkCreateImageView(vkDevice, &vkImageViewCreateInfo, vkAllocator, &ft->textureImageView); + assert(vkResult == VK_SUCCESS); + } + + /* + * Vulkan memory allocation + */ + + VkMemoryAllocateInfo vkMemoryAllocateInfo; + vkMemoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + vkMemoryAllocateInfo.pNext = nullptr; + + // verts + CalculateCombinedMemReqs(arr_vert_mem_reqs.next, (VkMemoryRequirements*)arr_vert_mem_reqs.data, combined_vert_mem_reqs); + vkMemoryAllocateInfo.allocationSize = combined_vert_mem_reqs.size; + vkMemoryAllocateInfo.memoryTypeIndex = FindMemoryTypeIndex(combined_vert_mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + vkAllocateMemory(vkDevice, &vkMemoryAllocateInfo, vkAllocator, &ft->deviceMemoryVert); + + // inst + CalculateCombinedMemReqs(arr_inst_mem_reqs.next, (VkMemoryRequirements*)arr_inst_mem_reqs.data, combined_inst_mem_reqs); + vkMemoryAllocateInfo.allocationSize = combined_inst_mem_reqs.size; + vkMemoryAllocateInfo.memoryTypeIndex = FindMemoryTypeIndex(combined_inst_mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + vkAllocateMemory(vkDevice, &vkMemoryAllocateInfo, vkAllocator, &ft->deviceMemoryInst); + + // texture + CalculateCombinedMemReqs(arr_texture_mem_reqs.next, (VkMemoryRequirements*)arr_texture_mem_reqs.data, combined_texture_mem_reqs); + vkMemoryAllocateInfo.allocationSize = combined_texture_mem_reqs.size; + vkMemoryAllocateInfo.memoryTypeIndex = FindMemoryTypeIndex(combined_texture_mem_reqs.memoryTypeBits, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); + if (vkMemoryAllocateInfo.memoryTypeIndex == 0) { + vkMemoryAllocateInfo.memoryTypeIndex = FindMemoryTypeIndex(combined_texture_mem_reqs.memoryTypeBits, 0); + } + vkAllocateMemory(vkDevice, &vkMemoryAllocateInfo, vkAllocator, &ft->deviceMemoryTexture); + + /* + * Vulkan data transfer + */ + VkBuffer transferBuffer; + VkDeviceMemory transferMemory; + void *deviceData; + VkDeviceSize runningOffset, alignmentPadding; + // vert + BeginTransferBuffer(combined_vert_mem_reqs.size, transferBuffer, transferMemory, deviceData); + { + index = 0; + runningOffset = 0; + + uint32_t offsetVert = runningOffset; + uint32_t sizeVert = sizeof(pkeIntrinsicsPlane.vert[0]) * 4; + ft->bindings.vertexBD.firstBinding = index; + ft->bindings.vertexBD.bindingCount = 1; + alignmentPadding = sizeVert % combined_vert_mem_reqs.alignment; + alignmentPadding = alignmentPadding == 0 ? 0 : combined_vert_mem_reqs.alignment - alignmentPadding; + sizeVert += alignmentPadding; + bufferCI.size = sizeVert; + bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &ft->bindings.vertexBD.buffer); + vkBindBufferMemory(vkDevice, ft->bindings.vertexBD.buffer, ft->deviceMemoryVert, offsetVert); + runningOffset += sizeVert; + index += 1; + + // uv + uint32_t offsetUV = runningOffset; + uint32_t sizeUV = sizeof(pkeIntrinsicsPlane.uv[0]) * 4; + ft->bindings.uvBD.firstBinding = index; + ft->bindings.uvBD.bindingCount = 1; + alignmentPadding = sizeUV % combined_vert_mem_reqs.alignment; + alignmentPadding = alignmentPadding == 0 ? 0 : combined_vert_mem_reqs.alignment - alignmentPadding; + sizeUV += alignmentPadding; + bufferCI.size = sizeUV; + vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &ft->bindings.uvBD.buffer); + vkBindBufferMemory(vkDevice, ft->bindings.uvBD.buffer, ft->deviceMemoryVert, offsetUV); + runningOffset += sizeUV; + index += 1; + + // 2023-09-27 - JCB + // I don't know where else to put this + ft->bindings.instanceBD.firstBinding = index; + ft->bindings.instanceBD.bindingCount = 1; + // no index += 1 because index just happens to be the right value here for + // the binding index, whereas binding the IndexBuffer doesn't need a binding index. + + // index + uint32_t offsetIndex = runningOffset; + uint32_t sizeIndex = sizeof(pkeIntrinsicsPlane.index[0]) * 6; + ft->bindings.indexBD.bindingCount = 1; + ft->bindings.indexCount = 6; + alignmentPadding = sizeIndex % combined_vert_mem_reqs.alignment; + alignmentPadding = alignmentPadding == 0 ? 0 : combined_vert_mem_reqs.alignment - alignmentPadding; + sizeIndex += alignmentPadding; + bufferCI.size = sizeIndex; + bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT; + vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &ft->bindings.indexBD.buffer); + vkBindBufferMemory(vkDevice, ft->bindings.indexBD.buffer, ft->deviceMemoryVert, offsetIndex); + runningOffset += sizeIndex; + // index += 1; + + assert(runningOffset == combined_vert_mem_reqs.size); + + + runningOffset = 0; + + char *dstPtr = nullptr; + char *srcPtr = nullptr; + + dstPtr = static_cast<char *>(deviceData) + runningOffset; + srcPtr = reinterpret_cast<char *>(pkeIntrinsicsPlane.vert); + memcpy(dstPtr, srcPtr, sizeVert); + runningOffset += sizeVert; + + dstPtr = static_cast<char *>(deviceData) + runningOffset; + srcPtr = reinterpret_cast<char *>(pkeIntrinsicsPlane.uv); + memcpy(dstPtr, srcPtr, sizeUV); + runningOffset += sizeUV; + + dstPtr = static_cast<char *>(deviceData) + runningOffset; + srcPtr = reinterpret_cast<char *>(pkeIntrinsicsPlane.index); + memcpy(dstPtr, srcPtr, sizeIndex); + // runningOffset += sizeIndex; + + VkCommandBufferBeginInfo vkCommandBufferBeginInfo; + vkCommandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + vkCommandBufferBeginInfo.pNext = nullptr; + // TODO consider single-use? + vkCommandBufferBeginInfo.flags = 0; + vkCommandBufferBeginInfo.pInheritanceInfo = nullptr; + vkBeginCommandBuffer(transferCommandBuffer, &vkCommandBufferBeginInfo); + VkBufferCopy bufferCopys[expectedBufferCount]; + for (VkDeviceSize i = 0; i < expectedBufferCount; ++i) { + bufferCopys[i].dstOffset = 0; + } + index = 0; + bufferCopys[index].srcOffset = offsetVert; + bufferCopys[index].size = sizeVert; + vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, ft->bindings.vertexBD.buffer, 1, &bufferCopys[index]); + index+=1; + + bufferCopys[index].srcOffset = offsetUV; + bufferCopys[index].size = sizeUV; + vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, ft->bindings.uvBD.buffer, 1, &bufferCopys[index]); + index+=1; + + bufferCopys[index].srcOffset = offsetIndex; + bufferCopys[index].size = sizeIndex; + vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, ft->bindings.indexBD.buffer, 1, &bufferCopys[index]); + // index+=1; + + vkEndCommandBuffer(transferCommandBuffer); + + VkSubmitInfo submitInfo; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.pNext = nullptr; + submitInfo.waitSemaphoreCount = 0; + submitInfo.pWaitSemaphores = nullptr; + submitInfo.pWaitDstStageMask = nullptr; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &transferCommandBuffer; + submitInfo.signalSemaphoreCount = 0; + submitInfo.pSignalSemaphores = nullptr; + vkQueueSubmit(transferQueue, 1, &submitInfo, nullptr); + vkQueueWaitIdle(transferQueue); + } + EndTransferBuffer(transferBuffer, transferMemory); + // set up instance buffer + { + ft->bindings.instanceBufferMaxCount = startingGlyphCount; + bufferCI.size = combined_inst_mem_reqs.size; + bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &ft->bindings.instanceBD.buffer); + vkBindBufferMemory(vkDevice, ft->bindings.instanceBD.buffer, ft->deviceMemoryInst, 0); + } + // texture // transition image layout and copy to buffer + BeginTransferBuffer(combined_texture_mem_reqs.size, transferBuffer, transferMemory, deviceData); + memcpy(deviceData, txtr_bytes, combined_texture_mem_reqs.size); + { + VkImageMemoryBarrier vkImageMemoryBarrier; + vkImageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + vkImageMemoryBarrier.pNext = nullptr; + vkImageMemoryBarrier.srcAccessMask = {}; + vkImageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + vkImageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + vkImageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + vkImageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + vkImageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + vkImageMemoryBarrier.image = ft->textureImage; + vkImageMemoryBarrier.subresourceRange = VkImageSubresourceRange { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + // TODO MipMap + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }; + + VkCommandBufferBeginInfo vkCommandBufferBeginInfo; + vkCommandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + vkCommandBufferBeginInfo.pNext = nullptr; + vkCommandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + vkCommandBufferBeginInfo.pInheritanceInfo = nullptr; + + vkBeginCommandBuffer(transferCommandBuffer, &vkCommandBufferBeginInfo); + + vkCmdPipelineBarrier(transferCommandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &vkImageMemoryBarrier); + + VkBufferImageCopy vkBufferImageCopy; + vkBufferImageCopy.bufferOffset = 0; + vkBufferImageCopy.bufferRowLength = txtr_x; + vkBufferImageCopy.bufferImageHeight = txtr_y; + vkBufferImageCopy.imageSubresource = VkImageSubresourceLayers { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .mipLevel = 0, + .baseArrayLayer = 0, + .layerCount = 1, + }; + vkBufferImageCopy.imageOffset = VkOffset3D { + .x = 0, + .y = 0, + .z = 0, + }; + vkBufferImageCopy.imageExtent = VkExtent3D { + .width = static_cast<uint32_t>(txtr_x), + .height = static_cast<uint32_t>(txtr_y), + .depth = 1, + }; + vkCmdCopyBufferToImage(transferCommandBuffer, transferBuffer, ft->textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &vkBufferImageCopy); + + vkEndCommandBuffer(transferCommandBuffer); + + VkSubmitInfo submitInfo; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.pNext = nullptr; + submitInfo.waitSemaphoreCount = 0; + submitInfo.pWaitSemaphores = nullptr; + submitInfo.pWaitDstStageMask = nullptr; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &transferCommandBuffer; + submitInfo.signalSemaphoreCount = 0; + submitInfo.pSignalSemaphores = nullptr; + vkQueueSubmit(transferQueue, 1, &submitInfo, nullptr); + vkQueueWaitIdle(transferQueue); + vkResetCommandBuffer(transferCommandBuffer, 0); + } + EndTransferBuffer(transferBuffer, transferMemory); + { + VkImageMemoryBarrier vkImageMemoryBarrier; + vkImageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + vkImageMemoryBarrier.pNext = nullptr; + vkImageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + vkImageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + vkImageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + vkImageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + vkImageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + vkImageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + vkImageMemoryBarrier.image = ft->textureImage; + vkImageMemoryBarrier.subresourceRange = VkImageSubresourceRange { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + // TODO MipMap + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }; + + VkCommandBufferBeginInfo vkCommandBufferBeginInfo; + vkCommandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + vkCommandBufferBeginInfo.pNext = nullptr; + vkCommandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + vkCommandBufferBeginInfo.pInheritanceInfo = nullptr; + + vkBeginCommandBuffer(graphicsCommandBuffer, &vkCommandBufferBeginInfo); + + vkCmdPipelineBarrier(graphicsCommandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &vkImageMemoryBarrier); + + vkEndCommandBuffer(graphicsCommandBuffer); + + VkSubmitInfo submitInfo; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.pNext = nullptr; + submitInfo.waitSemaphoreCount = 0; + submitInfo.pWaitSemaphores = nullptr; + submitInfo.pWaitDstStageMask = nullptr; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &graphicsCommandBuffer; + submitInfo.signalSemaphoreCount = 0; + submitInfo.pSignalSemaphores = nullptr; + vkQueueSubmit(graphicsQueue, 1, &submitInfo, nullptr); + vkQueueWaitIdle(graphicsQueue); + } + + /* + * Vulkan descriptor sets + */ + VkDescriptorPoolSize descriptorPoolSizes[1]; + descriptorPoolSizes[0].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + descriptorPoolSizes[0].descriptorCount = MAX_FRAMES_IN_FLIGHT; + + VkDescriptorPoolCreateInfo vkDescriptorPoolCreateInfo; + vkDescriptorPoolCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + vkDescriptorPoolCreateInfo.pNext = nullptr; + vkDescriptorPoolCreateInfo.flags = 0; + vkDescriptorPoolCreateInfo.maxSets = MAX_FRAMES_IN_FLIGHT; + vkDescriptorPoolCreateInfo.poolSizeCount = (uint32_t)1; + vkDescriptorPoolCreateInfo.pPoolSizes = descriptorPoolSizes; + + // consider making me a global pool + vkResult = vkCreateDescriptorPool(vkDevice, &vkDescriptorPoolCreateInfo, vkAllocator, &ft->vkDescriptorPool); + assert(vkResult == VK_SUCCESS); + + VkDescriptorSetLayout descriptorSets[MAX_FRAMES_IN_FLIGHT]; + for (long i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) { + descriptorSets[i] = pkePipelines.descr_layouts.named.glyph; + } + VkDescriptorSetAllocateInfo vkDescriptorSetAllocateInfo; + vkDescriptorSetAllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + vkDescriptorSetAllocateInfo.pNext = nullptr; + vkDescriptorSetAllocateInfo.descriptorPool = ft->vkDescriptorPool; + vkDescriptorSetAllocateInfo.descriptorSetCount = MAX_FRAMES_IN_FLIGHT; + vkDescriptorSetAllocateInfo.pSetLayouts = descriptorSets; + + ft->vkDescriptorSets = pk_new<VkDescriptorSet>(MAX_FRAMES_IN_FLIGHT); + for (long i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) { + ft->vkDescriptorSets[i] = VkDescriptorSet{}; + } + vkResult = vkAllocateDescriptorSets(vkDevice, &vkDescriptorSetAllocateInfo, ft->vkDescriptorSets); + assert(vkResult == VK_SUCCESS); + + VkWriteDescriptorSet writeDescriptorSets[1 * MAX_FRAMES_IN_FLIGHT]; + for (long i = 0; i < 1 * MAX_FRAMES_IN_FLIGHT; ++i) { + writeDescriptorSets[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptorSets[i].pNext = nullptr; + writeDescriptorSets[i].dstSet = nullptr; + writeDescriptorSets[i].dstBinding = i; + writeDescriptorSets[i].dstArrayElement = 0; + writeDescriptorSets[i].descriptorCount = 1; + writeDescriptorSets[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + writeDescriptorSets[i].pImageInfo = nullptr; + writeDescriptorSets[i].pBufferInfo = nullptr; + writeDescriptorSets[i].pTexelBufferView = nullptr; + } + + VkDescriptorImageInfo textureDescriptorInfo; + textureDescriptorInfo.sampler = pkePipelines.vkSampler_Texture; + textureDescriptorInfo.imageView = ft->textureImageView; + textureDescriptorInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + VkDescriptorBufferInfo vkDescriptorBufferInfo[MAX_FRAMES_IN_FLIGHT]; + + for (long i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) { + vkDescriptorBufferInfo[i].buffer = UniformBuffers[i]; + vkDescriptorBufferInfo[i].offset = 0; + vkDescriptorBufferInfo[i].range = sizeof(UniformBufferObject); + + long uboIndex = i * 2; + long samplerIndex = uboIndex + 1; + + writeDescriptorSets[uboIndex].pBufferInfo = &vkDescriptorBufferInfo[i]; + writeDescriptorSets[uboIndex].dstSet = ft->vkDescriptorSets[i]; + + writeDescriptorSets[samplerIndex].pImageInfo = &textureDescriptorInfo; + writeDescriptorSets[samplerIndex].dstSet = ft->vkDescriptorSets[i]; + } + + vkUpdateDescriptorSets(vkDevice, 2 * MAX_FRAMES_IN_FLIGHT, writeDescriptorSets, 0, nullptr); + + return idx; +} + +void FontType_Unload(FontTypeIndex idx) +{ + FontType *ft = &ftd.arr_ft[(FontTypeIndex_T)idx]; + + if (ft->vkDescriptorSets != VK_NULL_HANDLE && ft->vkDescriptorPool != VK_NULL_HANDLE) { + // 2023-09-27 - JCB (copied from entities.cpp) + // We are not setting the pool flag for allowing freeing descriptor sets + // so all we need to do is destroy the pool + // If we switch to a global pool, we will need to free here, and + // destroy the pool outside of this loop + vkDestroyDescriptorPool(vkDevice, ft->vkDescriptorPool, vkAllocator); + ft->vkDescriptorSets = CAFE_BABE(VkDescriptorSet); + ft->vkDescriptorPool = VK_NULL_HANDLE; + } + + if (ft->bindings.vertexBD.buffer != VK_NULL_HANDLE) + vkDestroyBuffer(vkDevice, ft->bindings.vertexBD.buffer, vkAllocator); + ft->bindings.vertexBD.buffer = VK_NULL_HANDLE; + ft->bindings.vertexBD.firstBinding = 0; + ft->bindings.vertexBD.bindingCount = 0; + ft->bindings.vertexBD.offsets[0] = 0; + + if (ft->bindings.uvBD.buffer != VK_NULL_HANDLE) + vkDestroyBuffer(vkDevice, ft->bindings.uvBD.buffer, vkAllocator); + ft->bindings.uvBD.buffer = VK_NULL_HANDLE; + ft->bindings.uvBD.firstBinding = 0; + ft->bindings.uvBD.bindingCount = 0; + ft->bindings.uvBD.offsets[0] = 0; + + if (ft->bindings.indexBD.buffer != VK_NULL_HANDLE) + vkDestroyBuffer(vkDevice, ft->bindings.indexBD.buffer, vkAllocator); + ft->bindings.indexBD.buffer = VK_NULL_HANDLE; + ft->bindings.indexBD.bindingCount = 0; + ft->bindings.indexBD.offsets[0] = 0; + ft->bindings.indexCount = 0; + + if (ft->bindings.instanceBD.buffer != VK_NULL_HANDLE) + vkDestroyBuffer(vkDevice, ft->bindings.instanceBD.buffer, vkAllocator); + ft->bindings.instanceBD.buffer = VK_NULL_HANDLE; + ft->bindings.instanceBD.firstBinding = 0; + ft->bindings.instanceBD.bindingCount = 0; + ft->bindings.instanceCounter = 0; + ft->bindings.instanceBufferMaxCount = 0; + ft->bindings.instanceBD.offsets[0] = 0; + + if (ft->textureImageView != VK_NULL_HANDLE) + vkDestroyImageView(vkDevice, ft->textureImageView, vkAllocator); + ft->textureImageView = VK_NULL_HANDLE; + + if (ft->textureImage != VK_NULL_HANDLE) + vkDestroyImage(vkDevice, ft->textureImage, vkAllocator); + ft->textureImage = VK_NULL_HANDLE; + + if (ft->deviceMemoryInst != VK_NULL_HANDLE) + vkFreeMemory(vkDevice, ft->deviceMemoryInst, vkAllocator); + ft->deviceMemoryInst = VK_NULL_HANDLE; + + if (ft->deviceMemoryVert != VK_NULL_HANDLE) + vkFreeMemory(vkDevice, ft->deviceMemoryVert, vkAllocator); + ft->deviceMemoryVert = VK_NULL_HANDLE; + + if (ft->deviceMemoryTexture != VK_NULL_HANDLE) + vkFreeMemory(vkDevice, ft->deviceMemoryTexture, vkAllocator); + ft->deviceMemoryTexture = VK_NULL_HANDLE; +} diff --git a/src/font.hpp b/src/font.hpp new file mode 100644 index 0000000..48a7b40 --- /dev/null +++ b/src/font.hpp @@ -0,0 +1,74 @@ +#ifndef PKE_FONT_TYPE_HPP +#define PKE_FONT_TYPE_HPP + +#include "asset-manager.hpp" +#include "components.hpp" +#include "pk.h" + +#include <glm/vec4.hpp> + +/* +Vert: (two triangles) +vec2 vertex +vec2 uv + +Inst: +vec4 fg_color +vec4 bg_color +vec4 sprite_region +float width + +Texture: +the MTSDF +*/ + +TypeSafeInt_H(FontTypeIndex, uint16_t, 0xFFFF); +TypeSafeInt_H(FontRenderIndex, uint16_t, 0xFFFF); + +struct FontGlyphChar { + uint32_t unicode; + glm::ivec4 bounds; +}; +struct FontRender { + uint32_t len; + FontTypeIndex index_ft; + FontRenderIndex index_fr; +}; +struct FontType : public Entity_Base { + pk_cstr title; + AssetHandle fontTextureAssetKey; + AssetHandle glyphDetailsAssetKey; + VkDeviceMemory deviceMemoryVert = VK_NULL_HANDLE; + VkDeviceMemory deviceMemoryTexture = VK_NULL_HANDLE; + VkDeviceMemory deviceMemoryInst = VK_NULL_HANDLE; + VkImage textureImage = VK_NULL_HANDLE; + VkImageView textureImageView = VK_NULL_HANDLE; + VkDescriptorPool vkDescriptorPool = VK_NULL_HANDLE; + VkDescriptorSet *vkDescriptorSets = nullptr; + FontRender *renders = nullptr; + FontRenderIndex n_render = FontRenderIndex{0}; + FontRenderIndex h_render = FontRenderIndex{0}; + FontTypeIndex index_ft = FontTypeIndex{0}; + struct FontTypeBindings { + BufferBindingDetails vertexBD; + BufferBindingDetails uvBD; + BufferBindingDetails indexBD; + BufferBindingDetails instanceBD; + uint32_t indexCount; + uint32_t instanceCounter = 0; + uint32_t instanceBufferMaxCount = 0; + } bindings; +}; + + +void FontType_Init(); +void FontType_Teardown(); +// void FontType_Serialize(FontType *ft); // TODO +// void FontType_Deserialize(FontType **ft); // TODO +FontType* FontType_GetFonts(FontTypeIndex &count); +FontTypeIndex FontType_RegisterFont(pk_cstr title, AssetKey fontTexture, AssetKey glyphs); +void FontType_Unload(FontTypeIndex idx); +FontRender FontType_AddStringRender(FontTypeIndex idx_ft, pk_cstr cstr); +void FontType_RemoveStringRender(FontRender fr); + +#endif /* PKE_FONT_TYPE_HPP */ diff --git a/src/static-plane.cpp b/src/static-plane.cpp new file mode 100644 index 0000000..d504b24 --- /dev/null +++ b/src/static-plane.cpp @@ -0,0 +1,21 @@ + +#include "static-plane.hpp" + +IntrinsicShapePlane pkeIntrinsicsPlane { + .vert = { + {-1, -1}, + { 1, -1}, + { 1, 1}, + {-1, 1}, + }, + .uv = { + {0,0}, + {1,0}, + {1,1}, + {0,1}, + }, + .index = { + 2, 1, 0, + 0, 3, 2, + }, +}; diff --git a/src/static-plane.hpp b/src/static-plane.hpp new file mode 100644 index 0000000..097a779 --- /dev/null +++ b/src/static-plane.hpp @@ -0,0 +1,15 @@ +#ifndef PKE_STATIC_PLANE_HPP +#define PKE_STATIC_PLANE_HPP + +#include <glm/ext/vector_float3.hpp> +#include <glm/ext/vector_float2.hpp> + +struct IntrinsicShapePlane { + glm::vec2 vert[4]; + glm::vec2 uv[4]; + uint16_t index[6]; +}; + +extern IntrinsicShapePlane pkeIntrinsicsPlane; + +#endif /* PKE_STATIC_PLANE_HPP */ diff --git a/src/window.cpp b/src/window.cpp index b83ef9a..a06895c 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1,3 +1,4 @@ +#include "font.hpp" #define GLFW_INCLUDE_NONE #define GLFW_INCLUDE_VULKAN @@ -1562,18 +1563,23 @@ void CreateGraphicsPipelines() { .bindingCount = 2, .pBindings = vkDescriptorSetLayoutBindings, }; - vkCreateDescriptorSetLayout(vkDevice, &vkDescriptorSetLayoutCreateInfo, vkAllocator, &pkePipelines.vkDescriptorSetLayout_Texture); + vkCreateDescriptorSetLayout(vkDevice, &vkDescriptorSetLayoutCreateInfo, vkAllocator, &pkePipelines.descr_layouts.named.texture); + + // no UBO on glyph + vkDescriptorSetLayoutBindings[0] = vkDescriptorSetLayoutBindings[1]; + vkDescriptorSetLayoutCreateInfo.bindingCount = 1; + vkCreateDescriptorSetLayout(vkDevice, &vkDescriptorSetLayoutCreateInfo, vkAllocator, &pkePipelines.descr_layouts.named.glyph); VkPipelineLayoutCreateInfo vkPipelineLayoutCreateInfo { .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, .pNext = nullptr, .flags = 0, - .setLayoutCount = 1, - .pSetLayouts = &pkePipelines.vkDescriptorSetLayout_Texture, + .setLayoutCount = 2, + .pSetLayouts = pkePipelines.descr_layouts.arr, .pushConstantRangeCount = 0, .pPushConstantRanges = nullptr, }; - vkCreatePipelineLayout(vkDevice, &vkPipelineLayoutCreateInfo, vkAllocator, &pkePipelines.vkPipelineLayout_Texture); + vkCreatePipelineLayout(vkDevice, &vkPipelineLayoutCreateInfo, vkAllocator, pkePipelines.pipe_layouts.arr); VkSamplerCreateInfo vkSamplerCreateInfo; vkSamplerCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; @@ -1814,7 +1820,7 @@ void CreateGraphicsPipelines() { vkGraphicsPipelineCreateInfo[i].pDepthStencilState = &vkPipelineDepthStencilStateCreateInfo; vkGraphicsPipelineCreateInfo[i].pColorBlendState = &vkPipelineColorBlendStateCreateInfo; vkGraphicsPipelineCreateInfo[i].pDynamicState = &vkPipelineDynamicStateCreateInfo; - vkGraphicsPipelineCreateInfo[i].layout = pkePipelines.vkPipelineLayout_Texture; + vkGraphicsPipelineCreateInfo[i].layout = pkePipelines.pipe_layouts.named.texture; vkGraphicsPipelineCreateInfo[i].renderPass = renderRenderPass; vkGraphicsPipelineCreateInfo[i].subpass = 0; vkGraphicsPipelineCreateInfo[i].basePipelineHandle = VK_NULL_HANDLE; @@ -2259,7 +2265,7 @@ void UpdateDebugGraphicsPipeline() { VkDescriptorSetLayout descriptorSets[MAX_FRAMES_IN_FLIGHT]; for (long i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) { - descriptorSets[i] = pkePipelines.vkDescriptorSetLayout_Texture; + descriptorSets[i] = pkePipelines.descr_layouts.named.texture; } VkDescriptorSetAllocateInfo vkDescriptorSetAllocateInfo; vkDescriptorSetAllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; @@ -2414,7 +2420,7 @@ void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) { throw "failed to begin recording command buffer"; } - // VkClearColorValue clearColorTransparent = {{0.0f, 0.0f, 0.0f, 0.0f}}; + VkClearColorValue clearColorTransparent = {{0.0f, 0.0f, 0.0f, 0.0f}}; VkClearColorValue clearColorBlack = {{0.0f, 0.0f, 0.0f, 1.0f}}; VkClearDepthStencilValue clearDepth; clearDepth.depth = 1.0; @@ -2463,7 +2469,7 @@ void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) { continue; if (!binder->vkPipelineLayout) continue; - if (binder->instanceBindingCount < 1) { + if (binder->instanceBD.bindingCount < 1) { continue; } vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, binder->graphicsPipeline); @@ -2474,13 +2480,13 @@ void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) { vkCmdBindVertexBuffers(commandBuffer, binder->vertexBD.firstBinding, binder->vertexBD.bindingCount, &binder->vertexBD.buffer, binder->vertexBD.offsets); vkCmdBindVertexBuffers(commandBuffer, binder->normalsBD.firstBinding, binder->normalsBD.bindingCount, &binder->normalsBD.buffer, binder->normalsBD.offsets); vkCmdBindVertexBuffers(commandBuffer, binder->uvBD.firstBinding, binder->uvBD.bindingCount, &binder->uvBD.buffer, binder->uvBD.offsets); - vkCmdBindVertexBuffers(commandBuffer, binder->instanceFirstBinding, binder->instanceBindingCount, &binder->instanceBuffer, &binder->instanceOffsets); + vkCmdBindVertexBuffers(commandBuffer, binder->instanceBD.firstBinding, binder->instanceBD.bindingCount, &binder->instanceBD.buffer, binder->instanceBD.offsets); vkCmdDrawIndexed(commandBuffer, binder->indexCount, binder->instanceCounter, 0, 0, 0); if (pkeSettings.isRenderingDebug) { - vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.pipelines.named.TextureWireframe); - vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.vkPipelineLayout_Texture, 0, 1, &pkeDebugHitbox.vkDescriptorSets[imageIndex], 0, {}); + vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.pipelines.named.texture_wireframe); + vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.pipe_layouts.named.texture, 0, 1, &pkeDebugHitbox.vkDescriptorSets[imageIndex], 0, {}); vkCmdBindVertexBuffers(commandBuffer, binder->physVertBD.firstBinding, 1, &binder->physVertBD.buffer, binder->physVertBD.offsets); vkCmdBindVertexBuffers(commandBuffer, binder->physNormBD.firstBinding, 1, &binder->physNormBD.buffer, binder->physVertBD.offsets); @@ -2493,8 +2499,8 @@ void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) { } if (pkeDebugHitbox.instanceBuffer != VK_NULL_HANDLE) { - vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.pipelines.named.TextureWireframe); - vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.vkPipelineLayout_Texture, 0, 1, &pkeDebugHitbox.vkDescriptorSets[imageIndex], 0, {}); + vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.pipelines.named.texture_wireframe); + vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.pipe_layouts.named.texture, 0, 1, &pkeDebugHitbox.vkDescriptorSets[imageIndex], 0, {}); vkCmdBindVertexBuffers(commandBuffer, 0, 1, &UniformBuffers[imageIndex], offsets); // TODO don't hardcode firstBinding @@ -2509,8 +2515,8 @@ void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) { vkCmdEndRenderPass(commandBuffer); - /* // 2d overlay pass + /* renderPassInfo.renderPass = d2OverlayRenderPass; renderPassInfo.framebuffer = d2OverlayImageFramebuffers[imageIndex]; renderPassInfo.clearValueCount = 1; @@ -2521,10 +2527,23 @@ void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) { vkCmdSetScissor(commandBuffer, 0, 1, &scissor); // TODO 2d overlay grbinds + FontTypeIndex count; + FontType *fts = FontType_GetFonts(count); + for (FontTypeIndex i = FontTypeIndex{0}; i < count; ++i) { + FontType *ft = &fts[(FontTypeIndex_T)i]; + vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.pipelines.named.glyph); - } + vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.pipe_layouts.named.glyph, 0, 1, &ft->vkDescriptorSets[imageIndex], 0, {}); + vkCmdBindVertexBuffers(commandBuffer, 0, 1, &UniformBuffers[imageIndex], offsets); + vkCmdBindIndexBuffer(commandBuffer, ft->bindings.indexBD.buffer, ft->bindings.indexBD.offsets[0], VK_INDEX_TYPE_UINT16); + vkCmdBindVertexBuffers(commandBuffer, ft->bindings.vertexBD.firstBinding, ft->bindings.vertexBD.bindingCount, &ft->bindings.vertexBD.buffer, ft->bindings.vertexBD.offsets); + vkCmdBindVertexBuffers(commandBuffer, ft->bindings.uvBD.firstBinding, ft->bindings.uvBD.bindingCount, &ft->bindings.uvBD.buffer, ft->bindings.uvBD.offsets); + vkCmdBindVertexBuffers(commandBuffer, ft->bindings.instanceBD.firstBinding, ft->bindings.instanceBD.bindingCount, &ft->bindings.instanceBD.buffer, ft->bindings.instanceBD.offsets); + + vkCmdDrawIndexed(commandBuffer, ft->bindings.indexCount, ft->bindings.instanceCounter, 0, 0, 0); + } vkCmdEndRenderPass(commandBuffer); */ @@ -2544,9 +2563,9 @@ void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) { vkCmdDraw(commandBuffer, 3, 1, 0, 0); // ImGui - const auto count = LoadedPkePlugins.Count(); + const auto plugin_count = LoadedPkePlugins.Count(); bool any = false; - for (long i = 0; i < count; ++i) { + for (long i = 0; i < plugin_count; ++i) { if (LoadedPkePlugins[i].OnImGuiRender != nullptr) { any = true; break; @@ -2556,7 +2575,7 @@ void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) { ImGui_ImplVulkan_NewFrame(); ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); - for (long i = 0; i < count; ++i) { + for (long i = 0; i < plugin_count; ++i) { if (LoadedPkePlugins[i].OnImGuiRender != nullptr) { LoadedPkePlugins[i].OnImGuiRender(); } @@ -2746,10 +2765,10 @@ void DestroyWindow() { if (pkePipelines.pipelines.arr[i] != VK_NULL_HANDLE) vkDestroyPipeline(vkDevice, pkePipelines.pipelines.arr[i], vkAllocator); } - if (pkePipelines.vkPipelineLayout_Texture != VK_NULL_HANDLE) - vkDestroyPipelineLayout(vkDevice, pkePipelines.vkPipelineLayout_Texture, vkAllocator); - if (pkePipelines.vkDescriptorSetLayout_Texture != VK_NULL_HANDLE) - vkDestroyDescriptorSetLayout(vkDevice, pkePipelines.vkDescriptorSetLayout_Texture, vkAllocator); + if (pkePipelines.pipe_layouts.named.texture != VK_NULL_HANDLE) + vkDestroyPipelineLayout(vkDevice, pkePipelines.pipe_layouts.named.texture, vkAllocator); + if (pkePipelines.descr_layouts.named.texture != VK_NULL_HANDLE) + vkDestroyDescriptorSetLayout(vkDevice, pkePipelines.descr_layouts.named.texture, vkAllocator); for (long i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) { vkDestroyBuffer(vkDevice, UniformBuffers[i], vkAllocator); @@ -2805,6 +2824,40 @@ VkShaderModule UploadShader(AssetHandle handle) { return vkShaderModule; } +void CalculateCombinedMemReqs(uint64_t memReqsCount, VkMemoryRequirements *memReqs, VkMemoryRequirements &combinedMemReqs) { + combinedMemReqs.size = 0; + combinedMemReqs.alignment = memReqs[0].alignment; + combinedMemReqs.memoryTypeBits = memReqs[0].memoryTypeBits; + for (uint64_t i = 1; i < memReqsCount; ++i) { + combinedMemReqs.memoryTypeBits |= memReqs[i].memoryTypeBits; + if (combinedMemReqs.alignment == memReqs[i].alignment) { + continue; + } + VkDeviceSize larger, smaller; + if (combinedMemReqs.alignment > memReqs[i].alignment) { + larger = combinedMemReqs.alignment; + smaller = memReqs[i].alignment; + } else { + larger = memReqs[i].alignment; + smaller = combinedMemReqs.alignment; + } + if (larger % smaller == 0) { + combinedMemReqs.alignment = larger; + continue; + } + int combined = larger * smaller; + while ((combined / 2) % 2 == 0 && (combined / 2) % larger == 0) { + combined /= 2; + } + combinedMemReqs.alignment = combined; + } + for (uint64_t i = 0; i < memReqsCount; ++i) { + uint32_t alignmentPadding = memReqs[i].size % combinedMemReqs.alignment; + memReqs[i].size += (alignmentPadding == 0 ? 0 : combinedMemReqs.alignment - alignmentPadding); + combinedMemReqs.size += memReqs[i].size; + } +} + void Render() { vkWaitForFences(vkDevice, 1, &presentInFlightFences[CURRENT_FRAME], VK_TRUE, UINT64_MAX); diff --git a/src/window.hpp b/src/window.hpp index 35891c0..e6f422a 100644 --- a/src/window.hpp +++ b/src/window.hpp @@ -66,14 +66,27 @@ struct DebugHitbox { }; extern DebugHitbox pkeDebugHitbox; struct ImplementedPipelines { - VkDescriptorSetLayout vkDescriptorSetLayout_Texture = VK_NULL_HANDLE; - VkPipelineLayout vkPipelineLayout_Texture = VK_NULL_HANDLE; VkSampler vkSampler_Texture = VK_NULL_HANDLE; union { - VkPipeline arr[2] = { VK_NULL_HANDLE, VK_NULL_HANDLE }; + VkDescriptorSetLayout arr[2] = { VK_NULL_HANDLE, VK_NULL_HANDLE }; + struct ImplementedPipelineLayoutsByName { + VkDescriptorSetLayout texture; + VkDescriptorSetLayout glyph; + } named; + } descr_layouts; + union { + VkPipelineLayout arr[2] = { VK_NULL_HANDLE, VK_NULL_HANDLE }; + struct ImplementedPipelineLayoutsByName { + VkPipelineLayout texture; + VkPipelineLayout glyph; + } named; + } pipe_layouts; + union { + VkPipeline arr[3] = { VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE }; struct ImplementedPipelinesByName { - VkPipeline Texture; - VkPipeline TextureWireframe; + VkPipeline texture; + VkPipeline texture_wireframe; + VkPipeline glyph; } named; } pipelines; }; @@ -85,6 +98,7 @@ VkShaderModule UploadShader(AssetHandle handle); void Render(); unsigned int FindMemoryTypeIndex(uint32_t typeFilter, VkMemoryPropertyFlags memPropertyFlags); +void CalculateCombinedMemReqs(uint64_t memReqsCount, VkMemoryRequirements *memReqs, VkMemoryRequirements &combinedMemReqs); void BeginTransferBuffer(VkDeviceSize requestedMemorySize, VkBuffer &buffer, VkDeviceMemory &deviceMemory, void *&deviceData); void EndTransferBuffer(VkBuffer &buffer, VkDeviceMemory &deviceMemory); |
