I am building a 3d renderer in C++ using Vulkan. I am using the C++ implementation of Vulkan. I've been trying to implement shadow mapping to my renderer. I've set up a separate render pass and command buffer to handle the shadow mapping and I have another render pass and command buffer to render the scene. I am no longer getting any validation errors when running the renderer. I am now trying to validate that the shadow mapping is working as intended by rendering the outputs to a texture within the scene. The transitions between the depth stencil and the output image are being handled using subpass dependencies in the shadow render pass. While testing the shadow mapping output, the resulting texture is now entirely red. Do you know what might be causing this problem?

Here is some of the code:

Shadow Render Pass:

vk::AttachmentDescription depthAttachment{};
    depthAttachment.format = FindDepthFormat(*GetPhysicalDevice()); // High precision format
    depthAttachment.samples = vk::SampleCountFlagBits::e1;
    depthAttachment.loadOp = vk::AttachmentLoadOp::eClear;
    depthAttachment.storeOp = vk::AttachmentStoreOp::eStore;
    depthAttachment.stencilLoadOp = vk::AttachmentLoadOp::eDontCare;
    depthAttachment.stencilStoreOp = vk::AttachmentStoreOp::eDontCare;
    depthAttachment.initialLayout = vk::ImageLayout::eUndefined;
    depthAttachment.finalLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal;

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

    vk::SubpassDescription subpass{};
    subpass.pipelineBindPoint = vk::PipelineBindPoint::eGraphics;
    subpass.colorAttachmentCount = 0;
    subpass.pDepthStencilAttachment = &depthAttachmentRef;

    // Use subpass dependencies for layout transitions
    std::array<vk::SubpassDependency, 2> dependencies;

    dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
    dependencies[0].dstSubpass = 0;
    dependencies[0].srcStageMask = vk::PipelineStageFlagBits::eFragmentShader;// VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
    dependencies[0].dstStageMask = vk::PipelineStageFlagBits::eEarlyFragmentTests;// VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
    dependencies[0].srcAccessMask = vk::AccessFlagBits::eShaderRead; //VK_ACCESS_SHADER_READ_BIT;
    dependencies[0].dstAccessMask = vk::AccessFlagBits::eDepthStencilAttachmentWrite; //VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
    dependencies[0].dependencyFlags = vk::DependencyFlagBits::eByRegion; //VK_DEPENDENCY_BY_REGION_BIT;

    dependencies[1].srcSubpass = 0;
    dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL;
    dependencies[1].srcStageMask = vk::PipelineStageFlagBits::eLateFragmentTests;// VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
    dependencies[1].dstStageMask = vk::PipelineStageFlagBits::eFragmentShader; //VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
    dependencies[1].srcAccessMask = vk::AccessFlagBits::eDepthStencilAttachmentWrite; //VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
    dependencies[1].dstAccessMask = vk::AccessFlagBits::eShaderRead;// VK_ACCESS_SHADER_READ_BIT;
    dependencies[1].dependencyFlags = vk::DependencyFlagBits::eByRegion;// VK_DEPENDENCY_BY_REGION_BIT;


    vk::RenderPassCreateInfo renderPassInfo{};
    renderPassInfo.attachmentCount = 1;
    renderPassInfo.pAttachments = &depthAttachment;
    renderPassInfo.subpassCount = 1;
    renderPassInfo.pSubpasses = &subpass;
    renderPassInfo.dependencyCount = static_cast<uint32_t>(dependencies.size());
    renderPassInfo.pDependencies = dependencies.data();

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


The Begin Shadow Frame:

// Wait for any previous work on this swapchain image to complete
    device.waitForFences(1, &inFlightFences[currentFrame], VK_TRUE, UINT64_MAX);
    device.resetFences(1, &inFlightFences[currentFrame]);

    // Acquire an image from the swapchain, then begin recording commands for the current frame.
    vk::Result acquireResult = device.acquireNextImageKHR(swapchain, UINT64_MAX, imageAvailableSemaphores[currentFrame], vk::Fence(), &imageIndex);

    if (acquireResult != vk::Result::eSuccess && acquireResult != vk::Result::eSuboptimalKHR) {
        throw std::runtime_error("Failed to acquire next swapchain image.");
    }

    vk::CommandBufferBeginInfo beginInfo{};
    beginInfo.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit;

    // Shadow Pass
    shadowCommandBuffers[0].begin(beginInfo);

    vk::RenderPassBeginInfo shadowPassInfo{};
    shadowPassInfo.renderPass = shadowRenderPass;
    shadowPassInfo.framebuffer = shadowFramebuffers[0];
    shadowPassInfo.renderArea.offset = vk::Offset2D{ 0, 0 };
    shadowPassInfo.renderArea.extent = vk::Extent2D(SHADOW_WIDTH, SHADOW_HEIGHT);

    vk::ClearValue shadowClearValue = { vk::ClearDepthStencilValue(1.0f, 0) };
    shadowPassInfo.clearValueCount = 1;
    shadowPassInfo.pClearValues = &shadowClearValue;

    shadowCommandBuffers[0].beginRenderPass(shadowPassInfo, vk::SubpassContents::eInline);
    // (Render scene from light perspective)

The End Shadow Frame:

    shadowCommandBuffers[0].endRenderPass();

    shadowCommandBuffers[0].end();

    vk::SubmitInfo shadowSubmitInfo{};
    shadowSubmitInfo.commandBufferCount = 1;
    shadowSubmitInfo.pCommandBuffers = &shadowCommandBuffers[0];

    vk::Semaphore waitSemaphores[] = { imageAvailableSemaphores[currentFrame] };
    vk::PipelineStageFlags waitStages[] = { vk::PipelineStageFlagBits::eColorAttachmentOutput };
    shadowSubmitInfo.waitSemaphoreCount = 1;
    shadowSubmitInfo.pWaitSemaphores = waitSemaphores;
    shadowSubmitInfo.pWaitDstStageMask = waitStages;

    vk::Semaphore signalSemaphores[] = { shadowMapCompletedSemaphore };
    shadowSubmitInfo.signalSemaphoreCount = 1;
    shadowSubmitInfo.pSignalSemaphores = signalSemaphores;

    graphicsQueue.submit(1, &shadowSubmitInfo, nullptr);

The Image creation:

        imageInfo.imageType = vk::ImageType::e2D;
        imageInfo.format = FindDepthFormat(*GetPhysicalDevice();
        imageInfo.extent = vk::Extent3D(SHADOW_WIDTH, SHADOW_HEIGHT, 1);
        imageInfo.mipLevels = 1;
        imageInfo.arrayLayers = 1;
        imageInfo.samples = vk::SampleCountFlagBits::e1;
        imageInfo.tiling = vk::ImageTiling::eOptimal;
        imageInfo.usage = vk::ImageUsageFlagBits::eDepthStencilAttachment | vk::ImageUsageFlagBits::eSampled;
        imageInfo.sharingMode = vk::SharingMode::eExclusive;