@luma.gl/webgl 9.1.9 → 9.2.0-alpha.2

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 (199) 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/sampler-parameters.js +13 -2
  4. package/dist/adapter/converters/sampler-parameters.js.map +1 -1
  5. package/dist/adapter/converters/shader-formats.d.ts +67 -8
  6. package/dist/adapter/converters/shader-formats.d.ts.map +1 -1
  7. package/dist/adapter/converters/shader-formats.js +82 -52
  8. package/dist/adapter/converters/shader-formats.js.map +1 -1
  9. package/dist/adapter/converters/webgl-shadertypes.d.ts +20 -0
  10. package/dist/adapter/converters/webgl-shadertypes.d.ts.map +1 -0
  11. package/dist/adapter/converters/webgl-shadertypes.js +122 -0
  12. package/dist/adapter/converters/webgl-shadertypes.js.map +1 -0
  13. package/dist/adapter/converters/webgl-texture-table.d.ts.map +1 -1
  14. package/dist/adapter/converters/webgl-texture-table.js +17 -13
  15. package/dist/adapter/converters/webgl-texture-table.js.map +1 -1
  16. package/dist/adapter/converters/{vertex-formats.d.ts → webgl-vertex-formats.d.ts} +4 -4
  17. package/dist/adapter/converters/webgl-vertex-formats.d.ts.map +1 -0
  18. package/dist/adapter/converters/{vertex-formats.js → webgl-vertex-formats.js} +2 -3
  19. package/dist/adapter/converters/webgl-vertex-formats.js.map +1 -0
  20. package/dist/adapter/device-helpers/webgl-device-features.d.ts.map +1 -1
  21. package/dist/adapter/device-helpers/webgl-device-features.js.map +1 -1
  22. package/dist/adapter/device-helpers/webgl-device-limits.d.ts +1 -1
  23. package/dist/adapter/device-helpers/webgl-device-limits.d.ts.map +1 -1
  24. package/dist/adapter/device-helpers/webgl-device-limits.js +1 -1
  25. package/dist/adapter/device-helpers/webgl-device-limits.js.map +1 -1
  26. package/dist/adapter/helpers/format-utils.d.ts +3 -2
  27. package/dist/adapter/helpers/format-utils.d.ts.map +1 -1
  28. package/dist/adapter/helpers/format-utils.js.map +1 -1
  29. package/dist/adapter/helpers/{get-shader-layout.d.ts → get-shader-layout-from-glsl.d.ts} +1 -1
  30. package/dist/adapter/helpers/get-shader-layout-from-glsl.d.ts.map +1 -0
  31. package/dist/adapter/helpers/{get-shader-layout.js → get-shader-layout-from-glsl.js} +12 -35
  32. package/dist/adapter/helpers/get-shader-layout-from-glsl.js.map +1 -0
  33. package/dist/adapter/helpers/set-uniform.d.ts +2 -2
  34. package/dist/adapter/helpers/set-uniform.d.ts.map +1 -1
  35. package/dist/adapter/helpers/set-uniform.js.map +1 -1
  36. package/dist/adapter/helpers/webgl-texture-utils.d.ts +2 -242
  37. package/dist/adapter/helpers/webgl-texture-utils.d.ts.map +1 -1
  38. package/dist/adapter/helpers/webgl-texture-utils.js +10 -99
  39. package/dist/adapter/helpers/webgl-texture-utils.js.map +1 -1
  40. package/dist/adapter/resources/webgl-buffer.d.ts +7 -7
  41. package/dist/adapter/resources/webgl-buffer.d.ts.map +1 -1
  42. package/dist/adapter/resources/webgl-buffer.js +29 -18
  43. package/dist/adapter/resources/webgl-buffer.js.map +1 -1
  44. package/dist/adapter/resources/webgl-command-buffer.d.ts +4 -3
  45. package/dist/adapter/resources/webgl-command-buffer.d.ts.map +1 -1
  46. package/dist/adapter/resources/webgl-command-buffer.js +5 -4
  47. package/dist/adapter/resources/webgl-command-buffer.js.map +1 -1
  48. package/dist/adapter/resources/webgl-command-encoder.d.ts +6 -2
  49. package/dist/adapter/resources/webgl-command-encoder.d.ts.map +1 -1
  50. package/dist/adapter/resources/webgl-command-encoder.js +9 -4
  51. package/dist/adapter/resources/webgl-command-encoder.js.map +1 -1
  52. package/dist/adapter/resources/webgl-external-texture.js +1 -0
  53. package/dist/adapter/resources/webgl-external-texture.js.map +1 -1
  54. package/dist/adapter/resources/webgl-framebuffer.d.ts +2 -2
  55. package/dist/adapter/resources/webgl-framebuffer.d.ts.map +1 -1
  56. package/dist/adapter/resources/webgl-framebuffer.js +2 -2
  57. package/dist/adapter/resources/webgl-framebuffer.js.map +1 -1
  58. package/dist/adapter/resources/webgl-query-set.d.ts +2 -2
  59. package/dist/adapter/resources/webgl-query-set.d.ts.map +1 -1
  60. package/dist/adapter/resources/webgl-query-set.js +5 -1
  61. package/dist/adapter/resources/webgl-query-set.js.map +1 -1
  62. package/dist/adapter/resources/webgl-render-pass.d.ts +1 -0
  63. package/dist/adapter/resources/webgl-render-pass.d.ts.map +1 -1
  64. package/dist/adapter/resources/webgl-render-pass.js +16 -13
  65. package/dist/adapter/resources/webgl-render-pass.js.map +1 -1
  66. package/dist/adapter/resources/webgl-render-pipeline.d.ts +5 -5
  67. package/dist/adapter/resources/webgl-render-pipeline.d.ts.map +1 -1
  68. package/dist/adapter/resources/webgl-render-pipeline.js +28 -24
  69. package/dist/adapter/resources/webgl-render-pipeline.js.map +1 -1
  70. package/dist/adapter/resources/webgl-sampler.js +1 -1
  71. package/dist/adapter/resources/webgl-sampler.js.map +1 -1
  72. package/dist/adapter/resources/webgl-shader.d.ts.map +1 -1
  73. package/dist/adapter/resources/webgl-shader.js +9 -2
  74. package/dist/adapter/resources/webgl-shader.js.map +1 -1
  75. package/dist/adapter/resources/webgl-texture-view.js +1 -1
  76. package/dist/adapter/resources/webgl-texture-view.js.map +1 -1
  77. package/dist/adapter/resources/webgl-texture.d.ts +21 -66
  78. package/dist/adapter/resources/webgl-texture.d.ts.map +1 -1
  79. package/dist/adapter/resources/webgl-texture.js +152 -320
  80. package/dist/adapter/resources/webgl-texture.js.map +1 -1
  81. package/dist/adapter/resources/webgl-transform-feedback.d.ts +1 -1
  82. package/dist/adapter/resources/webgl-transform-feedback.d.ts.map +1 -1
  83. package/dist/adapter/resources/webgl-transform-feedback.js +1 -1
  84. package/dist/adapter/resources/webgl-transform-feedback.js.map +1 -1
  85. package/dist/adapter/resources/webgl-vertex-array.d.ts +1 -1
  86. package/dist/adapter/resources/webgl-vertex-array.d.ts.map +1 -1
  87. package/dist/adapter/resources/webgl-vertex-array.js +3 -2
  88. package/dist/adapter/resources/webgl-vertex-array.js.map +1 -1
  89. package/dist/adapter/webgl-adapter.d.ts +4 -3
  90. package/dist/adapter/webgl-adapter.d.ts.map +1 -1
  91. package/dist/adapter/webgl-adapter.js +43 -30
  92. package/dist/adapter/webgl-adapter.js.map +1 -1
  93. package/dist/adapter/webgl-canvas-context.d.ts +3 -24
  94. package/dist/adapter/webgl-canvas-context.d.ts.map +1 -1
  95. package/dist/adapter/webgl-canvas-context.js +5 -44
  96. package/dist/adapter/webgl-canvas-context.js.map +1 -1
  97. package/dist/adapter/webgl-device.d.ts +19 -20
  98. package/dist/adapter/webgl-device.d.ts.map +1 -1
  99. package/dist/adapter/webgl-device.js +44 -31
  100. package/dist/adapter/webgl-device.js.map +1 -1
  101. package/dist/context/debug/spector-types.d.ts.map +1 -1
  102. package/dist/context/debug/spector-types.js +3 -0
  103. package/dist/context/debug/spector-types.js.map +1 -1
  104. package/dist/context/debug/spector.js.map +1 -1
  105. package/dist/context/debug/webgl-developer-tools.js +1 -0
  106. package/dist/context/debug/webgl-developer-tools.js.map +1 -1
  107. package/dist/context/helpers/webgl-extensions.d.ts.map +1 -1
  108. package/dist/context/helpers/webgl-extensions.js +3 -0
  109. package/dist/context/helpers/webgl-extensions.js.map +1 -1
  110. package/dist/context/parameters/unified-parameter-api.d.ts.map +1 -1
  111. package/dist/context/parameters/unified-parameter-api.js +7 -0
  112. package/dist/context/parameters/unified-parameter-api.js.map +1 -1
  113. package/dist/context/parameters/webgl-parameter-tables.d.ts +1 -1
  114. package/dist/context/parameters/webgl-parameter-tables.d.ts.map +1 -1
  115. package/dist/context/parameters/webgl-parameter-tables.js +1 -0
  116. package/dist/context/parameters/webgl-parameter-tables.js.map +1 -1
  117. package/dist/context/polyfills/polyfill-webgl1-extensions.d.ts.map +1 -1
  118. package/dist/context/polyfills/polyfill-webgl1-extensions.js +1 -0
  119. package/dist/context/polyfills/polyfill-webgl1-extensions.js.map +1 -1
  120. package/dist/context/state-tracker/deep-array-equal.d.ts +2 -1
  121. package/dist/context/state-tracker/deep-array-equal.d.ts.map +1 -1
  122. package/dist/context/state-tracker/deep-array-equal.js +4 -5
  123. package/dist/context/state-tracker/deep-array-equal.js.map +1 -1
  124. package/dist/context/state-tracker/webgl-state-tracker.d.ts.map +1 -1
  125. package/dist/context/state-tracker/webgl-state-tracker.js +4 -1
  126. package/dist/context/state-tracker/webgl-state-tracker.js.map +1 -1
  127. package/dist/context/state-tracker/with-parameters.js.map +1 -1
  128. package/dist/dist.dev.js +4788 -4801
  129. package/dist/dist.min.js +2 -2
  130. package/dist/index.cjs +3906 -3960
  131. package/dist/index.cjs.map +4 -4
  132. package/dist/index.d.ts +1 -3
  133. package/dist/index.d.ts.map +1 -1
  134. package/dist/index.js +1 -3
  135. package/dist/index.js.map +1 -1
  136. package/package.json +4 -4
  137. package/src/adapter/converters/device-parameters.ts +19 -9
  138. package/src/adapter/converters/sampler-parameters.ts +13 -2
  139. package/src/adapter/converters/shader-formats.ts +50 -24
  140. package/src/adapter/converters/webgl-shadertypes.ts +151 -0
  141. package/src/adapter/converters/webgl-texture-table.ts +21 -15
  142. package/src/adapter/converters/{vertex-formats.ts → webgl-vertex-formats.ts} +4 -5
  143. package/src/adapter/device-helpers/webgl-device-features.ts +1 -1
  144. package/src/adapter/device-helpers/webgl-device-limits.ts +1 -1
  145. package/src/adapter/helpers/format-utils.ts +2 -2
  146. package/src/adapter/helpers/{get-shader-layout.ts → get-shader-layout-from-glsl.ts} +20 -50
  147. package/src/adapter/helpers/set-uniform.ts +2 -2
  148. package/src/adapter/helpers/webgl-texture-utils.ts +12 -348
  149. package/src/adapter/resources/webgl-buffer.ts +43 -23
  150. package/src/adapter/resources/webgl-command-buffer.ts +9 -8
  151. package/src/adapter/resources/webgl-command-encoder.ts +18 -9
  152. package/src/adapter/resources/webgl-framebuffer.ts +4 -4
  153. package/src/adapter/resources/webgl-query-set.ts +7 -3
  154. package/src/adapter/resources/webgl-render-pass.ts +20 -17
  155. package/src/adapter/resources/webgl-render-pipeline.ts +38 -37
  156. package/src/adapter/resources/webgl-sampler.ts +1 -1
  157. package/src/adapter/resources/webgl-shader.ts +11 -2
  158. package/src/adapter/resources/webgl-texture-view.ts +1 -1
  159. package/src/adapter/resources/webgl-texture.ts +184 -394
  160. package/src/adapter/resources/webgl-transform-feedback.ts +2 -2
  161. package/src/adapter/resources/webgl-vertex-array.ts +4 -3
  162. package/src/adapter/webgl-adapter.ts +46 -33
  163. package/src/adapter/webgl-canvas-context.ts +7 -47
  164. package/src/adapter/webgl-device.ts +64 -44
  165. package/src/context/debug/spector-types.ts +5 -0
  166. package/src/context/debug/spector.ts +1 -1
  167. package/src/context/debug/webgl-developer-tools.ts +9 -3
  168. package/src/context/helpers/webgl-extensions.ts +3 -0
  169. package/src/context/parameters/unified-parameter-api.ts +9 -2
  170. package/src/context/parameters/webgl-parameter-tables.ts +2 -0
  171. package/src/context/polyfills/polyfill-webgl1-extensions.ts +1 -0
  172. package/src/context/state-tracker/deep-array-equal.ts +11 -6
  173. package/src/context/state-tracker/webgl-state-tracker.ts +5 -1
  174. package/src/context/state-tracker/with-parameters.ts +1 -1
  175. package/src/index.ts +1 -5
  176. package/dist/adapter/converters/vertex-formats.d.ts.map +0 -1
  177. package/dist/adapter/converters/vertex-formats.js.map +0 -1
  178. package/dist/adapter/helpers/decode-webgl-types.d.ts +0 -26
  179. package/dist/adapter/helpers/decode-webgl-types.d.ts.map +0 -1
  180. package/dist/adapter/helpers/decode-webgl-types.js +0 -102
  181. package/dist/adapter/helpers/decode-webgl-types.js.map +0 -1
  182. package/dist/adapter/helpers/get-shader-layout.d.ts.map +0 -1
  183. package/dist/adapter/helpers/get-shader-layout.js.map +0 -1
  184. package/dist/adapter/helpers/typed-array-utils.d.ts +0 -44
  185. package/dist/adapter/helpers/typed-array-utils.d.ts.map +0 -1
  186. package/dist/adapter/helpers/typed-array-utils.js +0 -107
  187. package/dist/adapter/helpers/typed-array-utils.js.map +0 -1
  188. package/dist/deprecated/accessor.d.ts +0 -53
  189. package/dist/deprecated/accessor.d.ts.map +0 -1
  190. package/dist/deprecated/accessor.js +0 -177
  191. package/dist/deprecated/accessor.js.map +0 -1
  192. package/dist/utils/split-uniforms-and-bindings.d.ts +0 -9
  193. package/dist/utils/split-uniforms-and-bindings.d.ts.map +0 -1
  194. package/dist/utils/split-uniforms-and-bindings.js +0 -21
  195. package/dist/utils/split-uniforms-and-bindings.js.map +0 -1
  196. package/src/adapter/helpers/decode-webgl-types.ts +0 -134
  197. package/src/adapter/helpers/typed-array-utils.ts +0 -129
  198. package/src/deprecated/accessor.ts +0 -225
  199. 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,245 +131,134 @@ 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
+ // WebGL automatically ignores these for compressed textures, but we are careful
151
+ const glParameters: GLValueParameters = !this.compressed
152
+ ? {
153
+ [GL.UNPACK_ROW_LENGTH]: options.bytesPerRow,
154
+ [GL.UNPACK_IMAGE_HEIGHT]: options.rowsPerImage
155
+ }
156
+ : {};
157
+
158
+ this.gl.bindTexture(glTarget, this.handle);
159
+
160
+ withGLParameters(this.gl, glParameters, () => {
161
+ switch (this.dimension) {
162
+ case '2d':
163
+ case 'cube':
164
+ if (compressed) {
165
+ // prettier-ignore
166
+ this.gl.compressedTexSubImage2D(glTarget, mipLevel, x, y, width, height, glFormat, typedArray, byteOffset); // , byteLength
167
+ } else {
168
+ // prettier-ignore
169
+ this.gl.texSubImage2D(glTarget, mipLevel, x, y, width, height, glFormat, glType, typedArray, byteOffset); // , byteLength
170
+ }
171
+ break;
172
+ case '2d-array':
173
+ case '3d':
174
+ if (compressed) {
175
+ // prettier-ignore
176
+ this.gl.compressedTexSubImage3D(glTarget, mipLevel, x, y, z, width, height, depth, glFormat, typedArray, byteOffset); // , byteLength
177
+ } else {
178
+ // prettier-ignore
179
+ this.gl.texSubImage3D(glTarget, mipLevel, x, y, z, width, height, depth, glFormat, glType, typedArray, byteOffset); // , byteLength
180
+ }
181
+ break;
182
+ default:
183
+ // Can never happen in WebGL
192
184
  }
193
- }
185
+ });
194
186
 
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
- }
187
+ this.gl.bindTexture(glTarget, null);
203
188
  }
204
189
 
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);
190
+ copyExternalImage(options_: CopyExternalImageOptions): {width: number; height: number} {
191
+ const options = this._normalizeCopyExternalImageOptions(options_);
232
192
 
233
193
  if (options.sourceX || options.sourceY) {
234
194
  // requires copyTexSubImage2D from a framebuffer'
235
195
  throw new Error('WebGL does not support sourceX/sourceY)');
236
196
  }
237
197
 
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');
198
+ const {glFormat, glType} = this;
199
+ const {image, depth, mipLevel, x, y, z, width, height} = options;
332
200
 
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
- }
201
+ // WebGL cube maps specify faces by overriding target instead of using the depth parameter
202
+ const glTarget = getWebGLCubeFaceTarget(this.glTarget, this.dimension, depth);
203
+ const glParameters: GLValueParameters = options.flipY ? {[GL.UNPACK_FLIP_Y_WEBGL]: true} : {};
338
204
 
339
- const faceDepth = Texture.CubeFaces.indexOf(face);
205
+ this.gl.bindTexture(this.glTarget, this.handle);
340
206
 
341
- this.setTexture2DData(lodData, faceDepth);
342
- }
207
+ withGLParameters(this.gl, glParameters, () => {
208
+ switch (this.dimension) {
209
+ case '2d':
210
+ case 'cube':
211
+ // prettier-ignore
212
+ this.gl.texSubImage2D(glTarget, mipLevel, x, y, width, height, glFormat, glType, image);
213
+ break;
214
+ case '2d-array':
215
+ case '3d':
216
+ // prettier-ignore
217
+ this.gl.texSubImage3D(glTarget, mipLevel, x, y, z, width, height, depth, glFormat, glType, image);
218
+ break;
219
+ default:
220
+ // Can never happen in WebGL
221
+ }
222
+ });
343
223
 
344
- // DEPRECATED METHODS
224
+ this.gl.bindTexture(this.glTarget, null);
345
225
 
346
- /** Update external texture (video frame or canvas) @deprecated Use ExternalTexture */
347
- update(): void {
348
- throw new Error('Texture.update() not implemented. Use ExternalTexture');
226
+ return {width: options.width, height: options.height};
349
227
  }
350
228
 
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;
229
+ // WEBGL SPECIFIC
367
230
 
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);
231
+ generateMipmapsWebGL(options?: {force?: boolean}): void {
232
+ const isFilterableAndRenderable =
233
+ this.device.isTextureFormatRenderable(this.props.format) &&
234
+ this.device.isTextureFormatFilterable(this.props.format);
235
+ if (!isFilterableAndRenderable) {
236
+ log.warn(`${this} is not renderable or filterable, may not be able to generate mipmaps`)();
237
+ if (!options?.force) {
238
+ return;
239
+ }
385
240
  }
386
- }
387
241
 
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
- }
242
+ try {
243
+ this.gl.bindTexture(this.glTarget, this.handle);
244
+ this.gl.generateMipmap(this.glTarget);
245
+ } catch (error) {
246
+ log.warn(`Error generating mipmap for ${this}: ${(error as Error).message}`)();
247
+ } finally {
248
+ this.gl.bindTexture(this.glTarget, null);
395
249
  }
396
- return faceData;
397
250
  }
398
251
 
399
- // RESOURCE METHODS
252
+ // INTERNAL
400
253
 
401
254
  /**
402
255
  * Sets sampler parameters on texture
403
256
  */
404
257
  _setSamplerParameters(parameters: GLSamplerParameters): void {
405
- log.log(1, `${this.id} sampler parameters`, this.device.getGLKeys(parameters))();
258
+ log.log(2, `${this.id} sampler parameters`, this.device.getGLKeys(parameters))();
406
259
 
407
260
  this.gl.bindTexture(this.glTarget, this.handle);
261
+
408
262
  for (const [pname, pvalue] of Object.entries(parameters)) {
409
263
  const param = Number(pname) as keyof GLSamplerParameters;
410
264
  const value = pvalue;
@@ -417,21 +271,26 @@ export class WEBGLTexture extends Texture {
417
271
  this.gl.texParameterf(this.glTarget, param, value);
418
272
  break;
419
273
 
274
+ case GL.TEXTURE_MAG_FILTER:
420
275
  case GL.TEXTURE_MIN_FILTER:
421
276
  this.gl.texParameteri(this.glTarget, param, value);
422
277
  break;
423
278
 
424
279
  case GL.TEXTURE_WRAP_S:
425
280
  case GL.TEXTURE_WRAP_T:
281
+ case GL.TEXTURE_WRAP_R:
426
282
  this.gl.texParameteri(this.glTarget, param, value);
427
283
  break;
284
+
428
285
  case GL.TEXTURE_MAX_ANISOTROPY_EXT:
429
286
  // We have to query feature before using it
430
287
  if (this.device.features.has('texture-filterable-anisotropic-webgl')) {
431
288
  this.gl.texParameteri(this.glTarget, param, value);
432
289
  }
433
290
  break;
434
- default:
291
+
292
+ case GL.TEXTURE_COMPARE_MODE:
293
+ case GL.TEXTURE_COMPARE_FUNC:
435
294
  this.gl.texParameteri(this.glTarget, param, value);
436
295
  break;
437
296
  }
@@ -439,132 +298,63 @@ export class WEBGLTexture extends Texture {
439
298
 
440
299
  this.gl.bindTexture(this.glTarget, null);
441
300
  }
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 {
301
+ _getActiveUnit(): number {
487
302
  return this.gl.getParameter(GL.ACTIVE_TEXTURE) - GL.TEXTURE0;
488
303
  }
489
304
 
490
- bind(textureUnit?: number): number {
305
+ _bind(_textureUnit?: number): number {
491
306
  const {gl} = this;
492
307
 
493
- if (textureUnit !== undefined) {
494
- this.textureUnit = textureUnit;
495
- gl.activeTexture(gl.TEXTURE0 + textureUnit);
308
+ if (_textureUnit !== undefined) {
309
+ this._textureUnit = _textureUnit;
310
+ gl.activeTexture(gl.TEXTURE0 + _textureUnit);
496
311
  }
497
312
 
498
313
  gl.bindTexture(this.glTarget, this.handle);
499
- return textureUnit;
314
+ // @ts-ignore TODO fix types
315
+ return _textureUnit;
500
316
  }
501
317
 
502
- unbind(textureUnit?: number): number | undefined {
318
+ _unbind(_textureUnit?: number): number | undefined {
503
319
  const {gl} = this;
504
320
 
505
- if (textureUnit !== undefined) {
506
- this.textureUnit = textureUnit;
507
- gl.activeTexture(gl.TEXTURE0 + textureUnit);
321
+ if (_textureUnit !== undefined) {
322
+ this._textureUnit = _textureUnit;
323
+ gl.activeTexture(gl.TEXTURE0 + _textureUnit);
508
324
  }
509
325
 
510
326
  gl.bindTexture(this.glTarget, null);
511
- return textureUnit;
327
+ return _textureUnit;
512
328
  }
513
329
  }
514
330
 
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
- });
331
+ // INTERNAL HELPERS
332
+
333
+ /** Convert a WebGPU style texture constant to a WebGL style texture constant */
334
+ export function getWebGLTextureTarget(
335
+ dimension: '1d' | '2d' | '2d-array' | 'cube' | 'cube-array' | '3d'
336
+ ): GLTextureTarget {
337
+ // prettier-ignore
338
+ switch (dimension) {
339
+ case '1d': break; // not supported in any WebGL version
340
+ case '2d': return GL.TEXTURE_2D; // supported in WebGL1
341
+ case '3d': return GL.TEXTURE_3D; // supported in WebGL2
342
+ case 'cube': return GL.TEXTURE_CUBE_MAP; // supported in WebGL1
343
+ case '2d-array': return GL.TEXTURE_2D_ARRAY; // supported in WebGL2
344
+ case 'cube-array': break; // not supported in any WebGL version
345
+ }
346
+ throw new Error(dimension);
347
+ }
567
348
 
568
- this.unbind();
349
+ /**
350
+ * In WebGL, cube maps specify faces by overriding target instead of using the depth parameter.
351
+ * @note We still bind the texture using GL.TEXTURE_CUBE_MAP, but we need to use the face-specific target when setting mip levels.
352
+ * @returns glTarget unchanged, if dimension !== 'cube'.
353
+ */
354
+ export function getWebGLCubeFaceTarget(
355
+ glTarget: GLTextureTarget,
356
+ dimension: '1d' | '2d' | '2d-array' | 'cube' | 'cube-array' | '3d',
357
+ level: number
358
+ ): GLTextureTarget | GLTextureCubeMapTarget {
359
+ return dimension === 'cube' ? GL.TEXTURE_CUBE_MAP_POSITIVE_X + level : glTarget;
569
360
  }
570
- */