Files
rustyJ/crates/ri-metal/shaders/histogram.metal
T
Omar SobhandClaude Opus 4.6 0fd39d7fd3 Add M9-M14: UI redesign, plugins, macros, 3D viz, binary/segmentation ops, Metal GPU, scientific LUTs
M9: TailwindCSS + shadcn/ui frontend redesign
M10: Dynamic plugin system with shared library loading
M11: Macro recording, playback, and batch processing
M12: 3D volume visualization, marching cubes, STL/OBJ export, rivol:// protocol
M13: Additional GPU shaders, enhanced auto-threshold, merge channels
M14: Binary image processing (EDT, watershed, skeleton, connected components,
     voronoi), segmentation & analysis (particles, colocalization, find maxima),
     math/noise/filter/transform ops (60+ total), scientific LUTs (Fire, Ice,
     Spectrum, Jet, Phase, HiLo + .lut file I/O), Apple Metal GPU optimization
     (metal-only feature, Apple Silicon detection, lower dispatch threshold),
     native Metal compute crate (ri-metal with MSL shaders via objc2-metal),
     7 new WGSL GPU shaders (bilateral, variance, mean, math_ops, outline,
     minmax_filter, affine transform). 25 crates, 162 tests, 75+ IPC commands.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-03-10 07:41:56 -07:00

46 lines
1.6 KiB
Metal

#include <metal_stdlib>
using namespace metal;
/// Per-threadgroup histogram using shared memory atomics, then reduced to global.
/// Input: buffer of f32 pixel values (expected range [0, 1]).
/// Output: buffer of 256 uint32 bins.
struct HistogramParams {
uint pixel_count;
uint _pad0;
uint _pad1;
uint _pad2;
};
kernel void histogram_compute(
device const float* input [[buffer(0)]],
device atomic_uint* output [[buffer(1)]],
constant HistogramParams& params [[buffer(2)]],
threadgroup atomic_uint* local_hist [[threadgroup(0)]],
uint tid [[thread_index_in_threadgroup]],
uint tg_size [[threads_per_threadgroup]],
uint gid [[thread_position_in_grid]]
) {
// Initialize threadgroup histogram bins to zero
for (uint i = tid; i < 256; i += tg_size) {
atomic_store_explicit(&local_hist[i], 0, memory_order_relaxed);
}
threadgroup_barrier(mem_flags::mem_threadgroup);
// Each thread accumulates its pixel into the local histogram
if (gid < params.pixel_count) {
float val = input[gid];
uint bin = (uint)clamp(val * 255.0f, 0.0f, 255.0f);
atomic_fetch_add_explicit(&local_hist[bin], 1, memory_order_relaxed);
}
threadgroup_barrier(mem_flags::mem_threadgroup);
// First threads in group flush local histogram to global
for (uint i = tid; i < 256; i += tg_size) {
uint count = atomic_load_explicit(&local_hist[i], memory_order_relaxed);
if (count > 0) {
atomic_fetch_add_explicit(&output[i], count, memory_order_relaxed);
}
}
}