#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 bktFont; void FontType_Init() { ftd.h_ft = FontTypeIndex{5}; ftd.arr_ft = pk_new(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(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((FontTypeIndex_T)ftd.n_ft); memcpy(arr, ftd.arr_ft, sizeof(FontType) * index); pk_delete(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(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 * swapchainLength; 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(deviceData) + runningOffset; srcPtr = reinterpret_cast(pkeIntrinsicsPlane.vert); memcpy(dstPtr, srcPtr, sizeVert); runningOffset += sizeVert; dstPtr = static_cast(deviceData) + runningOffset; srcPtr = reinterpret_cast(pkeIntrinsicsPlane.uv); memcpy(dstPtr, srcPtr, sizeUV); runningOffset += sizeUV; dstPtr = static_cast(deviceData) + runningOffset; srcPtr = reinterpret_cast(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(txtr_x), .height = static_cast(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 = swapchainLength; VkDescriptorPoolCreateInfo vkDescriptorPoolCreateInfo; vkDescriptorPoolCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; vkDescriptorPoolCreateInfo.pNext = nullptr; vkDescriptorPoolCreateInfo.flags = 0; vkDescriptorPoolCreateInfo.maxSets = swapchainLength; 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 = pk_new(swapchainLength); for (long i = 0; i < swapchainLength; ++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 = swapchainLength; vkDescriptorSetAllocateInfo.pSetLayouts = descriptorSets; ft->vkDescriptorSets = pk_new(swapchainLength); for (long i = 0; i < swapchainLength; ++i) { ft->vkDescriptorSets[i] = VkDescriptorSet{}; } vkResult = vkAllocateDescriptorSets(vkDevice, &vkDescriptorSetAllocateInfo, ft->vkDescriptorSets); pk_delete(descriptorSets, swapchainLength); assert(vkResult == VK_SUCCESS); VkWriteDescriptorSet *writeDescriptorSets = pk_new(swapchainLength); for (long i = 0; i < 1 * swapchainLength; ++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 = pk_new(swapchainLength); for (long i = 0; i < swapchainLength; ++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 * swapchainLength, writeDescriptorSets, 0, nullptr); pk_delete(vkDescriptorBufferInfo, swapchainLength); pk_delete(writeDescriptorSets, swapchainLength); 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); pk_delete(ft->vkDescriptorSets, swapchainLength); 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; }