{"id":19218195,"url":"https://github.com/greggman/webgl-helpers","last_synced_at":"2025-05-13T00:13:12.319Z","repository":{"id":48696780,"uuid":"223777694","full_name":"greggman/webgl-helpers","owner":"greggman","description":"some tiny webgl scripts that might come in handy","archived":false,"fork":false,"pushed_at":"2023-07-12T16:20:38.000Z","size":20434,"stargazers_count":58,"open_issues_count":0,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-05-13T00:13:05.610Z","etag":null,"topics":["webgl","webgl2"],"latest_commit_sha":null,"homepage":"https://greggman.github.io/webgl-helpers/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/greggman.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-11-24T16:51:27.000Z","updated_at":"2025-01-05T09:42:30.000Z","dependencies_parsed_at":"2024-11-09T14:36:30.459Z","dependency_job_id":null,"html_url":"https://github.com/greggman/webgl-helpers","commit_stats":{"total_commits":65,"total_committers":2,"mean_commits":32.5,"dds":0.09230769230769231,"last_synced_commit":"3d058136963b4495cfd86625d950e803852010a3"},"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/greggman%2Fwebgl-helpers","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/greggman%2Fwebgl-helpers/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/greggman%2Fwebgl-helpers/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/greggman%2Fwebgl-helpers/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/greggman","download_url":"https://codeload.github.com/greggman/webgl-helpers/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253843222,"owners_count":21972874,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["webgl","webgl2"],"created_at":"2024-11-09T14:25:39.933Z","updated_at":"2025-05-13T00:13:12.293Z","avatar_url":"https://github.com/greggman.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# WebGL Helpers\n\nSome scripts and debugger snippets that might come in handy.\n\n## Show Info\n\nShows how many vertices, instances, and draw calls \nare happening per frame as well as the amount of data\nbeing passed to WebGL via functions like `bufferSubData`\nand `texSubImage2D`.\n\n\u003cimg src=\"https://greggman.github.io/webgl-helpers/images/webgl-show-info.png\" /\u003e\n\nSee Live Example [here](https://greggman.github.io/webgl-helpers/examples/unity/index-webgl-show-info.html).\n\nClicking the info box will show per function counts for the functions being tracked.\n\nTo use, add this script before your other scripts\n\n```html\n\u003cscript src=\"https://greggman.github.io/webgl-helpers/webgl-show-info.js\"\u003e\u003c/script\u003e\n```\n\nIt inserts a `\u003cdiv\u003e` in the `\u003cbody\u003e` of the page and gives it a CSS class name of `webgl-show-info`\nso you can position with with `.webgl-show-info { right: 0; bottom: 0; }` etc...\n\nSome things to note:\n\nCertain things are marked in `red`.\n\n* updating `ELEMENT_ARRAY_BUFFER` buffers can cause perf issues because WebGL is required\n  to make sure no indices are out of bounds. WebGL implementations usually cache this info\n  but if you update the buffer they have to invalidate their cache for that buffer.\n\n  Of course if you can't avoid updating indices then you'll have to live with whatever the\n  perf hit is but if you can redesign so you don't need to update the indices you might find\n  some perf gains.\n\n* Calling any `getXXX` function every frame can cause perf issues. Common things are\n  calling `gl.getUniformLocation` or `gl.getAttribLocation` every frame instead of just\n  looking them up at init time. The same for example for `gl.checkFramebuffer`. Do it once\n  at init time. If you need different arrangements of framebuffer attachments then make\n  multiple framebuffers at init time.\n\n* Setting up vertex attributes (calling `gl.vertexAttribPointer`, `gl.enableVertexAttribArray`, etc....\n  If you want perf you should really be using vertex arrays (ie, `gl.createVertexArray`, `gl.bindVertexArray`).\n  To be honest, every WebGL app I've ever written breaks this rule because WebGL1 didn't support\n  vertex arrays without an extension.\n\nAlso, remember that **Premature Optimization is the root of all evil**. The majority of WebGL out there\njust doesn't do enough work that these optimizations will matter. But, if you happen to be getting near\nthe limits then these are places you might look for perf gains.\n\nRemember though, find the biggest perf issues first. If you have lots of overdraw, or slow complex shaders,\nor a complex post processing pipeline doing a bunch of passes, or you're just drawing way to much stuff,\nthe thing above are probably not your bottleneck.\n\nHere's a script you can paste into the JavaScript console to use on a running page\n\n```js\n(()=\u003e{const s = document.createElement('script');s.src='https://greggman.github.io/webgl-helpers/webgl-show-info.js';document.firstElementChild.appendChild(s)})();\n```\n\n## glEnumToString\n\nA simple one, incomplete, but useful in a pinch.\n\n```\nfunction glEnumToString(value) {\n  const keys = [];\n  for (const key in WebGL2RenderingContext) {\n    if (WebGL2RenderingContext[key] === value) {\n      keys.push(key);\n    }\n  }\n  return keys.length ? keys.join(' | ') : `0x${value.toString(16)}`;\n}\n```\n\nThe issue with it being incomplete it some enums are specified on extensions. \nOne that covers all enums is a little too involved. Also, GL unfortunately\nchose `0` for 4 different values. `NONE`, `POINTS`, `FALSE`, `NO_ERROR` which\nis why the `join` above. Otherwise you'd need to know the function the value\nis going to be used with in order to return the correct string.\n\n## Show the available extensions\n\n```\nconsole.log(document.createElement(\"canvas\").getContext(\"webgl\").getSupportedExtensions().join('\\n'));\nconsole.log(document.createElement(\"canvas\").getContext(\"webgl2\").getSupportedExtensions().join('\\n'));\n```\n\n## Show the VENDOR / RENDERER\n\nShow both `low-power` and `high-performance`\n\n```\n{\n    for (const powerPreference of [\"low-power\", \"high-performance\"]) {\n        const gl = document.createElement(\"canvas\").getContext(\"webgl\");\n        const ext = gl.getExtension(\"WEBGL_debug_renderer_info\");\n        console.log(`${powerPreference}\\n${[\"VENDOR\", \"RENDERER\", \"UNMASKED_RENDERER_WEBGL\", \"UNMASKED_VENDOR_WEBGL\"].map(name =\u003e {\n            const pname = ext[name] || gl[name];\n            return pname ? `${name}: ${gl.getParameter(pname)}` : \"\";\n        }).filter(v =\u003e v).join('\\n')}`);\n    }\n}\n```\n\nShow the default (usually `low-power` but up to the browser). Also, if you have a variable `gl` or some other context just delete the first line or change to `gl = \u003cidentifierForYourContext\u003e`\n\n```\n{\n    const gl = document.createElement(\"canvas\").getContext(\"webgl\");\n    const ext = gl.getExtension(\"WEBGL_debug_renderer_info\");\n    console.log([\"VENDOR\", \"RENDERER\", \"UNMASKED_RENDERER_WEBGL\", \"UNMASKED_VENDOR_WEBGL\"].map(name =\u003e {\n        const pname = ext[name] || gl[name];\n        return pname ? `${name}: ${gl.getParameter(pname)}` : \"\";\n    }).filter(v =\u003e v).join('\\n'));\n}\n```\n\n\n## Print out *most* of the limits\n\n```\n{\n    const gl = document.createElement('canvas').getContext('webgl2');\n    const m = {};\n    for (const key in gl) {\n      if (key.startsWith(\"MAX_\")) {\n          m[key] = gl.getParameter(gl[key]);\n      }\n    }\n    console.log(JSON.stringify(m, null, 2));\n}\n```\n\nYou could just go to [webglreport.com](https://webglreport.com) to see the limits but I needed to be able to compare.\n\n```\na = \u003cdata from above on machine 1\u003e\nb = \u003cdata from above on machine 2\u003e\nconsole.log(Object.entries(a).map(([k, v]) =\u003e `${v.toString().padStart(10)} ${b[k].toString().padStart(10)} : ${k}`).join('\\n'))\n```\n\n## Spy on draw calls\n\nCopy and paste this into the JavaScript console\n\n```\n(()=\u003e{const s = document.createElement('script');s.src='https://greggman.github.io/webgl-helpers/webgl-show-draw-calls.js';document.firstElementChild.appendChild(s)})();\n```\n\nor copy and pasted [the entire file](https://raw.githubusercontent.com/greggman/webgl-helpers/master/webgl-show-draw-calls.js) into the JavaScript console.\n\nExample, select the correct context, then copy and paste\n\n\u003cimg src=\"https://greggman.github.io/webgl-helpers/images/log-draw-calls-jsconsole.gif\" /\u003e\n\nOr use \n\n```\n\u003cscript src=\"https://greggman.github.io/webgl-helpers/webgl-show-draw-calls.js\"\u003e\u003c/script\u003e\n```\n\n# scripts to use when you're including a 3rd party WebGL lib (Unity, three.js, etc...)\n\n## webgl-log-shaders.js\n\nWant to dump shaders, add this script at the top of your HTML file\n\n```\n\u003cscript src=\"https://greggman.github.io/webgl-helpers/webgl-log-shaders.js\"\u003e\u003c/script\u003e\n```\n\nFor example [here's a Unity example with the script above added to the top of the HTML file](https://greggman.github.io/webgl-helpers/examples/unity/index-log-shaders.html).\n\n\u003cimg src=\"https://greggman.github.io/webgl-helpers/images/unity-log-shaders.png\" /\u003e\n\nAnd here's [the same with three.js](https://greggman.github.io/webgl-helpers/examples/threejs/).\n\n\u003cimg src=\"https://greggman.github.io/webgl-helpers/images/threejs-log-shaders.png\" /\u003e\n\n## webgl-bad-log-shaders.js\n\nSame as above but only logs a shader if it fails to compile. This can be useful\nif you have a big project like a Unity project and you want to extract the\nshader to file an [MCVE bug report](https://en.wikipedia.org/wiki/Minimal_reproducible_example).\n\nAdd this to the top of your HTML file\n\n```\n\u003cscript src=\"https://greggman.github.io/webgl-helpers/webgl-log-bad-shaders.js\"\u003e\u003c/script\u003e\n```\n\nIf a shader fails to compile or a program fails to link it will print an error and their source code to the console.\n\n## webgl-dump-shaders.js\n\nSame as above except you can possibly copy and paste this contents into the JS console.\n\n```\n(()=\u003e{const s = document.createElement('script');s.src='https://greggman.github.io/webgl-helpers/webgl-dump-shaders.js';document.firstElementChild.appendChild(s)})();\n```\n\nFor example Google Maps\n\n\u003cimg src=\"https://greggman.github.io/webgl-helpers/images/dump-shaders-google-maps.png\" /\u003e\n\nNote: This doesn't always work if the app deletes/detaches its shaders from its programs. Another method to dump shaders\nis to open the JavaScript console, add a breakpoint early in the page's JavaScript. When the breakpoint hits,\npaste the following into the JavaScript console.\n\n```js\nWebGL2RenderingContext.prototype.shaderSource = (function(origFn) {\n    return function(shader, source) {\n        origFn.call(this, shader, source);\n        console.log(source);\n    };\n})(WebGL2RenderingContext.prototype.shaderSource);\nWebGLRenderingContext.prototype.shaderSource = (function(origFn) {\n    return function(shader, source) {\n        origFn.call(this, shader, source);\n        console.log(source);\n    };\n})(WebGLRenderingContext.prototype.shaderSource);\n```\n\nThe continue the JavaScript execution.\n\n## webgl-disable2.js\n\nDisables WebGL2. Useful to force something to use WebGL1 assuming it can handle both\n\n```\n\u003cscript src=\"https://greggman.github.io/webgl-helpers/webgl2-disable.js\"\u003e\u003c/script\u003e\n```\n\n## webgl-force-preservedrawingbuffer.js\n\nForces `preserveDrawingBuffer: true`.\n\nMaybe you want to take a screenshot of some canvas that another script is controlling.\n\n```\n\u003cscript src=\"https://greggman.github.io/webgl-helpers/webgl-force-preservedrawingbuffer.js\"\u003e\u003c/script\u003e\n```\n\nExample:\n\n* [without script](https://greggman.github.io/webgl-helpers/examples/2d-lines.html)\n* [with script](https://greggman.github.io/webgl-helpers/examples/2d-lines-force-preservedrawingbuffer.html)\n\n\u003cimg src=\"https://greggman.github.io/webgl-helpers/images/preservedrawingbuffer.png\" /\u003e\n\n## webgl-force-alpha-true.js\n## webgl-force-alpha-false.js\n\nForces `alpha: true` or `alpha: false`\n\nCould be useful if you can't figure out how to get a certain library to\nbe one or the other. For example the myriad of poorly documented ways\nthat emscripten creates a canvas.\n\n```\n\u003cscript src=\"https://greggman.github.io/webgl-helpers/webgl-force-alpha-true.js\"\u003e\u003c/script\u003e\n```\n\n```\n\u003cscript src=\"https://greggman.github.io/webgl-helpers/webgl-force-alpha-false.js\"\u003e\u003c/script\u003e\n```\n\n## webgl-force-premultipliedalpha-true.js\n## webgl-force-premultipliedalpha-false.js\n\nForces `premultipliedAlpha: true` or `premultipliedAlpha: false`\n\nCould be useful if you can't figure out how to get a certain library to\nbe one or the other. For example the myriad of poorly documented ways\nthat emscripten creates a canvas.\n\n```\n\u003cscript src=\"https://greggman.github.io/webgl-helpers/webgl-force-premultipliedalpha-true.js\"\u003e\u003c/script\u003e\n```\n\n```\n\u003cscript src=\"https://greggman.github.io/webgl-helpers/webgl-force-premultipliedalpha-false.js\"\u003e\u003c/script\u003e\n```\n\n## webgl-force-powerpreference-low-power.js\n## webgl-force-powerpreference-high-performance.js\n\nForces the powerPreference setting.\n\nCould be useful if the library you're using has no way to set this\nand you want it to be something other than the default.\n\n```\n\u003cscript src=\"https://greggman.github.io/webgl-helpers/webgl-powerpreference-low-power.js\"\u003e\u003c/script\u003e\n```\n\n```\n\u003cscript src=\"https://greggman.github.io/webgl-helpers/webgl-powerpreference-high-performance.js\"\u003e\u003c/script\u003e\n```\n\n## webgl-gl-error-check.js\n\nThis script has moved to [https://github.com/greggman/webgl-lint](https://github.com/greggman/webgl-lint)\n\n# Other useful things\n\n* [virtual-webgl](https://github.com/greggman/virtual-webgl): A library to virtualize WebGL to surpass the context limit\n* [webgl-capture](https://github.com/greggman/webgl-capture/): A library to capture GL calls into a reproducible webpage\n* [twgl](https://twgljs.org): A library to simplify using WebGL\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgreggman%2Fwebgl-helpers","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgreggman%2Fwebgl-helpers","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgreggman%2Fwebgl-helpers/lists"}