Is write_image atomic? Is it better than atomic_max?


In the context of re-implementing in GPU the VoxLogicA project (see, I’m writing a connected components labelling algorithm for images (2d and 3d); I found no existing implementations and decided to write one based on pointer jumping and a “recollection step” (btw: if you are aware of an easy-to-use, production ready connected component labelling let me know).

The “recollection” step kernel pseudocode for 2d images is as follows:

1) global_id = (x,y) 
2) read v from img[x,y], decode it to a pair (tx,ty)
3) read v1 from img[tx,ty]
4) do some calculations to extract a boolean value C and a target value T from v1, v, and the neighbours of (x,y) and (tx,ty)
5) *** IF ( C ) THEN WRITE T INTO (tx,ty).

Q1: all the kernels where “C” is true will compete for writing. Suppose it does not matter which one wins (writes last). I’ve done some tests on an intel GPU, and (with filtering disabled, and clamping enabled) there seems to be no issue at all, write_image seems to be atomic, there is a winning value and my algorithm converges very fast. Can I safely assume that write_image on “unfiltered” images is atomic?

Q2: What I really need is to write into (tx,ty) the maximum T obtained from each kernel (if the winner is not the maximum the algorithm still converges, but it’s slower). That would involve using buffers instead of images, do clamping myself (or use a larger buffer padded with zeroes), and ** using atomic_max in each kernel**. I did not do this yet out of laziness since I need to change my code to use a buffer just to test it, but I believe it would be far slower. Am I right?

For completeness, here is my actual kernel (to be optimized, any suggestions welcome!)

__kernel void color_components2(/* base image */ __read_only image2d_t image,
                               /* uint32 */ __read_only image2d_t inputImage1,
                               __write_only image2d_t outImage1) {
  int2 gid = (int2)(get_global_id(0), get_global_id(1));
  int x = gid.x;
  int y = gid.y;
  int lock = 0;

  int2 size = get_image_dim(inputImage1);
  const sampler_t sampler =

  uint4 base = read_imageui(image, sampler, gid);
  uint4 ui4a = read_imageui(inputImage1, sampler, gid);
  int2 t = (int2)(ui4a[0] % size.x, ui4a[0] / size.x);

  unsigned int m = ui4a[0];
  unsigned int n = ui4a[0];

  if (base[0] > 0) {
    for (int a = -1; a <= 1; a++)
      for (int b = -1; b <= 1; b++) {
        uint4 tmpa =
            read_imageui(inputImage1, sampler, (int2)(t.x + a, t.y + b));
        m = max(tmpa[0], m);
        uint4 tmpb = read_imageui(inputImage1, sampler, (int2)(x + a, y + b));
        n = max(tmpb[0], n);

  if(n > m) write_imageui(outImage1,t,(uint4)(n,0,0,0));

I wanted to edit the post but as silly as it may sound, I can’t find the “edit” button. I just wanted to add that I cross-posted my question on stackoverflow: