微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

从 vulkan 帧缓冲区下载的图像失真

如何解决从 vulkan 帧缓冲区下载的图像失真

我正在使用 vulkan 进行离屏渲染。由于我在设备内存中获得了渲染图像,因此我将其下载到主机内存以用于其他目的。一切正常,直到图像宽度为 8 的倍数,否则图像会失真。

这是 vulkan 功能,还是我在某处犯了错误

帧缓冲代码

    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 举报,一经查实,本站将立刻删除。