VkCmdPipelineBarrier()不能转换图像布局的情况可能是什么

时间:2019-02-10 22:59:52

标签: c++ graphics vulkan

我正在尝试从交换链中提取图像并进行转换,以便可以从中创建视频。

我正在尝试使用一次性提交命令缓冲区转换图像布局。将命令缓冲区提交到队列后,我从验证层收到警告和错误,提示图像布局格式错误,但是我已经使用所有正确的参数明确设置了流水线障碍。

即使当我为对象过渡纹理布局时,也会发生这种情况,但是即使有这些警告,一切也都可以正常工作。由于此错误,我无法读取提取图像的内容。

这可能是什么原因?这是我转换布局的方法:

VkCommandBuffer cmdBuffer = commandBuffer == VK_NULL_HANDLE ? 
                            CommandBufferHandler::createOneTimeUsageBuffer(commandPool, device) : commandBuffer;
VkImageMemoryBarrier barrier = {};
VkPipelineStageFlags sourceStage = {};
VkPipelineStageFlags dstStage = {};

barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.oldLayout = oldLayout;
barrier.newLayout = newLayout;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = image;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = mipLevels;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 1;

if (newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
    barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;

    if (hasStencilComponent(format)) {
        barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
    }
}
else {
    barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
}

if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
    barrier.srcAccessMask = 0;
    barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;

    sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
    dstStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
    barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
    barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;

    sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
    dstStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
    barrier.srcAccessMask = 0;
    barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;

    sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
    dstStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
    barrier.srcAccessMask = 0;
    barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
    sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
    dstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR && newLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) {
    barrier.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;;
    barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
    sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
    dstStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) {
    barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
    barrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
    sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
    dstStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_GENERAL) {
    barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
    barrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
    sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
    dstStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
}
else {
    throw std::invalid_argument("unsupported layout transition!");
}

vkCmdPipelineBarrier(cmdBuffer, sourceStage, dstStage, 0, 0, nullptr, 0, nullptr, 1, &barrier);

if (commandBuffer == VK_NULL_HANDLE) {
    CommandBufferHandler::endOneTimeUsageBuffer(cmdBuffer, queue, commandPool, device);
}

这是我捕获图像的方式:

VkImageCreateInfo screenshotCreateInfo;
VkImage srcImage = images[activeImageSwapchainId];
VkDeviceMemory dstImageMemory;
VkImage dstImage = VK_NULL_HANDLE;

if (supportsBlit) {
    VkCommandBuffer cmdBuffer = CommandBufferHandler::createOneTimeUsageBuffer(
        mainWindow->getCommandHandler()->getCommandPool(), mainWindow->getRenderer()->getDevice());

    Util::createImage(sizeX, sizeY, 1, VK_FORMAT_B8G8R8A8_UNORM,
        VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
        &dstImage, &dstImageMemory, mainWindow->getRenderer()->getDevice(),
        mainWindow->getRenderer()->getPhysicalDeviceMemoryPropertiesPTR());

    Util::transitionImageLayout(dstImage,
        VK_FORMAT_B8G8R8A8_UNORM,
        VK_IMAGE_LAYOUT_UNDEFINED,
        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
        mainWindow->getCommandHandler()->getCommandPool(),
        mainWindow->getRenderer()->getQueueIndices()->getQueue(),
        mainWindow->getRenderer()->getDevice(),
        1,
        cmdBuffer);

    Util::transitionImageLayout(srcImage,
        VK_FORMAT_B8G8R8A8_UNORM,
        VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
        VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
        mainWindow->getCommandHandler()->getCommandPool(),
        mainWindow->getRenderer()->getQueueIndices()->getQueue(),
        mainWindow->getRenderer()->getDevice(),
        1,
        cmdBuffer);


    VkOffset3D offsets{};
    offsets.x = swapExtent.width;
    offsets.y = swapExtent.height;
    offsets.z = 1;

    VkImageBlit blit{};
    blit.srcSubresource.layerCount = 1;
    blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
    blit.dstSubresource.layerCount = 1;
    blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
    blit.srcOffsets[1] = offsets;
    blit.dstOffsets[1] = offsets;

    vkCmdBlitImage(cmdBuffer,
        srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
        dstImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
        1, &blit, VK_FILTER_NEAREST);

    Util::transitionImageLayout(dstImage, VK_FORMAT_B8G8R8A8_UNORM,
        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL,
        mainWindow->getCommandHandler()->getCommandPool(),
        mainWindow->getRenderer()->getQueueIndices()->getQueue(),
        mainWindow->getRenderer()->getDevice(),
        1,
        cmdBuffer);

    Util::transitionImageLayout(srcImage, VK_FORMAT_B8G8R8A8_UNORM,
        VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
        mainWindow->getCommandHandler()->getCommandPool(),
        mainWindow->getRenderer()->getQueueIndices()->getQueue(),
        mainWindow->getRenderer()->getDevice(),
        1,
        cmdBuffer);

    CommandBufferHandler::endOneTimeUsageBuffer(cmdBuffer, mainWindow->getRenderer()->getQueueIndices()->getQueue(),
        mainWindow->getCommandHandler()->getCommandPool(), mainWindow->getRenderer()->getDevice());

    VkImageSubresource subresource{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 0 };
    VkSubresourceLayout subresourceLayout;
    vkGetImageSubresourceLayout(mainWindow->getRenderer()->getDevice(), dstImage, &subresource, &subresourceLayout);

    const char *data = nullptr;
    vkMapMemory(mainWindow->getRenderer()->getDevice(), dstImageMemory, 0, VK_WHOLE_SIZE, 0, (void**)&data);
    data += subresourceLayout.offset;

    std::ofstream file(filePath, std::ios::out | std::ios::binary);
    file << "P6\n" << swapExtent.width << "\n" << swapExtent.height << "\n" << 255 << "\n";     //File header

    for (uint32_t y = 0; y < swapExtent.height; ++y) {
        unsigned int *row = (unsigned int*)data;

        for (uint32_t x = 0; x < swapExtent.width; ++x) {
            file.write((char*)row, 3);
            row++;
        }

        data += subresourceLayout.rowPitch;
    }

    file.close();

    std::cout << "Screenshot saved to: " << filePath << std::endl;

    vkUnmapMemory(mainWindow->getRenderer()->getDevice(), dstImageMemory);
    vkFreeMemory(mainWindow->getRenderer()->getDevice(), dstImageMemory, nullptr);
    vkDestroyImage(mainWindow->getRenderer()->getDevice(), dstImage, nullptr);
}
else {
    assert(0 && "Swapchain error: Your device does not support image blitting. Cannot save image. Will be patched.");
    return;
}

警告如下图所示。所有其他警告来自我的图像布局未转换。

Mip levels are 0-9

使用blit时,出现此错误。我正在创建dstImage格式的VK_FORMAT_R8G8B8A8_UNORM

1 个答案:

答案 0 :(得分:0)

我得到的警告与尝试提取图像无关。他们来自尝试为我的对象创建纹理mipmap。那是我没有解决的问题。

我解决的是此发短信错误。我只是避免使用它,而是使用vkCmdCopyImage()。方法如下:

void Swapchain::saveScreenshot(std::string filePath) {
    VkImageCreateInfo screenshotCreateInfo;
    VkImage srcImage = images[activeImageSwapchainId];
    VkDeviceMemory dstImageMemory;
    VkImage dstImage = VK_NULL_HANDLE;

    if (supportsBlit) {
        VkCommandBuffer cmdBuffer = CommandBufferHandler::createOneTimeUsageBuffer(
            mainWindow->getCommandHandler()->getCommandPool(), mainWindow->getRenderer()->getDevice());

        Util::createImage(sizeX, sizeY, 1, VK_FORMAT_R8G8B8A8_UNORM,
            VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
            &dstImage, &dstImageMemory, mainWindow->getRenderer()->getDevice(),
            mainWindow->getRenderer()->getPhysicalDeviceMemoryPropertiesPTR());

        //NOVU Sliku prebacujemo u transfer destination
        Util::transitionImageLayout(dstImage,
            VK_FORMAT_R8G8B8A8_UNORM,
            VK_IMAGE_LAYOUT_UNDEFINED,
            VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
            mainWindow->getCommandHandler()->getCommandPool(),
            mainWindow->getRenderer()->getQueueIndices()->getQueue(),
            mainWindow->getRenderer()->getDevice(),
            1,
            cmdBuffer);

        //Staru sliku prebacujemo iz prezentacije u transfer source
        Util::transitionImageLayout(srcImage,
            VK_FORMAT_R8G8B8A8_UNORM,
            VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
            VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
            mainWindow->getCommandHandler()->getCommandPool(),
            mainWindow->getRenderer()->getQueueIndices()->getQueue(),
            mainWindow->getRenderer()->getDevice(),
            1,
            cmdBuffer);

        VkExtent3D extent = { swapExtent.width, swapExtent.height, 1 };
        VkOffset3D offsets{};
        offsets.x = 0;
        offsets.y = 0;
        offsets.z = 0;

        VkImageSubresourceLayers layers{};
        layers.mipLevel = 0;
        layers.layerCount = 1;
        layers.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
        layers.baseArrayLayer = 0;

        VkImageCopy regions{};
        regions.dstOffset = offsets;
        regions.extent = extent;
        regions.srcOffset = offsets;
        regions.srcSubresource = layers;
        regions.dstSubresource = layers;

        vkCmdCopyImage(cmdBuffer,
            srcImage,
            VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
            dstImage,
            VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
            1,
            &regions);

        Util::transitionImageLayout(dstImage, VK_FORMAT_R8G8B8A8_UNORM,
            VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL,
            mainWindow->getCommandHandler()->getCommandPool(),
            mainWindow->getRenderer()->getQueueIndices()->getQueue(),
            mainWindow->getRenderer()->getDevice(),
            1,
            cmdBuffer);

        Util::transitionImageLayout(srcImage, VK_FORMAT_R8G8B8A8_UNORM,
            VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
            mainWindow->getCommandHandler()->getCommandPool(),
            mainWindow->getRenderer()->getQueueIndices()->getQueue(),
            mainWindow->getRenderer()->getDevice(),
            1,
            cmdBuffer);

        CommandBufferHandler::endOneTimeUsageBuffer(cmdBuffer, mainWindow->getRenderer()->getQueueIndices()->getQueue(),
            mainWindow->getCommandHandler()->getCommandPool(), mainWindow->getRenderer()->getDevice());

        unsigned char *data = nullptr;
        vkMapMemory(mainWindow->getRenderer()->getDevice(), dstImageMemory, 0, VK_WHOLE_SIZE, 0, (void**)&data);

        MagickCore::MagickWand *wand = MagickCore::NewMagickWand();
        MagickConstituteImage(wand, swapExtent.width, swapExtent.height, "BGRA", MagickCore::CharPixel, data);

        vkUnmapMemory(mainWindow->getRenderer()->getDevice(), dstImageMemory);
        vkFreeMemory(mainWindow->getRenderer()->getDevice(), dstImageMemory, nullptr);
        vkDestroyImage(mainWindow->getRenderer()->getDevice(), dstImage, nullptr);

        MagickCore::MagickBooleanType status = MagickWriteImage(wand, filePath.c_str());

        if (!status) {
            assert(0 && "ImageMagick error: Unable to save image to file.");
        }

        MagickCore::DestroyMagickWand(wand);
        MagickCore::MagickWandTerminus();
    }
    else {
        assert(0 && "Swapchain error: Your device does not support image blitting. Cannot save image. Will be patched.");
        return;
    }

}