@@ -60,6 +60,9 @@ import {
60
60
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
61
61
*/
62
62
63
+
64
+ const augmentedSet = new Set ( ) ;
65
+
63
66
/**
64
67
* Given a WebGL context replaces all the functions with wrapped functions
65
68
* that call gl.getError after every command
@@ -68,11 +71,11 @@ import {
68
71
* @param {string } nameOfClass (eg, webgl, webgl2, OES_texture_float)
69
72
*/
70
73
export function augmentAPI ( ctx , nameOfClass , options = { } ) {
71
- // Only augment this object once
72
- if ( ctx . __webgl_memory_augmented ) {
74
+
75
+ if ( augmentedSet . has ( ctx ) ) {
73
76
return ctx ;
74
77
}
75
- ctx . __webgl_memory_augmented = true ;
78
+ augmentedSet . add ( ctx ) ;
76
79
77
80
const origGLErrorFn = options . origGLErrorFn || ctx . getError ;
78
81
@@ -81,20 +84,23 @@ export function augmentAPI(ctx, nameOfClass, options = {}) {
81
84
const sharedState = {
82
85
baseContext : ctx ,
83
86
config : options ,
84
- customExtensions : {
87
+ apis : {
88
+ // custom extension
85
89
gman_webgl_memory : {
86
- getMemoryInfo ( ) {
87
- const drawingbuffer = computeDrawingbufferSize ( ctx , drawingBufferInfo ) ;
88
- return {
89
- memory : {
90
- ...memory ,
91
- drawingbuffer,
92
- total : drawingbuffer + memory . buffer + memory . texture + memory . renderbuffer ,
93
- } ,
94
- resources : {
95
- ...resources ,
96
- } ,
97
- } ;
90
+ ctx : {
91
+ getMemoryInfo ( ) {
92
+ const drawingbuffer = computeDrawingbufferSize ( ctx , drawingBufferInfo ) ;
93
+ return {
94
+ memory : {
95
+ ...memory ,
96
+ drawingbuffer,
97
+ total : drawingbuffer + memory . buffer + memory . texture + memory . renderbuffer ,
98
+ } ,
99
+ resources : {
100
+ ...resources ,
101
+ }
102
+ } ;
103
+ } ,
98
104
} ,
99
105
} ,
100
106
} ,
@@ -109,6 +115,12 @@ export function augmentAPI(ctx, nameOfClass, options = {}) {
109
115
webglObjectToMemory : new Map ( ) ,
110
116
} ;
111
117
118
+ const unRestorableAPIs = new Set ( [
119
+ 'webgl' ,
120
+ 'webgl2' ,
121
+ 'webgl_lose_context' ,
122
+ ] ) ;
123
+
112
124
function resetSharedState ( ) {
113
125
sharedState . bindings . clear ( ) ;
114
126
sharedState . webglObjectToMemory . clear ( ) ;
@@ -121,8 +133,46 @@ export function augmentAPI(ctx, nameOfClass, options = {}) {
121
133
} ) ;
122
134
}
123
135
136
+ function handleContextLost ( ) {
137
+ // Issues:
138
+ // * all resources are lost.
139
+ // Solution: handled by resetSharedState
140
+ // * all functions are no-op
141
+ // Solutions:
142
+ // * swap all functions for noop
143
+ // (not so easy because some functions return values)
144
+ // * wrap all functions is a isContextLost check forwarder
145
+ // (slow? and same as above)
146
+ // * have each function manually check for context lost
147
+ // (simple but repetitive)
148
+ // * all extensions are lost
149
+ // Solution: For these we go through and restore all the functions
150
+ // on each extension
151
+ resetSharedState ( ) ;
152
+ sharedState . isContextLost = true ;
153
+
154
+ // restore all original functions for extensions since
155
+ // user will have to get new extensions.
156
+ for ( const [ name , { ctx, origFuncs} ] of [ ...Object . entries ( sharedState . apis ) ] ) {
157
+ if ( ! unRestorableAPIs . has ( name ) && origFuncs ) {
158
+ augmentedSet . delete ( ctx ) ;
159
+ for ( const [ funcName , origFn ] of Object . entries ( origFuncs ) ) {
160
+ ctx [ funcName ] = origFn
161
+ }
162
+ delete apis [ name ] ;
163
+ }
164
+ }
165
+ }
166
+
167
+ function handleContextRestored ( ) {
168
+ sharedState . isContextLost = false ;
169
+ }
170
+
124
171
if ( ctx . canvas ) {
125
- ctx . canvas . addEventListener ( 'webglcontextlost' , resetSharedState ) ;
172
+ ctx . canvas . addEventListener ( 'webglcontextlost' , handleContextLost ) ;
173
+ ctx . canvas . addEventListener ( 'contextlost' , handleContextLost ) ;
174
+ ctx . canvas . addEventListener ( 'webglcontextrestored' , handleContextRestored ) ;
175
+ ctx . canvas . addEventListener ( 'contextrestored' , handleContextRestored ) ;
126
176
}
127
177
128
178
resetSharedState ( ) ;
@@ -133,13 +183,17 @@ export function augmentAPI(ctx, nameOfClass, options = {}) {
133
183
options . sharedState = sharedState ;
134
184
135
185
const {
186
+ apis,
187
+ baseContext,
136
188
bindings,
189
+ config,
137
190
memory,
138
191
resources,
139
192
webglObjectToMemory,
140
- customExtensions,
141
193
} = sharedState ;
142
194
195
+ const origFuncs = { } ;
196
+
143
197
function noop ( ) {
144
198
}
145
199
@@ -150,6 +204,9 @@ export function augmentAPI(ctx, nameOfClass, options = {}) {
150
204
}
151
205
resources [ typeName ] = 0 ;
152
206
return function ( ctx , funcName , args , webglObj ) {
207
+ if ( sharedState . isContextLost ) {
208
+ return null ;
209
+ }
153
210
++ resources [ typeName ] ;
154
211
webglObjectToMemory . set ( webglObj , {
155
212
size : 0 ,
@@ -163,6 +220,9 @@ export function augmentAPI(ctx, nameOfClass, options = {}) {
163
220
return ;
164
221
}
165
222
return function ( ctx , funcName , args ) {
223
+ if ( sharedState . isContextLost ) {
224
+ return ;
225
+ }
166
226
const [ obj ] = args ;
167
227
const info = webglObjectToMemory . get ( obj ) ;
168
228
if ( info ) {
@@ -175,6 +235,9 @@ export function augmentAPI(ctx, nameOfClass, options = {}) {
175
235
}
176
236
177
237
function updateRenderbuffer ( target , samples , internalFormat , width , height ) {
238
+ if ( sharedState . isContextLost ) {
239
+ return ;
240
+ }
178
241
const obj = bindings . get ( target ) ;
179
242
if ( ! obj ) {
180
243
throw new Error ( `no renderbuffer bound to ${ target } ` ) ;
@@ -275,11 +338,17 @@ export function augmentAPI(ctx, nameOfClass, options = {}) {
275
338
}
276
339
277
340
function handleBindVertexArray ( gl , funcName , args ) {
341
+ if ( sharedState . isContextLost ) {
342
+ return ;
343
+ }
278
344
const [ va ] = args ;
279
345
sharedState . currentVertexArray = va ? va : sharedState . defaultVertexArray ;
280
346
}
281
347
282
348
function handleBufferBinding ( target , obj ) {
349
+ if ( sharedState . isContextLost ) {
350
+ return ;
351
+ }
283
352
switch ( target ) {
284
353
case ELEMENT_ARRAY_BUFFER :
285
354
const info = webglObjectToMemory . get ( sharedState . currentVertexArray ) ;
@@ -300,6 +369,9 @@ export function augmentAPI(ctx, nameOfClass, options = {}) {
300
369
// void bufferData(GLenum target, [AllowShared] ArrayBufferView srcData, GLenum usage, GLuint srcOffset,
301
370
// optional GLuint length = 0);
302
371
bufferData ( gl , funcName , args ) {
372
+ if ( sharedState . isContextLost ) {
373
+ return ;
374
+ }
303
375
const [ target , src , /* usage */ , srcOffset = 0 , length = undefined ] = args ;
304
376
let obj ;
305
377
switch ( target ) {
@@ -356,17 +428,26 @@ export function augmentAPI(ctx, nameOfClass, options = {}) {
356
428
} ,
357
429
358
430
bindRenderbuffer ( gl , funcName , args ) {
431
+ if ( sharedState . isContextLost ) {
432
+ return ;
433
+ }
359
434
const [ target , obj ] = args ;
360
435
bindings . set ( target , obj ) ;
361
436
} ,
362
437
363
438
bindTexture ( gl , funcName , args ) {
439
+ if ( sharedState . isContextLost ) {
440
+ return ;
441
+ }
364
442
const [ target , obj ] = args ;
365
443
bindings . set ( target , obj ) ;
366
444
} ,
367
445
368
446
// void gl.copyTexImage2D(target, level, internalformat, x, y, width, height, border);
369
447
copyTexImage2D ( ctx , funcName , args ) {
448
+ if ( sharedState . isContextLost ) {
449
+ return ;
450
+ }
370
451
const [ target , level , internalFormat , x , y , width , height , border ] = args ;
371
452
const info = getTextureInfo ( target ) ;
372
453
updateMipLevel ( info , target , level , internalFormat , width , height , 1 , UNSIGNED_BYTE ) ;
@@ -393,6 +474,9 @@ export function augmentAPI(ctx, nameOfClass, options = {}) {
393
474
// void gl.compressedTexImage2D(target, level, internalformat, width, height, border,
394
475
// ArrayBufferView srcData, optional srcOffset, optional srcLengthOverride);
395
476
compressedTexImage2D ( ctx , funcName , args ) {
477
+ if ( sharedState . isContextLost ) {
478
+ return ;
479
+ }
396
480
const [ target , level , internalFormat , width , height ] = args ;
397
481
const info = getTextureInfo ( target ) ;
398
482
updateMipLevel ( info , target , level , internalFormat , width , height , 1 , UNSIGNED_BYTE ) ;
@@ -403,6 +487,9 @@ export function augmentAPI(ctx, nameOfClass, options = {}) {
403
487
// void gl.compressedTexImage3D(target, level, internalformat, width, height, depth, border,
404
488
// ArrayBufferView srcData, optional srcOffset, optional srcLengthOverride);
405
489
compressedTexImage3D ( ctx , funcName , args ) {
490
+ if ( sharedState . isContextLost ) {
491
+ return ;
492
+ }
406
493
const [ target , level , internalFormat , width , height , depth ] = args ;
407
494
const info = getTextureInfo ( target ) ;
408
495
updateMipLevel ( info , target , level , internalFormat , width , height , depth , UNSIGNED_BYTE ) ;
@@ -428,6 +515,9 @@ export function augmentAPI(ctx, nameOfClass, options = {}) {
428
515
deleteVertexArrayOES : makeDeleteWrapper ( 'vertexArray' , noop , 'deleteVertexArrayOES' ) ,
429
516
430
517
fenceSync : function ( ctx ) {
518
+ if ( sharedState . isContextLost ) {
519
+ return ;
520
+ }
431
521
if ( ! ctx . fenceSync ) {
432
522
return ;
433
523
}
@@ -442,6 +532,9 @@ export function augmentAPI(ctx, nameOfClass, options = {}) {
442
532
} ( ctx ) ,
443
533
444
534
generateMipmap ( ctx , funcName , args ) {
535
+ if ( sharedState . isContextLost ) {
536
+ return ;
537
+ }
445
538
const [ target ] = args ;
446
539
const info = getTextureInfo ( target ) ;
447
540
const baseMipNdx = info . parameters ? info . parameters . get ( TEXTURE_BASE_LEVEL ) || 0 : 0 ;
@@ -463,6 +556,9 @@ export function augmentAPI(ctx, nameOfClass, options = {}) {
463
556
} ,
464
557
465
558
getSupportedExtensions ( ctx , funcName , args , result ) {
559
+ if ( sharedState . isContextLost ) {
560
+ return ;
561
+ }
466
562
result . push ( 'GMAN_webgl_memory' ) ;
467
563
} ,
468
564
@@ -485,6 +581,9 @@ export function augmentAPI(ctx, nameOfClass, options = {}) {
485
581
} ,
486
582
487
583
texImage2D ( ctx , funcName , args ) {
584
+ if ( sharedState . isContextLost ) {
585
+ return ;
586
+ }
488
587
// WebGL1:
489
588
// void gl.texImage2D(target, level, internalformat, width, height, border, format, type, ArrayBufferView? pixels);
490
589
// void gl.texImage2D(target, level, internalformat, format, type, ImageData? pixels);
@@ -531,12 +630,18 @@ export function augmentAPI(ctx, nameOfClass, options = {}) {
531
630
// void gl.texImage3D(target, level, internalformat, width, height, depth, border, format, type, ArrayBufferView srcData, srcOffset);
532
631
533
632
texImage3D ( ctx , funcName , args ) {
633
+ if ( sharedState . isContextLost ) {
634
+ return ;
635
+ }
534
636
let [ target , level , internalFormat , width , height , depth , border , format , type ] = args ;
535
637
const info = getTextureInfo ( target ) ;
536
638
updateMipLevel ( info , target , level , internalFormat , width , height , depth , type ) ;
537
639
} ,
538
640
539
641
texParameteri ( ctx , funcName , args ) {
642
+ if ( sharedState . isContextLost ) {
643
+ return ;
644
+ }
540
645
let [ target , pname , value ] = args ;
541
646
const info = getTextureInfo ( target ) ;
542
647
info . parameters = info . parameters || new Map ( ) ;
@@ -558,17 +663,21 @@ export function augmentAPI(ctx, nameOfClass, options = {}) {
558
663
559
664
const extraWrappers = {
560
665
getExtension ( ctx , propertyName ) {
666
+ if ( sharedState . isContextLost ) {
667
+ return null ;
668
+ }
561
669
const origFn = ctx [ propertyName ] ;
562
670
ctx [ propertyName ] = function ( ...args ) {
563
671
const extensionName = args [ 0 ] . toLowerCase ( ) ;
564
- let ext = customExtensions [ extensionName ] ;
565
- if ( ! ext ) {
566
- ext = origFn . call ( ctx , ...args ) ;
567
- if ( ext ) {
568
- augmentAPI ( ext , extensionName , { ...options , origGLErrorFn } ) ;
569
- }
672
+ const api = apis [ extensionName ] ;
673
+ if ( api ) {
674
+ return api . ctx ;
570
675
}
571
- return ext || null ;
676
+ const ext = origFn . call ( ctx , ...args ) ;
677
+ if ( ext ) {
678
+ augmentAPI ( ext , extensionName , { ...options , origGLErrorFn} ) ;
679
+ }
680
+ return ext ;
572
681
} ;
573
682
} ,
574
683
} ;
@@ -596,8 +705,11 @@ export function augmentAPI(ctx, nameOfClass, options = {}) {
596
705
// Wrap each function
597
706
for ( const propertyName in ctx ) {
598
707
if ( typeof ctx [ propertyName ] === 'function' ) {
708
+ origFuncs [ propertyName ] = ctx [ propertyName ] ;
599
709
makeErrorWrapper ( ctx , propertyName ) ;
600
710
}
601
711
}
712
+
713
+ apis [ nameOfClass . toLowerCase ( ) ] = { ctx, origFuncs } ;
602
714
}
603
715
0 commit comments