diff options
| author | Jonathan Bradley <jcb@pikum.xyz> | 2025-08-19 13:51:40 -0400 |
|---|---|---|
| committer | Jonathan Bradley <jcb@pikum.xyz> | 2025-08-19 14:33:08 -0400 |
| commit | 154436ab88925540f86f43c0ac885c080949aa9b (patch) | |
| tree | 43a22f26286428f0d165fc1ff801cd0cb87092c6 /src/window.cpp | |
| parent | ebcae77b137a759c453b89a774ece5a755078a38 (diff) | |
pke: ui box type button image
Diffstat (limited to 'src/window.cpp')
| -rw-r--r-- | src/window.cpp | 427 |
1 files changed, 388 insertions, 39 deletions
diff --git a/src/window.cpp b/src/window.cpp index 0c7f281..773c767 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -76,8 +76,11 @@ VkSampleCountFlagBits global_sample_count; struct pkvk_queued_actions { struct pkvk_queued_actions_delete { + pk_arr_t<VkImageView> image_view{}; + pk_arr_t<VkImage> image{}; pk_arr_t<VkBuffer> buffers{}; pk_arr_t<VkDeviceMemory> memory{}; + pk_arr_t<VkDescriptorPool> descriptor_pool{}; } destroy; } pkvk_actn_queue; @@ -465,6 +468,7 @@ void pkvk_texture_upload(pkvk_texture_upload_data *data, pkvk_texture_upload_dat VkDeviceSize offsets[PKVK_TEXTURE_UPLOAD_ARR_MAX_LENGTH]; VkDeviceSize size = 0; VkDeviceSize offset = 0; + VkDeviceSize padding = 0; memset(&offsets, 0, sizeof(offsets)); @@ -551,7 +555,10 @@ void pkvk_texture_upload(pkvk_texture_upload_data *data, pkvk_texture_upload_dat */ for (i = 0; i < data->n_textures; ++i) { - assert(data->texture_assets[i]->type == PKE_ASSET_TYPE_TEXTURE); + if(data->texture_assets[i]->type != PKE_ASSET_TYPE_TEXTURE) { + fprintf(stderr, "[pkvk_texture_upload] Expected all passed assets to be textures, got: %hhu for idx#%i.", static_cast<AssetType_T>(data->texture_assets[i]->type), i); + return; + } imageCreateInfo.extent.width = data->texture_assets[i]->details.texture.width; imageCreateInfo.extent.height = data->texture_assets[i]->details.texture.height; @@ -626,7 +633,8 @@ void pkvk_texture_upload(pkvk_texture_upload_data *data, pkvk_texture_upload_dat vkImageMemoryBarriers[i].image = out->images[i]; offset += size; - offset += (combined_mem_reqs.alignment - (size % combined_mem_reqs.alignment)) % combined_mem_reqs.alignment; + padding = (combined_mem_reqs.alignment - (size % combined_mem_reqs.alignment)) % combined_mem_reqs.alignment; + offset += padding; } /* @@ -712,6 +720,276 @@ void pkvk_texture_upload(pkvk_texture_upload_data *data, pkvk_texture_upload_dat PKVK_EndBuffer(tmpBufferDetails); } +void pkvk_texture_upload_array(pkvk_texture_upload_data *data, pkvk_texture_upload_data_out *out) { + uint8_t i; + int txtr_x, txtr_y, txtr_chan; + VkResult vkResult{}; + VkImage tmpImage{}; + PKVK_TmpBufferDetails tmpBufferDetails{}; + VkImageViewCreateInfo vkImageViewCreateInfo{}; + VkImageCreateInfo imageCreateInfo{}; + VkMemoryRequirements combined_mem_reqs{}; + + VkBufferImageCopy2 vkBufferImageCopies[PKVK_TEXTURE_UPLOAD_ARR_MAX_LENGTH]; + VkCopyBufferToImageInfo2 copy_buffer_to_image_2{}; + VkImageMemoryBarrier vkImageMemoryBarrier{}; + VkDeviceSize size = 0; + VkDeviceSize offset = 0; + + vkImageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + vkImageViewCreateInfo.pNext = VK_NULL_HANDLE; + vkImageViewCreateInfo.flags = 0; + vkImageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; + vkImageViewCreateInfo.format = VK_FORMAT_R8G8B8A8_SRGB; + 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 { + .aspectMask = VkImageAspectFlagBits::VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0u, + // TODO MipMap + .levelCount = 1u, + .baseArrayLayer = 0u, + .layerCount = (uint32_t)data->n_textures, + }; + + imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageCreateInfo.pNext = VK_NULL_HANDLE; + imageCreateInfo.flags = 0; + imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; + imageCreateInfo.format = VK_FORMAT_R8G8B8A8_SRGB; + imageCreateInfo.extent.width = data->texture_assets[0]->details.texture.width; + imageCreateInfo.extent.height = data->texture_assets[0]->details.texture.height; + imageCreateInfo.extent.depth = 1; + imageCreateInfo.mipLevels = 1; + imageCreateInfo.arrayLayers = data->n_textures; + imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; + 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 = VK_NULL_HANDLE; + imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageCreateInfo.extent = { + .width = data->texture_assets[0]->details.texture.width, + .height = data->texture_assets[0]->details.texture.height, + .depth = 1, + }; + + vkImageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + vkImageMemoryBarrier.pNext = VK_NULL_HANDLE; + 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.subresourceRange = vkImageViewCreateInfo.subresourceRange; + + for (i = 0; i < data->n_textures; ++i) { + vkBufferImageCopies[i].sType = VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2; + vkBufferImageCopies[i].pNext = VK_NULL_HANDLE; + vkBufferImageCopies[i].bufferOffset = 0; + vkBufferImageCopies[i].bufferRowLength = data->texture_assets[0]->details.texture.width; + vkBufferImageCopies[i].bufferImageHeight = data->texture_assets[0]->details.texture.width; + vkBufferImageCopies[i].bufferRowLength = 0; + vkBufferImageCopies[i].bufferImageHeight = 0; + vkBufferImageCopies[i].imageSubresource = VkImageSubresourceLayers { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .mipLevel = 0, + .baseArrayLayer = i, + .layerCount = 1, + }; + vkBufferImageCopies[i].imageOffset = VkOffset3D { + .x = 0, + .y = 0, + .z = 0, + }; + vkBufferImageCopies[i].imageExtent = VkExtent3D { + .width = data->texture_assets[0]->details.texture.width, + .height = data->texture_assets[0]->details.texture.height, + .depth = 1, + }; + } + + copy_buffer_to_image_2.sType = VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2; + copy_buffer_to_image_2.pNext = VK_NULL_HANDLE; + copy_buffer_to_image_2.srcBuffer = VK_NULL_HANDLE; + copy_buffer_to_image_2.dstImage = VK_NULL_HANDLE; + copy_buffer_to_image_2.dstImageLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + copy_buffer_to_image_2.regionCount = (uint32_t)data->n_textures; + copy_buffer_to_image_2.pRegions = vkBufferImageCopies; + + /* + * get memory requirements + */ + for (i = 0; i < data->n_textures; ++i) { + if(data->texture_assets[i]->type != PKE_ASSET_TYPE_TEXTURE) { + fprintf(stderr, "[pkvk_texture_upload] Expected all passed assets to be textures, got: %hhu for idx#%i.", static_cast<AssetType_T>(data->texture_assets[i]->type), i); + return; + } + if (data->texture_assets[i]->details.texture.width != data->texture_assets[0]->details.texture.width + || data->texture_assets[i]->details.texture.height != data->texture_assets[0]->details.texture.height) { + fprintf(stderr, "[pkvk_texture_upload] Requested array but the dimensions of texture (idx %i) did not match.", i); + return; + } + } + + vkResult = vkCreateImage(vkDevice, &imageCreateInfo, vkAllocator, &tmpImage); + assert(vkResult == VK_SUCCESS); + vkGetImageMemoryRequirements(vkDevice, tmpImage, &combined_mem_reqs); + vkDestroyImage(vkDevice, tmpImage, vkAllocator); + + /* + * memory allocation + */ + + VkMemoryAllocateInfo vkMemoryAllocateInfo; + vkMemoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + vkMemoryAllocateInfo.pNext = nullptr; + vkMemoryAllocateInfo.allocationSize = combined_mem_reqs.size; + vkMemoryAllocateInfo.memoryTypeIndex = FindMemoryTypeIndex(combined_mem_reqs.memoryTypeBits, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); + if (vkMemoryAllocateInfo.memoryTypeIndex == 0) { + vkMemoryAllocateInfo.memoryTypeIndex = FindMemoryTypeIndex(combined_mem_reqs.memoryTypeBits, 0); + } + vkAllocateMemory(vkDevice, &vkMemoryAllocateInfo, vkAllocator, &out->device_memory); + + /* + * buffer setup + */ + + char *temp_buffer = (char *)malloc(combined_mem_reqs.size); + + // copy data to temp buffer + // 2025-08-06 - JCB - PERF TODO actually test performance + // It's possible that copying these to a temporary buffer is a performance loss. + // The idea here is to separate this number-crunching from the buffer recording. + // If this texture upload function ends up being a bottleneck here's a few suggestions: + // - split stbi work to separate threads (likely biggest impact) + // - reduce # of data-copies (copy straight to the vulkan buffer instead of intermediary) + for (i = 0; i < data->n_textures; ++i) { + + vkBufferImageCopies[i].bufferOffset = offset; + + /* run texture data through stbi, putting it in the VkFormat we desire, & copy */ + stbi_uc *txtr_bytes = stbi_load_from_memory((unsigned char*)data->texture_assets[i]->ptr, data->texture_assets[i]->size, &txtr_x, &txtr_y, &txtr_chan, 4); + assert(txtr_bytes != nullptr); + assert(txtr_chan == 4); + + size = sizeof(uint8_t) * txtr_x * txtr_y * txtr_chan; + memcpy(temp_buffer + offset, txtr_bytes, size); + + free(txtr_bytes); + + offset += size; + } + + // create image + + vkResult = vkCreateImage(vkDevice, &imageCreateInfo, vkAllocator, &out->images[0]); + assert(vkResult == VK_SUCCESS); + vkResult = vkBindImageMemory(vkDevice, out->images[0], out->device_memory, 0); + assert(vkResult == VK_SUCCESS); + + // create image view + + vkImageViewCreateInfo.image = out->images[0]; + vkResult = vkCreateImageView(vkDevice, &vkImageViewCreateInfo, vkAllocator, &out->image_views[0]); + assert(vkResult == VK_SUCCESS); + + // set up image copy parameters + vkImageMemoryBarrier.image = out->images[0]; + + /* + * transition layout & copy to buffer + */ + + PKVK_BeginBuffer(transferFamilyIndex, combined_mem_reqs.size, tmpBufferDetails); + + // copy data to vulkan buffer + memcpy(tmpBufferDetails.deviceData, temp_buffer, combined_mem_reqs.size); + free(temp_buffer); + + 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(tmpBufferDetails.cmdBuffer, &vkCommandBufferBeginInfo); + + vkCmdPipelineBarrier(tmpBufferDetails.cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &vkImageMemoryBarrier); + + copy_buffer_to_image_2.dstImage = out->images[0]; + copy_buffer_to_image_2.srcBuffer = tmpBufferDetails.buffer; + vkCmdCopyBufferToImage2(tmpBufferDetails.cmdBuffer, ©_buffer_to_image_2); + + vkEndCommandBuffer(tmpBufferDetails.cmdBuffer); + + 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 = &tmpBufferDetails.cmdBuffer; + submitInfo.signalSemaphoreCount = 0; + submitInfo.pSignalSemaphores = nullptr; + vkQueueSubmit(tmpBufferDetails.queue, 1, &submitInfo, nullptr); + vkQueueWaitIdle(tmpBufferDetails.queue); + vkResetCommandBuffer(tmpBufferDetails.cmdBuffer, 0); + + PKVK_EndBuffer(tmpBufferDetails); + + // update command buffer data + 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; + + tmpBufferDetails = {}; + PKVK_BeginBuffer(graphicsFamilyIndex, 0, tmpBufferDetails); + { + + 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(tmpBufferDetails.cmdBuffer, &vkCommandBufferBeginInfo); + + vkCmdPipelineBarrier(tmpBufferDetails.cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &vkImageMemoryBarrier); + + vkEndCommandBuffer(tmpBufferDetails.cmdBuffer); + + 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 = &tmpBufferDetails.cmdBuffer; + submitInfo.signalSemaphoreCount = 0; + submitInfo.pSignalSemaphores = nullptr; + vkQueueSubmit(tmpBufferDetails.queue, 1, &submitInfo, nullptr); + vkQueueWaitIdle(tmpBufferDetails.queue); + } + PKVK_EndBuffer(tmpBufferDetails); +} + +void pkvk_queue_vk_image_view_destroy(VkImageView image_view) { + pk_arr_append_t(&pkvk_actn_queue.destroy.image_view, image_view); +} + +void pkvk_queue_vk_image_destroy(VkImage image) { + pk_arr_append_t(&pkvk_actn_queue.destroy.image, image); +} + void pkvk_queue_vk_buffer_destroy(VkBuffer buffer) { pk_arr_append_t(&pkvk_actn_queue.destroy.buffers, buffer); } @@ -720,6 +998,10 @@ void pkvk_queue_vk_memory_free(VkDeviceMemory memory) { pk_arr_append_t(&pkvk_actn_queue.destroy.memory, memory); } +void pkvk_queue_vk_descriptor_pool_destroy(VkDescriptorPool descriptor_pool) { + pk_arr_append_t(&pkvk_actn_queue.destroy.descriptor_pool, descriptor_pool); +} + unsigned int FindQueueFamilyIndex(VkPhysicalDevice device, char hasPresentSupport = -1, VkQueueFlagBits includeBits = (VkQueueFlagBits)0U, VkQueueFlagBits excludeBits = (VkQueueFlagBits)0U) { if (hasPresentSupport == -1 && includeBits == 0 && excludeBits == 0) { @@ -1954,8 +2236,7 @@ void CreateGraphicsPipelines() { vkDescriptorSetLayoutCreateInfo.pBindings = VK_NULL_HANDLE; vkResult = vkCreateDescriptorSetLayout(vkDevice, &vkDescriptorSetLayoutCreateInfo, vkAllocator, &pkePipelines.descr_layouts.named.base); assert(vkResult == VK_SUCCESS); - assert(pkePipelines.descr_layouts.named.txtr != VK_NULL_HANDLE); - + assert(pkePipelines.descr_layouts.named.base != VK_NULL_HANDLE); VkPipelineLayoutCreateInfo vkPipelineLayoutCreateInfo { .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, @@ -1987,6 +2268,7 @@ void CreateGraphicsPipelines() { AssetHandle fragGlyphAssetHandle { AM_GetHandle(AssetKey{"pke_glyph_frg\0\0"})}; AssetHandle asset_handle_vert_ui_base { AM_GetHandle(AssetKey{"pke_ui_bs_vrt\0\0"})}; AssetHandle asset_handle_frag_ui_base { AM_GetHandle(AssetKey{"pke_ui_bs_frg\0\0"})}; + AssetHandle asset_handle_frag_ui_txtr { AM_GetHandle(AssetKey{"pke_ui_txt_frg\0"})}; const long vertexBindingCount = 4; long index = 0; @@ -2189,7 +2471,7 @@ void CreateGraphicsPipelines() { offset = 0; const long vertexBindingCount_ui_base = 3; VkVertexInputBindingDescription vertInputBD_ui_base[vertexBindingCount_ui_base]; - const long vertexAttrDescCount_ui_base = 10; + const long vertexAttrDescCount_ui_base = 11; VkVertexInputAttributeDescription vertAttrDesc_ui_base[vertexAttrDescCount_ui_base]; VkPipelineVertexInputStateCreateInfo vkPipelineVertexInputStateCreateInfo_ui_base{vkPipelineVertexInputStateCreateInfo_txtr}; { @@ -2213,7 +2495,7 @@ void CreateGraphicsPipelines() { + sizeof(glm::vec4) // in_background_color + sizeof(glm::vec2) // px_scale + sizeof(float) // depth - + (sizeof(float) * 1) // padding + + sizeof(float) // texture_layer + 0; vertInputBD_ui_base[index].inputRate = VK_VERTEX_INPUT_RATE_INSTANCE; // index += 1; @@ -2258,18 +2540,25 @@ void CreateGraphicsPipelines() { offset += sizeof(glm::vec4); index += 1; - // instance - in_sprite_region_min + // instance - px_scale vertAttrDesc_ui_base[index].binding = 2; vertAttrDesc_ui_base[index].format = VK_FORMAT_R32G32_SFLOAT; vertAttrDesc_ui_base[index].offset = offset; offset += sizeof(glm::vec2); index += 1; - // instance - in_sprite_region_min + // instance - depth vertAttrDesc_ui_base[index].binding = 2; vertAttrDesc_ui_base[index].format = VK_FORMAT_R32_SFLOAT; vertAttrDesc_ui_base[index].offset = offset; - // offset += sizeof(glm::vec2); + offset += sizeof(float); + index += 1; + + // instance - texture_layer + vertAttrDesc_ui_base[index].binding = 2; + vertAttrDesc_ui_base[index].format = VK_FORMAT_R32_SFLOAT; + vertAttrDesc_ui_base[index].offset = offset; + // offset += sizeof(float); // index += 1; vkPipelineVertexInputStateCreateInfo_ui_base.vertexBindingDescriptionCount = vertexBindingCount_ui_base; @@ -2408,8 +2697,15 @@ void CreateGraphicsPipelines() { vkPipelineShaderStageCreateInfo_ui_base[0].stage = VK_SHADER_STAGE_VERTEX_BIT; vkPipelineShaderStageCreateInfo_ui_base[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; - VkGraphicsPipelineCreateInfo vkGraphicsPipelineCreateInfo[4]; - for (long i = 0; i < 4; ++i) { + /* pipelines + * 0: entity_standard + * 1: entity_wireframe + * 2: glyph + * 3: ui_base + * 4: ui_txtr + */ + std::array<VkGraphicsPipelineCreateInfo, 5> vkGraphicsPipelineCreateInfo; + for (size_t i = 0; i < vkGraphicsPipelineCreateInfo.size(); ++i) { vkGraphicsPipelineCreateInfo[i].sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; vkGraphicsPipelineCreateInfo[i].pNext = nullptr; vkGraphicsPipelineCreateInfo[i].flags = {}; @@ -2417,6 +2713,7 @@ void CreateGraphicsPipelines() { vkGraphicsPipelineCreateInfo[i].pInputAssemblyState = &vkPipelineInputAssemblyStateCreateInfo; vkGraphicsPipelineCreateInfo[i].pTessellationState = nullptr; vkGraphicsPipelineCreateInfo[i].pViewportState = &vkPipelineViewportStateCreateInfo; + vkGraphicsPipelineCreateInfo[i].pRasterizationState = &vkPipelineRasterizationStateCreateInfoFill; vkGraphicsPipelineCreateInfo[i].pMultisampleState = &vkPipelineMultisampleStateCreateInfo; vkGraphicsPipelineCreateInfo[i].pDepthStencilState = &vkPipelineDepthStencilStateCreateInfo; vkGraphicsPipelineCreateInfo[i].pColorBlendState = &vkPipelineColorBlendStateCreateInfo; @@ -2424,46 +2721,50 @@ void CreateGraphicsPipelines() { vkGraphicsPipelineCreateInfo[i].subpass = 0; vkGraphicsPipelineCreateInfo[i].basePipelineHandle = VK_NULL_HANDLE; vkGraphicsPipelineCreateInfo[i].basePipelineIndex = {}; + vkGraphicsPipelineCreateInfo[i].renderPass = VK_NULL_HANDLE; // dynamic rendering } vkGraphicsPipelineCreateInfo[0].layout = pkePipelines.pipe_layouts.named.ubo_txtr; vkGraphicsPipelineCreateInfo[1].layout = pkePipelines.pipe_layouts.named.ubo_txtr; vkGraphicsPipelineCreateInfo[2].layout = pkePipelines.pipe_layouts.named.txtr; vkGraphicsPipelineCreateInfo[3].layout = pkePipelines.pipe_layouts.named.base; - - vkGraphicsPipelineCreateInfo[0].renderPass = VK_NULL_HANDLE; // dynamic rendering - vkGraphicsPipelineCreateInfo[1].renderPass = VK_NULL_HANDLE; // dynamic rendering - vkGraphicsPipelineCreateInfo[2].renderPass = VK_NULL_HANDLE; // dynamic rendering - vkGraphicsPipelineCreateInfo[3].renderPass = VK_NULL_HANDLE; // dynamic rendering + vkGraphicsPipelineCreateInfo[4].layout = pkePipelines.pipe_layouts.named.txtr; vkGraphicsPipelineCreateInfo[0].pVertexInputState = &vkPipelineVertexInputStateCreateInfo_txtr; vkGraphicsPipelineCreateInfo[1].pVertexInputState = &vkPipelineVertexInputStateCreateInfo_txtr; vkGraphicsPipelineCreateInfo[2].pVertexInputState = &vkPipelineVertexInputStateCreateInfo_glyph; vkGraphicsPipelineCreateInfo[3].pVertexInputState = &vkPipelineVertexInputStateCreateInfo_ui_base; + vkGraphicsPipelineCreateInfo[4].pVertexInputState = &vkPipelineVertexInputStateCreateInfo_ui_base; - vkGraphicsPipelineCreateInfo[0].pRasterizationState = &vkPipelineRasterizationStateCreateInfoFill; vkGraphicsPipelineCreateInfo[1].pRasterizationState = &vkPipelineRasterizationStateCreateInfoLine; - vkGraphicsPipelineCreateInfo[2].pRasterizationState = &vkPipelineRasterizationStateCreateInfoFill; - vkGraphicsPipelineCreateInfo[3].pRasterizationState = &vkPipelineRasterizationStateCreateInfoFill; vkGraphicsPipelineCreateInfo[0].pStages = vkPipelineShaderStageCreateInfo_txtr; vkGraphicsPipelineCreateInfo[1].pStages = vkPipelineShaderStageCreateInfo_txtr; vkGraphicsPipelineCreateInfo[2].pStages = vkPipelineShaderStageCreateInfo_glyph; vkGraphicsPipelineCreateInfo[3].pStages = vkPipelineShaderStageCreateInfo_ui_base; + vkGraphicsPipelineCreateInfo[4].pStages = vkPipelineShaderStageCreateInfo_ui_base; // deffered shader creation - vkPipelineShaderStageCreateInfo_txtr[0].module = UploadShader(vertShaderAssetHandle); - vkPipelineShaderStageCreateInfo_txtr[1].module = UploadShader(textureFragShaderAssetHandle); - vkPipelineShaderStageCreateInfo_glyph[0].module = UploadShader(vertGlyphAssetHandle); - vkPipelineShaderStageCreateInfo_glyph[1].module = UploadShader(fragGlyphAssetHandle); - vkPipelineShaderStageCreateInfo_ui_base[0].module = UploadShader(asset_handle_vert_ui_base); - vkPipelineShaderStageCreateInfo_ui_base[1].module = UploadShader(asset_handle_frag_ui_base); + auto shader_module_3d_vert = UploadShader(vertShaderAssetHandle); + auto shader_module_3d_frag = UploadShader(textureFragShaderAssetHandle); + auto shader_module_glyph_vert = UploadShader(vertGlyphAssetHandle); + auto shader_module_glyph_frag = UploadShader(fragGlyphAssetHandle); + auto shader_module_ui_base_vert = UploadShader(asset_handle_vert_ui_base); + auto shader_module_ui_clr_frag = UploadShader(asset_handle_frag_ui_base); + auto shader_module_ui_txtr_frag = UploadShader(asset_handle_frag_ui_txtr); + vkPipelineShaderStageCreateInfo_txtr[0].module = shader_module_3d_vert; + vkPipelineShaderStageCreateInfo_txtr[1].module = shader_module_3d_frag; + vkPipelineShaderStageCreateInfo_glyph[0].module = shader_module_glyph_vert; + vkPipelineShaderStageCreateInfo_glyph[1].module = shader_module_glyph_frag; + vkPipelineShaderStageCreateInfo_ui_base[0].module = shader_module_ui_base_vert; + vkPipelineShaderStageCreateInfo_ui_base[1].module = shader_module_ui_clr_frag; VkPipelineRenderingCreateInfo renderingInfo{}; vkGraphicsPipelineCreateInfo[0].pNext = &renderingInfo; vkGraphicsPipelineCreateInfo[1].pNext = &renderingInfo; vkGraphicsPipelineCreateInfo[2].pNext = &renderingInfo; vkGraphicsPipelineCreateInfo[3].pNext = &renderingInfo; + vkGraphicsPipelineCreateInfo[4].pNext = &renderingInfo; renderingInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO; std::array<VkFormat, 3> color_formats; @@ -2489,16 +2790,25 @@ void CreateGraphicsPipelines() { vkResult = vkCreateGraphicsPipelines(vkDevice, VK_NULL_HANDLE, 1, &vkGraphicsPipelineCreateInfo[3], vkAllocator, &pkePipelines.pipelines.named.ui_base); assert(vkResult == VK_SUCCESS); + + vkPipelineShaderStageCreateInfo_ui_base[1].module = shader_module_ui_txtr_frag; + vkResult = vkCreateGraphicsPipelines(vkDevice, VK_NULL_HANDLE, 1, &vkGraphicsPipelineCreateInfo[4], vkAllocator, &pkePipelines.pipelines.named.ui_txtr); + assert(vkResult == VK_SUCCESS); + assert(pkePipelines.pipelines.named.entity_standard != VK_NULL_HANDLE); assert(pkePipelines.pipelines.named.entity_wireframe != VK_NULL_HANDLE); assert(pkePipelines.pipelines.named.font_glyph != VK_NULL_HANDLE); assert(pkePipelines.pipelines.named.ui_base != VK_NULL_HANDLE); + assert(pkePipelines.pipelines.named.ui_txtr != VK_NULL_HANDLE); + + vkDestroyShaderModule(vkDevice, shader_module_ui_txtr_frag, vkAllocator); + vkDestroyShaderModule(vkDevice, shader_module_ui_clr_frag, vkAllocator); + vkDestroyShaderModule(vkDevice, shader_module_ui_base_vert, vkAllocator); + vkDestroyShaderModule(vkDevice, shader_module_glyph_frag, vkAllocator); + vkDestroyShaderModule(vkDevice, shader_module_glyph_vert, vkAllocator); + vkDestroyShaderModule(vkDevice, shader_module_3d_frag, vkAllocator); + vkDestroyShaderModule(vkDevice, shader_module_3d_vert, vkAllocator); - for (long i = 0; i < 2; ++i) { - vkDestroyShaderModule(vkDevice, vkPipelineShaderStageCreateInfo_txtr[i].module, vkAllocator); - vkDestroyShaderModule(vkDevice, vkPipelineShaderStageCreateInfo_glyph[i].module, vkAllocator); - vkDestroyShaderModule(vkDevice, vkPipelineShaderStageCreateInfo_ui_base[i].module, vkAllocator); - } } // debug texture @@ -3107,6 +3417,7 @@ void pkvk_transition_image_layout(VkCommandBuffer command_buffer, } void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) { + uint32_t i, counter; vkResetCommandBuffer(commandBuffer, 0); VkCommandBufferBeginInfo beginInfo; @@ -3336,15 +3647,30 @@ void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) { vkCmdSetScissor(commandBuffer, 0, 1, &scissor); // 2d overlay grbinds - pke_ui_graphics_bindings *ui_gr = pke_ui_get_graphics_bindings(); - if (ui_gr != nullptr && ui_gr->instance_counter > 0) + const pke_ui_graphics_bindings &ui_gr = pke_ui_get_graphics_bindings(); + pk_arr_t<pke_ui_graphics_bindings_texture> ui_gr_texture; + pke_ui_get_graphics_bindings_texture(&ui_gr_texture); + if (ui_gr.instance_counter > 0) { + counter = 0; + for (i = 0; i < ui_gr_texture.next; ++i) { + counter += ui_gr_texture[i].instance_count; + } + vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.pipelines.named.ui_base); - vkCmdBindIndexBuffer(commandBuffer, ui_gr->bd_index.buffer, ui_gr->bd_index.offsets[0], VK_INDEX_TYPE_UINT16); - vkCmdBindVertexBuffers(commandBuffer, ui_gr->bd_vertex.firstBinding, ui_gr->bd_vertex.bindingCount, &ui_gr->bd_vertex.buffer, ui_gr->bd_vertex.offsets); - vkCmdBindVertexBuffers(commandBuffer, ui_gr->bd_uv.firstBinding, ui_gr->bd_uv.bindingCount, &ui_gr->bd_uv.buffer, ui_gr->bd_uv.offsets); - vkCmdBindVertexBuffers(commandBuffer, ui_gr->bd_instance.firstBinding, ui_gr->bd_instance.bindingCount, &ui_gr->bd_instance.buffer, ui_gr->bd_instance.offsets); - vkCmdDrawIndexed(commandBuffer, ui_gr->index_count, ui_gr->instance_counter, 0, 0, 0); + vkCmdBindIndexBuffer(commandBuffer, ui_gr.bd_index.buffer, ui_gr.bd_index.offsets[0], VK_INDEX_TYPE_UINT16); + vkCmdBindVertexBuffers(commandBuffer, ui_gr.bd_vertex.firstBinding, ui_gr.bd_vertex.bindingCount, &ui_gr.bd_vertex.buffer, ui_gr.bd_vertex.offsets); + vkCmdBindVertexBuffers(commandBuffer, ui_gr.bd_uv.firstBinding, ui_gr.bd_uv.bindingCount, &ui_gr.bd_uv.buffer, ui_gr.bd_uv.offsets); + vkCmdBindVertexBuffers(commandBuffer, ui_gr.bd_instance.firstBinding, ui_gr.bd_instance.bindingCount, &ui_gr.bd_instance.buffer, ui_gr.bd_instance.offsets); + vkCmdDrawIndexed(commandBuffer, ui_gr.index_count, ui_gr.instance_counter - counter, 0, 0, 0); + + if (counter > 0) { + vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.pipelines.named.ui_txtr); + for (i = 0; i < ui_gr_texture.next; ++i) { + vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.pipe_layouts.named.txtr, 0, 1, &ui_gr_texture[i].descriptor_sets[imageIndex], 0, {}); + vkCmdDrawIndexed(commandBuffer, ui_gr.index_count, ui_gr_texture[i].instance_count, 0, 0, ui_gr_texture[i].instance_offset); + } + } } vkCmdEndRendering(commandBuffer); @@ -3790,6 +4116,7 @@ void CreateWindow(PKEWindowProperties wp) { void DestroyWindow() { if (vkInstance == nullptr) return; + window_tick_late(0.0); if (pke_window_did_init_imgui == true) { ImGui_ImplVulkan_Shutdown(); ImGui_ImplGlfw_Shutdown(); @@ -3817,6 +4144,8 @@ void DestroyWindow() { vkDestroyPipeline(vkDevice, pkePipelines.pipelines.named.font_glyph, vkAllocator); if (pkePipelines.pipelines.named.ui_base != VK_NULL_HANDLE) vkDestroyPipeline(vkDevice, pkePipelines.pipelines.named.ui_base, vkAllocator); + if (pkePipelines.pipelines.named.ui_txtr != VK_NULL_HANDLE) + vkDestroyPipeline(vkDevice, pkePipelines.pipelines.named.ui_txtr, vkAllocator); if (pkePipelines.pipe_layouts.named.ubo_txtr != VK_NULL_HANDLE) vkDestroyPipelineLayout(vkDevice, pkePipelines.pipe_layouts.named.ubo_txtr, vkAllocator); @@ -3860,8 +4189,11 @@ void DestroyWindow() { fprintf(stderr, "VkAllocator has '%u' outstanding allocations!", vulkanAllocs.next); } pk_arr_reset(&vulkanAllocs); + pk_arr_reset(&pkvk_actn_queue.destroy.image_view); + pk_arr_reset(&pkvk_actn_queue.destroy.image); pk_arr_reset(&pkvk_actn_queue.destroy.buffers); pk_arr_reset(&pkvk_actn_queue.destroy.memory); + pk_arr_reset(&pkvk_actn_queue.destroy.descriptor_pool); // TODO there's un-freed vulkan stuff in the bucket // comment this out to see it in the debug printout pk_mem_bucket_destroy(MemBkt_Vulkan); @@ -3932,6 +4264,7 @@ void CalculateCombinedMemReqs(uint64_t memReqsCount, VkMemoryRequirements *memRe * Vulkan was emitting an error that the buffer was in use by a command buffer. * Processing these actions after the graphics queue is idle solved that specific issue. * This is a stop-gap measure so I can keep working and is not intended to be permanent. + * This might be okay for switching levels (maybe?) * PERF * This will block the main thread until all in-flight renders are no longer using any of the resources needed to render a scene. * Move this to a fire-and-forget background thread that uses a memory barrier and a semaphore specifically for the target resource. @@ -3939,18 +4272,34 @@ void CalculateCombinedMemReqs(uint64_t memReqsCount, VkMemoryRequirements *memRe void window_tick_late(double delta) { (void)delta; uint32_t i; - if (pkvk_actn_queue.destroy.buffers.next > 0 - || pkvk_actn_queue.destroy.memory.next > 0) { + if (pkvk_actn_queue.destroy.image_view.next > 0 + || pkvk_actn_queue.destroy.image.next > 0 + || pkvk_actn_queue.destroy.buffers.next > 0 + || pkvk_actn_queue.destroy.memory.next > 0 + || pkvk_actn_queue.destroy.descriptor_pool.next > 0 + ) { vkQueueWaitIdle(pkvk_shared.queue.graphics); } + for (i = 0; i < pkvk_actn_queue.destroy.image_view.next; ++i) { + vkDestroyImageView(vkDevice, pkvk_actn_queue.destroy.image_view[i], vkAllocator); + } + for (i = 0; i < pkvk_actn_queue.destroy.image.next; ++i) { + vkDestroyImage(vkDevice, pkvk_actn_queue.destroy.image[i], vkAllocator); + } for (i = 0; i < pkvk_actn_queue.destroy.buffers.next; ++i) { vkDestroyBuffer(vkDevice, pkvk_actn_queue.destroy.buffers[i], vkAllocator); } for (i = 0; i < pkvk_actn_queue.destroy.memory.next; ++i) { vkFreeMemory(vkDevice, pkvk_actn_queue.destroy.memory[i], vkAllocator); } + for (i = 0; i < pkvk_actn_queue.destroy.descriptor_pool.next; ++i) { + vkDestroyDescriptorPool(vkDevice, pkvk_actn_queue.destroy.descriptor_pool[i], vkAllocator); + } + pk_arr_clear(&pkvk_actn_queue.destroy.image_view); + pk_arr_clear(&pkvk_actn_queue.destroy.image); pk_arr_clear(&pkvk_actn_queue.destroy.buffers); pk_arr_clear(&pkvk_actn_queue.destroy.memory); + pk_arr_clear(&pkvk_actn_queue.destroy.descriptor_pool); } void Render() { |
