我正在尝试从交换链中提取图像并进行转换,以便可以从中创建视频。
我正在尝试使用一次性提交命令缓冲区转换图像布局。将命令缓冲区提交到队列后,我从验证层收到警告和错误,提示图像布局格式错误,但是我已经使用所有正确的参数明确设置了流水线障碍。
即使当我为对象过渡纹理布局时,也会发生这种情况,但是即使有这些警告,一切也都可以正常工作。由于此错误,我无法读取提取图像的内容。
这可能是什么原因?这是我转换布局的方法:
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;
}
警告如下图所示。所有其他警告来自我的图像布局未转换。
使用blit时,出现此错误。我正在创建dstImage
格式的VK_FORMAT_R8G8B8A8_UNORM
。
答案 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,
®ions);
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;
}
}