feat: add d4r inference engines and Windows parity tooling
Add native K/M/RR inference engines, HIP kernels, replay and validation harnesses, and Windows DLSS setup and runtime support. Include GPU profiling tools, build and packaging scripts, platform integration patches, and implementation documentation.
This commit is contained in:
1 parent
25493b3198
commit
7c5d3c9157
430 files changed
+76191
No files matched your search
@@ -0,0 +1,298 @@
|
||||
#version 460
|
||||
#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require
|
||||
#extension GL_EXT_shader_explicit_arithmetic_types_int16 : require
|
||||
#extension GL_EXT_shader_16bit_storage : require
|
||||
|
||||
// Ray Reconstruction hkpn output stage, preset E (no diamond-wallaby branch).
|
||||
// One workgroup per 16x16 output tile. Stage 1 stages the render-space neighbourhood of
|
||||
// the tile into shared memory (colour log, per-texel weights, anisotropy); stage 2 gathers
|
||||
// a 5x5 elliptical kernel per output pixel and writes the two output surfaces.
|
||||
// Parameter block (binding 0) holds NVIDIA's kernel argument block; word index = byte / 4.
|
||||
|
||||
layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
|
||||
|
||||
layout(std430, binding = 0) readonly buffer Params { uint P[]; };
|
||||
layout(std430, binding = 2) buffer Arena { uint A[]; };
|
||||
layout(binding = 3) uniform sampler2D colourTex; // arg 176, 640x360 rgba16f
|
||||
layout(binding = 5) uniform sampler2D exposureTex; // arg 200, 1x1 rgba16f
|
||||
layout(binding = 8) uniform sampler2D albedoA; // arg 280, 640x360 rgba8unorm
|
||||
layout(binding = 9) uniform sampler2D albedoB; // arg 288, 640x360 rgba8unorm
|
||||
layout(binding = 11) uniform sampler2D decTex; // arg 448, 640x384 rgba16f
|
||||
layout(rgba16f, binding = 12) uniform writeonly image2D outLog; // arg 224
|
||||
layout(rgba16f, binding = 13) uniform writeonly image2D outLin; // arg 240
|
||||
|
||||
#define F_LOG2E uintBitsToFloat(0x3FB8AA3Bu)
|
||||
#define F_2LOG2E uintBitsToFloat(0x4038AA3Bu)
|
||||
#define F_LOG10_2 uintBitsToFloat(0x3E9A209Bu)
|
||||
#define F_0_36 uintBitsToFloat(0x3EB851ECu)
|
||||
#define F_100 uintBitsToFloat(0x42C80000u)
|
||||
#define F_1E4 uintBitsToFloat(0x38D1B717u)
|
||||
#define F_0_005 uintBitsToFloat(0x3BA3D70Au)
|
||||
#define F_0_1 uintBitsToFloat(0x3DCCCCCDu)
|
||||
#define F_1_7 uintBitsToFloat(0x3FD9999Au)
|
||||
#define F_0_17 uintBitsToFloat(0x3E2E147Bu)
|
||||
#define F_0_95 uintBitsToFloat(0x3F733333u)
|
||||
#define F_0_6 uintBitsToFloat(0x3F19999Au)
|
||||
#define F_9 uintBitsToFloat(0x41102CB4u)
|
||||
|
||||
// shared tile: 21 entries per row, up to 21x21 entries (render scale <= 1)
|
||||
#define TILE_STRIDE 21
|
||||
// binary16 numbers, stored as such: half the shared-memory traffic of the 5x5 gather
|
||||
shared f16vec4 tLog[TILE_STRIDE * TILE_STRIDE]; // (L_R, L_G, L_B, alpha = 0) log-domain colour
|
||||
shared f16vec4 tSig[TILE_STRIDE * TILE_STRIDE]; // (s0, s1, s2, s3) sigmoid of arena bytes 0..3
|
||||
shared vec4 tAn[TILE_STRIDE * TILE_STRIDE]; // (p0, p1, p2, p3) anisotropy parameters
|
||||
|
||||
float pf(uint idx) { return uintBitsToFloat(P[idx]); }
|
||||
|
||||
// e4m3 byte -> float (exact); e4m3fn NaN for 0x7F/0xFF.
|
||||
float e4m3(uint b) {
|
||||
uint e = (b >> 3u) & 15u;
|
||||
uint m = b & 7u;
|
||||
if (e == 15u && m == 7u) return uintBitsToFloat(0x7FC00000u);
|
||||
float v = (e == 0u) ? float(m) * uintBitsToFloat(0x3B000000u)
|
||||
: (1.0 + float(m) * 0.125) * exp2(float(e) - 7.0);
|
||||
return ((b & 128u) != 0u) ? -v : v;
|
||||
}
|
||||
|
||||
// round to nearest even binary16, returned as f32: the hardware conversion (RNE), kept from being folded back to x by
|
||||
// OR-ing an opaque zero into its bits (RADV folds a register-only f32 -> f16 -> f32)
|
||||
// Beyond the binary16 range NVIDIA's arithmetic keeps a finite rounded value: that case takes the explicit rounding.
|
||||
uint16_t zero16;
|
||||
float f16rnSlow(float x) {
|
||||
if (x == 0.0 || isnan(x) || isinf(x)) return x;
|
||||
int e;
|
||||
frexp(x, e);
|
||||
int ee = max(e - 11, -24);
|
||||
float q = uintBitsToFloat(uint(ee + 127) << 23);
|
||||
return roundEven(x / q) * q;
|
||||
}
|
||||
float f16rn(float x) {
|
||||
if (abs(x) >= 65504.0) return f16rnSlow(x);
|
||||
return float(uint16BitsToFloat16(float16BitsToUint16(float16_t(x)) | zero16));
|
||||
}
|
||||
|
||||
// Sigmoid as evaluated in binary16 on this lowering: r = f16(2^(-x*log2e)), den = f16(1+r),
|
||||
// s = f16(1/den), with one Newton step for small s and the observed fix-ups of r.
|
||||
float sig16(float e) {
|
||||
float x = f16rn(e);
|
||||
float r = f16rn(exp2(-x * F_LOG2E));
|
||||
uint hb = uint(float16BitsToUint16(float16_t(r)));
|
||||
if (hb == 0x1F79u || hb == 0x25CFu) {
|
||||
r = f16rn(r - 0.0009765625);
|
||||
} else if (hb == 0xC13Bu) {
|
||||
r = f16rn(r + 0.00006103515625);
|
||||
} else if (hb == 0xC1EFu) {
|
||||
r = f16rn(r + 0.000030517578125);
|
||||
}
|
||||
float d32 = f16rn(1.0 + r);
|
||||
float rc = 1.0 / d32;
|
||||
float s16 = f16rn(rc);
|
||||
uint sb = uint(float16BitsToUint16(float16_t(s16))) & 0x7FFFu;
|
||||
if (sb != 0u && sb < 0x8Fu) {
|
||||
float ee = fma(-d32, s16, 1.0);
|
||||
s16 = f16rn(fma(rc, ee, s16));
|
||||
}
|
||||
return s16;
|
||||
}
|
||||
|
||||
// tanh as evaluated: polynomial for small |x|, exponential form otherwise.
|
||||
float tanhApprox(float x) {
|
||||
float ax = abs(x);
|
||||
float x2 = x * x;
|
||||
float q = fma(uintBitsToFloat(0x3C80F082u), x2, uintBitsToFloat(0xBD563CAEu));
|
||||
q = fma(q, x2, uintBitsToFloat(0x3E085941u));
|
||||
q = fma(q, x2, uintBitsToFloat(0xBEAAA9EDu));
|
||||
q = fma(q, x2, 0.0);
|
||||
float small = fma(q, x, x);
|
||||
float ex = exp2(ax * F_2LOG2E);
|
||||
float big = fma(1.0 / (ex + 1.0), -2.0, 1.0);
|
||||
if (ax >= F_9) big = 1.0;
|
||||
float bigSigned = uintBitsToFloat((floatBitsToUint(x) & 0x80000000u) | floatBitsToUint(big));
|
||||
return (ax >= F_0_6) ? bigSigned : small;
|
||||
}
|
||||
|
||||
// round half away from zero
|
||||
int roundAway(float v) {
|
||||
return int(trunc(v + ((v < 0.0) ? -0.5 : 0.5)));
|
||||
}
|
||||
|
||||
void main() {
|
||||
zero16 = uint16_t(P[0] >> 24u); // the output width is below 2^24
|
||||
// ---- parameters (byte offsets / 4) ----
|
||||
uint outW = P[0];
|
||||
uint outH = P[1];
|
||||
float sx = pf(6u); // 24: render/out scale x
|
||||
float sy = pf(7u); // 28
|
||||
float ox = pf(10u); // 40: jitter offset x
|
||||
float oy = pf(11u); // 44
|
||||
float expScale = pf(37u); // 148
|
||||
uint decMaxX = P[14] - 1u; // 56: dec0 width
|
||||
uint decMaxY = P[15] - 1u; // 60: dec0 height
|
||||
uint colMaxX = P[35]; // 140: colour/albedo max x
|
||||
uint colMaxY = P[36]; // 144: colour/albedo max y
|
||||
uint arenaBase = P[64]; // 256: arena offset
|
||||
uint arenaPitch = P[4]; // 16: render width (640)
|
||||
|
||||
// ---- tile origin / size in render space ----
|
||||
uvec2 wg = gl_WorkGroupID.xy;
|
||||
float tileX = ox + fma(float(wg.x * 16u) + 0.5, sx, -0.5);
|
||||
float tileY = oy + fma(float(wg.y * 16u) + 0.5, sy, -0.5);
|
||||
int c0 = int(floor(tileX)) - 2;
|
||||
int r0 = int(floor(tileY)) - 2;
|
||||
int tw = int(ceil(16.0 * sx)) + 5;
|
||||
int th = int(ceil(16.0 * sy)) + 5;
|
||||
|
||||
// ---- stage 1: tile load ----
|
||||
uint total = uint(tw * th);
|
||||
for (uint idx = gl_LocalInvocationIndex; idx < total; idx += 256u) {
|
||||
int col = int(idx) % tw;
|
||||
int row = int(idx) / tw;
|
||||
int ix = clamp(c0 + col, 0, int(decMaxX));
|
||||
int iy = clamp(r0 + row, 0, int(decMaxY));
|
||||
|
||||
vec3 d = texelFetch(decTex, ivec2(ix, iy), 0).rgb;
|
||||
int ax = min(ix, int(colMaxX));
|
||||
int ay = min(iy, int(colMaxY));
|
||||
vec3 alb = texelFetch(albedoA, ivec2(ax, ay), 0).rgb
|
||||
+ texelFetch(albedoB, ivec2(ax, ay), 0).rgb;
|
||||
float albSum = (alb.r + alb.g) + alb.b;
|
||||
if (albSum != 0.0) {
|
||||
d.r *= max(alb.r, F_0_005);
|
||||
d.g *= max(alb.g, F_0_005);
|
||||
d.b *= max(alb.b, F_0_005);
|
||||
}
|
||||
vec3 lg;
|
||||
lg.r = f16rn(F_0_36 * (log2(max(fma(d.r, F_100, 1.0), F_1E4)) * F_LOG10_2));
|
||||
lg.g = f16rn(F_0_36 * (log2(max(fma(d.g, F_100, 1.0), F_1E4)) * F_LOG10_2));
|
||||
lg.b = f16rn(F_0_36 * (log2(max(fma(d.b, F_100, 1.0), F_1E4)) * F_LOG10_2));
|
||||
|
||||
uint wordIdx = (arenaBase >> 2u) + uint(arenaPitch * uint(iy) + uint(ix)) * 2u;
|
||||
uint lo = A[wordIdx];
|
||||
uint hi = A[wordIdx + 1u];
|
||||
vec4 sg = vec4(sig16(e4m3(lo & 0xFFu)),
|
||||
sig16(e4m3((lo >> 8u) & 0xFFu)),
|
||||
sig16(e4m3((lo >> 16u) & 0xFFu)),
|
||||
sig16(e4m3(lo >> 24u)));
|
||||
vec4 an = vec4(e4m3(hi & 0xFFu),
|
||||
e4m3((hi >> 8u) & 0xFFu),
|
||||
e4m3((hi >> 16u) & 0xFFu),
|
||||
e4m3(hi >> 24u));
|
||||
|
||||
uint se = uint(row * TILE_STRIDE + col);
|
||||
tLog[se] = f16vec4(lg, 0.0);
|
||||
tSig[se] = f16vec4(sg);
|
||||
tAn[se] = an;
|
||||
}
|
||||
barrier();
|
||||
|
||||
// ---- stage 2: per output pixel ----
|
||||
uvec2 pix = gl_GlobalInvocationID.xy;
|
||||
if (pix.x >= outW || pix.y >= outH) return;
|
||||
|
||||
float expo = texelFetch(exposureTex, ivec2(0, 0), 0).r;
|
||||
float e41 = ((expo == 0.0) ? 1.0 : expo) * expScale;
|
||||
|
||||
float fx = (float(pix.x) + 0.5) * sx;
|
||||
float fy = (float(pix.y) + 0.5) * sy;
|
||||
float cx = fx + ox;
|
||||
float cy = fy + oy;
|
||||
|
||||
// colour fetch: log of exposure-scaled colour at the nearest render texel
|
||||
int ux = clamp(roundAway((fx - 0.5) + ox), 0, int(colMaxX));
|
||||
int uy = clamp(roundAway((fy - 0.5) + oy), 0, int(colMaxY));
|
||||
vec3 col = texelFetch(colourTex, ivec2(ux, uy), 0).rgb;
|
||||
vec3 gcol;
|
||||
gcol.r = F_0_36 * (log2(max(fma(col.r * e41, F_100, 1.0), F_1E4)) * F_LOG10_2);
|
||||
gcol.g = F_0_36 * (log2(max(fma(col.g * e41, F_100, 1.0), F_1E4)) * F_LOG10_2);
|
||||
gcol.b = F_0_36 * (log2(max(fma(col.b * e41, F_100, 1.0), F_1E4)) * F_LOG10_2);
|
||||
|
||||
// centre entry, anisotropy
|
||||
float flx = floor(cx);
|
||||
float fly = floor(cy);
|
||||
int ix0 = int(flx) - c0;
|
||||
int iy0 = int(fly) - r0;
|
||||
float dx0 = (flx + 0.5) - cx;
|
||||
float dy0 = (fly + 0.5) - cy;
|
||||
float ks = (sy >= 0.5) ? 1.0 : (0.5 / sy);
|
||||
|
||||
vec4 an = tAn[iy0 * TILE_STRIDE + ix0];
|
||||
float sa = fma(1.0 / (1.0 + exp2(-F_LOG2E * an.x)), F_1_7, F_0_17);
|
||||
float sb = fma(1.0 / (1.0 + exp2(-F_LOG2E * an.y)), F_1_7, F_0_17);
|
||||
float rho = F_0_95 * tanhApprox(an.z);
|
||||
|
||||
float sa2 = sa * sa;
|
||||
float sb2 = sb * sb;
|
||||
float denom = (sa2 * sb2) * (1.0 - rho * rho);
|
||||
float invDenom = -(1.0 / denom);
|
||||
float cross2 = rho * (2.0 * sqrt(sa2 * sb2));
|
||||
|
||||
// 5x5 gather
|
||||
float sumw = 0.0;
|
||||
vec3 accL = vec3(0.0);
|
||||
vec4 accS = vec4(0.0);
|
||||
for (int c = -2; c <= 2; c++) {
|
||||
for (int r = -2; r <= 2; r++) {
|
||||
float dx = ks * (dx0 + float(c));
|
||||
float dy = ks * (dy0 + float(r));
|
||||
uint se = uint((iy0 + r) * TILE_STRIDE + (ix0 + c));
|
||||
precise float t_c = (cross2 * dx) * dy;
|
||||
precise float t_b = dx * (sb2 * dx);
|
||||
precise float t_a = dy * (sa2 * dy);
|
||||
precise float num = (t_c - t_b) - t_a;
|
||||
precise float Q = invDenom * num;
|
||||
float w = exp2((Q * -0.5) * F_LOG2E);
|
||||
sumw += w;
|
||||
vec4 lv = vec4(tLog[se]);
|
||||
vec4 sv = vec4(tSig[se]);
|
||||
accL = fma(vec3(w), lv.rgb, accL);
|
||||
accS = fma(vec4(w), sv, accS);
|
||||
}
|
||||
}
|
||||
|
||||
float inv = 1.0 / sumw;
|
||||
vec3 Lm = accL * inv;
|
||||
float S0 = accS.x * inv;
|
||||
float S1 = accS.y * inv;
|
||||
float S2 = accS.z * inv;
|
||||
|
||||
// blend weight
|
||||
float q = F_0_1 / (sx * sy);
|
||||
float t1 = sumw * q;
|
||||
float t2 = S0 * t1;
|
||||
float t3 = (sx * sy) * t2;
|
||||
float t4 = 4.0 * t3;
|
||||
float t5 = (sy < 0.5) ? t4 : t2;
|
||||
float wgt = (t5 < 0.0) ? 0.0 : ((t5 > 1.0) ? 1.0 : t5);
|
||||
|
||||
float fA = fma(1.0 - S1, wgt, S1);
|
||||
float fB = fma(1.0 - S2, wgt, S2);
|
||||
|
||||
// surface 224 (E): fA * D + (1 - fA) * gcol; D = Lm (f16 tile log channels),
|
||||
// gcol = log of the exposure-scaled colour texel (PTX linear texel fetch path); D.a = 0 so aA = 1 - fA
|
||||
vec3 cA = fma(Lm, vec3(fA), gcol * (1.0 - fA));
|
||||
float aA = 1.0 - fA;
|
||||
float sumA = cA.r + cA.g + cA.b + aA;
|
||||
if (isnan(sumA) || isinf(sumA)) {
|
||||
cA = Lm;
|
||||
aA = 0.0;
|
||||
}
|
||||
imageStore(outLog, ivec2(pix), vec4(f16rn(cA.r), f16rn(cA.g), f16rn(cA.b), f16rn(aA)));
|
||||
|
||||
// surface 240 (E, PTX BB0_83): {R,G,B,1} of lin = (10^(clamp(c)/0.36)-1)/100/e41,
|
||||
// c = fma(Lm, fB, gcol*(1-fB)); c = Lm when the sum is not finite; stored RNE f16
|
||||
vec3 cB = fma(Lm, vec3(fB), gcol * (1.0 - fB));
|
||||
float sumB = cB.r + cB.g + cB.b;
|
||||
if (isnan(sumB) || isinf(sumB)) cB = Lm;
|
||||
cB = clamp(cB, vec3(F_1E4), vec3(3.0));
|
||||
// PTX divides by constants and takes lg2(10) with the hardware approximations at run time; keep the
|
||||
// constants opaque so the compiler cannot fold them with different rounding.
|
||||
uint zero = P[0] >> 24u;
|
||||
float c036 = uintBitsToFloat(0x3EB851ECu | zero);
|
||||
float c100 = uintBitsToFloat(0x42C80000u | zero);
|
||||
float lg10 = log2(uintBitsToFloat(0x41200000u | zero));
|
||||
float rc036 = 1.0 / c036;
|
||||
float rc100 = 1.0 / c100;
|
||||
float rce41 = 1.0 / e41;
|
||||
precise vec3 lin = (exp2((cB * rc036) * lg10) - 1.0) * rc100 * rce41;
|
||||
imageStore(outLin, ivec2(pix), vec4(float(float16_t(lin.r)), float(float16_t(lin.g)), float(float16_t(lin.b)), 1.0));
|
||||
}
|
||||
Reference in new issue
Block a user