pNext 和 sType

Vulkan 新手会开始注意到 Vulkan 规范中到处都有 pNextsType 变量。 void* pNext 用于通过在结构之间创建链表来扩展 Vulkan 规范。 VkStructureType sType 由加载器、层和实现使用,以了解由 pNext 传入的结构类型。 pNext 主要在处理暴露新结构的扩展时使用。

两个基本结构

Vulkan API 提供了两个基本结构 VkBaseInStructureVkBaseOutStructure,用作迭代结构指针链的便捷方式。

VkBaseInStructureIn 指的是 pNext 是一个 const *,并且对于接收它们的加载器、层和驱动程序是只读的。 VkBaseOutStructureOut 指的是 pNext 用于将数据返回给应用程序。

设置 pNext 结构示例

// An example with two simple structures, "a" and "b"
typedef struct VkA {
    VkStructureType sType;
    void* pNext;
    uint32_t value;
} VkA;

typedef struct VkB {
    VkStructureType sType;
    void* pNext;
    uint32_t value;
} VkB;

// A Vulkan Function that takes struct "a" as an argument
// This function is in charge of populating the values
void vkGetValue(VkA* pA);

// Define "a" and "b" and set their sType
struct VkB b = {};
b.sType = VK_STRUCTURE_TYPE_B;

struct VkA a = {};
a.sType = VK_STRUCTURE_TYPE_A;

// Set the pNext pointer from "a" to "b"
a.pNext = (void*)&b;

// Pass "a" to the function
vkGetValue(&a);

// Use the values which were both set from vkGetValue()
printf("VkA value = %u \n", a.value);
printf("VkB value = %u \n", b.value);

读取 pNext 值示例

在底层,加载器、层和驱动程序现在能够找到链接的 pNext 结构。这是一个示例,以帮助说明如何从加载器、层或驱动程序的角度可以实现 pNext

void vkGetValue(VkA* pA) {

    VkBaseOutStructure* next = reinterpret_cast<VkBaseOutStructure*>(pA->pNext);
    while (next != nullptr) {
        switch (next->sType) {

            case VK_STRUCTURE_TYPE_B:
                VkB* pB = reinterpret_cast<VkB*>(next);
                // This is where the "b.value" above got set
                pB->value = 42;
                break;

            case VK_STRUCTURE_TYPE_C:
                // Can chain as many structures as supported
                VkC* pC = reinterpret_cast<VkC*>(next);
                SomeFunction(pC);
                break;

            default:
                LOG("Unsupported sType %d", next->sType);
        }

        // This works because the first two values of all chainable Vulkan structs
        // are "sType" and "pNext" making the offsets the same for pNext
        next = reinterpret_cast<VkBaseOutStructure*>(next->pNext);
    }

    // ...
}