xgpui-apple 5.0.0

Apple rendering and platform services for xgpui
Documentation
#include <metal_stdlib>
using namespace metal;
struct Params { float4 bounds; float4 mask; float4 radii; float4 viewport; float4 color_r; float4 color_g; float4 color_b; float4 vignette; float4 linear; };
struct Vertex { float4 position [[position]]; float2 uv; };
vertex Vertex gamut_vertex(uint id [[vertex_id]], constant Params &p [[buffer(0)]]) {
    const float2 v[] = {{0,0},{1,0},{0,1},{0,1},{1,0},{1,1}};
    float2 uv = v[id], xy = p.bounds.xy + uv*p.bounds.zw;
    return {float4(xy.x/p.viewport.x*2-1, 1-xy.y/p.viewport.y*2,0,1),uv};
}
float3 decode_srgb(float3 c) {
    return select(c/12.92, pow(max((c+0.055)/1.055,0.0),float3(2.4)), c>0.04045);
}
float3 encode_srgb(float3 c) {
    c = clamp(c,0.0,1.0);
    return select(c*12.92, 1.055*pow(c,float3(1.0/2.4))-0.055, c>0.0031308);
}
float3 srgb_to_p3(float3 c) {
    return float3(dot(c,float3(.822461969,.177538031,0)),
                  dot(c,float3(.033194199,.966805801,0)),
                  dot(c,float3(.017082631,.072397441,.910519929)));
}
float3 p3_to_srgb(float3 c) {
    return float3(dot(c,float3(1.224940176,-.224940176,0)),
                  dot(c,float3(-.042056955,1.042056955,0)),
                  dot(c,float3(-.019637555,-.078636046,1.098273600)));
}
float3 rec2020_to_p3(float3 c) {
    return float3(dot(c,float3(1.343578253,-0.282179671,-0.061398582)),dot(c,float3(-0.065297453,1.075787916,-0.010490463)),dot(c,float3(0.002821787,-0.019598495,1.016776707)));
}
fragment float4 gamut_fragment(Vertex in [[stage_in]], constant Params &p [[buffer(0)]],
 texture2d<float> image [[texture(0)]], texture2d<float> mask [[texture(1)]]) {
    float2 xy=in.position.xy;
    if(any(xy<p.mask.xy)||any(xy>=p.mask.xy+p.mask.zw)) discard_fragment();
    constexpr sampler s(coord::normalized,address::clamp_to_edge,filter::linear,mip_filter::linear);
    float4 c;
    if(p.viewport.w > .5) { // Legacy scratch: exact texel read, associated encoded sRGB.
        c=image.read(uint2(xy));
        c.rgb=c.a>0 ? srgb_to_p3(decode_srgb(c.rgb/c.a))*c.a : float3(0);
    } else { // Explicit private wide contract: associated linear P3.
        c=image.sample(s,in.uv);
        if (p.linear.z > .5) c.rgb=rec2020_to_p3(c.rgb);
        if (p.linear.x > .5) {
            float3 rgb=c.a>0 ? c.rgb/c.a : float3(0);
            if (p.linear.y < .5) rgb=p3_to_srgb(rgb);
            float4 v=float4(rgb,1);
            rgb=float3(dot(p.color_r,v),dot(p.color_g,v),dot(p.color_b,v));
            float2 dims=float2(image.get_width(),image.get_height());
            float2 q=in.uv*2.-1.;
            float d=mix(length(q),length(q*dims/min(dims.x,dims.y)),p.vignette.w);
            float t=clamp((d-p.vignette.y)/p.vignette.z,0.,1.);
            rgb*=1.-p.vignette.x*t*t*(3.-2.*t);
            if (p.linear.y < .5) rgb=srgb_to_p3(rgb);
            c.rgb=rgb*c.a; // Extended linear SDR; map only at final preview/presentation.
        }
    }
    float2 local=in.uv*p.bounds.zw;
    bool right=local.x>p.bounds.z*.5, bottom=local.y>p.bounds.w*.5;
    float r=bottom?(right?p.radii.z:p.radii.w):(right?p.radii.y:p.radii.x);
    float2 q=abs(local-p.bounds.zw*.5)-p.bounds.zw*.5+r;
    float d=length(max(q,float2(0)))+min(max(q.x,q.y),0.0)-r;
    float coverage=clamp(.5-d,0.0,1.0);
    if(p.viewport.w < -.5) coverage=mask.sample(s,in.uv).r;
    return c*(coverage*p.viewport.z);
}
// Explicit clipped sRGB preview/readback, never a wide-gamut export.
fragment float4 gamut_preview(Vertex in [[stage_in]], texture2d<float> image [[texture(0)]]) {
    float4 c=image.read(uint2(in.position.xy));
    float3 rgb=c.a>0 ? encode_srgb(p3_to_srgb(c.rgb/c.a))*c.a : float3(0);
    return float4(rgb,c.a);
}