yum-mirror/slang

Making it easier to work with shaders

git clone https://git.yummers.dev/yum-mirror/slang

kaizhangNVMigrate 3 more examples to slang-unit-test (#4927)efda04f3c

master
6.2 KiB193 linesraw
1// texture.slang
2
3// This class encapsulates a differentiable texture object that uses
4// hardware sampling for the primal version, but substitutes a reference
5// interpolation implementation to generate backward pass.
6//
7// This specific implementation also makes the choice to use fast fixed point
8// atomics to accumulate the derivative (suitable for this example, but maybe
9// not in general)
10//
11struct DifferentiableTexture
12{
13    RWStructuredBuffer<int> accumulateBuffer; // Per-mip-level accumulate buffer
14    Texture2D texture;                        // Hardware texture handle.
15    float minLOD;
16
17    [BackwardDerivative(bwd_LoadTexel)]
18    float4 LoadTexel(int3 location, constexpr int2 offset, uint dLayerW, uint dMipOffset)
19    {
20        return texture.Load(location, offset);
21    }
22
23    void bwd_LoadTexel(int3 location, constexpr int2 offset, uint dLayerW, uint dMipOffset, float4 val)
24    {
25        // Ignore alpha dimension for this example..
26        int4 uval = int4(int3(val.xyz * 65536), 1);
27
28        // We'll use fast fixed point atomics instead of floats.
29        InterlockedAdd(accumulateBuffer[dMipOffset + ((uint)location.y * dLayerW + (uint)location.x) * 4 + 0], uval.x);
30        InterlockedAdd(accumulateBuffer[dMipOffset + ((uint)location.y * dLayerW + (uint)location.x) * 4 + 1], uval.y);
31        InterlockedAdd(accumulateBuffer[dMipOffset + ((uint)location.y * dLayerW + (uint)location.x) * 4 + 2], uval.z);
32        InterlockedAdd(accumulateBuffer[dMipOffset + ((uint)location.y * dLayerW + (uint)location.x) * 4 + 3], uval.w);
33    }
34
35    // Software reference implementation of linear filtering.
36    [BackwardDifferentiable]
37    float4 sampleTexture_linear(uint lod, float2 uv, uint w, uint h)
38    {
39        w >>= lod;
40        h >>= lod;
41        uv = uv - no_diff(floor(uv));
42        float2 loc = uv * float2(w, h) - float2(0.5);
43        float x0 = no_diff(floor(loc.x));
44        float y0 = no_diff(floor(loc.y));
45        float fracX = loc.x - x0;
46        float fracY = loc.y - y0;
47        float x1 = x0 + 1;
48        float y1 = y0 + 1;
49        if (x0 < 0) x0 += w;
50        if (y0 < 0) y0 += h;
51        if (x1 >= w) x1 -= w;
52        if (y1 >= h) y1 -= h;
53        float weight0 = 1.0f - fracY;
54        float weight1 = fracY;
55        float weight00 = weight0 * (1.0f - fracX);
56        float weight01 = weight0 * fracX;
57        float weight10 = weight1 * (1.0f - fracX);
58        float weight11 = weight1 * fracX;
59
60        uint dLayerW = w >>= lod;
61        var offset = mipOffset[lod / 4][lod % 4];
62        return LoadTexel(int3(int(x0), int(y0), int(lod)), int2(0), dLayerW, offset) * weight00 +
63               LoadTexel(int3(int(x1), int(y0), int(lod)), int2(0), dLayerW, offset) * weight01 +
64               LoadTexel(int3(int(x0), int(y1), int(lod)), int2(0), dLayerW, offset) * weight10 +
65               LoadTexel(int3(int(x1), int(y1), int(lod)), int2(0), dLayerW, offset) * weight11;
66    }
67
68    // Software reference implementation of trilinear filtering.
69    [BackwardDifferentiable]
70    float4 sampleTexture_trilinear(uint w, uint h, uint levels, float2 uv, float2 dX, float2 dY)
71    {
72        dX = dX * float2(w, h);
73        dY = dY * float2(w, h);
74
75        // Isotropic filter.
76        float lengthX = length(dX);
77        float lengthY = length(dY);
78        float LOD = log2(max(lengthX, lengthY));
79        float maxLOD = levels - 1;
80        float clampedLOD = max(minLOD, (min(maxLOD, LOD)));
81
82        float lodFrac = clampedLOD - no_diff(floor(clampedLOD));
83        uint lod0 = (uint)floor(clampedLOD);
84        uint lod1 = min(levels - 1, lod0 + 1);
85        float weightLod0 = 1.0 - lodFrac;
86        float weightLod1 = lodFrac;
87
88        let v0 = sampleTexture_linear(lod0, uv, w, h) * weightLod0;
89        let v1 = sampleTexture_linear(lod1, uv, w, h) * weightLod1;
90        return v0 + v1;
91    }
92
93    // Note that there is no need to mark this [BackwardDifferentiable] since it has a substitute
94    // that is marked [BackwardDifferentiable]. The compiler automatically considers a call to
95    // sample() to be differentiable.
96    //
97    static float4 sample(DifferentiableTexture t, SamplerState s, float2 uv, float2 dX, float2 dY)
98    {
99        return t.texture.Sample(s, uv);
100    }
101
102    // Software reference implementation of DifferentiableTexture.sample (trilinear only in this example)
103    [PrimalSubstituteOf(DifferentiableTexture.sample)]
104    [BackwardDifferentiable]
105    static float4 sample_reference_impl(DifferentiableTexture t, SamplerState s, float2 uv, float2 dX, float2 dY)
106    {
107        uint w;
108        uint h;
109        uint levels;
110        t.texture.GetDimensions(0, w, h, levels);
111        return t.sampleTexture_trilinear(w, h, levels, uv, dX, dY);
112    }
113}
114
115cbuffer Uniforms
116{
117    float4x4 modelViewProjection;
118    uint4 mipOffset[16];
119
120    Texture2D texRef;
121    SamplerState sampler;
122    DifferentiableTexture bwdTexture;
123}
124
125struct AssembledVertex
126{
127    float3	position : POSITION;
128};
129
130struct Fragment
131{
132    float4 color;
133};
134
135struct VertexStageOutput
136{
137    float2 uv : UV;
138    float4          sv_position     : SV_Position;
139};
140
141[BackwardDifferentiable]
142float4 shadeFragment(float2 uv)
143{
144    uv = uv * 2;
145
146    // Compute fragment differentials using shader intrinsics.
147    float2 dX = no_diff ddx_coarse(uv);
148    float2 dY = no_diff ddy_coarse(uv);
149
150    float3 color = DifferentiableTexture.sample(bwdTexture, sampler, uv, dX, dY).xyz;
151    return float4(color, 1.0);
152}
153
154[BackwardDifferentiable]
155float3 loss(no_diff float2 uv, no_diff float4 screenPos)
156{
157    float3 refColor = (no_diff texRef.Load(int3(int2(screenPos.xy), 0))).xyz;
158    float3 rs = shadeFragment(uv).xyz - refColor;
159    rs *= rs;
160    return rs;
161}
162
163[shader("vertex")]
164VertexStageOutput vertexMain(
165    AssembledVertex assembledVertex)
166{
167    VertexStageOutput output;
168
169    float3 position = assembledVertex.position;
170
171    output.uv = position.xy;
172    output.sv_position = mul(modelViewProjection, float4(position, 1.0));
173
174    return output;
175}
176
177float3 sqr(float3 v) { return v * v; }
178
179[shader("fragment")]
180float4 fragmentMain(
181    float2 uv : UV) : SV_Target
182{
183    return shadeFragment(uv);
184}
185
186[shader("fragment")]
187float4 diffFragmentMain(
188    float2 uv : UV,
189    float4 screenPos : SV_POSITION) : SV_Target
190{
191    __bwd_diff(loss)(uv, screenPos, float3(1.0));
192    return float4(loss(uv, screenPos), 1.0);
193}