简体   繁体   English

您如何将规范化的设备与Apple的Metal内核功能进行协调?

[英]How do you get normalized devices coordinates into Apple's Metal kernel functions?

I have a kernel function in Metal that I pass in a texture to so that I can perform some operations on the image. 我在Metal中有一个内核函数,我将纹理传递给该内核函数,以便可以对图像执行一些操作。 I'm passing in uint2 gid [[thread_position_in_grid]] which gives me the pixel coordinates as integers. 我传入了uint2 gid [[thread_position_in_grid]] ,该像素为我提供了整数的像素坐标。

To get a the normalized devices coordinates I can do some simple math on gid.x and gid.y along with my texture width and heigh. 为了获得标准化的设备坐标,我可以对gid.xgid.y以及我的纹理宽度和gid.y进行一些简单的数学运算。 Is this the best way to do it? 这是最好的方法吗? Better way? 更好的方法?

Your approach is a good one. 您的方法是一种很好的方法。 If you don't want to query the texture dimensions inside the kernel function or create a buffer just to pass them in, you can use the -[MTLComputeCommandEncoder setBytes:length:atIndex:] method to bind the texture dimensions in a "temporary" buffer of sorts that is handled by Metal: 如果您不想在内核函数中查询纹理尺寸或创建仅用于传递它们的缓冲区,则可以使用-[MTLComputeCommandEncoder setBytes:length:atIndex:]方法将纹理尺寸绑定为“临时” Metal处理的各种缓冲区:

[computeEncoder setBytes:&dimensions length:sizeof(dimensions) atIndex:0]

I think you right, and it is good way to use the same approach usually is applied in GLSL: 我认为您是对的,这是在GLSL中通常使用相同方法的好方法:

  1. compute texel size 计算纹理像素大小

float2 texSize = float2(1/outTexture.get_with(),1/outTexture.get_height());

  1. then use it to get normalized pixel position 然后用它来获得标准化的像素位置

constexpr sampler s(address::clamp_to_edge, filter::linear, coord::normalized);

//
//  something to do...
//
float4 color = inTexture.sample(s,float2(gid)*texSize);

//
// something todo with pixel
//

outTexture.write(color,gid);

The method specified in the question works well. 问题中指定的方法效果很好。 But for completion, an alternate way to read from textures using non-normalized (and/or normalized device coordinates) would be to use samplers. 但是为了完成,使用非规范化(和/或规范化的设备坐标)读取纹理的另一种方法是使用采样器。

Create a sampler: 创建一个采样器:

id<MTLSamplerState> GetSamplerState()
{
    MTLSamplerDescriptor *desc = [[MTLSamplerDescriptor alloc] autorelease];
    desc.minFilter = MTLSamplerMinMagFilterNearest;
    desc.magFilter = MTLSamplerMinMagFilterNearest;
    desc.mipFilter = MTLSamplerMipFilterNotMipmapped;
    desc.maxAnisotropy = 1;
    desc.sAddressMode = MTLSamplerAddressModeClampToEdge;
    desc.tAddressMode = MTLSamplerAddressModeClampToEdge;
    desc.rAddressMode = MTLSamplerAddressModeClampToEdge;

    // The key point: specifies that the sampler reads non-normalized coordinates
    desc.normalizedCoordinates = NO;

    desc.lodMinClamp = 0.0f;
    desc.lodMaxClamp = FLT_MAX;

    id <MTLSamplerState> sampler_state = nil;
    sampler_state = [[device_ newSamplerStateWithDescriptor:desc] autorelease];

    // Release the descriptor
    desc = nil;

    return sampler_state;
}

And then attach it to your compute command encoder: 然后将其附加到您的计算命令编码器:

id <MTLComputeCommandEncoder> compute_encoder = [comand_buffer computeCommandEncoder];
id<MTLSamplerState> ss = GetSamplerState();

// Attach the sampler state to the encoder, say at sampler bind point 0
[compute_encoder setSamplerState:ss atIndex:0];

// And set your texture, say at texture bind point 0
[compute_encoder setTexture:my_texture atIndex:0];

Finally use it in the kernel: 最后在内核中使用它:

// An example kernel that samples from a texture,
// writes one component of the sample into an output buffer
kernel void compute_main( 
                texture2d<uint, access::sample> tex_to_sample [[ texture(0) ]],
                sampler smp [[ sampler(0) ]],
                device uint *out [[buffer(0)]],
                uint2 tid [[thread_position_in_grid]])
{
    out[tid] = tex_to_sample.sample(smp, tid).x;
}

Using a sampler allows you to specify parameters for sampling (like filtering). 使用采样器可以指定采样参数(如过滤)。 You can also access the texture in different ways by using different samplers attached to the same kernel. 您还可以通过使用附加到同一内核的不同采样器以不同方式访问纹理。 Sampler also avoids having to pass and check for bounds on texture dimensions. 采样器还避免了必须通过并检查纹理尺寸的边界。

Note that the sampler can also be set up from within the compute kernel. 请注意,也可以从计算内核中设置采样器。 Refer to Section 2.6 Samplers in the Metal Shading Language Specification 请参阅金属底纹语言规范中的2.6节采样器

Finally, one main difference between read function (using gid, as specified in the question) vs. sampling using a sampler is that read() takes integer coordinates, whereas sample() takes floating point coordinates. 最后,读取函数(使用问题中指定的gid)与使用采样器采样之间的一个主要区别是read()采用整数坐标,而sample()采用浮点坐标。 So integer coordinates passed into sample will get casted into equivalent floating-point. 因此,传递给样本的整数坐标将转换为等效的浮点数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM