Vulkan编程指南翻译 第六章 着色器和管线 第5节 在着色器中访问资源

99 篇文章 54 订阅
81 篇文章 2 订阅

6.5  在着色器中访问资源

应用程序中的着色器有两种方式来消耗和生产数据。第一种是通过固定管线,第二种是直接读取和写入资源。你在第二章”内存和资源“中看到如何创建缓冲区和图像。在本节,我们介绍描述符集合,它表示着色器程序可以操作的资源的集合。

 

6.5.1描述符集合

描述符集合是被绑定到管线的一系列资源形成的组。多个集合可以同时绑定到管线。每一个集合都有布局,描述了集合中资源的排放顺序和类型。两个拥有相同布局的集合被视为兼容的和可互交换的。集合的布局铜鼓一个对象表示,集合都是参照这个对象被创建的。甚至,可被管线访问的集合的集合组成了另一个对象:管线布局。管线通过参照这个管线布局对象来创建。

描述符集合布局和管线布局在Figure 6.1展示。你可以在此图中看到,定义了两个描述符集合,第一个有纹理,采样器和两个缓冲区。第二个包含四个纹理,两个采样器和三个缓冲区。这些描述符集合的布局堆积在一个管线布局上。然后,可以参考管线布局来创建一个管线,参考描述符集合布局来创建描述符集合。那些描述符集合和兼容的管线一道被绑定到命令缓冲区,来允许管线访问到他们的资源。

 

在任何时刻,应用程序都可以绑定一个新的描述符集合到命令缓冲区的某一个具有相同布局的绑定点。相同的描述符集合布局可以被用来创建多个管线。因此,如果你一系列的具有相同资源的对象,但是每一个对象有额外不同的资源,当你的应用程序需要从一个对象转移到另外一个对象来做渲染时,你可以把相同的集合绑定并替换独有的资源。可调用vkCreateDescriptorSetLayout()来创建描述符集合布局对象,其原型如下:

         VkResultvkCreateDescriptorSetLayout (

                   VkDevice                                                                device,

                   constVkDescriptorSetLayoutCreateInfo*     pCreateInfo,

                   constVkAllocationCallbacks*                            pAllocator,

                   VkDescriptorSetLayout*                                    pSetLayout);

和往常一样,用来狗仔描述符集合布局对象的信息通过一个数据的指针来传递。这个数据是VkDescriptorSetLayoutCreateInfo

类型的,其定义如下:

         typedefstruct VkDescriptorSetLayoutCreateInfo {

                   VkStructureType                                         sType;

                   constvoid*                                                    pNext;

                   VkDescriptorSetLayoutCreateFlags      flags;

                   uint32_t                                                        bindingCount;

                   constVkDescriptorSetLayoutBinding* pBindings;

         }VkDescriptorSetLayoutCreateInfo;

        

VkDescriptorSetLayoutCreateInfo的sType域应被置为VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,pNext应置为nullptr。flags被保留使用,应置为0。资源被绑定到描述符集合的绑定点。VkDescriptorSetLayoutCreateInfo的bindingCount 和 pBindings成员包含了该集合的绑定点个数,和一个包含有它们描述的数组的指针。每一个绑定都通过一个VkDescriptorSetLayoutBinding

类型的实例来表示,其定义如下:

         typedefstruct VkDescriptorSetLayoutBinding {

                   uint32_t                                      binding;

                   VkDescriptorType                    descriptorType;

                   uint32_t                                      descriptorCount;

                   VkShaderStageFlags                stageFlags;

                   constVkSampler*                     pImmutableSamplers;

         }VkDescriptorSetLayoutBinding;

 

每个着色器可访问的资源都被给定了一个绑定号。这个绑定号存储在VkDescriptorSetLayoutBinding

的binding域,在一个集合中序号可以不连续。然而,很推荐你不要创建稀疏防止的集合,因为这回浪费GPU设备资源。这个绑定点的描述符的类型存储在descriptorType。这是VkDescriptorType枚举类型的一个成员。我们在稍后章节讨论不同的资源类型,它们包括:

 

• VK_DESCRIPTOR_TYPE_SAMPLER: A sampler is an object that can be usedto perform

operations such as filtering and samplecoordinate transformations when reading data from an

image.

• VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: A sampled image is an image thatcan be used

in conjunction with a sampler to providefiltered data to a shader.

• VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: A combined image-sampler

object is a sampler and an image pairedtogether. The same sampler is always used to sample

from the image, which can be more efficienton some architectures.

• VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: A storage image is an image thatcannot be

used with a sampler but can be written to.This is in contrast to a sampled image, which cannot

be written to.

• VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: A uniform texel buffer isa buffer

that is filled with homogeneous formatteddata that cannot be written by shaders. Knowing that

buffer content is constant may allow someVulkan implementations to optimize access to the

buffer better.

• VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: A storage texel buffer isa buffer

that contains formatted data much like auniform texel buffer, but a storage buffer can be written

to.

• VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER and

VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: Theseare similar to

VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER and

VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,except that the data is unformatted

and described by structures declared in theshader.

• VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC and

VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:These are similar to

VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER and

VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, butinclude an offset and size that are passed

when the descriptor set is bound to thepipeline rather than when the descriptor is bound into the

set. This allows a single buffer in asingle set to be updated at high frequency.

• VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: An input attachment is aspecial type of

image whose content is generated by earlieroperations on the same image in a graphics

pipeline.

 

Listing 6.8 illustrates how a selection ofresources is declared inside a GLSL shader.

         #version450 core

layout (set = 0, binding = 0) uniformsampler2DmyTexture;

layout (set = 0, binding = 2) uniformsampler3DmyLut;

layout (set = 1, binding = 0) uniformmyTransforms

{

mat4 transform1;

mat3 transform2;

};

void main(void)

{

// Do nothing!

}

 

Listing 6.9 展示了Listing 6.8中一个着色器被GLSL编译器编译为紧密格式。

 

 

Listing 6.9: Declaring Resources in SPIR-V

        

; SPIR-V

; Version: 1.0

; Generator: Khronos Glslang Reference Front End; 1

; Bound: 22

; Schema: 0

OpCapability Shader

%1 = OpExtInstImport "GLSL.std.450"

OpMemoryModel Logical GLSL450

OpEntryPoint GLCompute %4 "main"

OpExecutionMode %4 LocalSize 1 1 1

OpSource GLSL 450

OpName %4 "main"

OpName %10 "myTexture"

OpName %14 "myLut"

OpName %19 "myTransforms"

OpMemberName %19 0 "transform1"

OpMemberName %19 1 "transform2"

OpName %21 ""

OpDecorate %10 DescriptorSet 0

OpDecorate %10 Binding 0

OpDecorate %14 DescriptorSet 0

OpDecorate %14 Binding 2

OpMemberDecorate %19 0 ColMajor

OpMemberDecorate %19 0 Offset 0

OpMemberDecorate %19 0 MatrixStride 16

OpMemberDecorate %19 1 ColMajor

OpMemberDecorate %19 1 Offset 64

OpMemberDecorate %19 1 MatrixStride 16

OpDecorate %19 Block

OpDecorate %21 DescriptorSet 1

OpDecorate %21 Binding 0

%2 = OpTypeVoid

%3 = OpTypeFunction %2

%6 = OpTypeFloat 32

%7 = OpTypeImage %6 2D 0 0 0 1 Unknown

%8 = OpTypeSampledImage %7

%9 = OpTypePointer UniformConstant %8

%10 = OpVariable %9 UniformConstant

%11 = OpTypeImage %6 3D 0 0 0 1 Unknown

%12 = OpTypeSampledImage %11

%13 = OpTypePointer UniformConstant %12

%14 = OpVariable %13 UniformConstant

%15 = OpTypeVector %6 4

%16 = OpTypeMatrix %15 4

%17 = OpTypeVector %6 3

%18 = OpTypeMatrix %17 3

%19 = OpTypeStruct %16 %18

%20 = OpTypePointer Uniform %19

%21 = OpVariable %20 Uniform

%4 = OpFunction %2 None %3

%5 = OpLabel

OpReturn

OpFunctionEnd

 

 

在一个管线中可以使用多个描述符集合布局。你可以在Listing 6.8和 6.9看到,资源被放到了两个集合,第一个包含"myTexture" and "myLut"(两个采样器),第二个包含"myTransforms"(a uniform buffer). 把两个或多个描述符集合打包来给管线使用,我们需要把它们汇集到一个VkPipelineLayout对象。可以调用vkCreatePipelineLayout()来做到,其原型如下:

         VkResultvkCreatePipelineLayout (

                   VkDevice                                                       device,

                   constVkPipelineLayoutCreateInfo*       pCreateInfo,

                   constVkAllocationCallbacks*                   pAllocator,

                   VkPipelineLayout*                                      pPipelineLayout);

 

这个函数使用device参数指定的设备,使用pCreateInfo指针所指向的VkPipelineLayoutCreateInfo类型的数据的信息,来创建新的VkPipelineLayout对象。

VkPipelineLayoutCreateInfo定义如下:

         typedefstruct VkPipelineLayoutCreateInfo {

                   VkStructureType                                sType;

                   constvoid*                                           pNext;

                   VkPipelineLayoutCreateFlags        flags;

                   uint32_t                                               setLayoutCount;

                   constVkDescriptorSetLayout*       pSetLayouts;

                   uint32_t                                               pushConstantRangeCount;

                   constVkPushConstantRange*       pPushConstantRanges;

         }VkPipelineLayoutCreateInfo;

 

                  

VkPipelineLayoutCreateInfo的sType域应置为VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,pNext应置为nullptr。flags域被当前版本Vulkan保留,应置为0。描述符集合布局的数量()通过setLayoutCount给定,pSetLayouts是一个指向之前调用vkCreateDescriptorSetLayout()创建的VkDescriptorSetLayout类型handle数组的指针。一次可绑定的描述符集合的最大数()至少为4.一些Vulkan实现也许会支持更大的个数。你可以通过调用vkGetPhysicalDeviceProperties()来获取的VkPhysicalDeviceLimits类型的数据,检查它的maxBoundDescriptorSets来获知布局的最大个数。最后两个参数,pushConstantRangeCount 和 pPushConstantRanges,用来描述管线中用到的pushconstants。Push Constants是一种特殊的资源类型,它可以被当作着色器直接使用的常量。对push constants的更新非常快,并且无需同步。我们在稍后章节讨论push constants。

当VkDescriptorSetLayout对象被创建了,一个管线内所有集合使用的资源都被集合了,并且需要符合设备自身的上限值。一个管线可访问的资源的个数和类型是有上限的。

可以通过调用vkGetPhysicalDeviceProperties()得到设备的VkPhysicalDeviceLimits类型数据,

通过检查该数据中相关的成员来来获取到每一个上限值。VkPhysicalDeviceLimits和管线布局最大数相关的成员如下所列:

 

 

如果你的着色器程序或者生成的管线需要使用比上述规定最大值还大的资源数量,那么你需要检查资源上限,并准备当超过了是如何正确的处理失败。然而,如果你的资源需求在允许的范围内,那么便没有理由去检查Vulkan支持的最低标准。

一个描述符集合可以使用两个管线,如果这两个管线的布局是兼容的。对描述符集合兼容的两个管线布局,需符合:

         •Use the same number of push constant ranges

         •Use the same descriptor set layouts (or identical layouts) in the same order

 

如两个管线布局对于前面几个集合使用相同()的集合布局,后面不相同,那这两个管线布局被认为是部分兼容的。在这种情况下,管线是兼容的,直至描述符集合布局不同的地方。

当管线被绑定到一个命令缓冲区时,它可继续使用一个管线布局内与集合绑定兼容的已绑定的描述符集合中任一个。且,交换两个部分兼容的管线无需重绑定任何集合到管线共享布局的点上。如果你有一系列的资源并向在全局访问,比如包含每帧所需常量的uniform block,或者在每个着色器都需要访问的纹理,那就把这些资源放在第一个集合里。频繁被访问的资源可以放到高序号的集合里。

Listing 6.10 展示了创建描述符集合布局与描述该集合的管线布局创建所需的应用程序端代码:

         Listing6.10: Creating a Pipeline Layout

 

// This describes our combinedimage-samplers. One set, two disjoint

bindings.

static const VkDescriptorSetLayoutBindingSamplers[] =

{

         {

         0,                                                    // Start from binding

         0

         VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,// Combined imagesampler

         1,                                                    // Create one binding

         VK_SHADER_STAGE_ALL,       // Usable in all

         stages

         nullptr                                          // Nostatic samplers

         },

         {

         2,                                                    // Start from binding

         2

         VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,// Combined imagesampler

         1,                                                   //Create one binding

         VK_SHADER_STAGE_ALL,        // Usable in all

         stages

         nullptr                                          // Nostatic samplers

}

};

// This is our uniform block. One set, onebinding.

static const VkDescriptorSetLayoutBindingUniformBlock =

{

         0,// Start from binding

         0

         VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,// Uniform block

         1,// One binding

         VK_SHADER_STAGE_ALL,// All stages

         nullptr// No static samplers

};

// Now create the two descriptor setlayouts.

static constVkDescriptorSetLayoutCreateInfo createInfoSamplers =

{

         VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,

         nullptr,

         0,

         2,

         &Samplers[0]

};

static constVkDescriptorSetLayoutCreateInfo createInfoUniforms =

{

         VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,

         nullptr,

         0,

         1,

         &UniformBlock

};

// This array holds the two set layouts.

VkDescriptorSetLayout setLayouts[2];

vkCreateDescriptorSetLayout(device,&createInfoSamplers,

                                                        nullptr,&setLaouts[0]);

vkCreateDescriptorSetLayout(device,&createInfoUniforms,

                                                        nullptr,&setLayouts[1]);

// Now create the pipeline layout.

const VkPipelineLayoutCreateInfopipelineLayoutCreateInfo =

{

         VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,nullptr,

         0,

         2,setLayouts,

         0,nullptr

};

VkPipelineLayout pipelineLayout;

vkCreatePipelineLayout(device,&pipelineLayoutCreateInfo,

                                               nullptr,pipelineLayout);

 

在Listing 6.10中所创建的管线布局与Listing 6.9与Listing 6.10中着色器代码所期待的布局匹配。当我们创建一个使用该着色器的计算管线,我们把Listing 6.10 创建的管线布局对象作为VkComputePipelineCreateInfo类型数据的layout域传递给vkCreateComputePipelines()。当管线布局不再被需要时,应该调用vkDestroyPipelineLayout()来销毁它。这将释放管线布局对象关联的任何资源。vkDestroyPipelineLayout()原型如下:

         voidvkDestroyPipelineLayout (

                   VkDevice                                    device,

                   VkPipelineLayout                      pipelineLayout,

                   constVkAllocationCallbacks* pAllocator);

在管线布局对象被销毁后,它不应被再次使用了。然而,通过该管线布局对象创建的管线依然是有效的,直到它们被销毁。因此,没有必要在创建了管线之后依然让管线布局对象继续存在。可调用下面函数来销毁描述符集合布局对象并释放它的资源:

         voidvkDestroyDescriptorSetLayout (

                   VkDevice                                    device,

                   VkDescriptorSetLayout          descriptorSetLayout,

                   constVkAllocationCallbacks* pAllocator);

拥有该描述符集合布局的设备应通过device传递,描述符集合布局通过descriptorSetLayout传递。pAllocator应指向一个主机内存分配器,和用来创建该描述符集合布局的内存分配器匹配,或当vkCreateDescriptorSetLayout()的pAllocator为nullptr时这个pAllocator也为nullptr。

 

 

6.5.2 绑定资源到描述符集合

资源是通过描述符表示的,被绑定到管线上--首先把描述符绑定到集合上,然后把描述符集合绑定到管线。这允许花费很少时间消耗就能绑定一个很大的资源,因为被特定绘制命令使用的资源的集合可以提前就指定了,并提前创建好存放它们的描述符集合。描述符是从“描述符池”分配出来的。因为对不同资源类型的描述符都拥有相同的数据结构--不管在那种Vulkan实现里。以缓存池的方式类存储描述符让驱动可以更加高效的使用内存。可以使用vkCreateDescriptorPool()来创建描述符缓存池,其原型为:

         VkResultvkCreateDescriptorPool (

         VkDevice                                                       device,

         constVkDescriptorPoolCreateInfo*       pCreateInfo,

         constVkAllocationCallbacks*                   pAllocator,

         VkDescriptorPool*                                     pDescriptorPool);

创建描述符缓存池的设备通过device指定,剩下的参数描述了新的缓存池,通过VkDescriptorPoolCreateInfo类型的pCreateInfo来传递。VkDescriptorPoolCreateInfo原型如下:

         typedefstruct VkDescriptorPoolCreateInfo {

                   VkStructureType                                sType;

                   constvoid*                                           pNext;

                   VkDescriptorPoolCreateFlags        flags;

                   uint32_t                                               maxSets;

                   uint32_t                                               poolSizeCount;

                   constVkDescriptorPoolSize*                    pPoolSizes;

         }VkDescriptorPoolCreateInfo;

VkDescriptorPoolCreateInfo的sType域应置为VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,pNext应置为nullptr。flags用来传递关于分配策略的附加的信息,这个策略用在管理资源池的。当前唯一已定义的标志位是VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,它表示应用程序可以释放从池子中获取的单个描述符,所以应该为此准备好内存分配器。如果你不打算把单个描述符还给缓存池,把flags置为0即可。

maxSets域指定了可从池中分配出集合的数量的最大值。注意,这是集合的总个数,无关每个集合的大小或者池子的总大小。下两个域,poolSizeCount 和 pPoolSize,指定了存储在集合中每种类型资源描述的个数。pPoolSize是一个指向大小为poolSizeCount 的VkDescriptorPoolSize类型的数组的指针,数组每一个元素指定了可以从池子中分配出的一种类型描述符的个数。VkDescriptorPoolSize定义如下:

         typedefstruct VkDescriptorPoolSize {

VkDescriptorType            type;

uint32_t                             descriptorCount;

} VkDescriptorPoolSize;

VkDescriptorPoolSize的第一个域,type,指定了资源的类型,第二个域descriptorCount指定了在池子中该种类型资源的个数。type是VkDescriptorType枚举的一个枚举值。如果pPoolSizes数组中没有元素指定了一个特殊类型的资源,那么就没有那种类型的描述符可以从池子重分配出来。如果一个特定类型的资源在数组中出现两次,那么他们两个的descriptorCount域之和指定了缓存池中该类型资源的个数。当资源被分配出去后,资源池中的资源个数就相应的减少。

如果成功的创建了缓存池,那么一个新的VkDescriptorPool类型的对象的handle就会被写入到pDescriptorPool所指的变量里。为了从缓存池中分配多块描述符,我们可以调用vkAllocateDescriptorSets()来创建描述符集合对象,该函数原型如下:

         VkResultvkAllocateDescriptorSets (

VkDevice                                                        device,

const VkDescriptorSetAllocateInfo*      pAllocateInfo,

VkDescriptorSet*                                        pDescriptorSets);

拥有该描述符缓存池并可以从其分配出集合的设备通过device传递。剩下的关于集合分配的信息通过一个VkDescriptorSetAllocateInfo类型数据的指针pDescriptorSets来传递。VkDescriptorSetAllocateInfo的定义如下:

         typedefstruct VkDescriptorSetAllocateInfo {

VkStructureType sType;

const void* pNext;

VkDescriptorPool descriptorPool;

uint32_t descriptorSetCount;

const VkDescriptorSetLayout* pSetLayouts;

} VkDescriptorSetAllocateInfo;

VkDescriptorSetAllocateInfo的sType域应该置为VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,pNext应置为nullptr。可以分配出集合的描述符缓存池的handle通过descriptorPool指定,这个handle通过调用vkCreateDescriptorPool()来产生。对于descriptorPool的访问应该在外部保持同步。创建的集合的个数通过descriptorSetCount指定。每一个集合的布局通过VkDescriptorSetLayout类型数组pSetLayouts中每一个元素来传递。我们在之前讲过如何创建VkDescriptorSetLayout类型对象。

当调用成功,vkAllocateDescriptorSets()从指定的缓存池消耗集合和描述符,把新的描述符集合存储到一个pDescriptorSets指向的数组中。对于每一个描述符集合从缓存池中消耗的描述符的个数由描述符集合布局的pSetLayouts 决定,我们在之前讲过如何创建该布局。

如果创建描述符缓存池是带有的VkDescriptorSetCreateInfo类型参数包含VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT标志位,那么描述符集合可以通过被释放得以返回缓存池。可调用vkFreeDescriptorSets()来释放一个或者多个描述符集合,其原型如下:

         VkResultvkFreeDescriptorSets (

VkDevice device,

VkDescriptorPool                      descriptorPool,

uint32_t descriptorSetCount,

const VkDescriptorSet* pDescriptorSets);

拥有该描述符缓存池的设备通过device指定,描述符集合需要返回的缓存池通过descriptorPool指定。对于descriptorPool的访问需要在外部同步。需释放的描述符集合的个数通过descriptorSetCount传递,pDescriptorSets指向一个VkDescriptorSet类型的数组,每个元素都是需要被释放的对象。当描述符集合被释放,他们的资源都被返回到它们所来自的那个缓存池,这些资源将来可能被分配到一个新的集合。

即使在创建描述符缓存池时VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT没有被指定,也可以把所有集合的资源回收到它们所分配出来的缓存池。可以调用vkResetDescriptorPool()函数来做到重置缓存池。对于这个命令,有必要显式的指定每一个才哦你缓存池中分配出来的集合。函数原型如下:

         VkResultvkResetDescriptorPool (

VkDevice device,

VkDescriptorPool descriptorPool,

VkDescriptorPoolResetFlags flags);

Device是拥有该描述符缓存池的设备的handle,descriptorPool是需要被重置的描述符缓存池的handle。对于描述符缓存池的访问需要在外部同步。Flags被保留使用,应置为0。

不管集合是通过调用vkFreeDescriptorSets()单独的释放,还是通过调用vkResetDescriptorPool()来整块的释放,必须要注意保证在释放这些集合后不再引用它们。特别是,任何包含可能引用将被释放的到描述符集合的命令的命令缓冲区,应该已经完成了执行或者丢弃未提交的命令。

为了释放和资源关联的描述符缓存池,你应该通过调用vkDestroyDescriptorPool()来销毁,其原型如下:

         voidvkDestroyDescriptorPool(

VkDevice device,

VkDescriptorPool descriptorPool,

const VkAllocationCallbacks* pAllocator);

拥有该缓存池的设备的handle通过device传递,需要被销毁的缓存池的handle通过descriptorPool传递。pAllocator指向一个主机端内存分配器,它应和创建缓存池时使用的分配器相匹配,或者如果vkCreateDescriptorPool()的pAllocator参数为nullptr时就设置为nullptr。

当描述符缓存池被销毁了,它里面所有的资源也被释放了,包含从它分配出来的任何集合。在调用vkResetDescriptorPool()来销毁缓存池之前,没有必要显式的释放从缓存池分配出来的描述符集合。然而,当描述符集合被显示释放,你必须保证你的应用程序在缓存池被销毁后不会再次访问从缓存池中分配出来的描述符集合。这包含设备命令缓冲区中已提交但未完成的正在执行的任务。

我们可以直接写入描述符集合或者从其他一个描述符集合复制绑定,来把自然绑定到描述符集合。这种情况下,我们可以使用vkUpdateDescriptorSets()命令,其原型如下:

         voidvkUpdateDescriptorSets (

VkDevice device,

uint32_t descriptorWriteCount,

const VkWriteDescriptorSet* pDescriptorWrites,

uint32_t descriptorCopyCount,

const VkCopyDescriptorSet* pDescriptorCopies);

拥有需要被更新的描述符集合的设备通过device传递。直接写入的个数通过descriptorWriteCount传入,描述符复制的个数通过descriptorCopyCount传入。每一个写入的参数都包含在一个VkWriteDescriptorSet类型的数据里,每一个复制的参数包含在一个VkCopyDescriptorSet类型的数据。pDescriptorWrites 和 pDescriptorCopies参数包含

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值