@luma.gl/webgl 9.1.0-beta.9 → 9.2.0-alpha.1

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.
Files changed (189) hide show
  1. package/dist/adapter/converters/device-parameters.js +14 -9
  2. package/dist/adapter/converters/device-parameters.js.map +1 -1
  3. package/dist/adapter/converters/shader-formats.d.ts +67 -8
  4. package/dist/adapter/converters/shader-formats.d.ts.map +1 -1
  5. package/dist/adapter/converters/shader-formats.js +82 -52
  6. package/dist/adapter/converters/shader-formats.js.map +1 -1
  7. package/dist/adapter/converters/webgl-shadertypes.d.ts +20 -0
  8. package/dist/adapter/converters/webgl-shadertypes.d.ts.map +1 -0
  9. package/dist/adapter/converters/webgl-shadertypes.js +123 -0
  10. package/dist/adapter/converters/webgl-shadertypes.js.map +1 -0
  11. package/dist/adapter/converters/webgl-texture-table.js +6 -6
  12. package/dist/adapter/converters/webgl-texture-table.js.map +1 -1
  13. package/dist/adapter/converters/{vertex-formats.d.ts → webgl-vertex-formats.d.ts} +4 -4
  14. package/dist/adapter/converters/webgl-vertex-formats.d.ts.map +1 -0
  15. package/dist/adapter/converters/{vertex-formats.js → webgl-vertex-formats.js} +1 -1
  16. package/dist/adapter/converters/webgl-vertex-formats.js.map +1 -0
  17. package/dist/adapter/device-helpers/webgl-device-features.d.ts.map +1 -1
  18. package/dist/adapter/device-helpers/webgl-device-features.js.map +1 -1
  19. package/dist/adapter/device-helpers/webgl-device-limits.d.ts +1 -1
  20. package/dist/adapter/device-helpers/webgl-device-limits.d.ts.map +1 -1
  21. package/dist/adapter/device-helpers/webgl-device-limits.js +1 -1
  22. package/dist/adapter/device-helpers/webgl-device-limits.js.map +1 -1
  23. package/dist/adapter/helpers/format-utils.d.ts +3 -2
  24. package/dist/adapter/helpers/format-utils.d.ts.map +1 -1
  25. package/dist/adapter/helpers/format-utils.js.map +1 -1
  26. package/dist/adapter/helpers/{get-shader-layout.d.ts → get-shader-layout-from-glsl.d.ts} +1 -1
  27. package/dist/adapter/helpers/get-shader-layout-from-glsl.d.ts.map +1 -0
  28. package/dist/adapter/helpers/{get-shader-layout.js → get-shader-layout-from-glsl.js} +12 -35
  29. package/dist/adapter/helpers/get-shader-layout-from-glsl.js.map +1 -0
  30. package/dist/adapter/helpers/set-uniform.d.ts +2 -2
  31. package/dist/adapter/helpers/set-uniform.d.ts.map +1 -1
  32. package/dist/adapter/helpers/set-uniform.js.map +1 -1
  33. package/dist/adapter/helpers/webgl-texture-utils.d.ts +2 -25
  34. package/dist/adapter/helpers/webgl-texture-utils.d.ts.map +1 -1
  35. package/dist/adapter/helpers/webgl-texture-utils.js +10 -99
  36. package/dist/adapter/helpers/webgl-texture-utils.js.map +1 -1
  37. package/dist/adapter/resources/webgl-buffer.d.ts.map +1 -1
  38. package/dist/adapter/resources/webgl-buffer.js +5 -3
  39. package/dist/adapter/resources/webgl-buffer.js.map +1 -1
  40. package/dist/adapter/resources/webgl-command-buffer.d.ts +2 -2
  41. package/dist/adapter/resources/webgl-command-buffer.d.ts.map +1 -1
  42. package/dist/adapter/resources/webgl-command-buffer.js +4 -4
  43. package/dist/adapter/resources/webgl-command-buffer.js.map +1 -1
  44. package/dist/adapter/resources/webgl-command-encoder.d.ts +6 -2
  45. package/dist/adapter/resources/webgl-command-encoder.d.ts.map +1 -1
  46. package/dist/adapter/resources/webgl-command-encoder.js +9 -4
  47. package/dist/adapter/resources/webgl-command-encoder.js.map +1 -1
  48. package/dist/adapter/resources/webgl-external-texture.js +1 -0
  49. package/dist/adapter/resources/webgl-external-texture.js.map +1 -1
  50. package/dist/adapter/resources/webgl-framebuffer.js +2 -2
  51. package/dist/adapter/resources/webgl-framebuffer.js.map +1 -1
  52. package/dist/adapter/resources/webgl-query-set.d.ts.map +1 -1
  53. package/dist/adapter/resources/webgl-query-set.js +5 -1
  54. package/dist/adapter/resources/webgl-query-set.js.map +1 -1
  55. package/dist/adapter/resources/webgl-render-pass.d.ts.map +1 -1
  56. package/dist/adapter/resources/webgl-render-pass.js +11 -6
  57. package/dist/adapter/resources/webgl-render-pass.js.map +1 -1
  58. package/dist/adapter/resources/webgl-render-pipeline.d.ts +3 -3
  59. package/dist/adapter/resources/webgl-render-pipeline.d.ts.map +1 -1
  60. package/dist/adapter/resources/webgl-render-pipeline.js +27 -24
  61. package/dist/adapter/resources/webgl-render-pipeline.js.map +1 -1
  62. package/dist/adapter/resources/webgl-sampler.js +1 -1
  63. package/dist/adapter/resources/webgl-sampler.js.map +1 -1
  64. package/dist/adapter/resources/webgl-shader.d.ts.map +1 -1
  65. package/dist/adapter/resources/webgl-shader.js +9 -2
  66. package/dist/adapter/resources/webgl-shader.js.map +1 -1
  67. package/dist/adapter/resources/webgl-texture-view.js +1 -1
  68. package/dist/adapter/resources/webgl-texture-view.js.map +1 -1
  69. package/dist/adapter/resources/webgl-texture.d.ts +21 -66
  70. package/dist/adapter/resources/webgl-texture.d.ts.map +1 -1
  71. package/dist/adapter/resources/webgl-texture.js +148 -319
  72. package/dist/adapter/resources/webgl-texture.js.map +1 -1
  73. package/dist/adapter/resources/webgl-transform-feedback.d.ts +1 -1
  74. package/dist/adapter/resources/webgl-transform-feedback.d.ts.map +1 -1
  75. package/dist/adapter/resources/webgl-transform-feedback.js +1 -1
  76. package/dist/adapter/resources/webgl-transform-feedback.js.map +1 -1
  77. package/dist/adapter/resources/webgl-vertex-array.d.ts +1 -1
  78. package/dist/adapter/resources/webgl-vertex-array.d.ts.map +1 -1
  79. package/dist/adapter/resources/webgl-vertex-array.js +3 -2
  80. package/dist/adapter/resources/webgl-vertex-array.js.map +1 -1
  81. package/dist/adapter/webgl-adapter.d.ts +4 -3
  82. package/dist/adapter/webgl-adapter.d.ts.map +1 -1
  83. package/dist/adapter/webgl-adapter.js +16 -7
  84. package/dist/adapter/webgl-adapter.js.map +1 -1
  85. package/dist/adapter/webgl-canvas-context.d.ts +3 -24
  86. package/dist/adapter/webgl-canvas-context.d.ts.map +1 -1
  87. package/dist/adapter/webgl-canvas-context.js +5 -44
  88. package/dist/adapter/webgl-canvas-context.js.map +1 -1
  89. package/dist/adapter/webgl-device.d.ts +17 -20
  90. package/dist/adapter/webgl-device.d.ts.map +1 -1
  91. package/dist/adapter/webgl-device.js +30 -28
  92. package/dist/adapter/webgl-device.js.map +1 -1
  93. package/dist/context/debug/spector-types.d.ts.map +1 -1
  94. package/dist/context/debug/spector-types.js +3 -0
  95. package/dist/context/debug/spector-types.js.map +1 -1
  96. package/dist/context/debug/spector.js.map +1 -1
  97. package/dist/context/debug/webgl-developer-tools.js.map +1 -1
  98. package/dist/context/helpers/webgl-extensions.d.ts.map +1 -1
  99. package/dist/context/helpers/webgl-extensions.js +3 -0
  100. package/dist/context/helpers/webgl-extensions.js.map +1 -1
  101. package/dist/context/parameters/unified-parameter-api.d.ts.map +1 -1
  102. package/dist/context/parameters/unified-parameter-api.js +7 -0
  103. package/dist/context/parameters/unified-parameter-api.js.map +1 -1
  104. package/dist/context/parameters/webgl-parameter-tables.d.ts +1 -1
  105. package/dist/context/parameters/webgl-parameter-tables.d.ts.map +1 -1
  106. package/dist/context/parameters/webgl-parameter-tables.js +1 -0
  107. package/dist/context/parameters/webgl-parameter-tables.js.map +1 -1
  108. package/dist/context/polyfills/polyfill-webgl1-extensions.d.ts.map +1 -1
  109. package/dist/context/polyfills/polyfill-webgl1-extensions.js +1 -0
  110. package/dist/context/polyfills/polyfill-webgl1-extensions.js.map +1 -1
  111. package/dist/context/state-tracker/deep-array-equal.d.ts +2 -1
  112. package/dist/context/state-tracker/deep-array-equal.d.ts.map +1 -1
  113. package/dist/context/state-tracker/deep-array-equal.js +4 -5
  114. package/dist/context/state-tracker/deep-array-equal.js.map +1 -1
  115. package/dist/context/state-tracker/webgl-state-tracker.d.ts.map +1 -1
  116. package/dist/context/state-tracker/webgl-state-tracker.js +4 -1
  117. package/dist/context/state-tracker/webgl-state-tracker.js.map +1 -1
  118. package/dist/context/state-tracker/with-parameters.js.map +1 -1
  119. package/dist/dist.dev.js +4720 -4771
  120. package/dist/dist.min.js +2 -2
  121. package/dist/index.cjs +3849 -3938
  122. package/dist/index.cjs.map +4 -4
  123. package/dist/index.d.ts +1 -3
  124. package/dist/index.d.ts.map +1 -1
  125. package/dist/index.js +1 -3
  126. package/dist/index.js.map +1 -1
  127. package/package.json +4 -4
  128. package/src/adapter/converters/device-parameters.ts +19 -9
  129. package/src/adapter/converters/shader-formats.ts +50 -24
  130. package/src/adapter/converters/webgl-shadertypes.ts +152 -0
  131. package/src/adapter/converters/webgl-texture-table.ts +9 -9
  132. package/src/adapter/converters/{vertex-formats.ts → webgl-vertex-formats.ts} +3 -3
  133. package/src/adapter/device-helpers/webgl-device-features.ts +1 -1
  134. package/src/adapter/device-helpers/webgl-device-limits.ts +1 -1
  135. package/src/adapter/helpers/format-utils.ts +2 -2
  136. package/src/adapter/helpers/{get-shader-layout.ts → get-shader-layout-from-glsl.ts} +20 -50
  137. package/src/adapter/helpers/set-uniform.ts +2 -2
  138. package/src/adapter/helpers/webgl-texture-utils.ts +12 -127
  139. package/src/adapter/resources/webgl-buffer.ts +5 -3
  140. package/src/adapter/resources/webgl-command-buffer.ts +5 -5
  141. package/src/adapter/resources/webgl-command-encoder.ts +17 -8
  142. package/src/adapter/resources/webgl-framebuffer.ts +2 -2
  143. package/src/adapter/resources/webgl-query-set.ts +5 -1
  144. package/src/adapter/resources/webgl-render-pass.ts +15 -9
  145. package/src/adapter/resources/webgl-render-pipeline.ts +32 -35
  146. package/src/adapter/resources/webgl-sampler.ts +1 -1
  147. package/src/adapter/resources/webgl-shader.ts +11 -2
  148. package/src/adapter/resources/webgl-texture-view.ts +1 -1
  149. package/src/adapter/resources/webgl-texture.ts +180 -393
  150. package/src/adapter/resources/webgl-transform-feedback.ts +2 -2
  151. package/src/adapter/resources/webgl-vertex-array.ts +4 -3
  152. package/src/adapter/webgl-adapter.ts +20 -8
  153. package/src/adapter/webgl-canvas-context.ts +7 -47
  154. package/src/adapter/webgl-device.ts +46 -41
  155. package/src/context/debug/spector-types.ts +5 -0
  156. package/src/context/debug/spector.ts +1 -1
  157. package/src/context/debug/webgl-developer-tools.ts +8 -3
  158. package/src/context/helpers/webgl-extensions.ts +3 -0
  159. package/src/context/parameters/unified-parameter-api.ts +9 -2
  160. package/src/context/parameters/webgl-parameter-tables.ts +2 -0
  161. package/src/context/polyfills/polyfill-webgl1-extensions.ts +1 -0
  162. package/src/context/state-tracker/deep-array-equal.ts +11 -6
  163. package/src/context/state-tracker/webgl-state-tracker.ts +5 -1
  164. package/src/context/state-tracker/with-parameters.ts +1 -1
  165. package/src/index.ts +1 -5
  166. package/dist/adapter/converters/vertex-formats.d.ts.map +0 -1
  167. package/dist/adapter/converters/vertex-formats.js.map +0 -1
  168. package/dist/adapter/helpers/decode-webgl-types.d.ts +0 -26
  169. package/dist/adapter/helpers/decode-webgl-types.d.ts.map +0 -1
  170. package/dist/adapter/helpers/decode-webgl-types.js +0 -102
  171. package/dist/adapter/helpers/decode-webgl-types.js.map +0 -1
  172. package/dist/adapter/helpers/get-shader-layout.d.ts.map +0 -1
  173. package/dist/adapter/helpers/get-shader-layout.js.map +0 -1
  174. package/dist/adapter/helpers/typed-array-utils.d.ts +0 -44
  175. package/dist/adapter/helpers/typed-array-utils.d.ts.map +0 -1
  176. package/dist/adapter/helpers/typed-array-utils.js +0 -107
  177. package/dist/adapter/helpers/typed-array-utils.js.map +0 -1
  178. package/dist/deprecated/accessor.d.ts +0 -53
  179. package/dist/deprecated/accessor.d.ts.map +0 -1
  180. package/dist/deprecated/accessor.js +0 -177
  181. package/dist/deprecated/accessor.js.map +0 -1
  182. package/dist/utils/split-uniforms-and-bindings.d.ts +0 -9
  183. package/dist/utils/split-uniforms-and-bindings.d.ts.map +0 -1
  184. package/dist/utils/split-uniforms-and-bindings.js +0 -21
  185. package/dist/utils/split-uniforms-and-bindings.js.map +0 -1
  186. package/src/adapter/helpers/decode-webgl-types.ts +0 -134
  187. package/src/adapter/helpers/typed-array-utils.ts +0 -129
  188. package/src/deprecated/accessor.ts +0 -225
  189. package/src/utils/split-uniforms-and-bindings.ts +0 -31
@@ -8,39 +8,28 @@ import type {
8
8
  TextureViewProps,
9
9
  Sampler,
10
10
  SamplerProps,
11
- SamplerParameters,
12
- TextureCubeFace,
13
- ExternalImage,
14
- Texture1DData,
15
- Texture2DData,
16
- Texture3DData,
17
- TextureCubeData,
18
- TextureArrayData,
19
- TextureCubeArrayData
11
+ CopyExternalImageOptions,
12
+ CopyImageDataOptions,
13
+ TypedArray
20
14
  } from '@luma.gl/core';
21
15
  import {Texture, log} from '@luma.gl/core';
22
16
  import {
23
17
  GL,
18
+ GLTextureTarget,
19
+ GLTextureCubeMapTarget,
20
+ GLTexelDataFormat,
24
21
  GLPixelType,
22
+ // GLDataType,
25
23
  GLSamplerParameters,
26
- GLTexelDataFormat,
27
- GLTextureTarget
24
+ GLValueParameters
28
25
  } from '@luma.gl/constants';
29
26
  import {getTextureFormatWebGL} from '../converters/webgl-texture-table';
30
27
  import {convertSamplerParametersToWebGL} from '../converters/sampler-parameters';
28
+ import {withGLParameters} from '../../context/state-tracker/with-parameters';
31
29
  import {WebGLDevice} from '../webgl-device';
32
30
  import {WEBGLSampler} from './webgl-sampler';
33
31
  import {WEBGLTextureView} from './webgl-texture-view';
34
32
 
35
- import {
36
- initializeTextureStorage,
37
- // clearMipLevel,
38
- copyExternalImageToMipLevel,
39
- copyCPUDataToMipLevel,
40
- // copyGPUBufferToMipLevel,
41
- getWebGLTextureTarget
42
- } from '../helpers/webgl-texture-utils';
43
-
44
33
  /**
45
34
  * WebGL... the texture API from hell... hopefully made simpler
46
35
  */
@@ -50,14 +39,9 @@ export class WEBGLTexture extends Texture {
50
39
  readonly gl: WebGL2RenderingContext;
51
40
  handle: WebGLTexture;
52
41
 
53
- sampler: WEBGLSampler = undefined; // TODO - currently unused in WebGL. Create dummy sampler?
54
- view: WEBGLTextureView = undefined; // TODO - currently unused in WebGL. Create dummy view?
55
-
56
- mipmaps: boolean;
57
-
58
- // Texture type
59
- /** Whether the internal format is compressed */
60
- compressed: boolean;
42
+ // @ts-ignore TODO - currently unused in WebGL. Create dummy sampler?
43
+ sampler: WEBGLSampler = undefined;
44
+ view: WEBGLTextureView;
61
45
 
62
46
  /**
63
47
  * The WebGL target corresponding to the texture type
@@ -75,81 +59,62 @@ export class WEBGLTexture extends Texture {
75
59
  glType: GLPixelType;
76
60
  /** The WebGL constant corresponding to the WebGPU style constant in format */
77
61
  glInternalFormat: GL;
62
+ /** Whether the internal format is compressed */
63
+ compressed: boolean;
78
64
 
79
65
  // state
80
66
  /** Texture binding slot - TODO - move to texture view? */
81
- textureUnit: number = 0;
67
+ _textureUnit: number = 0;
82
68
 
83
69
  constructor(device: Device, props: TextureProps) {
84
70
  super(device, props);
85
71
 
86
- // Texture base class strips out the data prop, so we need to add it back in
87
- const propsWithData = {...this.props};
88
- propsWithData.data = props.data;
89
-
90
72
  this.device = device as WebGLDevice;
91
73
  this.gl = this.device.gl;
92
74
 
75
+ const formatInfo = getTextureFormatWebGL(this.props.format);
76
+
93
77
  // Note: In WebGL the texture target defines the type of texture on first bind.
94
78
  this.glTarget = getWebGLTextureTarget(this.props.dimension);
95
-
96
- // The target format of this texture
97
- const formatInfo = getTextureFormatWebGL(this.props.format);
98
79
  this.glInternalFormat = formatInfo.internalFormat;
99
80
  this.glFormat = formatInfo.format;
100
81
  this.glType = formatInfo.type;
101
82
  this.compressed = formatInfo.compressed;
102
- this.mipmaps = Boolean(this.props.mipmaps);
103
-
104
- this._initialize(propsWithData);
105
-
106
- Object.seal(this);
107
- }
108
83
 
109
- /** Initialize texture with supplied props */
110
- // eslint-disable-next-line max-statements
111
- _initialize(propsWithData: TextureProps): void {
112
84
  this.handle = this.props.handle || this.gl.createTexture();
113
- this.device.setSpectorMetadata(this.handle, {...this.props, data: propsWithData.data});
114
-
115
- let {width, height} = propsWithData;
116
-
117
- if (!width || !height) {
118
- const textureSize = Texture.getTextureDataSize(propsWithData.data);
119
- width = textureSize?.width || 1;
120
- height = textureSize?.height || 1;
85
+ this.device._setWebGLDebugMetadata(this.handle, this, {spector: this.props});
86
+
87
+ /**
88
+ * Use WebGL immutable texture storage to allocate and clear texture memory.
89
+ * - texStorage2D should be considered a preferred alternative to texImage2D. It may have lower memory costs than texImage2D in some implementations.
90
+ * - Once texStorage*D has been called, the texture is immutable and can only be updated with texSubImage*(), not texImage()
91
+ * @see https://registry.khronos.org/webgl/specs/latest/2.0/ WebGL 2 spec section 3.7.6
92
+ */
93
+ this.gl.bindTexture(this.glTarget, this.handle);
94
+ const {dimension, width, height, depth, mipLevels, glTarget, glInternalFormat} = this;
95
+ switch (dimension) {
96
+ case '2d':
97
+ case 'cube':
98
+ this.gl.texStorage2D(glTarget, mipLevels, glInternalFormat, width, height);
99
+ break;
100
+ case '2d-array':
101
+ case '3d':
102
+ this.gl.texStorage3D(glTarget, mipLevels, glInternalFormat, width, height, depth);
103
+ break;
104
+ default:
105
+ throw new Error(dimension);
121
106
  }
107
+ this.gl.bindTexture(this.glTarget, null);
122
108
 
123
- // Store opts for accessors
124
- this.width = width;
125
- this.height = height;
126
- this.depth = propsWithData.depth;
109
+ // Set data
110
+ this._initializeData(props.data);
127
111
 
128
112
  // Set texture sampler parameters
129
- this.setSampler(propsWithData.sampler);
113
+ this.setSampler(this.props.sampler);
130
114
  // @ts-ignore TODO - fix types
131
115
  this.view = new WEBGLTextureView(this.device, {...this.props, texture: this});
132
116
 
133
- this.bind();
134
- initializeTextureStorage(this.gl, this.mipLevels, this);
135
-
136
- if (propsWithData.data) {
137
- // prettier-ignore
138
- switch (propsWithData.dimension) {
139
- case '1d': this.setTexture1DData(propsWithData.data); break;
140
- case '2d': this.setTexture2DData(propsWithData.data); break;
141
- case '3d': this.setTexture3DData(propsWithData.data); break;
142
- case 'cube': this.setTextureCubeData(propsWithData.data); break;
143
- case '2d-array': this.setTextureArrayData(propsWithData.data); break;
144
- case 'cube-array': this.setTextureCubeArrayData(propsWithData.data); break;
145
- // @ts-expect-error
146
- default: throw new Error(propsWithData.dimension);
147
- }
148
- }
149
-
150
- if (this.mipmaps) {
151
- this.generateMipmap();
152
- }
117
+ Object.seal(this);
153
118
  }
154
119
 
155
120
  override destroy(): void {
@@ -166,237 +131,122 @@ export class WEBGLTexture extends Texture {
166
131
  return new WEBGLTextureView(this.device, {...props, texture: this});
167
132
  }
168
133
 
169
- setSampler(sampler: Sampler | SamplerProps = {}): void {
170
- let samplerProps: SamplerParameters;
171
- if (sampler instanceof WEBGLSampler) {
172
- this.sampler = sampler;
173
- samplerProps = sampler.props;
174
- } else {
175
- this.sampler = new WEBGLSampler(this.device, sampler);
176
- samplerProps = sampler as SamplerProps;
177
- }
178
-
179
- const parameters = convertSamplerParametersToWebGL(samplerProps);
134
+ override setSampler(sampler: Sampler | SamplerProps = {}): void {
135
+ super.setSampler(sampler);
136
+ // Apply sampler parameters to texture
137
+ const parameters = convertSamplerParametersToWebGL(this.sampler.props);
180
138
  this._setSamplerParameters(parameters);
181
139
  }
182
140
 
183
- // Call to regenerate mipmaps after modifying texture(s)
184
- generateMipmap(options?: {force?: boolean}): void {
185
- const isFilterableAndRenderable =
186
- this.device.isTextureFormatRenderable(this.props.format) &&
187
- this.device.isTextureFormatFilterable(this.props.format);
188
- if (!isFilterableAndRenderable) {
189
- log.warn(`${this} is not renderable or filterable, may not be able to generate mipmaps`)();
190
- if (!options?.force) {
191
- return;
141
+ copyImageData(options_: CopyImageDataOptions): void {
142
+ const options = this._normalizeCopyImageDataOptions(options_);
143
+
144
+ const typedArray = options.data as TypedArray;
145
+ const {width, height, depth} = this;
146
+ const {mipLevel = 0, byteOffset = 0, x = 0, y = 0, z = 0} = options;
147
+ const {glFormat, glType, compressed} = this;
148
+ const glTarget = getWebGLCubeFaceTarget(this.glTarget, this.dimension, depth);
149
+
150
+ const glParameters: GLValueParameters = {
151
+ [GL.UNPACK_ROW_LENGTH]: options.bytesPerRow,
152
+ [GL.UNPACK_IMAGE_HEIGHT]: options.rowsPerImage
153
+ };
154
+
155
+ this.gl.bindTexture(glTarget, this.handle);
156
+
157
+ withGLParameters(this.gl, glParameters, () => {
158
+ switch (this.dimension) {
159
+ case '2d':
160
+ case 'cube':
161
+ if (compressed) {
162
+ // prettier-ignore
163
+ this.gl.compressedTexSubImage2D(glTarget, mipLevel, x, y, width, height, glFormat, typedArray, byteOffset); // , byteLength
164
+ } else {
165
+ // prettier-ignore
166
+ this.gl.texSubImage2D(glTarget, mipLevel, x, y, width, height, glFormat, glType, typedArray, byteOffset); // , byteLength
167
+ }
168
+ break;
169
+ case '2d-array':
170
+ case '3d':
171
+ if (compressed) {
172
+ // prettier-ignore
173
+ this.gl.compressedTexSubImage3D(glTarget, mipLevel, x, y, z, width, height, depth, glFormat, typedArray, byteOffset); // , byteLength
174
+ } else {
175
+ // prettier-ignore
176
+ this.gl.texSubImage3D(glTarget, mipLevel, x, y, z, width, height, depth, glFormat, glType, typedArray, byteOffset); // , byteLength
177
+ }
178
+ break;
179
+ default:
180
+ // Can never happen in WebGL
192
181
  }
193
- }
182
+ });
194
183
 
195
- try {
196
- this.gl.bindTexture(this.glTarget, this.handle);
197
- this.gl.generateMipmap(this.glTarget);
198
- } catch (error) {
199
- log.warn(`Error generating mipmap for ${this}: ${(error as Error).message}`)();
200
- } finally {
201
- this.gl.bindTexture(this.glTarget, null);
202
- }
184
+ this.gl.bindTexture(glTarget, null);
203
185
  }
204
186
 
205
- // Image Data Setters
206
- copyExternalImage(options: {
207
- image: ExternalImage;
208
- sourceX?: number;
209
- sourceY?: number;
210
- width?: number;
211
- height?: number;
212
- depth?: number;
213
- mipLevel?: number;
214
- x?: number;
215
- y?: number;
216
- z?: number;
217
- aspect?: 'all' | 'stencil-only' | 'depth-only';
218
- colorSpace?: 'srgb';
219
- premultipliedAlpha?: boolean;
220
- flipY?: boolean;
221
- }): {width: number; height: number} {
222
- const size = Texture.getExternalImageSize(options.image);
223
- const opts = {...Texture.defaultCopyExternalImageOptions, ...size, ...options};
224
-
225
- const {image, depth, mipLevel, x, y, z, flipY} = opts;
226
- let {width, height} = opts;
227
- const {dimension, glTarget, glFormat, glInternalFormat, glType} = this;
228
-
229
- // WebGL will error if we try to copy outside the bounds of the texture
230
- width = Math.min(width, this.width - x);
231
- height = Math.min(height, this.height - y);
187
+ copyExternalImage(options_: CopyExternalImageOptions): {width: number; height: number} {
188
+ const options = this._normalizeCopyExternalImageOptions(options_);
232
189
 
233
190
  if (options.sourceX || options.sourceY) {
234
191
  // requires copyTexSubImage2D from a framebuffer'
235
192
  throw new Error('WebGL does not support sourceX/sourceY)');
236
193
  }
237
194
 
238
- copyExternalImageToMipLevel(this.device.gl, this.handle, image, {
239
- dimension,
240
- mipLevel,
241
- x,
242
- y,
243
- z,
244
- width,
245
- height,
246
- depth,
247
- glFormat,
248
- glInternalFormat,
249
- glType,
250
- glTarget,
251
- flipY
252
- });
253
-
254
- return {width: opts.width, height: opts.height};
255
- }
256
-
257
- setTexture1DData(data: Texture1DData): void {
258
- throw new Error('setTexture1DData not supported in WebGL.');
259
- }
260
-
261
- /** Set a simple texture */
262
- setTexture2DData(lodData: Texture2DData, depth = 0): void {
263
- this.bind();
264
-
265
- const lodArray = Texture.normalizeTextureData(lodData, this);
266
-
267
- // If the user provides multiple LODs, then automatic mipmap
268
- // generation generateMipmap() should be disabled to avoid overwriting them.
269
- if (lodArray.length > 1 && this.props.mipmaps !== false) {
270
- log.warn(`Texture ${this.id} mipmap and multiple LODs.`)();
271
- }
272
-
273
- for (let lodLevel = 0; lodLevel < lodArray.length; lodLevel++) {
274
- const imageData = lodArray[lodLevel];
275
- this._setMipLevel(depth, lodLevel, imageData);
276
- }
277
-
278
- this.unbind();
279
- }
280
-
281
- /**
282
- * Sets a 3D texture
283
- * @param data
284
- */
285
- setTexture3DData(data: Texture3DData): void {
286
- if (this.props.dimension !== '3d') {
287
- throw new Error(this.id);
288
- }
289
- if (ArrayBuffer.isView(data)) {
290
- this.bind();
291
- copyCPUDataToMipLevel(this.device.gl, data, this);
292
- this.unbind();
293
- }
294
- }
295
-
296
- /**
297
- * Set a Texture Cube Data
298
- * @todo - could support TextureCubeArray with depth
299
- * @param data
300
- * @param index
301
- */
302
- setTextureCubeData(data: TextureCubeData, depth: number = 0): void {
303
- if (this.props.dimension !== 'cube') {
304
- throw new Error(this.id);
305
- }
306
- for (const face of Texture.CubeFaces) {
307
- this.setTextureCubeFaceData(data[face], face);
308
- }
309
- }
310
-
311
- /**
312
- * Sets an entire texture array
313
- * @param data
314
- */
315
- setTextureArrayData(data: TextureArrayData): void {
316
- if (this.props.dimension !== '2d-array') {
317
- throw new Error(this.id);
318
- }
319
- throw new Error('setTextureArrayData not implemented.');
320
- }
321
-
322
- /**
323
- * Sets an entire texture cube array
324
- * @param data
325
- */
326
- setTextureCubeArrayData(data: TextureCubeArrayData): void {
327
- throw new Error('setTextureCubeArrayData not supported in WebGL2.');
328
- }
329
-
330
- setTextureCubeFaceData(lodData: Texture2DData, face: TextureCubeFace, depth: number = 0): void {
331
- // assert(this.props.dimension === 'cube');
195
+ const {glFormat, glType} = this;
196
+ const {image, depth, mipLevel, x, y, z, width, height} = options;
332
197
 
333
- // If the user provides multiple LODs, then automatic mipmap
334
- // generation generateMipmap() should be disabled to avoid overwriting them.
335
- if (Array.isArray(lodData) && lodData.length > 1 && this.props.mipmaps !== false) {
336
- log.warn(`${this.id} has mipmap and multiple LODs.`)();
337
- }
198
+ // WebGL cube maps specify faces by overriding target instead of using the depth parameter
199
+ const glTarget = getWebGLCubeFaceTarget(this.glTarget, this.dimension, depth);
200
+ const glParameters: GLValueParameters = options.flipY ? {[GL.UNPACK_FLIP_Y_WEBGL]: true} : {};
338
201
 
339
- const faceDepth = Texture.CubeFaces.indexOf(face);
202
+ this.gl.bindTexture(this.glTarget, this.handle);
340
203
 
341
- this.setTexture2DData(lodData, faceDepth);
342
- }
204
+ withGLParameters(this.gl, glParameters, () => {
205
+ switch (this.dimension) {
206
+ case '2d':
207
+ case 'cube':
208
+ // prettier-ignore
209
+ this.gl.texSubImage2D(glTarget, mipLevel, x, y, width, height, glFormat, glType, image);
210
+ break;
211
+ case '2d-array':
212
+ case '3d':
213
+ // prettier-ignore
214
+ this.gl.texSubImage3D(glTarget, mipLevel, x, y, z, width, height, depth, glFormat, glType, image);
215
+ break;
216
+ default:
217
+ // Can never happen in WebGL
218
+ }
219
+ });
343
220
 
344
- // DEPRECATED METHODS
221
+ this.gl.bindTexture(this.glTarget, null);
345
222
 
346
- /** Update external texture (video frame or canvas) @deprecated Use ExternalTexture */
347
- update(): void {
348
- throw new Error('Texture.update() not implemented. Use ExternalTexture');
223
+ return {width: options.width, height: options.height};
349
224
  }
350
225
 
351
- // INTERNAL METHODS
352
-
353
- /** @todo update this method to accept LODs */
354
- setImageDataForFace(options): void {
355
- const {
356
- face,
357
- width,
358
- height,
359
- pixels,
360
- data,
361
- format = GL.RGBA,
362
- type = GL.UNSIGNED_BYTE
363
- // generateMipmap = false // TODO
364
- } = options;
365
-
366
- const {gl} = this;
226
+ // WEBGL SPECIFIC
367
227
 
368
- const imageData = pixels || data;
369
-
370
- this.bind();
371
- if (imageData instanceof Promise) {
372
- imageData.then(resolvedImageData =>
373
- this.setImageDataForFace(
374
- Object.assign({}, options, {
375
- face,
376
- data: resolvedImageData,
377
- pixels: resolvedImageData
378
- })
379
- )
380
- );
381
- } else if (this.width || this.height) {
382
- gl.texImage2D(face, 0, format, width, height, 0 /* border*/, format, type, imageData);
383
- } else {
384
- gl.texImage2D(face, 0, format, format, type, imageData);
228
+ generateMipmapsWebGL(options?: {force?: boolean}): void {
229
+ const isFilterableAndRenderable =
230
+ this.device.isTextureFormatRenderable(this.props.format) &&
231
+ this.device.isTextureFormatFilterable(this.props.format);
232
+ if (!isFilterableAndRenderable) {
233
+ log.warn(`${this} is not renderable or filterable, may not be able to generate mipmaps`)();
234
+ if (!options?.force) {
235
+ return;
236
+ }
385
237
  }
386
- }
387
238
 
388
- _getImageDataMap(faceData: Record<string | GL, any>): Record<GL, any> {
389
- for (let i = 0; i < Texture.CubeFaces.length; ++i) {
390
- const faceName = Texture.CubeFaces[i];
391
- if (faceData[faceName]) {
392
- faceData[GL.TEXTURE_CUBE_MAP_POSITIVE_X + i] = faceData[faceName];
393
- delete faceData[faceName];
394
- }
239
+ try {
240
+ this.gl.bindTexture(this.glTarget, this.handle);
241
+ this.gl.generateMipmap(this.glTarget);
242
+ } catch (error) {
243
+ log.warn(`Error generating mipmap for ${this}: ${(error as Error).message}`)();
244
+ } finally {
245
+ this.gl.bindTexture(this.glTarget, null);
395
246
  }
396
- return faceData;
397
247
  }
398
248
 
399
- // RESOURCE METHODS
249
+ // INTERNAL
400
250
 
401
251
  /**
402
252
  * Sets sampler parameters on texture
@@ -405,6 +255,7 @@ export class WEBGLTexture extends Texture {
405
255
  log.log(1, `${this.id} sampler parameters`, this.device.getGLKeys(parameters))();
406
256
 
407
257
  this.gl.bindTexture(this.glTarget, this.handle);
258
+
408
259
  for (const [pname, pvalue] of Object.entries(parameters)) {
409
260
  const param = Number(pname) as keyof GLSamplerParameters;
410
261
  const value = pvalue;
@@ -417,21 +268,26 @@ export class WEBGLTexture extends Texture {
417
268
  this.gl.texParameterf(this.glTarget, param, value);
418
269
  break;
419
270
 
271
+ case GL.TEXTURE_MAG_FILTER:
420
272
  case GL.TEXTURE_MIN_FILTER:
421
273
  this.gl.texParameteri(this.glTarget, param, value);
422
274
  break;
423
275
 
424
276
  case GL.TEXTURE_WRAP_S:
425
277
  case GL.TEXTURE_WRAP_T:
278
+ case GL.TEXTURE_WRAP_R:
426
279
  this.gl.texParameteri(this.glTarget, param, value);
427
280
  break;
281
+
428
282
  case GL.TEXTURE_MAX_ANISOTROPY_EXT:
429
283
  // We have to query feature before using it
430
284
  if (this.device.features.has('texture-filterable-anisotropic-webgl')) {
431
285
  this.gl.texParameteri(this.glTarget, param, value);
432
286
  }
433
287
  break;
434
- default:
288
+
289
+ case GL.TEXTURE_COMPARE_MODE:
290
+ case GL.TEXTURE_COMPARE_FUNC:
435
291
  this.gl.texParameteri(this.glTarget, param, value);
436
292
  break;
437
293
  }
@@ -439,132 +295,63 @@ export class WEBGLTexture extends Texture {
439
295
 
440
296
  this.gl.bindTexture(this.glTarget, null);
441
297
  }
442
-
443
- // INTERNAL SETTERS
444
-
445
- /**
446
- * Copy a region of data from a CPU memory buffer into this texture.
447
- * @todo - GLUnpackParameters parameters
448
- */
449
- protected _setMipLevel(
450
- depth: number,
451
- mipLevel: number,
452
- textureData: Texture2DData,
453
- glTarget: GL = this.glTarget
454
- ) {
455
- // if (!textureData) {
456
- // clearMipLevel(this.device.gl, {...this, depth, level});
457
- // return;
458
- // }
459
-
460
- if (Texture.isExternalImage(textureData)) {
461
- copyExternalImageToMipLevel(this.device.gl, this.handle, textureData, {
462
- ...this,
463
- depth,
464
- mipLevel,
465
- glTarget,
466
- flipY: this.props.flipY
467
- });
468
- return;
469
- }
470
-
471
- // @ts-expect-error
472
- if (Texture.isTextureLevelData(textureData)) {
473
- copyCPUDataToMipLevel(this.device.gl, textureData.data, {
474
- ...this,
475
- depth,
476
- mipLevel,
477
- glTarget
478
- });
479
- return;
480
- }
481
-
482
- throw new Error('Texture: invalid image data');
483
- }
484
- // HELPERS
485
-
486
- getActiveUnit(): number {
298
+ _getActiveUnit(): number {
487
299
  return this.gl.getParameter(GL.ACTIVE_TEXTURE) - GL.TEXTURE0;
488
300
  }
489
301
 
490
- bind(textureUnit?: number): number {
302
+ _bind(_textureUnit?: number): number {
491
303
  const {gl} = this;
492
304
 
493
- if (textureUnit !== undefined) {
494
- this.textureUnit = textureUnit;
495
- gl.activeTexture(gl.TEXTURE0 + textureUnit);
305
+ if (_textureUnit !== undefined) {
306
+ this._textureUnit = _textureUnit;
307
+ gl.activeTexture(gl.TEXTURE0 + _textureUnit);
496
308
  }
497
309
 
498
310
  gl.bindTexture(this.glTarget, this.handle);
499
- return textureUnit;
311
+ // @ts-ignore TODO fix types
312
+ return _textureUnit;
500
313
  }
501
314
 
502
- unbind(textureUnit?: number): number | undefined {
315
+ _unbind(_textureUnit?: number): number | undefined {
503
316
  const {gl} = this;
504
317
 
505
- if (textureUnit !== undefined) {
506
- this.textureUnit = textureUnit;
507
- gl.activeTexture(gl.TEXTURE0 + textureUnit);
318
+ if (_textureUnit !== undefined) {
319
+ this._textureUnit = _textureUnit;
320
+ gl.activeTexture(gl.TEXTURE0 + _textureUnit);
508
321
  }
509
322
 
510
323
  gl.bindTexture(this.glTarget, null);
511
- return textureUnit;
324
+ return _textureUnit;
512
325
  }
513
326
  }
514
327
 
515
- // TODO - Remove when texture refactor is complete
516
-
517
- /*
518
- setCubeMapData(options: {
519
- width: number;
520
- height: number;
521
- data: Record<GL, Texture2DData> | Record<TextureCubeFace, Texture2DData>;
522
- format?: any;
523
- type?: any;
524
- /** @deprecated Use .data *
525
- pixels: any;
526
- }): void {
527
- const {gl} = this;
528
-
529
- const {width, height, pixels, data, format = GL.RGBA, type = GL.UNSIGNED_BYTE} = options;
530
-
531
- // pixel data (imageDataMap) is an Object from Face to Image or Promise.
532
- // For example:
533
- // {
534
- // GL.TEXTURE_CUBE_MAP_POSITIVE_X : Image-or-Promise,
535
- // GL.TEXTURE_CUBE_MAP_NEGATIVE_X : Image-or-Promise,
536
- // ... }
537
- // To provide multiple level-of-details (LODs) this can be Face to Array
538
- // of Image or Promise, like this
539
- // {
540
- // GL.TEXTURE_CUBE_MAP_POSITIVE_X : [Image-or-Promise-LOD-0, Image-or-Promise-LOD-1],
541
- // GL.TEXTURE_CUBE_MAP_NEGATIVE_X : [Image-or-Promise-LOD-0, Image-or-Promise-LOD-1],
542
- // ... }
543
-
544
- const imageDataMap = this._getImageDataMap(pixels || data);
545
-
546
- const resolvedFaces = WEBGLTexture.FACES.map(face => {
547
- const facePixels = imageDataMap[face];
548
- return Array.isArray(facePixels) ? facePixels : [facePixels];
549
- });
550
- this.bind();
551
-
552
- WEBGLTexture.FACES.forEach((face, index) => {
553
- if (resolvedFaces[index].length > 1 && this.props.mipmaps !== false) {
554
- // If the user provides multiple LODs, then automatic mipmap
555
- // generation generateMipmap() should be disabled to avoid overwritting them.
556
- log.warn(`${this.id} has mipmap and multiple LODs.`)();
557
- }
558
- resolvedFaces[index].forEach((image, lodLevel) => {
559
- // TODO: adjust width & height for LOD!
560
- if (width && height) {
561
- gl.texImage2D(face, lodLevel, format, width, height, 0 /* border*, format, type, image);
562
- } else {
563
- gl.texImage2D(face, lodLevel, format, format, type, image);
564
- }
565
- });
566
- });
328
+ // INTERNAL HELPERS
329
+
330
+ /** Convert a WebGPU style texture constant to a WebGL style texture constant */
331
+ export function getWebGLTextureTarget(
332
+ dimension: '1d' | '2d' | '2d-array' | 'cube' | 'cube-array' | '3d'
333
+ ): GLTextureTarget {
334
+ // prettier-ignore
335
+ switch (dimension) {
336
+ case '1d': break; // not supported in any WebGL version
337
+ case '2d': return GL.TEXTURE_2D; // supported in WebGL1
338
+ case '3d': return GL.TEXTURE_3D; // supported in WebGL2
339
+ case 'cube': return GL.TEXTURE_CUBE_MAP; // supported in WebGL1
340
+ case '2d-array': return GL.TEXTURE_2D_ARRAY; // supported in WebGL2
341
+ case 'cube-array': break; // not supported in any WebGL version
342
+ }
343
+ throw new Error(dimension);
344
+ }
567
345
 
568
- this.unbind();
346
+ /**
347
+ * In WebGL, cube maps specify faces by overriding target instead of using the depth parameter.
348
+ * @note We still bind the texture using GL.TEXTURE_CUBE_MAP, but we need to use the face-specific target when setting mip levels.
349
+ * @returns glTarget unchanged, if dimension !== 'cube'.
350
+ */
351
+ export function getWebGLCubeFaceTarget(
352
+ glTarget: GLTextureTarget,
353
+ dimension: '1d' | '2d' | '2d-array' | 'cube' | 'cube-array' | '3d',
354
+ level: number
355
+ ): GLTextureTarget | GLTextureCubeMapTarget {
356
+ return dimension === 'cube' ? GL.TEXTURE_CUBE_MAP_POSITIVE_X + level : glTarget;
569
357
  }
570
- */