在Vulkan中生成mipmaps

6

我正在尝试使用vkCmdBlitImage生成运行时mipmaps(实现glGenerateMipmap()功能),但不理解过程。以下是我的代码:

VkImageCreateInfo imageCreateInfo = {};
imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageCreateInfo.pNext = nullptr;
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
imageCreateInfo.format = format;
imageCreateInfo.mipLevels = mipLevels;
imageCreateInfo.arrayLayers = 1;
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
imageCreateInfo.extent = { static_cast<std::uint32_t>( width ), static_cast<std::uint32_t>( height ), 1 };
imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;

err = vkCreateImage( GfxDeviceGlobal::device, &imageCreateInfo, nullptr, &image );

...

    for (int i = 1; i < mipLevels; ++i)
    {
        const std::int32_t mipWidth = width >> i;
        const std::int32_t mipHeight = height >> i;

        VkImageBlit imageBlit = {};
        imageBlit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
        imageBlit.srcSubresource.baseArrayLayer = 0;
        imageBlit.srcSubresource.layerCount = 1;
        imageBlit.srcSubresource.mipLevel = 0;
        imageBlit.srcOffsets[ 0 ] = { 0, 0, 0 };
        imageBlit.srcOffsets[ 1 ] = { width, height, 1 };

        imageBlit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
        imageBlit.dstSubresource.baseArrayLayer = 0;
        imageBlit.dstSubresource.layerCount = 1;
        imageBlit.dstSubresource.mipLevel = i;
        imageBlit.dstOffsets[ 0 ] = { 0, 0, 0 };
        imageBlit.dstOffsets[ 1 ] = { mipWidth, mipHeight, 1 };

        vkCmdBlitImage( texCmdBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
                        image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
                        1, &imageBlit, VK_FILTER_LINEAR );
    }

每个mip级别需要自己的图像吗?它们应该如何初始化?当使用暂存缓冲区进行纹理数据时,何时生成mipmaps?

编辑:按照建议,我修改了代码仅使用一个图像,现在似乎可以正常工作(我可以在RenderDoc纹理查看器中看到正确的mip级别图像,并且没有收到任何验证错误)。


1
源图像和目标图像可以相同。为此,甚至应该这样做。每个图像至少有一个mip级别([0]是基本“纹理”)。将i复制到i很奇怪。 - krOoze
1个回答

4
每个mip级别都需要自己的图像吗?
不需要,您不需要为每个mip级别创建单独的图像。如果为纹理创建图像,则只需设置VkImageCreateInfo的mipLevels即可。
它们应该如何初始化?在使用分段缓冲区进行纹理数据时何时生成mipmap?
这取决于您想用什么来填充mips。您只想从纹理文件中加载它们(静态mip级别)还是需要在运行时生成它们?
如果您只想从文件中加载它们,请根本不要进行blit。创建一个分段缓冲区(而不是图像),将纹理数据加载到其中,并使用vkCmdCopyBufferToImage从该缓冲区向您的图像进行复制。
但是,您是否可以添加更多细节?我没有看到任何可能因实现而异的图像布局转换,也没有关于图像创建信息(例如标志)的信息,您也没有说明您的代码是否实际工作或未工作。
可能有问题的一件事情(没有更多的代码很难判断)是blit源中的mipLevel。您真的有一个具有完整mip链的源,并逐个mip复制吗?

谢谢,我在问题中添加了一些细节。我还没有写转换,因为我对整个流程还不确定。 - SurvivalMachine
1
@SurvivalMachine 通过我的超级谷歌搜索技巧,找到了一个与你所尝试做的事情完全相同的示例。我将在此答案中附上它:https://skia.googlesource.com/skia.git/+/master/src/gpu/vk/GrVkGpu.cpp#779 - krOoze

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接