Vulkan-均匀的缓冲区未发送到着色器



在使用C#i的Vulkan教程时,我到达了我应该开始使用统一缓冲区的地步(您可以在此处找到教程)首先,让我显示相关的代码,然后解释问题。我有几个相关的结构:

unsafe struct Buffer
{
    public SharpVulkan.Buffer buffer;
    public DeviceMemory memory;
    public readonly ulong size;
    public Buffer(ulong size) : this()
    {
        this.size = size;
    }
    public void Destroy(Device device)
    {
        device.DestroyBuffer(buffer);
        device.FreeMemory(memory);
    }
}
struct MVPMatrices
{
    public static MVPMatrices Identity { get; } = new MVPMatrices { model = Matrix4x4.Identity, view = Matrix4x4.Identity, projection = Matrix4x4.Identity };
    public Matrix4x4 model;
    public Matrix4x4 view;
    public Matrix4x4 projection;
}
struct UniformBuffer
{
    public Buffer buffer;
    public DescriptorSet descriptorSet;
    public void Destroy(Device device)
    {
        buffer.Destroy(device);
    }
}

我认为它们都是非常不言自明的,但是如果您需要更多信息,我可以更新问题。接下来,在主要程序中,我创建了一些相关的字段:

static DescriptorSetLayout descriptorSetLayout;
static DescriptorPool descriptorPool;
static UniformBuffer mvpMatricesBuffer;
static readonly MVPMatrices[] mvpMatricesArray = new MVPMatrices[1];
static ref MVPMatrices MVPMatrices => ref mvpMatricesArray[0];

这些是我对缓冲区的一些实用方法:

static Buffer CreateBuffer(ulong size, BufferUsageFlags usage, MemoryPropertyFlags memoryPropertyFlags = MemoryPropertyFlags.HostVisible | MemoryPropertyFlags.HostCoherent)
    {
        Buffer buffer = new Buffer(size);
        BufferCreateInfo createInfo = new BufferCreateInfo
        {
            StructureType = StructureType.BufferCreateInfo,
            SharingMode = SharingMode.Exclusive,
            Size = size,
            Usage = usage,
        };
        buffer.buffer = logicalDevice.CreateBuffer(ref createInfo);
        logicalDevice.GetBufferMemoryRequirements(buffer.buffer, out MemoryRequirements memoryRequirements);
        physicalDevice.GetMemoryProperties(out PhysicalDeviceMemoryProperties memoryProperties);
        uint memoryTypeIndex = 0;
        for (uint i = 0; i < memoryProperties.MemoryTypeCount; i++)
        {
            MemoryType* memoryType = &memoryProperties.MemoryTypes.Value0 + i;
            if ((memoryRequirements.MemoryTypeBits & (1 << (int)i)) != 0 && memoryType->PropertyFlags.HasFlag(memoryPropertyFlags))
            {
                memoryTypeIndex = i;
                break;
            }
        }
        MemoryAllocateInfo allocateInfo = new MemoryAllocateInfo
        {
            StructureType = StructureType.MemoryAllocateInfo,
            AllocationSize = memoryRequirements.Size,
            MemoryTypeIndex = memoryTypeIndex,
        };
        buffer.memory = logicalDevice.AllocateMemory(ref allocateInfo);
        logicalDevice.BindBufferMemory(buffer.buffer, buffer.memory, 0);
        return buffer;
    }
    static void SetBufferData<T>(this Buffer buffer, T[] data)
        where T : struct
    {
        ulong size = (ulong)(Marshal.SizeOf<T>() * data.Length);
        if (size != buffer.size)
            throw new ArgumentException("Size of buffer data must be the same as the size of the buffer!");
        IntPtr memory = logicalDevice.MapMemory(buffer.memory, 0, size, MemoryMapFlags.None);
        System.Buffer.MemoryCopy(Marshal.UnsafeAddrOfPinnedArrayElement(data, 0).ToPointer(), memory.ToPointer(), (uint)size, (uint)size);
        logicalDevice.UnmapMemory(buffer.memory);
    }
    static T[] GetBufferData<T>(this Buffer buffer)
        where T : struct
    {
        T[] result = new T[(int)buffer.size / Marshal.SizeOf<T>()];
        IntPtr memory = logicalDevice.MapMemory(buffer.memory, 0, buffer.size, MemoryMapFlags.None);
        System.Buffer.MemoryCopy(memory.ToPointer(), Marshal.UnsafeAddrOfPinnedArrayElement(result, 0).ToPointer(), (uint)buffer.size, (uint)buffer.size);
        logicalDevice.UnmapMemory(buffer.memory);
        return result;
    }
    static DescriptorSet AllocateDescriptorSet()
    {
        DescriptorSetLayout* setLayout = stackalloc DescriptorSetLayout[1];
        *setLayout = descriptorSetLayout;
        DescriptorSetAllocateInfo allocateInfo = new DescriptorSetAllocateInfo
        {
            StructureType = StructureType.DescriptorSetAllocateInfo,
            DescriptorPool = descriptorPool,
            DescriptorSetCount = 1,
            SetLayouts = (IntPtr)setLayout,
        };
        DescriptorSet set = DescriptorSet.Null;
        logicalDevice.AllocateDescriptorSets(ref allocateInfo, &set);
        return set;
    }
    static UniformBuffer CreateUniformBuffer(ulong size, uint binding)
    {
        UniformBuffer buffer = new UniformBuffer
        {
            buffer = CreateBuffer(size, BufferUsageFlags.UniformBuffer),
            descriptorSet = AllocateDescriptorSet(),
        };
        DescriptorBufferInfo bufferInfo = new DescriptorBufferInfo
        {
            Buffer = buffer.buffer.buffer,
            Offset = 0,
            Range = buffer.buffer.size,
        };
        WriteDescriptorSet descriptorWrite = new WriteDescriptorSet
        {
            StructureType = StructureType.WriteDescriptorSet,
            BufferInfo = new IntPtr(&bufferInfo),
            DescriptorCount = 1,
            DescriptorType = DescriptorType.UniformBuffer,
            DestinationArrayElement = 0,
            DestinationBinding = binding,
            DestinationSet = buffer.descriptorSet,
            ImageInfo = IntPtr.Zero,
            TexelBufferView = IntPtr.Zero,
        };
        logicalDevice.UpdateDescriptorSets(1, &descriptorWrite, 0, null);
        return buffer;
    }

在开始时,我还以一个值初始化了它,但是我制作了get/setBufferdata方法,因此我可以每个帧更新数据。这是在渲染之前在主循环中调用的函数:

static void UpdateApplication()
{
    MVPMatrices.model = Matrix4x4.Identity;
    MVPMatrices.view = Matrix4x4.Identity;
    MVPMatrices.projection = Matrix4x4.Identity;
    mvpMatricesBuffer.buffer.SetBufferData(mvpMatricesArray);
    Console.WriteLine(mvpMatricesBuffer.buffer.GetBufferData<MVPMatrices>()[0].model);
    Console.WriteLine(mvpMatricesBuffer.buffer.GetBufferData<MVPMatrices>()[0].view);
    Console.WriteLine(mvpMatricesBuffer.buffer.GetBufferData<MVPMatrices>()[0].projection);
}

也有分配命令缓冲区的功能。确实没有必要显示整个过程,但基本上是:我分配缓冲区,绑定一些缓冲区并绘制。在绘制之前,我将设置的描述符设置为命令缓冲区,因此这是我使用的代码(您需要知道的只是"缓冲区"指向命令缓冲区的指针):

DescriptorSet* descriptorSets = stackalloc DescriptorSet[1];
*descriptorSets = mvpMatricesBuffer.descriptorSet;
buffer->BindDescriptorSets(PipelineBindPoint.Graphics, pipelineLayout, 0, 1, descriptorSets, 0, null);

现在有两个着色器。唯一相关的着色器是顶点着色器,因此是:

#version 450
#extension GL_ARB_separate_shader_objects : enable
layout(binding = 0) uniform MVPMatrices
{
    mat4 model;
    mat4 view;
    mat4 projection;
} mvpMatrices;
layout(location = 0) in vec3 position;
layout(location = 1) in vec4 color;
layout(location = 0) out vec4 vertexColor;
void main()
{
    gl_Position = mvpMatrices.projection * mvpMatrices.view * mvpMatrices.model * vec4(position, 1);
    vertexColor = color;
}

那是什么问题?
与往常一样,图形:它不会渲染。每当我删除乘以矩阵的部分时,它的工作正常。我还尝试将颜色设置为模型矩阵的第二行(应该是绿色),并且它不起作用。

我在更新方法中显示的日志打印了矩阵缓冲区的数据,它们都是身份矩阵(就像应该的矩阵一样)。
这意味着缓冲区的数据很好。

描述符集是另一个故事。当我不将设置布局绑定到管道布局时,我会遇到一个错误,说着色器使用描述符插槽,但在管道布局中没有声明。
这意味着设置布局已正确绑定。

如果我不创建描述符集,则将其绑定到命令缓冲区时会出现错误。
这意味着描述符集正确创建了,因此描述库池也很好(否则我会遇到错误)。

因此,缓冲区和描述符设置两个工作。
给我一个结论:缓冲区和描述符集未正确链接。奇怪的是,链接两者的代码是设备。问题是,如果我不通过缓冲区信息the DeScriptorWrite变量,或者如果将空句柄传递给缓冲区信息,我会收到一个错误,说描述符集从未更新。
如果我不将设置的描述符设置到DecitiveorWrite变量。
这意味着它知道我更新它的事实,并且知道我 am 发送缓冲区的事实,但是数据仍然不在一定程度上发送给着色器。

尝试调试一个多星期后,我可以说一切对我来说都是完美的,而且我有 no 知道问题所在。这使我非常绝望,所以我来到这里。

这是我在网站上的第一篇文章,我不知道我是否给您所有您需要的信息(即使我觉得我给了很多信息),因此,如果帖子有任何问题,请告诉我,我将尝试修复它。

显然可以的所有代码都可以。由于某种原因,问题是在调试报告中。我真的不知道它与制服有什么关系,但是当我禁用它时,一切都是完美的。

我决定要做的只是在大多数情况下禁用调试报告,但是只需简单地使用#Define定义某些内容,就可以将其带回(当我需要Vulkan关于东西的一些反馈时)。这可能不是一个很好的解决方案,但这是我能想到的最好的解决方案。

我面临着类似的东西,并且仍在试图追逐原因。如果我启用" vk_layer_lunarg_core_validation"在我的Android应用中验证层,则我的统一缓冲区在着色器中为零。

还没有解决方法,但是我想知道这是验证层中的错误还是我的描述符集中的错误。

我能够在没有此问题的情况下启用其他验证层。

相关内容

  • 没有找到相关文章

最新更新