@geastack/native-webgl-angle 0.1.12 → 0.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/geatsc-plugin-readback.mjs +21 -0
- package/geatsc-plugin-uniforms.mjs +214 -59
- package/geatsc-plugin-uploads.mjs +7 -2
- package/geatsc-plugin.mjs +912 -67
- package/native/angle_webgl_host.mm +217 -22
- package/package.json +1 -1
- package/src/inflate.ts +1 -1
- package/src/nativeWebGL.ts +67 -13
- package/src/nativeWebGLHost.ts +19 -0
package/geatsc-plugin.mjs
CHANGED
|
@@ -98,6 +98,13 @@ const hostFunctions = [
|
|
|
98
98
|
...nativeUploadFunctions,
|
|
99
99
|
...nativeReadbackFunctions,
|
|
100
100
|
['threeWebGLBlitFramebuffer','gea_three_webgl_blit_framebuffer','void','extern "C" void gea_three_webgl_blit_framebuffer(double,double,double,double,double,double,double,double,double,double);'],
|
|
101
|
+
['threeWebGLReadPixelsPack','gea_three_webgl_read_pixels_pack','void','extern "C" void gea_three_webgl_read_pixels_pack(double,double,double,double,double,double,double);'],
|
|
102
|
+
['threeWebGLFenceSync','gea_three_webgl_fence_sync','double','extern "C" double gea_three_webgl_fence_sync();'],
|
|
103
|
+
['threeWebGLClientWaitSync','gea_three_webgl_client_wait_sync','double','extern "C" double gea_three_webgl_client_wait_sync(double,double,double);'],
|
|
104
|
+
['threeWebGLDeleteSync','gea_three_webgl_delete_sync','void','extern "C" void gea_three_webgl_delete_sync(double);'],
|
|
105
|
+
['threeWebGLTimerBegin','gea_three_webgl_timer_begin','double','extern "C" double gea_three_webgl_timer_begin();'],
|
|
106
|
+
['threeWebGLTimerEnd','gea_three_webgl_timer_end','void','extern "C" void gea_three_webgl_timer_end();'],
|
|
107
|
+
['threeWebGLTimerResult','gea_three_webgl_timer_result','double','extern "C" double gea_three_webgl_timer_result(double);'],
|
|
101
108
|
['threeWebGLRenderbufferStorageMultisample','gea_three_webgl_renderbuffer_storage_multisample','void','extern "C" void gea_three_webgl_renderbuffer_storage_multisample(double,double,double,double,double);'],
|
|
102
109
|
[
|
|
103
110
|
"threeNativeProfilePhase",
|
|
@@ -513,6 +520,18 @@ const hostFunctions = [
|
|
|
513
520
|
"void",
|
|
514
521
|
'extern "C" void gea_three_webgl_tex_storage_2d(double target, double levels, double internalFormat, double width, double height);',
|
|
515
522
|
],
|
|
523
|
+
[
|
|
524
|
+
"threeWebGLTexStorage3D",
|
|
525
|
+
"gea_three_webgl_tex_storage_3d",
|
|
526
|
+
"void",
|
|
527
|
+
'extern "C" void gea_three_webgl_tex_storage_3d(double target, double levels, double internalFormat, double width, double height, double depth);',
|
|
528
|
+
],
|
|
529
|
+
[
|
|
530
|
+
"threeWebGLFramebufferTextureLayer",
|
|
531
|
+
"gea_three_webgl_framebuffer_texture_layer",
|
|
532
|
+
"void",
|
|
533
|
+
'extern "C" void gea_three_webgl_framebuffer_texture_layer(double target, double attachment, double texture, double level, double layer);',
|
|
534
|
+
],
|
|
516
535
|
|
|
517
536
|
[
|
|
518
537
|
"threeWebGLCreateVertexArray",
|
|
@@ -2676,7 +2695,81 @@ class WebGLRenderer {
|
|
|
2676
2695
|
}
|
|
2677
2696
|
transformed = transformed.replaceAll(
|
|
2678
2697
|
rendererUniformUploadSource,
|
|
2679
|
-
"\t\t\t\tWebGLUniforms.upload( _gl, getUniformList( materialProperties ), m_uniforms, textures, materialProperties.clippingPlanes );",
|
|
2698
|
+
"\t\t\t\tWebGLUniforms.upload( _gl, getUniformList( materialProperties ), m_uniforms, textures, materialProperties.clippingPlanes, getUniformSlots( materialProperties ) );",
|
|
2699
|
+
);
|
|
2700
|
+
// Each upload looked every uniform's value cell up by name in the
|
|
2701
|
+
// material's uniforms dictionary. Resolve the cells once beside the
|
|
2702
|
+
// uniform list they belong to; both are rebuilt together, and a list
|
|
2703
|
+
// only ever changes by being recomputed.
|
|
2704
|
+
transformed = replaceOne(
|
|
2705
|
+
transformed,
|
|
2706
|
+
"\t\tfunction getUniformList( materialProperties ) {",
|
|
2707
|
+
`\t\t/** @param {import('./webgl/WebGLProperties.js').NativeWebGLPropertyBag} materialProperties */
|
|
2708
|
+
\t\tfunction getUniformSlots( materialProperties ) {
|
|
2709
|
+
|
|
2710
|
+
\t\t\tconst list = getUniformList( materialProperties );
|
|
2711
|
+
|
|
2712
|
+
\t\t\tif ( materialProperties.nativeUniformSlotsList !== list ) {
|
|
2713
|
+
|
|
2714
|
+
\t\t\t\tmaterialProperties.nativeUniformSlots = WebGLUniforms.slotsOf( list, materialProperties.uniforms );
|
|
2715
|
+
\t\t\t\tmaterialProperties.nativeUniformSlotsList = list;
|
|
2716
|
+
|
|
2717
|
+
\t\t\t}
|
|
2718
|
+
|
|
2719
|
+
\t\t\treturn materialProperties.nativeUniformSlots;
|
|
2720
|
+
|
|
2721
|
+
\t\t}
|
|
2722
|
+
|
|
2723
|
+
\t\tfunction getUniformList( materialProperties ) {`,
|
|
2724
|
+
fileName,
|
|
2725
|
+
"WebGLRenderer resolved uniform slots",
|
|
2726
|
+
);
|
|
2727
|
+
// envMapIntensity and dfgLUT were looked up by name on every draw, and the
|
|
2728
|
+
// ten light cells on every refresh; resolve them once per uniforms object.
|
|
2729
|
+
transformed = replaceOne(
|
|
2730
|
+
transformed,
|
|
2731
|
+
"import { WebGLProperties } from './webgl/WebGLProperties.js';",
|
|
2732
|
+
"import { WebGLProperties, NativeMaterialCells } from './webgl/WebGLProperties.js';",
|
|
2733
|
+
fileName,
|
|
2734
|
+
"WebGLRenderer material cells import",
|
|
2735
|
+
);
|
|
2736
|
+
transformed = replaceOne(
|
|
2737
|
+
transformed,
|
|
2738
|
+
"\t\t/** @param {import('./webgl/WebGLProperties.js').NativeWebGLPropertyBag} materialProperties */\n\t\tfunction getUniformSlots( materialProperties ) {",
|
|
2739
|
+
`\t\t/** @param {import('./webgl/WebGLProperties.js').NativeWebGLPropertyBag} materialProperties @param {import('./shaders/UniformsLib.js').NativeUniforms} uniforms @return {NativeMaterialCells} */
|
|
2740
|
+
\t\tfunction nativeCells( materialProperties, uniforms ) {
|
|
2741
|
+
|
|
2742
|
+
\t\t\tlet cells = materialProperties.nativeCells;
|
|
2743
|
+
|
|
2744
|
+
\t\t\tif ( cells === undefined || cells.uniforms !== uniforms ) {
|
|
2745
|
+
|
|
2746
|
+
\t\t\t\tcells = new NativeMaterialCells( uniforms );
|
|
2747
|
+
\t\t\t\tmaterialProperties.nativeCells = cells;
|
|
2748
|
+
|
|
2749
|
+
\t\t\t}
|
|
2750
|
+
|
|
2751
|
+
\t\t\treturn cells;
|
|
2752
|
+
|
|
2753
|
+
\t\t}
|
|
2754
|
+
|
|
2755
|
+
\t\t/** @param {import('./webgl/WebGLProperties.js').NativeWebGLPropertyBag} materialProperties */
|
|
2756
|
+
\t\tfunction getUniformSlots( materialProperties ) {`,
|
|
2757
|
+
fileName,
|
|
2758
|
+
"WebGLRenderer material cells helper",
|
|
2759
|
+
);
|
|
2760
|
+
transformed = replaceOne(
|
|
2761
|
+
transformed,
|
|
2762
|
+
"\t\t\t\tm_uniforms.envMapIntensity.value = scene.environmentIntensity;",
|
|
2763
|
+
"\t\t\t\tconst envMapIntensity = nativeCells( materialProperties, m_uniforms ).envMapIntensity;\n\t\t\t\tif ( envMapIntensity !== undefined ) envMapIntensity.value = scene.environmentIntensity;",
|
|
2764
|
+
fileName,
|
|
2765
|
+
"WebGLRenderer envMapIntensity cell",
|
|
2766
|
+
);
|
|
2767
|
+
transformed = replaceOne(
|
|
2768
|
+
transformed,
|
|
2769
|
+
"\t\t\tif ( m_uniforms.dfgLUT !== undefined ) {\n\n\t\t\t\tm_uniforms.dfgLUT.value = getDFGLUT();",
|
|
2770
|
+
"\t\t\tconst dfgLUT = nativeCells( materialProperties, m_uniforms ).dfgLUT;\n\n\t\t\tif ( dfgLUT !== undefined ) {\n\n\t\t\t\tdfgLUT.value = getDFGLUT();",
|
|
2771
|
+
fileName,
|
|
2772
|
+
"WebGLRenderer dfgLUT cell",
|
|
2680
2773
|
);
|
|
2681
2774
|
transformed = replaceOne(
|
|
2682
2775
|
transformed,
|
|
@@ -2803,7 +2896,7 @@ class WebGLRenderer {
|
|
|
2803
2896
|
);
|
|
2804
2897
|
}
|
|
2805
2898
|
for (const name of nativeUniformNamesEnabled
|
|
2806
|
-
? ["toneMappingExposure", "cameraPosition"]
|
|
2899
|
+
? ["toneMappingExposure", "cameraPosition", "receiveShadow", "isOrthographic"]
|
|
2807
2900
|
: []) {
|
|
2808
2901
|
transformed = replaceOne(
|
|
2809
2902
|
transformed,
|
|
@@ -2842,6 +2935,89 @@ class WebGLRenderer {
|
|
|
2842
2935
|
`WebGLRenderer ${field} uniform`,
|
|
2843
2936
|
);
|
|
2844
2937
|
}
|
|
2938
|
+
if (nativeUniformNamesEnabled && nativeUniformBindingsEnabled) {
|
|
2939
|
+
// Every lit draw re-bound every shadow map: a unit allocation, a sampler
|
|
2940
|
+
// uniform check and a texture bind per map, all redundant while the same
|
|
2941
|
+
// program draws again with the same maps and nothing has rebound their
|
|
2942
|
+
// units since. The program remembers what it bound and the slot stamps
|
|
2943
|
+
// (WebGLState) of the units it used; when both still hold, the draw only
|
|
2944
|
+
// allocates the same units, so later textures keep their unit numbers.
|
|
2945
|
+
const shadowSetters =
|
|
2946
|
+
"\t\t\t\tif ( directionalShadowMaps.length > 0 ) {\n\n\t\t\t\t\tp_uniforms.set_directionalShadowMap( _gl, directionalShadowMaps, textures );\n\n\t\t\t\t}\n\n" +
|
|
2947
|
+
"\t\t\t\tif ( spotShadowMaps.length > 0 ) {\n\n\t\t\t\t\tp_uniforms.set_spotShadowMap( _gl, spotShadowMaps, textures );\n\n\t\t\t\t}\n\n" +
|
|
2948
|
+
"\t\t\t\tif ( pointShadowMaps.length > 0 ) {\n\n\t\t\t\t\tp_uniforms.set_pointShadowMap( _gl, pointShadowMaps, textures );\n\n\t\t\t\t}\n";
|
|
2949
|
+
transformed = replaceOne(
|
|
2950
|
+
transformed,
|
|
2951
|
+
shadowSetters,
|
|
2952
|
+
"\t\t\t\tif ( nativeShadowMapsBound( program, directionalShadowMaps, spotShadowMaps, pointShadowMaps ) ) {\n\n" +
|
|
2953
|
+
"\t\t\t\t\tfor ( let unit = 0; unit < program.nativeShadowUnits; unit ++ ) textures.allocateTextureUnit();\n\n" +
|
|
2954
|
+
"\t\t\t\t} else {\n\n" +
|
|
2955
|
+
shadowSetters.replaceAll("\n\t\t\t\t", "\n\t\t\t\t\t").replace(/^\t\t\t\t/, "\t\t\t\t\t") +
|
|
2956
|
+
"\n\t\t\t\t\tnativeShadowMapsRecord( program, p_uniforms, directionalShadowMaps, spotShadowMaps, pointShadowMaps );\n\n" +
|
|
2957
|
+
"\t\t\t\t}\n",
|
|
2958
|
+
fileName,
|
|
2959
|
+
"WebGLRenderer shadow-map binding fast path",
|
|
2960
|
+
);
|
|
2961
|
+
transformed = replaceOne(
|
|
2962
|
+
transformed,
|
|
2963
|
+
"\t\tfunction setProgram( camera, scene, geometry, material, object ) {",
|
|
2964
|
+
`\t\t/**
|
|
2965
|
+
\t\t * @param {import('./webgl/WebGLProgram.js').WebGLProgram} program
|
|
2966
|
+
\t\t * @param {Array<import('../textures/Texture.js').Texture|null>} directional
|
|
2967
|
+
\t\t * @param {Array<import('../textures/Texture.js').Texture|null>} spot
|
|
2968
|
+
\t\t * @param {Array<import('../textures/Texture.js').Texture|null>} point
|
|
2969
|
+
\t\t * @return {boolean}
|
|
2970
|
+
\t\t */
|
|
2971
|
+
\t\tfunction nativeShadowMapsBound( program, directional, spot, point ) {
|
|
2972
|
+
|
|
2973
|
+
\t\t\tconst counts = program.nativeShadowCounts;
|
|
2974
|
+
\t\t\tif ( counts[ 0 ] !== directional.length || counts[ 1 ] !== spot.length || counts[ 2 ] !== point.length ) return false;
|
|
2975
|
+
\t\t\tconst maps = program.nativeShadowMaps;
|
|
2976
|
+
\t\t\tlet k = 0;
|
|
2977
|
+
\t\t\tfor ( let i = 0; i < directional.length; i ++ ) if ( maps[ k ++ ] !== directional[ i ] ) return false;
|
|
2978
|
+
\t\t\tfor ( let i = 0; i < spot.length; i ++ ) if ( maps[ k ++ ] !== spot[ i ] ) return false;
|
|
2979
|
+
\t\t\tfor ( let i = 0; i < point.length; i ++ ) if ( maps[ k ++ ] !== point[ i ] ) return false;
|
|
2980
|
+
\t\t\tconst stamps = program.nativeShadowStamps;
|
|
2981
|
+
\t\t\tfor ( let unit = 0; unit < stamps.length; unit ++ ) if ( state.nativeSlotStamp( _gl.TEXTURE0 + unit ) !== stamps[ unit ] ) return false;
|
|
2982
|
+
\t\t\treturn true;
|
|
2983
|
+
|
|
2984
|
+
\t\t}
|
|
2985
|
+
|
|
2986
|
+
\t\t/**
|
|
2987
|
+
\t\t * @param {import('./webgl/WebGLProgram.js').WebGLProgram} program
|
|
2988
|
+
\t\t * @param {import('./webgl/WebGLUniforms.js').WebGLUniforms} p_uniforms
|
|
2989
|
+
\t\t * @param {Array<import('../textures/Texture.js').Texture|null>} directional
|
|
2990
|
+
\t\t * @param {Array<import('../textures/Texture.js').Texture|null>} spot
|
|
2991
|
+
\t\t * @param {Array<import('../textures/Texture.js').Texture|null>} point
|
|
2992
|
+
\t\t */
|
|
2993
|
+
\t\tfunction nativeShadowMapsRecord( program, p_uniforms, directional, spot, point ) {
|
|
2994
|
+
|
|
2995
|
+
\t\t\tprogram.nativeShadowCounts[ 0 ] = directional.length;
|
|
2996
|
+
\t\t\tprogram.nativeShadowCounts[ 1 ] = spot.length;
|
|
2997
|
+
\t\t\tprogram.nativeShadowCounts[ 2 ] = point.length;
|
|
2998
|
+
\t\t\t/** @type {Array<import('../textures/Texture.js').Texture|null>} */
|
|
2999
|
+
\t\t\tconst maps = [];
|
|
3000
|
+
\t\t\tfor ( let i = 0; i < directional.length; i ++ ) maps.push( directional[ i ] );
|
|
3001
|
+
\t\t\tfor ( let i = 0; i < spot.length; i ++ ) maps.push( spot[ i ] );
|
|
3002
|
+
\t\t\tfor ( let i = 0; i < point.length; i ++ ) maps.push( point[ i ] );
|
|
3003
|
+
\t\t\tprogram.nativeShadowMaps = maps;
|
|
3004
|
+
\t\t\t// A setter whose uniform the program lacks allocates nothing.
|
|
3005
|
+
\t\t\tconst units = ( p_uniforms.fixed_directionalShadowMap !== undefined ? directional.length : 0 ) +
|
|
3006
|
+
\t\t\t\t( p_uniforms.fixed_spotShadowMap !== undefined ? spot.length : 0 ) +
|
|
3007
|
+
\t\t\t\t( p_uniforms.fixed_pointShadowMap !== undefined ? point.length : 0 );
|
|
3008
|
+
\t\t\tprogram.nativeShadowUnits = units;
|
|
3009
|
+
\t\t\t/** @type {number[]} */
|
|
3010
|
+
\t\t\tconst stamps = [];
|
|
3011
|
+
\t\t\tfor ( let unit = 0; unit < units; unit ++ ) stamps.push( state.nativeSlotStamp( _gl.TEXTURE0 + unit ) );
|
|
3012
|
+
\t\t\tprogram.nativeShadowStamps = stamps;
|
|
3013
|
+
|
|
3014
|
+
\t\t}
|
|
3015
|
+
|
|
3016
|
+
\t\tfunction setProgram( camera, scene, geometry, material, object ) {`,
|
|
3017
|
+
fileName,
|
|
3018
|
+
"WebGLRenderer shadow-map binding fast path helpers",
|
|
3019
|
+
);
|
|
3020
|
+
}
|
|
2845
3021
|
// Three tests a tag and then reads fields off the untyped object; a
|
|
2846
3022
|
// class test narrows the object to the class that declares those fields,
|
|
2847
3023
|
// so each read has a type and each uniform value arrives already typed.
|
|
@@ -3023,6 +3199,27 @@ class WebGLRenderer {
|
|
|
3023
3199
|
fileName,
|
|
3024
3200
|
"WebGLRenderer native framebuffer selection",
|
|
3025
3201
|
);
|
|
3202
|
+
// The typed property bag keeps cube and mipmap framebuffers in their own arrays, so `__webglFramebuffer`
|
|
3203
|
+
// stays undefined for those targets. three asks exactly that to decide whether a target is set up yet, so
|
|
3204
|
+
// every setRenderTarget of a cube target ran setupRenderTarget again: six new framebuffers (and six face
|
|
3205
|
+
// allocations) per call, never deleted (probe faces and each sky-cube step at a lighting change).
|
|
3206
|
+
const setUpTarget = (name) =>
|
|
3207
|
+
`${name}.__webglFramebuffer === undefined && ${name}.__webglMipmapFramebuffers.length === 0 && ` +
|
|
3208
|
+
`${name}.__webglCubeFramebuffers.length === 0 && ${name}.__webglCubeMipmapFramebuffers.length === 0`;
|
|
3209
|
+
transformed = replaceOne(
|
|
3210
|
+
transformed,
|
|
3211
|
+
"\t\t\t\t} else if ( renderTargetProperties.__webglFramebuffer === undefined ) {\n\n\t\t\t\t\ttextures.setupRenderTarget( renderTarget );",
|
|
3212
|
+
`\t\t\t\t} else if ( ${setUpTarget("renderTargetProperties")} ) {\n\n\t\t\t\t\ttextures.setupRenderTarget( renderTarget );`,
|
|
3213
|
+
fileName,
|
|
3214
|
+
"WebGLRenderer render target set up once",
|
|
3215
|
+
);
|
|
3216
|
+
transformed = replaceOne(
|
|
3217
|
+
transformed,
|
|
3218
|
+
"\t\t\tif ( properties.get( target ).__webglFramebuffer === undefined ) {\n\n\t\t\t\ttextures.setupRenderTarget( target );",
|
|
3219
|
+
`\t\t\tconst targetProperties = properties.get( target );\n\n\t\t\tif ( ${setUpTarget("targetProperties")} ) {\n\n\t\t\t\ttextures.setupRenderTarget( target );`,
|
|
3220
|
+
fileName,
|
|
3221
|
+
"WebGLRenderer initRenderTarget set up once",
|
|
3222
|
+
);
|
|
3026
3223
|
transformed = replaceOne(
|
|
3027
3224
|
transformed,
|
|
3028
3225
|
"\t\tthis.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex, textureIndex = 0 ) {",
|
|
@@ -4847,12 +5044,14 @@ function requireWebGLStateTextureImageSource( value ) {
|
|
|
4847
5044
|
|
|
4848
5045
|
\t\t\t} else {
|
|
4849
5046
|
|
|
4850
|
-
\t\t\t\tgl.texImage2D( ${sourceArguments(9, 8, true)} );
|
|
5047
|
+
\t\t\t\tgl.texImage2D( ${sourceArguments(9, 8, true).replace("arguments[ 5 ]", "0")} );
|
|
4851
5048
|
|
|
4852
5049
|
\t\t\t}`,
|
|
4853
5050
|
fileName,
|
|
4854
5051
|
"WebGLState native TexImageSource image expansion",
|
|
4855
5052
|
);
|
|
5053
|
+
// The pixel form above passes border 0 (WebGL requires it): forwarding `arguments[ 5 ]` types it from
|
|
5054
|
+
// every caller's sixth argument (border or image), a nested union the compiler's emitter recasts to undefined.
|
|
4856
5055
|
// Preserve the actual argument count (and Function#length) while stating
|
|
4857
5056
|
// the native upload protocol at the forwarding boundary. An arguments
|
|
4858
5057
|
// object with no formal parameters otherwise erases every pixel source
|
|
@@ -5029,21 +5228,34 @@ function requireWebGLStateTextureImageSource( value ) {
|
|
|
5029
5228
|
transformed = replaceOne(
|
|
5030
5229
|
transformed,
|
|
5031
5230
|
"\tlet currentBoundTextures = {};",
|
|
5032
|
-
|
|
5231
|
+
// Indexed by slot - TEXTURE0 in a dense array: a texture bind on every
|
|
5232
|
+
// sampler of every draw read this table, and an object keyed by 33984+
|
|
5233
|
+
// is a hashed dictionary natively.
|
|
5234
|
+
"\t/** @typedef {{ type: number|undefined, texture: import('@geastack/native-webgl-angle/nativeWebGL').NativeHandle|null|undefined }} NativeBoundTexture */\n" +
|
|
5235
|
+
"\t/** @type {Array<NativeBoundTexture|undefined>} */\n\tlet currentBoundTextures = [];\n\n" +
|
|
5236
|
+
"\t/** @param {number} slot @return {NativeBoundTexture|undefined} */\n" +
|
|
5237
|
+
"\tfunction boundTextureAt( slot ) {\n\n\t\tconst index = slot - 0x84C0;\n\t\treturn index >= 0 && index < currentBoundTextures.length ? currentBoundTextures[ index ] : undefined;\n\n\t}\n\n" +
|
|
5238
|
+
"\t/** @param {number} slot @param {NativeBoundTexture} bound */\n" +
|
|
5239
|
+
"\tfunction setBoundTextureAt( slot, bound ) {\n\n\t\tconst index = slot - 0x84C0;\n\t\twhile ( currentBoundTextures.length <= index ) currentBoundTextures.push( undefined );\n\t\tcurrentBoundTextures[ index ] = bound;\n\n\t}\n\n" +
|
|
5240
|
+
"\t/** @type {number[]} */\n\tlet slotStamps = [];\n\tlet nextSlotStamp = 0;\n\n" +
|
|
5241
|
+
"\t/** @param {number} slot */\n" +
|
|
5242
|
+
"\tfunction stampSlot( slot ) {\n\n\t\tconst index = slot - 0x84C0;\n\t\twhile ( slotStamps.length <= index ) slotStamps.push( - 1 );\n\t\tslotStamps[ index ] = ++ nextSlotStamp;\n\n\t}\n\n" +
|
|
5243
|
+
"\t/** @param {number} slot @return {number} The slot's stamp, -1 if never bound since the last reset. */\n" +
|
|
5244
|
+
"\tfunction slotStamp( slot ) {\n\n\t\tconst index = slot - 0x84C0;\n\t\treturn index >= 0 && index < slotStamps.length ? slotStamps[ index ] : - 1;\n\n\t}",
|
|
5033
5245
|
fileName,
|
|
5034
5246
|
"WebGLState bound texture table",
|
|
5035
5247
|
);
|
|
5036
5248
|
transformed = replaceOne(
|
|
5037
5249
|
transformed,
|
|
5038
5250
|
"\tfunction unbindTexture() {\n\n\t\tconst boundTexture = currentBoundTextures[ currentTextureSlot ];",
|
|
5039
|
-
"\tfunction unbindTexture() {\n\n\t\tif ( typeof currentTextureSlot !== 'number' ) return;\n\n\t\tconst textureSlot = currentTextureSlot;\n\t\tconst boundTexture =
|
|
5251
|
+
"\tfunction unbindTexture() {\n\n\t\tif ( typeof currentTextureSlot !== 'number' ) return;\n\n\t\tconst textureSlot = currentTextureSlot;\n\t\tconst boundTexture = boundTextureAt( textureSlot );",
|
|
5040
5252
|
fileName,
|
|
5041
5253
|
"WebGLState current texture slot narrowing",
|
|
5042
5254
|
);
|
|
5043
5255
|
transformed = replaceOne(
|
|
5044
5256
|
transformed,
|
|
5045
5257
|
"\t\tcurrentBoundTextures = {};",
|
|
5046
|
-
"\t\tcurrentBoundTextures =
|
|
5258
|
+
"\t\tcurrentBoundTextures = [];",
|
|
5047
5259
|
fileName,
|
|
5048
5260
|
"WebGLState bound texture reset",
|
|
5049
5261
|
);
|
|
@@ -5113,7 +5325,7 @@ function requireWebGLStateTextureImageSource( value ) {
|
|
|
5113
5325
|
transformed = replaceOne(
|
|
5114
5326
|
transformed,
|
|
5115
5327
|
"\t\tlet boundTexture = currentBoundTextures[ webglSlot ];",
|
|
5116
|
-
"\t\tconst textureSlot = /** @type {number} */ ( webglSlot );\n\n\t\tlet boundTexture =
|
|
5328
|
+
"\t\tconst textureSlot = /** @type {number} */ ( webglSlot );\n\n\t\tlet boundTexture = boundTextureAt( textureSlot );",
|
|
5117
5329
|
fileName,
|
|
5118
5330
|
"WebGLState required texture slot",
|
|
5119
5331
|
);
|
|
@@ -5133,7 +5345,7 @@ function requireWebGLStateTextureImageSource( value ) {
|
|
|
5133
5345
|
.slice(bindTextureStart, bindTextureEnd)
|
|
5134
5346
|
.replace(
|
|
5135
5347
|
"currentBoundTextures[ webglSlot ] = boundTexture;",
|
|
5136
|
-
"
|
|
5348
|
+
"setBoundTextureAt( textureSlot, boundTexture );",
|
|
5137
5349
|
)
|
|
5138
5350
|
.replaceAll(
|
|
5139
5351
|
"currentTextureSlot !== webglSlot",
|
|
@@ -5154,10 +5366,34 @@ function requireWebGLStateTextureImageSource( value ) {
|
|
|
5154
5366
|
transformed = replaceOne(
|
|
5155
5367
|
transformed,
|
|
5156
5368
|
"\t\t\tgl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] );",
|
|
5157
|
-
"\t\t\tconst textureToBind = webglTexture || emptyTextures[ webglType ];\n\n\t\t\tif ( textureToBind === undefined ) throw new Error( 'THREE.WebGLState: Missing empty texture for binding target.' );\n\n\t\t\tgl.bindTexture( webglType, textureToBind );",
|
|
5369
|
+
"\t\t\tconst textureToBind = webglTexture || emptyTextures[ webglType ];\n\n\t\t\tif ( textureToBind === undefined ) throw new Error( 'THREE.WebGLState: Missing empty texture for binding target.' );\n\n\t\t\tgl.bindTexture( webglType, textureToBind );\n\t\t\tstampSlot( textureSlot );",
|
|
5158
5370
|
fileName,
|
|
5159
5371
|
"WebGLState bound texture fallback",
|
|
5160
5372
|
);
|
|
5373
|
+
// Each texture slot carries a stamp that changes whenever the slot is
|
|
5374
|
+
// rebound, so a caller can tell its earlier binds are still in place
|
|
5375
|
+
// (WebGLRenderer's shadow-map fast path).
|
|
5376
|
+
transformed = replaceOne(
|
|
5377
|
+
transformed,
|
|
5378
|
+
"\t\t\tgl.bindTexture( boundTexture.type, null );",
|
|
5379
|
+
"\t\t\tgl.bindTexture( boundTexture.type, null );\n\t\t\tstampSlot( textureSlot );",
|
|
5380
|
+
fileName,
|
|
5381
|
+
"WebGLState unbind slot stamp",
|
|
5382
|
+
);
|
|
5383
|
+
transformed = replaceOne(
|
|
5384
|
+
transformed,
|
|
5385
|
+
"\t\tcurrentBoundTextures = [];",
|
|
5386
|
+
"\t\tcurrentBoundTextures = [];\n\t\tslotStamps = [];",
|
|
5387
|
+
fileName,
|
|
5388
|
+
"WebGLState slot stamp reset",
|
|
5389
|
+
);
|
|
5390
|
+
transformed = replaceOne(
|
|
5391
|
+
transformed,
|
|
5392
|
+
"\t\tbindTexture: bindTexture,\n",
|
|
5393
|
+
"\t\tbindTexture: bindTexture,\n\t\tnativeSlotStamp: slotStamp,\n",
|
|
5394
|
+
fileName,
|
|
5395
|
+
"WebGLState slot stamp export",
|
|
5396
|
+
);
|
|
5161
5397
|
transformed = replaceOne(
|
|
5162
5398
|
transformed,
|
|
5163
5399
|
"\t\tcurrentDrawbuffers = new WeakMap();",
|
|
@@ -5749,8 +5985,331 @@ ${transformed}`;
|
|
|
5749
5985
|
);
|
|
5750
5986
|
transformed = transformed.slice(0, start) + body + transformed.slice(end);
|
|
5751
5987
|
}
|
|
5988
|
+
// Every render pass updates every drawn geometry's attributes, and each
|
|
5989
|
+
// update hashed the attribute into `buffers`. The WeakMap stays the
|
|
5990
|
+
// authority; each data attribute also carries the entry its owning
|
|
5991
|
+
// WebGLAttributes stored, tagged with that instance's number, so the
|
|
5992
|
+
// per-draw read is a field load. Every write and delete of `buffers`
|
|
5993
|
+
// keeps the field in step.
|
|
5994
|
+
transformed = replaceOne(
|
|
5995
|
+
transformed,
|
|
5996
|
+
"function WebGLAttributes( gl ) {\n",
|
|
5997
|
+
"let nextNativeAttributesOwner = 1;\n\nfunction WebGLAttributes( gl ) {\n\n\tconst nativeOwner = nextNativeAttributesOwner ++;\n",
|
|
5998
|
+
fileName,
|
|
5999
|
+
"WebGLAttributes front cache owner",
|
|
6000
|
+
);
|
|
6001
|
+
transformed = replaceOne(
|
|
6002
|
+
transformed,
|
|
6003
|
+
"\t\treturn buffers.get( dataAttribute );",
|
|
6004
|
+
"\t\tif ( dataAttribute.__nativeBufferOwner === nativeOwner ) return dataAttribute.__nativeBuffer;\n\n\t\treturn buffers.get( dataAttribute );",
|
|
6005
|
+
fileName,
|
|
6006
|
+
"WebGLAttributes front cache get",
|
|
6007
|
+
);
|
|
6008
|
+
transformed = replaceOne(
|
|
6009
|
+
transformed,
|
|
6010
|
+
"\t\t\tbuffers.delete( dataAttribute );",
|
|
6011
|
+
"\t\t\tbuffers.delete( dataAttribute );\n\n\t\t\tif ( dataAttribute.__nativeBufferOwner === nativeOwner ) {\n\n\t\t\t\tdataAttribute.__nativeBufferOwner = 0;\n\t\t\t\tdataAttribute.__nativeBuffer = undefined;\n\n\t\t\t}",
|
|
6012
|
+
fileName,
|
|
6013
|
+
"WebGLAttributes front cache delete",
|
|
6014
|
+
);
|
|
6015
|
+
transformed = replaceOne(
|
|
6016
|
+
transformed,
|
|
6017
|
+
`\t\t\t\tbuffers.set( dataAttribute, {
|
|
6018
|
+
\t\t\t\t\tbuffer: dataAttribute.buffer,
|
|
6019
|
+
\t\t\t\t\ttype: dataAttribute.type,
|
|
6020
|
+
\t\t\t\t\tbytesPerElement: dataAttribute.elementSize,
|
|
6021
|
+
\t\t\t\t\tversion: dataAttribute.version
|
|
6022
|
+
\t\t\t\t} );`,
|
|
6023
|
+
`\t\t\t\t/** @type {NativeAttributeBufferCache} */
|
|
6024
|
+
\t\t\t\tconst entry = {
|
|
6025
|
+
\t\t\t\t\tbuffer: dataAttribute.buffer,
|
|
6026
|
+
\t\t\t\t\ttype: dataAttribute.type,
|
|
6027
|
+
\t\t\t\t\tbytesPerElement: dataAttribute.elementSize,
|
|
6028
|
+
\t\t\t\t\tversion: dataAttribute.version
|
|
6029
|
+
\t\t\t\t};
|
|
6030
|
+
\t\t\t\tbuffers.set( dataAttribute, entry );
|
|
6031
|
+
\t\t\t\tdataAttribute.__nativeBufferOwner = nativeOwner;
|
|
6032
|
+
\t\t\t\tdataAttribute.__nativeBuffer = entry;`,
|
|
6033
|
+
fileName,
|
|
6034
|
+
"WebGLAttributes front cache GL attribute write",
|
|
6035
|
+
);
|
|
6036
|
+
transformed = replaceOne(
|
|
6037
|
+
transformed,
|
|
6038
|
+
`\t\tconst data = buffers.get( dataAttribute );
|
|
6039
|
+
|
|
6040
|
+
\t\tif ( data === undefined ) {
|
|
6041
|
+
|
|
6042
|
+
\t\t\tbuffers.set( dataAttribute, createBuffer( dataAttribute, bufferType ) );`,
|
|
6043
|
+
`\t\tconst data = dataAttribute.__nativeBufferOwner === nativeOwner ? dataAttribute.__nativeBuffer : buffers.get( dataAttribute );
|
|
6044
|
+
|
|
6045
|
+
\t\tif ( data === undefined ) {
|
|
6046
|
+
|
|
6047
|
+
\t\t\tconst entry = createBuffer( dataAttribute, bufferType );
|
|
6048
|
+
\t\t\tbuffers.set( dataAttribute, entry );
|
|
6049
|
+
\t\t\tdataAttribute.__nativeBufferOwner = nativeOwner;
|
|
6050
|
+
\t\t\tdataAttribute.__nativeBuffer = entry;`,
|
|
6051
|
+
fileName,
|
|
6052
|
+
"WebGLAttributes front cache update",
|
|
6053
|
+
);
|
|
6054
|
+
}
|
|
6055
|
+
if (
|
|
6056
|
+
normalized.endsWith("/three/src/core/BufferAttribute.js") ||
|
|
6057
|
+
normalized.endsWith("/three/src/core/InterleavedBuffer.js") ||
|
|
6058
|
+
normalized.endsWith("/three/src/core/GLBufferAttribute.js")
|
|
6059
|
+
) {
|
|
6060
|
+
// The native WebGLAttributes front cache (see WebGLAttributes above).
|
|
6061
|
+
transformed = replaceOne(
|
|
6062
|
+
transformed,
|
|
6063
|
+
"\t\tthis.version = 0;\n",
|
|
6064
|
+
`\t\tthis.version = 0;
|
|
6065
|
+
|
|
6066
|
+
\t\t/** @type {number} The WebGLAttributes instance whose entry \`__nativeBuffer\` holds; 0 when none. */
|
|
6067
|
+
\t\tthis.__nativeBufferOwner = 0;
|
|
6068
|
+
\t\t/** @type {{ buffer: import('@geastack/native-webgl-angle/nativeWebGL').NativeHandle, type: number, bytesPerElement: number, version: number, size?: number }|undefined} */
|
|
6069
|
+
\t\tthis.__nativeBuffer = undefined;
|
|
6070
|
+
`,
|
|
6071
|
+
fileName,
|
|
6072
|
+
"native attribute buffer front cache fields",
|
|
6073
|
+
);
|
|
6074
|
+
}
|
|
6075
|
+
if (
|
|
6076
|
+
normalized.endsWith("/three/src/materials/Material.js") ||
|
|
6077
|
+
normalized.endsWith("/three/src/textures/Texture.js") ||
|
|
6078
|
+
normalized.endsWith("/three/src/textures/Source.js")
|
|
6079
|
+
) {
|
|
6080
|
+
// The native WebGLProperties front cache (see WebGLProperties).
|
|
6081
|
+
transformed = replaceOne(
|
|
6082
|
+
transformed,
|
|
6083
|
+
"\t\tthis.version = 0;\n",
|
|
6084
|
+
`\t\tthis.version = 0;
|
|
6085
|
+
|
|
6086
|
+
\t\t/** @type {number} The WebGLProperties instance whose bag \`__nativeProperties\` holds; 0 when none. */
|
|
6087
|
+
\t\tthis.__nativePropertiesOwner = 0;
|
|
6088
|
+
\t\t/** @type {import('../renderers/webgl/WebGLProperties.js').NativeWebGLPropertyBag|undefined} */
|
|
6089
|
+
\t\tthis.__nativeProperties = undefined;
|
|
6090
|
+
`,
|
|
6091
|
+
fileName,
|
|
6092
|
+
"native property bag front cache fields",
|
|
6093
|
+
);
|
|
6094
|
+
}
|
|
6095
|
+
if (normalized.endsWith("/three/src/core/Object3D.js") || normalized.endsWith("/three/src/core/BufferGeometry.js")) {
|
|
6096
|
+
// The native WebGLObjects front cache (see WebGLObjects).
|
|
6097
|
+
transformed = replaceOne(
|
|
6098
|
+
transformed,
|
|
6099
|
+
"\t\tthis.uuid = generateUUID();\n",
|
|
6100
|
+
`\t\tthis.uuid = generateUUID();
|
|
6101
|
+
|
|
6102
|
+
\t\t/** @type {number} The WebGLObjects instance whose update frame \`__nativeObjectsFrame\` holds; 0 when none. */
|
|
6103
|
+
\t\tthis.__nativeObjectsOwner = 0;
|
|
6104
|
+
\t\t/** @type {number} */
|
|
6105
|
+
\t\tthis.__nativeObjectsFrame = - 1;
|
|
6106
|
+
`,
|
|
6107
|
+
fileName,
|
|
6108
|
+
"native objects update front cache fields",
|
|
6109
|
+
);
|
|
6110
|
+
}
|
|
6111
|
+
if (normalized.endsWith("/three/src/core/BufferGeometry.js")) {
|
|
6112
|
+
// The attribute-set stamp WebGLBindingStates' needsUpdate fast path reads.
|
|
6113
|
+
transformed = replaceOne(
|
|
6114
|
+
transformed,
|
|
6115
|
+
"\t\t */\n\t\tthis.attributes = {};\n",
|
|
6116
|
+
"\t\t */\n\t\tthis.attributes = {};\n\n\t\t/** @type {number} Bumped whenever the attribute set changes. */\n\t\tthis.__nativeAttributeStamp = 0;\n",
|
|
6117
|
+
fileName,
|
|
6118
|
+
"native attribute-set stamp field",
|
|
6119
|
+
);
|
|
6120
|
+
transformed = replaceOne(
|
|
6121
|
+
transformed,
|
|
6122
|
+
"\t\tthis.index = null;\n\t\tthis.attributes = {};\n",
|
|
6123
|
+
"\t\tthis.index = null;\n\t\tthis.attributes = {};\n\t\tthis.__nativeAttributeStamp ++;\n",
|
|
6124
|
+
fileName,
|
|
6125
|
+
"native attribute-set stamp on copy",
|
|
6126
|
+
);
|
|
6127
|
+
transformed = replaceOne(
|
|
6128
|
+
transformed,
|
|
6129
|
+
"\t\tthis.attributes[ name ] = attribute;\n",
|
|
6130
|
+
"\t\tthis.attributes[ name ] = attribute;\n\t\tthis.__nativeAttributeStamp ++;\n",
|
|
6131
|
+
fileName,
|
|
6132
|
+
"native attribute-set stamp on set",
|
|
6133
|
+
);
|
|
6134
|
+
transformed = replaceOne(
|
|
6135
|
+
transformed,
|
|
6136
|
+
"\t\tdelete this.attributes[ name ];\n",
|
|
6137
|
+
"\t\tdelete this.attributes[ name ];\n\t\tthis.__nativeAttributeStamp ++;\n",
|
|
6138
|
+
fileName,
|
|
6139
|
+
"native attribute-set stamp on delete",
|
|
6140
|
+
);
|
|
6141
|
+
}
|
|
6142
|
+
// Light uniforms (the light, shadow, ambient and probe structures
|
|
6143
|
+
// markUniformsLightsNeedsUpdate flags) are written only by WebGLLights.setup
|
|
6144
|
+
// and setupView. three re-uploads them whenever the program changes, which
|
|
6145
|
+
// natively is a walk over every light struct member on nearly every draw.
|
|
6146
|
+
// Each setup/setupView takes a new stamp; a program records the stamp whose
|
|
6147
|
+
// values it last received and skips the upload while that stamp is current,
|
|
6148
|
+
// because its GL uniforms already hold exactly those values. Shadow-map
|
|
6149
|
+
// samplers are bound separately and still every draw.
|
|
6150
|
+
if (normalized.endsWith("/three/src/renderers/webgl/WebGLLights.js")) {
|
|
6151
|
+
transformed = replaceOne(
|
|
6152
|
+
transformed,
|
|
6153
|
+
"\tconst state = {\n\n\t\tversion: 0,\n",
|
|
6154
|
+
"\tconst state = {\n\n\t\tversion: 0,\n\n\t\tnativeStamp: 0,\n",
|
|
6155
|
+
fileName,
|
|
6156
|
+
"WebGLLights native upload stamp field",
|
|
6157
|
+
);
|
|
6158
|
+
transformed = replaceOne(
|
|
6159
|
+
transformed,
|
|
6160
|
+
"\tfunction setup( lights ) {\n",
|
|
6161
|
+
"\tfunction setup( lights ) {\n\n\t\tstate.nativeStamp = ++ nativeLightsStamp;\n",
|
|
6162
|
+
fileName,
|
|
6163
|
+
"WebGLLights.setup native upload stamp",
|
|
6164
|
+
);
|
|
6165
|
+
transformed = replaceOne(
|
|
6166
|
+
transformed,
|
|
6167
|
+
"\tfunction setupView( lights, camera ) {\n",
|
|
6168
|
+
"\tfunction setupView( lights, camera ) {\n\n\t\tstate.nativeStamp = ++ nativeLightsStamp;\n",
|
|
6169
|
+
fileName,
|
|
6170
|
+
"WebGLLights.setupView native upload stamp",
|
|
6171
|
+
);
|
|
6172
|
+
transformed = replaceOne(
|
|
6173
|
+
transformed,
|
|
6174
|
+
"function WebGLLights(",
|
|
6175
|
+
`let nativeLightsStamp = 0;
|
|
6176
|
+
|
|
6177
|
+
// Every render state (the main view, and each nested render such as a mirror)
|
|
6178
|
+
// owns a WebGLLights whose version counts its own hash changes, so a material
|
|
6179
|
+
// drawn in two states sees a "new" version on every switch and three rebuilds
|
|
6180
|
+
// its program parameters to find the same program. Equal hashes (light and
|
|
6181
|
+
// shadow counts) share one structure id, which lets the renderer tell a
|
|
6182
|
+
// re-wire from a real program change.
|
|
6183
|
+
/** @type {Map<string, number>} */
|
|
6184
|
+
const nativeLightStructures = new Map();
|
|
6185
|
+
/** @param {{ directionalLength: number, pointLength: number, spotLength: number, rectAreaLength: number, hemiLength: number, numDirectionalShadows: number, numPointShadows: number, numSpotShadows: number, numSpotMaps: number, numLightProbes: number }} hash @return {number} */
|
|
6186
|
+
function nativeLightStructure( hash ) {
|
|
6187
|
+
|
|
6188
|
+
\tconst key = [ hash.directionalLength, hash.pointLength, hash.spotLength, hash.rectAreaLength, hash.hemiLength,
|
|
6189
|
+
\t\thash.numDirectionalShadows, hash.numPointShadows, hash.numSpotShadows, hash.numSpotMaps, hash.numLightProbes ].join( ',' );
|
|
6190
|
+
\tlet structure = nativeLightStructures.get( key );
|
|
6191
|
+
|
|
6192
|
+
\tif ( structure === undefined ) {
|
|
6193
|
+
|
|
6194
|
+
\t\tstructure = nativeLightStructures.size + 1;
|
|
6195
|
+
\t\tnativeLightStructures.set( key, structure );
|
|
6196
|
+
|
|
6197
|
+
\t}
|
|
6198
|
+
|
|
6199
|
+
\treturn structure;
|
|
6200
|
+
|
|
6201
|
+
}
|
|
6202
|
+
|
|
6203
|
+
function WebGLLights(`,
|
|
6204
|
+
fileName,
|
|
6205
|
+
"WebGLLights native upload stamp counter",
|
|
6206
|
+
);
|
|
6207
|
+
transformed = replaceOne(
|
|
6208
|
+
transformed,
|
|
6209
|
+
"\t\tnativeStamp: 0,\n",
|
|
6210
|
+
"\t\tnativeStamp: 0,\n\n\t\tnativeStructure: 0,\n",
|
|
6211
|
+
fileName,
|
|
6212
|
+
"WebGLLights native structure field",
|
|
6213
|
+
);
|
|
6214
|
+
transformed = replaceOne(
|
|
6215
|
+
transformed,
|
|
6216
|
+
"\t\t\tstate.version = nextVersion ++;",
|
|
6217
|
+
"\t\t\tstate.version = nextVersion ++;\n\t\t\tstate.nativeStructure = nativeLightStructure( hash );",
|
|
6218
|
+
fileName,
|
|
6219
|
+
"WebGLLights native structure on hash change",
|
|
6220
|
+
);
|
|
6221
|
+
}
|
|
6222
|
+
if (normalized.endsWith("/three/src/renderers/webgl/WebGLProgram.js")) {
|
|
6223
|
+
transformed = replaceOne(
|
|
6224
|
+
transformed,
|
|
6225
|
+
"\tthis.cacheKey = cacheKey;\n",
|
|
6226
|
+
"\tthis.cacheKey = cacheKey;\n\t/** The WebGLLights stamp whose light uniforms this program holds; 0 when none. */\n\tthis.nativeLightsStamp = 0;\n" +
|
|
6227
|
+
"\t/** @type {Array<import('../../textures/Texture.js').Texture|null>} The shadow maps (directional, spot, point, in order) this program last bound, see WebGLRenderer's shadow-map fast path. */\n\tthis.nativeShadowMaps = [];\n" +
|
|
6228
|
+
"\t/** @type {number[]} Lengths of the three arrays in nativeShadowMaps. */\n\tthis.nativeShadowCounts = [ - 1, - 1, - 1 ];\n" +
|
|
6229
|
+
"\t/** @type {number[]} WebGLState slot stamps of the units those maps were bound to. */\n\tthis.nativeShadowStamps = [];\n" +
|
|
6230
|
+
"\t/** The texture units the shadow-map setters allocated. */\n\tthis.nativeShadowUnits = 0;\n",
|
|
6231
|
+
fileName,
|
|
6232
|
+
"WebGLProgram native light upload stamp",
|
|
6233
|
+
);
|
|
6234
|
+
}
|
|
6235
|
+
if (normalized.endsWith("/three/src/renderers/WebGLRenderer.js")) {
|
|
6236
|
+
transformed = replaceOne(
|
|
6237
|
+
transformed,
|
|
6238
|
+
"\t\t\t\t\tmarkUniformsLightsNeedsUpdate( m_uniforms, refreshLights );",
|
|
6239
|
+
`\t\t\t\t\tconst lightsStamp = lights.state.nativeStamp;
|
|
6240
|
+
\t\t\t\t\tconst uploadLights = refreshLights && program.nativeLightsStamp !== lightsStamp;
|
|
6241
|
+
\t\t\t\t\t// The ten light cells, resolved once per uniforms object (nativeCells).
|
|
6242
|
+
\t\t\t\t\tfor ( const cell of nativeCells( materialProperties, m_uniforms ).lights ) cell.needsUpdate = uploadLights;
|
|
6243
|
+
\t\t\t\t\tif ( uploadLights ) program.nativeLightsStamp = lightsStamp;`,
|
|
6244
|
+
fileName,
|
|
6245
|
+
"WebGLRenderer light uniform upload stamp",
|
|
6246
|
+
);
|
|
6247
|
+
const lightWiring = [
|
|
6248
|
+
["ambientLightColor", "ambient"], ["lightProbe", "probe"],
|
|
6249
|
+
["directionalLights", "directional"], ["directionalLightShadows", "directionalShadow"],
|
|
6250
|
+
["spotLights", "spot"], ["spotLightShadows", "spotShadow"], ["rectAreaLights", "rectArea"],
|
|
6251
|
+
["ltc_1", "rectAreaLTC1"], ["ltc_2", "rectAreaLTC2"],
|
|
6252
|
+
["pointLights", "point"], ["pointLightShadows", "pointShadow"], ["hemisphereLights", "hemi"],
|
|
6253
|
+
["directionalShadowMatrix", "directionalShadowMatrix"], ["spotLightMatrix", "spotLightMatrix"],
|
|
6254
|
+
["spotLightMap", "spotLightMap"], ["pointShadowMatrix", "pointShadowMatrix"],
|
|
6255
|
+
];
|
|
6256
|
+
const wiringText = lightWiring.map(([u, s]) => `\t\t\t\tuniforms.${u}.value = lights.state.${s};\n`).join("");
|
|
6257
|
+
// getProgram's wiring must still be exactly this list, or the re-wire below would miss a field.
|
|
6258
|
+
if (!transformed.includes(wiringText.replace("\t\t\t\tuniforms.directionalShadowMatrix", "\n\t\t\t\tuniforms.directionalShadowMatrix"))) {
|
|
6259
|
+
throw new Error(`Three WebGLRenderer light wiring at ${fileName} no longer matches the native re-wire list`);
|
|
6260
|
+
}
|
|
6261
|
+
transformed = replaceOne(
|
|
6262
|
+
transformed,
|
|
6263
|
+
"\t\t\tmaterialProperties.lightsStateVersion = lightsStateVersion;\n",
|
|
6264
|
+
"\t\t\tmaterialProperties.lightsStateVersion = lightsStateVersion;\n\t\t\tmaterialProperties.nativeLightsStructure = lights.state.nativeStructure;\n\t\t\tmaterialProperties.nativeShadowCount = shadowsArray.length;\n",
|
|
6265
|
+
fileName,
|
|
6266
|
+
"WebGLRenderer program light structure",
|
|
6267
|
+
);
|
|
6268
|
+
// A lights version from another render state with the same structure and
|
|
6269
|
+
// shadow count selects the same program: point the material's light
|
|
6270
|
+
// uniforms at this state's arrays (getProgram's wiring) instead of
|
|
6271
|
+
// rebuilding the program parameters. Every other program check still runs.
|
|
6272
|
+
transformed = replaceOne(
|
|
6273
|
+
transformed,
|
|
6274
|
+
"\t\t\tif ( material.version === materialProperties.__version ) {\n\n\t\t\t\tif ( materialProperties.needsLights && ( materialProperties.lightsStateVersion !== lights.state.version ) ) {",
|
|
6275
|
+
`\t\t\tif ( material.version === materialProperties.__version && materialProperties.needsLights &&
|
|
6276
|
+
\t\t\t\tmaterialProperties.lightsStateVersion !== lights.state.version &&
|
|
6277
|
+
\t\t\t\tmaterialProperties.nativeLightsStructure === lights.state.nativeStructure &&
|
|
6278
|
+
\t\t\t\tmaterialProperties.nativeShadowCount === currentRenderState.state.shadowsArray.length ) {
|
|
6279
|
+
|
|
6280
|
+
\t\t\t\tconst uniforms = materialProperties.uniforms;
|
|
6281
|
+
${wiringText.replace(/\t\t\t\t/g, "\t\t\t\t")}
|
|
6282
|
+
\t\t\t\tmaterialProperties.lightsStateVersion = lights.state.version;
|
|
6283
|
+
|
|
6284
|
+
\t\t\t}
|
|
6285
|
+
|
|
6286
|
+
\t\t\tif ( material.version === materialProperties.__version ) {
|
|
6287
|
+
|
|
6288
|
+
\t\t\t\tif ( materialProperties.needsLights && ( materialProperties.lightsStateVersion !== lights.state.version ) ) {`,
|
|
6289
|
+
fileName,
|
|
6290
|
+
"WebGLRenderer light re-wire across render states",
|
|
6291
|
+
);
|
|
5752
6292
|
}
|
|
5753
6293
|
if (normalized.endsWith("/three/src/renderers/webgl/WebGLShadowMap.js")) {
|
|
6294
|
+
// An app that replaces `shadowMap.render` (the browser's cached sun shadow)
|
|
6295
|
+
// cannot do so natively: the field holds a `this`-bound function expression
|
|
6296
|
+
// no app function converts to. This hook is an ordinary function-typed
|
|
6297
|
+
// field instead; render() offers each call to it first, and a hook that
|
|
6298
|
+
// returns true has rendered the shadows itself.
|
|
6299
|
+
transformed = replaceOne(
|
|
6300
|
+
transformed,
|
|
6301
|
+
"\tconst scope = this;\n",
|
|
6302
|
+
"\tconst scope = this;\n\n\t/** @type {((lights: Array<import('../../lights/Light.js').Light>, scene: import('../../scenes/Scene.js').Scene, camera: import('../../cameras/Camera.js').Camera) => boolean)|null} */\n\tthis.nativeRenderHook = null;\n",
|
|
6303
|
+
fileName,
|
|
6304
|
+
"WebGLShadowMap native render hook field",
|
|
6305
|
+
);
|
|
6306
|
+
transformed = replaceOne(
|
|
6307
|
+
transformed,
|
|
6308
|
+
"\t\tif ( scope.enabled === false ) return;\n",
|
|
6309
|
+
"\t\tconst nativeRenderHook = scope.nativeRenderHook;\n\t\tif ( nativeRenderHook !== null && nativeRenderHook( lights, scene, camera ) ) return;\n\n\t\tif ( scope.enabled === false ) return;\n",
|
|
6310
|
+
fileName,
|
|
6311
|
+
"WebGLShadowMap native render hook call",
|
|
6312
|
+
);
|
|
5754
6313
|
transformed = replaceOne(
|
|
5755
6314
|
transformed,
|
|
5756
6315
|
"\t\tuniforms: {\n\t\t\tshadow_pass:",
|
|
@@ -6157,13 +6716,9 @@ class WebGLBackgroundCubeMaterial extends ShaderMaterial {
|
|
|
6157
6716
|
\tsetEnvironment( texture ) {
|
|
6158
6717
|
|
|
6159
6718
|
\t\tthis.uniforms.envMap.value = texture;
|
|
6160
|
-
|
|
6161
|
-
\t
|
|
6162
|
-
|
|
6163
|
-
\t/** @this {WebGLBackgroundCubeMaterial} */
|
|
6164
|
-
\tget envMap() {
|
|
6165
|
-
|
|
6166
|
-
\t\treturn uniformTexture( this.uniforms.envMap );
|
|
6719
|
+
\t\t// The renderer reads material.envMap as the base Material field (a subclass getter is not
|
|
6720
|
+
\t\t// dispatched through that read), so keep the field itself in step.
|
|
6721
|
+
\t\tthis.envMap = texture;
|
|
6167
6722
|
|
|
6168
6723
|
\t}
|
|
6169
6724
|
|
|
@@ -6175,13 +6730,7 @@ class WebGLBackgroundPlaneMaterial extends ShaderMaterial {
|
|
|
6175
6730
|
\tsetMap( texture ) {
|
|
6176
6731
|
|
|
6177
6732
|
\t\tthis.uniforms.t2D.value = texture;
|
|
6178
|
-
|
|
6179
|
-
\t}
|
|
6180
|
-
|
|
6181
|
-
\t/** @this {WebGLBackgroundPlaneMaterial} */
|
|
6182
|
-
\tget map() {
|
|
6183
|
-
|
|
6184
|
-
\t\treturn uniformTexture( this.uniforms.t2D );
|
|
6733
|
+
\t\tthis.map = texture;
|
|
6185
6734
|
|
|
6186
6735
|
\t}
|
|
6187
6736
|
|
|
@@ -6551,23 +7100,31 @@ class WebGLBackgroundPlaneMaterial extends ShaderMaterial {
|
|
|
6551
7100
|
transformed = transformUniformsUtils(transformed, fileName);
|
|
6552
7101
|
}
|
|
6553
7102
|
if (normalized.endsWith("/three/src/utils.js")) {
|
|
6554
|
-
|
|
6555
|
-
|
|
6556
|
-
|
|
6557
|
-
const
|
|
6558
|
-
if (
|
|
6559
|
-
probeStartIndex < 0 ||
|
|
6560
|
-
probeEndIndex < 0 ||
|
|
6561
|
-
transformed.indexOf(probeStart, probeStartIndex + 1) >= 0
|
|
6562
|
-
) {
|
|
7103
|
+
// probeAsync keeps three's fence polling (the host implements fenceSync/clientWaitSync, so the
|
|
7104
|
+
// async readback resolves when the GPU has finished the copy), once per frame: setTimeout's result
|
|
7105
|
+
// types as Node's Timeout, which has no native boundary.
|
|
7106
|
+
const probeRetries = transformed.split("setTimeout( probe, interval );").length - 1;
|
|
7107
|
+
if (probeRetries !== 2) {
|
|
6563
7108
|
throw new Error(
|
|
6564
|
-
`Three async WebGL probe source at ${fileName}
|
|
7109
|
+
`Three async WebGL probe source at ${fileName} has ${probeRetries} probe timers; expected 2`,
|
|
6565
7110
|
);
|
|
6566
7111
|
}
|
|
7112
|
+
transformed = transformed.replaceAll("setTimeout( probe, interval );", "requestAnimationFrame( probe );");
|
|
7113
|
+
// Resolve with the sync status: a value-less resolve() of a Promise<void> lowers its optional
|
|
7114
|
+
// payload incorrectly, and the callers only await completion.
|
|
7115
|
+
const probeAt = transformed.indexOf("function probeAsync( gl, sync, interval ) {");
|
|
7116
|
+
const probeDocAt = transformed.lastIndexOf(" * @return {Promise<void>}", probeAt);
|
|
7117
|
+
const probeEndAt = transformed.indexOf("\n}\n", probeAt);
|
|
7118
|
+
const probeBody = transformed.slice(probeAt, probeEndAt);
|
|
7119
|
+
if (probeAt < 0 || probeDocAt < 0 || probeDocAt < transformed.lastIndexOf("/**", probeAt) || probeBody.split("resolve();").length !== 2) {
|
|
7120
|
+
throw new Error(`Three async WebGL probe source at ${fileName} no longer matches the native adaptation`);
|
|
7121
|
+
}
|
|
6567
7122
|
transformed =
|
|
6568
|
-
transformed.slice(0,
|
|
6569
|
-
"
|
|
6570
|
-
transformed.slice(
|
|
7123
|
+
transformed.slice(0, probeDocAt) +
|
|
7124
|
+
" * @return {Promise<number>}" +
|
|
7125
|
+
transformed.slice(probeDocAt + " * @return {Promise<void>}".length, probeAt) +
|
|
7126
|
+
probeBody.replace("resolve();", "resolve( 1 );") +
|
|
7127
|
+
transformed.slice(probeEndAt);
|
|
6571
7128
|
transformed = replaceOne(
|
|
6572
7129
|
transformed,
|
|
6573
7130
|
"\t\t\tparams[ 0 ] += ' ' + stackTrace.getLocation();",
|
|
@@ -6633,13 +7190,6 @@ class WebGLBackgroundPlaneMaterial extends ShaderMaterial {
|
|
|
6633
7190
|
`Three utils source at ${fileName} has ${warnCalls} console.warn calls; expected 2`,
|
|
6634
7191
|
);
|
|
6635
7192
|
transformed = transformed.replaceAll("console.warn(", "console.error(");
|
|
6636
|
-
transformed = replaceOne(
|
|
6637
|
-
transformed,
|
|
6638
|
-
"@param {number} interval - The polling interval in milliseconds.\n * @return {Promise<void>} A promise that resolves when the sync completes or rejects if it fails.",
|
|
6639
|
-
"@param {number} interval - The polling interval in milliseconds.\n * @return {Promise<undefined>} A promise that resolves when the sync completes or rejects if it fails.",
|
|
6640
|
-
fileName,
|
|
6641
|
-
"probeAsync resolved payload",
|
|
6642
|
-
);
|
|
6643
7193
|
}
|
|
6644
7194
|
if (
|
|
6645
7195
|
normalized.endsWith("/three/src/renderers/webgl/WebGLClipping.js") &&
|
|
@@ -7319,6 +7869,76 @@ ${indent}}`,
|
|
|
7319
7869
|
fileName,
|
|
7320
7870
|
"WebGLBindingStates wireframe cache write",
|
|
7321
7871
|
);
|
|
7872
|
+
// The nested cache is keyed by ids spelled as strings, so every draw formats
|
|
7873
|
+
// three numbers and hashes them through string dictionaries. A numeric front
|
|
7874
|
+
// cache answers repeat lookups: geometry id, then one exact integer packing
|
|
7875
|
+
// object id, program id and wireframe (program ids past 2^16 skip it). Any
|
|
7876
|
+
// release clears it before the nested states are deleted, so it never holds a
|
|
7877
|
+
// state the nested cache no longer has.
|
|
7878
|
+
transformed = replaceOne(
|
|
7879
|
+
transformed,
|
|
7880
|
+
"\tconst bindingStates = {};",
|
|
7881
|
+
"\tconst bindingStates = {};\n\t/** @type {Map<number, Map<number, NativeBindingState>>} */\n\tconst fastBindingStates = new Map();",
|
|
7882
|
+
fileName,
|
|
7883
|
+
"WebGLBindingStates numeric front cache",
|
|
7884
|
+
);
|
|
7885
|
+
transformed = replaceOne(
|
|
7886
|
+
transformed,
|
|
7887
|
+
"\t\tconst wireframe = ( material.wireframe === true );\n\n\t\tlet objectMap = bindingStates[ geometry.id ];",
|
|
7888
|
+
`\t\tconst wireframe = ( material.wireframe === true );
|
|
7889
|
+
\t\tconst fastKey = program.id < 65536 ? ( ( ( object.isInstancedMesh === true ) ? object.id : 0 ) * 65536 + program.id ) * 2 + ( wireframe ? 1 : 0 ) : - 1;
|
|
7890
|
+
\t\tlet fastGeometry = fastBindingStates.get( geometry.id );
|
|
7891
|
+
|
|
7892
|
+
\t\tif ( fastKey >= 0 && fastGeometry !== undefined ) {
|
|
7893
|
+
|
|
7894
|
+
\t\t\tconst cached = fastGeometry.get( fastKey );
|
|
7895
|
+
|
|
7896
|
+
\t\t\tif ( cached !== undefined ) return cached;
|
|
7897
|
+
|
|
7898
|
+
\t\t}
|
|
7899
|
+
|
|
7900
|
+
\t\tlet objectMap = bindingStates[ geometry.id ];`,
|
|
7901
|
+
fileName,
|
|
7902
|
+
"WebGLBindingStates numeric front cache read",
|
|
7903
|
+
);
|
|
7904
|
+
transformed = replaceOne(
|
|
7905
|
+
transformed,
|
|
7906
|
+
"\t\t\tstateMap[ wireframeKey ] = state;\n\n\t\t}\n\n\t\treturn state;",
|
|
7907
|
+
`\t\t\tstateMap[ wireframeKey ] = state;
|
|
7908
|
+
|
|
7909
|
+
\t\t}
|
|
7910
|
+
|
|
7911
|
+
\t\tif ( fastKey >= 0 ) {
|
|
7912
|
+
|
|
7913
|
+
\t\t\tif ( fastGeometry === undefined ) {
|
|
7914
|
+
|
|
7915
|
+
\t\t\t\tfastGeometry = new Map();
|
|
7916
|
+
\t\t\t\tfastBindingStates.set( geometry.id, fastGeometry );
|
|
7917
|
+
|
|
7918
|
+
\t\t\t}
|
|
7919
|
+
|
|
7920
|
+
\t\t\tfastGeometry.set( fastKey, state );
|
|
7921
|
+
|
|
7922
|
+
\t\t}
|
|
7923
|
+
|
|
7924
|
+
\t\treturn state;`,
|
|
7925
|
+
fileName,
|
|
7926
|
+
"WebGLBindingStates numeric front cache write",
|
|
7927
|
+
);
|
|
7928
|
+
for (const header of [
|
|
7929
|
+
"\tfunction dispose() {\n\n\t\treset();",
|
|
7930
|
+
"\tfunction releaseStatesOfGeometry( geometry ) {",
|
|
7931
|
+
"\tfunction releaseStatesOfProgram( program ) {",
|
|
7932
|
+
"\tfunction releaseStatesOfObject( object ) {",
|
|
7933
|
+
]) {
|
|
7934
|
+
transformed = replaceOne(
|
|
7935
|
+
transformed,
|
|
7936
|
+
header,
|
|
7937
|
+
`${header}\n\n\t\tfastBindingStates.clear();`,
|
|
7938
|
+
fileName,
|
|
7939
|
+
"WebGLBindingStates numeric front cache release",
|
|
7940
|
+
);
|
|
7941
|
+
}
|
|
7322
7942
|
transformed = replaceOne(
|
|
7323
7943
|
transformed,
|
|
7324
7944
|
"\tfunction releaseStatesOfGeometry( geometry ) {",
|
|
@@ -7413,9 +8033,48 @@ ${indent}}`,
|
|
|
7413
8033
|
"geometry._maxInstanceCount = geometryAttribute.meshPerAttribute * geometryAttribute.count;",
|
|
7414
8034
|
"geometry._maxInstanceCount = requireVertexScalar( geometryAttribute.meshPerAttribute ) * requireVertexScalar( geometryAttribute.count );",
|
|
7415
8035
|
);
|
|
8036
|
+
// needsUpdate walked the program's attributes by name on every draw: two
|
|
8037
|
+
// string-keyed lookups per attribute. A binding state is already specific
|
|
8038
|
+
// to its geometry and program, so the set it cached can only change when
|
|
8039
|
+
// the geometry's attribute set changes (setAttribute/deleteAttribute bump
|
|
8040
|
+
// __nativeAttributeStamp) or the object's instance attributes are replaced.
|
|
8041
|
+
// With both unchanged the walk's answer is the index comparison alone.
|
|
8042
|
+
transformed = replaceOne(
|
|
8043
|
+
transformed,
|
|
8044
|
+
"\t\t\tindex: /** @type {import('../../core/BufferAttribute.js').BufferAttribute|null} */ ( null )\n",
|
|
8045
|
+
"\t\t\tindex: /** @type {import('../../core/BufferAttribute.js').BufferAttribute|null} */ ( null ),\n" +
|
|
8046
|
+
"\t\t\tnativeAttributeStamp: - 1,\n" +
|
|
8047
|
+
"\t\t\t/** @type {import('../../core/InstancedBufferAttribute.js').InstancedBufferAttribute|null} */\n" +
|
|
8048
|
+
"\t\t\tnativeInstanceMatrix: null,\n" +
|
|
8049
|
+
"\t\t\t/** @type {import('../../core/InstancedBufferAttribute.js').InstancedBufferAttribute|null} */\n" +
|
|
8050
|
+
"\t\t\tnativeInstanceColor: null\n",
|
|
8051
|
+
fileName,
|
|
8052
|
+
"WebGLBindingStates attribute-set stamp fields",
|
|
8053
|
+
);
|
|
8054
|
+
transformed = replaceOne(
|
|
8055
|
+
transformed,
|
|
8056
|
+
"\tfunction needsUpdate( object, geometry, program, index ) {\n",
|
|
8057
|
+
"\tfunction needsUpdate( object, geometry, program, index ) {\n\n" +
|
|
8058
|
+
"\t\tconst instanced = object instanceof InstancedMesh ? object : null;\n" +
|
|
8059
|
+
"\t\tif ( currentState.nativeAttributeStamp === geometry.__nativeAttributeStamp &&\n" +
|
|
8060
|
+
"\t\t\tcurrentState.nativeInstanceMatrix === ( instanced !== null ? instanced.instanceMatrix : null ) &&\n" +
|
|
8061
|
+
"\t\t\tcurrentState.nativeInstanceColor === ( instanced !== null ? instanced.instanceColor : null ) ) return currentState.index !== index;\n",
|
|
8062
|
+
fileName,
|
|
8063
|
+
"WebGLBindingStates attribute-set fast path",
|
|
8064
|
+
);
|
|
8065
|
+
transformed = replaceOne(
|
|
8066
|
+
transformed,
|
|
8067
|
+
"\t\tcurrentState.attributes = cache;\n\t\tcurrentState.attributesNum = attributesNum;\n",
|
|
8068
|
+
"\t\tcurrentState.attributes = cache;\n\t\tcurrentState.attributesNum = attributesNum;\n" +
|
|
8069
|
+
"\t\tcurrentState.nativeAttributeStamp = geometry.__nativeAttributeStamp;\n" +
|
|
8070
|
+
"\t\tcurrentState.nativeInstanceMatrix = object instanceof InstancedMesh ? object.instanceMatrix : null;\n" +
|
|
8071
|
+
"\t\tcurrentState.nativeInstanceColor = object instanceof InstancedMesh ? object.instanceColor : null;\n",
|
|
8072
|
+
fileName,
|
|
8073
|
+
"WebGLBindingStates attribute-set stamp record",
|
|
8074
|
+
);
|
|
7416
8075
|
}
|
|
7417
8076
|
if (normalized.endsWith("/three/src/renderers/webgl/WebGLObjects.js")) {
|
|
7418
|
-
transformed = `import { BufferGeometry } from '../../core/BufferGeometry.js';\n\n${transformed}`;
|
|
8077
|
+
transformed = `import { BufferGeometry } from '../../core/BufferGeometry.js';\nimport { Object3D } from '../../core/Object3D.js';\n\n${transformed}`;
|
|
7419
8078
|
transformed = replaceOne(
|
|
7420
8079
|
transformed,
|
|
7421
8080
|
"\t\tconst instancedMesh = event.target;",
|
|
@@ -7460,13 +8119,52 @@ ${indent}}`,
|
|
|
7460
8119
|
"updateMap.set( skeleton, frame )",
|
|
7461
8120
|
"skeletonUpdateMap.set( skeleton, frame )",
|
|
7462
8121
|
);
|
|
8122
|
+
// Every pass updates every drawn object, and each update read the geometry's
|
|
8123
|
+
// (and an instanced mesh's) frame out of a WeakMap. The maps stay the
|
|
8124
|
+
// authority; the geometry and object also carry the frame this instance
|
|
8125
|
+
// stored, tagged with its number, so the per-draw read is a field load.
|
|
8126
|
+
transformed = replaceOne(
|
|
8127
|
+
transformed,
|
|
8128
|
+
"function WebGLObjects( gl, geometries, attributes, bindingStates, info ) {\n",
|
|
8129
|
+
"let nextNativeObjectsOwner = 1;\n\nfunction WebGLObjects( gl, geometries, attributes, bindingStates, info ) {\n\n\tconst nativeOwner = nextNativeObjectsOwner ++;\n",
|
|
8130
|
+
fileName,
|
|
8131
|
+
"WebGLObjects front cache owner",
|
|
8132
|
+
);
|
|
7463
8133
|
transformed = replaceOne(
|
|
7464
8134
|
transformed,
|
|
7465
8135
|
"\t\tif ( geometryUpdateMap.get( buffergeometry ) !== frame ) {",
|
|
7466
|
-
"\t\tconst geometryFrame = geometryUpdateMap.get( buffergeometry );\n\n\t\tif ( geometryFrame !== frame ) {",
|
|
8136
|
+
"\t\tconst geometryFrame = buffergeometry.__nativeObjectsOwner === nativeOwner ? buffergeometry.__nativeObjectsFrame : geometryUpdateMap.get( buffergeometry );\n\n\t\tif ( geometryFrame !== frame ) {",
|
|
7467
8137
|
fileName,
|
|
7468
8138
|
"WebGLObjects stable geometry frame lookup",
|
|
7469
8139
|
);
|
|
8140
|
+
transformed = replaceOne(
|
|
8141
|
+
transformed,
|
|
8142
|
+
"\t\t\tgeometryUpdateMap.set( buffergeometry, frame );",
|
|
8143
|
+
"\t\t\tgeometryUpdateMap.set( buffergeometry, frame );\n\t\t\tbuffergeometry.__nativeObjectsOwner = nativeOwner;\n\t\t\tbuffergeometry.__nativeObjectsFrame = frame;",
|
|
8144
|
+
fileName,
|
|
8145
|
+
"WebGLObjects geometry frame front cache",
|
|
8146
|
+
);
|
|
8147
|
+
transformed = replaceOne(
|
|
8148
|
+
transformed,
|
|
8149
|
+
"\t\t\tif ( instancedMeshUpdateMap.get( object ) !== frame ) {",
|
|
8150
|
+
"\t\t\tif ( ( object.__nativeObjectsOwner === nativeOwner ? object.__nativeObjectsFrame : instancedMeshUpdateMap.get( object ) ) !== frame ) {",
|
|
8151
|
+
fileName,
|
|
8152
|
+
"WebGLObjects instanced frame lookup",
|
|
8153
|
+
);
|
|
8154
|
+
transformed = replaceOne(
|
|
8155
|
+
transformed,
|
|
8156
|
+
"\t\t\t\tinstancedMeshUpdateMap.set( object, frame );",
|
|
8157
|
+
"\t\t\t\tinstancedMeshUpdateMap.set( object, frame );\n\t\t\t\tobject.__nativeObjectsOwner = nativeOwner;\n\t\t\t\tobject.__nativeObjectsFrame = frame;",
|
|
8158
|
+
fileName,
|
|
8159
|
+
"WebGLObjects instanced frame front cache",
|
|
8160
|
+
);
|
|
8161
|
+
transformed = replaceOne(
|
|
8162
|
+
transformed,
|
|
8163
|
+
"\t\tinstancedMeshUpdateMap.delete( instancedMesh );",
|
|
8164
|
+
"\t\tinstancedMeshUpdateMap.delete( instancedMesh );\n\n\t\tif ( instancedMesh instanceof Object3D && instancedMesh.__nativeObjectsOwner === nativeOwner ) instancedMesh.__nativeObjectsOwner = 0;",
|
|
8165
|
+
fileName,
|
|
8166
|
+
"WebGLObjects instanced front cache cleanup",
|
|
8167
|
+
);
|
|
7470
8168
|
transformed = replaceOne(
|
|
7471
8169
|
transformed,
|
|
7472
8170
|
"\t\t\tgeometries.update( buffergeometry );",
|
|
@@ -7493,6 +8191,7 @@ ${indent}}`,
|
|
|
7493
8191
|
|
|
7494
8192
|
\t\tbuffergeometry.removeEventListener( 'dispose', onBufferGeometryDispose );
|
|
7495
8193
|
\t\tgeometryUpdateMap.delete( buffergeometry );
|
|
8194
|
+
\t\tif ( buffergeometry.__nativeObjectsOwner === nativeOwner ) buffergeometry.__nativeObjectsOwner = 0;
|
|
7496
8195
|
|
|
7497
8196
|
\t}
|
|
7498
8197
|
|
|
@@ -7588,12 +8287,22 @@ class NativeWebGLPropertyBag {
|
|
|
7588
8287
|
\t\tthis.needsLights = undefined;
|
|
7589
8288
|
\t\t/** @type {number} */
|
|
7590
8289
|
\t\tthis.lightsStateVersion = -1;
|
|
8290
|
+
\t\t/** @type {number} light structure (WebGLLights nativeStructure) the program was built for */
|
|
8291
|
+
\t\tthis.nativeLightsStructure = -1;
|
|
8292
|
+
\t\t/** @type {number} shadow caster count the program was built for */
|
|
8293
|
+
\t\tthis.nativeShadowCount = -1;
|
|
7591
8294
|
\t\t/** @type {boolean|import('./WebGLRenderStates.js').NativeLightProbeGrid|null} */
|
|
7592
8295
|
\t\tthis.lightProbeGrid = null;
|
|
7593
8296
|
\t\t/** @type {import('../shaders/UniformsLib.js').NativeUniforms} */
|
|
7594
8297
|
\t\tthis.uniforms = {};
|
|
7595
8298
|
\t\t/** @type {Array<import('./WebGLUniforms.js').NativeUniform>|null} */
|
|
7596
8299
|
\t\tthis.uniformsList = null;
|
|
8300
|
+
\t\t/** @type {Array<import('../shaders/UniformsLib.js').NativeUniformSlot|undefined>|undefined} The value cells of \`uniformsList\`, in order. */
|
|
8301
|
+
\t\tthis.nativeUniformSlots = undefined;
|
|
8302
|
+
\t\t/** @type {Array<import('./WebGLUniforms.js').NativeUniform>|null} The list \`nativeUniformSlots\` was resolved for. */
|
|
8303
|
+
\t\tthis.nativeUniformSlotsList = null;
|
|
8304
|
+
\t\t/** @type {NativeMaterialCells|undefined} */
|
|
8305
|
+
\t\tthis.nativeCells = undefined;
|
|
7597
8306
|
\t\t/** @type {string} */
|
|
7598
8307
|
\t\tthis.outputColorSpace = '';
|
|
7599
8308
|
\t\t/** @type {boolean} */
|
|
@@ -7657,49 +8366,148 @@ class NativeWebGLPropertyBag {
|
|
|
7657
8366
|
|
|
7658
8367
|
}
|
|
7659
8368
|
|
|
8369
|
+
/**
|
|
8370
|
+
* The value cells of one material uniforms object that WebGLRenderer touches on
|
|
8371
|
+
* every draw or every refresh, resolved once instead of by name each time.
|
|
8372
|
+
* Built for one uniforms object; a material given another gets a new one.
|
|
8373
|
+
*/
|
|
8374
|
+
class NativeMaterialCells {
|
|
8375
|
+
|
|
8376
|
+
\t/** @param {import('../shaders/UniformsLib.js').NativeUniforms} uniforms */
|
|
8377
|
+
\tconstructor( uniforms ) {
|
|
8378
|
+
|
|
8379
|
+
\t\tthis.uniforms = uniforms;
|
|
8380
|
+
\t\t/** @type {import('../shaders/UniformsLib.js').NativeUniformSlot|undefined} */
|
|
8381
|
+
\t\tthis.envMapIntensity = uniforms.envMapIntensity;
|
|
8382
|
+
\t\t/** @type {import('../shaders/UniformsLib.js').NativeUniformSlot|undefined} */
|
|
8383
|
+
\t\tthis.dfgLUT = uniforms.dfgLUT;
|
|
8384
|
+
\t\t/** @type {Array<import('../shaders/UniformsLib.js').NativeUniformSlot>} The light cells markUniformsLightsNeedsUpdate flags. */
|
|
8385
|
+
\t\tthis.lights = [];
|
|
8386
|
+
\t\tfor ( const name of [ 'ambientLightColor', 'lightProbe', 'directionalLights', 'directionalLightShadows', 'pointLights', 'pointLightShadows', 'spotLights', 'spotLightShadows', 'rectAreaLights', 'hemisphereLights' ] ) {
|
|
8387
|
+
|
|
8388
|
+
\t\t\tconst cell = uniforms[ name ];
|
|
8389
|
+
\t\t\tif ( cell !== undefined ) this.lights.push( cell );
|
|
8390
|
+
|
|
8391
|
+
\t\t}
|
|
8392
|
+
|
|
8393
|
+
\t}
|
|
8394
|
+
|
|
8395
|
+
}
|
|
8396
|
+
|
|
8397
|
+
let nextNativePropertiesOwner = 1;
|
|
8398
|
+
|
|
7660
8399
|
function WebGLProperties() {
|
|
7661
8400
|
|
|
7662
|
-
\
|
|
7663
|
-
\tconst properties = new Map();
|
|
8401
|
+
\tlet nativeOwner = nextNativePropertiesOwner ++;
|
|
7664
8402
|
|
|
7665
|
-
\t
|
|
7666
|
-
\
|
|
8403
|
+
\t// One map per owner kind, keyed by the owner's numeric id: a lookup per draw
|
|
8404
|
+
\t// hashes a number instead of building and hashing a 'kind:id' string. A render
|
|
8405
|
+
\t// target is keyed by its texture's id in its own map, as before.
|
|
8406
|
+
\t/** @type {Map<number, NativeWebGLPropertyBag>} */
|
|
8407
|
+
\tconst materials = new Map();
|
|
8408
|
+
\t/** @type {Map<number, NativeWebGLPropertyBag>} */
|
|
8409
|
+
\tconst sources = new Map();
|
|
8410
|
+
\t/** @type {Map<number, NativeWebGLPropertyBag>} */
|
|
8411
|
+
\tconst textures = new Map();
|
|
8412
|
+
\t/** @type {Map<number, NativeWebGLPropertyBag>} */
|
|
8413
|
+
\tconst targets = new Map();
|
|
8414
|
+
|
|
8415
|
+
\t/** @param {WebGLPropertyOwner} object @return {Map<number, NativeWebGLPropertyBag>} */
|
|
8416
|
+
\tfunction propertyMap( object ) {
|
|
8417
|
+
|
|
8418
|
+
\t\tif ( object instanceof Material ) return materials;
|
|
8419
|
+
\t\tif ( object instanceof Source ) return sources;
|
|
8420
|
+
\t\tif ( object instanceof Texture ) return textures;
|
|
8421
|
+
\t\treturn targets;
|
|
8422
|
+
|
|
8423
|
+
\t}
|
|
8424
|
+
|
|
8425
|
+
\t/** @param {WebGLPropertyOwner} object @return {number} */
|
|
8426
|
+
\tfunction propertyId( object ) {
|
|
8427
|
+
|
|
8428
|
+
\t\tif ( object instanceof Material ) return object.id;
|
|
8429
|
+
\t\tif ( object instanceof Source ) return object.id;
|
|
8430
|
+
\t\tif ( object instanceof Texture ) return object.id;
|
|
8431
|
+
\t\treturn object.texture.id;
|
|
8432
|
+
|
|
8433
|
+
\t}
|
|
8434
|
+
|
|
8435
|
+
\t/** @param {Map<number, NativeWebGLPropertyBag>} map @param {number} id @return {NativeWebGLPropertyBag} */
|
|
8436
|
+
\tfunction bagIn( map, id ) {
|
|
8437
|
+
|
|
8438
|
+
\t\tlet bag = map.get( id );
|
|
8439
|
+
|
|
8440
|
+
\t\tif ( bag === undefined ) {
|
|
8441
|
+
|
|
8442
|
+
\t\t\tbag = new NativeWebGLPropertyBag();
|
|
8443
|
+
\t\t\tmap.set( id, bag );
|
|
8444
|
+
|
|
8445
|
+
\t\t}
|
|
7667
8446
|
|
|
7668
|
-
\t\
|
|
7669
|
-
\t\tif ( object instanceof Source ) return 'source:' + object.id;
|
|
7670
|
-
\t\tif ( object instanceof Texture ) return 'texture:' + object.id;
|
|
7671
|
-
\t\treturn 'target:' + object.texture.id;
|
|
8447
|
+
\t\treturn bag;
|
|
7672
8448
|
|
|
7673
8449
|
\t}
|
|
7674
8450
|
|
|
7675
8451
|
\t/** @param {WebGLPropertyOwner} object */
|
|
7676
8452
|
\tfunction has( object ) {
|
|
7677
8453
|
|
|
7678
|
-
\t\treturn
|
|
8454
|
+
\t\treturn propertyMap( object ).has( propertyId( object ) );
|
|
7679
8455
|
|
|
7680
8456
|
\t}
|
|
7681
8457
|
|
|
7682
8458
|
\t/** @param {WebGLPropertyOwner} object */
|
|
7683
8459
|
\tfunction get( object ) {
|
|
7684
8460
|
|
|
7685
|
-
\t\
|
|
7686
|
-
\t\
|
|
8461
|
+
\t\t// Materials, sources and textures are read on every draw (textures once per
|
|
8462
|
+
\t\t// bound sampler). Each also carries the bag this instance stored for it,
|
|
8463
|
+
\t\t// tagged with the instance's number, so the read is a field load; the maps
|
|
8464
|
+
\t\t// stay the authority and remove/dispose keep the fields in step.
|
|
8465
|
+
\t\tif ( object instanceof Material ) {
|
|
8466
|
+
|
|
8467
|
+
\t\t\tif ( object.__nativePropertiesOwner === nativeOwner && object.__nativeProperties !== undefined ) return object.__nativeProperties;
|
|
8468
|
+
\t\t\tconst bag = bagIn( materials, object.id );
|
|
8469
|
+
\t\t\tobject.__nativePropertiesOwner = nativeOwner;
|
|
8470
|
+
\t\t\tobject.__nativeProperties = bag;
|
|
8471
|
+
\t\t\treturn bag;
|
|
7687
8472
|
|
|
7688
|
-
\t\
|
|
8473
|
+
\t\t}
|
|
8474
|
+
\t\tif ( object instanceof Source ) {
|
|
7689
8475
|
|
|
7690
|
-
\t\t\
|
|
7691
|
-
\t\t\
|
|
8476
|
+
\t\t\tif ( object.__nativePropertiesOwner === nativeOwner && object.__nativeProperties !== undefined ) return object.__nativeProperties;
|
|
8477
|
+
\t\t\tconst bag = bagIn( sources, object.id );
|
|
8478
|
+
\t\t\tobject.__nativePropertiesOwner = nativeOwner;
|
|
8479
|
+
\t\t\tobject.__nativeProperties = bag;
|
|
8480
|
+
\t\t\treturn bag;
|
|
7692
8481
|
|
|
7693
8482
|
\t\t}
|
|
8483
|
+
\t\tif ( object instanceof Texture ) {
|
|
7694
8484
|
|
|
7695
|
-
\t\
|
|
8485
|
+
\t\t\tif ( object.__nativePropertiesOwner === nativeOwner && object.__nativeProperties !== undefined ) return object.__nativeProperties;
|
|
8486
|
+
\t\t\tconst bag = bagIn( textures, object.id );
|
|
8487
|
+
\t\t\tobject.__nativePropertiesOwner = nativeOwner;
|
|
8488
|
+
\t\t\tobject.__nativeProperties = bag;
|
|
8489
|
+
\t\t\treturn bag;
|
|
8490
|
+
|
|
8491
|
+
\t\t}
|
|
8492
|
+
\t\treturn bagIn( targets, object.texture.id );
|
|
7696
8493
|
|
|
7697
8494
|
\t}
|
|
7698
8495
|
|
|
7699
8496
|
\t/** @param {WebGLPropertyOwner} object */
|
|
7700
8497
|
\tfunction remove( object ) {
|
|
7701
8498
|
|
|
7702
|
-
\t\
|
|
8499
|
+
\t\tpropertyMap( object ).delete( propertyId( object ) );
|
|
8500
|
+
|
|
8501
|
+
\t\tif ( object instanceof Material || object instanceof Source || object instanceof Texture ) {
|
|
8502
|
+
|
|
8503
|
+
\t\t\tif ( object.__nativePropertiesOwner === nativeOwner ) {
|
|
8504
|
+
|
|
8505
|
+
\t\t\t\tobject.__nativePropertiesOwner = 0;
|
|
8506
|
+
\t\t\t\tobject.__nativeProperties = undefined;
|
|
8507
|
+
|
|
8508
|
+
\t\t\t}
|
|
8509
|
+
|
|
8510
|
+
\t\t}
|
|
7703
8511
|
|
|
7704
8512
|
\t}
|
|
7705
8513
|
|
|
@@ -7716,7 +8524,12 @@ function WebGLProperties() {
|
|
|
7716
8524
|
|
|
7717
8525
|
\tfunction dispose() {
|
|
7718
8526
|
|
|
7719
|
-
\t\
|
|
8527
|
+
\t\tmaterials.clear();
|
|
8528
|
+
\t\tsources.clear();
|
|
8529
|
+
\t\ttextures.clear();
|
|
8530
|
+
\t\ttargets.clear();
|
|
8531
|
+
\t\t// Every field still tagged with the old number is now stale.
|
|
8532
|
+
\t\tnativeOwner = nextNativePropertiesOwner ++;
|
|
7720
8533
|
|
|
7721
8534
|
\t}
|
|
7722
8535
|
|
|
@@ -7724,7 +8537,7 @@ function WebGLProperties() {
|
|
|
7724
8537
|
|
|
7725
8538
|
}
|
|
7726
8539
|
|
|
7727
|
-
export { WebGLProperties };
|
|
8540
|
+
export { WebGLProperties, NativeWebGLPropertyBag, NativeMaterialCells };
|
|
7728
8541
|
`;
|
|
7729
8542
|
}
|
|
7730
8543
|
if (normalized.endsWith("/three/src/renderers/webgl/WebGLInfo.js")) {
|
|
@@ -8848,9 +9661,31 @@ function WebGLRenderState( extensions ) {`,
|
|
|
8848
9661
|
|
|
8849
9662
|
\t\t\trenderTarget.depthTexture.image.width = renderTarget.width;
|
|
8850
9663
|
\t\t\trenderTarget.depthTexture.image.height = renderTarget.height;`,
|
|
8851
|
-
`\t\
|
|
9664
|
+
`\t\t// A render target disposed before it was set up again has no onRenderTargetDispose listener, so a
|
|
9665
|
+
\t\t// second dispose (RenderTarget.setSize) leaves its depth texture alone; and a material that samples
|
|
9666
|
+
\t\t// that depth texture meanwhile re-uploads it at its old image size (setSize does not resize
|
|
9667
|
+
\t\t// depthTexture.image). The size check below then only marks it needsUpdate, which never re-specifies
|
|
9668
|
+
\t\t// immutable texStorage2D storage: the target was set up with a depth attachment of the old size (a
|
|
9669
|
+
\t\t// multisample resolve past it removes the D3D12 device; WebGL reports FRAMEBUFFER_INCOMPLETE_DIMENSIONS).
|
|
9670
|
+
\t\t// Release that storage here so the upload below allocates it at the target's size.
|
|
9671
|
+
\t\tif ( ! isCube && properties.has( renderTarget.depthTexture ) ) {
|
|
9672
|
+
|
|
9673
|
+
\t\t\tconst allocated = properties.get( renderTarget.depthTexture );
|
|
9674
|
+
\t\t\tconst allocatedImage = requireTextureImageRecord( renderTarget.depthTexture.image );
|
|
9675
|
+
|
|
9676
|
+
\t\t\tif ( allocated.__webglTexture !== undefined && allocated.__webglTexture !== null &&
|
|
9677
|
+
\t\t\t\t( allocatedImage.width !== renderTarget.width || allocatedImage.height !== renderTarget.height ) ) {
|
|
9678
|
+
|
|
9679
|
+
\t\t\t\tdeallocateTexture( renderTarget.depthTexture );
|
|
9680
|
+
|
|
9681
|
+
\t\t\t}
|
|
9682
|
+
|
|
9683
|
+
\t\t}
|
|
9684
|
+
|
|
9685
|
+
\t\tconst textureProperties = properties.get( renderTarget.depthTexture );
|
|
8852
9686
|
\t\ttextureProperties.__renderTarget = renderTarget;
|
|
8853
|
-
\t\
|
|
9687
|
+
\t\t// A CubeDepthTexture's image is its six face records (one shared object); size it through face 0.
|
|
9688
|
+
\t\tconst depthTextureImage = isCube ? requireTextureImageRecords( renderTarget.depthTexture.image )[ 0 ] : requireTextureImageRecord( renderTarget.depthTexture.image );
|
|
8854
9689
|
|
|
8855
9690
|
\t\t// upload an empty depth texture with framebuffer size
|
|
8856
9691
|
\t\tif ( ! textureProperties.__webglTexture ||
|
|
@@ -8858,7 +9693,10 @@ function WebGLRenderState( extensions ) {`,
|
|
|
8858
9693
|
\t\t\t\tdepthTextureImage.height !== renderTarget.height ) {
|
|
8859
9694
|
|
|
8860
9695
|
\t\t\tdepthTextureImage.width = renderTarget.width;
|
|
8861
|
-
\t\t\tdepthTextureImage.height = renderTarget.height
|
|
9696
|
+
\t\t\tdepthTextureImage.height = renderTarget.height;
|
|
9697
|
+
\t\t\t// requireTextureImageRecord returns a copy, so a 2D depth texture's own image must be replaced
|
|
9698
|
+
\t\t\t// for the upload below to use the new size (upstream writes the image in place).
|
|
9699
|
+
\t\t\tif ( ! isCube ) renderTarget.depthTexture.image = { width: renderTarget.width, height: renderTarget.height, depth: depthTextureImage.depth !== undefined ? depthTextureImage.depth : 1 };`,
|
|
8862
9700
|
fileName,
|
|
8863
9701
|
"WebGLTextures depth image record narrowing",
|
|
8864
9702
|
);
|
|
@@ -8939,7 +9777,9 @@ function WebGLRenderState( extensions ) {`,
|
|
|
8939
9777
|
);
|
|
8940
9778
|
transformed =
|
|
8941
9779
|
transformed.slice(0, dimensionsStartIndex) +
|
|
8942
|
-
|
|
9780
|
+
// The records reaching here already carry width and height; passing them through
|
|
9781
|
+
// requireTextureImageRecord recasts them into a nested union the emitter drops to undefined.
|
|
9782
|
+
"\tfunction getDimensions( image ) {\n\n\t\t_imageDimensions.width = image.width;\n\t\t_imageDimensions.height = image.height;\n\n\t\treturn _imageDimensions;" +
|
|
8943
9783
|
transformed.slice(dimensionsEndIndex);
|
|
8944
9784
|
transformed = replaceOne(
|
|
8945
9785
|
transformed,
|
|
@@ -10216,6 +11056,11 @@ class Texture extends EventDispatcher {`,
|
|
|
10216
11056
|
fileName,
|
|
10217
11057
|
"native volume texture source image",
|
|
10218
11058
|
);
|
|
11059
|
+
// Same JSDoc defect as DataTexture: a number documented as `boolean`. Without
|
|
11060
|
+
// the correction an array texture is not a Texture and cannot be a uniform.
|
|
11061
|
+
transformed = transformed
|
|
11062
|
+
.replace(dataTextureUnpackAlignmentSource, nativeDataTextureUnpackAlignmentSource)
|
|
11063
|
+
.replace(dataTextureOverlayUnpackAlignmentSource, nativeDataTextureOverlayUnpackAlignmentSource);
|
|
10219
11064
|
}
|
|
10220
11065
|
if (normalized.endsWith("/three/src/textures/ExternalTexture.js")) {
|
|
10221
11066
|
transformed = replaceOne(
|