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