fp64 sine sweep

fp64 sine sweep

큰 기준값에 화면에서 조금씩 움직이는 값을 더한 x로 sin(x)를 구합니다.

TypeScript로 쓰고 TypeShade가 컴파일한 fp64 sine sweep 셰이더. 빌드할 때 렌더링함.
// ═══ typeshade example — fp64 sine sweep (df64 sin at large argument) ═══
//
// sin(x) where the argument x is a LARGE base plus a small on-screen sweep. As the
// base grows past ~2²⁴, one f32 ulp of x widens past the sweep window: the plain-f32
// argument `base + sx·span` quantizes to a few discrete steps, so its sine renders
// as a STAIRCASE — the wave the eye expects has dissolved into aliased blocks. The
// df64 side carries the base in extended precision, adds the sweep exactly, and the
// injected df64_sin (3-stage reduction + tabled angle-addition + short Taylor)
// resolves the smooth curve. Drag the BASE slider from 10⁴ (both smooth) up to 10⁸
// (the f32 wave shatters, the f64 wave holds); flip the fp64 toggle to shatter both.
//
// This is the transcendental twin of fp64-cancellation: same graph-paper split, a
// different f32 failure mode (argument-resolution loss, not term cancellation).
//
// The `_fp64` guard uniform is auto-injected by the lowering; the render harnesses
// bind it to 1.0f by probing the program for the Fp64Guard block.
import {
fn,
module,
uniformStruct,
vec3,
vec4,
f32,
toF64,
sin,
fract,
abs,
min,
mix,
step,
smoothstep,
toF32,
f32T,
f64T,
vec2fT,
Let,
} from '../src/index.js';
import { VsOut, vs } from './_fullscreen.js';
import type { ShaderExample } from './_shared.js';
// Sweep window (radians of argument spanned across one half's width). ~4 cycles
// when the base is small enough to resolve them.
const SPAN = 8 * Math.PI;
const Uni = uniformStruct(
'Uniforms',
{ group: 0, binding: 0, as: 'u' },
{
resolution: vec2fT,
base: f64T, // large argument base (seconds-like), swept 10^4..10^8
fp64: f32T, // toggle: 1 = split-screen f32 | f64 (canonical), 0 = all-f32
},
);
const fsSweep = fn(
'fs_sweep',
{ vo: VsOut },
(p) => {
// Position within this half: sx ∈ [0, 1] over each half's width.
const halfUv = Let(p.vo.uv.x.mul(2.0));
const sx = Let(halfUv.sub(p.vo.uv.x.lt(0.5).select(0.0, 1.0)));
const isF32 = Let(p.vo.uv.x.lt(0.5).or(Uni.field.fp64.lt(0.5)));
// The swept argument = base + sx·SPAN. f64: add in extended precision, then
// df64_sin. f32: narrow the base first (its ulp swallows the sweep at large base).
const arg64 = Let(Uni.field.base.add(toF64(sx.mul(SPAN))));
const y64 = Let(toF32(sin(arg64)));
const y32 = Let(sin(toF32(Uni.field.base).add(sx.mul(SPAN))));
const v = Let(isF32.select(y32, y64)); // sine value ∈ [−1, 1]
// Plot: py ∈ [−1, 1] over the height; the curve is v.
const py = Let(p.vo.uv.y.sub(0.5).mul(2.0));
const px = Let(f32(2).div(Uni.field.resolution.y)); // plot-units per pixel
// Graph-paper: parchment + a pale grid (10 columns per half, 0.25-unit rows).
const gxf = Let(fract(sx.mul(10.0)));
const gyf = Let(fract(py.add(1.0).mul(4.0)));
const dgx = Let(min(gxf, f32(1).sub(gxf)));
const dgy = Let(min(gyf, f32(1).sub(gyf)));
const aaCx = Let(f32(30).div(Uni.field.resolution.x));
const aaCy = Let(f32(20).div(Uni.field.resolution.y));
const grid = Let(
f32(1)
.sub(smoothstep(f32(0), aaCx, dgx))
.add(f32(1).sub(smoothstep(f32(0), aaCy, dgy))),
);
const paper = vec3(0.96, 0.94, 0.88);
const rgb0 = Let(mix(paper, vec3(0.72, 0.78, 0.86), min(grid, f32(1)).mul(0.45)));
// Fill under the curve — its boundary reads the verdict at a glance (a smooth
// sine on f64, a stepped barcode on f32 once the base is large).
const fill = Let(step(py, v));
const rgb1 = Let(mix(rgb0, vec3(0.62, 0.74, 0.9), fill.mul(0.4)));
// Ink the curve.
const ink = Let(f32(1).sub(smoothstep(px.mul(1.2), px.mul(3.0), abs(v.sub(py)))));
const rgb2 = Let(mix(rgb1, vec3(0.13, 0.16, 0.3), ink.mul(0.85)));
// Axes: the midline y = 0 and the half divider.
const axis = Let(
min(
smoothstep(f32(0), px.mul(1.5), abs(py)),
smoothstep(f32(0), px.mul(1.5), abs(sx.sub(0.5)).mul(2.0)),
),
);
const rgb = Let(mix(vec3(0.35, 0.33, 0.3), rgb2, axis));
return vec4(rgb, f32(1));
},
{ stage: 'fragment', retAttr: '@location(0)' },
);
// `_fp64` guard lands at (group 0, binding 1) automatically.
const fp64SineSweepModule = module({
funcs: [vs, fsSweep],
uses: [Uni, VsOut],
});
export const fp64SineSweep: ShaderExample = {
id: 'fp64-sine-sweep',
title: 'fp64 sine sweep',
blurb:
'sin(x) for x = a large base + a small on-screen sweep. Past ~2²⁴ one f32 ulp of the argument grows wider than the sweep window, so the plain-f32 wave (left) collapses into an aliased staircase; the emulated-f64 side (right) carries the base in extended precision and the injected df64_sin — argument reduction + tabled angle-addition + a short Taylor — resolves the smooth curve. Drag BASE from 10⁴ (both smooth) to 10⁸ (only f64 survives); flip the fp64 toggle to shatter both. Correct on backends where the df64 multiply survives fast-math (Apple/Metal collapses it — see AUTHORING §7).',
category: 'generic',
file: 'fp64-sine-sweep.ts',
module: fp64SineSweepModule,
renderable: true,
splitLabels: ['f32 sin', 'f64 sin (emulated)'],
controls: {
resolution: { kind: 'resolution' },
base: { kind: 'logmag1d', magField: 'mag', base: 1, offset: 0.123 },
mag: {
kind: 'slider',
label: 'Argument base 10^x',
min: 4,
max: 8,
step: 0.02,
value: 6,
wheel: true,
},
fp64: { kind: 'toggle', label: 'fp64 emulation', value: true },
},
};
struct Uniforms {
resolution: vec2<f32>,
base: vec2<f32>,
fp64: f32,
}
struct VsOut {
@builtin(position) pos: vec4<f32>,
@location(0) uv: vec2<f32>,
}
@group(0) @binding(0) var<uniform> u: Uniforms;
@group(0) @binding(1) var _fp64: texture_2d<f32>;
@vertex
fn vs(@builtin(vertex_index) vi: u32) -> VsOut {
let _cse0 = ((f32((vi & 1u)) * 4.0) - 1.0);
let _cse1 = ((f32((vi >> 1u)) * 4.0) - 1.0);
return VsOut(vec4<f32>(_cse0, _cse1, 0.0, 1.0), vec2<f32>(((_cse0 * 0.5) + 0.5), ((_cse1 * 0.5) + 0.5)));
}
@fragment
fn fs_sweep(vo: VsOut) -> @location(0) vec4<f32> {
let _fp64_g = textureLoad(_fp64, vec2<i32>(0, 0), 0).x;
let _v0 = (vo.uv.x * 2.0);
let _cse0 = (vo.uv.x < 0.5);
let _v1 = (_v0 - select(1.0, 0.0, _cse0));
let _v2 = (_cse0 || (u.fp64 < 0.5));
let _gv0 = (_v1 * 25.132741228718345);
let _v3 = df64_add(u.base, vec2<f32>(_gv0, 0.0), _fp64_g);
let _cse1 = bitcast<f32>(bitcast<u32>(0.0));
let _v4 = df64_narrow(df64_sin(df64_add(_v3, vec2<f32>(_cse1, _cse1), _fp64_g), _fp64_g));
let _v5 = sin((df64_narrow(u.base) + _gv0));
let _v6 = select(_v4, _v5, _v2);
let _v7 = ((vo.uv.y - 0.5) * 2.0);
let _v8 = (2.0 / u.resolution.y);
let _v9 = fract((_v1 * 10.0));
let _v10 = fract(((_v7 + 1.0) * 4.0));
let _v11 = min(_v9, (1.0 - _v9));
let _v12 = min(_v10, (1.0 - _v10));
let _v13 = (30.0 / u.resolution.x);
let _v14 = (20.0 / u.resolution.y);
let _v15 = ((1.0 - smoothstep(0.0, _v13, _v11)) + (1.0 - smoothstep(0.0, _v14, _v12)));
let _v16 = mix(vec3<f32>(0.96, 0.94, 0.88), vec3<f32>(0.72, 0.78, 0.86), (min(_v15, 1.0) * 0.45));
let _v17 = step(_v7, _v6);
let _v18 = mix(_v16, vec3<f32>(0.62, 0.74, 0.9), (_v17 * 0.4));
let _v19 = (1.0 - smoothstep((_v8 * 1.2), (_v8 * 3.0), abs((_v6 - _v7))));
let _v20 = mix(_v18, vec3<f32>(0.13, 0.16, 0.3), (_v19 * 0.85));
let _lc0 = (_v8 * 1.5);
let _v21 = min(smoothstep(0.0, _lc0, abs(_v7)), smoothstep(0.0, _lc0, (abs((_v1 - 0.5)) * 2.0)));
let _v22 = mix(vec3<f32>(0.35, 0.33, 0.3), _v20, _v21);
return vec4<f32>(_v22, 1.0);
}
fn df64_twoSum(a: f32, b: f32, _fp64_g: f32) -> vec2<f32> {
let _v0 = (a + b);
let _v1 = (((_v0 * _fp64_g) - a) * _fp64_g);
let _v2 = (((a - ((_v0 - _v1) * _fp64_g)) * _fp64_g) + (b - _v1));
return vec2<f32>(_v0, _v2);
}
fn df64_quickTwoSum(a: f32, b: f32, _fp64_g: f32) -> vec2<f32> {
let _v0 = ((a + b) * _fp64_g);
let _v1 = (b - ((_v0 - a) * _fp64_g));
return vec2<f32>(_v0, _v1);
}
fn df64_split(a: f32, _fp64_g: f32) -> vec2<f32> {
let _v0 = (a * (_fp64_g * 4097.0));
let _v1 = ((_v0 * _fp64_g) - (_v0 - a));
let _v2 = ((a * _fp64_g) - _v1);
return vec2<f32>(_v1, _v2);
}
fn df64_twoProd(a: f32, b: f32, _fp64_g: f32) -> vec2<f32> {
let _v0 = (a * b);
let _v1 = df64_split(a, _fp64_g);
let _v2 = df64_split(b, _fp64_g);
let _v3 = (((((_v1.x * _v2.x) - _v0) + (_v1.x * _v2.y)) + (_v1.y * _v2.x)) + (_v1.y * _v2.y));
return vec2<f32>(_v0, _v3);
}
fn df64_add(a: vec2<f32>, b: vec2<f32>, _fp64_g: f32) -> vec2<f32> {
var _v0: vec2<f32> = df64_twoSum(a.x, b.x, _fp64_g);
let _v1 = df64_twoSum(a.y, b.y, _fp64_g);
_v0.y = (_v0.y + _v1.x);
_v0 = df64_quickTwoSum(_v0.x, _v0.y, _fp64_g);
_v0.y = (_v0.y + _v1.y);
_v0 = df64_quickTwoSum(_v0.x, _v0.y, _fp64_g);
return _v0;
}
fn df64_sub(a: vec2<f32>, b: vec2<f32>, _fp64_g: f32) -> vec2<f32> {
return df64_add(a, (-b), _fp64_g);
}
fn df64_mul(a: vec2<f32>, b: vec2<f32>, _fp64_g: f32) -> vec2<f32> {
var _v0: vec2<f32> = df64_twoProd(a.x, b.x, _fp64_g);
_v0.y = (_v0.y + (a.x * b.y));
_v0 = df64_quickTwoSum(_v0.x, _v0.y, _fp64_g);
_v0.y = (_v0.y + (a.y * b.x));
return df64_quickTwoSum(_v0.x, _v0.y, _fp64_g);
}
fn df64_div(a: vec2<f32>, b: vec2<f32>, _fp64_g: f32) -> vec2<f32> {
let _v0 = (_fp64_g / b.x);
let _v1 = (a * _v0);
let _v2 = df64_sub(a, df64_mul(b, _v1, _fp64_g), _fp64_g).x;
let _v3 = df64_twoProd(_v0, _v2, _fp64_g);
return df64_add(_v1, _v3, _fp64_g);
}
fn df64_narrow(a: vec2<f32>) -> f32 {
return (a.x + a.y);
}
fn df64_nint(a: vec2<f32>, _fp64_g: f32) -> vec2<f32> {
let _v0 = floor((a.x + 0.5));
let _v1 = select(_v0, (_v0 - 1.0), ((abs((_v0 - a.x)) == 0.5) && (a.y < 0.0)));
return select(vec2<f32>(_v1, 0.0), df64_quickTwoSum(_v0, floor((a.y + 0.5)), _fp64_g), (_v0 == a.x));
}
fn df64_sin_taylor(a: vec2<f32>, _fp64_g: f32) -> vec2<f32> {
let _v0 = (-df64_mul(a, a, _fp64_g));
let _v1 = df64_mul(a, _v0, _fp64_g);
let _v2 = df64_add(a, df64_mul(_v1, vec2<f32>(0.1666666716337204, -4.967053879312289e-9), _fp64_g), _fp64_g);
let _v3 = df64_mul(_v1, _v0, _fp64_g);
return df64_add(_v2, df64_mul(_v3, vec2<f32>(0.008333333767950535, -4.34617203337595e-10), _fp64_g), _fp64_g);
}
fn df64_cos_taylor(a: vec2<f32>, _fp64_g: f32) -> vec2<f32> {
let _v0 = (-df64_mul(a, a, _fp64_g));
let _v1 = df64_add(vec2<f32>(1.0, 0.0), df64_mul(_v0, vec2<f32>(0.5, 0.0), _fp64_g), _fp64_g);
let _v2 = df64_mul(_v0, _v0, _fp64_g);
let _v3 = df64_add(_v1, df64_mul(_v2, vec2<f32>(0.0416666679084301, -1.2417634698280722e-9), _fp64_g), _fp64_g);
let _v4 = df64_mul(_v2, _v0, _fp64_g);
return df64_add(_v3, df64_mul(_v4, vec2<f32>(0.0013888889225199819, -3.3631094437103215e-11), _fp64_g), _fp64_g);
}
fn df64_sin(a: vec2<f32>, _fp64_g: f32) -> vec2<f32> {
let _cse0 = vec2<f32>(6.2831854820251465, -1.7484555314695172e-7);
let _v0 = df64_nint(df64_div(a, _cse0, _fp64_g), _fp64_g);
let _v1 = df64_sub(a, df64_mul(_cse0, _v0, _fp64_g), _fp64_g);
let _v2 = floor(((_v1.x / 1.5707963705062866) + 0.5));
let _v3 = df64_sub(_v1, df64_mul(vec2<f32>(1.5707963705062866, -4.371138828673793e-8), vec2<f32>(_v2, 0.0), _fp64_g), _fp64_g);
let _v4 = floor(((_v3.x / 0.19634954631328583) + 0.5));
let _v5 = df64_sub(_v3, df64_mul(vec2<f32>(0.19634954631328583, -5.463923535842241e-9), vec2<f32>(_v4, 0.0), _fp64_g), _fp64_g);
let _v6 = df64_sin_taylor(_v5, _fp64_g);
let _v7 = df64_cos_taylor(_v5, _fp64_g);
let _v8 = abs(_v4);
let _cse1 = vec2<f32>(0.7071067690849304, 1.2101617485882343e-8);
let _gv0 = (_v8 == 1.0);
let _v9 = select(select(select(select(vec2<f32>(1.0, 0.0), _cse1, (_v8 == 4.0)), vec2<f32>(0.8314695954322815, 1.687026340846387e-8), (_v8 == 3.0)), vec2<f32>(0.9238795042037964, 2.830748968563057e-8), (_v8 == 2.0)), vec2<f32>(0.9807852506637573, 2.9739473106360492e-8), _gv0);
let _v10 = select(select(select(select(vec2<f32>(0.0, 0.0), _cse1, (_v8 == 4.0)), vec2<f32>(0.5555702447891235, -1.1769521357507529e-8), (_v8 == 3.0)), vec2<f32>(0.3826834261417389, 6.2233507236442165e-9), (_v8 == 2.0)), vec2<f32>(0.19509032368659973, -1.6704715388726754e-9), _gv0);
let _v11 = select((-_v10), _v10, (_v4 >= 0.0));
let _v12 = df64_add(df64_mul(_v9, _v6, _fp64_g), df64_mul(_v11, _v7, _fp64_g), _fp64_g);
let _v13 = df64_sub(df64_mul(_v9, _v7, _fp64_g), df64_mul(_v11, _v6, _fp64_g), _fp64_g);
return select(select(select((-_v12), (-_v13), (_v2 == -1.0)), _v13, (_v2 == 1.0)), _v12, (_v2 == 0.0));
}
#version 300 es
precision highp float;
precision highp int;
out vec2 uv;
void main() {
uint vi = uint(gl_VertexID);
float _cse0 = ((float((vi & 1u)) * 4.0) - 1.0);
float _cse1 = ((float((vi >> 1u)) * 4.0) - 1.0);
gl_Position = vec4(_cse0, _cse1, 0.0, 1.0);
uv = vec2(((_cse0 * 0.5) + 0.5), ((_cse1 * 0.5) + 0.5));
}
#version 300 es
precision highp float;
precision highp int;
layout(std140) uniform Uniforms {
vec2 resolution;
vec2 base;
float fp64;
} u;
uniform highp sampler2D _fp64;
vec2 df64_twoSum(float a, float b, float _fp64_g) {
float _v0 = (a + b);
float _v1 = (((_v0 * _fp64_g) - a) * _fp64_g);
float _v2 = (((a - ((_v0 - _v1) * _fp64_g)) * _fp64_g) + (b - _v1));
return vec2(_v0, _v2);
}
vec2 df64_quickTwoSum(float a, float b, float _fp64_g) {
float _v0 = ((a + b) * _fp64_g);
float _v1 = (b - ((_v0 - a) * _fp64_g));
return vec2(_v0, _v1);
}
vec2 df64_split(float a, float _fp64_g) {
float _v0 = (a * (_fp64_g * 4097.0));
float _v1 = ((_v0 * _fp64_g) - (_v0 - a));
float _v2 = ((a * _fp64_g) - _v1);
return vec2(_v1, _v2);
}
vec2 df64_twoProd(float a, float b, float _fp64_g) {
float _v0 = (a * b);
vec2 _v1 = df64_split(a, _fp64_g);
vec2 _v2 = df64_split(b, _fp64_g);
float _v3 = (((((_v1.x * _v2.x) - _v0) + (_v1.x * _v2.y)) + (_v1.y * _v2.x)) + (_v1.y * _v2.y));
return vec2(_v0, _v3);
}
vec2 df64_add(vec2 a, vec2 b, float _fp64_g) {
vec2 _v0 = df64_twoSum(a.x, b.x, _fp64_g);
vec2 _v1 = df64_twoSum(a.y, b.y, _fp64_g);
_v0.y = (_v0.y + _v1.x);
_v0 = df64_quickTwoSum(_v0.x, _v0.y, _fp64_g);
_v0.y = (_v0.y + _v1.y);
_v0 = df64_quickTwoSum(_v0.x, _v0.y, _fp64_g);
return _v0;
}
vec2 df64_sub(vec2 a, vec2 b, float _fp64_g) {
return df64_add(a, (-b), _fp64_g);
}
vec2 df64_mul(vec2 a, vec2 b, float _fp64_g) {
vec2 _v0 = df64_twoProd(a.x, b.x, _fp64_g);
_v0.y = (_v0.y + (a.x * b.y));
_v0 = df64_quickTwoSum(_v0.x, _v0.y, _fp64_g);
_v0.y = (_v0.y + (a.y * b.x));
return df64_quickTwoSum(_v0.x, _v0.y, _fp64_g);
}
vec2 df64_div(vec2 a, vec2 b, float _fp64_g) {
float _v0 = (_fp64_g / b.x);
vec2 _v1 = (a * _v0);
float _v2 = df64_sub(a, df64_mul(b, _v1, _fp64_g), _fp64_g).x;
vec2 _v3 = df64_twoProd(_v0, _v2, _fp64_g);
return df64_add(_v1, _v3, _fp64_g);
}
float df64_narrow(vec2 a) {
return (a.x + a.y);
}
vec2 df64_nint(vec2 a, float _fp64_g) {
float _v0 = floor((a.x + 0.5));
float _v1 = (((abs((_v0 - a.x)) == 0.5) && (a.y < 0.0)) ? (_v0 - 1.0) : _v0);
return ((_v0 == a.x) ? df64_quickTwoSum(_v0, floor((a.y + 0.5)), _fp64_g) : vec2(_v1, 0.0));
}
vec2 df64_sin_taylor(vec2 a, float _fp64_g) {
vec2 _v0 = (-df64_mul(a, a, _fp64_g));
vec2 _v1 = df64_mul(a, _v0, _fp64_g);
vec2 _v2 = df64_add(a, df64_mul(_v1, vec2(0.1666666716337204, -4.967053879312289e-9), _fp64_g), _fp64_g);
vec2 _v3 = df64_mul(_v1, _v0, _fp64_g);
return df64_add(_v2, df64_mul(_v3, vec2(0.008333333767950535, -4.34617203337595e-10), _fp64_g), _fp64_g);
}
vec2 df64_cos_taylor(vec2 a, float _fp64_g) {
vec2 _v0 = (-df64_mul(a, a, _fp64_g));
vec2 _v1 = df64_add(vec2(1.0, 0.0), df64_mul(_v0, vec2(0.5, 0.0), _fp64_g), _fp64_g);
vec2 _v2 = df64_mul(_v0, _v0, _fp64_g);
vec2 _v3 = df64_add(_v1, df64_mul(_v2, vec2(0.0416666679084301, -1.2417634698280722e-9), _fp64_g), _fp64_g);
vec2 _v4 = df64_mul(_v2, _v0, _fp64_g);
return df64_add(_v3, df64_mul(_v4, vec2(0.0013888889225199819, -3.3631094437103215e-11), _fp64_g), _fp64_g);
}
vec2 df64_sin(vec2 a, float _fp64_g) {
vec2 _cse0 = vec2(6.2831854820251465, -1.7484555314695172e-7);
vec2 _v0 = df64_nint(df64_div(a, _cse0, _fp64_g), _fp64_g);
vec2 _v1 = df64_sub(a, df64_mul(_cse0, _v0, _fp64_g), _fp64_g);
float _v2 = floor(((_v1.x / 1.5707963705062866) + 0.5));
vec2 _v3 = df64_sub(_v1, df64_mul(vec2(1.5707963705062866, -4.371138828673793e-8), vec2(_v2, 0.0), _fp64_g), _fp64_g);
float _v4 = floor(((_v3.x / 0.19634954631328583) + 0.5));
vec2 _v5 = df64_sub(_v3, df64_mul(vec2(0.19634954631328583, -5.463923535842241e-9), vec2(_v4, 0.0), _fp64_g), _fp64_g);
vec2 _v6 = df64_sin_taylor(_v5, _fp64_g);
vec2 _v7 = df64_cos_taylor(_v5, _fp64_g);
float _v8 = abs(_v4);
vec2 _cse1 = vec2(0.7071067690849304, 1.2101617485882343e-8);
bool _gv0 = (_v8 == 1.0);
vec2 _v9 = (_gv0 ? vec2(0.9807852506637573, 2.9739473106360492e-8) : ((_v8 == 2.0) ? vec2(0.9238795042037964, 2.830748968563057e-8) : ((_v8 == 3.0) ? vec2(0.8314695954322815, 1.687026340846387e-8) : ((_v8 == 4.0) ? _cse1 : vec2(1.0, 0.0)))));
vec2 _v10 = (_gv0 ? vec2(0.19509032368659973, -1.6704715388726754e-9) : ((_v8 == 2.0) ? vec2(0.3826834261417389, 6.2233507236442165e-9) : ((_v8 == 3.0) ? vec2(0.5555702447891235, -1.1769521357507529e-8) : ((_v8 == 4.0) ? _cse1 : vec2(0.0, 0.0)))));
vec2 _v11 = ((_v4 >= 0.0) ? _v10 : (-_v10));
vec2 _v12 = df64_add(df64_mul(_v9, _v6, _fp64_g), df64_mul(_v11, _v7, _fp64_g), _fp64_g);
vec2 _v13 = df64_sub(df64_mul(_v9, _v7, _fp64_g), df64_mul(_v11, _v6, _fp64_g), _fp64_g);
return ((_v2 == 0.0) ? _v12 : ((_v2 == 1.0) ? _v13 : ((_v2 == -1.0) ? (-_v13) : (-_v12))));
}
in vec2 uv;
layout(location = 0) out vec4 _ret;
void main() {
float _fp64_g = texelFetch(_fp64, ivec2(0, 0), 0).x;
float _v0 = (uv.x * 2.0);
bool _cse0 = (uv.x < 0.5);
float _v1 = (_v0 - (_cse0 ? 0.0 : 1.0));
bool _v2 = (_cse0 || (u.fp64 < 0.5));
float _gv0 = (_v1 * 25.132741228718345);
vec2 _v3 = df64_add(u.base, vec2(_gv0, 0.0), _fp64_g);
float _cse1 = uintBitsToFloat(floatBitsToUint(0.0));
float _v4 = df64_narrow(df64_sin(df64_add(_v3, vec2(_cse1, _cse1), _fp64_g), _fp64_g));
float _v5 = sin((df64_narrow(u.base) + _gv0));
float _v6 = (_v2 ? _v5 : _v4);
float _v7 = ((uv.y - 0.5) * 2.0);
float _v8 = (2.0 / u.resolution.y);
float _v9 = fract((_v1 * 10.0));
float _v10 = fract(((_v7 + 1.0) * 4.0));
float _v11 = min(_v9, (1.0 - _v9));
float _v12 = min(_v10, (1.0 - _v10));
float _v13 = (30.0 / u.resolution.x);
float _v14 = (20.0 / u.resolution.y);
float _v15 = ((1.0 - smoothstep(0.0, _v13, _v11)) + (1.0 - smoothstep(0.0, _v14, _v12)));
vec3 _v16 = mix(vec3(0.96, 0.94, 0.88), vec3(0.72, 0.78, 0.86), (min(_v15, 1.0) * 0.45));
float _v17 = step(_v7, _v6);
vec3 _v18 = mix(_v16, vec3(0.62, 0.74, 0.9), (_v17 * 0.4));
float _v19 = (1.0 - smoothstep((_v8 * 1.2), (_v8 * 3.0), abs((_v6 - _v7))));
vec3 _v20 = mix(_v18, vec3(0.13, 0.16, 0.3), (_v19 * 0.85));
float _lc0 = (_v8 * 1.5);
float _v21 = min(smoothstep(0.0, _lc0, abs(_v7)), smoothstep(0.0, _lc0, (abs((_v1 - 0.5)) * 2.0)));
vec3 _v22 = mix(vec3(0.35, 0.33, 0.3), _v20, _v21);
_ret = vec4(_v22, 1.0);
}

fp64 sine sweep. 빌드할 때 그린 화면입니다.

WGSL과 GLSL 탭은 커밋 c66579bf의 컴파일러가 직접 낸 출력입니다. 컴파일러의 출력 검사가 구워 둔 골든 파일에서 그대로 읽어 왔습니다(emit-goldens.test.ts).

이 예제는 fn() 빌더 API로 작성해서 Playground의 편집기가 받지 않습니다.

GitHub의 파일

이 페이지 편집 문제 보고