如何解决从 vulkan 帧缓冲区下载的图像失真
我正在使用 vulkan 进行离屏渲染。由于我在设备内存中获得了渲染图像,因此我将其下载到主机内存以用于其他目的。一切正常,直到图像宽度为 8 的倍数,否则图像会失真。
帧缓冲代码:
colorImageInfo = VkImageCreateInfo(
imageType=VK_IMAGE_TYPE_2D,format=VK_FORMAT_B8G8R8A8_UnorM,mipLevels=1,arrayLayers=1,samples=1,tiling=VK_IMAGE_TILING_OPTIMAL,usage=VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,initialLayout=VK_IMAGE_LAYOUT_UNDEFINED,extent=[self.width,self.height,1]
)
colorImage = vkCreateImage(self.inst.device,colorImageInfo,None)
self.colorImage = colorImage
memReqs = vkGetimageMemoryRequirements(self.inst.device,colorImage)
memReqs = cdh.cdata_dict(memReqs)
memProps = cdh.cdata_dict(self.inst.memoryProperties)
memoryType = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
typeBits = memReqs["memoryTypeBits"]
for i in range(32):
if (typeBits & 1) == 1:
if (memProps["memoryTypes"][i]["propertyFlags"] & memoryType) == memoryType:
memType = i
break
typeBits >>= 1
memAlLocinfo = VkMemoryAllocateInfo(
memoryTypeIndex=memType,allocationSize=memReqs["size"]
)
memAlloc = vkAllocateMemory(self.inst.device,memAlLocinfo,None)
# print(memAlloc)
vkBindImageMemory(self.inst.device,colorImage,memAlloc,0)
subresourceRange = VkImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT,1,1)
imageViewInfo = VkImageViewCreateInfo(
viewType=VK_IMAGE_VIEW_TYPE_2D,image=colorImage,subresourceRange=subresourceRange
)
colorImageView = vkCreateImageView(self.inst.device,imageViewInfo,None)
# print(colorImageView)
# depth Image
# create frame buffer
framebuffferCreateInfo = VkFramebufferCreateInfo(
pAttachments=[colorImageView],width=self.width,height=self.height,layers=1,renderPass=self.inst.renderPass
)
self.fb = vkCreateFramebuffer(self.inst.device,framebuffferCreateInfo,None)
复制图像到宿主可见内存代码:
colorImageInfo = VkImageCreateInfo(
imageType=VK_IMAGE_TYPE_2D,format=self.inst.colorFormat,tiling=VK_IMAGE_TILING_LINEAR,usage=VK_IMAGE_USAGE_TRANSFER_DST_BIT,None)
memReqs = vkGetimageMemoryRequirements(self.inst.device,colorImage)
memReqs = cdh.cdata_dict(memReqs)
memProps = cdh.cdata_dict(self.inst.memoryProperties)
memoryType = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
typeBits = memReqs["memoryTypeBits"]
for i in range(32):
if (typeBits & 1) == 1:
if (memProps["memoryTypes"][i]["propertyFlags"] & memoryType) == memoryType:
memType = i
break
typeBits >>= 1
memAlLocinfo = VkMemoryAllocateInfo(
memoryTypeIndex=memType,None)
vkBindImageMemory(self.inst.device,0)
commandBufferAllocateInfo = VkCommandBufferAllocateInfo(
commandPool=self.inst.commandPool,level=VK_COMMAND_BUFFER_LEVEL_PRIMARY,commandBufferCount=1
)
cmdBuff = vkAllocateCommandBuffers(self.inst.device,commandBufferAllocateInfo)
cmdBuff = ffi.addressof(cmdBuff,0)[0]
beginInfo = VkCommandBufferBeginInfo(
sType=VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,flags=VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT
)
vkBeginCommandBuffer(cmdBuff,beginInfo)
subresourceRange = VkImageSubresourceRange(
aspectMask=VK_IMAGE_ASPECT_COLOR_BIT,baseMipLevel=0,levelCount=1,baseArrayLayer=0,layerCount=1
)
barrier = VkImageMemoryBarrier(
oldLayout=VK_IMAGE_LAYOUT_UNDEFINED,newLayout=VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,srcQueueFamilyIndex=VK_QUEUE_FAMILY_IGnorED,dstQueueFamilyIndex=VK_QUEUE_FAMILY_IGnorED,srcAccessMask=0,dstAccessMask=VK_ACCESS_TRANSFER_WRITE_BIT,subresourceRange=subresourceRange
)
vkCmdPipelineBarrier(cmdBuff,VK_PIPELINE_STAGE_TRANSFER_BIT,None,barrier)
# source image barrier
barrier = VkImageMemoryBarrier(
oldLayout=VK_IMAGE_LAYOUT_GENERAL,image=self.colorImage,srcAccessMask=VK_ACCESS_MEMORY_READ_BIT,dstAccessMask=VK_ACCESS_TRANSFER_READ_BIT,barrier)
srcSubresource = VkImageSubresourceLayers(
aspectMask=VK_IMAGE_ASPECT_COLOR_BIT,layerCount=1
)
dstSubresource = VkImageSubresourceLayers(
aspectMask=VK_IMAGE_ASPECT_COLOR_BIT,layerCount=1
)
imagecopy = VkImagecopy(
srcSubresource,VkOffset3D(0,0),dstSubresource,VkExtent3D(self.width,self.height)
)
vkCmdcopyImage(cmdBuff,self.colorImage,VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,imagecopy)
barrier = VkImageMemoryBarrier(
oldLayout=VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,newLayout=VK_IMAGE_LAYOUT_GENERAL,srcAccessMask=VK_ACCESS_TRANSFER_WRITE_BIT,dstAccessMask=VK_ACCESS_MEMORY_READ_BIT,barrier)
barrier = VkImageMemoryBarrier(
oldLayout=VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,srcAccessMask=VK_ACCESS_TRANSFER_READ_BIT,barrier)
vkEndCommandBuffer(cmdBuff)
self.getimageSubmitInfo = VkSubmitInfo(
pCommandBuffers=[cmdBuff]
)
self.imageMemory = memAlloc
vkQueueSubmit(self.inst.graphicsQueue,self.getimageSubmitInfo,VK_NULL_HANDLE)
vkQueueWaitIdle(self.inst.graphicsQueue)
pb = vkMapMemory(self.inst.device,self.imageMemory,self.width * self.height * 4,0)
out = np.frombuffer(pb,np.uint8)
out = out.reshape((self.height,self.width,4))
vkUnmapMemory(self.inst.device,self.imageMemory)
解决方法
这就是我发现的 19.4.1. Buffer and Image Addressing。
这是 vkCmdCopyImage 复制压缩数据的方式:
rowLength = region->bufferRowLength;
if (rowLength == 0)
rowLength = region->imageExtent.width;
imageHeight = region->bufferImageHeight;
if (imageHeight == 0)
imageHeight = region->imageExtent.height;
compressedTexelBlockSizeInBytes = <compressed texel block size taken from the src/dstImage>;
rowLength /= compressedTexelBlockWidth;
imageHeight /= compressedTexelBlockHeight;
address of (x,y,z) = region->bufferOffset + (((z * imageHeight) + y) * rowLength + x) * compressedTexelBlockSizeInBytes;
where x,z range from (0,0) to region->imageExtent.{width/compressedTexelBlockWidth,height/compressedTexelBlockHeight,depth/compressedTexelBlockDepth}.
因此,如果我假设具有最佳布局的图像被压缩,但具有线性布局的图像没有被压缩,这就解释了问题。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。