Skip to content

Commit cbbc01e

Browse files
committed
Minor improvements for WebGL 2 and development.
- Basic support for texSubImage3D. - Code support for Renderdoc, which is enabled via a define. - Fix for nodejs issue with detecting instances of buffer types. - Simple conversion for RGBA->RED pixel formats on texture upload.
1 parent 325b6e9 commit cbbc01e

File tree

3 files changed

+115
-26
lines changed

3 files changed

+115
-26
lines changed

src/javascript/utils.js

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,22 +26,26 @@ function checkObject (object) {
2626
(object === undefined)
2727
}
2828

29+
function isInstanceOfType (instance, type) {
30+
return Object.prototype.toString.call(instance) === `[object ${type}]`
31+
}
32+
2933
function checkUniform (program, location) {
3034
return location instanceof WebGLUniformLocation &&
3135
location._program === program &&
3236
location._linkCount === program._linkCount
3337
}
3438

3539
function isTypedArray (data) {
36-
return data instanceof Uint8Array ||
37-
data instanceof Uint8ClampedArray ||
38-
data instanceof Int8Array ||
39-
data instanceof Uint16Array ||
40-
data instanceof Int16Array ||
41-
data instanceof Uint32Array ||
42-
data instanceof Int32Array ||
43-
data instanceof Float32Array ||
44-
data instanceof Float64Array
40+
return isInstanceOfType(data, 'Uint8Array') ||
41+
isInstanceOfType(data, 'Uint8ClampedArray') ||
42+
isInstanceOfType(data, 'Int8Array') ||
43+
isInstanceOfType(data, 'Uint16Array') ||
44+
isInstanceOfType(data, 'Int16Array') ||
45+
isInstanceOfType(data, 'Uint32Array') ||
46+
isInstanceOfType(data, 'Int32Array') ||
47+
isInstanceOfType(data, 'Float32Array') ||
48+
isInstanceOfType(data, 'Float64Array')
4549
}
4650

4751
// Don't allow: ", $, `, @, \, ', \0
@@ -159,6 +163,23 @@ function extractImageData (pixels) {
159163
return null
160164
}
161165

166+
function convertPixelFormats (ctx, pixels, srcFormat, dstFormat) {
167+
switch (srcFormat) {
168+
case ctx.RGBA:
169+
switch (dstFormat) {
170+
case ctx.RGBA:
171+
return pixels
172+
case ctx.RED:
173+
// extract the red channel from pixels, which is in typed array format, and convert to Uint8Array
174+
return new Uint8Array(pixels.filter((_, i) => i % 4 === 0))
175+
default:
176+
throw new Error('unsupported destination format')
177+
}
178+
default:
179+
throw new Error('unsupported source format')
180+
}
181+
}
182+
162183
function formatSize (internalFormat) {
163184
switch (internalFormat) {
164185
case gl.ALPHA:
@@ -176,14 +197,14 @@ function formatSize (internalFormat) {
176197

177198
function convertPixels (pixels) {
178199
if (typeof pixels === 'object' && pixels !== null) {
179-
if (pixels instanceof ArrayBuffer) {
200+
if (isInstanceOfType(pixels, 'ArrayBuffer')) {
180201
return new Uint8Array(pixels)
181-
} else if (pixels instanceof Uint8Array ||
182-
pixels instanceof Uint16Array ||
183-
pixels instanceof Uint8ClampedArray ||
184-
pixels instanceof Float32Array) {
202+
} else if (isInstanceOfType(pixels, 'Uint8Array') ||
203+
isInstanceOfType(pixels, 'Uint16Array') ||
204+
isInstanceOfType(pixels, 'Uint8ClampedArray') ||
205+
isInstanceOfType(pixels, 'Float32Array')) {
185206
return unpackTypedArray(pixels)
186-
} else if (pixels instanceof Buffer) {
207+
} else if (isInstanceOfType(pixels, 'Buffer')) {
187208
return new Uint8Array(pixels)
188209
}
189210
}
@@ -218,6 +239,7 @@ module.exports = {
218239
uniformTypeSize,
219240
unpackTypedArray,
220241
extractImageData,
242+
convertPixelFormats,
221243
formatSize,
222244
checkFormat,
223245
checkUniform,

src/javascript/webgl-rendering-context.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const {
2020
typeSize,
2121
uniformTypeSize,
2222
extractImageData,
23+
convertPixelFormats,
2324
isTypedArray,
2425
unpackTypedArray,
2526
convertPixels,
@@ -2296,6 +2297,8 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext {
22962297
width = pixels.width
22972298
height = pixels.height
22982299
pixels = pixels.data
2300+
2301+
pixels = convertPixelFormats(this, pixels, this.RGBA, format)
22992302
}
23002303

23012304
target |= 0
@@ -2366,6 +2369,8 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext {
23662369
width = pixels.width
23672370
height = pixels.height
23682371
pixels = pixels.data
2372+
2373+
pixels = convertPixelFormats(this, pixels, this.RGBA, format)
23692374
}
23702375

23712376
if (typeof pixels !== 'object') {
@@ -2386,6 +2391,28 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext {
23862391
data)
23872392
}
23882393

2394+
texSubImage3D (target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels) {
2395+
if (pixels === null || pixels === undefined) {
2396+
return
2397+
}
2398+
2399+
if (typeof pixels !== 'object') {
2400+
throw new TypeError('texSubImage3D(GLenum, GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLenum, GLenum, Uint8Array)')
2401+
}
2402+
2403+
if (
2404+
typeof pixels === 'object' &&
2405+
typeof pixels.width !== 'undefined' &&
2406+
typeof pixels.height !== 'undefined'
2407+
) {
2408+
pixels = extractImageData(pixels).data
2409+
pixels = convertPixelFormats(this, pixels, this.RGBA, format)
2410+
}
2411+
const data = convertPixels(pixels)
2412+
2413+
super.texSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, data)
2414+
}
2415+
23892416
texParameterf (target, pname, param) {
23902417
target |= 0
23912418
pname |= 0

src/native/webgl.cc

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@
77

88
#include "webgl.h"
99

10+
#if defined(RENDERDOC_ENABLED)
11+
#include "renderdoc_app.h"
12+
13+
RENDERDOC_API_1_1_2 *rdoc_api = NULL;
14+
#endif
15+
1016
const char *GetDebugMessageSourceString(GLenum source) {
1117
switch (source) {
1218
case GL_DEBUG_SOURCE_API:
@@ -143,6 +149,19 @@ std::string JoinStringSet(const std::set<std::string> &inputSet,
143149
return oss.str();
144150
}
145151

152+
// Helper function to potentially end RenderDoc frame capture after a few draw calls
153+
#if defined(RENDERDOC_ENABLED)
154+
static void MaybeEndRenderDocCapture() {
155+
static int drawCallCounter = 0;
156+
if (drawCallCounter++ == 100 && rdoc_api) {
157+
rdoc_api->EndFrameCapture(NULL, NULL);
158+
printf("RenderDoc capture ended after %d draw calls.\n", drawCallCounter);
159+
drawCallCounter = 0;
160+
rdoc_api->StartFrameCapture(NULL, NULL);
161+
}
162+
}
163+
#endif
164+
146165
bool WebGLRenderingContext::HAS_DISPLAY = false;
147166
EGLDisplay WebGLRenderingContext::DISPLAY;
148167
WebGLRenderingContext *WebGLRenderingContext::ACTIVE = NULL;
@@ -191,6 +210,23 @@ WebGLRenderingContext::WebGLRenderingContext(int width, int height, bool alpha,
191210
unpack_colorspace_conversion(0x9244), unpack_alignment(4),
192211
webGLToANGLEExtensions(&CaseInsensitiveCompare), next(NULL), prev(NULL) {
193212

213+
// Uncomment on Windows to attach debugger
214+
// MessageBox(NULL, "Hello", "Hello", MB_OK);
215+
216+
#if defined(RENDERDOC_ENABLED)
217+
if (!rdoc_api) {
218+
if (HMODULE mod = GetModuleHandleA("renderdoc.dll")) {
219+
pRENDERDOC_GetAPI RENDERDOC_GetAPI =
220+
(pRENDERDOC_GetAPI)GetProcAddress(mod, "RENDERDOC_GetAPI");
221+
int ret = RENDERDOC_GetAPI(eRENDERDOC_API_Version_1_1_2, (void **)&rdoc_api);
222+
printf("RENDERDOC_GetAPI ret: %d %p\n", ret, rdoc_api);
223+
assert(ret == 1);
224+
} else {
225+
printf("renderdoc.dll not found\n");
226+
}
227+
}
228+
#endif
229+
194230
if (!eglGetProcAddress) {
195231
if (!eglLibrary.open("libEGL")) {
196232
errorMessage = "Error opening ANGLE shared library.";
@@ -342,6 +378,12 @@ WebGLRenderingContext::WebGLRenderingContext(int width, int height, bool alpha,
342378
supportedWebGLExtensions.insert(webGLExtension);
343379
}
344380
}
381+
382+
#if defined(RENDERDOC_ENABLED)
383+
if (rdoc_api) {
384+
rdoc_api->StartFrameCapture(NULL, NULL);
385+
}
386+
#endif
345387
}
346388

347389
bool WebGLRenderingContext::setActive() {
@@ -1056,6 +1098,10 @@ GL_METHOD(TexSubImage2D) {
10561098
Nan::TypedArrayContents<unsigned char> pixels(info[8]);
10571099

10581100
if (inst->unpack_flip_y || inst->unpack_premultiply_alpha) {
1101+
if (!*pixels) {
1102+
inst->setError(GL_INVALID_OPERATION);
1103+
return;
1104+
}
10591105
std::vector<uint8_t> unpacked = inst->unpackPixels(type, format, width, height, *pixels);
10601106
glTexSubImage2DRobustANGLE(target, level, xoffset, yoffset, width, height, format, type,
10611107
unpacked.size(), unpacked.data());
@@ -2410,6 +2456,7 @@ GL_METHOD(TexImage3D) {
24102456
GLint border = Nan::To<int32_t>(info[6]).ToChecked();
24112457
GLenum format = Nan::To<int32_t>(info[7]).ToChecked();
24122458
GLenum type = Nan::To<int32_t>(info[8]).ToChecked();
2459+
24132460
if (info[9]->IsUndefined()) {
24142461
glTexImage3D(target, level, internalformat, width, height, depth, border, format, type,
24152462
nullptr);
@@ -2435,17 +2482,10 @@ GL_METHOD(TexSubImage3D) {
24352482
GLsizei depth = Nan::To<int32_t>(info[7]).ToChecked();
24362483
GLenum format = Nan::To<int32_t>(info[8]).ToChecked();
24372484
GLenum type = Nan::To<int32_t>(info[9]).ToChecked();
2438-
if (info[10]->IsUndefined()) {
2439-
glTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type,
2440-
nullptr);
2441-
} else if (info[10]->IsArrayBufferView()) {
2442-
auto buffer = info[10].As<v8::ArrayBufferView>();
2443-
void *bufferPtr = buffer->Buffer()->GetBackingStore()->Data();
2444-
glTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type,
2445-
bufferPtr);
2446-
} else {
2447-
Nan::ThrowTypeError("Invalid data type for TexSubImage3D");
2448-
}
2485+
Nan::TypedArrayContents<unsigned char> pixels(info[10]);
2486+
2487+
glTexSubImage3DRobustANGLE(target, level, xoffset, yoffset, zoffset, width, height, depth, format,
2488+
type, pixels.length(), *pixels);
24492489
}
24502490

24512491
GL_METHOD(CopyTexSubImage3D) {

0 commit comments

Comments
 (0)