oxigdal-gpu 0.1.4

GPU-accelerated geospatial operations for OxiGDAL using WGPU
Documentation
// GPU-accelerated raster reprojection
// Transforms each output pixel to source coordinates using the inverse of the target CRS transform

struct ReprojParams {
    // Source raster dimensions
    src_width: u32,
    src_height: u32,
    // Output raster dimensions
    dst_width: u32,
    dst_height: u32,
    // Source geo-transform (affine): [a, b, c, d, e, f]
    // x_geo = c + col * a + row * b
    // y_geo = f + col * d + row * e
    src_gt: array<f32, 6>,
    // Destination inverse geo-transform
    dst_inv_gt: array<f32, 6>,
    // Resampling method: 0=nearest, 1=bilinear
    resample_method: u32,
    // Nodata value
    nodata: f32,
    use_nodata: u32,
};

@group(0) @binding(0) var<uniform> params: ReprojParams;
@group(0) @binding(1) var src_texture: texture_2d<f32>;
@group(0) @binding(2) var src_sampler: sampler;
@group(0) @binding(3) var<storage, read_write> dst_buffer: array<f32>;

@compute @workgroup_size(16, 16)
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
    let dst_col = gid.x;
    let dst_row = gid.y;

    if dst_col >= params.dst_width || dst_row >= params.dst_height {
        return;
    }

    let dst_idx = dst_row * params.dst_width + dst_col;

    // For now: simple identity passthrough (real reprojection requires CRS math)
    let src_col = f32(dst_col) * f32(params.src_width) / f32(params.dst_width);
    let src_row = f32(dst_row) * f32(params.src_height) / f32(params.dst_height);

    let uv = vec2<f32>(src_col / f32(params.src_width), src_row / f32(params.src_height));
    let value = textureSampleLevel(src_texture, src_sampler, uv, 0.0).r;

    dst_buffer[dst_idx] = value;
}