Add refraction.

Add refraction.

// Diffuse layer
float3 UberV2_Lambert_Evaluate(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Outgoing direction
    float3 wo,
    // Texture args
    TEXTURE_ARG_LIST
)
{
    const float3 kd = Texture_GetValue3f(dg->mat.uberv2.diffuse_color.xyz, dg->uv, TEXTURE_ARGS_IDX(dg->mat.uberv2.diffuse_color_idx));

    return kd / PI;
}

float UberV2_Lambert_GetPdf(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Outgoing direction
    float3 wo,
    // Texture args
    TEXTURE_ARG_LIST
    )
{
    return fabs(wo.y) / PI;
}

/// Lambert BRDF sampling
float3 UberV2_Lambert_Sample(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Texture args
    TEXTURE_ARG_LIST,
    // Sample
    float2 sample,
    // Outgoing  direction
    float3* wo,
    // PDF at wo
    float* pdf
)
{
    const float3 kd = UberV2_Lambert_Evaluate(dg, wi, *wo, TEXTURE_ARGS);

    *wo = Sample_MapToHemisphere(sample, make_float3(0.f, 1.f, 0.f), 1.f);

    *pdf = fabs((*wo).y) / PI;

    return kd;
}

// Reflection/Coating
/*
Microfacet GGX
*/
// Distribution fucntion
float UberV2_MicrofacetDistribution_GGX_D(float roughness, float3 m)
{
    float ndotm = fabs(m.y);
    float ndotm2 = ndotm * ndotm;
    float sinmn = native_sqrt(1.f - clamp(ndotm * ndotm, 0.f, 1.f));
    float tanmn = ndotm > DENOM_EPS ? sinmn / ndotm : 0.f;
    float a2 = roughness * roughness;
    float denom = (PI * ndotm2 * ndotm2 * (a2 + tanmn * tanmn) * (a2 + tanmn * tanmn));
    return denom > DENOM_EPS ? (a2 / denom) : 1.f;
}

// PDF of the given direction
float UberV2_MicrofacetDistribution_GGX_GetPdf(
    // Halfway vector
    float3 m,
    // Rougness
    float roughness,
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Outgoing direction
    float3 wo,
    // Texture args
    TEXTURE_ARG_LIST
)
{
    float mpdf = UberV2_MicrofacetDistribution_GGX_D(roughness, m) * fabs(m.y);
    // See Humphreys and Pharr for derivation
    float denom = (4.f * fabs(dot(wo, m)));

    return denom > DENOM_EPS ? mpdf / denom : 0.f;
}

// Sample the distribution
void UberV2_MicrofacetDistribution_GGX_SampleNormal(
    // Roughness
    float roughness,
    // Differential geometry
    DifferentialGeometry const* dg,
    // Texture args
    TEXTURE_ARG_LIST,
    // Sample
    float2 sample,
    // Outgoing  direction
    float3* wh
)
{
    float r1 = sample.x;
    float r2 = sample.y;

    // Sample halfway vector first, then reflect wi around that
    float theta = atan2(roughness * native_sqrt(r1), native_sqrt(1.f - r1));
    float costheta = native_cos(theta);
    float sintheta = native_sin(theta);

    // phi = 2*PI*ksi2
    float phi = 2.f * PI * r2;
    float cosphi = native_cos(phi);
    float sinphi = native_sin(phi);

    // Calculate wh
    *wh = make_float3(sintheta * cosphi, costheta, sintheta * sinphi);
}

//
float UberV2_MicrofacetDistribution_GGX_G1(float roughness, float3 v, float3 m)
{
    float ndotv = fabs(v.y);
    float mdotv = fabs(dot(m, v));

    float sinnv = native_sqrt(1.f - clamp(ndotv * ndotv, 0.f, 1.f));
    float tannv = ndotv > DENOM_EPS ? sinnv / ndotv : 0.f;
    float a2 = roughness * roughness;
    return 2.f / (1.f + native_sqrt(1.f + a2 * tannv * tannv));
}

// Shadowing function also depends on microfacet distribution
float UberV2_MicrofacetDistribution_GGX_G(float roughness, float3 wi, float3 wo, float3 wh)
{
    return UberV2_MicrofacetDistribution_GGX_G1(roughness, wi, wh) * UberV2_MicrofacetDistribution_GGX_G1(roughness, wo, wh);
}

float3 UberV2_MicrofacetGGX_Evaluate(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Outgoing direction
    float3 wo,
    // Texture args
    TEXTURE_ARG_LIST
)
{
    const float3 ks = Texture_GetValue3f(dg->mat.uberv2.reflection_color.xyz, dg->uv, TEXTURE_ARGS_IDX(dg->mat.uberv2.reflection_color_idx));
    const float roughness = Texture_GetValue1f(dg->mat.uberv2.reflection_roughness, dg->uv, TEXTURE_ARGS_IDX(dg->mat.uberv2.reflection_roughness_idx));

    // Incident and reflected zenith angles
    float costhetao = fabs(wo.y);
    float costhetai = fabs(wi.y);

    // Calc halfway vector
    float3 wh = normalize(wi + wo);

    float denom = (4.f * costhetao * costhetai);

    return denom > DENOM_EPS ? ks * UberV2_MicrofacetDistribution_GGX_G(roughness, wi, wo, wh) * UberV2_MicrofacetDistribution_GGX_D(roughness, wh) / denom : 0.f;
}

float UberV2_MicrofacetGGX_GetPdf(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Outgoing direction
    float3 wo,
    // Texture args
    TEXTURE_ARG_LIST
)
{
    const float roughness = Texture_GetValue1f(dg->mat.uberv2.reflection_roughness, dg->uv, TEXTURE_ARGS_IDX(dg->mat.uberv2.reflection_roughness_idx));

    float3 wh = normalize(wo + wi);

    return UberV2_MicrofacetDistribution_GGX_GetPdf(wh, roughness, dg, wi, wo, TEXTURE_ARGS);
}

float3 UberV2_MicrofacetGGX_Sample(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Texture args
    TEXTURE_ARG_LIST,
    // Sample
    float2 sample,
    // Outgoing  direction
    float3* wo,
    // PDF at wo
    float* pdf
)
{
    const float roughness = Texture_GetValue1f(dg->mat.uberv2.reflection_roughness, dg->uv, TEXTURE_ARGS_IDX(dg->mat.uberv2.reflection_roughness_idx));

    float3 wh;
    UberV2_MicrofacetDistribution_GGX_SampleNormal(roughness, dg, TEXTURE_ARGS, sample, &wh);

    *wo = -wi + 2.f*fabs(dot(wi, wh)) * wh;

    *pdf = UberV2_MicrofacetDistribution_GGX_GetPdf(wh, roughness, dg, wi, *wo, TEXTURE_ARGS);

    return UberV2_MicrofacetGGX_Evaluate(dg, wi, *wo, TEXTURE_ARGS);
}

/*
Ideal reflection BRDF
*/
float3 UberV2_IdealReflect_Evaluate(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Outgoing direction
    float3 wo,
    // Texture args
    TEXTURE_ARG_LIST
)
{
    return 0.f;
}

float UberV2_IdealReflect_GetPdf(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Outgoing direction
    float3 wo,
    // Texture args
    TEXTURE_ARG_LIST
)
{
    return 0.f;
}

float3 UberV2_IdealReflect_Sample(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Texture args
    TEXTURE_ARG_LIST,
    // Sample
    float2 sample,
    // Outgoing  direction
    float3* wo,
    // PDF at wo
    float* pdf
)
{
    const float3 ks = Texture_GetValue3f(dg->mat.uberv2.reflection_color.xyz, dg->uv, TEXTURE_ARGS_IDX(dg->mat.uberv2.reflection_color_idx));
    const float eta = dg->mat.uberv2.reflection_roughness;

    // Mirror reflect wi
    *wo = normalize(make_float3(-wi.x, wi.y, -wi.z));

    // PDF is infinite at that point, but deltas are going to cancel out while evaluating
    // so set it to 1.f
    *pdf = 1.f;

    float coswo = fabs((*wo).y);

    // Return reflectance value
    return coswo > DENOM_EPS ? (ks * (1.f / coswo)) : 0.f;
}

// Refraction
/*
Ideal refraction BTDF
*/

float3 UberV2_IdealRefract_Evaluate(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Outgoing direction
    float3 wo,
    // Texture args
    TEXTURE_ARG_LIST
)
{
    return 0.f;
}

float UberV2_IdealRefract_GetPdf(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Outgoing direction
    float3 wo,
    // Texture args
    TEXTURE_ARG_LIST
)
{
    return 0.f;
}

float3 UberV2_IdealRefract_Sample(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Texture args
    TEXTURE_ARG_LIST,
    // Sample
    float2 sample,
    // Outgoing  direction
    float3* wo,
    // PDF at wo
    float* pdf
)
{
    const float3 ks = Texture_GetValue3f(dg->mat.uberv2.refraction_color.xyz, dg->uv, TEXTURE_ARGS_IDX(dg->mat.uberv2.refraction_color_idx));

    float etai = 1.f;
    float etat = dg->mat.uberv2.refraction_ior;
    float cosi = wi.y;

    bool entering = cosi > 0.f;

    // Revert normal and eta if needed
    if (!entering)
    {
        float tmp = etai;
        etai = etat;
        etat = tmp;
    }

    float eta = etai / etat;
    float sini2 = 1.f - cosi * cosi;
    float sint2 = eta * eta * sini2;

    if (sint2 >= 1.f)
    {
        *pdf = 0.f;
        return 0.f;
    }

    float cost = native_sqrt(max(0.f, 1.f - sint2));

    // Transmitted ray
    *wo = normalize(make_float3(eta * -wi.x, entering ? -cost : cost, eta * -wi.z));

    *pdf = 1.f;

    return cost > DENOM_EPS ? (eta * eta * ks / cost) : 0.f;
}

float3 UberV2_MicrofacetRefractionGGX_Evaluate(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Outgoing direction
    float3 wo,
    // Texture args
    TEXTURE_ARG_LIST
)
{
    const float3 ks = Texture_GetValue3f(dg->mat.uberv2.refraction_color.xyz, dg->uv, TEXTURE_ARGS_IDX(dg->mat.uberv2.refraction_color_idx));
    const float roughness = max(Texture_GetValue1f(dg->mat.uberv2.refraction_roughness, dg->uv, TEXTURE_ARGS_IDX(dg->mat.uberv2.refraction_roughness_idx)), ROUGHNESS_EPS);

    float ndotwi = wi.y;
    float ndotwo = wo.y;

    if (ndotwi * ndotwo >= 0.f)
    {
        return 0.f;
    }

    float etai = 1.f;
    float etat = dg->mat.uberv2.refraction_ior;

    // Revert normal and eta if needed
    if (ndotwi < 0.f)
    {
        float tmp = etai;
        etai = etat;
        etat = tmp;
    }

    // Calc halfway vector
    float3 ht = -(etai * wi + etat * wo);
    float3 wh = normalize(ht);

    float widotwh = fabs(dot(wh, wi));
    float wodotwh = fabs(dot(wh, wo));

    float denom = dot(ht, ht);
    denom *= (fabs(ndotwi) * fabs(ndotwo));

    return denom > DENOM_EPS ? (ks * (widotwh * wodotwh)  * (etat)* (etat)*
        UberV2_MicrofacetDistribution_GGX_G(roughness, wi, wo, wh) * UberV2_MicrofacetDistribution_GGX_D(roughness, wh) / denom) : 0.f;
}

float UberV2_MicrofacetRefractionGGX_GetPdf(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Outgoing direction
    float3 wo,
    // Texture args
    TEXTURE_ARG_LIST
)
{
    const float roughness = max(Texture_GetValue1f(dg->mat.uberv2.refraction_roughness, dg->uv, TEXTURE_ARGS_IDX(dg->mat.uberv2.refraction_roughness_idx)), ROUGHNESS_EPS);

    float ndotwi = wi.y;
    float ndotwo = wo.y;

    if (ndotwi * ndotwo >= 0.f)
    {
        return 0.f;
    }

    float etai = 1.f;
    float etat = dg->mat.uberv2.refraction_ior;

    // Revert normal and eta if needed
    if (ndotwi < 0.f)
    {
        float tmp = etai;
        etai = etat;
        etat = tmp;
    }

    // Calc halfway vector
    float3 ht = -(etai * wi + etat * wo);

    float3 wh = normalize(ht);

    float wodotwh = fabs(dot(wo, wh));

    float whpdf = UberV2_MicrofacetDistribution_GGX_D(roughness, wh) * fabs(wh.y);

    float whwo = wodotwh * etat * etat;

    float denom = dot(ht, ht);

    return denom > DENOM_EPS ? whpdf * whwo / denom : 0.f;
}

float3 UberV2_MicrofacetRefractionGGX_Sample(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Texture args
    TEXTURE_ARG_LIST,
    // Sample
    float2 sample,
    // Outgoing  direction
    float3* wo,
    // PDF at wo
    float* pdf
)
{
    const float3 ks = Texture_GetValue3f(dg->mat.uberv2.refraction_color.xyz, dg->uv, TEXTURE_ARGS_IDX(dg->mat.uberv2.refraction_color_idx));
    const float roughness = max(Texture_GetValue1f(dg->mat.uberv2.refraction_roughness, dg->uv, TEXTURE_ARGS_IDX(dg->mat.uberv2.refraction_roughness_idx)), ROUGHNESS_EPS);

    float ndotwi = wi.y;

    if (ndotwi == 0.f)
    {
        *pdf = 0.f;
        return 0.f;
    }

    float etai = 1.f;
    float etat = dg->mat.uberv2.refraction_ior;
    float s = 1.f;

    // Revert normal and eta if needed
    if (ndotwi < 0.f)
    {
        float tmp = etai;
        etai = etat;
        etat = tmp;
        s = -s;
    }

    float3 wh;
    UberV2_MicrofacetDistribution_GGX_SampleNormal(roughness, dg, TEXTURE_ARGS, sample, &wh);

    float c = dot(wi, wh);
    float eta = etai / etat;

    float d = 1 + eta * (c * c - 1);

    if (d <= 0.f)
    {
        *pdf = 0.f;
        return 0.f;
    }

    *wo = normalize((eta * c - s * native_sqrt(d)) * wh - eta * wi);

    *pdf = UberV2_MicrofacetRefractionGGX_GetPdf(dg, wi, *wo, TEXTURE_ARGS);

    return UberV2_MicrofacetRefractionGGX_Evaluate(dg, wi, *wo, TEXTURE_ARGS);
}

float3 UberV2_Evaluate(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Outgoing direction
    float3 wo,
    // Texture args
    TEXTURE_ARG_LIST
)
{
    const float reflection_weight = Texture_GetValue1f(dg->mat.uberv2.reflection_weight, dg->uv, TEXTURE_ARGS_IDX(dg->mat.uberv2.reflection_weight_idx));
    const float refraction_weight = Texture_GetValue1f(dg->mat.uberv2.refraction_weight, dg->uv, TEXTURE_ARGS_IDX(dg->mat.uberv2.refraction_weight_idx));

    if (reflection_weight > 0.0f)
        return UberV2_MicrofacetGGX_Evaluate(dg, wi, wo, TEXTURE_ARGS);
    if (refraction_weight > 0.0f)
        return UberV2_MicrofacetRefractionGGX_Evaluate(dg, wi, wo, TEXTURE_ARGS);
    else
        return UberV2_Lambert_Evaluate(dg, wi, wo, TEXTURE_ARGS);
}

/// Lambert BRDF PDF
float UberV2_GetPdf(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Outgoing direction
    float3 wo,
    // Texture args
    TEXTURE_ARG_LIST
)
{
    const float reflection_weight = Texture_GetValue1f(dg->mat.uberv2.reflection_weight, dg->uv, TEXTURE_ARGS_IDX(dg->mat.uberv2.reflection_weight_idx));
    const float refraction_weight = Texture_GetValue1f(dg->mat.uberv2.refraction_weight, dg->uv, TEXTURE_ARGS_IDX(dg->mat.uberv2.refraction_weight_idx));

    if (reflection_weight > 0.0f)
        return UberV2_MicrofacetGGX_GetPdf(dg, wi, wo, TEXTURE_ARGS);
    if (refraction_weight > 0.0f)
        return UberV2_MicrofacetRefractionGGX_GetPdf(dg, wi, wo, TEXTURE_ARGS);
    else
        return UberV2_Lambert_GetPdf(dg, wi, wo, TEXTURE_ARGS);
}

/// Lambert BRDF sampling
float3 UberV2_Sample(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Texture args
    TEXTURE_ARG_LIST,
    // Sample
    float2 sample,
    // Outgoing  direction
    float3* wo,
    // PDF at wo
    float* pdf
)
{
    const float reflection_weight = Texture_GetValue1f(dg->mat.uberv2.reflection_weight, dg->uv, TEXTURE_ARGS_IDX(dg->mat.uberv2.reflection_weight_idx));
    const float refraction_weight = Texture_GetValue1f(dg->mat.uberv2.refraction_weight, dg->uv, TEXTURE_ARGS_IDX(dg->mat.uberv2.refraction_weight_idx));

    if (reflection_weight > 0.0f)
        return UberV2_MicrofacetGGX_Sample(dg, wi, TEXTURE_ARGS, sample, wo, pdf);
    if (refraction_weight > 0.0f)
        return UberV2_MicrofacetRefractionGGX_Sample(dg, wi, TEXTURE_ARGS, sample, wo, pdf);
    else
        return UberV2_Lambert_Sample(dg, wi, TEXTURE_ARGS, sample, wo, pdf);
}

// Diffuse layer
float3 UberV2_Lambert_Evaluate(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Outgoing direction
    float3 wo,
    // Texture args
    TEXTURE_ARG_LIST
)
{
    const float3 kd = Texture_GetValue3f(dg->mat.uberv2.diffuse_color.xyz, dg->uv, TEXTURE_ARGS_IDX(dg->mat.uberv2.diffuse_color_idx));

    return kd / PI;
}

float UberV2_Lambert_GetPdf(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Outgoing direction
    float3 wo,
    // Texture args
    TEXTURE_ARG_LIST
    )
{
    return fabs(wo.y) / PI;
}

/// Lambert BRDF sampling
float3 UberV2_Lambert_Sample(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Texture args
    TEXTURE_ARG_LIST,
    // Sample
    float2 sample,
    // Outgoing  direction
    float3* wo,
    // PDF at wo
    float* pdf
)
{
    const float3 kd = UberV2_Lambert_Evaluate(dg, wi, *wo, TEXTURE_ARGS);

    *wo = Sample_MapToHemisphere(sample, make_float3(0.f, 1.f, 0.f), 1.f);

    *pdf = fabs((*wo).y) / PI;

    return kd;
}

// Reflection/Coating
/*
Microfacet GGX
*/
// Distribution fucntion
float UberV2_MicrofacetDistribution_GGX_D(float roughness, float3 m)
{
    float ndotm = fabs(m.y);
    float ndotm2 = ndotm * ndotm;
    float sinmn = native_sqrt(1.f - clamp(ndotm * ndotm, 0.f, 1.f));
    float tanmn = ndotm > DENOM_EPS ? sinmn / ndotm : 0.f;
    float a2 = roughness * roughness;
    float denom = (PI * ndotm2 * ndotm2 * (a2 + tanmn * tanmn) * (a2 + tanmn * tanmn));
    return denom > DENOM_EPS ? (a2 / denom) : 1.f;
}

// PDF of the given direction
float UberV2_MicrofacetDistribution_GGX_GetPdf(
    // Halfway vector
    float3 m,
    // Rougness
    float roughness,
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Outgoing direction
    float3 wo,
    // Texture args
    TEXTURE_ARG_LIST
)
{
    float mpdf = UberV2_MicrofacetDistribution_GGX_D(roughness, m) * fabs(m.y);
    // See Humphreys and Pharr for derivation
    float denom = (4.f * fabs(dot(wo, m)));

    return denom > DENOM_EPS ? mpdf / denom : 0.f;
}

// Sample the distribution
void UberV2_MicrofacetDistribution_GGX_SampleNormal(
    // Roughness
    float roughness,
    // Differential geometry
    DifferentialGeometry const* dg,
    // Texture args
    TEXTURE_ARG_LIST,
    // Sample
    float2 sample,
    // Outgoing  direction
    float3* wh
)
{
    float r1 = sample.x;
    float r2 = sample.y;

    // Sample halfway vector first, then reflect wi around that
    float theta = atan2(roughness * native_sqrt(r1), native_sqrt(1.f - r1));
    float costheta = native_cos(theta);
    float sintheta = native_sin(theta);

    // phi = 2*PI*ksi2
    float phi = 2.f * PI * r2;
    float cosphi = native_cos(phi);
    float sinphi = native_sin(phi);

    // Calculate wh
    *wh = make_float3(sintheta * cosphi, costheta, sintheta * sinphi);
}

//
float UberV2_MicrofacetDistribution_GGX_G1(float roughness, float3 v, float3 m)
{
    float ndotv = fabs(v.y);
    float mdotv = fabs(dot(m, v));

    float sinnv = native_sqrt(1.f - clamp(ndotv * ndotv, 0.f, 1.f));
    float tannv = ndotv > DENOM_EPS ? sinnv / ndotv : 0.f;
    float a2 = roughness * roughness;
    return 2.f / (1.f + native_sqrt(1.f + a2 * tannv * tannv));
}

// Shadowing function also depends on microfacet distribution
float UberV2_MicrofacetDistribution_GGX_G(float roughness, float3 wi, float3 wo, float3 wh)
{
    return UberV2_MicrofacetDistribution_GGX_G1(roughness, wi, wh) * UberV2_MicrofacetDistribution_GGX_G1(roughness, wo, wh);
}

float3 UberV2_MicrofacetGGX_Evaluate(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Outgoing direction
    float3 wo,
    // Texture args
    TEXTURE_ARG_LIST
)
{
    const float3 ks = Texture_GetValue3f(dg->mat.uberv2.reflection_color.xyz, dg->uv, TEXTURE_ARGS_IDX(dg->mat.uberv2.reflection_color_idx));
    const float roughness = Texture_GetValue1f(dg->mat.uberv2.reflection_roughness, dg->uv, TEXTURE_ARGS_IDX(dg->mat.uberv2.reflection_roughness_idx));

    // Incident and reflected zenith angles
    float costhetao = fabs(wo.y);
    float costhetai = fabs(wi.y);

    // Calc halfway vector
    float3 wh = normalize(wi + wo);

    float denom = (4.f * costhetao * costhetai);

    return denom > DENOM_EPS ? ks * UberV2_MicrofacetDistribution_GGX_G(roughness, wi, wo, wh) * UberV2_MicrofacetDistribution_GGX_D(roughness, wh) / denom : 0.f;
}

float UberV2_MicrofacetGGX_GetPdf(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Outgoing direction
    float3 wo,
    // Texture args
    TEXTURE_ARG_LIST
)
{
    const float roughness = Texture_GetValue1f(dg->mat.uberv2.reflection_roughness, dg->uv, TEXTURE_ARGS_IDX(dg->mat.uberv2.reflection_roughness_idx));

    float3 wh = normalize(wo + wi);

    return UberV2_MicrofacetDistribution_GGX_GetPdf(wh, roughness, dg, wi, wo, TEXTURE_ARGS);
}

float3 UberV2_MicrofacetGGX_Sample(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Texture args
    TEXTURE_ARG_LIST,
    // Sample
    float2 sample,
    // Outgoing  direction
    float3* wo,
    // PDF at wo
    float* pdf
)
{
    const float roughness = Texture_GetValue1f(dg->mat.uberv2.reflection_roughness, dg->uv, TEXTURE_ARGS_IDX(dg->mat.uberv2.reflection_roughness_idx));

    float3 wh;
    UberV2_MicrofacetDistribution_GGX_SampleNormal(roughness, dg, TEXTURE_ARGS, sample, &wh);

    *wo = -wi + 2.f*fabs(dot(wi, wh)) * wh;

    *pdf = UberV2_MicrofacetDistribution_GGX_GetPdf(wh, roughness, dg, wi, *wo, TEXTURE_ARGS);

    return UberV2_MicrofacetGGX_Evaluate(dg, wi, *wo, TEXTURE_ARGS);
}

/*
Ideal reflection BRDF
*/
float3 UberV2_IdealReflect_Evaluate(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Outgoing direction
    float3 wo,
    // Texture args
    TEXTURE_ARG_LIST
)
{
    return 0.f;
}

float UberV2_IdealReflect_GetPdf(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Outgoing direction
    float3 wo,
    // Texture args
    TEXTURE_ARG_LIST
)
{
    return 0.f;
}

float3 UberV2_IdealReflect_Sample(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Texture args
    TEXTURE_ARG_LIST,
    // Sample
    float2 sample,
    // Outgoing  direction
    float3* wo,
    // PDF at wo
    float* pdf
)
{
    const float3 ks = Texture_GetValue3f(dg->mat.uberv2.reflection_color.xyz, dg->uv, TEXTURE_ARGS_IDX(dg->mat.uberv2.reflection_color_idx));
    const float eta = dg->mat.uberv2.reflection_roughness;

    // Mirror reflect wi
    *wo = normalize(make_float3(-wi.x, wi.y, -wi.z));

    // PDF is infinite at that point, but deltas are going to cancel out while evaluating
    // so set it to 1.f
    *pdf = 1.f;

    float coswo = fabs((*wo).y);

    // Return reflectance value
    return coswo > DENOM_EPS ? (ks * (1.f / coswo)) : 0.f;
}

// Refraction
/*
Ideal refraction BTDF
*/

/*float3 IdealRefract_Evaluate(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Outgoing direction
    float3 wo,
    // Texture args
    TEXTURE_ARG_LIST
)
{
    return 0.f;
}

float IdealRefract_GetPdf(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Outgoing direction
    float3 wo,
    // Texture args
    TEXTURE_ARG_LIST
)
{
    return 0.f;
}

float3 IdealRefract_Sample(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Texture args
    TEXTURE_ARG_LIST,
    // Sample
    float2 sample,
    // Outgoing  direction
    float3* wo,
    // PDF at wo
    float* pdf
)
{
    const float3 ks = Texture_GetValue3f(dg->mat.simple.kx.xyz, dg->uv, TEXTURE_ARGS_IDX(dg->mat.simple.kxmapidx));

    float etai = 1.f;
    float etat = dg->mat.simple.ni;
    float cosi = wi.y;

    bool entering = cosi > 0.f;

    // Revert normal and eta if needed
    if (!entering)
    {
        float tmp = etai;
        etai = etat;
        etat = tmp;
    }

    float eta = etai / etat;
    float sini2 = 1.f - cosi * cosi;
    float sint2 = eta * eta * sini2;

    if (sint2 >= 1.f)
    {
        *pdf = 0.f;
        return 0.f;
    }

    float cost = native_sqrt(max(0.f, 1.f - sint2));

    // Transmitted ray
    float F = dg->mat.simple.fresnel;

    *wo = normalize(make_float3(eta * -wi.x, entering ? -cost : cost, eta * -wi.z));

    *pdf = 1.f;

    return cost > DENOM_EPS ? (F * eta * eta * ks / cost) : 0.f;
}

float3 MicrofacetRefractionGGX_Evaluate(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Outgoing direction
    float3 wo,
    // Texture args
    TEXTURE_ARG_LIST
)
{
    const float3 ks = Texture_GetValue3f(dg->mat.simple.kx.xyz, dg->uv, TEXTURE_ARGS_IDX(dg->mat.simple.kxmapidx));
    const float roughness = max(Texture_GetValue1f(dg->mat.simple.ns, dg->uv, TEXTURE_ARGS_IDX(dg->mat.simple.nsmapidx)), ROUGHNESS_EPS);

    float ndotwi = wi.y;
    float ndotwo = wo.y;

    if (ndotwi * ndotwo >= 0.f)
    {
        return 0.f;
    }

    float etai = 1.f;
    float etat = dg->mat.simple.ni;

    // Revert normal and eta if needed
    if (ndotwi < 0.f)
    {
        float tmp = etai;
        etai = etat;
        etat = tmp;
    }

    // Calc halfway vector
    float3 ht = -(etai * wi + etat * wo);
    float3 wh = normalize(ht);

    float widotwh = fabs(dot(wh, wi));
    float wodotwh = fabs(dot(wh, wo));

    float F = dg->mat.simple.fresnel;

    float denom = dot(ht, ht);
    denom *= (fabs(ndotwi) * fabs(ndotwo));

    return denom > DENOM_EPS ? (F * ks * (widotwh * wodotwh)  * (etat)* (etat)*
        MicrofacetDistribution_GGX_G(roughness, wi, wo, wh) * MicrofacetDistribution_GGX_D(roughness, wh) / denom) : 0.f;
}

float MicrofacetRefractionGGX_GetPdf(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Outgoing direction
    float3 wo,
    // Texture args
    TEXTURE_ARG_LIST
)
{
    const float roughness = max(Texture_GetValue1f(dg->mat.simple.ns, dg->uv, TEXTURE_ARGS_IDX(dg->mat.simple.nsmapidx)), ROUGHNESS_EPS);
    float ndotwi = wi.y;
    float ndotwo = wo.y;

    float etai = 1.f;
    float etat = dg->mat.simple.ni;

    if (ndotwi * ndotwo >= 0.f)
    {
        return 0.f;
    }

    // Revert normal and eta if needed
    if (ndotwi < 0.f)
    {
        float tmp = etai;
        etai = etat;
        etat = tmp;
    }

    // Calc halfway vector
    float3 ht = -(etai * wi + etat * wo);

    float3 wh = normalize(ht);

    float wodotwh = fabs(dot(wo, wh));

    float whpdf = MicrofacetDistribution_GGX_D(roughness, wh) * fabs(wh.y);

    float whwo = wodotwh * etat * etat;

    float denom = dot(ht, ht);

    return denom > DENOM_EPS ? whpdf * whwo / denom : 0.f;
}

float3 MicrofacetRefractionGGX_Sample(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Texture args
    TEXTURE_ARG_LIST,
    // Sample
    float2 sample,
    // Outgoing  direction
    float3* wo,
    // PDF at wo
    float* pdf
)
{
    const float3 ks = Texture_GetValue3f(dg->mat.simple.kx.xyz, dg->uv, TEXTURE_ARGS_IDX(dg->mat.simple.kxmapidx));
    const float roughness = max(Texture_GetValue1f(dg->mat.simple.ns, dg->uv, TEXTURE_ARGS_IDX(dg->mat.simple.nsmapidx)), ROUGHNESS_EPS);

    float ndotwi = wi.y;

    if (ndotwi == 0.f)
    {
        *pdf = 0.f;
        return 0.f;
    }

    float etai = 1.f;
    float etat = dg->mat.simple.ni;
    float s = 1.f;

    // Revert normal and eta if needed
    if (ndotwi < 0.f)
    {
        float tmp = etai;
        etai = etat;
        etat = tmp;
        s = -s;
    }

    float3 wh;
    MicrofacetDistribution_GGX_SampleNormal(roughness, dg, TEXTURE_ARGS, sample, &wh);

    float c = dot(wi, wh);
    float eta = etai / etat;

    float d = 1 + eta * (c * c - 1);

    if (d <= 0.f)
    {
        *pdf = 0.f;
        return 0.f;
    }

    *wo = normalize((eta * c - s * native_sqrt(d)) * wh - eta * wi);

    *pdf = MicrofacetRefractionGGX_GetPdf(dg, wi, *wo, TEXTURE_ARGS);

    return MicrofacetRefractionGGX_Evaluate(dg, wi, *wo, TEXTURE_ARGS);
}
*/

float3 UberV2_Evaluate(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Outgoing direction
    float3 wo,
    // Texture args
    TEXTURE_ARG_LIST
)
{
    return UberV2_Lambert_Evaluate(dg, wi, wo, TEXTURE_ARGS);
}

/// Lambert BRDF PDF
float UberV2_GetPdf(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Outgoing direction
    float3 wo,
    // Texture args
    TEXTURE_ARG_LIST
)
{
    return UberV2_Lambert_GetPdf(dg, wi, wo, TEXTURE_ARGS);
}

/// Lambert BRDF sampling
float3 UberV2_Sample(
    // Geometry
    DifferentialGeometry const* dg,
    // Incoming direction
    float3 wi,
    // Texture args
    TEXTURE_ARG_LIST,
    // Sample
    float2 sample,
    // Outgoing  direction
    float3* wo,
    // PDF at wo
    float* pdf
)
{
    return UberV2_Lambert_Sample(dg, wi, TEXTURE_ARGS, sample, wo, pdf);
}


Separate out voxel coloring from voxel iteration.

/* Size of the texture currently hard-coded */
#define SCREEN_W 640
#define SCREEN_H 480

/* With the current algorithm, this is the maximum number of voxels to
   traverse */
#define LOOP_LIMIT 100

/* Colors for the various sides of wall blocks */
#define WALL_UNDER ((float4)(0.3,0.5,0.5,1.0))
#define WALL_SIDE  ((float4)(0.45,0.75,0.75,1.0))
#define WALL_TOP   ((float4)(0.6,1.0,1.0,1.0))
#define WALLG_UNDER ((float4)(0.3,0.5,0.4,1.0))
#define WALLG_SIDE  ((float4)(0.45,0.75,0.45,1.0))
#define WALLG_TOP   ((float4)(0.6,1.0,0.6,1.0))

/* Edge types - what appears at the end of the grid */
#define ET_WALL         0
#define ET_PORTAL_TORUS 1
#define ET_SOLID_AIR    2

/* Block types */
#define BK_AIR      0
#define BK_WALL     1
#define BK_WALLG    2

/* Handy macro for computing nearest axis boundary */
#define POSITIVE(X) ((X) > 0 ? (X) : 0)

typedef struct world_t {
    __constant uchar *grid;
    uchar4 bounds;
    uint edge_type;
} world_t;

typedef struct ray_t {
    int4 P;
    float4 ray_color;
    uint outside;
    char4 last_step;
} ray_t;

/* Returns new ray_color. Halts ray if alpha is 1.0f */
float4 color_ray(world_t w, ray_t r)
{
    uchar block_type = BK_AIR;

    if (r.outside) {
        if (w.edge_type == ET_WALL) {
            block_type = BK_WALL;
        } else {
            /* else leave block_type as BK_AIR */
            // TODO ET_PORTAL_TORUS
            return (float4)(0.0f, 0.0f, 0.0f, 1.0f);
        }
    } else {
        block_type = w.grid[r.P.x + (r.P.y * w.bounds.x) +
            (r.P.z * w.bounds.x * w.bounds.y)];
    }

    float4 new_ray_color = r.ray_color;

    if (block_type == BK_WALL) {
        if (r.last_step.y == 0) {
            // viewing block from side
            new_ray_color = WALL_SIDE;
        } else if (r.last_step.y == -1) {
            // viewing block from above
            new_ray_color = WALL_TOP;
        } else {
            // viewing block from below
            new_ray_color = WALL_UNDER;
        }
    } else if (block_type == BK_WALLG) {
        if (r.last_step.y == 0)
            new_ray_color = WALLG_SIDE;
        else if (r.last_step.y == -1)
            new_ray_color = WALLG_TOP;
        else
            new_ray_color = WALLG_UNDER;
    }

    return new_ray_color;
}

__kernel void raytrace(__write_only __global image2d_t bmp,
    uchar x_size, uchar y_size, uchar z_size, uchar edge_type,
    float rot_x, float rot_y, float cam_x, float cam_y, float cam_z,
    float fov_x, float fov_y, __constant uchar *grid)
{
    world_t w;
    w.grid = grid;
    w.edge_type = edge_type;
    w.bounds = (uchar4)(x_size, y_size, z_size, 0); /* Grid dimensions */

    /* Screen pixel position: */
    int2 p_pos = (int2)(get_global_id(0), get_global_id(1));

    float4 ray_rot = (float4)(rot_x, rot_y,
                              (p_pos.x * fov_x) / SCREEN_W - fov_x/2,
                              (p_pos.y * fov_y) / SCREEN_H - fov_y/2);
    float4 rot_sin = sin(ray_rot),
           rot_cos = cos(ray_rot);

    /* Voxel traversal ray-tracing algorithm based on John Amanatides'
       and Andrew Woo's paper. */

    /* n is the vector of the ray as if the camera was looking directly
       down the z-axis without any rotation around it.
       Multiply it by rotation matrices to get v (below) */
    float4 n = (float4)(rot_cos.w * rot_sin.z,
                        -rot_sin.w,
                        rot_cos.w * rot_cos.z,
                        0.0f);

    ray_t r;

    // v is the unit vector along the ray in actual world coords
    float4 v = (float4)(
      n.x*rot_cos.x + n.y*rot_sin.x*rot_sin.y + n.z*rot_sin.x*rot_cos.y,
      n.y*rot_cos.y - n.z*rot_sin.y,
      -n.x*rot_sin.x + n.y*rot_cos.x*rot_sin.y + n.z*rot_cos.x*rot_cos.y,
      0.0f);

    /* u is the starting point of the ray */
    float4 u = (float4)(cam_x, cam_y, cam_z, 0.0f);
    // Thus equation of the ray = u + vt

    // P = (X,Y,Z) = current voxel coordinates
    r.P = (int4)((int)u.x, (int)u.y, (int)u.z, 0);
    // TODO handle P being outside bounds of grid

    /* step = (stepX, stepY, stepZ) = values are either 1, 0, or -1.
       Components are determined from the sign of the components of v */
    char4 step = (char4)((char)sign(v.x), (char)sign(v.y),
                     (char)sign(v.z), 0);

    /* tmax = (tmaxX, tmaxY, tmaxZ) = values of t at which ray next
       crosses a voxel boundary in the respective direction */
    float4 tmax = (float4)((r.P.x + POSITIVE(step.x) - u.x)/v.x,
                      (r.P.y + POSITIVE(step.y) - u.y)/v.y,
                      (r.P.z + POSITIVE(step.z) - u.z)/v.z,
                      0.0f);

    /* dt = (dtX, dtY, dtZ) = how far along ray (in units of t) we must
       move for x/y/z component of move to equal width of one voxel */
    float4 dt = (float4)(step.x / v.x,
                    step.y / v.y,
                    step.z / v.z,
                    0.0f);

    /* justOut vector - used for checking we remain within the bounds
       of the grid */
    int4 justOut = (int4)(step.x == -1 ? -1 : w.bounds.x,
                     step.y == -1 ? -1 : w.bounds.y,
                     step.z == -1 ? -1 : w.bounds.z,
                     0);

    r.ray_color = (float4)(0.0f, 0.0f, 0.0f, 0.0f);
    r.outside = false;
    r.last_step = (char4)(0,0,0,0);

    // FIXME assuming camera is always inside the grid
    r.ray_color = color_ray(w, r);

    #define STEP(dim) do { \
                        r.P.dim += step.dim; \
                        r.last_step = (char4)(0,0,0,0); \
                        r.last_step.dim = step.dim; \
                        if (r.P.dim == justOut.dim) { \
                            r.outside = true; \
                        } else \
                        tmax.dim += dt.dim; \
                      } while (0)

    for (uint iter_count = 0; iter_count < LOOP_LIMIT;
         iter_count++)
    {

        if (tmax.x < tmax.y) {
            if (tmax.x < tmax.z) {
                STEP(x);
            } else {
                STEP(z);
            }
        } else {
            if (tmax.y < tmax.z) {
                STEP(y);
            } else {
                STEP(z);
            }
        }

        r.ray_color = color_ray(w, r);

        if (r.ray_color.w == 1.0f)
            break;

    }

    write_imagef(bmp, p_pos, r.ray_color);
}

/* Size of the texture currently hard-coded */
#define SCREEN_W 640
#define SCREEN_H 480

/* With the current algorithm, this is the maximum number of voxels to
   traverse */
#define LOOP_LIMIT 200

/* Colors for the various sides of wall blocks */
#define WALL_UNDER ((float4)(0.3,0.5,0.5,1.0))
#define WALL_SIDE  ((float4)(0.45,0.75,0.75,1.0))
#define WALL_TOP   ((float4)(0.6,1.0,1.0,1.0))
#define WALLG_UNDER ((float4)(0.3,0.5,0.4,1.0))
#define WALLG_SIDE  ((float4)(0.45,0.75,0.45,1.0))
#define WALLG_TOP   ((float4)(0.6,1.0,0.6,1.0))

/* Edge types - what appears at the end of the grid */
#define ET_WALL         0
#define ET_PORTAL_TORUS 1
#define ET_SOLID_AIR    2

/* Block types */
#define BK_AIR      0
#define BK_WALL     1
#define BK_WALLG    2

/* Handy macro to get the element at a given location from the map
   grid */
#define GRID_GET(grid,x,y,z) ((grid)[x + y*x_size + z*x_size*y_size])
#define GRID_GETV(grid,v) GRID_GET((grid), (v).x,(v).y,(v).z)

/* Given X, it returns X if X is positive, or 0 otherwise */
#define POSITIVE(X) ((X) > 0 ? (X) : 0)

__kernel void raytrace(__write_only __global image2d_t bmp,
    uchar x_size, uchar y_size, uchar z_size, uchar edge_type,
    float rot_x, float rot_y, float cam_x, float cam_y, float cam_z,
    float fov_x, float fov_y, __constant uchar *grid)
{
    /* Screen pixel position: */
    int2 p_pos = (int2)(get_global_id(0), get_global_id(1));

    /* Grid dimensions */
    uchar4 bounds = (uchar4)(x_size, y_size, z_size, 0);

    float4 ray_rot = (float4)(rot_x, rot_y,
                              (p_pos.x * fov_x) / SCREEN_W - fov_x/2,
                              (p_pos.y * fov_y) / SCREEN_H - fov_y/2);
    float4 rot_sin = sin(ray_rot),
           rot_cos = cos(ray_rot);

    /* Voxel traversal ray-tracing algorithm based on John Amanatides'
       and Andrew Woo's paper. */

    /* n is the vector of the ray as if the camera was looking directly
       down the z-axis without any rotation around it. */
    float4 n = (float4)(rot_cos.w * rot_sin.z,
                        -rot_sin.w,
                        rot_cos.w * rot_cos.z,
                        0.0f);

    // v is the unit vector along the ray in actual world coords
    float4 v = (float4)(
      n.x*rot_cos.x + n.y*rot_sin.x*rot_sin.y + n.z*rot_sin.x*rot_cos.y,
      n.y*rot_cos.y - n.z*rot_sin.y,
      -n.x*rot_sin.x + n.y*rot_cos.x*rot_sin.y + n.z*rot_cos.x*rot_cos.y,
      0.0f);

    /* u is the starting point of the ray */
    float4 u = (float4)(cam_x, cam_y, cam_z, 0.0f);
    // Thus equation of the ray = u + vt

    // P = (X,Y,Z) = current voxel coordinates
    int4 P = (int4)((int)u.x, (int)u.y, (int)u.z, 0);
    // TODO handle P being outside bounds of grid

    /* step = (stepX, stepY, stepZ) = values are either 1, 0, or -1.
       Components are determined from the sign of the components of v */
    char4 step = (char4)((char)sign(v.x), (char)sign(v.y),
                         (char)sign(v.z), 0);

    /* tmax = (tmaxX, tmaxY, tmaxZ) = values of t at which ray next
       crosses a voxel boundary in the respective direction */
    float4 tmax = (float4)((P.x + POSITIVE(step.x) - u.x)/v.x,
                           (P.y + POSITIVE(step.y) - u.y)/v.y,
                           (P.z + POSITIVE(step.z) - u.z)/v.z,
                           0.0f);

    /* dt = (dtX, dtY, dtZ) = how far along ray (in units of t) we must
       move for x/y/z component of move to equal width of one voxel */
    float4 dt = (float4)(step.x / v.x,
                         step.y / v.y,
                         step.z / v.z,
                         0.0f);

    /* justOut vector - used for checking we remain within the bounds
       of the grid */
    int4 justOut = (int4)(step.x == -1 ? -1 : bounds.x,
                          step.y == -1 ? -1 : bounds.y,
                          step.z == -1 ? -1 : bounds.z,
                          0);

    float4 ray_color = (float4)(0.0f, 0.0f, 0.0f, 0.0f);
    bool outside = false;
    char lastStep = 'x';

    #define STEP(dim) do { \
                        P.dim += step.dim; \
                        lastStep = (#dim)[0]; \
                        if (P.dim == justOut.dim) { \
                            outside = true; \
                        } else \
                        tmax.dim += dt.dim; \
                      } while (0)

    for (uint iter_count = 0; iter_count < LOOP_LIMIT; iter_count++) {
        uchar block_type = BK_AIR;

        if (tmax.x < tmax.y) {
            if (tmax.x < tmax.z) {
                STEP(x);
            } else {
                STEP(z);
            }
        } else {
            if (tmax.y < tmax.z) {
                STEP(y);
            } else {
                STEP(z);
            }
        }

        if (outside) {
            if (edge_type == ET_WALL) {
                block_type = BK_WALL;
            } /* else leave block_type as BK_AIR */
            // TODO ET_PORTAL_TORUS
        } else {
            block_type = GRID_GETV(grid, P);
        }

        if (block_type == BK_WALL) {
            if (lastStep != 'y') {
                // viewing block from side
                ray_color = WALL_SIDE;
            } else if (step.y == -1) {
                // viewing block from above
                ray_color = WALL_TOP;
            } else {
                // viewing block from below
                ray_color = WALL_UNDER;
            }
        } else if (block_type == BK_WALLG) {
            if (lastStep != 'y')
                ray_color = WALLG_SIDE;
            else if (step.y == -1)
                ray_color = WALLG_TOP;
            else
                ray_color = WALLG_UNDER;
        }

        if (outside || block_type != BK_AIR)
            break;

    }

    write_imagef(bmp, p_pos, ray_color);
}


Fix typo in test

Fix typo in test

git-svn-id: ffe668792ed300d6c2daa1f6eba2e0aa28d7ec6c@178510 91177308-0d34-0410-b5e6-96231b3b80d8

// Check that -mcpu works for all supported GPUs

// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=r600 %s -o - 2>&1 | FileCheck --check-prefix=R600-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=rv610 %s -o - 2>&1 | FileCheck --check-prefix=R600-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=rv620 %s -o - 2>&1 | FileCheck --check-prefix=R600-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=rv630 %s -o - 2>&1 | FileCheck --check-prefix=R600-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=rv635 %s -o - 2>&1 | FileCheck --check-prefix=R600-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=rs780 %s -o - 2>&1 | FileCheck --check-prefix=R600-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=rs880 %s -o - 2>&1 | FileCheck --check-prefix=R600-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=rv670 %s -o - 2>&1 | FileCheck --check-prefix=RV670-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=rv710 %s -o - 2>&1 | FileCheck --check-prefix=RV710-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=rv730 %s -o - 2>&1 | FileCheck --check-prefix=RV730-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=rv740 %s -o - 2>&1 | FileCheck --check-prefix=RV770-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=rv770 %s -o - 2>&1 | FileCheck --check-prefix=RV770-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=palm %s -o - 2>&1 | FileCheck --check-prefix=CEDAR-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=cedar %s -o - 2>&1 | FileCheck --check-prefix=CEDAR-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=sumo %s -o - 2>&1 | FileCheck --check-prefix=REDWOOD-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=sumo2 %s -o - 2>&1 | FileCheck --check-prefix=REDWOOD-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=redwood %s -o - 2>&1 | FileCheck --check-prefix=REDWOOD-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=juniper %s -o - 2>&1 | FileCheck --check-prefix=JUNIPER-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=juniper %s -o - 2>&1 | FileCheck --check-prefix=JUNIPER-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=hemlock %s -o - 2>&1 | FileCheck --check-prefix=CYPRESS-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=cypress %s -o - 2>&1 | FileCheck --check-prefix=CYPRESS-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=barts %s -o - 2>&1 | FileCheck --check-prefix=BARTS-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=turks %s -o - 2>&1 | FileCheck --check-prefix=TURKS-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=caicos %s -o - 2>&1 | FileCheck --check-prefix=CAICOS-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=cayman %s -o - 2>&1 | FileCheck --check-prefix=CAYMAN-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=aruba %s -o - 2>&1 | FileCheck --check-prefix=CAYMAN-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=tahiti %s -o - 2>&1 | FileCheck --check-prefix=TAHITI-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=pitcairn %s -o - 2>&1 | FileCheck --check-prefix=PITCAIRN-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=verde %s -o - 2>&1 | FileCheck --check-prefix=VERDE-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=oland %s -o - 2>&1 | FileCheck --check-prefix=OLAND-CHECK %s

// R600-CHECK:  "-target-cpu" "r600"
// RV670-CHECK: "-target-cpu" "rv670"
// RV710-CHECK: "-target-cpu" "rv710"
// RV730-CHECK: "-target-cpu" "rv730"
// RV770-CHECK: "-target-cpu" "rv770"
// CEDAR-CHECK: "-target-cpu" "cedar"
// REDWOOD-CHECK: "-target-cpu" "redwood"
// JUNIPER-CHECK: "-target-cpu" "juniper"
// CYPRESS-CHECK: "-target-cpu" "cypress"
// BARTS-CHECK: "-target-cpu" "barts"
// TURKS-CHECK: "-target-cpu" "turks"
// CAICOS-CHECK: "-target-cpu" "caicos"
// CAYMAN-CHECK: "-target-cpu" "cayman"
// TAHITI-CHECK: "-target-cpu" "tahiti"
// PITCAIRN-CHECK: "-target-cpu" "pitcairn"
// VERDE-CHECK: "-target-cpu" "verde"
// OLAND-CHECK: "-target-cpu" "oland"

// Check that -mcpu works for all supported GPUs

// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=r600 %s -o - 2>&1 | FileCheck --check-prefix=R600-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=rv610 %s -o - 2>&1 | FileCheck --check-prefix=R600-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=rv620 %s -o - 2>&1 | FileCheck --check-prefix=R600-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=rv630 %s -o - 2>&1 | FileCheck --check-prefix=R600-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=rv635 %s -o - 2>&1 | FileCheck --check-prefix=R600-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=rs780 %s -o - 2>&1 | FileCheck --check-prefix=R600-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=rs880 %s -o - 2>&1 | FileCheck --check-prefix=R600-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=rv670 %s -o - 2>&1 | FileCheck --check-prefix=RV670-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=rv710 %s -o - 2>&1 | FileCheck --check-prefix=RV710-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=rv730 %s -o - 2>&1 | FileCheck --check-prefix=RV730-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=rv740 %s -o - 2>&1 | FileCheck --check-prefix=RV770-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=rv770 %s -o - 2>&1 | FileCheck --check-prefix=RV770-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=palm %s -o - 2>&1 | FileCheck --check-prefix=CEDAR-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=cedar %s -o - 2>&1 | FileCheck --check-prefix=CEDAR-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=sumo %s -o - 2>&1 | FileCheck --check-prefix=REDWOOD-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=sumo2 %s -o - 2>&1 | FileCheck --check-prefix=REDWOOD-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=redwood %s -o - 2>&1 | FileCheck --check-prefix=REDWOOD-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=juniper %s -o - 2>&1 | FileCheck --check-prefix=JUNIPER-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=juniper %s -o - 2>&1 | FileCheck --check-prefix=JUNIPER-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=hemlock %s -o - 2>&1 | FileCheck --check-prefix=CYPRESS-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=cypress %s -o - 2>&1 | FileCheck --check-prefix=CYPRESS-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=barts %s -o - 2>&1 | FileCheck --check-prefix=BARTS-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=turks %s -o - 2>&1 | FileCheck --check-prefix=TURKS-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=caicos %s -o - 2>&1 | FileCheck --check-prefix=CAICOS-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=cayman %s -o - 2>&1 | FileCheck --check-prefix=CAYMAN-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=aruba %s -o - 2>&1 | FileCheck --check-prefix=CAYMAN-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=tahiti %s -o - 2>&1 | FileCheck --check-prefix=TAHITI-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=pitcairn %s -o - 2>&1 | FileCheck --check-prefix=PITCAIRN-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=verde %s -o - 2>&1 | FileCheck --check-prefix=VERDE-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=oland %s -o - 2>&1 | FileCheck --check-prefix=OLAND-CHECK %s

// R600-CHECK:  "-target-cpu" "r600"
// RV670-CHECK: "-target-cpu" "rv670"
// RV710-CHECK: "-target-cpu" "rv710"
// RV730-CHECK: "-target-cpu" "rv730"
// RV770-CHECK: "-target-cpu" "rv770"
// CEDAR-CHECK: "-target-cpu" "cedar"
// REDOWOOD-CHECK: "-target-cpu" "redwood"
// JUNIPER-CHECK: "-target-cpu" "juniper"
// CYPRESS-CHECK: "-target-cpu" "cypress"
// BARTS-CHECK: "-target-cpu" "barts"
// TURKS-CHECK: "-target-cpu" "turks"
// CAICOS-CHECK: "-target-cpu" "caicos"
// CAYMAN-CHECK: "-target-cpu" "cayman"
// TAHITI-CHECK: "-target-cpu" "tahiti"
// PITCAIRN-CHECK: "-target-cpu" "pitcairn"
// VERDE-CHECK: "-target-cpu" "verde"
// OLAND-CHECK: "-target-cpu" "oland"


faster GPU kernel

faster GPU kernel

#define HADD(v) ((v).x+(v).y+(v).z+(v).w)

#define W 1
#define SUMLEN (W*8)
#define STRIDE 16
#define CACHE (SUMLEN+STRIDE)

__attribute__((reqd_work_group_size(64,1,1)))
__kernel void correlate (
  __global float8 *correlation,
  const int corr_size,
  __constant float4 *base,
  __constant float4 *mask,
  const int sample_size,
  const int stride )
{
  float4 l_base[CACHE], l_mask[CACHE];
  float4 sums[SUMLEN]; for(int i=0; i<SUMLEN; i++) sums[i] = 0;
  int gid = get_global_id(0);
  int offset_y = gid*(W*8) / corr_size;
  int offset_x = gid*(W*8) - (offset_y*corr_size);
  for (int y=0; y < sample_size-offset_y; y++) {
    int mask_idx = y*stride - offset_x;
    int mi = y*stride;
    int base_idx = (offset_y+y)*stride;
    for (int x=offset_x%STRIDE; x < sample_size; x+=STRIDE) {
      if (x < offset_x) {
        for (int i=0; i<8; i++) {
          l_base[i] = base[base_idx+x+i];
          l_mask[i] = mask[mi+x+i];
        }
      } else {
        for (int i=0; i<CACHE; i++) {
          l_base[i] = base[base_idx+x+i];
          l_mask[i] = mask[mask_idx+x+i];
        }
        for (int i=0; i<STRIDE; i++)
          for (int j=0; j<SUMLEN; j++)
            sums[j] += l_base[i+j] * l_mask[i];
      }
    }
  }
  for (int i=0; i<W; i++)
  correlation[gid*W+i] = (float8)(
    HADD(sums[i*8+0]),
    HADD(sums[i*8+1]),
    HADD(sums[i*8+2]),
    HADD(sums[i*8+3]),
    HADD(sums[i*8+4]),
    HADD(sums[i*8+5]),
    HADD(sums[i*8+6]),
    HADD(sums[i*8+7])
  );
}

#define HADD(v) ((v).x+(v).y+(v).z+(v).w)

#define W 1
#define SUMLEN (W*8)
#define STRIDE 16
#define CACHE (SUMLEN+STRIDE)

__attribute__((reqd_work_group_size(64,1,1)))
__kernel void correlate (
  __global float8 *correlation,
  const int corr_size,
  __constant float4 *base,
  __constant float4 *mask,
  const int sample_size,
  const int stride )
{
  float4 l_base[CACHE], l_mask[CACHE];
  float4 sums[SUMLEN]; for(int i=0; i<SUMLEN; i++) sums[i] = 0;
  int gid = get_global_id(0);
  int offset_y = gid*(W*8) / corr_size;
  int offset_x = gid*(W*8) - (offset_y*corr_size);
  for (int y=0; y < sample_size-offset_y; y++) {
    int mask_idx = y*stride - offset_x;
    int mi = max(mask_idx, 0);
    int base_idx = (offset_y+y)*stride;
    for (int x=offset_x%STRIDE; x < sample_size; x+=STRIDE) {
      if (x < offset_x) {
        for (int i=0; i<8; i++) {
          l_base[i] = base[base_idx+x+i];
          l_mask[i] = mask[mi+x+i];
        }
      } else {
        for (int i=0; i<CACHE; i++) {
          l_base[i] = base[base_idx+x+i];
          l_mask[i] = mask[mask_idx+x+i];
        }
        for (int i=0; i<STRIDE; i++)
          for (int j=0; j<SUMLEN; j++)
            sums[j] += l_base[i+j] * l_mask[i];
      }
    }
  }
  for (int i=0; i<W; i++)
  correlation[gid*W+i] = (float8)(
    HADD(sums[i*8+0]),
    HADD(sums[i*8+1]),
    HADD(sums[i*8+2]),
    HADD(sums[i*8+3]),
    HADD(sums[i*8+4]),
    HADD(sums[i*8+5]),
    HADD(sums[i*8+6]),
    HADD(sums[i*8+7])
  );
}


Fix permissions

Fix permissions


Fixed a bug with MeshToSegmentation in 2D with new mesh system

// http://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect
char get_line_intersection(float p0_x, float p0_y, float p1_x, float p1_y,
    float p2_x, float p2_y, float p3_x, float p3_y, float* i_x, float* i_y)
{
    float s1_x, s1_y, s2_x, s2_y;
    s1_x = p1_x - p0_x;     s1_y = p1_y - p0_y;
    s2_x = p3_x - p2_x;     s2_y = p3_y - p2_y;

    float s, t;
    s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y);
    t = ( s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y);

    if (s >= 0 && s <= 1 && t >= 0 && t <= 1)
    {
        // Collision detected
        *i_x = p0_x + (t * s1_x);
        *i_y = p0_y + (t * s1_y);
        return 1;
    }

    return 0; // No collision
}

__kernel void mesh_to_segmentation_2d(
		__global float* coordinates,
		__global uint2* lines,
		__private uint nrOfLines,
		__write_only image2d_t segmentation,
		__private float spacingX,
		__private float spacingY,
		__private uchar label
	) {

	const int2 pos = {get_global_id(0), get_global_id(1)};

	// For each line, check if ray (arbitrary direction) from this pixel intersects
	// Count number of intersections, if even: not inside, if odd: inside
	int intersections = 0;
    float x1 = pos.x*spacingX;
    float y1 = pos.y*spacingY;
    const float t = 0.00000001; // threshold
    // x2 and y2 is 0
    float y2 = y1;
	for(int i = 0; i < nrOfLines; ++i) {
	    // https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection
	    // http://geomalgorithms.com/a03-_inclusion.html
	    // Find intersection point
	    float3 coordinate3 = vload3(lines[i].x, coordinates);
	    float3 coordinate4 = vload3(lines[i].y, coordinates);
	    float x3 = coordinate3.x;
	    float y3 = coordinate3.y;
	    float x4 = coordinate4.x;
	    float y4 = coordinate4.y;

	    // Order edge points so that it point downwards
	    if(y3 > y4) {
	        float tmp = y4;
	        y4 = y3;
	        y3 = tmp;
	        tmp = x4;
	        x4 = x3;
	        x3 = tmp;
	    }

	    if(y3 == y4) {
	        // Horizontal edge, drop
	        continue;
	    }

        float x, y;
        if(get_line_intersection(x1, y1, 0, y2, x3, y3, x4, y4, &x, &y) == 1) {
            // Have we hit an edge point?
            if(fabs(x-x4) < t && fabs(y-y4) < t) {
                intersections++;
            } else if(fabs(x-x3) < t && fabs(y-y3) < t) {
            } else {
                intersections++;
            }
        }
	}

	write_imageui(segmentation, pos, intersections % 2 == 0 ? 0:label);
}

int rayIntersectsTriangle(float3 p, float3 d, float3 v0, float3 v1, float3 v2) {

	float3 e1,e2,h,s,q;
	float a,f,u,v;
	e1 = v1 - v0;
	e2 = v2 - v0;

	h = cross(d, e2);
	a = dot(e1,h);

	if (a > -0.00000000001f && a < 0.00000000001f)
        return 0;

	f = 1.0f/a;
	s = p - v0;
	u = f * (dot(s,h));

	if (u < 0.0 || u > 1.0)
		return 0;

	q = cross(s,e1);
	v = f * dot(d,q);

	if (v < 0.0 || u + v > 1.0)
        return 0;

	// at this stage we can compute t to find out where
	// the intersection point is on the line
	float t = f * dot(e2,q);

	if (t > 0.00000001f) { // ray intersection
        return 1;

	} else { // this means that there is a line intersection
		 // but not a ray intersection
		 return 0;
     }

}

__kernel void mesh_to_segmentation_3d(
		__global float* coordinates,
		__global uint* triangles,
		__private uint nrOfTriangles,
		__global uchar* segmentation,
		__private float spacingX,
		__private float spacingY,
		__private float spacingZ,
		__private uchar label
	) {
	const int4 pos = {get_global_id(0), get_global_id(1), get_global_id(2), 0};

	// For each triangle, check if ray (arbitrary direction) from this pixel intersects
	// See: http://geomalgorithms.com/a06-_intersect-2.html#intersect3D_RayTriangle()
	// Count number of intersections, if even: not inside, if odd: inside
	int intersections = 0;

	// Ray start point
    float3 P0 = {pos.x*spacingX, pos.y*spacingY, pos.z*spacingZ};
    if(P0.y == 0) {
        // There is a strange problem if y component is exactly zero
        // This is a hack to avoid this
        P0.y = 0.00001;
    }

    // Set arbitrarty direction
    float3 P1 = P0;
    P1.x += 0.1;

    for(int i = 0; i < nrOfTriangles; i++) {
        const uint3 triangle = vload3(i, triangles);
        const float3 u = vload3(triangle.x, coordinates);
        const float3 v = vload3(triangle.y, coordinates);
        const float3 w = vload3(triangle.z, coordinates);

        if(rayIntersectsTriangle(P0, P1, u, v, w) >= 1) {
            intersections++;
        }
    }

	segmentation[pos.x + pos.y*get_global_size(0) + pos.z*get_global_size(0)*get_global_size(1)] = intersections % 2 == 0 ? 0:label;
}

// http://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect
char get_line_intersection(float p0_x, float p0_y, float p1_x, float p1_y,
    float p2_x, float p2_y, float p3_x, float p3_y, float* i_x, float* i_y)
{
    float s1_x, s1_y, s2_x, s2_y;
    s1_x = p1_x - p0_x;     s1_y = p1_y - p0_y;
    s2_x = p3_x - p2_x;     s2_y = p3_y - p2_y;

    float s, t;
    s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y);
    t = ( s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y);

    if (s >= 0 && s <= 1 && t >= 0 && t <= 1)
    {
        // Collision detected
        *i_x = p0_x + (t * s1_x);
        *i_y = p0_y + (t * s1_y);
        return 1;
    }

    return 0; // No collision
}

__kernel void mesh_to_segmentation_2d(
		__global float2* coordinates,
		__global uint2* lines,
		__private uint nrOfLines,
		__write_only image2d_t segmentation,
		__private float spacingX,
		__private float spacingY,
		__private uchar label
	) {

	const int2 pos = {get_global_id(0), get_global_id(1)};

	// For each line, check if ray (arbitrary direction) from this pixel intersects
	// Count number of intersections, if even: not inside, if odd: inside
	int intersections = 0;
    float x1 = pos.x*spacingX;
    float y1 = pos.y*spacingY;
    const float t = 0.00000001; // threshold
    // x2 and y2 is 0
    float y2 = y1;
	for(int i = 0; i < nrOfLines; ++i) {
	    // https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection
	    // http://geomalgorithms.com/a03-_inclusion.html
	    // Find intersection point
	    float x3 = coordinates[lines[i].x].x;
	    float y3 = coordinates[lines[i].x].y;
	    float x4 = coordinates[lines[i].y].x;
	    float y4 = coordinates[lines[i].y].y;

	    // Order edge points so that it point downwards
	    if(y3 > y4) {
	        float tmp = y4;
	        y4 = y3;
	        y3 = tmp;
	        tmp = x4;
	        x4 = x3;
	        x3 = tmp;
	    }

	    if(y3 == y4) {
	        // Horizontal edge, drop
	        continue;
	    }

        float x, y;
        if(get_line_intersection(x1, y1, 0, y2, x3, y3, x4, y4, &x, &y) == 1) {
            // Have we hit an edge point?
            if(fabs(x-x4) < t && fabs(y-y4) < t) {
                intersections++;
            } else if(fabs(x-x3) < t && fabs(y-y3) < t) {
            } else {
                intersections++;
            }
        }
	}

	write_imageui(segmentation, pos, intersections % 2 == 0 ? 0:label);
}

int rayIntersectsTriangle(float3 p, float3 d, float3 v0, float3 v1, float3 v2) {

	float3 e1,e2,h,s,q;
	float a,f,u,v;
	e1 = v1 - v0;
	e2 = v2 - v0;

	h = cross(d, e2);
	a = dot(e1,h);

	if (a > -0.00000000001f && a < 0.00000000001f)
        return 0;

	f = 1.0f/a;
	s = p - v0;
	u = f * (dot(s,h));

	if (u < 0.0 || u > 1.0)
		return 0;

	q = cross(s,e1);
	v = f * dot(d,q);

	if (v < 0.0 || u + v > 1.0)
        return 0;

	// at this stage we can compute t to find out where
	// the intersection point is on the line
	float t = f * dot(e2,q);

	if (t > 0.00000001f) { // ray intersection
        return 1;

	} else { // this means that there is a line intersection
		 // but not a ray intersection
		 return 0;
     }

}

__kernel void mesh_to_segmentation_3d(
		__global float* coordinates,
		__global uint* triangles,
		__private uint nrOfTriangles,
		__global uchar* segmentation,
		__private float spacingX,
		__private float spacingY,
		__private float spacingZ,
		__private uchar label
	) {
	const int4 pos = {get_global_id(0), get_global_id(1), get_global_id(2), 0};

	// For each triangle, check if ray (arbitrary direction) from this pixel intersects
	// See: http://geomalgorithms.com/a06-_intersect-2.html#intersect3D_RayTriangle()
	// Count number of intersections, if even: not inside, if odd: inside
	int intersections = 0;

	// Ray start point
    float3 P0 = {pos.x*spacingX, pos.y*spacingY, pos.z*spacingZ};
    if(P0.y == 0) {
        // There is a strange problem if y component is exactly zero
        // This is a hack to avoid this
        P0.y = 0.00001;
    }

    // Set arbitrarty direction
    float3 P1 = P0;
    P1.x += 0.1;

    for(int i = 0; i < nrOfTriangles; i++) {
        const uint3 triangle = vload3(i, triangles);
        const float3 u = vload3(triangle.x, coordinates);
        const float3 v = vload3(triangle.y, coordinates);
        const float3 w = vload3(triangle.z, coordinates);

        if(rayIntersectsTriangle(P0, P1, u, v, w) >= 1) {
            intersections++;
        }
    }

	segmentation[pos.x + pos.y*get_global_size(0) + pos.z*get_global_size(0)*get_global_size(1)] = intersections % 2 == 0 ? 0:label;
}


Revert this change to make things work on ATI (I'm not sure what's up)


more attempts to perturb rays

more attempts to perturb rays

#include "cl/mwc64x/cl/mwc64x.cl"

// Doesn't return 0 so that rays can bounce without bumping.
float sphere_toi(
  const float3 eye,
  const float3 look,

  const float3 center,
  const float radius)
{
  // quadratic coefficients
  float a = dot(look, look);
  float b = 2 * dot(eye - center, look);
  float3 to_center = eye - center;
  float c = dot(to_center, to_center) - radius*radius;

  // discriminant
  float d = b*b - 4*a*c;

  if (d < 0) {
    return HUGE_VALF;
  }

  float s1 = (sqrt(d) - b) / (2 * a);
  if (s1 <= 0) {
    s1 = HUGE_VALF;
  }

  float s2 = (-sqrt(d) - b) / (2 * a);
  if (s1 < s2 || s2 <= 0) {
    return s1;
  }

  return s2;
}

typedef struct {
  float4 row1;
  float4 row2;
  float4 row3;
  float4 row4;
} mat4;

float4 vmult(mat4 m, float4 v) {
  return
    (float4)(
      dot(m.row1, v),
      dot(m.row2, v),
      dot(m.row3, v),
      dot(m.row4, v)
    );
}

mat4 screen_to_view(uint w, uint h, float fovy) {
  float aspect = (float)w / (float)h;

  float b = tan(fovy / 2);
  float a = 2 * b / h;
  b = -b;

  mat4 r;
  // We divide both x and y by h, to take aspect ratio into account.
  // An increase in image width will cause wider rays to be shot.
  r.row1 = (float4)(a, 0, 0, b * aspect);
  r.row2 = (float4)(0, a, 0, b);
  r.row3 = (float4)(0, 0, 1, 0);
  r.row4 = (float4)(0, 0, 0, 1);

  return r;
}

mat4 view_to_world(float3 eye, float3 look, float3 up) {
  float4 x = (float4)(cross(look, up), 0);
  float4 y = (float4)(up, 0);
  float4 z = (float4)(look, 0);
  float4 w = (float4)(eye, 1);

  // Change of basis

  mat4 r;
  r.row1.x = x.x;
  r.row2.x = x.y;
  r.row3.x = x.z;
  r.row4.x = x.w;

  r.row1.y = y.x;
  r.row2.y = y.y;
  r.row3.y = y.z;
  r.row4.y = y.w;

  r.row1.z = z.x;
  r.row2.z = z.y;
  r.row3.z = z.z;
  r.row4.z = z.w;

  r.row1.w = w.x;
  r.row2.w = w.y;
  r.row3.w = w.z;
  r.row4.w = w.w;

  return r;
}

typedef struct {
  float r;
  float g;
  float b;
} RGB;

RGB rgb(float3 xyz) {
  RGB r;
  r.r = xyz.x;
  r.g = xyz.y;
  r.b = xyz.z;
  return r;
}

typedef struct { float x, y, z } float3_parse;

float3 pack_float3(float3_parse f) {
  return (float3)(f.x, f.y, f.z);
}

typedef struct {
  float3_parse center;
  float radius;
  float3_parse color;
  float diffuseness;
  float emittance;
  float reflectance;
  float transmittance;
} Object;

float parse_float(__global const float** data) {
  float r = **data;
  ++*data;
  return r;
}

float3_parse parse_float3(__global const float** data) {
  float3_parse r;
  r.x = parse_float(data);
  r.y = parse_float(data);
  r.z = parse_float(data);
  return r;
}

Object parse_object(__global const float* data) {
  Object r;
  r.center        = parse_float3(&data);
  r.radius        = parse_float(&data);
  r.color         = parse_float3(&data);
  r.diffuseness   = parse_float(&data);
  r.emittance     = parse_float(&data);
  r.reflectance   = parse_float(&data);
  r.transmittance = parse_float(&data);
  return r;
}

typedef struct {
  float3 origin;
  float3 direction;
} Ray;

void raycast(
  Ray ray,

  __global const float* objects,
  const uint num_objects,

  float* toi,
  Object* collision
) {
  *toi = HUGE_VALF;

  for (uint i = 0; i < num_objects; ++i) {
    Object object = parse_object((Object*)objects + i);
    float this_toi = sphere_toi(ray.origin, ray.direction, pack_float3(object.center), object.radius);

    if (this_toi >= *toi) {
      continue;
    }

    *toi = this_toi;
    *collision = object;
  }
}

float rand(mwc64x_state_t* rand_state) {
  return (float)MWC64X_NextUint(rand_state) / (float)UINT_MAX;
}

float3 perturb_frame(mwc64x_state_t* rand_state, const float max_angle, float3 x, float3 y, float3 z) {
  float3 coeffs;
  const float c = cos(max_angle);
  coeffs.y = rand(rand_state) * (1 - c) + c;
  const float xz = sqrt(1 - coeffs.y * coeffs.y);
  const float azimuth = rand(rand_state) * 2 * 3.14;
  coeffs.x = cos(azimuth);
  coeffs.z = sin(azimuth);
  coeffs.x *= xz;
  coeffs.z *= xz;
  return coeffs.x*x + coeffs.y*y + coeffs.z*z;
}

float3 perturb(mwc64x_state_t* rand_state, const float3 unperturbed, const float3 normal, const float max_angle) {
  const float3 y = unperturbed;
  // TODO: find z/x better when normal ~= unperturbed
  const float3 z = normalize(cross(normal, y));
  const float3 x = normalize(cross(z, y));

  for (int i = 0; i < 8; ++i) {
    const float3 r = perturb_frame(rand_state, max_angle, x, y, z);
    if (dot(r, normal) >= 0) {
      return r;
    }
  }

  // If we failed several times, we're probably almost perpendicular to the normal.
  // I think that's a pretty small area, so we can just forget the perturb here.
  return unperturbed;
}

float3 pathtrace(
  Ray ray,
  uint max_depth,
  float3 ambient,
  mwc64x_state_t* rand_state,
  __global const float* objects,
  const uint num_objects
) {
  if (max_depth == 0) {
    return ambient;
  }

  float toi;
  Object collided_object;

  raycast(ray, objects, num_objects, &toi, &collided_object);

  if (toi == HUGE_VALF) {
    return ambient;
  }

  float3 light = ambient * (collided_object.reflectance + collided_object.transmittance);

  light += (float3)(collided_object.emittance);

  const float3 collision_point = ray.origin + toi*ray.direction;
  const float3 normal = (collision_point - pack_float3(collided_object.center)) / collided_object.radius;
  const float max_scatter_angle = 3.14 * collided_object.diffuseness;

  float r = rand(rand_state);

  // TODO: loop + accumulators instead of recursion
  // TODO: consider removing ambient light and adding a large light "around" the whole world.

  r -= collided_object.transmittance;
  if (r <= 0) {
    // TODO: cos_theta < 0?
    Ray transmitted_ray;
    const float3 unperturbed = ray.direction;
    transmitted_ray.direction = perturb(rand_state, unperturbed, -normal, max_scatter_angle);
    transmitted_ray.origin = collision_point + 0.1f * transmitted_ray.direction;

    light +=
      pathtrace(
        transmitted_ray,
        max_depth - 1,
        ambient,
        rand_state,
        objects,
        num_objects
      );
  } else {
    r -= collided_object.reflectance;
    if (r <= 0) {
      // TODO: cos_theta < 0?
      Ray reflected_ray;
      const float cos_theta = dot(ray.direction, normal);
      const float3 unperturbed = ray.direction - 2*cos_theta*normal;
      reflected_ray.direction = perturb(rand_state, unperturbed, normal, max_scatter_angle);
      reflected_ray.origin = collision_point + 0.1f * reflected_ray.direction;

      light +=
        pathtrace(
          reflected_ray,
          max_depth - 1,
          ambient,
          rand_state,
          objects,
          num_objects
        );
    }
  }

  return pack_float3(collided_object.color) * light;
}

mwc64x_state_t init_rand_state(ulong random_seed) {
  mwc64x_state_t rand_state;
  rand_state.x = (uint)(random_seed & 0xFFFFFFFF);
  rand_state.c = (random_seed & 0xFFFFFFFF00000000) >> 32;
  return rand_state;
}

__kernel void render(
  const uint image_width,
  const uint image_height,

  const float fovy,
  float3 eye,
  const float3 look,
  const float3 up,

  ulong random_seed,
  float3 ambient_light,

  __global const float* objects,
  const uint num_objects,

  __global RGB * output)
{
  int id = get_global_id(0);

  const int x_pix = id % image_width;
  const int y_pix = id / image_width;

  float4 world_pos =
    vmult(view_to_world(eye, look, up),
    vmult(screen_to_view(image_width, image_height, fovy),
    (float4)(x_pix, y_pix, 1, 1)
  ));

  Ray ray;
  ray.origin = eye;
  ray.direction = normalize((world_pos / world_pos.w).xyz - eye);

  random_seed = random_seed * id * id;
  mwc64x_state_t rand_state = init_rand_state(random_seed);
  MWC64X_Skip(&rand_state, 20);

  output[id] = rgb(pathtrace(ray, 8, ambient_light, &rand_state, objects, num_objects));
}

#include "cl/mwc64x/cl/mwc64x.cl"

// Doesn't return 0 so that rays can bounce without bumping.
float sphere_toi(
  const float3 eye,
  const float3 look,

  const float3 center,
  const float radius)
{
  // quadratic coefficients
  float a = dot(look, look);
  float b = 2 * dot(eye - center, look);
  float3 to_center = eye - center;
  float c = dot(to_center, to_center) - radius*radius;

  // discriminant
  float d = b*b - 4*a*c;

  if (d < 0) {
    return HUGE_VALF;
  }

  float s1 = (sqrt(d) - b) / (2 * a);
  if (s1 <= 0) {
    s1 = HUGE_VALF;
  }

  float s2 = (-sqrt(d) - b) / (2 * a);
  if (s1 < s2 || s2 <= 0) {
    return s1;
  }

  return s2;
}

typedef struct {
  float4 row1;
  float4 row2;
  float4 row3;
  float4 row4;
} mat4;

float4 vmult(mat4 m, float4 v) {
  return
    (float4)(
      dot(m.row1, v),
      dot(m.row2, v),
      dot(m.row3, v),
      dot(m.row4, v)
    );
}

mat4 screen_to_view(uint w, uint h, float fovy) {
  float aspect = (float)w / (float)h;

  float b = tan(fovy / 2);
  float a = 2 * b / h;
  b = -b;

  mat4 r;
  // We divide both x and y by h, to take aspect ratio into account.
  // An increase in image width will cause wider rays to be shot.
  r.row1 = (float4)(a, 0, 0, b * aspect);
  r.row2 = (float4)(0, a, 0, b);
  r.row3 = (float4)(0, 0, 1, 0);
  r.row4 = (float4)(0, 0, 0, 1);

  return r;
}

mat4 view_to_world(float3 eye, float3 look, float3 up) {
  float4 x = (float4)(cross(look, up), 0);
  float4 y = (float4)(up, 0);
  float4 z = (float4)(look, 0);
  float4 w = (float4)(eye, 1);

  // Change of basis

  mat4 r;
  r.row1.x = x.x;
  r.row2.x = x.y;
  r.row3.x = x.z;
  r.row4.x = x.w;

  r.row1.y = y.x;
  r.row2.y = y.y;
  r.row3.y = y.z;
  r.row4.y = y.w;

  r.row1.z = z.x;
  r.row2.z = z.y;
  r.row3.z = z.z;
  r.row4.z = z.w;

  r.row1.w = w.x;
  r.row2.w = w.y;
  r.row3.w = w.z;
  r.row4.w = w.w;

  return r;
}

typedef struct {
  float r;
  float g;
  float b;
} RGB;

RGB rgb(float3 xyz) {
  RGB r;
  r.r = xyz.x;
  r.g = xyz.y;
  r.b = xyz.z;
  return r;
}

typedef struct { float x, y, z } float3_parse;

float3 pack_float3(float3_parse f) {
  return (float3)(f.x, f.y, f.z);
}

typedef struct {
  float3_parse center;
  float radius;
  float3_parse color;
  float diffuseness;
  float emittance;
  float reflectance;
  float transmittance;
} Object;

float parse_float(__global const float** data) {
  float r = **data;
  ++*data;
  return r;
}

float3_parse parse_float3(__global const float** data) {
  float3_parse r;
  r.x = parse_float(data);
  r.y = parse_float(data);
  r.z = parse_float(data);
  return r;
}

Object parse_object(__global const float* data) {
  Object r;
  r.center        = parse_float3(&data);
  r.radius        = parse_float(&data);
  r.color         = parse_float3(&data);
  r.diffuseness   = parse_float(&data);
  r.emittance     = parse_float(&data);
  r.reflectance   = parse_float(&data);
  r.transmittance = parse_float(&data);
  return r;
}

typedef struct {
  float3 origin;
  float3 direction;
} Ray;

void raycast(
  Ray ray,

  __global const float* objects,
  const uint num_objects,

  float* toi,
  Object* collision
) {
  *toi = HUGE_VALF;

  for (uint i = 0; i < num_objects; ++i) {
    Object object = parse_object((Object*)objects + i);
    float this_toi = sphere_toi(ray.origin, ray.direction, pack_float3(object.center), object.radius);

    if (this_toi >= *toi) {
      continue;
    }

    *toi = this_toi;
    *collision = object;
  }
}

float rand(mwc64x_state_t* rand_state) {
  return (float)MWC64X_NextUint(rand_state) / (float)UINT_MAX;
}

float3 perturb_frame(mwc64x_state_t* rand_state, const float max_angle, float3 x, float3 y, float3 z) {
  float3 coeffs;
  const float c = cos(max_angle);
  coeffs.y = rand(rand_state) * (1 - c) + c;
  const float xz = sqrt(1 - coeffs.y * coeffs.y);
  const float azimuth = rand(rand_state) * 2 * 3.14;
  coeffs.x = cos(azimuth);
  coeffs.z = sin(azimuth);
  coeffs.x *= xz;
  coeffs.z *= xz;
  return coeffs.x*x + coeffs.y*y + coeffs.z*z;
}

float3 perturb(mwc64x_state_t* rand_state, const float3 unperturbed, const float3 normal, const float max_angle) {
  const float3 y = unperturbed;
  // TODO: find z/x better when normal ~= unperturbed
  const float3 z = normalize(cross(normal, y));
  const float3 x = normalize(cross(z, y));

  for (int i = 0; i < 4; ++i) {
    const float3 r = perturb_frame(rand_state, max_angle, x, y, z);
    if (dot(r, normal) >= 0) {
      return r;
    }
  }

  // If we failed several times, we're probably almost perpendicular to the normal.
  // I think that's a pretty small area, so we can just forget the perturb here.
  return unperturbed;
}

float3 pathtrace(
  Ray ray,
  uint max_depth,
  float3 ambient,
  mwc64x_state_t* rand_state,
  __global const float* objects,
  const uint num_objects
) {
  if (max_depth == 0) {
    return ambient;
  }

  float toi;
  Object collided_object;

  raycast(ray, objects, num_objects, &toi, &collided_object);

  if (toi == HUGE_VALF) {
    return ambient;
  }

  float3 light = ambient * (collided_object.reflectance + collided_object.transmittance);

  light += (float3)(collided_object.emittance);

  const float3 collision_point = ray.origin + toi*ray.direction;
  const float3 normal = (collision_point - pack_float3(collided_object.center)) / collided_object.radius;
  const float max_scatter_angle = 3.14 * collided_object.diffuseness;

  float r = rand(rand_state);

  // TODO: loop + accumulators instead of recursion
  // TODO: consider removing ambient light and adding a large light "around" the whole world.

  r -= collided_object.transmittance;
  if (r <= 0) {
    // TODO: cos_theta < 0?
    Ray transmitted_ray;
    const float3 unperturbed = ray.direction;
    transmitted_ray.direction = perturb(rand_state, unperturbed, -normal, max_scatter_angle);
    transmitted_ray.origin = collision_point + 0.1f * transmitted_ray.direction;

    light +=
      pathtrace(
        transmitted_ray,
        max_depth - 1,
        ambient,
        rand_state,
        objects,
        num_objects
      );
  } else {
    r -= collided_object.reflectance;
    if (r <= 0) {
      // TODO: cos_theta < 0?
      Ray reflected_ray;
      const float cos_theta = dot(ray.direction, normal);
      const float3 unperturbed = ray.direction - 2*cos_theta*normal;
      reflected_ray.direction = perturb(rand_state, unperturbed, normal, max_scatter_angle);
      reflected_ray.origin = collision_point + 0.1f * reflected_ray.direction;

      light +=
        pathtrace(
          reflected_ray,
          max_depth - 1,
          ambient,
          rand_state,
          objects,
          num_objects
        );
    }
  }

  return pack_float3(collided_object.color) * light;
}

mwc64x_state_t init_rand_state(ulong random_seed) {
  mwc64x_state_t rand_state;
  rand_state.x = (uint)(random_seed & 0xFFFFFFFF);
  rand_state.c = (random_seed & 0xFFFFFFFF00000000) >> 32;
  return rand_state;
}

__kernel void render(
  const uint image_width,
  const uint image_height,

  const float fovy,
  float3 eye,
  const float3 look,
  const float3 up,

  ulong random_seed,
  float3 ambient_light,

  __global const float* objects,
  const uint num_objects,

  __global RGB * output)
{
  int id = get_global_id(0);

  const int x_pix = id % image_width;
  const int y_pix = id / image_width;

  float4 world_pos =
    vmult(view_to_world(eye, look, up),
    vmult(screen_to_view(image_width, image_height, fovy),
    (float4)(x_pix, y_pix, 1, 1)
  ));

  Ray ray;
  ray.origin = eye;
  ray.direction = normalize((world_pos / world_pos.w).xyz - eye);

  random_seed = random_seed * id * id;
  mwc64x_state_t rand_state = init_rand_state(random_seed);
  MWC64X_Skip(&rand_state, 20);

  output[id] = rgb(pathtrace(ray, 8, ambient_light, &rand_state, objects, num_objects));
}


sixtracklib/opencl: Bugfixes in NS(Track_particles_beam_elements_opencl) kernel function

- Fix an buffer overflow/overwrite issue in the generic tracking kernel.
  The error had been detected using the tests/sixtracklib/opencl/test_track_opencl_c99.cpp
  unit-test and has been caused by the particle_id < num_particles tests being, effectively,
  mot performed on the GPU due to the SIXTRL_ASSERT() macro there having noeffect.

  The bug has been fixed by introducing a proper run-time check that is always performed.
  STATUS: The bug seems to have been fixed, no more buffer overwrites occur

- The aggregation of success / error status flags into the global ptr_success_flag
  parameter was still performed using the unsafe bitwise or-assignment; while unlikely
  to result problems due to race-conditions, the kernels from
  sixtracklib/opencl/impl/track_particles_kernel.cl are now using the 32-bit atomic
  atomic_or() function.

  NOTE: sixtracklib thus depends on the availability of the cl_khr_int32_extended_atomics
        opencl extension!!!

#ifndef SIXTRACKLIB_OPENCL_IMPL_MANAGED_TRACK_PARTICLES_KERNEL_OPENCL_CL__
#define SIXTRACKLIB_OPENCL_IMPL_MANAGED_TRACK_PARTICLES_KERNEL_OPENCL_CL__

#if !defined( SIXTRL_NO_INCLUDES )
    #include "sixtracklib/_impl/definitions.h"
    #include "sixtracklib/common/impl/managed_buffer_minimal.h"
    #include "sixtracklib/common/impl/managed_buffer_remap.h"
    #include "sixtracklib/common/impl/particles_defines.h"
    #include "sixtracklib/common/particles.h"
    #include "sixtracklib/common/track.h"
#endif /* !defined( SIXTRL_NO_INCLUDES ) */

#pragma OPENCL_EXTENSION cl_khr_int32_extended_atomics

__kernel void NS(Remap_particles_beam_elements_buffers_opencl)(
    SIXTRL_BUFFER_DATAPTR_DEC unsigned char* SIXTRL_RESTRICT particles_buf,
    SIXTRL_BUFFER_DATAPTR_DEC unsigned char* SIXTRL_RESTRICT beam_elements_buf,
    SIXTRL_BUFFER_DATAPTR_DEC unsigned char* SIXTRL_RESTRICT ptr_success_flag )
{
    typedef NS(buffer_size_t) buf_size_t;

    size_t const global_id                     = get_global_id( 0 );
    size_t const global_size                   = get_global_size( 0 );

    size_t const gid_to_remap_particles_buffer     = ( size_t )0u;
    size_t const gid_to_remap_beam_elements_buffer = ( global_size > 1u )
        ? ( gid_to_remap_particles_buffer + 1u )
        : ( gid_to_remap_particles_buffer );

    if( global_id <= gid_to_remap_beam_elements_buffer )
    {
        buf_size_t const slot_size = ( buf_size_t )8u;
        long int success_flag = ( long int )0u;

        if( global_id == gid_to_remap_particles_buffer )
        {
            if( ( particles_buf != SIXTRL_NULLPTR ) &&
                ( beam_elements_buf != particles_buf ) )
            {
                if( 0 != NS(ManagedBuffer_remap)( particles_buf, slot_size ) )
                {
                    success_flag |= -2;
                }
            }
            else
            {
                success_flag |= -1;
            }
        }

        if( global_id == gid_to_remap_beam_elements_buffer )
        {
            if( ( beam_elements_buf != SIXTRL_NULLPTR ) &&
                ( particles_buf != beam_elements_buf ) )
            {
                if( 0 != NS(ManagedBuffer_remap)(
                        beam_elements_buf, slot_size ) )
                {
                    success_flag |= -4;
                }
            }
            else
            {
                success_flag |= -1;
            }
        }

        if( ( success_flag != 0 ) && ( ptr_success_flag != SIXTRL_NULLPTR ) )
        {

            atomic_or( ptr_success_flag, success_flag );
        }
    }

    return;
}

__kernel void NS(Track_particles_beam_elements_opencl)(
    SIXTRL_BUFFER_DATAPTR_DEC unsigned char* SIXTRL_RESTRICT particles_buf,
    SIXTRL_BUFFER_DATAPTR_DEC unsigned char* SIXTRL_RESTRICT beam_elements_buf,
    SIXTRL_UINT64_T const num_turns,
    SIXTRL_BUFFER_DATAPTR_DEC unsigned char* SIXTRL_RESTRICT ptr_success_flag )
{
    typedef NS(buffer_size_t) buf_size_t;
    typedef SIXTRL_BUFFER_OBJ_ARGPTR_DEC  NS(Object)*        obj_iter_t;
    typedef SIXTRL_BUFFER_OBJ_ARGPTR_DEC  NS(Object) const*  obj_const_iter_t;
    typedef SIXTRL_BUFFER_DATAPTR_DEC     NS(Particles)*     ptr_particles_t;

    long int success_flag      = ( long int )0u;
    buf_size_t const slot_size = ( buf_size_t )8u;

    if( ( !NS(ManagedBuffer_needs_remapping( particles_buf,     slot_size ) ) ) &&
        ( !NS(ManagedBuffer_needs_remapping( beam_elements_buf, slot_size ) ) ) )
    {
        size_t const stride             = get_local_size( 0 );
        size_t global_particle_id       = get_global_id( 0 );
        size_t object_begin_particle_id = ( size_t )0u;

        obj_iter_t part_block_it  = NS(ManagedBuffer_get_objects_index_begin)(
                particles_buf, slot_size );

        obj_iter_t part_block_end =
            NS(ManagedBuffer_get_objects_index_end)( particles_buf, slot_size );

        obj_const_iter_t be_begin =
            NS(ManagedBuffer_get_const_objects_index_begin)(
                beam_elements_buf, slot_size );

        obj_const_iter_t be_end   =
            NS(ManagedBuffer_get_const_objects_index_end)(
                beam_elements_buf, slot_size );

        for( ; part_block_it != part_block_end ; ++part_block_it )
        {
            ptr_particles_t particles = ( ptr_particles_t )(
                uintptr_t )NS(Object_get_begin_addr)( part_block_it );

            size_t const object_end_particle_id = object_begin_particle_id +
                NS(Particles_get_num_of_particles)( particles );

            SIXTRL_ASSERT( NS(Object_get_type_id)( part_block_it ) ==
                           NS(OBJECT_TYPE_PARTICLE) );

            if( ( global_particle_id <  object_end_particle_id   ) &&
                ( global_particle_id >= object_begin_particle_id ) )
            {
                size_t const particle_id =
                    global_particle_id - object_begin_particle_id;

                SIXTRL_UINT64_T turn = ( SIXTRL_UINT64_T )0u;

                SIXTRL_ASSERT( particle_id <
                    NS(Particles_get_num_of_particles)( particles ) );

                for( ; turn < num_turns ; ++turn )
                {
                    success_flag |= NS(Track_particle_beam_elements)(
                        particles, particle_id, be_begin, be_end );
                }
            }

            object_begin_particle_id = object_end_particle_id;
        }
    }
    else
    {
        if( NS(ManagedBuffer_needs_remapping( particles_buf, slot_size ) ) )
        {
            success_flag |= -2;
        }

        if( NS(ManagedBuffer_needs_remapping( beam_elements_buf, slot_size ) ) )
        {
            success_flag |= -4;
        }
    }

    if( ( success_flag != 0 ) && ( ptr_success_flag != SIXTRL_NULLPTR ) )
    {

        atomic_or( ptr_success_flag, success_flag );
    }

    return;
}

#endif /* SIXTRACKLIB_OPENCL_IMPL_MANAGED_TRACK_PARTICLES_KERNEL_OPENCL_CL__ */
/* end: sixtracklib/opencl/impl/track_particles_kernel.cl */

#ifndef SIXTRACKLIB_OPENCL_IMPL_MANAGED_TRACK_PARTICLES_KERNEL_OPENCL_CL__
#define SIXTRACKLIB_OPENCL_IMPL_MANAGED_TRACK_PARTICLES_KERNEL_OPENCL_CL__

#if !defined( SIXTRL_NO_INCLUDES )
    #include "sixtracklib/_impl/definitions.h"
    #include "sixtracklib/common/impl/managed_buffer_minimal.h"
    #include "sixtracklib/common/impl/managed_buffer_remap.h"
    #include "sixtracklib/common/impl/particles_defines.h"
    #include "sixtracklib/common/particles.h"
    #include "sixtracklib/common/track.h"
#endif /* !defined( SIXTRL_NO_INCLUDES ) */

__kernel void NS(Remap_particles_beam_elements_buffers_opencl)(
    SIXTRL_BUFFER_DATAPTR_DEC unsigned char* SIXTRL_RESTRICT particles_buf,
    SIXTRL_BUFFER_DATAPTR_DEC unsigned char* SIXTRL_RESTRICT beam_elements_buf,
    SIXTRL_BUFFER_DATAPTR_DEC unsigned char* SIXTRL_RESTRICT ptr_success_flag )
{
    typedef NS(buffer_size_t) buf_size_t;

    size_t const global_id                     = get_global_id( 0 );
    size_t const global_size                   = get_global_size( 0 );

    size_t const gid_to_remap_particles_buffer     = ( size_t )0u;
    size_t const gid_to_remap_beam_elements_buffer = ( global_size > 1u )
        ? ( gid_to_remap_particles_buffer + 1u )
        : ( gid_to_remap_particles_buffer );

    if( global_id <= gid_to_remap_beam_elements_buffer )
    {
        buf_size_t const slot_size = ( buf_size_t )8u;
        long int success_flag = ( long int )0u;

        if( global_id == gid_to_remap_particles_buffer )
        {
            if( ( particles_buf != SIXTRL_NULLPTR ) &&
                ( beam_elements_buf != particles_buf ) )
            {
                if( 0 != NS(ManagedBuffer_remap)( particles_buf, slot_size ) )
                {
                    success_flag |= -2;
                }
            }
            else
            {
                success_flag |= -1;
            }
        }

        if( global_id == gid_to_remap_beam_elements_buffer )
        {
            if( ( beam_elements_buf != SIXTRL_NULLPTR ) &&
                ( particles_buf != beam_elements_buf ) )
            {
                if( 0 != NS(ManagedBuffer_remap)(
                        beam_elements_buf, slot_size ) )
                {
                    success_flag |= -4;
                }
            }
            else
            {
                success_flag |= -1;
            }
        }

        if(  ptr_success_flag != SIXTRL_NULLPTR )
        {
            *ptr_success_flag  = success_flag;
        }
    }

    return;
}

__kernel void NS(Track_particles_beam_elements_opencl)(
    SIXTRL_BUFFER_DATAPTR_DEC unsigned char* SIXTRL_RESTRICT particles_buf,
    SIXTRL_BUFFER_DATAPTR_DEC unsigned char* SIXTRL_RESTRICT beam_elements_buf,
    SIXTRL_UINT64_T const num_turns,
    SIXTRL_BUFFER_DATAPTR_DEC unsigned char* SIXTRL_RESTRICT ptr_success_flag )
{
    typedef NS(buffer_size_t) buf_size_t;
    typedef SIXTRL_BUFFER_OBJ_ARGPTR_DEC  NS(Object)*        obj_iter_t;
    typedef SIXTRL_BUFFER_OBJ_ARGPTR_DEC  NS(Object) const*  obj_const_iter_t;
    typedef SIXTRL_BUFFER_DATAPTR_DEC     NS(Particles)*     ptr_particles_t;

    long int success_flag      = ( long int )0u;
    buf_size_t const slot_size = ( buf_size_t )8u;

    if( ( !NS(ManagedBuffer_needs_remapping( particles_buf,     slot_size ) ) ) &&
        ( !NS(ManagedBuffer_needs_remapping( beam_elements_buf, slot_size ) ) ) )
    {
        size_t const stride             = get_local_size( 0 );
        size_t global_particle_id       = get_global_id( 0 );
        size_t object_begin_particle_id = ( size_t )0u;

        obj_iter_t part_block_it  = NS(ManagedBuffer_get_objects_index_begin)(
                particles_buf, slot_size );

        obj_iter_t part_block_end =
            NS(ManagedBuffer_get_objects_index_end)( particles_buf, slot_size );

        obj_const_iter_t be_begin =
            NS(ManagedBuffer_get_const_objects_index_begin)(
                beam_elements_buf, slot_size );

        obj_const_iter_t be_end   =
            NS(ManagedBuffer_get_const_objects_index_end)(
                beam_elements_buf, slot_size );

        for( ; part_block_it != part_block_end ; ++part_block_it )
        {
            ptr_particles_t particles = ( ptr_particles_t )(
                uintptr_t )NS(Object_get_begin_addr)( part_block_it );

            size_t const object_end_particle_id = object_begin_particle_id +
                NS(Particles_get_num_of_particles)( particles );

            SIXTRL_ASSERT( NS(Object_get_type_id)( part_block_it ) ==
                           NS(OBJECT_TYPE_PARTICLE) );

            if( global_particle_id >= object_begin_particle_id )
            {
                size_t const particle_id =
                    global_particle_id - object_begin_particle_id;

                SIXTRL_UINT64_T turn = ( SIXTRL_UINT64_T )0u;

                SIXTRL_ASSERT( particle_id <
                    NS(Particles_get_num_of_particles)( particles ) );

                for( ; turn < num_turns ; ++turn )
                {
                    success_flag |= NS(Track_particle_beam_elements)(
                        particles, particle_id, be_begin, be_end );
                }
            }

            object_begin_particle_id = object_end_particle_id;
        }
    }
    else
    {
        if( NS(ManagedBuffer_needs_remapping( particles_buf, slot_size ) ) )
        {
            success_flag |= -2;
        }

        if( NS(ManagedBuffer_needs_remapping( beam_elements_buf, slot_size ) ) )
        {
            success_flag |= -4;
        }
    }

    if(  ptr_success_flag != SIXTRL_NULLPTR )
    {
        *ptr_success_flag |= success_flag;
    }

    return;
}

#endif /* SIXTRACKLIB_OPENCL_IMPL_MANAGED_TRACK_PARTICLES_KERNEL_OPENCL_CL__ */
/* end: sixtracklib/opencl/impl/track_particles_kernel.cl */


brackets

brackets

#include "kernel_header.h"

float3			get_abc(float radius, float3 ray, float3 origin)
{
	float3		abc;

	abc.x = dot_vect(ray, ray);
	abc.y = 2 * dot_vect(ray, origin);
	abc.z = dot_vect(origin, origin) - (radius * radius);
	return (abc);
}

float			inter_sphere(float radius, float3 ray, float3 cam_origin, float3 sphere_origin)
{
	float3		abc;
	float		d;
	float		res1;
	float		res2;

	cam_origin.x -= sphere_origin.x;
	cam_origin.y -= sphere_origin.y;
	cam_origin.z -= sphere_origin.z;
	abc = get_abc(radius, ray, cam_origin);
	d = (abc.y * abc.y) - (4 * (abc.x * abc.z));
	if (d < 0)
		return (1000000000);
	if (d == 0)
		return ((-abc[1]) / (2 * abc[0]));
	res1 = (((-abc[1]) + sqrt(d)) / (2 * abc[0]));
	res2 = (((-abc[1]) - sqrt(d)) / (2 * abc[0]));
	if ((res1 < res2 && res1 > 0) || (res1 > res2 && res2 < 0))
		return(res1);
	return(res2);
}

float			inter_plan(float3 plan_origin, float3 plan_normale, float3 ray, float3 cam_origin)
{
	float		t;

	t = dot_vect(ray, plan_normale);

	t = dot_vect(sub_vect(plan_origin, cam_origin), plan_normale) / t;
	if (t < 0.0000001)
		return (1000000000);
	return (t);
}

float3			get_ray(float3 n, float3 v, float3 h, int x, int y)
{
	float3		res;

	h = mult_fvect(modh_vect(x), h);
	v = mult_fvect(modv_vect(y), v);
	res = add_vect(n, v);
	res = add_vect(res, h);
	return (res);
}

__kernel void	ray_trace(__global char *output,
							float3 mvt,
							__constant t_object *scene)
{
	int		id = get_global_id(0);
	int		x = id % WINX;
	int		y = id / WINX;

	// CAM
	float3	cam_origin;
	cam_origin.x = 0 + mvt.x;
	cam_origin.y = 0 + mvt.y;
	cam_origin.z = -10 + mvt.z;
	float3	hor;
	hor.x = 0.6;
	hor.y = 0;
	hor.z = 0;
	float3	vert;
	vert.x = 0;
	vert.y = 0.6;
	vert.z = 0;
	float3	cam_dir;
	cam_dir.x = 0;
	cam_dir.y = 0;
	cam_dir.z = 1;

	// SPHERE
	float3	boule_origin;
	boule_origin.x = 0;
	boule_origin.y = 10;
	boule_origin.z = 200;
	float	radius = 10;

	// SPHERE2
	float3	boule_origin2;
	boule_origin2.x = 0;
	boule_origin2.y = -10;
	boule_origin2.z = 50;
	float	radius2 = 10;

	// PLANE
	float3	plan_origin;
	plan_origin.x = 0;
	plan_origin.y = 0;
	plan_origin.z = 300;
	float3	plan_normale;
	plan_normale.x = 0;
	plan_normale.y = -1;
	plan_normale.z = 0;

	float plan;
	float sphere;
	float sphere2;

	plan_origin = plan_origin + plan_normale;

	float3 ray = get_ray(cam_dir, vert, hor, x ,y);
	if (( plan = inter_plan(plan_origin, plan_normale, ray, cam_origin)) < 0)
		plan = 1000000000;
	if (( sphere= inter_sphere(radius, ray, cam_origin, boule_origin)) < 0)
		sphere = 1000000000;
	if ((sphere2 = inter_sphere(radius2, ray, cam_origin, boule_origin2)) < 0)
		sphere2 = 1000000000;
	if (sphere == 1000000000 && plan == 1000000000 && sphere2 == 1000000000)
		OUTPUTE = BACKCOLOR;
	else if (sphere < plan && sphere < sphere2)
		OUTPUTE = SCOLOR;
	else if (sphere2 < sphere && sphere2 < plan)
		OUTPUTE = SSCOLOR;
	else
		OUTPUTE = PCOLOR;
}

#include "kernel_header.h"

float3			get_abc(float radius, float3 ray, float3 origin)
{
	float3		abc;

	abc.x = dot_vect(ray, ray);
	abc.y = 2 * dot_vect(ray, origin);
	abc.z = dot_vect(origin, origin) - (radius * radius);
	return (abc);
}

float			inter_sphere(float radius, float3 ray, float3 cam_origin, float3 sphere_origin)
{
	float3		abc;
	float		d;
	float		res1;
	float		res2;

	cam_origin.x -= sphere_origin.x;
	cam_origin.y -= sphere_origin.y;
	cam_origin.z -= sphere_origin.z;
	abc = get_abc(radius, ray, cam_origin);
	d = (abc.y * abc.y) - (4 * (abc.x * abc.z));
	if (d < 0)
		return (1000000000);
	if (d == 0)
		return ((-abc[1]) / (2 * abc[0]));
	res1 = (((-abc[1]) + sqrt(d)) / (2 * abc[0]));
	res2 = (((-abc[1]) - sqrt(d)) / (2 * abc[0]));
	if (res1 < res2 && res1 > 0 || res1 > res2 && res2 < 0)
		return(res1);
	return(res2);
}

float			inter_plan(float3 plan_origin, float3 plan_normale, float3 ray, float3 cam_origin)
{
	float		t;

	t = dot_vect(ray, plan_normale);

	t = dot_vect(sub_vect(plan_origin, cam_origin), plan_normale) / t;
	if (t < 0.0000001)
		return (1000000000);
	return (t);
}

float3			get_ray(float3 n, float3 v, float3 h, int x, int y)
{
	float3		res;

	h = mult_fvect(modh_vect(x), h);
	v = mult_fvect(modv_vect(y), v);
	res = add_vect(n, v);
	res = add_vect(res, h);
	return (res);
}

__kernel void	ray_trace(__global char *output,
							float3 mvt,
							__constant t_object *scene)
{
	int		id = get_global_id(0);
	int		x = id % WINX;
	int		y = id / WINX;

	// CAM
	float3	cam_origin;
	cam_origin.x = 0 + mvt.x;
	cam_origin.y = 0 + mvt.y;
	cam_origin.z = -10 + mvt.z;
	float3	hor;
	hor.x = 0.6;
	hor.y = 0;
	hor.z = 0;
	float3	vert;
	vert.x = 0;
	vert.y = 0.6;
	vert.z = 0;
	float3	cam_dir;
	cam_dir.x = 0;
	cam_dir.y = 0;
	cam_dir.z = 1;

	// SPHERE
	float3	boule_origin;
	boule_origin.x = 0;
	boule_origin.y = 10;
	boule_origin.z = 200;
	float	radius = 10;

	// SPHERE2
	float3	boule_origin2;
	boule_origin2.x = 0;
	boule_origin2.y = -10;
	boule_origin2.z = 50;
	float	radius2 = 10;

	// PLANE
	float3	plan_origin;
	plan_origin.x = 0;
	plan_origin.y = 0;
	plan_origin.z = 300;
	float3	plan_normale;
	plan_normale.x = 0;
	plan_normale.y = -1;
	plan_normale.z = 0;

	float plan;
	float sphere;
	float sphere2;

	plan_origin = plan_origin + plan_normale;

	float3 ray = get_ray(cam_dir, vert, hor, x ,y);
	if (( plan = inter_plan(plan_origin, plan_normale, ray, cam_origin)) < 0)
		plan = 1000000000;
	if (( sphere= inter_sphere(radius, ray, cam_origin, boule_origin)) < 0)
		sphere = 1000000000;
	if ((sphere2 = inter_sphere(radius2, ray, cam_origin, boule_origin2)) < 0)
		sphere2 = 1000000000;
	if (sphere == 1000000000 && plan == 1000000000 && sphere2 == 1000000000)
		OUTPUTE = BACKCOLOR;
	else if (sphere < plan && sphere < sphere2)
		OUTPUTE = SCOLOR;
	else if (sphere2 < sphere && sphere2 < plan)
		OUTPUTE = SSCOLOR;
	else
		OUTPUTE = PCOLOR;
}


work_group_reduction_sum now returns the total sum to all work-items instead of only the first.

#ifndef ACCUMULATOR
    #define ACCUMULATOR double
#endif

#ifndef WGS
    #define WGS 256
#endif

// ================= Sum reduction =============================================

inline ACCUMULATOR work_group_reduction_sum (const ACCUMULATOR value) {

    uint local_id = get_local_id(0);

    __local ACCUMULATOR lacc[WGS];
    lacc[local_id] = value;

    work_group_barrier(CLK_LOCAL_MEM_FENCE);

    ACCUMULATOR pacc = value;
    uint i = get_local_size(0);
    while (i > 0) {
        bool include_odd = (i > ((i >> 1) << 1)) && (local_id == ((i >> 1) - 1));
        i >>= 1;
        if (include_odd) {
            pacc += lacc[local_id + i + 1];
        }
        if (local_id < i) {
            pacc += lacc[local_id + i];
            lacc[local_id] = pacc;
        }
        work_group_barrier(CLK_LOCAL_MEM_FENCE);
    }

    return lacc[0];
}

#ifndef ACCUMULATOR
    #define ACCUMULATOR double
#endif

#ifndef WGS
    #define WGS 256
#endif

// ================= Sum reduction =============================================

inline ACCUMULATOR work_group_reduction_sum (const ACCUMULATOR value) {

    uint local_id = get_local_id(0);

    __local ACCUMULATOR lacc[WGS];
    lacc[local_id] = value;

    work_group_barrier(CLK_LOCAL_MEM_FENCE);

    ACCUMULATOR pacc = value;
    uint i = get_local_size(0);
    while (i > 0) {
        bool include_odd = (i > ((i >> 1) << 1)) && (local_id == ((i >> 1) - 1));
        i >>= 1;
        if (include_odd) {
            pacc += lacc[local_id + i + 1];
        }
        if (local_id < i) {
            pacc += lacc[local_id + i];
            lacc[local_id] = pacc;
        }
        work_group_barrier(CLK_LOCAL_MEM_FENCE);
    }

    return pacc;
}