struct Params { block_size: vec2, offsets_stride: u32, search_radius: i32, skip_threshold: f32, } struct BlockOffset { score: f32, offset: vec2, tint: vec3, } @group(0) @binding(0) var params: Params; @group(0) @binding(1) var offsets: array; @group(0) @binding(2) var next: texture_2d; @group(0) @binding(3) var prev: texture_2d; @compute @workgroup_size(1) fn main(@builtin(global_invocation_id) global_id: vec3) { let uv = vec2(global_id.xy) * params.block_size; let _f = search_offset(uv); let best_err = _f.error; let best_offset = _f.offset; var best_tint = vec3(0.); var average_pcol = vec3(0.); var average_ncol = vec3(0.); for (var x = 0; x < params.block_size.x; x++) { for (var y = 0; y < params.block_size.y; y++) { let base = uv+vec2(x,y); average_pcol += textureLoad(prev, base+best_offset, 0).rgb; average_ncol += textureLoad(next, base, 0).rgb; }} let tint = (average_ncol - average_pcol) / f32(params.block_size.x * params.block_size.y); var err = 0.; for (var x = 0; x < params.block_size.x; x++) { for (var y = 0; y < params.block_size.y; y++) { let base = uv+vec2(x,y); let pcol = textureLoad(prev, base+best_offset, 0).rgb+tint; let ncol = textureLoad(next, base, 0).rgb; err += distance(pcol, ncol); }} if err < best_err { best_tint = tint; } offsets[global_id.x + global_id.y * params.offsets_stride] = BlockOffset(best_err, best_offset, best_tint); } struct SearchRes {offset: vec2, error: f32} fn search_offset(uv: vec2) -> SearchRes { var best_err = 100000000.; var best_offset = vec2(0); // TODO: better ordering for (var ox = -params.search_radius; ox <= params.search_radius; ox++) { for (var oy = -params.search_radius; oy <= params.search_radius; oy++) { let offset = vec2(ox,oy); var err = 0.; for (var x = 0; x < params.block_size.x; x++) { for (var y = 0; y < params.block_size.y; y++) { let base = uv+vec2(x,y); let pcol = textureLoad(prev, base+offset, 0).rgb; let ncol = textureLoad(next, base, 0).rgb; err += distance(pcol, ncol); }} if err < best_err { best_err = err; best_offset = offset; if err < params.skip_threshold { return SearchRes(offset, err); } } }} return SearchRes(best_offset,best_err); } // fn colormap_vec(v: vec2) -> vec3 { // return vec3(v.y, v.x - 0.5 * v.y, -v.x - 0.5 * v.y); // }