《Metal》官方文档翻译008--数据并行计算处理:计算命令编码器

本章介绍如何创建和使用MTLComputeCommandEncoder对象来对数据并行计算处理状态和命令进行编码并提交它们以便在设备上执行。

要执行数据并行计算,请按照以下主要步骤操作:

1:使用一种MTLDevice方法创建一个MTLComputePipelineState包含来自MTLFunction对象的编译代码的计算状态(),如创建计算状态中所述。该MTLFunction对象表示与Metal着色语言编写的compute函数,如在描述的功能和库。

2:指定MTLComputePipelineState计算命令编码器要使用的对象,如为计算命令编码器指定计算状态和资源所述。

3:指定资源和相关的对象(MTLBuffer,MTLTexture以及可能的MTLSamplerState),其可以包含要处理的数据,并通过计算返回的状态,如在讨论指定计算状态和参考资料中的计算命令编码器。还设置参数表索引,以便Metal框架代码可以在着色器代码中找到相应的资源。在任何给定的时刻,MTLComputeCommandEncoder都可以与多个资源对象相关联。

4:调度计算函数指定的次数,如执行计算命令中所述。

创建计算流水线状态

一个MTLFunction对象表示可以由MTLComputePipelineState对象执行的数据并行代码。该MTLComputeCommandEncoder对象编码设置参数并执行compute函数命令。因为创建计算流水线状态可能需要昂贵的Metal shading语言代码的编译,您可以使用阻塞或异步方法来以最适合您的应用程序设计的方式安排此类工作。

  • 要同步创建计算流水线状态对象,请调用其中的一个newComputePipelineStateWithFunction:error:或多个newComputePipelineStateWithFunction:options:reflection:erro:方法MTLDevice。这些方法阻止当前线程,而Metal编译着色器代码以创建管道状态对象。

  • 要创建异步计算流水线状态对象,调用无论是newComputePipelineStateWithFunction:completionHandler:或
    newComputePipelineStateWithFunction:options:completionHandler:方法MTLDevice。这些方法立即返回 - Metal异步编译着色器代码来创建管道状态对象,然后调用完成处理程序来提供新MTLComputePipelineState对象。

创建MTLComputePipelineState对象时,您还可以选择创建反映数据,以显示计算函数及其参数的详细信息。该newComputePipelineStateWithFunction:options:reflection:error:和newComputePipelineStateWithFunction:options:completionHandler:方法提供这些数据。如果不使用反射数据,请避免使用。有关如何分析反射数据的更多信息,请参阅在运行时确定功能详细信息。

为计算命令编码器指定计算状态和资源

对象的setComputePipelineState:方法MTLComputeCommandEncoder指定用于数据并行计算通过的状态,包括编译的计算着色器函数。在任何给定的时刻,计算命令编码器可以仅与一个计算功能相关联。

以下MTLComputeCommandEncoder方法指定用作MTLComputePipelineState对象所表示的计算函数的参数的资源(即缓冲区,纹理,采样器状态或线程组内存)。

  • setBuffer:offset:atIndex:

  • setBuffers:offsets:withRange:

  • setTexture:atIndex:

  • setTextures:withRange:

  • setSamplerState:atIndex:

  • setSamplerState:lodMinClamp:lodMaxClamp:atIndex:

  • setSamplerStates:withRange:

  • setSamplerStates:lodMinClamps:lodMaxClamps:withRange:

  • setThreadgroupMemoryLength:atIndex:
    每个方法将一个或多个资源分配给相应的参数,如图6-1所示。

《Metal》官方文档翻译008--数据并行计算处理:计算命令编码器_第1张图片
图6-1 计算命令编码器的参数表

缓冲区,纹理或采样器状态参数表中最大条目数的限制列在“ 实现限制”表中。

最大总线程组内存分配的限制也列在实施限制表中。

执行计算命令

要编码执行计算函数的命令,请调用dispatchThreadgroups:threadsPerThreadgroup:方法MTLComputeCommandEncoder并指定线程组维度和线程组数。您可以查询threadExecutionWidth和maxTotalThreadsPerThreadgroup属性MTLComputePipelineState来优化此设备上计算功能的执行。

线程组中的线程总数是threadsPerThreadgroup:的组成部分的乘积threadsPerThreadgroup.width *threadsPerThreadgroup.height *threadsPerThreadgroup.depth。该
maxTotalThreadsPerThreadgroup属性指定在单个线程组中可以在设备上执行此计算功能的最大线程数。

计算命令按照编码到命令缓冲区的顺序执行。当与命令关联的所有线程组完成执行并将所有结果写入内存时,计算命令将完成执行。由于这种排序,计算命令的结果可用于在命令缓冲区中编码的任何命令。

要结束计算命令编码器的编码命令,请调用其endEncoding方法MTLComputeCommandEncoder。在结束上一个命令编码器之后,您可以创建任何类型的新命令编码器,以将其他命令编码到命令缓冲区中。

代码示例:执行数据并行函数

清单6-1显示了创建和使用MTLComputeCommandEncoder对象执行指定数据上的图像转换并行计算的示例。(此示例不显示如何创建和初始化设备,库,命令队列和资源对象。)示例创建命令缓冲区,然后使用它来创建MTLComputeCommandEncoder对象。接下来,MTLFunction
创建一个对象filter_main,该MTLLibrary对象表示从对象加载的入口点,如清单6-2所示。然后使用函数对象来创建一个MTLComputePipelineState被调用的对象filterState。

计算函数对inputImage返回的结果对图像执行图像变换和过滤操作outputImage。首先setTexture:atIndex:,setBuffer:offset:atIndex:方法将纹理和缓冲区对象分配给指定参数表中的索引。paramsBuffer指定用于执行图像变换的值,并inputTableData指定过滤器权重。计算功能在每个维度中被执行为尺寸为16 x 16像素的2D线程组。该dispatchThreadgroups:threadsPerThreadgroup:方法排队命令来分派执行计算函数的线程,该endEncoding方法终止MTLComputeCommandEncoder。最后,尽快执行命令的commit方法MTLCommandBuffer。

清单6-1 在计算状态中指定和运行函数

id  device;
id  library;
id  commandQueue;

id  inputImage;
id  outputImage;
id  inputTableData;
id  paramsBuffer;

// ... Create and initialize device, library, queue, resources

// Obtain a new command buffer
id  commandBuffer = [commandQueue commandBuffer];

// Create a compute command encoder
id computeCE = [commandBuffer computeCommandEncoder];

NSError *errors;
id  func = [library newFunctionWithName:@"filter_main"];
id  filterState
          = [device newComputePipelineStateWithFunction:func error:&errors];
[computeCE setComputePipelineState:filterState];
[computeCE setTexture:inputImage atIndex:0];
[computeCE setTexture:outputImage atIndex:1];
[computeCE setTexture:inputTableData atIndex:2];
[computeCE setBuffer:paramsBuffer offset:0 atIndex:0];

MTLSize threadsPerGroup = {16, 16, 1};
MTLSize numThreadgroups = {inputImage.width/threadsPerGroup.width,
                       inputImage.height/threadsPerGroup.height, 1};

[computeCE dispatchThreadgroups:numThreadgroups
                            threadsPerThreadgroup:threadsPerGroup];
[computeCE endEncoding];

// Commit the command buffer
[commandBuffer commit];

清单6-2显示了上述示例的相应着色器代码。(功能read_and_transform和filter_table用户定义代码的占位符)。

清单6-2 着色语言计算功能声明

kernel void filter_main(
  texture2d   inputImage   [[ texture(0) ]],
  texture2d  outputImage  [[ texture(1) ]],
  uint2 gid                                    [[ thread_position_in_grid ]],
  texture2d table        [[ texture(2) ]],
   constant Parameters* params                  [[ buffer(0) ]]
 )
{
  float2 p0          = static_cast(gid);
  float3x3 transform = params->transform;
  float4   dims      = params->dims;

  float4 v0 = read_and_transform(inputImage, p0, transform);
  float4 v1 = filter_table(v0,table, dims);

  outputImage.write(v1,gid);
}

下一页

上一页

你可能感兴趣的:(《Metal》官方文档翻译008--数据并行计算处理:计算命令编码器)