label.clΒΆ

///
/// @file label.cl
///
/// Kernel to map channel confluences and identify their major & minor upstream pixels.
///
/// @author CPS
/// @bug No known bugs
///

#ifdef KERNEL_LABEL_CONFLUENCES

#define CHECK_INFLOWS(here_idx,nbr_vec) { \
   nbr_idx = get_array_idx(nbr_vec); \
   if ( !mask_array[nbr_idx] && (mapping_array[nbr_idx]&IS_THINCHANNEL) ) { \
       if ( link_array[nbr_idx]==here_idx ) { \
           /* The nbr pixel flows into here */ \
           inflows_list[n_inflows++] = nbr_idx; \
       } \
   } \
}
// Check in all 8 pixel-nbr directions
#define CHECK_E_INFLOWS(idx,vec)  CHECK_INFLOWS(idx,(float2)(vec[0]+1.0f, vec[1]      ))
#define CHECK_NE_INFLOWS(idx,vec) CHECK_INFLOWS(idx,(float2)(vec[0]+1.0f, vec[1]+1.0f ))
#define CHECK_N_INFLOWS(idx,vec)  CHECK_INFLOWS(idx,(float2)(vec[0],      vec[1]+1.0f ))
#define CHECK_NW_INFLOWS(idx,vec) CHECK_INFLOWS(idx,(float2)(vec[0]-1.0f, vec[1]+1.0f ))
#define CHECK_W_INFLOWS(idx,vec)  CHECK_INFLOWS(idx,(float2)(vec[0]-1.0f, vec[1]      ))
#define CHECK_SW_INFLOWS(idx,vec) CHECK_INFLOWS(idx,(float2)(vec[0]-1.0f, vec[1]-1.0f ))
#define CHECK_S_INFLOWS(idx,vec)  CHECK_INFLOWS(idx,(float2)(vec[0],      vec[1]-1.0f ))
#define CHECK_SE_INFLOWS(idx,vec) CHECK_INFLOWS(idx,(float2)(vec[0]+1.0f, vec[1]-1.0f ))

///
/// Flag if a pixel IS_MAJORCONFLUENCE and if so flag which upstream pixel IS_MAJORINFLOW
///   or IS_MINORINFLOW.
///
/// Compiled if KERNEL_LABEL_CONFLUENCES is defined.
///
/// @param[in]  seed_point_array       (float2 *, RO):
/// @param[in]  mask_array             (bool *,   RO):
/// @param[in]  uv_array               (float2 *, RO):
/// @param[in]  slt_array              (uint *,   RO):
/// @param[in,out]  mapping_array      (uint *,   RW):
/// @param[in]  count_array            (uint *,   RO):
/// @param[in]  link_array             (uint *,   RO):
///
/// @returns void
///
/// @ingroup structure
///
__kernel void label_confluences(
        __global const float2 *seed_point_array,
        __global const bool   *mask_array,
        __global const float2 *uv_array,
        __global const float  *slt_array,
        __global       uint   *mapping_array,
        __global const uint   *count_array,
        __global const uint   *link_array
   )
{
    // For every (redesignated) thin channel pixel...

    const uint global_id = get_global_id(0u)+get_global_id(1u)*get_global_size(0u);
    if (global_id>=N_SEED_POINTS) {
        // This is a "padding" seed, so let's bail
        return;
    }
#ifdef VERBOSE
    // Report how kernel instances are distributed
    if (global_id==0 || global_id==get_global_offset(0u)) {
        printf("\n  >>> on GPU/OpenCL device: id=%d offset=%d ",
                get_global_id(0u),
                get_global_offset(0u));
        printf("#workitems=%d x #workgroups=%d = %d=%d\n",
                get_local_size(0u), get_num_groups(0u),
                get_local_size(0u)*get_num_groups(0u),
                get_global_size(0u));
    }
#endif
    __private uchar n_inflows=0u, n_equal_dominant_inflows=0u;
    __private uint i, idx, nbr_idx, inflows_list[8], equal_dominant_inflows_list[8],
                   dominant_slt_index=0u;
    __private float dominant_slt=-MAXFLOAT;
    __private float2 vec=seed_point_array[global_id];

    // Remember here
    idx = get_array_idx(vec);
    // Check upstream neighbors
    CHECK_N_INFLOWS(idx,vec);
    CHECK_S_INFLOWS(idx,vec);
    CHECK_E_INFLOWS(idx,vec);
    CHECK_W_INFLOWS(idx,vec);
    CHECK_NE_INFLOWS(idx,vec);
    CHECK_SE_INFLOWS(idx,vec);
    CHECK_NW_INFLOWS(idx,vec);
    CHECK_SW_INFLOWS(idx,vec);
    if (n_inflows>1) {
        atomic_or(&mapping_array[idx],IS_MAJORCONFLUENCE);
        for (i=0;i<n_inflows;i++) {
            if ( count_array[idx]!=(count_array[inflows_list[i]]+1) ) {
                atomic_or(&mapping_array[inflows_list[i]],IS_MINORINFLOW);
            } else {
                equal_dominant_inflows_list[n_equal_dominant_inflows++]= inflows_list[i];
                if (slt_array[inflows_list[i]]>dominant_slt) {
                    dominant_slt_index = inflows_list[i];
                    dominant_slt = slt_array[dominant_slt_index];
                }
            }
        }
#ifdef DEBUG
        if (n_equal_dominant_inflows==0) {
            printf(
         "\nn_equal_dominant_inflows=0 @ %g,%g  idx=%d  mapping=%d & %d= is_thin=%d mask=%d \n",
                    vec[0],vec[1],
                    idx,
                    mapping_array[idx],IS_THINCHANNEL,(mapping_array[idx]&IS_THINCHANNEL),
                    mask_array[idx]);
            for (i=0;i<n_inflows;i++) {
                printf("ifidx=%d   count=%d => %d @ idx=%d\n",inflows_list[i],
                        count_array[inflows_list[i]], count_array[idx],idx);
            }
            for (i=0;i<n_inflows;i++) {
                printf("slt=%g : domslt=%g\n",slt_array[inflows_list[i]]+1, dominant_slt);
            }
        }
#endif
        for (i=0;i<n_equal_dominant_inflows;i++) {
            if (equal_dominant_inflows_list[i]==dominant_slt_index) {
                atomic_or(&mapping_array[equal_dominant_inflows_list[i]],IS_MAJORINFLOW);
            } else {
                atomic_or(&mapping_array[equal_dominant_inflows_list[i]],IS_MINORINFLOW);
            }
        }
    }
    return;
}
#endif