diff --git a/base/VulkanUIOverlay.cpp b/base/VulkanUIOverlay.cpp index 24cc746e..190e9481 100644 --- a/base/VulkanUIOverlay.cpp +++ b/base/VulkanUIOverlay.cpp @@ -10,24 +10,12 @@ namespace vks { - UIOverlay::UIOverlay(vks::VulkanDevice *vulkanDevice, VkQueue copyQueue, std::vector &framebuffers, VkFormat colorformat, VkFormat depthformat, uint32_t width, uint32_t height, std::vector shaderstages) + UIOverlay::UIOverlay(vks::UIOverlayCreateInfo createInfo) { - this->device = vulkanDevice; - this->copyQueue = copyQueue; - this->colorFormat = colorformat; - this->depthFormat = depthformat; + this->createInfo = createInfo; + this->renderPass = createInfo.renderPass; - this->frameBuffers.resize(framebuffers.size()); - for (uint32_t i = 0; i < framebuffers.size(); i++) { - this->frameBuffers[i] = &framebuffers[i]; - } - - this->shaderStages = shaderstages; - - this->width = width; - this->height = height; - - #if defined(__ANDROID__) +#if defined(__ANDROID__) if (vks::android::screenDensity >= ACONFIGURATION_DENSITY_XXHIGH) { scale = 3.5f; } @@ -37,7 +25,7 @@ namespace vks else if (vks::android::screenDensity >= ACONFIGURATION_DENSITY_HIGH) { scale = 2.0f; }; - #endif +#endif // Init ImGui // Color scheme @@ -52,12 +40,14 @@ namespace vks style.Colors[ImGuiCol_CheckMark] = ImVec4(1.0f, 0.0f, 0.0f, 0.8f); // Dimensions ImGuiIO& io = ImGui::GetIO(); - io.DisplaySize = ImVec2((float)(width), (float)(height)); + io.DisplaySize = ImVec2((float)(createInfo.width), (float)(createInfo.height)); io.FontGlobalScale = scale; - cmdBuffers.resize(framebuffers.size()); + cmdBuffers.resize(createInfo.framebuffers.size()); prepareResources(); - prepareRenderPass(); + if (createInfo.renderPass == VK_NULL_HANDLE) { + prepareRenderPass(); + } preparePipeline(); } @@ -66,19 +56,21 @@ namespace vks { vertexBuffer.destroy(); indexBuffer.destroy(); - vkDestroyImageView(device->logicalDevice, fontView, nullptr); - vkDestroyImage(device->logicalDevice, fontImage, nullptr); - vkFreeMemory(device->logicalDevice, fontMemory, nullptr); - vkDestroySampler(device->logicalDevice, sampler, nullptr); - vkDestroyDescriptorSetLayout(device->logicalDevice, descriptorSetLayout, nullptr); - vkDestroyDescriptorPool(device->logicalDevice, descriptorPool, nullptr); - vkDestroyPipelineLayout(device->logicalDevice, pipelineLayout, nullptr); - vkDestroyPipelineCache(device->logicalDevice, pipelineCache, nullptr); - vkDestroyPipeline(device->logicalDevice, pipeline, nullptr); - vkDestroyRenderPass(device->logicalDevice, renderPass, nullptr); - vkFreeCommandBuffers(device->logicalDevice, commandPool, static_cast(cmdBuffers.size()), cmdBuffers.data()); - vkDestroyCommandPool(device->logicalDevice, commandPool, nullptr); - vkDestroyFence(device->logicalDevice, fence, nullptr); + vkDestroyImageView(createInfo.device->logicalDevice, fontView, nullptr); + vkDestroyImage(createInfo.device->logicalDevice, fontImage, nullptr); + vkFreeMemory(createInfo.device->logicalDevice, fontMemory, nullptr); + vkDestroySampler(createInfo.device->logicalDevice, sampler, nullptr); + vkDestroyDescriptorSetLayout(createInfo.device->logicalDevice, descriptorSetLayout, nullptr); + vkDestroyDescriptorPool(createInfo.device->logicalDevice, descriptorPool, nullptr); + vkDestroyPipelineLayout(createInfo.device->logicalDevice, pipelineLayout, nullptr); + vkDestroyPipelineCache(createInfo.device->logicalDevice, pipelineCache, nullptr); + vkDestroyPipeline(createInfo.device->logicalDevice, pipeline, nullptr); + if (createInfo.renderPass == VK_NULL_HANDLE) { + vkDestroyRenderPass(createInfo.device->logicalDevice, renderPass, nullptr); + } + vkFreeCommandBuffers(createInfo.device->logicalDevice, commandPool, static_cast(cmdBuffers.size()), cmdBuffers.data()); + vkDestroyCommandPool(createInfo.device->logicalDevice, commandPool, nullptr); + vkDestroyFence(createInfo.device->logicalDevice, fence, nullptr); } /** Prepare all vulkan resources required to render the UI overlay */ @@ -106,14 +98,14 @@ namespace vks imageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - VK_CHECK_RESULT(vkCreateImage(device->logicalDevice, &imageInfo, nullptr, &fontImage)); + VK_CHECK_RESULT(vkCreateImage(createInfo.device->logicalDevice, &imageInfo, nullptr, &fontImage)); VkMemoryRequirements memReqs; - vkGetImageMemoryRequirements(device->logicalDevice, fontImage, &memReqs); + vkGetImageMemoryRequirements(createInfo.device->logicalDevice, fontImage, &memReqs); VkMemoryAllocateInfo memAllocInfo = vks::initializers::memoryAllocateInfo(); memAllocInfo.allocationSize = memReqs.size; - memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - VK_CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &fontMemory)); - VK_CHECK_RESULT(vkBindImageMemory(device->logicalDevice, fontImage, fontMemory, 0)); + memAllocInfo.memoryTypeIndex = createInfo.device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + VK_CHECK_RESULT(vkAllocateMemory(createInfo.device->logicalDevice, &memAllocInfo, nullptr, &fontMemory)); + VK_CHECK_RESULT(vkBindImageMemory(createInfo.device->logicalDevice, fontImage, fontMemory, 0)); // Image view VkImageViewCreateInfo viewInfo = vks::initializers::imageViewCreateInfo(); @@ -123,12 +115,12 @@ namespace vks viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; viewInfo.subresourceRange.levelCount = 1; viewInfo.subresourceRange.layerCount = 1; - VK_CHECK_RESULT(vkCreateImageView(device->logicalDevice, &viewInfo, nullptr, &fontView)); + VK_CHECK_RESULT(vkCreateImageView(createInfo.device->logicalDevice, &viewInfo, nullptr, &fontView)); // Staging buffers for font data upload vks::Buffer stagingBuffer; - VK_CHECK_RESULT(device->createBuffer( + VK_CHECK_RESULT(createInfo.device->createBuffer( VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &stagingBuffer, @@ -139,7 +131,7 @@ namespace vks stagingBuffer.unmap(); // Copy buffer data to font image - VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); + VkCommandBuffer copyCmd = createInfo.device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); // Prepare for transfer vks::tools::setImageLayout( @@ -178,7 +170,7 @@ namespace vks VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - device->flushCommandBuffer(copyCmd, copyQueue, true); + createInfo.device->flushCommandBuffer(copyCmd, createInfo.copyQueue, true); stagingBuffer.destroy(); @@ -191,36 +183,36 @@ namespace vks samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; - VK_CHECK_RESULT(vkCreateSampler(device->logicalDevice, &samplerInfo, nullptr, &sampler)); + VK_CHECK_RESULT(vkCreateSampler(createInfo.device->logicalDevice, &samplerInfo, nullptr, &sampler)); // Command buffer VkCommandPoolCreateInfo cmdPoolInfo = {}; cmdPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - cmdPoolInfo.queueFamilyIndex = device->queueFamilyIndices.graphics; + cmdPoolInfo.queueFamilyIndex = createInfo.device->queueFamilyIndices.graphics; cmdPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - VK_CHECK_RESULT(vkCreateCommandPool(device->logicalDevice, &cmdPoolInfo, nullptr, &commandPool)); + VK_CHECK_RESULT(vkCreateCommandPool(createInfo.device->logicalDevice, &cmdPoolInfo, nullptr, &commandPool)); VkCommandBufferAllocateInfo cmdBufAllocateInfo = vks::initializers::commandBufferAllocateInfo(commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, static_cast(cmdBuffers.size())); - VK_CHECK_RESULT(vkAllocateCommandBuffers(device->logicalDevice, &cmdBufAllocateInfo, cmdBuffers.data())); + VK_CHECK_RESULT(vkAllocateCommandBuffers(createInfo.device->logicalDevice, &cmdBufAllocateInfo, cmdBuffers.data())); // Descriptor pool std::vector poolSizes = { vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1) }; VkDescriptorPoolCreateInfo descriptorPoolInfo = vks::initializers::descriptorPoolCreateInfo(poolSizes, 2); - VK_CHECK_RESULT(vkCreateDescriptorPool(device->logicalDevice, &descriptorPoolInfo, nullptr, &descriptorPool)); + VK_CHECK_RESULT(vkCreateDescriptorPool(createInfo.device->logicalDevice, &descriptorPoolInfo, nullptr, &descriptorPool)); // Descriptor set layout std::vector setLayoutBindings = { vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 0), }; VkDescriptorSetLayoutCreateInfo descriptorLayout = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); - VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device->logicalDevice, &descriptorLayout, nullptr, &descriptorSetLayout)); + VK_CHECK_RESULT(vkCreateDescriptorSetLayout(createInfo.device->logicalDevice, &descriptorLayout, nullptr, &descriptorSetLayout)); // Descriptor set VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout, 1); - VK_CHECK_RESULT(vkAllocateDescriptorSets(device->logicalDevice, &allocInfo, &descriptorSet)); + VK_CHECK_RESULT(vkAllocateDescriptorSets(createInfo.device->logicalDevice, &allocInfo, &descriptorSet)); VkDescriptorImageInfo fontDescriptor = vks::initializers::descriptorImageInfo( sampler, fontView, @@ -229,12 +221,12 @@ namespace vks std::vector writeDescriptorSets = { vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 0, &fontDescriptor) }; - vkUpdateDescriptorSets(device->logicalDevice, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr); + vkUpdateDescriptorSets(createInfo.device->logicalDevice, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr); // Pipeline cache VkPipelineCacheCreateInfo pipelineCacheCreateInfo = {}; pipelineCacheCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; - VK_CHECK_RESULT(vkCreatePipelineCache(device->logicalDevice, &pipelineCacheCreateInfo, nullptr, &pipelineCache)); + VK_CHECK_RESULT(vkCreatePipelineCache(createInfo.device->logicalDevice, &pipelineCacheCreateInfo, nullptr, &pipelineCache)); // Pipeline layout // Push constants for UI rendering parameters @@ -242,11 +234,11 @@ namespace vks VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayout, 1); pipelineLayoutCreateInfo.pushConstantRangeCount = 1; pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstantRange; - VK_CHECK_RESULT(vkCreatePipelineLayout(device->logicalDevice, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout)); + VK_CHECK_RESULT(vkCreatePipelineLayout(createInfo.device->logicalDevice, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout)); // Command buffer execution fence VkFenceCreateInfo fenceCreateInfo = vks::initializers::fenceCreateInfo(); - VK_CHECK_RESULT(vkCreateFence(device->logicalDevice, &fenceCreateInfo, nullptr, &fence)); + VK_CHECK_RESULT(vkCreateFence(createInfo.device->logicalDevice, &fenceCreateInfo, nullptr, &fence)); } /** Prepare a separate pipeline for the UI overlay rendering decoupled from the main application */ @@ -270,8 +262,20 @@ namespace vks blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD; + std::vector blendStates(createInfo.attachmentCount); + for (uint32_t i = 0; i < createInfo.attachmentCount; i++) { + blendStates[i].blendEnable = VK_TRUE; + blendStates[i].colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + blendStates[i].srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + blendStates[i].dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + blendStates[i].colorBlendOp = VK_BLEND_OP_ADD; + blendStates[i].srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + blendStates[i].dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + blendStates[i].alphaBlendOp = VK_BLEND_OP_ADD; + } + VkPipelineColorBlendStateCreateInfo colorBlendState = - vks::initializers::pipelineColorBlendStateCreateInfo(1, &blendAttachmentState); + vks::initializers::pipelineColorBlendStateCreateInfo(static_cast(blendStates.size()), blendStates.data()); VkPipelineDepthStencilStateCreateInfo depthStencilState = vks::initializers::pipelineDepthStencilStateCreateInfo(VK_FALSE, VK_FALSE, VK_COMPARE_OP_LESS_OR_EQUAL); @@ -280,7 +284,7 @@ namespace vks vks::initializers::pipelineViewportStateCreateInfo(1, 1, 0); VkPipelineMultisampleStateCreateInfo multisampleState = - vks::initializers::pipelineMultisampleStateCreateInfo(VK_SAMPLE_COUNT_1_BIT); + vks::initializers::pipelineMultisampleStateCreateInfo(createInfo.rasterizationSamples); std::vector dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, @@ -298,8 +302,8 @@ namespace vks pipelineCreateInfo.pViewportState = &viewportState; pipelineCreateInfo.pDepthStencilState = &depthStencilState; pipelineCreateInfo.pDynamicState = &dynamicState; - pipelineCreateInfo.stageCount = static_cast(shaderStages.size()); - pipelineCreateInfo.pStages = shaderStages.data(); + pipelineCreateInfo.stageCount = static_cast(createInfo.shaders.size()); + pipelineCreateInfo.pStages = createInfo.shaders.data(); // Vertex bindings an attributes based on ImGui vertex definition std::vector vertexInputBindings = { @@ -318,18 +322,17 @@ namespace vks pipelineCreateInfo.pVertexInputState = &vertexInputState; - VK_CHECK_RESULT(vkCreateGraphicsPipelines(device->logicalDevice, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipeline)); + VK_CHECK_RESULT(vkCreateGraphicsPipelines(createInfo.device->logicalDevice, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipeline)); } - /** Prepare a separate render pass for rendering the text as an overlay */ + /** Prepare a separate render pass for rendering the UI as an overlay */ void UIOverlay::prepareRenderPass() { VkAttachmentDescription attachments[2] = {}; // Color attachment - attachments[0].format = colorFormat; + attachments[0].format = createInfo.colorformat; attachments[0].samples = VK_SAMPLE_COUNT_1_BIT; - // Don't clear the framebuffer (like the renderpass from the example does) attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; @@ -338,7 +341,7 @@ namespace vks attachments[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; // Depth attachment - attachments[1].format = depthFormat; + attachments[1].format = createInfo.depthformat; attachments[1].samples = VK_SAMPLE_COUNT_1_BIT; attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; @@ -397,26 +400,25 @@ namespace vks renderPassInfo.dependencyCount = 2; renderPassInfo.pDependencies = subpassDependencies; - VK_CHECK_RESULT(vkCreateRenderPass(device->logicalDevice, &renderPassInfo, nullptr, &renderPass)); + VK_CHECK_RESULT(vkCreateRenderPass(createInfo.device->logicalDevice, &renderPassInfo, nullptr, &renderPass)); } - /** Update the command buffers to reflect text changes */ + /** Update the command buffers to reflect UI changes */ void UIOverlay::updateCommandBuffers() { VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo(); VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo(); renderPassBeginInfo.renderPass = renderPass; - renderPassBeginInfo.renderArea.extent.width = width; - renderPassBeginInfo.renderArea.extent.height = height; - // None of the attachments will be cleared - renderPassBeginInfo.clearValueCount = 0; - renderPassBeginInfo.pClearValues = nullptr; + renderPassBeginInfo.renderArea.extent.width = createInfo.width; + renderPassBeginInfo.renderArea.extent.height = createInfo.height; + renderPassBeginInfo.clearValueCount = static_cast(createInfo.clearValues.size()); + renderPassBeginInfo.pClearValues = createInfo.clearValues.data(); ImGuiIO& io = ImGui::GetIO(); for (size_t i = 0; i < cmdBuffers.size(); ++i) { - renderPassBeginInfo.framebuffer = *frameBuffers[i]; + renderPassBeginInfo.framebuffer = createInfo.framebuffers[i]; VK_CHECK_RESULT(vkBeginCommandBuffer(cmdBuffers[i], &cmdBufInfo)); @@ -464,6 +466,13 @@ namespace vks vertexOffset += cmd_list->VtxBuffer.Size; } + // Add empty subpasses if requested + if (createInfo.subpassCount > 1) { + for (uint32_t j = 1; j < createInfo.subpassCount; j++) { + vkCmdNextSubpass(cmdBuffers[i], VK_SUBPASS_CONTENTS_INLINE); + } + } + vkCmdEndRenderPass(cmdBuffers[i]); if (vks::debugmarker::active) { @@ -492,7 +501,7 @@ namespace vks if ((vertexBuffer.buffer == VK_NULL_HANDLE) || (vertexCount != imDrawData->TotalVtxCount)) { vertexBuffer.unmap(); vertexBuffer.destroy(); - VK_CHECK_RESULT(device->createBuffer(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &vertexBuffer, vertexBufferSize)); + VK_CHECK_RESULT(createInfo.device->createBuffer(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &vertexBuffer, vertexBufferSize)); vertexCount = imDrawData->TotalVtxCount; vertexBuffer.unmap(); vertexBuffer.map(); @@ -504,7 +513,7 @@ namespace vks if ((indexBuffer.buffer == VK_NULL_HANDLE) || (indexCount < imDrawData->TotalIdxCount)) { indexBuffer.unmap(); indexBuffer.destroy(); - VK_CHECK_RESULT(device->createBuffer(VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &indexBuffer, indexBufferSize)); + VK_CHECK_RESULT(createInfo.device->createBuffer(VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &indexBuffer, indexBufferSize)); indexCount = imDrawData->TotalIdxCount; indexBuffer.map(); updateCmdBuffers = true; @@ -535,8 +544,8 @@ namespace vks { ImGuiIO& io = ImGui::GetIO(); io.DisplaySize = ImVec2((float)(width), (float)(height)); - this->width = width; - this->height = height; + createInfo.width = width; + createInfo.height = height; updateCommandBuffers(); } @@ -552,8 +561,8 @@ namespace vks VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, fence)); - VK_CHECK_RESULT(vkWaitForFences(device->logicalDevice, 1, &fence, VK_TRUE, UINT64_MAX)); - VK_CHECK_RESULT(vkResetFences(device->logicalDevice, 1, &fence)); + VK_CHECK_RESULT(vkWaitForFences(createInfo.device->logicalDevice, 1, &fence, VK_TRUE, UINT64_MAX)); + VK_CHECK_RESULT(vkResetFences(createInfo.device->logicalDevice, 1, &fence)); } bool UIOverlay::header(const char *caption) diff --git a/base/VulkanUIOverlay.h b/base/VulkanUIOverlay.h index f1a9e005..f545fba4 100644 --- a/base/VulkanUIOverlay.h +++ b/base/VulkanUIOverlay.h @@ -30,18 +30,26 @@ namespace vks { + struct UIOverlayCreateInfo + { + vks::VulkanDevice *device; + VkQueue copyQueue; + VkRenderPass renderPass; + std::vector framebuffers; + VkFormat colorformat; + VkFormat depthformat; + uint32_t width; + uint32_t height; + std::vector shaders; + VkSampleCountFlagBits rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + uint32_t subpassCount = 1; + std::vector clearValues = {}; + uint32_t attachmentCount = 1; + }; + class UIOverlay { private: - vks::VulkanDevice *device; - - VkQueue copyQueue; - VkFormat colorFormat; - VkFormat depthFormat; - - uint32_t width; - uint32_t height; - vks::Buffer vertexBuffer; vks::Buffer indexBuffer; int32_t vertexCount = 0; @@ -55,8 +63,6 @@ namespace vks VkPipeline pipeline; VkRenderPass renderPass; VkCommandPool commandPool; - std::vector frameBuffers; - std::vector shaderStages; VkFence fence; VkDeviceMemory fontMemory = VK_NULL_HANDLE; @@ -69,6 +75,8 @@ namespace vks glm::vec2 translate; } pushConstBlock; + UIOverlayCreateInfo createInfo = {}; + void prepareResources(); void preparePipeline(); void prepareRenderPass(); @@ -79,7 +87,7 @@ namespace vks std::vector cmdBuffers; - UIOverlay(vks::VulkanDevice *vulkanDevice, VkQueue copyQueue, std::vector &framebuffers, VkFormat colorformat, VkFormat depthformat, uint32_t width, uint32_t height, std::vector shaderstages); + UIOverlay(vks::UIOverlayCreateInfo createInfo); ~UIOverlay(); void update(); diff --git a/base/vulkanexamplebase.cpp b/base/vulkanexamplebase.cpp index c8a727f4..95382116 100644 --- a/base/vulkanexamplebase.cpp +++ b/base/vulkanexamplebase.cpp @@ -188,11 +188,25 @@ void VulkanExampleBase::prepare() setupFrameBuffer(); settings.overlay = settings.overlay && (!benchmark.active); if (settings.overlay) { - std::vector shaderStages = { - loadShader(getAssetPath() + "shaders/base/uioverlay.vert.spv", VK_SHADER_STAGE_VERTEX_BIT), - loadShader(getAssetPath() + "shaders/base/uioverlay.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT), - }; - UIOverlay = new vks::UIOverlay(vulkanDevice, queue, frameBuffers, swapChain.colorFormat, depthFormat, width, height, shaderStages); + vks::UIOverlayCreateInfo overlayCreateInfo = {}; + // Setup default overlay creation info + overlayCreateInfo.device = vulkanDevice; + overlayCreateInfo.copyQueue = queue; + overlayCreateInfo.framebuffers = frameBuffers; + overlayCreateInfo.colorformat = swapChain.colorFormat; + overlayCreateInfo.depthformat = depthFormat; + overlayCreateInfo.width = width; + overlayCreateInfo.height = height; + // Virtual function call for example to customize overlay creation + OnSetupUIOverlay(overlayCreateInfo); + // Load default shaders if not specified by example + if (overlayCreateInfo.shaders.size() == 0) { + overlayCreateInfo.shaders = { + loadShader(getAssetPath() + "shaders/base/uioverlay.vert.spv", VK_SHADER_STAGE_VERTEX_BIT), + loadShader(getAssetPath() + "shaders/base/uioverlay.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT), + }; + } + UIOverlay = new vks::UIOverlay(overlayCreateInfo); updateOverlay(); } } @@ -2141,4 +2155,5 @@ void VulkanExampleBase::setupSwapChain() swapChain.create(&width, &height, settings.vsync); } +void VulkanExampleBase::OnSetupUIOverlay(vks::UIOverlayCreateInfo &createInfo) {} void VulkanExampleBase::OnUpdateUIOverlay(vks::UIOverlay *overlay) {} \ No newline at end of file diff --git a/base/vulkanexamplebase.h b/base/vulkanexamplebase.h index 8e6ccb0b..68bc71ba 100644 --- a/base/vulkanexamplebase.h +++ b/base/vulkanexamplebase.h @@ -392,6 +392,8 @@ public: // Submit the frames' workload void submitFrame(); + /** @brief (Virtual) Called before the UI overlay is created, can be used to do a custom setup e.g. with different renderpass */ + virtual void OnSetupUIOverlay(vks::UIOverlayCreateInfo &createInfo); /** @brief (Virtual) Called when the UI overlay is updating, can be used to add custom elements to the overlay */ virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay); };