Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,12 @@ Once this is done, you should be good to go! A few more things

Note: the `gl-conformance` package is currently hosted on GitHub Package Registry. To install from there, you may need to add `//npm.pkg.github.com` to your user directory's `.npmrc` file

### Debugging with RenderDoc

To debug with RenderDoc, you can set the `RENDERDOC_ENABLED` define in the `src/native/webgl.cc` file.

You'll need to also install RenderDoc and attach it to the gl process when you launch your program. The easiest way to attach to the running process is to uncomment the MessageBoxA call in the `src/native/webgl.cc` file.

## License

See LICENSES
53 changes: 38 additions & 15 deletions src/javascript/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,27 @@ function checkObject (object) {
(object === undefined)
}

// Works around the fact that "instanceof" doesn't work for polyfilled types
function isInstanceOfType (instance, type) {
return Object.prototype.toString.call(instance) === `[object ${type}]`
}

function checkUniform (program, location) {
return location instanceof WebGLUniformLocation &&
location._program === program &&
location._linkCount === program._linkCount
}

function isTypedArray (data) {
return data instanceof Uint8Array ||
data instanceof Uint8ClampedArray ||
data instanceof Int8Array ||
data instanceof Uint16Array ||
data instanceof Int16Array ||
data instanceof Uint32Array ||
data instanceof Int32Array ||
data instanceof Float32Array ||
data instanceof Float64Array
return isInstanceOfType(data, 'Uint8Array') ||
Copy link
Member

@dhritzkiv dhritzkiv May 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you briefly describe the issues in node with checking if it's a typed array with instanceof ? Something to do with tests / use in a vm module?

This looks fine, I'm more curious for myself – and perhaps there's a another, simpler yet still foolproof version.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a comment to "isInstanceOfType". The issue I think was coming from Webpack, which was supplying some kind of polyfill that broke instanceof. I didn't 100% root cause the issue to the point where I know who was responsible, but I am certain that instanceof was failing in this case and comparing the type string did work properly for our case.

isInstanceOfType(data, 'Uint8ClampedArray') ||
isInstanceOfType(data, 'Int8Array') ||
isInstanceOfType(data, 'Uint16Array') ||
isInstanceOfType(data, 'Int16Array') ||
isInstanceOfType(data, 'Uint32Array') ||
isInstanceOfType(data, 'Int32Array') ||
isInstanceOfType(data, 'Float32Array') ||
isInstanceOfType(data, 'Float64Array')
}

// Don't allow: ", $, `, @, \, ', \0
Expand Down Expand Up @@ -159,6 +164,23 @@ function extractImageData (pixels) {
return null
}

function convertPixelFormats (ctx, pixels, srcFormat, dstFormat) {
switch (srcFormat) {
case ctx.RGBA:
switch (dstFormat) {
case ctx.RGBA:
return pixels
case ctx.RED:
// extract the red channel from pixels, which is in typed array format, and convert to Uint8Array
return new Uint8Array(pixels.filter((_, i) => i % 4 === 0))
default:
throw new Error('unsupported destination format')
}
default:
throw new Error('unsupported source format')
}
}

function formatSize (internalFormat) {
switch (internalFormat) {
case gl.ALPHA:
Expand All @@ -176,14 +198,14 @@ function formatSize (internalFormat) {

function convertPixels (pixels) {
if (typeof pixels === 'object' && pixels !== null) {
if (pixels instanceof ArrayBuffer) {
if (isInstanceOfType(pixels, 'ArrayBuffer')) {
return new Uint8Array(pixels)
} else if (pixels instanceof Uint8Array ||
pixels instanceof Uint16Array ||
pixels instanceof Uint8ClampedArray ||
pixels instanceof Float32Array) {
} else if (isInstanceOfType(pixels, 'Uint8Array') ||
isInstanceOfType(pixels, 'Uint16Array') ||
isInstanceOfType(pixels, 'Uint8ClampedArray') ||
isInstanceOfType(pixels, 'Float32Array')) {
return unpackTypedArray(pixels)
} else if (pixels instanceof Buffer) {
} else if (isInstanceOfType(pixels, 'Buffer')) {
return new Uint8Array(pixels)
}
}
Expand Down Expand Up @@ -218,6 +240,7 @@ module.exports = {
uniformTypeSize,
unpackTypedArray,
extractImageData,
convertPixelFormats,
formatSize,
checkFormat,
checkUniform,
Expand Down
26 changes: 26 additions & 0 deletions src/javascript/webgl-rendering-context.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const {
typeSize,
uniformTypeSize,
extractImageData,
convertPixelFormats,
isTypedArray,
unpackTypedArray,
convertPixels,
Expand Down Expand Up @@ -2303,6 +2304,8 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext {
width = pixels.width
height = pixels.height
pixels = pixels.data

pixels = convertPixelFormats(this, pixels, this.RGBA, format)
}

target |= 0
Expand Down Expand Up @@ -2373,6 +2376,8 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext {
width = pixels.width
height = pixels.height
pixels = pixels.data

pixels = convertPixelFormats(this, pixels, this.RGBA, format)
}

if (typeof pixels !== 'object') {
Expand All @@ -2393,6 +2398,27 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext {
data)
}

texSubImage3D (target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels) {
if (pixels === null || pixels === undefined) {
return
}

if (typeof pixels !== 'object') {
throw new TypeError('texSubImage3D(GLenum, GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLenum, GLenum, Uint8Array)')
}

if (
typeof pixels.width !== 'undefined' &&
typeof pixels.height !== 'undefined'
) {
pixels = extractImageData(pixels).data
pixels = convertPixelFormats(this, pixels, this.RGBA, format)
}
const data = convertPixels(pixels)

super.texSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, data)
}

texParameterf (target, pname, param) {
target |= 0
pname |= 0
Expand Down
Loading
Loading