区块链技术博客
www.b2bchain.cn

使用资源堆的参数缓冲区求职学习资料

本文介绍了使用资源堆的参数缓冲区求职学习资料,有助于帮助完成毕业设计以及求职,是一篇很好的资料。

对技术面试,学习经验等有一些体会,在此分享。

Using Argument Buffers with Resource Heaps | Apple Developer Documentation

通过在参数缓冲区内使用数组并与资源堆结合使用,减少CPU开销。

翻译术语表

概述

在Encoding Argument Buffers on the GPU示例中,你学习了如何在参数缓冲区中指定、编码、设置和访问资源。

在本示例中,你将学习如何把参数缓冲区、资源数组和资源堆结合使用。特别是,你将学习如何定义一个包含数组的参数缓冲区结构体,以及如何从堆中分配和使用资源。本示例渲染了一个静态四边形,该四边形使用了编码到参数缓冲区中的多个资源。

入门

Xcode项目包含在macOS、iOS或tvOS上运行本示例的方案。iOS或tvOS模拟器不支持Metal,所以iOS和tvOS方案需要物理设备来运行示例。默认方案是macOS,它将按Mac上的方式运行示例。

Metal着色器语言中的参数数组

数组可以作为图形或运算函数的参数。当一个函数采用数组作为参数时,数组的第一个资源的索引等于数组参数本身的起始索引(base index)。因此,数组中后续的每个资源都会自动分配一个后续索引值,从起始索引值开始递增计数。

例如,下面的片元函数exampleFragmentFunction,其参数textureParameters是一个由10个纹理组成的数组,起始索引值为5

fragment float4 exampleFragmentFunction(array<texture2d<float>, 10> textureParameters [[ texture(5) ]])

因为textureParameters[[ texture(5) ]]属性限定符,所以设置这个参数对应的Metal框架方法是setFragmentTexture:atIndex:,其中index的值从5开始。因此,数组索引0的纹理设置为索引编号5,数组索引1处的纹理设置为索引编号6,以此类推。数组中最后一个纹理,在数组索引9处,被设置为索引编号14

用数组定义参数缓冲区

数组也可以被用于参数缓冲区结构体的元素。在这种情况下,参数缓冲区的[[ id(n) ]]属性限定符与函数参数的[[ texture(n) ]]属性限定符的行为方式相同,其中n是数组的起始索引值。然而,你不会调用MTLRenderCommandEncoder对象的setFragmentTexture:atIndex:方法来设置数组中的纹理。取而代之的是调用MTLArgumentEncoder对象的setTexture:atIndex:方法,将数组中的纹理编码到参数缓冲区中,其中index对应于起始索引值n加上数组中的纹理的索引的和。

本示例中的参数缓冲区被声明为FragmentShaderArguments结构体,这是它的定义:

typedef struct FragmentShaderArguments {     array<texture2d<float>, AAPLNumTextureArguments> exampleTextures  [[ id(AAPLArgumentBufferIDExampleTextures)  ]];     array<device float *,  AAPLNumBufferArguments>   exampleBuffers   [[ id(AAPLArgumentBufferIDExampleBuffers)   ]];     array<uint32_t, AAPLNumBufferArguments>          exampleConstants [[ id(AAPLArgumentBufferIDExampleConstants) ]]; } FragmentShaderArguments;

结构体的每个元素使用array<T, N>模板,它把元素定义为一个特定类型的数组T,以及元素数量N。该参数缓冲区包含以下资源:

  • exampleTextures,包含32个2D纹理的数组,起始索引值为0
  • exampleBuffers,包含32个float缓冲区的数组,起始索引值为100
  • exampleConstants,包含32个uint32_t常量的数组,起始索引值为200

使用资源堆的参数缓冲区

把数组元素编码到参数缓冲区

本示例通过把数组每个元素对应的索引值与setTexture:atIndex:setBuffer:offset:atIndex:方法的index参数进行匹配,把数组元素编码到参数缓冲区中。参数缓冲区中的[[ id(n) ]]属性限定符定义了这种行为。

for(uint32_t i = 0; i < AAPLNumTextureArguments; i++) {     [argumentEncoder setTexture:_texture[i]                         atIndex:AAPLArgumentBufferIDExampleTextures+i]; } for(uint32_t i = 0; i < AAPLNumBufferArguments; i++) {     [argumentEncoder setBuffer:_dataBuffer[i]                         offset:0                         atIndex:AAPLArgumentBufferIDExampleBuffers+i];      uint32_t *elementCountAddress =         [argumentEncoder constantDataAtIndex:AAPLArgumentBufferIDExampleConstants+i];      *elementCountAddress = (uint32_t)_dataBuffer[i].length / 4; }

访问参数缓冲区的数组元素

在一个函数中,访问一个参数缓冲区中编码的数组元素与访问一个标准数组的元素是一样的。在本示例中,exampleTexturesexampleBuffersexampleConstants数组是通过fragmentShader函数的fragmentShaderArgs参数访问的。每个数组元素都是用[n]下标语法访问的,其中n是数组元素的索引。

for(uint32_t textureToSample = 0; textureToSample < AAPLNumTextureArguments; textureToSample++) {     float4 textureValue = fragmentShaderArgs.exampleTextures[textureToSample].sample(textureSampler, in.texCoord);      color += textureValue; }

fragmentShader函数包含一个if-else条件,它根据texCoordx分量,确定片元在四边形的哪一侧。

如果片元在左侧,函数会对exampleBuffers数组中的每一个纹理进行采样,并将采样值相加,以确定最终输出的颜色。如果片元在四边形的右侧,函数从exampleBuffers数组中读取一个值。函数先使用texCoordx分量来确定从哪个缓冲区读取,然后使用texCoordy分量来确定读取缓冲区的位置。缓冲区中的值决定了最终输出的颜色。

// Use texCoord.x to select the buffer to read from uint32_t bufferToRead = (in.texCoord.x-0.5)*2.0 * (AAPLNumBufferArguments-1);  // Retrieve the number of elements for the selected buffer from // the array of constants in the argument buffer uint32_t numElements = fragmentShaderArgs.exampleConstants[bufferToRead];  // Determine the index used to read from the buffer uint32_t indexToRead = in.texCoord.y * numElements;  // Retrieve the buffer to read from by accessing the array of // buffers in the argument buffer device float* buffer = fragmentShaderArgs.exampleBuffers[bufferToRead];  // Read from the buffer and assign the value to the output color color = buffer[indexToRead];

将参数缓冲区与资源堆相结合

片元函数通过参数缓冲区访问32个纹理和32个缓冲区,总共有64个不同的资源。如果这些资源中的每一个,其内存是单独分配的,尽管它们驻留在数组中,Metal在把这些资源提供给GPU访问之前,需要验证这64个单独资源的内存。

相反,本示例从一个MTLHeap对象中分配资源。堆是一个单一的内存区域,可以从中分配多个资源。因此,本示例可以通过调用一次useHeap:方法,让GPU访问堆的整个内存,包括堆内所有资源的内存。

本示例实现了一个loadResources方法,该方法将资源数据加载到临时的MTLTextureMTLBuffer对象中。然后,该示例实现了一个createHeap方法,该方法计算出在堆中存储资源数据所需的总大小,并创建堆本身。

“`

  • (void) createHeap
    {
    MTLHeapDescriptor *heapDescriptor = [MTLHeapDescriptor new];
    heapDescriptor.storageMode = MTLStorageModePrivate;
    heapDescriptor.size = 0;

    // Build a descriptor for each texture and calculate the size required to store all textures in the heap
    for(uint32_t i = 0; i < AAPLNumTextureArguments; i++)
    {
    // Create a descriptor using the texture’s properties
    MTLTextureDescriptor *descriptor = [AAPLRenderer newDescriptorFromTexture:_texture[i]
    storageMode:heapDescriptor.storageMode];

    // Determine the size required for the heap for the given descriptor MTLSizeAndAlign sizeAndAlign = [_device heapTextureSizeAndAlignWithDescriptor:descriptor];  // Align the size so that more resources will fit in the heap after this texture sizeAndAlign.size += (sizeAndAlign.size & (sizeAndAlign.align - 1)) + sizeAndAlign.align;

Using Argument Buffers with Resource Heaps | Apple Developer Documentation

通过在参数缓冲区内使用数组并与资源堆结合使用,减少CPU开销。

翻译术语表

概述

在Encoding Argument Buffers on the GPU示例中,你学习了如何在参数缓冲区中指定、编码、设置和访问资源。

在本示例中,你将学习如何把参数缓冲区、资源数组和资源堆结合使用。特别是,你将学习如何定义一个包含数组的参数缓冲区结构体,以及如何从堆中分配和使用资源。本示例渲染了一个静态四边形,该四边形使用了编码到参数缓冲区中的多个资源。

入门

Xcode项目包含在macOS、iOS或tvOS上运行本示例的方案。iOS或tvOS模拟器不支持Metal,所以iOS和tvOS方案需要物理设备来运行示例。默认方案是macOS,它将按Mac上的方式运行示例。

Metal着色器语言中的参数数组

数组可以作为图形或运算函数的参数。当一个函数采用数组作为参数时,数组的第一个资源的索引等于数组参数本身的起始索引(base index)。因此,数组中后续的每个资源都会自动分配一个后续索引值,从起始索引值开始递增计数。

例如,下面的片元函数exampleFragmentFunction,其参数textureParameters是一个由10个纹理组成的数组,起始索引值为5

fragment float4 exampleFragmentFunction(array<texture2d<float>, 10> textureParameters [[ texture(5) ]])

因为textureParameters[[ texture(5) ]]属性限定符,所以设置这个参数对应的Metal框架方法是setFragmentTexture:atIndex:,其中index的值从5开始。因此,数组索引0的纹理设置为索引编号5,数组索引1处的纹理设置为索引编号6,以此类推。数组中最后一个纹理,在数组索引9处,被设置为索引编号14

用数组定义参数缓冲区

数组也可以被用于参数缓冲区结构体的元素。在这种情况下,参数缓冲区的[[ id(n) ]]属性限定符与函数参数的[[ texture(n) ]]属性限定符的行为方式相同,其中n是数组的起始索引值。然而,你不会调用MTLRenderCommandEncoder对象的setFragmentTexture:atIndex:方法来设置数组中的纹理。取而代之的是调用MTLArgumentEncoder对象的setTexture:atIndex:方法,将数组中的纹理编码到参数缓冲区中,其中index对应于起始索引值n加上数组中的纹理的索引的和。

本示例中的参数缓冲区被声明为FragmentShaderArguments结构体,这是它的定义:

typedef struct FragmentShaderArguments {     array<texture2d<float>, AAPLNumTextureArguments> exampleTextures  [[ id(AAPLArgumentBufferIDExampleTextures)  ]];     array<device float *,  AAPLNumBufferArguments>   exampleBuffers   [[ id(AAPLArgumentBufferIDExampleBuffers)   ]];     array<uint32_t, AAPLNumBufferArguments>          exampleConstants [[ id(AAPLArgumentBufferIDExampleConstants) ]]; } FragmentShaderArguments;

结构体的每个元素使用array<T, N>模板,它把元素定义为一个特定类型的数组T,以及元素数量N。该参数缓冲区包含以下资源:

  • exampleTextures,包含32个2D纹理的数组,起始索引值为0
  • exampleBuffers,包含32个float缓冲区的数组,起始索引值为100
  • exampleConstants,包含32个uint32_t常量的数组,起始索引值为200

使用资源堆的参数缓冲区

把数组元素编码到参数缓冲区

本示例通过把数组每个元素对应的索引值与setTexture:atIndex:setBuffer:offset:atIndex:方法的index参数进行匹配,把数组元素编码到参数缓冲区中。参数缓冲区中的[[ id(n) ]]属性限定符定义了这种行为。

for(uint32_t i = 0; i < AAPLNumTextureArguments; i++) {     [argumentEncoder setTexture:_texture[i]                         atIndex:AAPLArgumentBufferIDExampleTextures+i]; } for(uint32_t i = 0; i < AAPLNumBufferArguments; i++) {     [argumentEncoder setBuffer:_dataBuffer[i]                         offset:0                         atIndex:AAPLArgumentBufferIDExampleBuffers+i];      uint32_t *elementCountAddress =         [argumentEncoder constantDataAtIndex:AAPLArgumentBufferIDExampleConstants+i];      *elementCountAddress = (uint32_t)_dataBuffer[i].length / 4; }

访问参数缓冲区的数组元素

在一个函数中,访问一个参数缓冲区中编码的数组元素与访问一个标准数组的元素是一样的。在本示例中,exampleTexturesexampleBuffersexampleConstants数组是通过fragmentShader函数的fragmentShaderArgs参数访问的。每个数组元素都是用[n]下标语法访问的,其中n是数组元素的索引。

for(uint32_t textureToSample = 0; textureToSample < AAPLNumTextureArguments; textureToSample++) {     float4 textureValue = fragmentShaderArgs.exampleTextures[textureToSample].sample(textureSampler, in.texCoord);      color += textureValue; }

fragmentShader函数包含一个if-else条件,它根据texCoordx分量,确定片元在四边形的哪一侧。

如果片元在左侧,函数会对exampleBuffers数组中的每一个纹理进行采样,并将采样值相加,以确定最终输出的颜色。如果片元在四边形的右侧,函数从exampleBuffers数组中读取一个值。函数先使用texCoordx分量来确定从哪个缓冲区读取,然后使用texCoordy分量来确定读取缓冲区的位置。缓冲区中的值决定了最终输出的颜色。

// Use texCoord.x to select the buffer to read from uint32_t bufferToRead = (in.texCoord.x-0.5)*2.0 * (AAPLNumBufferArguments-1);  // Retrieve the number of elements for the selected buffer from // the array of constants in the argument buffer uint32_t numElements = fragmentShaderArgs.exampleConstants[bufferToRead];  // Determine the index used to read from the buffer uint32_t indexToRead = in.texCoord.y * numElements;  // Retrieve the buffer to read from by accessing the array of // buffers in the argument buffer device float* buffer = fragmentShaderArgs.exampleBuffers[bufferToRead];  // Read from the buffer and assign the value to the output color color = buffer[indexToRead];

将参数缓冲区与资源堆相结合

片元函数通过参数缓冲区访问32个纹理和32个缓冲区,总共有64个不同的资源。如果这些资源中的每一个,其内存是单独分配的,尽管它们驻留在数组中,Metal在把这些资源提供给GPU访问之前,需要验证这64个单独资源的内存。

相反,本示例从一个MTLHeap对象中分配资源。堆是一个单一的内存区域,可以从中分配多个资源。因此,本示例可以通过调用一次useHeap:方法,让GPU访问堆的整个内存,包括堆内所有资源的内存。

本示例实现了一个loadResources方法,该方法将资源数据加载到临时的MTLTextureMTLBuffer对象中。然后,该示例实现了一个createHeap方法,该方法计算出在堆中存储资源数据所需的总大小,并创建堆本身。

“`

  • (void) createHeap
    {
    MTLHeapDescriptor *heapDescriptor = [MTLHeapDescriptor new];
    heapDescriptor.storageMode = MTLStorageModePrivate;
    heapDescriptor.size = 0;

    // Build a descriptor for each texture and calculate the size required to store all textures in the heap
    for(uint32_t i = 0; i < AAPLNumTextureArguments; i++)
    {
    // Create a descriptor using the texture’s properties
    MTLTextureDescriptor *descriptor = [AAPLRenderer newDescriptorFromTexture:_texture[i]
    storageMode:heapDescriptor.storageMode];

    // Determine the size required for the heap for the given descriptor MTLSizeAndAlign sizeAndAlign = [_device heapTextureSizeAndAlignWithDescriptor:descriptor];  // Align the size so that more resources will fit in the heap after this texture sizeAndAlign.size += (sizeAndAlign.size & (sizeAndAlign.align - 1)) + sizeAndAlign.align;

Using Argument Buffers with Resource Heaps | Apple Developer Documentation

通过在参数缓冲区内使用数组并与资源堆结合使用,减少CPU开销。

翻译术语表

概述

在Encoding Argument Buffers on the GPU示例中,你学习了如何在参数缓冲区中指定、编码、设置和访问资源。

在本示例中,你将学习如何把参数缓冲区、资源数组和资源堆结合使用。特别是,你将学习如何定义一个包含数组的参数缓冲区结构体,以及如何从堆中分配和使用资源。本示例渲染了一个静态四边形,该四边形使用了编码到参数缓冲区中的多个资源。

入门

Xcode项目包含在macOS、iOS或tvOS上运行本示例的方案。iOS或tvOS模拟器不支持Metal,所以iOS和tvOS方案需要物理设备来运行示例。默认方案是macOS,它将按Mac上的方式运行示例。

Metal着色器语言中的参数数组

数组可以作为图形或运算函数的参数。当一个函数采用数组作为参数时,数组的第一个资源的索引等于数组参数本身的起始索引(base index)。因此,数组中后续的每个资源都会自动分配一个后续索引值,从起始索引值开始递增计数。

例如,下面的片元函数exampleFragmentFunction,其参数textureParameters是一个由10个纹理组成的数组,起始索引值为5

fragment float4 exampleFragmentFunction(array<texture2d<float>, 10> textureParameters [[ texture(5) ]])

因为textureParameters[[ texture(5) ]]属性限定符,所以设置这个参数对应的Metal框架方法是setFragmentTexture:atIndex:,其中index的值从5开始。因此,数组索引0的纹理设置为索引编号5,数组索引1处的纹理设置为索引编号6,以此类推。数组中最后一个纹理,在数组索引9处,被设置为索引编号14

用数组定义参数缓冲区

数组也可以被用于参数缓冲区结构体的元素。在这种情况下,参数缓冲区的[[ id(n) ]]属性限定符与函数参数的[[ texture(n) ]]属性限定符的行为方式相同,其中n是数组的起始索引值。然而,你不会调用MTLRenderCommandEncoder对象的setFragmentTexture:atIndex:方法来设置数组中的纹理。取而代之的是调用MTLArgumentEncoder对象的setTexture:atIndex:方法,将数组中的纹理编码到参数缓冲区中,其中index对应于起始索引值n加上数组中的纹理的索引的和。

本示例中的参数缓冲区被声明为FragmentShaderArguments结构体,这是它的定义:

typedef struct FragmentShaderArguments {     array<texture2d<float>, AAPLNumTextureArguments> exampleTextures  [[ id(AAPLArgumentBufferIDExampleTextures)  ]];     array<device float *,  AAPLNumBufferArguments>   exampleBuffers   [[ id(AAPLArgumentBufferIDExampleBuffers)   ]];     array<uint32_t, AAPLNumBufferArguments>          exampleConstants [[ id(AAPLArgumentBufferIDExampleConstants) ]]; } FragmentShaderArguments;

结构体的每个元素使用array<T, N>模板,它把元素定义为一个特定类型的数组T,以及元素数量N。该参数缓冲区包含以下资源:

  • exampleTextures,包含32个2D纹理的数组,起始索引值为0
  • exampleBuffers,包含32个float缓冲区的数组,起始索引值为100
  • exampleConstants,包含32个uint32_t常量的数组,起始索引值为200

使用资源堆的参数缓冲区

把数组元素编码到参数缓冲区

本示例通过把数组每个元素对应的索引值与setTexture:atIndex:setBuffer:offset:atIndex:方法的index参数进行匹配,把数组元素编码到参数缓冲区中。参数缓冲区中的[[ id(n) ]]属性限定符定义了这种行为。

for(uint32_t i = 0; i < AAPLNumTextureArguments; i++) {     [argumentEncoder setTexture:_texture[i]                         atIndex:AAPLArgumentBufferIDExampleTextures+i]; } for(uint32_t i = 0; i < AAPLNumBufferArguments; i++) {     [argumentEncoder setBuffer:_dataBuffer[i]                         offset:0                         atIndex:AAPLArgumentBufferIDExampleBuffers+i];      uint32_t *elementCountAddress =         [argumentEncoder constantDataAtIndex:AAPLArgumentBufferIDExampleConstants+i];      *elementCountAddress = (uint32_t)_dataBuffer[i].length / 4; }

访问参数缓冲区的数组元素

在一个函数中,访问一个参数缓冲区中编码的数组元素与访问一个标准数组的元素是一样的。在本示例中,exampleTexturesexampleBuffersexampleConstants数组是通过fragmentShader函数的fragmentShaderArgs参数访问的。每个数组元素都是用[n]下标语法访问的,其中n是数组元素的索引。

for(uint32_t textureToSample = 0; textureToSample < AAPLNumTextureArguments; textureToSample++) {     float4 textureValue = fragmentShaderArgs.exampleTextures[textureToSample].sample(textureSampler, in.texCoord);      color += textureValue; }

fragmentShader函数包含一个if-else条件,它根据texCoordx分量,确定片元在四边形的哪一侧。

如果片元在左侧,函数会对exampleBuffers数组中的每一个纹理进行采样,并将采样值相加,以确定最终输出的颜色。如果片元在四边形的右侧,函数从exampleBuffers数组中读取一个值。函数先使用texCoordx分量来确定从哪个缓冲区读取,然后使用texCoordy分量来确定读取缓冲区的位置。缓冲区中的值决定了最终输出的颜色。

// Use texCoord.x to select the buffer to read from uint32_t bufferToRead = (in.texCoord.x-0.5)*2.0 * (AAPLNumBufferArguments-1);  // Retrieve the number of elements for the selected buffer from // the array of constants in the argument buffer uint32_t numElements = fragmentShaderArgs.exampleConstants[bufferToRead];  // Determine the index used to read from the buffer uint32_t indexToRead = in.texCoord.y * numElements;  // Retrieve the buffer to read from by accessing the array of // buffers in the argument buffer device float* buffer = fragmentShaderArgs.exampleBuffers[bufferToRead];  // Read from the buffer and assign the value to the output color color = buffer[indexToRead];

将参数缓冲区与资源堆相结合

片元函数通过参数缓冲区访问32个纹理和32个缓冲区,总共有64个不同的资源。如果这些资源中的每一个,其内存是单独分配的,尽管它们驻留在数组中,Metal在把这些资源提供给GPU访问之前,需要验证这64个单独资源的内存。

相反,本示例从一个MTLHeap对象中分配资源。堆是一个单一的内存区域,可以从中分配多个资源。因此,本示例可以通过调用一次useHeap:方法,让GPU访问堆的整个内存,包括堆内所有资源的内存。

本示例实现了一个loadResources方法,该方法将资源数据加载到临时的MTLTextureMTLBuffer对象中。然后,该示例实现了一个createHeap方法,该方法计算出在堆中存储资源数据所需的总大小,并创建堆本身。

“`

  • (void) createHeap
    {
    MTLHeapDescriptor *heapDescriptor = [MTLHeapDescriptor new];
    heapDescriptor.storageMode = MTLStorageModePrivate;
    heapDescriptor.size = 0;

    // Build a descriptor for each texture and calculate the size required to store all textures in the heap
    for(uint32_t i = 0; i < AAPLNumTextureArguments; i++)
    {
    // Create a descriptor using the texture’s properties
    MTLTextureDescriptor *descriptor = [AAPLRenderer newDescriptorFromTexture:_texture[i]
    storageMode:heapDescriptor.storageMode];

    // Determine the size required for the heap for the given descriptor MTLSizeAndAlign sizeAndAlign = [_device heapTextureSizeAndAlignWithDescriptor:descriptor];  // Align the size so that more resources will fit in the heap after this texture sizeAndAlign.size += (sizeAndAlign.size & (sizeAndAlign.align - 1)) + sizeAndAlign.align;

部分转自互联网,侵权删除联系

赞(0) 打赏
部分文章转自网络,侵权联系删除b2bchain区块链学习技术社区 » 使用资源堆的参数缓冲区求职学习资料
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

b2b链

联系我们联系我们