in src/webgpu/util/texture.ts [260:401]
function getCopyBufferToTextureViaRenderCode(
srcFormat: GPUTextureFormat,
dstFormat: GPUTextureFormat
) {
const info = kLoadValueFromStorageInfo[srcFormat];
assert(!!info);
const { storageType, texelType, unpackWGSL } = info;
const { useFragDepth, discardWithStencil } = getDepthStencilOptionsForFormat(dstFormat);
const [depthDecl, depthCode] = useFragDepth
? ['@builtin(frag_depth) d: f32,', 'fs.d = fs.v[0];']
: ['', ''];
const stencilCode = discardWithStencil ? 'if ((fs.v.r & vin.stencilMask) == 0) { discard; }' : '';
const code = `
struct Uniforms {
numTexelRows: u32,
bytesPerRow: u32,
bytesPerSample: u32,
sampleCount: u32,
offset: u32,
};
struct VSOutput {
@builtin(position) pos: vec4f,
@location(0) @interpolate(flat, either) sampleIndex: u32,
@location(1) @interpolate(flat, either) stencilMask: u32,
};
@vertex fn vs(@builtin(vertex_index) vNdx: u32, @builtin(instance_index) iNdx: u32) -> VSOutput {
let points = array(
vec2f(0, 0), vec2f(1, 0), vec2f(0, 1), vec2f(1, 1),
);
let sampleRow = vNdx / 4;
let numSampleRows = f32(uni.numTexelRows * uni.sampleCount);
let rowOffset = f32(sampleRow) / numSampleRows;
let rowMult = 1.0 / numSampleRows;
let p = (points[vNdx % 4] * vec2f(1, rowMult) + vec2f(0, rowOffset)) * 2.0 - 1.0;
return VSOutput(
vec4f(p, 0, 1),
uni.sampleCount - sampleRow % uni.sampleCount - 1,
1u << iNdx);
}
@group(0) @binding(0) var<uniform> uni: Uniforms;
@group(0) @binding(1) var src: texture_2d<${storageType}>;
// get a u32/i32/f32 from a r32uint/r32sint/r32float as though it was 1d array
fn getSrc(offset: u32) -> ${storageType} {
let width = textureDimensions(src, 0).x;
let x = offset % width;
let y = offset / width;
return textureLoad(src, vec2u(x, y), 0).r;
}
const kFloat32FormatMantissaBits = 23;
const kFloat32FormatBias = 127;
fn floatBitsToNumber(
rawBits: u32,
bitOffset: u32,
exponentBits: u32,
mantissaBits: u32,
bias: u32,
signed: bool) -> f32 {
let nonSignBits = exponentBits + mantissaBits;
let allBits = nonSignBits + select(0u, 1u, signed);
let allMask = (1u << allBits) - 1u;
let bits = (rawBits >> bitOffset) & allMask;
let nonSignBitsMask = (1u << nonSignBits) - 1u;
let exponentAndMantissaBits = bits & nonSignBitsMask;
let exponentMask = ((1u << exponentBits) - 1u) << mantissaBits;
let infinityOrNaN = (bits & exponentMask) == exponentMask;
if (infinityOrNaN) {
let mantissaMask = (1u << mantissaBits) - 1;
let signBit = 1u << nonSignBits;
let isNegative = (bits & signBit) != 0;
if ((bits & mantissaMask) != 0u) {
return 0.0; // NaN (does not exist in WGSL)
}
if (isNegative) {
return f32(-2e38); // NEGATIVE_INFINITY (does not exist in WGSL)
} else {
return f32(2e38); // POSITIVE_INFINITY (does not exist in WGSL)
}
}
var f32BitsWithWrongBias =
exponentAndMantissaBits << (kFloat32FormatMantissaBits - mantissaBits);
// add in the sign
f32BitsWithWrongBias |= (bits << (31u - nonSignBits)) & 0x80000000u;
let numberWithWrongBias = bitcast<f32>(f32BitsWithWrongBias);
return numberWithWrongBias * pow(2.0f, f32(kFloat32FormatBias - bias));
}
fn unpackRG11B10UFloat(v: u32) -> vec4f {
return vec4f(
floatBitsToNumber(v, 0, 5, 6, 15, false),
floatBitsToNumber(v, 11, 5, 6, 15, false),
floatBitsToNumber(v, 22, 5, 5, 15, false),
1
);
}
fn unpack(byteOffset: u32) -> ${texelType} {
${unpackWGSL};
}
struct FSOutput {
@location(0) v: ${texelType},
${depthDecl}
};
@fragment fn fs(vin: VSOutput) -> FSOutput {
let coord = vec2u(vin.pos.xy);
let byteOffset =
uni.offset +
coord.y * uni.bytesPerRow +
(coord.x * uni.sampleCount + vin.sampleIndex) * uni.bytesPerSample;
var fs: FSOutput;
fs.v = unpack(byteOffset);
${depthCode}
${stencilCode}
return fs;
}
`;
let dataFormat: GPUTextureFormat;
switch (storageType) {
case 'f32':
dataFormat = 'r32float';
break;
case 'i32':
dataFormat = 'r32sint';
break;
case 'u32':
dataFormat = 'r32uint';
break;
default:
unreachable();
}
return { code, dataFormat };
}