Hello,
I’m trying to use subpasses just for a learning purpose.
My idea was to use toneMapping using subpass.
I have 3 attachments : The final output(wich will be used to toneMap), the colorImage in HDR,and the depthAttachment.
However I’m geting no result at all, the screen is completed cleaned and no Validation Layer message (I’m pretty sure it’s something silly, but I’m struggling"). Would you please spot the problem in my implementation.
Renderpass and attachments creation :
VkAttachmentDescription swapchainColorAttachment = {};
swapchainColorAttachment.format = presentationEngine.getSwapChainFormat();
swapchainColorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
swapchainColorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
swapchainColorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
swapchainColorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
swapchainColorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
swapchainColorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
swapchainColorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
VkAttachmentDescription toneMappingAttachment = {};
toneMappingAttachment.format = presentationEngine.getSwapChainFormat();
toneMappingAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
toneMappingAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
toneMappingAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
toneMappingAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
toneMappingAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
toneMappingAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
toneMappingAttachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkAttachmentDescription depthAttachment = {};
depthAttachment.format = device.getSupportedFormat(
{ VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT },
VK_IMAGE_TILING_OPTIMAL,
VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT
);
depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkAttachmentReference toneMappingRef = {};
toneMappingRef.attachment = 1;
toneMappingRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkAttachmentReference depthAttachmentRef = {};
depthAttachmentRef.attachment = 2;
depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkAttachmentReference swapChainColor = {};
swapChainColor.attachment = 0;
swapChainColor.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
std::array<VkSubpassDescription,2> subpass = {};
subpass[0].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass[0].colorAttachmentCount = 1;
subpass[0].pColorAttachments = &toneMappingRef;
subpass[0].pDepthStencilAttachment = &depthAttachmentRef;
subpass[1].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass[1].colorAttachmentCount = 1;
subpass[1].pColorAttachments = &swapChainColor;
VkAttachmentReference inputReferences[2];
inputReferences[0] = { 1, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL };
inputReferences[1] = { 2, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL };
subpass[1].inputAttachmentCount = 2;
subpass[1].pInputAttachments = inputReferences;
std::array<VkSubpassDependency, 3> dependencies;
dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
dependencies[0].dstSubpass = 0;
dependencies[0].srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
dependencies[1].srcSubpass = 0;
dependencies[1].dstSubpass = 1;
dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[1].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[1].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
dependencies[2].srcSubpass = 0;
dependencies[2].dstSubpass = VK_SUBPASS_EXTERNAL;
dependencies[2].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[2].dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
dependencies[2].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[2].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
dependencies[2].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
std::array<VkAttachmentDescription, 3> attachments = { swapchainColorAttachment,toneMappingAttachment, depthAttachment };
VkRenderPassCreateInfo renderPassInfo = {};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
renderPassInfo.pAttachments = attachments.data();
renderPassInfo.subpassCount = static_cast<uint32_t>(subpass.size());
renderPassInfo.pSubpasses = subpass.data();
renderPassInfo.dependencyCount = static_cast<uint32_t>(dependencies.size());
renderPassInfo.pDependencies = dependencies.data();
VkResult result = vkCreateRenderPass(*device.getDevice(), &renderPassInfo, nullptr, &mainRenderPass);
vkTools::checkVkresult(result, "FTC RenderPass");
if (result == VK_SUCCESS) {
std::cout << "successfully created MainRenderPass \n";
}
FrameBufferCreation :
frameBufferAttachments.resize(presentationEngine.getImageCount());
for(int i=0;i<frameBufferAttachments.size();i++)
createAttachments(presentationEngine.getSwapChainFormat(), VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,&frameBufferAttachments[i]);
size_t imageCount = presentationEngine.getImageViews().size();
mainFrameBuffers.resize(imageCount);
VkBool32 frameBufferCreation = VK_FALSE;
for (size_t i = 0; i < imageCount; i++) {
std::array<VkImageView, 3> attachments = { presentationEngine.getImageViews()[i],frameBufferAttachments[i].view, depthResource.view };
VkFramebufferCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
createInfo.renderPass = mainRenderPass;
createInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
createInfo.pAttachments = attachments.data();
createInfo.layers = 1;
createInfo.width = WIDTH;
createInfo.height = HEIGHT;
VkResult result = vkCreateFramebuffer(*device.getDevice(), &createInfo, nullptr, &mainFrameBuffers[i]);
vkTools::checkVkresult(result, "FTC Main FrameBuffers\n");
frameBufferCreation += result;
}
if (frameBufferCreation == 0)std::cout << "Successfully created MainFrameBuffers " << "\n";
drawCommand:
for (int i = 0; i < cmdBuffers.size(); i++) {
VkCommandBufferBeginInfo beginInfo{};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
VkResult result = vkBeginCommandBuffer(cmdBuffers[i], &beginInfo);
vkTools::checkVkresult(result, "Failed to Begin cmdBuffer\n");
VkRenderPassBeginInfo renderPassInfo{};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassInfo.renderPass = mainRenderPass;
renderPassInfo.framebuffer = mainFrameBuffers[i];
renderPassInfo.renderArea.offset = { 0,0 };
renderPassInfo.renderArea.extent = presentationEngine.getExtent();
std::array<VkClearValue, 3> clearValues = {};
clearValues[0].color = { .1f, .1f, .1f, 1.f };
clearValues[1].color = { .4f, .1f, .1f, 1.f };
clearValues[2].depthStencil = { 1.0f, 0 };
renderPassInfo.clearValueCount = static_cast<uint32_t>(clearValues.size());
renderPassInfo.pClearValues = clearValues.data();
vkCmdBeginRenderPass(cmdBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
VkViewport viewport = {};
viewport.height = HEIGHT;
viewport.width = WIDTH;
viewport.maxDepth = 1.0f;
VkRect2D rect = {};
rect.extent.width = WIDTH;
rect.extent.height = HEIGHT;
rect.offset = { 0,0 };
vkCmdSetViewport(cmdBuffers[i], 0, 1, &viewport);
vkCmdSetScissor(cmdBuffers[i], 0, 1, &rect);
for (int j = 0; j < sceneGraph->root->childs.size(); j++) {
Entity *node = sceneGraph->root->childs[j].get()->entity.get();
switch (node->getPipelineType()) {
case NONE:
break;
case COOK_TORRANCE1:
node->draw(cmdBuffers[i], cookTorrance1, i, lightDescriptorSets);
break;
case COOK_TORRANCE2:
node->draw(cmdBuffers[i], cookTorrance2, i, lightDescriptorSets);
break;
case DUMMY:
node->draw(cmdBuffers[i], dummyPipeline, i, lightDescriptorSets);
break;
}
}
vkCmdNextSubpass(cmdBuffers[i], VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(cmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, toneMapPipeline.pipeline);
vkCmdBindDescriptorSets(cmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, toneMapPipeline.pipelinelayout, 0, 1, &toneMapDescriptorSets[i], 0, NULL);
vkCmdDraw(cmdBuffers[i], 3, 1, 0, 0);
vkCmdEndRenderPass(cmdBuffers[i]);
if (vkEndCommandBuffer(cmdBuffers[i]) != VK_SUCCESS) {
std::cout << "Failed to record CommandBuffer\n";
}
}
toneMapPipeline.pipeline shader (not any tonemapping yet) :
#version 450
layout (input_attachment_index = 0, binding = 0) uniform subpassInput inputColor;
layout (input_attachment_index = 1, binding = 1) uniform subpassInput inputDepth;
layout(set = 0,binding = 2) uniform UniformBufferObject{
float exposure;
}ubo;
layout (location = 0 ) out vec4 outColor ;
void main() {
vec3 color = subpassLoad(inputColor).rgb;
outColor =vec4(color,1);
}