簡體   English   中英

您如何將規范化的設備與Apple的Metal內核功能進行協調?

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

我在Metal中有一個內核函數,我將紋理傳遞給該內核函數,以便可以對圖像執行一些操作。 我傳入了uint2 gid [[thread_position_in_grid]] ,該像素為我提供了整數的像素坐標。

為了獲得標准化的設備坐標,我可以對gid.xgid.y以及我的紋理寬度和gid.y進行一些簡單的數學運算。 這是最好的方法嗎? 更好的方法?

您的方法是一種很好的方法。 如果您不想在內核函數中查詢紋理尺寸或創建僅用於傳遞它們的緩沖區,則可以使用-[MTLComputeCommandEncoder setBytes:length:atIndex:]方法將紋理尺寸綁定為“臨時” Metal處理的各種緩沖區:

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

我認為您是對的,這是在GLSL中通常使用相同方法的好方法:

  1. 計算紋理像素大小

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

  1. 然后用它來獲得標准化的像素位置

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);

問題中指定的方法效果很好。 但是為了完成,使用非規范化(和/或規范化的設備坐標)讀取紋理的另一種方法是使用采樣器。

創建一個采樣器:

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;
}

然后將其附加到您的計算命令編碼器:

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];

最后在內核中使用它:

// 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;
}

使用采樣器可以指定采樣參數(如過濾)。 您還可以通過使用附加到同一內核的不同采樣器以不同方式訪問紋理。 采樣器還避免了必須通過並檢查紋理尺寸的邊界。

請注意,也可以從計算內核中設置采樣器。 請參閱金屬底紋語言規范中的2.6節采樣器

最后,讀取函數(使用問題中指定的gid)與使用采樣器采樣之間的一個主要區別是read()采用整數坐標,而sample()采用浮點坐標。 因此,傳遞給樣本的整數坐標將轉換為等效的浮點數。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM