Using webgl-debug to emit the low-level WebGL API calls from the regl project

This commit is contained in:
Rezmason
2023-08-25 09:10:19 -07:00
parent d1f00e7e42
commit 00c7f42ce4
3 changed files with 1457 additions and 16 deletions

View File

@@ -23,6 +23,7 @@ const loadJS = (src) =>
const init = async () => { const init = async () => {
await loadJS("lib/regl.js"); await loadJS("lib/regl.js");
await loadJS("lib/webgl-debug.js");
const resize = () => { const resize = () => {
const devicePixelRatio = window.devicePixelRatio ?? 1; const devicePixelRatio = window.devicePixelRatio ?? 1;
@@ -49,7 +50,249 @@ const init = async () => {
// These extensions are also needed, but Safari misreports that they are missing // These extensions are also needed, but Safari misreports that they are missing
const optionalExtensions = ["EXT_color_buffer_half_float", "WEBGL_color_buffer_float", "OES_standard_derivatives"]; const optionalExtensions = ["EXT_color_buffer_half_float", "WEBGL_color_buffer_float", "OES_standard_derivatives"];
const regl = createREGL({ canvas, pixelRatio: 1, extensions, optionalExtensions }); const { makeDebugContext } = WebGLDebugUtils;
const glConsts = {
DEPTH_TEST: 0x0B71,
BLEND: 0x0BE2,
UNPACK_ALIGNMENT: 0x0CF5,
TEXTURE_2D: 0x0DE1,
RGBA: 0x1908,
LUMINANCE: 0x1909,
NEAREST: 0x2600,
LINEAR: 0x2601,
TEXTURE_MAG_FILTER: 0x2800,
TEXTURE_MIN_FILTER: 0x2801,
TEXTURE_WRAP_S: 0x2802,
TEXTURE_WRAP_T: 0x2803,
CLAMP_TO_EDGE: 0x812F,
DEPTH_STENCIL_ATTACHMENT: 0x821A,
TEXTURE0: 0x84C0,
DEPTH_STENCIL: 0x84F9,
RGBA16F_EXT: 0x881A,
STATIC_DRAW: 0x88E4,
ACTIVE_UNIFORMS: 0x8B86,
ACTIVE_ATTRIBUTES: 0x8B89,
COLOR_ATTACHMENT0: 0x8CE0,
DEPTH_ATTACHMENT: 0x8D00,
STENCIL_ATTACHMENT: 0x8D20,
FRAMEBUFFER: 0x8D40,
RENDERBUFFER: 0x8D41,
HALF_FLOAT_OES: 0x8D61,
UNPACK_FLIP_Y_WEBGL: 0x9240,
UNPACK_PREMULTIPLY_ALPHA_WEBGL: 0x9241,
UNPACK_COLORSPACE_CONVERSION_WEBGL: 0x9243,
BROWSER_DEFAULT_WEBGL: 0x9244,
ARRAY_BUFFER: 34962,
FRAGMENT_SHADER: 35632,
FRAGMENT_SHADER: 35632,
VERTEX_SHADER: 35633,
COMPILE_STATUS: 35713,
LINK_STATUS: 35714,
TRIANGLES: 4,
UNSIGNED_BYTE: 5121,
FLOAT: 5126,
};
for (let i = 1; i < 32; i++) {
glConsts[`TEXTURE${i}`] = 0x84C0 + i;
}
const betterNames = {
[11]: "defaultFragShader",
[12]: "defaultVertShader",
[13]: "defaultProgram",
[17]: "fullscreen_geometry",
[18]: "rain_compute_doublebuffer_1_texture", [19]: "rain_compute_doublebuffer_1_framebuffer",
[20]: "rain_compute_doublebuffer_2_texture", [21]: "rain_compute_doublebuffer_2_framebuffer",
[22]: "rain_compute_shader",
[23]: "placeholder_texture",
[24]: "rain_output_texture", [25]: "rain_output_framebuffer", [26]: "rain_output_renderbuffer",
[27]: "rain_frag_shader",
[28]: "rain_vert_shader",
[29]: "rain_program",
[47]: "rain_geometry",
[48]: "bloom_high_pass_pyr_0_texture", [49]: "bloom_high_pass_pyr_0_framebuffer", [50]: "bloom_high_pass_pyr_0_renderbuffer",
[51]: "bloom_high_pass_pyr_1_texture", [52]: "bloom_high_pass_pyr_1_framebuffer", [53]: "bloom_high_pass_pyr_1_renderbuffer",
[54]: "bloom_high_pass_pyr_2_texture", [55]: "bloom_high_pass_pyr_2_framebuffer", [56]: "bloom_high_pass_pyr_2_renderbuffer",
[57]: "bloom_high_pass_pyr_3_texture", [58]: "bloom_high_pass_pyr_3_framebuffer", [59]: "bloom_high_pass_pyr_3_renderbuffer",
[60]: "bloom_high_pass_pyr_4_texture", [61]: "bloom_high_pass_pyr_4_framebuffer", [62]: "bloom_high_pass_pyr_4_renderbuffer",
[63]: "bloom_h_blur_pyr_0_texture", [64]: "bloom_h_blur_pyr_0_framebuffer", [65]: "bloom_h_blur_pyr_0_renderbuffer",
[66]: "bloom_h_blur_pyr_1_texture", [67]: "bloom_h_blur_pyr_1_framebuffer", [68]: "bloom_h_blur_pyr_1_renderbuffer",
[69]: "bloom_h_blur_pyr_2_texture", [70]: "bloom_h_blur_pyr_2_framebuffer", [71]: "bloom_h_blur_pyr_2_renderbuffer",
[72]: "bloom_h_blur_pyr_3_texture", [73]: "bloom_h_blur_pyr_3_framebuffer", [74]: "bloom_h_blur_pyr_3_renderbuffer",
[75]: "bloom_h_blur_pyr_4_texture", [76]: "bloom_h_blur_pyr_4_framebuffer", [77]: "bloom_h_blur_pyr_4_renderbuffer",
[78]: "bloom_v_blur_pyr_0_texture", [79]: "bloom_v_blur_pyr_0_framebuffer", [80]: "bloom_v_blur_pyr_0_renderbuffer",
[81]: "bloom_v_blur_pyr_1_texture", [82]: "bloom_v_blur_pyr_1_framebuffer", [83]: "bloom_v_blur_pyr_1_renderbuffer",
[84]: "bloom_v_blur_pyr_2_texture", [85]: "bloom_v_blur_pyr_2_framebuffer", [86]: "bloom_v_blur_pyr_2_renderbuffer",
[87]: "bloom_v_blur_pyr_3_texture", [88]: "bloom_v_blur_pyr_3_framebuffer", [89]: "bloom_v_blur_pyr_3_renderbuffer",
[90]: "bloom_v_blur_pyr_4_texture", [91]: "bloom_v_blur_pyr_4_framebuffer", [92]: "bloom_v_blur_pyr_4_renderbuffer",
[93]: "bloom_output_texture", [94]: "bloom_output_framebuffer", [95]: "bloom_output_renderbuffer",
[96]: "bloom_high_pass_shader",
[97]: "bloom_blur_shader",
[98]: "bloom_combine_shader",
[99]: "palette_output_texture", [100]: "palette_output_framebuffer", [101]: "palette_output_renderbuffer",
[102]: "palette_texture",
[103]: "palette_shader",
[104]: "msdf_texture",
[105]: "rain_compute_program",
[125]: "bloom_high_pass_program",
[131]: "bloom_blur_program",
[141]: "bloom_combine_program",
[155]: "palette_program",
};
const returnedValueNames = [];
const glConstsByID = {};
Object.entries(glConsts).forEach(([key, value]) => {
if (glConstsByID[value] == null) {
glConstsByID[value] = [];
}
glConstsByID[value].push(key);
});
const returnedValues = [];
const returnedValueUsages = [];
const commands = [];
const log = [];
const printCommands = (label) => {
const printedCommands = [];
for (const {name, args, retIndex} of commands) {
const printedArgs = [];
for (const [type, value] of args) {
if (value == null) {
printedArgs.push(`null`);
continue;
}
if (Array.isArray(value) || ArrayBuffer.isView(value)) {
printedArgs.push(`[${value.join(", ")}]`);
continue;
}
switch (type) {
case "string":
printedArgs.push(`\`${value}\``);
break;
case "GLenum":
printedArgs.push(`gl.${value}`);
break;
case "object":
printedArgs.push(`${value}`);
break;
case "returnedValue":
printedArgs.push(`state.${returnedValueNames[value]}`);
break;
default:
printedArgs.push(`${value}`);
break;
}
}
if (retIndex != -1 && returnedValueUsages[retIndex] > 0) {
printedCommands.push(`state.${returnedValueNames[retIndex]} = gl.${name}(${printedArgs.join(", ")});`);
} else {
printedCommands.push(`gl.${name}(${printedArgs.join(", ")});`);
}
}
log.push(`// ${label}`);
log.push(printedCommands.join("\n"));
commands.length = 0;
};
const rawGL = canvas.getContext("webgl");
const gl = new Proxy(makeDebugContext(
rawGL,
null,
(...a) => {
const name = a[0];
const args = Array.from(a[1]);
const ret = a[2];
for (let i = 0; i < args.length; i++) {
let value = args[i];
let type = typeof value;
if (type === "number" && glConstsByID[value] != null) {
type = "GLenum";
value = glConstsByID[value][0];
}
if (returnedValues.includes(value)) {
type = "returnedValue";
value = returnedValues.indexOf(value);
returnedValueUsages[value]++;
}
args[i] = [type, value];
}
let retIndex = -1;
if (typeof ret === "object" && !returnedValues.includes(ret)) {
returnedValues.push(ret);
returnedValueUsages.push(0);
retIndex = returnedValues.length - 1;
let glType = (ret[Symbol.toStringTag] ?? "object").replaceAll("WebGL", "").toLowerCase();
let retName = glType + "_" + retIndex;
switch (name) {
case "getExtension":
retName = glType;
break;
}
switch (glType) {
case "texture":
break;
case "framebuffer":
break;
case "renderbuffer":
break;
case "program":
break;
case "shader":
if (args[0][1].toLowerCase().includes("fragment")) {
retName = "fragment_shader" + "_" + retIndex;
} else {
retName = "vertex_shader" + "_" + retIndex;;
}
break;
case "activeinfo":
retName = returnedValueNames[args[0][1]] + "_a_" + ret.name;
break;
case "uniformlocation":
retName = returnedValueNames[args[0][1]] + "_u_" + args[1][1];
break;
}
if (returnedValueNames.includes(retName)) {
retName = retName + "_" + retIndex;
}
if (betterNames[retIndex] != null) {
retName = betterNames[retIndex];
}
returnedValueNames[retIndex] = retName;
}
commands.push({ name, args, retIndex });
}
), {
/*
get(target, prop, receiver) {
const ret = Reflect.get(...arguments);
if (typeof ret !== "function") {
console.log("GET", prop, ret);
}
return ret;
}
*/
});
const regl = createREGL({ gl, pixelRatio: 1, extensions, optionalExtensions });
printCommands("INIT");
returnedValueUsages.fill(0);
// All this takes place in a full screen quad. // All this takes place in a full screen quad.
const fullScreenQuad = makeFullScreenQuad(regl); const fullScreenQuad = makeFullScreenQuad(regl);
@@ -58,6 +301,8 @@ const init = async () => {
const drawToScreen = regl({ uniforms: screenUniforms }); const drawToScreen = regl({ uniforms: screenUniforms });
await Promise.all(pipeline.map((step) => step.ready)); await Promise.all(pipeline.map((step) => step.ready));
printCommands("LOAD");
const render = ({ viewportWidth, viewportHeight }) => { const render = ({ viewportWidth, viewportHeight }) => {
const now = regl.now() * 1000; const now = regl.now() * 1000;
@@ -67,6 +312,7 @@ const init = async () => {
for (const step of pipeline) { for (const step of pipeline) {
step.setSize(viewportWidth, viewportHeight); step.setSize(viewportWidth, viewportHeight);
} }
printCommands("RESIZE");
} }
fullScreenQuad(() => { fullScreenQuad(() => {
for (const step of pipeline) { for (const step of pipeline) {
@@ -74,11 +320,20 @@ const init = async () => {
} }
drawToScreen(); drawToScreen();
}); });
printCommands("DRAW");
}; };
render({ viewportWidth: 1, viewportHeight: 1 }); render({ viewportWidth: 640, viewportHeight: 480 });
const tick = regl.frame(render); await new Promise(resolve => {
setTimeout(() => resolve(), 1000)
});
render({ viewportWidth: 640, viewportHeight: 480 });
console.log(log.join("\n"));
// const tick = regl.frame(render);
}; };
document.body.onload = () => { document.body.onload = () => {

View File

@@ -115,14 +115,6 @@ export default ({ regl }) => {
framebuffer: computeDoubleBuffer.front, framebuffer: computeDoubleBuffer.front,
}); });
const quadPositions = Array(1)
.fill()
.map((_, y) =>
Array(1)
.fill()
.map((_, x) => Array(numVerticesPerQuad).fill([x, y]))
);
// We render the code into an FBO using MSDFs: https://github.com/Chlumsky/msdfgen // We render the code into an FBO using MSDFs: https://github.com/Chlumsky/msdfgen
const glyphMSDF = loadImage(regl, "assets/matrixcode_msdf.png"); const glyphMSDF = loadImage(regl, "assets/matrixcode_msdf.png");
const output = makePassFBO(regl); const output = makePassFBO(regl);
@@ -137,13 +129,13 @@ export default ({ regl }) => {
vert: ` vert: `
precision lowp float; precision lowp float;
attribute vec2 aPosition, aCorner; attribute vec2 aPosition;
uniform vec2 screenSize; uniform vec2 screenSize;
varying vec2 vUV; varying vec2 vUV;
void main() { void main() {
vUV = aPosition + aCorner; vUV = aPosition;
gl_Position = vec4((aPosition + aCorner - 0.5) * 2.0 * screenSize, 0.0, 1.0); gl_Position = vec4((aPosition - 0.5) * 2.0 * screenSize, 0.0, 1.0);
} }
`, `,
frag: ` frag: `
@@ -232,8 +224,7 @@ export default ({ regl }) => {
}, },
attributes: { attributes: {
aPosition: quadPositions, aPosition: quadVertices,
aCorner: quadVertices,
}, },
count: numVerticesPerQuad, count: numVerticesPerQuad,

1195
lib/webgl-debug.js Normal file

File diff suppressed because it is too large Load Diff