I am building a rendering in Vulkan using C++. I have been running into issues implementing subpasses in the renderer to split lighting into a separate subpass. The issue suggests a problem with dependencies where it is expecting a different image layout than the one transitioned to for the second pass. However, I believe the issue may be in the shaders where I may not be using the correct vertex shader for the second pass. Can you please look at the shaders and suggest new code for the lighting vertex shader if required? Also update any other code from the engine as needed. Here is the code for the shaders:

Geometry Vertex Shader:

#version 450

layout(binding = 0) buffer ModelBufferObject {
    mat4 models[];
} modelUBO;

layout(binding = 1) uniform ViewBufferObject {
    mat4 view;
} viewUBO;

layout(binding = 2) uniform ProjBufferObject {
    mat4 proj;
} projUBO;

layout(location = 0) in vec3 inPosition;
layout(location = 1) in vec3 inColor;
layout(location = 2) in vec2 inTexCoord;
layout(location = 3) in vec3 inNormal;

layout(location = 0) out vec3 fragPosition;
layout(location = 1) out vec3 fragNormal;
layout(location = 2) out vec3 fragColor;
layout(location = 3) out vec2 fragTexCoord;

void main() {
    mat4 model = modelUBO.models[gl_InstanceIndex]; // Use the model matrix for the current instance
    gl_Position = projUBO.proj * viewUBO.view * model * vec4(inPosition, 1.0);
    fragPosition = vec3(model * vec4(inPosition, 1.0));
    fragNormal = normalize(mat3(transpose(inverse(model))) * inNormal);
    fragColor = inColor;
    fragTexCoord = inTexCoord;
}

Geometry Fragment Shader:

#version 450

layout(location = 0) in vec3 fragPosition;
layout(location = 1) in vec3 fragNormal;
layout(location = 2) in vec3 fragColor;
layout(location = 3) in vec2 fragTexCoord;

layout(binding = 3) uniform sampler2D texSampler;

layout(location = 0) out vec4 gPosition;
layout(location = 1) out vec4 gNormal;
layout(location = 2) out vec4 gAlbedo;

void main() {
    gPosition = vec4(fragPosition, 1.0);
    gNormal = vec4(fragNormal, 1.0);
    gAlbedo = texture(texSampler, fragTexCoord) * vec4(fragColor, 1.0);
}

Lighting Vertex Shader:

#version 450

layout(binding = 0) buffer ModelBufferObject {
    mat4 models[];
} modelUBO;

layout(binding = 1) uniform ViewBufferObject {
    mat4 view;
} viewUBO;

layout(binding = 2) uniform ProjBufferObject {
    mat4 proj;
} projUBO;

layout(location = 0) in vec3 inPosition;
layout(location = 1) in vec3 inColor;
layout(location = 2) in vec2 inTexCoord;
layout(location = 3) in vec3 inNormal;

layout(location = 0) out vec3 fragPosition;
layout(location = 1) out vec3 fragNormal;
layout(location = 2) out vec3 fragColor;
layout(location = 3) out vec2 fragTexCoord;

void main() {
    mat4 model = modelUBO.models[gl_InstanceIndex]; // Use the model matrix for the current instance
    gl_Position = projUBO.proj * viewUBO.view * model * vec4(inPosition, 1.0);
    fragPosition = vec3(model * vec4(inPosition, 1.0));
    fragNormal = normalize(mat3(transpose(inverse(model))) * inNormal);
    fragColor = inColor;
    fragTexCoord = inTexCoord;
}

Lighting Fragment Shader:

#version 450

layout(location = 0) out vec4 outColor;

layout(binding = 3) uniform sampler2D gPosition;
layout(binding = 4) uniform sampler2D gNormal;
layout(binding = 5) uniform sampler2D gAlbedo;

layout(location = 0) in vec3 fragPosition;
layout(location = 1) in vec3 fragNormal;
layout(location = 2) in vec3 fragColor;
layout(location = 3) in vec2 fragTexCoord;

layout(set = 0, binding = 6) uniform Ambient_Data {
    vec3 color;
    float intensity;
} ambient;

layout(set = 0, binding = 7) uniform Directional_Data {
    vec3 position;
    vec3 color;
    float intensity;
} directional;

void main() {
    vec3 fragPosition = texture(gPosition, fragTexCoord).xyz;
    vec3 fragNormal = normalize(texture(gNormal, fragTexCoord).xyz);
    vec3 fragAlbedo = texture(gAlbedo, fragTexCoord).rgb;

    vec3 ambientLight = ambient.intensity * ambient.color;

    vec3 lightDir = normalize(directional.position - fragPosition);
    float diff = max(dot(fragNormal, lightDir), 0.0);
    vec3 diffuse = diff * directional.color;

    outColor = vec4((ambientLight + diffuse) * fragAlbedo, 1.0);
}

Here is some of the relevant code from the rendering engine:

void Renderer::CreateRenderPass()
{
    vk::AttachmentDescription positionAttachment{};
    positionAttachment.format = vk::Format::eR16G16B16A16Sfloat; // High precision format
    positionAttachment.samples = vk::SampleCountFlagBits::e1;
    positionAttachment.loadOp = vk::AttachmentLoadOp::eClear;
    positionAttachment.storeOp = vk::AttachmentStoreOp::eStore;
    positionAttachment.initialLayout = vk::ImageLayout::eUndefined;
    positionAttachment.finalLayout = vk::ImageLayout::eShaderReadOnlyOptimal;

    vk::AttachmentDescription normalAttachment = positionAttachment;
    normalAttachment.format = vk::Format::eR16G16B16A16Sfloat;

    vk::AttachmentDescription albedoAttachment = positionAttachment;
    albedoAttachment.format = swapChainImageFormat;

    vk::AttachmentDescription depthAttachment = positionAttachment;
    depthAttachment.format = FindDepthFormat(*GetPhysicalDevice());
    depthAttachment.samples = msaaSamples;
    depthAttachment.finalLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal;

    //vk::AttachmentDescription colorAttachmentResolve = albedoAttachment;

    vk::AttachmentDescription colorAttachmentResolve{};
    colorAttachmentResolve.format = swapChainImageFormat;
    colorAttachmentResolve.samples = vk::SampleCountFlagBits::e1;
    colorAttachmentResolve.loadOp = vk::AttachmentLoadOp::eClear;
    colorAttachmentResolve.storeOp = vk::AttachmentStoreOp::eStore;
    colorAttachmentResolve.stencilLoadOp = vk::AttachmentLoadOp::eDontCare;
    colorAttachmentResolve.stencilStoreOp = vk::AttachmentStoreOp::eDontCare;
    colorAttachmentResolve.initialLayout = vk::ImageLayout::eUndefined;
    colorAttachmentResolve.finalLayout = vk::ImageLayout::ePresentSrcKHR;

    std::array<vk::AttachmentDescription, 5> attachments = {
        positionAttachment, normalAttachment, albedoAttachment, depthAttachment, colorAttachmentResolve
    };

    vk::AttachmentReference positionAttachmentRef{};
    positionAttachmentRef.attachment = 0;
    positionAttachmentRef.layout = vk::ImageLayout::eColorAttachmentOptimal;

    vk::AttachmentReference normalAttachmentRef{};
    normalAttachmentRef.attachment = 1;
    normalAttachmentRef.layout = vk::ImageLayout::eColorAttachmentOptimal;

    vk::AttachmentReference albedoAttachmentRef{};
    albedoAttachmentRef.attachment = 2;
    albedoAttachmentRef.layout = vk::ImageLayout::eColorAttachmentOptimal;

    vk::AttachmentReference depthAttachmentRef{};
    depthAttachmentRef.attachment = 3;
    depthAttachmentRef.layout = vk::ImageLayout::eDepthStencilAttachmentOptimal;

    vk::AttachmentReference colorAttachmentResolveRef{};
    colorAttachmentResolveRef.attachment = 4;
    colorAttachmentResolveRef.layout = vk::ImageLayout::eColorAttachmentOptimal;

    std::array<vk::AttachmentReference, 3> colorAttachments = {
        positionAttachmentRef, normalAttachmentRef, albedoAttachmentRef
    };

    vk::SubpassDescription geometryPass{};
    geometryPass.pipelineBindPoint = vk::PipelineBindPoint::eGraphics;
    geometryPass.colorAttachmentCount = static_cast<uint32_t>(colorAttachments.size());
    geometryPass.pColorAttachments = colorAttachments.data();
    geometryPass.pDepthStencilAttachment = &depthAttachmentRef;

    vk::AttachmentReference depthAttachmentResolveRef{};
    depthAttachmentResolveRef.attachment = 3; // Index of the depth attachment in the attachments array
    depthAttachmentResolveRef.layout = vk::ImageLayout::eDepthStencilAttachmentOptimal;

    vk::AttachmentReference colorAttachmentFinalRef{};
    colorAttachmentFinalRef.attachment = 4;
    colorAttachmentFinalRef.layout = vk::ImageLayout::eColorAttachmentOptimal;

    vk::SubpassDescription lightingPass{};
    lightingPass.pipelineBindPoint = vk::PipelineBindPoint::eGraphics;
    lightingPass.colorAttachmentCount = 1;
    lightingPass.pColorAttachments = &colorAttachmentFinalRef;

    std::array<vk::SubpassDescription, 2> subpasses = { geometryPass, lightingPass };

    // Define subpass dependencies
    vk::SubpassDependency externalToGeometryDependency{};
    externalToGeometryDependency.srcSubpass = VK_SUBPASS_EXTERNAL;
    externalToGeometryDependency.dstSubpass = 0;
    externalToGeometryDependency.srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput;
    externalToGeometryDependency.dstStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput;
    externalToGeometryDependency.srcAccessMask = {};
    externalToGeometryDependency.dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite;

    vk::SubpassDependency geometryToLightingDependency{};
    geometryToLightingDependency.srcSubpass = 0;
    geometryToLightingDependency.dstSubpass = 1;
    geometryToLightingDependency.srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput;
    geometryToLightingDependency.dstStageMask = vk::PipelineStageFlagBits::eFragmentShader;
    geometryToLightingDependency.srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite;
    geometryToLightingDependency.dstAccessMask = vk::AccessFlagBits::eShaderRead;
    geometryToLightingDependency.dependencyFlags = vk::DependencyFlagBits::eByRegion;

    vk::SubpassDependency geometryToLightingDepthDependency{};
    geometryToLightingDepthDependency.srcSubpass = 0;
    geometryToLightingDepthDependency.dstSubpass = 1;
    geometryToLightingDepthDependency.srcStageMask = vk::PipelineStageFlagBits::eEarlyFragmentTests | vk::PipelineStageFlagBits::eLateFragmentTests;
    geometryToLightingDepthDependency.dstStageMask = vk::PipelineStageFlagBits::eFragmentShader;
    geometryToLightingDepthDependency.srcAccessMask = vk::AccessFlagBits::eDepthStencilAttachmentWrite;
    geometryToLightingDepthDependency.dstAccessMask = vk::AccessFlagBits::eShaderRead;
    geometryToLightingDepthDependency.dependencyFlags = vk::DependencyFlagBits::eByRegion;

    std::array<vk::SubpassDependency, 3> dependencies = {
        externalToGeometryDependency,
        geometryToLightingDependency,
        geometryToLightingDepthDependency
    };

    vk::RenderPassCreateInfo renderPassInfo{};
    renderPassInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
    renderPassInfo.pAttachments = attachments.data();
    renderPassInfo.subpassCount = static_cast<uint32_t>(subpasses.size());
    renderPassInfo.pSubpasses = subpasses.data();
    renderPassInfo.dependencyCount = static_cast<uint32_t>(dependencies.size());
    renderPassInfo.pDependencies = dependencies.data();// &dependency;

    if (device.createRenderPass(&renderPassInfo, nullptr, &renderPass) != vk::Result::eSuccess)
    {
        throw std::runtime_error("Failed to create render pass.");
    }
}

RenderLoop:

VkDescriptorSet geomSet = this->geomdescriptorSet.get();
	vkCmdBindPipeline(*renderer.GetCurrentCommandBuffer(), VK_PIPELINE_BIND_POINT_GRAPHICS, renderer.GetPipeline(0).get()->GetPipeline());
	vkCmdBindDescriptorSets(*renderer.GetCurrentCommandBuffer(), VK_PIPELINE_BIND_POINT_GRAPHICS, geompipelineLayout, 0, 1, &geomSet, 0, nullptr);

	uint32_t numIndices4 = static_cast<uint32_t>(meshes[0].get()->GetIndices().size());
	vkCmdDrawIndexed(*renderer.GetCurrentCommandBuffer(), numIndices4, modelcount, 0, 0, 0);

	renderer.GetCurrentCommandBuffer()->nextSubpass(vk::SubpassContents::eInline);

	VkDescriptorSet lightSet = this->lightdescriptorSet.get();
	vkCmdBindPipeline(*renderer.GetCurrentCommandBuffer(), VK_PIPELINE_BIND_POINT_GRAPHICS, renderer.GetPipeline(1).get()->GetPipeline());
	vkCmdBindDescriptorSets(*renderer.GetCurrentCommandBuffer(), VK_PIPELINE_BIND_POINT_GRAPHICS, lightpipelineLayout, 0, 1, &lightSet, 0, nullptr);

	renderer.GetCurrentCommandBuffer()->draw(3, 1, 0, 0);

void Engine::CreateGeomDescriptorSet(vk::Device device, std::vector<VkBuffer> buffers, vk::DeviceSize bufferSize, vk::UniqueDescriptorPool& descriptorPool, Texture* texture, vk::DescriptorSetLayout descriptorSetLayout) {
	vk::DescriptorSetAllocateInfo allocInfo{};
	allocInfo.setDescriptorPool(descriptorPool.get());
	allocInfo.setDescriptorSetCount(1);
	allocInfo.setPSetLayouts(&descriptorSetLayout);

	geomdescriptorSet = std::move(device.allocateDescriptorSetsUnique(allocInfo)[0]);

	if (!geomdescriptorSet) {
		throw std::runtime_error("Failed to allocate descriptor set!");
	}

	vk::DescriptorBufferInfo bufferInfo1{};
	bufferInfo1.buffer = buffers[0];
	bufferInfo1.offset = 0;
	bufferInfo1.range = bufferSize * modelcount;

	vk::DescriptorBufferInfo bufferInfo2{};
	bufferInfo2.buffer = buffers[1];
	bufferInfo2.offset = 0;
	bufferInfo2.range = bufferSize;

	vk::DescriptorBufferInfo bufferInfo3{};
	bufferInfo3.buffer = buffers[2];
	bufferInfo3.offset = 0;
	bufferInfo3.range = bufferSize;

	vk::DescriptorImageInfo imageInfo{};
	imageInfo.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
	imageInfo.imageView = texture->GetImageView();
	imageInfo.sampler = texture->GetSampler();


	std::array<vk::WriteDescriptorSet, 4> descriptorWrites{};

	descriptorWrites[0].setDstSet(geomdescriptorSet.get());
	descriptorWrites[0].setDstBinding(0);
	descriptorWrites[0].setDstArrayElement(0);
	descriptorWrites[0].setDescriptorType(vk::DescriptorType::eStorageBuffer);
	descriptorWrites[0].setDescriptorCount(1);
	descriptorWrites[0].setPBufferInfo(&bufferInfo1);

	descriptorWrites[1].setDstSet(geomdescriptorSet.get());
	descriptorWrites[1].setDstBinding(1);
	descriptorWrites[1].setDstArrayElement(0);
	descriptorWrites[1].setDescriptorType(vk::DescriptorType::eUniformBuffer);
	descriptorWrites[1].setDescriptorCount(1);
	descriptorWrites[1].setPBufferInfo(&bufferInfo2);

	descriptorWrites[2].setDstSet(geomdescriptorSet.get());
	descriptorWrites[2].setDstBinding(2);
	descriptorWrites[2].setDstArrayElement(0);
	descriptorWrites[2].setDescriptorType(vk::DescriptorType::eUniformBuffer);
	descriptorWrites[2].setDescriptorCount(1);
	descriptorWrites[2].setPBufferInfo(&bufferInfo3);

	descriptorWrites[3].setDstSet(geomdescriptorSet.get());
	descriptorWrites[3].setDstBinding(3);
	descriptorWrites[3].setDstArrayElement(0);
	descriptorWrites[3].setDescriptorType(vk::DescriptorType::eCombinedImageSampler);
	descriptorWrites[3].setDescriptorCount(1);
	descriptorWrites[3].setPImageInfo(&imageInfo);


	device.updateDescriptorSets(static_cast<uint32_t>(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr);
}


void Engine::CreateLightDescriptorSet(Renderer* renderer, vk::Device device, std::vector<VkBuffer> buffers, vk::DeviceSize bufferSize, vk::UniqueDescriptorPool& descriptorPool, Texture* texture, vk::DescriptorSetLayout descriptorSetLayout) {
	vk::DescriptorSetAllocateInfo allocInfo{};
	allocInfo.setDescriptorPool(descriptorPool.get());
	allocInfo.setDescriptorSetCount(1);
	allocInfo.setPSetLayouts(&descriptorSetLayout);

	lightdescriptorSet = std::move(device.allocateDescriptorSetsUnique(allocInfo)[0]);

	if (!lightdescriptorSet) {
		throw std::runtime_error("Failed to allocate descriptor set!");
	}

	vk::DescriptorBufferInfo bufferInfo1{};
	bufferInfo1.buffer = buffers[0];
	bufferInfo1.offset = 0;
	bufferInfo1.range = bufferSize * modelcount;

	vk::DescriptorBufferInfo bufferInfo2{};
	bufferInfo2.buffer = buffers[1];
	bufferInfo2.offset = 0;
	bufferInfo2.range = bufferSize;

	vk::DescriptorBufferInfo bufferInfo3{};
	bufferInfo3.buffer = buffers[2];
	bufferInfo3.offset = 0;
	bufferInfo3.range = bufferSize;

	vk::DescriptorImageInfo positionTextureInfo{};
	positionTextureInfo.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
	positionTextureInfo.imageView = renderer->positionImageView;//texture->GetImageView();
	positionTextureInfo.sampler = texture->GetSampler();

	vk::DescriptorImageInfo normalTextureInfo{};
	normalTextureInfo.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
	normalTextureInfo.imageView = renderer->normalImageView;// texture->GetImageView();
	normalTextureInfo.sampler = texture->GetSampler();

	vk::DescriptorImageInfo albedoTextureInfo{};
	albedoTextureInfo.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
	albedoTextureInfo.imageView = renderer->albedoImageView;// texture->GetImageView();
	albedoTextureInfo.sampler = texture->GetSampler();

	vk::DescriptorBufferInfo bufferInfo4{};
	bufferInfo4.buffer = buffers[3];
	bufferInfo4.offset = 0;
	bufferInfo4.range = sizeof(AmbientLight);

	vk::DescriptorBufferInfo bufferInfo5{};
	bufferInfo5.buffer = buffers[4];
	bufferInfo5.offset = 0;
	bufferInfo5.range = sizeof(DirectionalLight);




	std::array<vk::WriteDescriptorSet, 8> descriptorWrites{};

	descriptorWrites[0].setDstSet(lightdescriptorSet.get());
	descriptorWrites[0].setDstBinding(0);
	descriptorWrites[0].setDstArrayElement(0);
	descriptorWrites[0].setDescriptorType(vk::DescriptorType::eStorageBuffer);
	descriptorWrites[0].setDescriptorCount(1);
	descriptorWrites[0].setPBufferInfo(&bufferInfo1);

	descriptorWrites[1].setDstSet(lightdescriptorSet.get());
	descriptorWrites[1].setDstBinding(1);
	descriptorWrites[1].setDstArrayElement(0);
	descriptorWrites[1].setDescriptorType(vk::DescriptorType::eUniformBuffer);
	descriptorWrites[1].setDescriptorCount(1);
	descriptorWrites[1].setPBufferInfo(&bufferInfo2);

	descriptorWrites[2].setDstSet(lightdescriptorSet.get());
	descriptorWrites[2].setDstBinding(2);
	descriptorWrites[2].setDstArrayElement(0);
	descriptorWrites[2].setDescriptorType(vk::DescriptorType::eUniformBuffer);
	descriptorWrites[2].setDescriptorCount(1);
	descriptorWrites[2].setPBufferInfo(&bufferInfo3);

	descriptorWrites[3].setDstSet(lightdescriptorSet.get());
	descriptorWrites[3].setDstBinding(3);
	descriptorWrites[3].setDstArrayElement(0);
	descriptorWrites[3].setDescriptorType(vk::DescriptorType::eCombinedImageSampler);
	descriptorWrites[3].setDescriptorCount(1);
	descriptorWrites[3].setPImageInfo(&positionTextureInfo);

	descriptorWrites[4].setDstSet(lightdescriptorSet.get());
	descriptorWrites[4].setDstBinding(4);
	descriptorWrites[4].setDstArrayElement(0);
	descriptorWrites[4].setDescriptorType(vk::DescriptorType::eCombinedImageSampler);
	descriptorWrites[4].setDescriptorCount(1);
	descriptorWrites[4].setPImageInfo(&normalTextureInfo);

	descriptorWrites[5].setDstSet(lightdescriptorSet.get());
	descriptorWrites[5].setDstBinding(5);
	descriptorWrites[5].setDstArrayElement(0);
	descriptorWrites[5].setDescriptorType(vk::DescriptorType::eCombinedImageSampler);
	descriptorWrites[5].setDescriptorCount(1);
	descriptorWrites[5].setPImageInfo(&albedoTextureInfo);


	descriptorWrites[6].setDstSet(lightdescriptorSet.get());
	descriptorWrites[6].setDstBinding(6);
	descriptorWrites[6].setDstArrayElement(0);
	descriptorWrites[6].setDescriptorType(vk::DescriptorType::eUniformBuffer);
	descriptorWrites[6].setDescriptorCount(1);
	descriptorWrites[6].setPBufferInfo(&bufferInfo4);

	descriptorWrites[7].setDstSet(lightdescriptorSet.get());
	descriptorWrites[7].setDstBinding(7);
	descriptorWrites[7].setDstArrayElement(0);
	descriptorWrites[7].setDescriptorType(vk::DescriptorType::eUniformBuffer);
	descriptorWrites[7].setDescriptorCount(1);
	descriptorWrites[7].setPBufferInfo(&bufferInfo5);


	device.updateDescriptorSets(static_cast<uint32_t>(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr);
}