【发布时间】:2016-08-08 09:36:37
【问题描述】:
我有一个包含 16 位无符号整数 (MTLPixelFormatR16Uint) 的 MTLTexture。值的范围从大约 7000 到 20000,其中 0 用作“nodata”值,这就是在下面的代码中跳过它的原因。我想找到最小值和最大值,以便我可以在 0-255 之间重新调整这些值。最终,我将寻找基于数据直方图的最小值和最大值(它有一些异常值),但现在我坚持简单地提取最小值/最大值。
我可以将数据从 GPU 读取到 CPU 并提取最小值/最大值,但我更愿意在 GPU 上执行此任务。
第一次尝试
每个线程组使用 16x16 个线程调度命令编码器,线程组的数量取决于纹理大小(例如,宽度 = textureWidth / 16,高度 = 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);
}
}
}
由此我得到一个最小值和最大值,但对于同一个数据集,最小值和最大值通常会返回不同的值。可以肯定的是,当有多个线程在运行时,这是单个线程的最小值和最大值。
第二次尝试
在上一次尝试的基础上,这次我将存储每个线程的单个最小值/最大值,全部为 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);
}
}
}
这将返回一个包含 256 组最小/最大值的数组。从这些我想我可以找到最小值中的最低值,但这似乎是一个糟糕的方法。将不胜感激指向正确方向的指针,谢谢!
【问题讨论】:
标签: ios multithreading metal