anchor.diff:  
           }
   
  +      
  +    let inputImage2d =
  +        sampler2d {
  +            texture uniform?InputTexture
  +            filter Filter.MinMagMipPoint
  +            addressU WrapMode.Clamp
  +            addressV WrapMode.Clamp
  +        }
  +
  +    [<LocalSize(X = 8, Y = 8)>]
  +    let mapReduceImageKernel2d (map : Expr<V3i -> V4f -> 'b>) (add : Expr<'b -> 'b -> 'b>) (numGroups : V2i) (inputSize : V2i) (inputLevel : int) (outputData : 'b[]) =
  +        compute {
  +            let s = inputSize
  +            let ggc = numGroups
  +            let lc = getLocalId().XY
  +            let gc = getWorkGroupId().XY
  +            let tid = lc.Y * 8 + lc.X
  +            
  +            let group = gc.Y * ggc.X + gc.X
  +
  +            let ai = gc * V2i(16,8) + lc * V2i(2,1)
  +            let bi = ai + V2i(1,0)
  +            let lai = lc.Y * 16 + lc.X * 2
  +            let lbi = lai + 1
  +            
  +            let mem : 'b[] = allocateShared 128
  +
  +            if ai.X < s.X && ai.Y < s.Y then mem.[lai] <- (%map) (V3i(ai, 0)) (V4f inputImage2d.[ai, inputLevel])
  +            else mem.[lai] <- (%map) (V3i(ai, 0)) V4f.Zero
  +
  +            if bi.X < s.X && bi.Y < s.Y then mem.[lbi] <- (%map) (V3i(bi, 0)) (V4f inputImage2d.[bi, inputLevel])
  +            else mem.[lbi] <- (%map) (V3i(bi, 0)) V4f.Zero
  +
  +            
  +            barrier()
  +            let mutable s = 64
  +            while s > 0 do
  +                if tid < s then
  +                    mem.[tid] <- (%add) mem.[tid] mem.[tid + s]
  +
  +                s <- s >>> 1
  +                barrier()
  +
  +            if tid = 0 then
  +                outputData.[group] <- mem.[0]
  +
  +        }
  +
  +
  +      
  +    let inputImage3d =
  +        sampler3d {
  +            texture uniform?InputTexture
  +            filter Filter.MinMagMipPoint
  +            addressU WrapMode.Clamp
  +            addressV WrapMode.Clamp
  +            addressW WrapMode.Clamp
  +        }
  +
  +    [<LocalSize(X = 4, Y = 4, Z = 2)>]
  +    let mapReduceImageKernel3d (map : Expr<V3i -> V4f -> 'b>) (add : Expr<'b -> 'b -> 'b>) (numGroups : V3i) (inputSize : V3i) (inputLevel : int) (outputData : 'b[]) =
  +        compute {
  +            let s = inputSize
  +            let ggc = numGroups
  +            let lc = getLocalId()
  +            let gc = getWorkGroupId()
  +            let tid = lc.Z * 16 + lc.Y * 4 + lc.X
  +            
  +            let group = gc.Z * (ggc.X * ggc.Y) + gc.Y * ggc.X + gc.X
  +
  +            let ai = gc * V3i(8,4,2) + lc * V3i(2,1,1)
  +            let bi = ai + V3i(1,0,0)
  +            let lai = lc.Z * 32 + lc.Y * 8 + lc.X * 2
  +            let lbi = lai + 1
  +            
  +            let mem : 'b[] = allocateShared 128
  +
  +            if ai.X < s.X && ai.Y < s.Y then mem.[lai] <- (%map) ai (V4f inputImage3d.[ai, inputLevel])
  +            else mem.[lai] <- (%map) ai V4f.Zero
  +
  +            if bi.X < s.X && bi.Y < s.Y then mem.[lbi] <- (%map) bi (V4f inputImage3d.[bi, inputLevel])
  +            else mem.[lbi] <- (%map) bi V4f.Zero
  +
  +            
  +            barrier()
  +            let mutable s = 64
  +            while s > 0 do
  +                if tid < s then
  +                    mem.[tid] <- (%add) mem.[tid] mem.[tid + s]
  +
  +                s <- s >>> 1
  +                barrier()
  +
  +            if tid = 0 then
  +                outputData.[group] <- mem.[0]
  +
  +        }
  +
  +
  +    [<LocalSize(X = 64)>]
  +    let map (map : Expr<int -> 'a -> 'b>) (src : 'a[]) (dst : 'b[]) =
  +        compute {
  +            let id = getGlobalId().X
  +            let srcOffset : int = uniform?SrcOffset
  +            let srcDelta : int = uniform?SrcDelta
  +            let srcCnt : int = uniform?SrcCount
  +            
  +            let dstOffset : int = uniform?DstOffset
  +            let dstDelta : int = uniform?DstDelta
  +
  +            if id < srcCnt then
  +                dst.[dstOffset + id * dstDelta] <- (%map) id src.[srcOffset + id * srcDelta]
  +        }
  +
  +
  +type private Map<'a, 'b when 'a : unmanaged and 'b : unmanaged>(runtime : IComputeRuntime, map : Expr<int -> 'a -> 'b>) =
  +    
  +    static let ceilDiv (v : int) (d : int) =
  +        if v % d = 0 then v / d
  +        else 1 + v / d
  +
  +    let map    = runtime.CreateComputeShader (Kernels.map map)
  +
  +    let build (src : IBufferVector<'a>) (dst : IBufferVector<'b>) =
  +        let args = runtime.NewInputBinding(map)
  +        
  +        args.["src"] <- src.Buffer
  +        args.["SrcOffset"] <- src.Origin
  +        args.["SrcDelta"] <- src.Delta
  +        args.["SrcCount"] <- src.Count
  +        
  +        args.["dst"] <- dst.Buffer
  +        args.["DstOffset"] <- dst.Origin
  +        args.["DstDelta"] <- dst.Delta
  +        args.Flush()
  +        
  +        args, [
  +            ComputeCommand.Bind map
  +            ComputeCommand.SetInput args
  +            ComputeCommand.Dispatch(ceilDiv (int src.Count) 64)
  +            ComputeCommand.Sync(dst.Buffer)
  +        ]
  +
  +
  +
  +    member x.Compile(input : IBufferVector<'a>, output : IBufferVector<'b>) =
  +        let args, cmd = build input output
  +        
  +        let prog = runtime.Compile cmd
  +        { new ComputeProgram<unit>() with
  +            member x.Dispose() =
  +                prog.Dispose()
  +                args.Dispose()
  +            member x.RunUnit() =
  +                prog.Run()
  +        }
  +
  +    member x.Run(input : IBufferVector<'a>, output : IBufferVector<'b>) =
  +        let args, cmd = build input output
  +        runtime.Run(cmd)
  +        args.Dispose()
  +
  +        
   
   type private Scan<'a when 'a : unmanaged>(runtime : IComputeRuntime, add : Expr<'a -> 'a -> 'a>) =
   
  
positive.code:                     outputData.[oid] <- (%add) inputData.[iid] outputData.[oid]
  
          }
        
  
      let inputImage =
          sampler2d {
              texture uniform?InputTexture
              filter Filter.MinMagMipPoint
              addressU WrapMode.Clamp
              addressV WrapMode.Clamp
          }
  
      [<LocalSize(X = halfScanSize)>]
      let reduceKernel (add : Expr<'a -> 'a -> 'a>) (inputData : 'a[]) (outputData : 'a[]) =
  
negative.code:         let reducer = getMapReducer map add
          reducer.Compile(input)
  
      member x.CompileMapReduce(map : Expr<V3i -> V4f -> 'b>, add : Expr<'b -> 'b -> 'b>, input : ITextureSubResource) =
          let reducer = getImageMapReducer map add
          reducer.Compile(input)
  
      member x.CompileMap(map : Expr<int -> 'a -> 'b>, input : IBufferVector<'a>, output : IBufferVector<'b>) =
          let mapper = getMapper map
          mapper.Compile(input, output)
  
      member x.Scan(add : Expr<'a -> 'a -> 'a>, input : IBufferVector<'a>, output : IBufferVector<'a>) =
          let scanner = getScanner add
  