在Vulkan中加载非二次幂纹理

时间:2021-12-25 04:11:40

My 2D texture loader works fine if my texture dimensions are power-of-two, but when they are not, the texture data displays as skewed. How do I fix this? I assume the issue has something to do with memory alignment and row pitch. Here's relevant parts of my loader code:

如果我的纹理尺寸是2的幂,我的2D纹理加载器工作正常,但当它们不是时,纹理数据显示为倾斜。我该如何解决?我认为这个问题与内存对齐和行间距有关。这是我的加载程序代码的相关部分:

VkMemoryRequirements memReqs;
vkGetImageMemoryRequirements( GfxDeviceGlobal::device, mappableImage, &memReqs );

VkMemoryAllocateInfo memAllocInfo = {};
memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
memAllocInfo.pNext = nullptr;
memAllocInfo.memoryTypeIndex = 0;
memAllocInfo.allocationSize = memReqs.size;

GetMemoryType( memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &memAllocInfo.memoryTypeIndex );

VkDeviceMemory mappableMemory;
err = vkAllocateMemory( GfxDeviceGlobal::device, &memAllocInfo, nullptr, &mappableMemory );
CheckVulkanResult( err, "vkAllocateMemory in Texture2D" );

err = vkBindImageMemory( GfxDeviceGlobal::device, mappableImage, mappableMemory, 0 );
CheckVulkanResult( err, "vkBindImageMemory in Texture2D" );

VkImageSubresource subRes = {};
subRes.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
subRes.mipLevel = 0;
subRes.arrayLayer = 0;

VkSubresourceLayout subResLayout;
vkGetImageSubresourceLayout( GfxDeviceGlobal::device, mappableImage, &subRes, &subResLayout );

void* mapped;
err = vkMapMemory( GfxDeviceGlobal::device, mappableMemory, 0, memReqs.size, 0, &mapped );
CheckVulkanResult( err, "vkMapMemory in Texture2D" );

const int bytesPerPixel = 4;
std::size_t dataSize = bytesPerPixel * width * height;
std::memcpy( mapped, data, dataSize );

vkUnmapMemory( GfxDeviceGlobal::device, mappableMemory );

1 个解决方案

#1


3  

The VkSubresourceLayout, which you obtained from vkGetImageSubresourceLayout will contain the pitch of the texture in the rowPitch member. It's more than likely not equal to the width, thus, when you do a memcpy of the entire data block, you're copying relevant data into the padding section of the texture.

从vkGetImageSubresourceLayout获得的VkSubresourceLayout将包含rowPitch成员中纹理的间距。它很可能不等于宽度,因此,当您对整个数据块执行memcpy时,您将相关数据复制到纹理的填充部分。

Instead you will need to memcpy row-by-row, skipping the padding memory in the mapped texture:

相反,您需要逐行memcpy,跳过映射纹理中的填充内存:

const int bytesPerPixel = 4;
std::size_t dataRowSize = bytesPerPixel * width;
char* mappedBytes = (char*)mapped;
for(int i = 0; i < height; ++i)
{
    std::memcpy(mapped, data, dataSize);
    mappedBytes += rowPitch;
    data += dataRowSize;
}

(this code assumes data is a char * as well - its declaration wasn't given)

(此代码假设数据也是char * - 未给出声明)

#1


3  

The VkSubresourceLayout, which you obtained from vkGetImageSubresourceLayout will contain the pitch of the texture in the rowPitch member. It's more than likely not equal to the width, thus, when you do a memcpy of the entire data block, you're copying relevant data into the padding section of the texture.

从vkGetImageSubresourceLayout获得的VkSubresourceLayout将包含rowPitch成员中纹理的间距。它很可能不等于宽度,因此,当您对整个数据块执行memcpy时,您将相关数据复制到纹理的填充部分。

Instead you will need to memcpy row-by-row, skipping the padding memory in the mapped texture:

相反,您需要逐行memcpy,跳过映射纹理中的填充内存:

const int bytesPerPixel = 4;
std::size_t dataRowSize = bytesPerPixel * width;
char* mappedBytes = (char*)mapped;
for(int i = 0; i < height; ++i)
{
    std::memcpy(mapped, data, dataSize);
    mappedBytes += rowPitch;
    data += dataRowSize;
}

(this code assumes data is a char * as well - its declaration wasn't given)

(此代码假设数据也是char * - 未给出声明)