Ho uno MTLTexture
contenente numeri interi senza segno a 16 bit (MTLPixelFormatR16Uint
). I valori vanno da circa 7000 a 20000, con 0 usato come valore 'nodata', motivo per cui viene saltato nel codice sottostante. Mi piacerebbe trovare i valori minimi e massimi in modo da poter ridimensionare questi valori tra 0-255. In definitiva cercherò di basare i valori minimi e massimi su un istogramma dei dati (ha alcuni valori anomali), ma per ora sono bloccato semplicemente estraendo il minimo/massimo.Ricerca del valore minimo e massimo all'interno di una trama metallica
Posso leggere i dati dalla GPU alla CPU e tirare fuori i valori min/max ma preferirei eseguire questa operazione sulla GPU.
Primo tentativo
L'encoder comando viene inviato con 16x16 filetti per gruppo filo, il numero di gruppi di thread si basa sulla dimensione trama (per esempio, larghezza = textureWidth/16, altezza = textureHeight/16).
typedef struct {
atomic_uint min;
atomic_uint max;
} BandMinMax;
kernel void minMax(texture2d<ushort, access::read> band1 [[texture(0)]],
device BandMinMax &out [[buffer(0)]],
uint2 gid [[thread_position_in_grid]])
{
ushort value = band1.read(gid).r;
if (value != 0) {
uint currentMin = atomic_load_explicit(&out.min, memory_order_relaxed);
uint currentMax = atomic_load_explicit(&out.max, memory_order_relaxed);
if (value > currentMax) {
atomic_store_explicit(&out.max, value, memory_order_relaxed);
}
if (value < currentMin) {
atomic_store_explicit(&out.min, value, memory_order_relaxed);
}
}
}
Da questo ottengo un valore minimo e massimo, ma per lo stesso insieme di dati il min e max sarà spesso restituire valori diversi. Abbastanza sicuro questo è il minimo e il massimo da un singolo thread quando ci sono più thread in esecuzione.
Secondo tentativo
Basandosi sul tentativo precedente, questa volta sto memorizzando i singoli valori min/max da ogni thread, tutti 256 (16x16).
kernel void minMax(texture2d<ushort, access::read> band1 [[texture(0)]],
device BandMinMax *out [[buffer(0)]],
uint2 gid [[thread_position_in_grid]],
uint tid [[ thread_index_in_threadgroup ]])
{
ushort value = band1.read(gid).r;
if (value != 0) {
uint currentMin = atomic_load_explicit(&out[tid].min, memory_order_relaxed);
uint currentMax = atomic_load_explicit(&out[tid].max, memory_order_relaxed);
if (value > currentMax) {
atomic_store_explicit(&out[tid].max, value, memory_order_relaxed);
}
if (value < currentMin) {
atomic_store_explicit(&out[tid].min, value, memory_order_relaxed);
}
}
}
Questo restituisce un array contenente 256 serie di valori min/max. Da questi suppongo di aver trovato il minimo dei valori minimi, ma questo mi sembra un approccio inadeguato. Gradirei un puntatore nella giusta direzione, grazie!
Grazie @warrenm, sembra funzionare. Ho una domanda sull'offset per il buffer atomico; es. 'atomicBuffer + ((tgpig [1] * tpt [0] + tgpig [0]) * 2)'. La mia comprensione è che le operazioni atomiche si applicano per threadgroup (si prega di correggere qualcuna di queste ipotesi se BTW errato)? Uso i thread 16x16 per gruppo di thread passati nel kernel tramite l'annotazione 'threads_per_threadgroup' alla variabile' tpt'. Non sono sicuro che questa sia la larghezza della griglia del mio gruppo di thread? per esempio; la dimensione della trama è 192x160, con la griglia di threadgroup 12x10 e il calcolo di offset 'atomicBuffer + ((tgpig [1] * 12 + tgpig [0]) * 2)'? – lock
Si prega di scusare l'hardcoded 12 in quest'ultima riga. Penso che quello che sto cercando di dire è la sostituzione di 'threads_per_threadgroup' con' threadgroups_per_grid' nel kernel min_max_per_threadgroup lo corregge? – lock
@lock Sì, hai assolutamente ragione. Sono stato fortunato nella mia implementazione perché 'threads_per_threadgroup' è stato uguale a' threadgroups_per_grid'. Corretto sopra – warrenm