Framebuffer-attachment is being cleared, but not drawn to

I’m about to write a G-Buffer in Vulkan. As of now, I got two attachments in the framebuffer and render pass: albedo and depth. Albedo has index 0 and depth index 1.
Now, I’m trying to add another attachment for the world-space position. So albedo still has index 0, position now has index 1 and depth index 2. The albedo attachment still works as usual, e.g. my scene is being drawn into that attachment and depth testing is working. But the position attachment isn’t working as expected. Although the attachment is being cleared at the beginning of the render pass, nothing is being drawn into that attachment. I checked the examples by Sascha Willems for clues, but didn’t find any.

Here is my MRT fragment shader:

#version 450
#extension GL_ARB_separate_shader_objects : enable

layout(set = 1, binding = 0) uniform sampler2D diffuse;
layout(set = 1, binding = 1) uniform sampler2D normal;
layout(set = 1, binding = 2) uniform sampler2D specular;
layout(set = 1, binding = 3) uniform sampler2D emissive;

layout(location = 0) in vec2 texCoord;
layout(location = 1) in vec3 modelPosition;
layout(location = 2) in vec3 modelNormal;

layout(location = 0) out vec4 outDiffuse;
layout(location = 1) out vec4 outPosition;

void main() {
    outDiffuse = vec4(texture(diffuse, texCoord).rgb, 1.0);
	outPosition = vec4(texture(diffuse, texCoord).rgb, 1.0);
}

So I’m expecting the same image in the position attachment as in the albedo/diffuse attachment.
Here is the code where I’m creating the render pass (the formats and layouts are there for testing purposes):

std::vector<VkAttachmentReference> colorAttachmentRefs;

// diffuse
VkAttachmentDescription diffuseAttachment = {};
diffuseAttachment.format				= VK_FORMAT_R8G8B8A8_UNORM;
diffuseAttachment.samples				= VK_SAMPLE_COUNT_1_BIT;
diffuseAttachment.loadOp				= VK_ATTACHMENT_LOAD_OP_CLEAR;
diffuseAttachment.storeOp				= VK_ATTACHMENT_STORE_OP_STORE;
diffuseAttachment.stencilLoadOp			= VK_ATTACHMENT_LOAD_OP_DONT_CARE;
diffuseAttachment.stencilStoreOp		= VK_ATTACHMENT_STORE_OP_DONT_CARE;
diffuseAttachment.initialLayout			= VK_IMAGE_LAYOUT_UNDEFINED;
diffuseAttachment.finalLayout			= VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
attachments.push_back(diffuseAttachment);

VkAttachmentReference diffuseAttachmentRef = {};
diffuseAttachmentRef.attachment			= GBUFFER_ATTACHMENT_DIFFUSE;
diffuseAttachmentRef.layout				= VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
colorAttachmentRefs.push_back(diffuseAttachmentRef);

VkAttachmentDescription positionAttachment = {};
positionAttachment.format				= VK_FORMAT_R8G8B8A8_UNORM;
positionAttachment.samples				= VK_SAMPLE_COUNT_1_BIT;
positionAttachment.loadOp				= VK_ATTACHMENT_LOAD_OP_CLEAR;
positionAttachment.storeOp				= VK_ATTACHMENT_STORE_OP_STORE;
positionAttachment.stencilLoadOp		= VK_ATTACHMENT_LOAD_OP_DONT_CARE;
positionAttachment.stencilStoreOp		= VK_ATTACHMENT_STORE_OP_DONT_CARE;
positionAttachment.initialLayout		= VK_IMAGE_LAYOUT_UNDEFINED;
positionAttachment.finalLayout			= VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
attachments.push_back(positionAttachment);

VkAttachmentReference positionAttachmentRef = {};
positionAttachmentRef.attachment		= GBUFFER_ATTACHMENT_POSITION;
positionAttachmentRef.layout			= VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
colorAttachmentRefs.push_back(positionAttachmentRef);

// depth
VkAttachmentDescription depthAttachment = {};
depthAttachment.format				= VK_FORMAT_D24_UNORM_S8_UINT;
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_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
depthAttachment.finalLayout			= VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
attachments.push_back(depthAttachment);

VkAttachmentReference depthAttachmentRef = {};
depthAttachmentRef.attachment		= GBUFFER_ATTACHMENT_DEPTH;
depthAttachmentRef.layout			= VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;

VkSubpassDependency dependencies[2] = {};

dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
dependencies[0].dstSubpass = 0;
dependencies[0].srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[0].srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;

dependencies[1].srcSubpass = 0;													
dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL;								
dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[1].dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[1].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;

VkSubpassDescription subPass		= {};
subPass.pipelineBindPoint			= VK_PIPELINE_BIND_POINT_GRAPHICS;
subPass.colorAttachmentCount		= colorAttachmentRefs.size();
subPass.pColorAttachments			= colorAttachmentRefs.data();
subPass.pDepthStencilAttachment		= &depthAttachmentRef;

VkRenderPassCreateInfo renderPassInfo = {};
renderPassInfo.sType				= VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassInfo.attachmentCount		= attachments.size();
renderPassInfo.pAttachments			= attachments.data();
renderPassInfo.subpassCount			= 1;
renderPassInfo.pSubpasses			= &subPass;
renderPassInfo.dependencyCount = 2;
renderPassInfo.pDependencies = dependencies;

if(vkCreateRenderPass(_vulkanCommon->device, &renderPassInfo, nullptr, &renderPass) != VK_SUCCESS){
	log::error("could not create render pass.");
    return false;
}

“GBUFFER_ATTACHMENT_POSITION” is 1.

Do you guys have any clue why that attachment is being cleared, but now drawn to? Did I forget something?

Renderpass looks fine at first sight, so the problem may be located somewhere else. Did you adjust the number of color blend attachment states for the pipeline? If your pipeline is missing a color blend state for your new attachment, the write mask defaults to 0x0 which could explain why you can clear but don’t see anything rendered to that attachment. Just a guess, but that’s exactly what happened when I wrote my first G-Buffer example using MRT with Vulkan.

Thank you very much, that was exactly it. :smiley: