[[block]] struct Uniforms { dstTextureFlipY : u32; channelCount : u32; srcCopyOrigin : vec2; dstCopyOrigin : vec2; copySize : vec2; }; [[block]] struct OutputBuf { result : array; }; [[group(0), binding(0)]] var src : texture_2d; [[group(0), binding(1)]] var dst : texture_2d; [[group(0), binding(2)]] var output : OutputBuf; [[group(0), binding(3)]] var uniforms : Uniforms; fn aboutEqual(value : f32, expect : f32) -> bool { return (abs((value - expect)) < 0.001); } [[stage(compute), workgroup_size(1, 1, 1)]] fn main([[builtin(global_invocation_id)]] GlobalInvocationID : vec3) { let srcSize : vec2 = textureDimensions(src); let dstSize : vec2 = textureDimensions(dst); let dstTexCoord : vec2 = vec2(GlobalInvocationID.xy); let nonCoveredColor : vec4 = vec4(0.0, 1.0, 0.0, 1.0); var success : bool = true; if (((((dstTexCoord.x < uniforms.dstCopyOrigin.x) || (dstTexCoord.y < uniforms.dstCopyOrigin.y)) || (dstTexCoord.x >= (uniforms.dstCopyOrigin.x + uniforms.copySize.x))) || (dstTexCoord.y >= (uniforms.dstCopyOrigin.y + uniforms.copySize.y)))) { success = (success && all((textureLoad(dst, vec2(dstTexCoord), 0) == nonCoveredColor))); } else { var srcTexCoord : vec2 = ((dstTexCoord - uniforms.dstCopyOrigin) + uniforms.srcCopyOrigin); if ((uniforms.dstTextureFlipY == 1u)) { srcTexCoord.y = ((u32(srcSize.y) - srcTexCoord.y) - 1u); } let srcColor : vec4 = textureLoad(src, vec2(srcTexCoord), 0); let dstColor : vec4 = textureLoad(dst, vec2(dstTexCoord), 0); if ((uniforms.channelCount == 2u)) { success = ((success && aboutEqual(dstColor.r, srcColor.r)) && aboutEqual(dstColor.g, srcColor.g)); } else { success = ((((success && aboutEqual(dstColor.r, srcColor.r)) && aboutEqual(dstColor.g, srcColor.g)) && aboutEqual(dstColor.b, srcColor.b)) && aboutEqual(dstColor.a, srcColor.a)); } } let outputIndex : u32 = ((GlobalInvocationID.y * u32(dstSize.x)) + GlobalInvocationID.x); if (success) { output.result[outputIndex] = 1u; } else { output.result[outputIndex] = 0u; } }