@luma.gl/webgl 9.3.0-alpha.4 → 9.3.0-alpha.8

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 (210) hide show
  1. package/dist/adapter/converters/device-parameters.d.ts +1 -1
  2. package/dist/adapter/converters/device-parameters.d.ts.map +1 -1
  3. package/dist/adapter/converters/device-parameters.js +4 -1
  4. package/dist/adapter/converters/device-parameters.js.map +1 -1
  5. package/dist/adapter/converters/sampler-parameters.d.ts +1 -1
  6. package/dist/adapter/converters/sampler-parameters.d.ts.map +1 -1
  7. package/dist/adapter/converters/sampler-parameters.js +1 -1
  8. package/dist/adapter/converters/sampler-parameters.js.map +1 -1
  9. package/dist/adapter/converters/shader-formats.d.ts +1 -64
  10. package/dist/adapter/converters/shader-formats.d.ts.map +1 -1
  11. package/dist/adapter/converters/shader-formats.js +1 -64
  12. package/dist/adapter/converters/shader-formats.js.map +1 -1
  13. package/dist/adapter/converters/webgl-shadertypes.d.ts +1 -3
  14. package/dist/adapter/converters/webgl-shadertypes.d.ts.map +1 -1
  15. package/dist/adapter/converters/webgl-shadertypes.js +1 -6
  16. package/dist/adapter/converters/webgl-shadertypes.js.map +1 -1
  17. package/dist/adapter/converters/webgl-texture-table.d.ts +8 -4
  18. package/dist/adapter/converters/webgl-texture-table.d.ts.map +1 -1
  19. package/dist/adapter/converters/webgl-texture-table.js +122 -58
  20. package/dist/adapter/converters/webgl-texture-table.js.map +1 -1
  21. package/dist/adapter/converters/webgl-vertex-formats.d.ts +1 -1
  22. package/dist/adapter/converters/webgl-vertex-formats.d.ts.map +1 -1
  23. package/dist/adapter/converters/webgl-vertex-formats.js +1 -1
  24. package/dist/adapter/converters/webgl-vertex-formats.js.map +1 -1
  25. package/dist/adapter/device-helpers/webgl-device-features.d.ts +1 -1
  26. package/dist/adapter/device-helpers/webgl-device-features.d.ts.map +1 -1
  27. package/dist/adapter/device-helpers/webgl-device-features.js +1 -2
  28. package/dist/adapter/device-helpers/webgl-device-features.js.map +1 -1
  29. package/dist/adapter/device-helpers/webgl-device-info.d.ts +1 -1
  30. package/dist/adapter/device-helpers/webgl-device-info.d.ts.map +1 -1
  31. package/dist/adapter/device-helpers/webgl-device-info.js +6 -1
  32. package/dist/adapter/device-helpers/webgl-device-info.js.map +1 -1
  33. package/dist/adapter/device-helpers/webgl-device-limits.d.ts +1 -1
  34. package/dist/adapter/device-helpers/webgl-device-limits.d.ts.map +1 -1
  35. package/dist/adapter/device-helpers/webgl-device-limits.js +1 -1
  36. package/dist/adapter/device-helpers/webgl-device-limits.js.map +1 -1
  37. package/dist/adapter/helpers/format-utils.d.ts +1 -1
  38. package/dist/adapter/helpers/format-utils.d.ts.map +1 -1
  39. package/dist/adapter/helpers/format-utils.js +1 -1
  40. package/dist/adapter/helpers/format-utils.js.map +1 -1
  41. package/dist/adapter/helpers/get-shader-layout-from-glsl.js +30 -19
  42. package/dist/adapter/helpers/get-shader-layout-from-glsl.js.map +1 -1
  43. package/dist/adapter/helpers/set-uniform.d.ts +1 -1
  44. package/dist/adapter/helpers/set-uniform.d.ts.map +1 -1
  45. package/dist/adapter/helpers/set-uniform.js +1 -1
  46. package/dist/adapter/helpers/set-uniform.js.map +1 -1
  47. package/dist/adapter/helpers/webgl-texture-utils.d.ts +1 -1
  48. package/dist/adapter/helpers/webgl-texture-utils.d.ts.map +1 -1
  49. package/dist/adapter/helpers/webgl-texture-utils.js +4 -4
  50. package/dist/adapter/helpers/webgl-texture-utils.js.map +1 -1
  51. package/dist/adapter/helpers/webgl-topology-utils.d.ts +1 -1
  52. package/dist/adapter/helpers/webgl-topology-utils.d.ts.map +1 -1
  53. package/dist/adapter/helpers/webgl-topology-utils.js +1 -1
  54. package/dist/adapter/helpers/webgl-topology-utils.js.map +1 -1
  55. package/dist/adapter/resources/webgl-buffer.d.ts +1 -1
  56. package/dist/adapter/resources/webgl-buffer.d.ts.map +1 -1
  57. package/dist/adapter/resources/webgl-buffer.js +20 -5
  58. package/dist/adapter/resources/webgl-buffer.js.map +1 -1
  59. package/dist/adapter/resources/webgl-command-buffer.d.ts +3 -3
  60. package/dist/adapter/resources/webgl-command-buffer.d.ts.map +1 -1
  61. package/dist/adapter/resources/webgl-command-buffer.js +22 -36
  62. package/dist/adapter/resources/webgl-command-buffer.js.map +1 -1
  63. package/dist/adapter/resources/webgl-command-encoder.d.ts +6 -5
  64. package/dist/adapter/resources/webgl-command-encoder.d.ts.map +1 -1
  65. package/dist/adapter/resources/webgl-command-encoder.js +23 -8
  66. package/dist/adapter/resources/webgl-command-encoder.js.map +1 -1
  67. package/dist/adapter/resources/webgl-framebuffer.d.ts +3 -1
  68. package/dist/adapter/resources/webgl-framebuffer.d.ts.map +1 -1
  69. package/dist/adapter/resources/webgl-framebuffer.js +10 -1
  70. package/dist/adapter/resources/webgl-framebuffer.js.map +1 -1
  71. package/dist/adapter/resources/webgl-query-set.d.ts +37 -31
  72. package/dist/adapter/resources/webgl-query-set.d.ts.map +1 -1
  73. package/dist/adapter/resources/webgl-query-set.js +247 -96
  74. package/dist/adapter/resources/webgl-query-set.js.map +1 -1
  75. package/dist/adapter/resources/webgl-render-pass.d.ts +1 -1
  76. package/dist/adapter/resources/webgl-render-pass.d.ts.map +1 -1
  77. package/dist/adapter/resources/webgl-render-pass.js +25 -11
  78. package/dist/adapter/resources/webgl-render-pass.js.map +1 -1
  79. package/dist/adapter/resources/webgl-render-pipeline.d.ts +17 -21
  80. package/dist/adapter/resources/webgl-render-pipeline.d.ts.map +1 -1
  81. package/dist/adapter/resources/webgl-render-pipeline.js +69 -167
  82. package/dist/adapter/resources/webgl-render-pipeline.js.map +1 -1
  83. package/dist/adapter/resources/webgl-sampler.d.ts +1 -1
  84. package/dist/adapter/resources/webgl-sampler.d.ts.map +1 -1
  85. package/dist/adapter/resources/webgl-sampler.js +1 -1
  86. package/dist/adapter/resources/webgl-sampler.js.map +1 -1
  87. package/dist/adapter/resources/webgl-shader.d.ts +1 -1
  88. package/dist/adapter/resources/webgl-shader.d.ts.map +1 -1
  89. package/dist/adapter/resources/webgl-shader.js +15 -8
  90. package/dist/adapter/resources/webgl-shader.js.map +1 -1
  91. package/dist/adapter/resources/webgl-shared-render-pipeline.d.ts +24 -0
  92. package/dist/adapter/resources/webgl-shared-render-pipeline.d.ts.map +1 -0
  93. package/dist/adapter/resources/webgl-shared-render-pipeline.js +155 -0
  94. package/dist/adapter/resources/webgl-shared-render-pipeline.js.map +1 -0
  95. package/dist/adapter/resources/webgl-texture.d.ts +27 -6
  96. package/dist/adapter/resources/webgl-texture.d.ts.map +1 -1
  97. package/dist/adapter/resources/webgl-texture.js +199 -101
  98. package/dist/adapter/resources/webgl-texture.js.map +1 -1
  99. package/dist/adapter/resources/webgl-transform-feedback.js +1 -1
  100. package/dist/adapter/resources/webgl-transform-feedback.js.map +1 -1
  101. package/dist/adapter/resources/webgl-vertex-array.d.ts +2 -2
  102. package/dist/adapter/resources/webgl-vertex-array.d.ts.map +1 -1
  103. package/dist/adapter/resources/webgl-vertex-array.js +1 -1
  104. package/dist/adapter/resources/webgl-vertex-array.js.map +1 -1
  105. package/dist/adapter/webgl-device.d.ts +6 -3
  106. package/dist/adapter/webgl-device.d.ts.map +1 -1
  107. package/dist/adapter/webgl-device.js +36 -4
  108. package/dist/adapter/webgl-device.js.map +1 -1
  109. package/dist/adapter/webgl-presentation-context.d.ts +21 -0
  110. package/dist/adapter/webgl-presentation-context.d.ts.map +1 -0
  111. package/dist/adapter/webgl-presentation-context.js +64 -0
  112. package/dist/adapter/webgl-presentation-context.js.map +1 -0
  113. package/dist/constants/index.d.ts +3 -0
  114. package/dist/constants/index.d.ts.map +1 -0
  115. package/dist/constants/index.js +5 -0
  116. package/dist/constants/index.js.map +1 -0
  117. package/dist/constants/webgl-constants.d.ts +822 -0
  118. package/dist/constants/webgl-constants.d.ts.map +1 -0
  119. package/dist/constants/webgl-constants.js +928 -0
  120. package/dist/constants/webgl-constants.js.map +1 -0
  121. package/dist/constants/webgl-types.d.ts +480 -0
  122. package/dist/constants/webgl-types.d.ts.map +1 -0
  123. package/dist/constants/webgl-types.js +6 -0
  124. package/dist/constants/webgl-types.js.map +1 -0
  125. package/dist/context/debug/webgl-developer-tools.js +1 -1
  126. package/dist/context/debug/webgl-developer-tools.js.map +1 -1
  127. package/dist/context/helpers/webgl-context-data.d.ts +1 -1
  128. package/dist/context/helpers/webgl-context-data.d.ts.map +1 -1
  129. package/dist/context/helpers/webgl-extensions.d.ts +1 -1
  130. package/dist/context/helpers/webgl-extensions.d.ts.map +1 -1
  131. package/dist/context/parameters/unified-parameter-api.d.ts +1 -1
  132. package/dist/context/parameters/unified-parameter-api.d.ts.map +1 -1
  133. package/dist/context/parameters/webgl-parameter-tables.d.ts +1 -1
  134. package/dist/context/parameters/webgl-parameter-tables.d.ts.map +1 -1
  135. package/dist/context/parameters/webgl-parameter-tables.js +1 -1
  136. package/dist/context/parameters/webgl-parameter-tables.js.map +1 -1
  137. package/dist/context/polyfills/polyfill-webgl1-extensions.js +1 -1
  138. package/dist/context/polyfills/polyfill-webgl1-extensions.js.map +1 -1
  139. package/dist/dist.dev.js +1473 -824
  140. package/dist/dist.min.js +2 -2
  141. package/dist/index.cjs +3 -5491
  142. package/dist/index.cjs.map +4 -4
  143. package/dist/index.d.ts +2 -0
  144. package/dist/index.d.ts.map +1 -1
  145. package/dist/index.js +1 -0
  146. package/dist/index.js.map +1 -1
  147. package/dist/webgl-constants.d.ts +2 -0
  148. package/dist/webgl-constants.d.ts.map +1 -0
  149. package/dist/webgl-constants.js +5 -0
  150. package/dist/webgl-constants.js.map +1 -0
  151. package/dist/webgl-types.d.ts +2 -0
  152. package/dist/webgl-types.d.ts.map +1 -0
  153. package/dist/{types.js → webgl-types.js} +1 -1
  154. package/dist/webgl-types.js.map +1 -0
  155. package/package.json +18 -4
  156. package/src/adapter/converters/device-parameters.ts +6 -2
  157. package/src/adapter/converters/sampler-parameters.ts +1 -1
  158. package/src/adapter/converters/shader-formats.ts +1 -66
  159. package/src/adapter/converters/webgl-shadertypes.ts +1 -9
  160. package/src/adapter/converters/webgl-texture-table.ts +160 -68
  161. package/src/adapter/converters/webgl-vertex-formats.ts +1 -1
  162. package/src/adapter/device-helpers/webgl-device-features.ts +2 -3
  163. package/src/adapter/device-helpers/webgl-device-info.ts +7 -1
  164. package/src/adapter/device-helpers/webgl-device-limits.ts +1 -1
  165. package/src/adapter/helpers/format-utils.ts +1 -1
  166. package/src/adapter/helpers/get-shader-layout-from-glsl.ts +38 -20
  167. package/src/adapter/helpers/set-uniform.ts +1 -1
  168. package/src/adapter/helpers/webgl-texture-utils.ts +4 -4
  169. package/src/adapter/helpers/webgl-topology-utils.ts +1 -1
  170. package/src/adapter/resources/webgl-buffer.ts +17 -5
  171. package/src/adapter/resources/webgl-command-buffer.ts +28 -28
  172. package/src/adapter/resources/webgl-command-encoder.ts +28 -11
  173. package/src/adapter/resources/webgl-framebuffer.ts +12 -1
  174. package/src/adapter/resources/webgl-query-set.ts +295 -101
  175. package/src/adapter/resources/webgl-render-pass.ts +26 -13
  176. package/src/adapter/resources/webgl-render-pipeline.ts +101 -196
  177. package/src/adapter/resources/webgl-sampler.ts +1 -1
  178. package/src/adapter/resources/webgl-shader.ts +15 -8
  179. package/src/adapter/resources/webgl-shared-render-pipeline.ts +211 -0
  180. package/src/adapter/resources/webgl-texture.ts +324 -122
  181. package/src/adapter/resources/webgl-transform-feedback.ts +1 -1
  182. package/src/adapter/resources/webgl-vertex-array.ts +1 -1
  183. package/src/adapter/webgl-device.ts +50 -6
  184. package/src/adapter/webgl-presentation-context.ts +93 -0
  185. package/src/constants/index.d.ts.map +1 -0
  186. package/src/constants/index.js.map +1 -0
  187. package/src/constants/index.ts +31 -0
  188. package/src/constants/webgl-constants.d.ts.map +1 -0
  189. package/src/constants/webgl-constants.js.map +1 -0
  190. package/src/constants/webgl-constants.ts +1051 -0
  191. package/src/constants/webgl-types.d.ts.map +1 -0
  192. package/src/constants/webgl-types.js.map +1 -0
  193. package/src/constants/webgl-types.ts +813 -0
  194. package/src/context/debug/webgl-developer-tools.ts +1 -1
  195. package/src/context/helpers/webgl-context-data.ts +1 -1
  196. package/src/context/helpers/webgl-extensions.ts +1 -1
  197. package/src/context/parameters/unified-parameter-api.ts +1 -1
  198. package/src/context/parameters/webgl-parameter-tables.ts +1 -1
  199. package/src/context/polyfills/polyfill-webgl1-extensions.ts +1 -1
  200. package/src/index.ts +26 -0
  201. package/src/webgl-constants.d.ts.map +1 -0
  202. package/src/webgl-constants.js.map +1 -0
  203. package/src/webgl-constants.ts +5 -0
  204. package/src/webgl-types.d.ts.map +1 -0
  205. package/src/webgl-types.js.map +1 -0
  206. package/src/webgl-types.ts +29 -0
  207. package/dist/types.d.ts +0 -11
  208. package/dist/types.d.ts.map +0 -1
  209. package/dist/types.js.map +0 -1
  210. package/src/types.ts +0 -14
@@ -11,12 +11,11 @@ import {
11
11
  type Sampler,
12
12
  type SamplerProps,
13
13
  type CopyExternalImageOptions,
14
- type CopyImageDataOptions,
15
14
  type TextureReadOptions,
16
15
  type TextureWriteOptions,
17
16
  type TextureFormat,
18
- type TypedArray,
19
17
  Buffer,
18
+ getTypedArrayConstructor,
20
19
  Texture,
21
20
  log
22
21
  } from '@luma.gl/core';
@@ -29,18 +28,17 @@ import {
29
28
  GLTextureCubeMapTarget,
30
29
  GLTexelDataFormat,
31
30
  GLPixelType
32
- } from '@luma.gl/constants';
31
+ } from '@luma.gl/webgl/constants';
33
32
 
34
33
  import {getTextureFormatWebGL} from '../converters/webgl-texture-table';
35
34
  import {convertSamplerParametersToWebGL} from '../converters/sampler-parameters';
36
35
  import {withGLParameters} from '../../context/state-tracker/with-parameters';
37
36
  import {WebGLDevice} from '../webgl-device';
37
+ import {WEBGLBuffer} from './webgl-buffer';
38
38
  import {WEBGLFramebuffer} from './webgl-framebuffer';
39
39
  import {WEBGLSampler} from './webgl-sampler';
40
40
  import {WEBGLTextureView} from './webgl-texture-view';
41
- import {convertDataTypeToGLDataType} from '../converters/webgl-shadertypes';
42
41
  import {convertGLDataTypeToDataType} from '../converters/shader-formats';
43
- import {getTypedArrayConstructor, getDataType} from '@luma.gl/core';
44
42
 
45
43
  /**
46
44
  * WebGL... the texture API from hell... hopefully made simpler
@@ -77,8 +75,10 @@ export class WEBGLTexture extends Texture {
77
75
  // state
78
76
  /** Texture binding slot - TODO - move to texture view? */
79
77
  _textureUnit: number = 0;
80
- /** Chached framebuffer */
78
+ /** Cached framebuffer reused for color texture readback. */
81
79
  _framebuffer: WEBGLFramebuffer | null = null;
80
+ /** Cache key for the currently attached readback subresource `${mipLevel}:${layer}`. */
81
+ _framebufferAttachmentKey: string | null = null;
82
82
 
83
83
  constructor(device: Device, props: TextureProps) {
84
84
  // const byteAlignment = this._getRowByteAlignment(props.format, props.width);
@@ -107,23 +107,31 @@ export class WEBGLTexture extends Texture {
107
107
  */
108
108
  this.gl.bindTexture(this.glTarget, this.handle);
109
109
  const {dimension, width, height, depth, mipLevels, glTarget, glInternalFormat} = this;
110
- switch (dimension) {
111
- case '2d':
112
- case 'cube':
113
- this.gl.texStorage2D(glTarget, mipLevels, glInternalFormat, width, height);
114
- break;
115
- case '2d-array':
116
- case '3d':
117
- this.gl.texStorage3D(glTarget, mipLevels, glInternalFormat, width, height, depth);
118
- break;
119
- default:
120
- throw new Error(dimension);
110
+ if (!this.compressed) {
111
+ switch (dimension) {
112
+ case '2d':
113
+ case 'cube':
114
+ this.gl.texStorage2D(glTarget, mipLevels, glInternalFormat, width, height);
115
+ break;
116
+ case '2d-array':
117
+ case '3d':
118
+ this.gl.texStorage3D(glTarget, mipLevels, glInternalFormat, width, height, depth);
119
+ break;
120
+ default:
121
+ throw new Error(dimension);
122
+ }
121
123
  }
122
124
  this.gl.bindTexture(this.glTarget, null);
123
125
 
124
126
  // Set data
125
127
  this._initializeData(props.data);
126
128
 
129
+ if (!this.props.handle) {
130
+ this.trackAllocatedMemory(this.getAllocatedByteLength(), 'Texture');
131
+ } else {
132
+ this.trackReferencedMemory(this.getAllocatedByteLength(), 'Texture');
133
+ }
134
+
127
135
  // Set texture sampler parameters
128
136
  this.setSampler(this.props.sampler);
129
137
  // @ts-ignore TODO - fix types
@@ -137,10 +145,15 @@ export class WEBGLTexture extends Texture {
137
145
  // Destroy any cached framebuffer
138
146
  this._framebuffer?.destroy();
139
147
  this._framebuffer = null;
148
+ this._framebufferAttachmentKey = null;
140
149
 
141
- this.gl.deleteTexture(this.handle);
142
150
  this.removeStats();
143
- this.trackDeallocatedMemory('Texture');
151
+ if (!this.props.handle) {
152
+ this.gl.deleteTexture(this.handle);
153
+ this.trackDeallocatedMemory('Texture');
154
+ } else {
155
+ this.trackDeallocatedReferencedMemory('Texture');
156
+ }
144
157
  // this.handle = null;
145
158
  this.destroyed = true;
146
159
  }
@@ -196,103 +209,156 @@ export class WEBGLTexture extends Texture {
196
209
  return {width: options.width, height: options.height};
197
210
  }
198
211
 
199
- copyImageData(options_: CopyImageDataOptions): void {
200
- const options = this._normalizeCopyImageDataOptions(options_);
212
+ override copyImageData(options_): void {
213
+ super.copyImageData(options_);
214
+ }
201
215
 
202
- const typedArray = options.data as TypedArray;
203
- const {width, height, depth, z = 0} = options;
204
- const {mipLevel = 0, byteOffset = 0, x = 0, y = 0} = options;
205
- const {glFormat, glType, compressed} = this;
216
+ /**
217
+ * Reads a color texture subresource into a GPU buffer using `PIXEL_PACK_BUFFER`.
218
+ *
219
+ * @note Only first-pass color readback is supported. Unsupported formats and aspects throw
220
+ * before any WebGL calls are issued.
221
+ */
222
+ readBuffer(options: TextureReadOptions & {byteOffset?: number} = {}, buffer?: Buffer): Buffer {
223
+ if (!buffer) {
224
+ throw new Error(`${this} readBuffer requires a destination buffer`);
225
+ }
226
+ const normalizedOptions = this._getSupportedColorReadOptions(options);
227
+ const byteOffset = options.byteOffset ?? 0;
228
+ const memoryLayout = this.computeMemoryLayout(normalizedOptions);
229
+
230
+ if (buffer.byteLength < byteOffset + memoryLayout.byteLength) {
231
+ throw new Error(
232
+ `${this} readBuffer target is too small (${buffer.byteLength} < ${byteOffset + memoryLayout.byteLength})`
233
+ );
234
+ }
235
+
236
+ const webglBuffer = buffer as WEBGLBuffer;
237
+ this.gl.bindBuffer(GL.PIXEL_PACK_BUFFER, webglBuffer.handle);
238
+ try {
239
+ this._readColorTextureLayers(normalizedOptions, memoryLayout, destinationByteOffset => {
240
+ this.gl.readPixels(
241
+ normalizedOptions.x,
242
+ normalizedOptions.y,
243
+ normalizedOptions.width,
244
+ normalizedOptions.height,
245
+ this.glFormat,
246
+ this.glType,
247
+ byteOffset + destinationByteOffset
248
+ );
249
+ });
250
+ } finally {
251
+ this.gl.bindBuffer(GL.PIXEL_PACK_BUFFER, null);
252
+ }
253
+
254
+ return buffer;
255
+ }
256
+
257
+ async readDataAsync(options: TextureReadOptions = {}): Promise<ArrayBuffer> {
258
+ throw new Error(
259
+ `${this} readDataAsync is deprecated; use readBuffer() with an explicit destination buffer or DynamicTexture.readAsync()`
260
+ );
261
+ }
206
262
 
207
- // Target used for face updates, but not for binding
263
+ writeBuffer(buffer: Buffer, options_: TextureWriteOptions = {}) {
264
+ const options = this._normalizeTextureWriteOptions(options_);
265
+ const {width, height, depthOrArrayLayers, mipLevel, byteOffset, x, y, z} = options;
266
+ const {glFormat, glType, compressed} = this;
208
267
  const glTarget = getWebGLCubeFaceTarget(this.glTarget, this.dimension, z);
209
268
 
210
- let unpackRowLength: number | undefined;
211
- if (!this.compressed) {
212
- const {bytesPerPixel} = this.device.getTextureFormatInfo(this.format);
213
- if (bytesPerPixel) {
214
- if (options.bytesPerRow % bytesPerPixel !== 0) {
215
- throw new Error(
216
- `bytesPerRow (${options.bytesPerRow}) must be a multiple of bytesPerPixel (${bytesPerPixel}) for ${this.format}`
217
- );
218
- }
219
- unpackRowLength = options.bytesPerRow / bytesPerPixel;
220
- }
269
+ if (compressed) {
270
+ throw new Error('writeBuffer for compressed textures is not implemented in WebGL');
221
271
  }
222
272
 
223
- const glParameters: GLValueParameters = !this.compressed
224
- ? {
225
- [GL.UNPACK_ALIGNMENT]: this.byteAlignment,
226
- ...(unpackRowLength !== undefined ? {[GL.UNPACK_ROW_LENGTH]: unpackRowLength} : {}),
227
- [GL.UNPACK_IMAGE_HEIGHT]: options.rowsPerImage
228
- }
229
- : {};
273
+ const {bytesPerPixel} = this.device.getTextureFormatInfo(this.format);
274
+ const unpackRowLength = bytesPerPixel ? options.bytesPerRow / bytesPerPixel : undefined;
275
+ const glParameters: GLValueParameters = {
276
+ [GL.UNPACK_ALIGNMENT]: this.byteAlignment,
277
+ ...(unpackRowLength !== undefined ? {[GL.UNPACK_ROW_LENGTH]: unpackRowLength} : {}),
278
+ [GL.UNPACK_IMAGE_HEIGHT]: options.rowsPerImage
279
+ };
230
280
 
231
281
  this.gl.bindTexture(this.glTarget, this.handle);
282
+ this.gl.bindBuffer(GL.PIXEL_UNPACK_BUFFER, buffer.handle);
232
283
 
233
284
  withGLParameters(this.gl, glParameters, () => {
234
285
  switch (this.dimension) {
235
286
  case '2d':
236
287
  case 'cube':
237
- if (compressed) {
238
- // prettier-ignore
239
- this.gl.compressedTexSubImage2D(glTarget, mipLevel, x, y, width, height, glFormat, typedArray, byteOffset); // , byteLength
240
- } else {
241
- // prettier-ignore
242
- this.gl.texSubImage2D(glTarget, mipLevel, x, y, width, height, glFormat, glType, typedArray, byteOffset); // , byteLength
243
- }
288
+ this.gl.texSubImage2D(
289
+ glTarget,
290
+ mipLevel,
291
+ x,
292
+ y,
293
+ width,
294
+ height,
295
+ glFormat,
296
+ glType,
297
+ byteOffset
298
+ );
244
299
  break;
245
300
  case '2d-array':
246
301
  case '3d':
247
- if (compressed) {
248
- // prettier-ignore
249
- this.gl.compressedTexSubImage3D(glTarget, mipLevel, x, y, z, width, height, depth, glFormat, typedArray, byteOffset); // , byteLength
250
- } else {
251
- // prettier-ignore
252
- this.gl.texSubImage3D(glTarget, mipLevel, x, y, z, width, height, depth, glFormat, glType, typedArray, byteOffset); // , byteLength
253
- }
302
+ this.gl.texSubImage3D(
303
+ glTarget,
304
+ mipLevel,
305
+ x,
306
+ y,
307
+ z,
308
+ width,
309
+ height,
310
+ depthOrArrayLayers,
311
+ glFormat,
312
+ glType,
313
+ byteOffset
314
+ );
254
315
  break;
255
316
  default:
256
- // Can never happen in WebGL
257
317
  }
258
318
  });
259
319
 
320
+ this.gl.bindBuffer(GL.PIXEL_UNPACK_BUFFER, null);
260
321
  this.gl.bindTexture(this.glTarget, null);
261
322
  }
262
323
 
263
- readBuffer(options: TextureReadOptions = {}, buffer?: Buffer): Buffer {
264
- throw new Error('readBuffer not implemented');
265
- }
266
-
267
- async readDataAsync(options: TextureReadOptions = {}): Promise<ArrayBuffer> {
268
- return this.readDataSyncWebGL(options);
269
- }
270
-
271
- writeBuffer(buffer: Buffer, options_: TextureWriteOptions = {}) {}
272
-
273
- writeData(data: ArrayBuffer | ArrayBufferView, options_: TextureWriteOptions = {}): void {
324
+ writeData(
325
+ data: ArrayBuffer | SharedArrayBuffer | ArrayBufferView,
326
+ options_: TextureWriteOptions = {}
327
+ ): void {
274
328
  const options = this._normalizeTextureWriteOptions(options_);
275
329
 
276
330
  const typedArray = ArrayBuffer.isView(data) ? data : new Uint8Array(data);
277
- const {} = this;
278
- const {width, height, mipLevel, x, y, z} = options;
331
+ const {width, height, depthOrArrayLayers, mipLevel, x, y, z, byteOffset} = options;
279
332
  const {glFormat, glType, compressed} = this;
280
- const depth = 0; // TODO - fix
281
- const glTarget = getWebGLCubeFaceTarget(this.glTarget, this.dimension, depth);
333
+ const glTarget = getWebGLCubeFaceTarget(this.glTarget, this.dimension, z);
282
334
 
283
- // const byteOffset = 0;
284
- // const {bytesPerRow, rowsPerImage} = this.computeMemoryLayout(options);
335
+ let unpackRowLength: number | undefined;
336
+ if (!compressed) {
337
+ const {bytesPerPixel} = this.device.getTextureFormatInfo(this.format);
338
+ if (bytesPerPixel) {
339
+ unpackRowLength = options.bytesPerRow / bytesPerPixel;
340
+ }
341
+ }
285
342
 
286
343
  const glParameters: GLValueParameters = !this.compressed
287
344
  ? {
288
- // WebGL does not require byte alignment, but allows it to be specified
289
- [GL.UNPACK_ALIGNMENT]: this.byteAlignment
290
- // [GL.UNPACK_ROW_LENGTH]: bytesPerRow,
291
- // [GL.UNPACK_IMAGE_HEIGHT]: rowsPerImage
345
+ [GL.UNPACK_ALIGNMENT]: this.byteAlignment,
346
+ ...(unpackRowLength !== undefined ? {[GL.UNPACK_ROW_LENGTH]: unpackRowLength} : {}),
347
+ [GL.UNPACK_IMAGE_HEIGHT]: options.rowsPerImage
292
348
  }
293
349
  : {};
350
+ const sourceElementOffset = getWebGLTextureSourceElementOffset(typedArray, byteOffset);
351
+ const compressedData = compressed ? getArrayBufferView(typedArray, byteOffset) : typedArray;
352
+ const mipLevelSize = this._getMipLevelSize(mipLevel);
353
+ const isFullMipUpload =
354
+ x === 0 &&
355
+ y === 0 &&
356
+ z === 0 &&
357
+ width === mipLevelSize.width &&
358
+ height === mipLevelSize.height &&
359
+ depthOrArrayLayers === mipLevelSize.depthOrArrayLayers;
294
360
 
295
- this.gl.bindTexture(glTarget, this.handle);
361
+ this.gl.bindTexture(this.glTarget, this.handle);
296
362
  this.gl.bindBuffer(GL.PIXEL_UNPACK_BUFFER, null);
297
363
 
298
364
  withGLParameters(this.gl, glParameters, () => {
@@ -300,21 +366,51 @@ export class WEBGLTexture extends Texture {
300
366
  case '2d':
301
367
  case 'cube':
302
368
  if (compressed) {
303
- // prettier-ignore
304
- this.gl.compressedTexSubImage2D(glTarget, mipLevel, x, y, width, height, glFormat, typedArray);
369
+ if (isFullMipUpload) {
370
+ // prettier-ignore
371
+ this.gl.compressedTexImage2D(glTarget, mipLevel, glFormat, width, height, 0, compressedData);
372
+ } else {
373
+ // prettier-ignore
374
+ this.gl.compressedTexSubImage2D(glTarget, mipLevel, x, y, width, height, glFormat, compressedData);
375
+ }
305
376
  } else {
306
377
  // prettier-ignore
307
- this.gl.texSubImage2D(glTarget, mipLevel, x, y, width, height, glFormat, glType, typedArray);
378
+ this.gl.texSubImage2D(glTarget, mipLevel, x, y, width, height, glFormat, glType, typedArray, sourceElementOffset);
308
379
  }
309
380
  break;
310
381
  case '2d-array':
311
382
  case '3d':
312
383
  if (compressed) {
313
- // prettier-ignore
314
- this.gl.compressedTexSubImage3D(glTarget, mipLevel, x, y, z, width, height, depth, glFormat, typedArray);
384
+ if (isFullMipUpload) {
385
+ // prettier-ignore
386
+ this.gl.compressedTexImage3D(
387
+ glTarget,
388
+ mipLevel,
389
+ glFormat,
390
+ width,
391
+ height,
392
+ depthOrArrayLayers,
393
+ 0,
394
+ compressedData
395
+ );
396
+ } else {
397
+ // prettier-ignore
398
+ this.gl.compressedTexSubImage3D(
399
+ glTarget,
400
+ mipLevel,
401
+ x,
402
+ y,
403
+ z,
404
+ width,
405
+ height,
406
+ depthOrArrayLayers,
407
+ glFormat,
408
+ compressedData
409
+ );
410
+ }
315
411
  } else {
316
412
  // prettier-ignore
317
- this.gl.texSubImage3D(glTarget, mipLevel, x, y, z, width, height, depth, glFormat, glType, typedArray);
413
+ this.gl.texSubImage3D(glTarget, mipLevel, x, y, z, width, height, depthOrArrayLayers, glFormat, glType, typedArray, sourceElementOffset);
318
414
  }
319
415
  break;
320
416
  default:
@@ -322,7 +418,7 @@ export class WEBGLTexture extends Texture {
322
418
  }
323
419
  });
324
420
 
325
- this.gl.bindTexture(glTarget, null);
421
+ this.gl.bindTexture(this.glTarget, null);
326
422
  }
327
423
 
328
424
  // IMPLEMENTATION SPECIFIC
@@ -357,57 +453,138 @@ export class WEBGLTexture extends Texture {
357
453
  // WEBGL SPECIFIC
358
454
 
359
455
  override readDataSyncWebGL(options_: TextureReadOptions = {}): ArrayBuffer {
360
- const options = this._normalizeTextureReadOptions(options_);
361
-
456
+ const options = this._getSupportedColorReadOptions(options_);
362
457
  const memoryLayout = this.computeMemoryLayout(options);
363
458
 
364
459
  // const formatInfo = getTextureFormatInfo(format);
365
460
  // Allocate pixel array if not already available, using supplied type
366
461
  const shaderType = convertGLDataTypeToDataType(this.glType);
367
-
368
462
  const ArrayType = getTypedArrayConstructor(shaderType);
369
- // const components = glFormatToComponents(this.glFormat);
370
- // TODO - check for composite type (components = 1).
371
-
372
- const targetArray = new ArrayType(memoryLayout.byteLength) as
463
+ const targetArray = new ArrayType(memoryLayout.byteLength / ArrayType.BYTES_PER_ELEMENT) as
373
464
  | Uint8Array
374
465
  | Uint16Array
375
- | Float32Array;
376
-
377
- // Pixel array available, if necessary, deduce type from it.
378
- const signedType = getDataType(targetArray);
379
- const sourceType = convertDataTypeToGLDataType(signedType);
466
+ | Float32Array
467
+ | Int8Array
468
+ | Int16Array
469
+ | Int32Array
470
+ | Uint32Array;
471
+
472
+ this._readColorTextureLayers(options, memoryLayout, destinationByteOffset => {
473
+ const layerView = new ArrayType(
474
+ targetArray.buffer,
475
+ targetArray.byteOffset + destinationByteOffset,
476
+ memoryLayout.bytesPerImage / ArrayType.BYTES_PER_ELEMENT
477
+ );
478
+ this.gl.readPixels(
479
+ options.x,
480
+ options.y,
481
+ options.width,
482
+ options.height,
483
+ this.glFormat,
484
+ this.glType,
485
+ layerView
486
+ );
487
+ });
380
488
 
381
- // There is a lot of hedging in the WebGL2 spec about what formats are guaranteed to be readable
382
- // (It should always be possible to read RGBA/UNSIGNED_BYTE, but most other combinations are not guaranteed)
383
- // Querying is possible but expensive:
384
- // const {device} = framebuffer;
385
- // texture.glReadFormat ||= gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT);
386
- // texture.glReadType ||= gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE);
387
- // console.log('params', device.getGLKey(texture.glReadFormat), device.getGLKey(texture.glReadType));
489
+ return targetArray.buffer as ArrayBuffer;
490
+ }
388
491
 
492
+ /**
493
+ * Iterates the requested mip/layer/slice range, reattaching the cached read framebuffer as
494
+ * needed before delegating the actual `readPixels()` call to the supplied callback.
495
+ */
496
+ private _readColorTextureLayers(
497
+ options: Required<TextureReadOptions>,
498
+ memoryLayout: ReturnType<Texture['computeMemoryLayout']>,
499
+ readLayer: (destinationByteOffset: number) => void
500
+ ): void {
389
501
  const framebuffer = this._getFramebuffer();
390
-
391
- // Note: luma.gl overrides bindFramebuffer so that we can reliably restore the previous framebuffer (this is the only function for which we do that)
502
+ const packRowLength = memoryLayout.bytesPerRow / memoryLayout.bytesPerPixel;
503
+ const glParameters: GLValueParameters = {
504
+ [GL.PACK_ALIGNMENT]: this.byteAlignment,
505
+ ...(packRowLength !== options.width ? {[GL.PACK_ROW_LENGTH]: packRowLength} : {})
506
+ };
507
+
508
+ // Note: luma.gl overrides bindFramebuffer so that we can reliably restore the previous framebuffer.
509
+ const prevReadBuffer = this.gl.getParameter(GL.READ_BUFFER) as GL;
392
510
  const prevHandle = this.gl.bindFramebuffer(
393
511
  GL.FRAMEBUFFER,
394
512
  framebuffer.handle
395
513
  ) as unknown as WebGLFramebuffer | null;
396
514
 
397
- // Select the color attachment to read from
398
- this.gl.readBuffer(GL.COLOR_ATTACHMENT0);
399
- this.gl.readPixels(
400
- options.x,
401
- options.y,
402
- options.width,
403
- options.height,
404
- this.glFormat,
405
- sourceType,
406
- targetArray
407
- );
408
- this.gl.bindFramebuffer(GL.FRAMEBUFFER, prevHandle || null);
515
+ try {
516
+ this.gl.readBuffer(GL.COLOR_ATTACHMENT0);
517
+ withGLParameters(this.gl, glParameters, () => {
518
+ for (let layerIndex = 0; layerIndex < options.depthOrArrayLayers; layerIndex++) {
519
+ this._attachReadSubresource(framebuffer, options.mipLevel, options.z + layerIndex);
520
+ readLayer(layerIndex * memoryLayout.bytesPerImage);
521
+ }
522
+ });
523
+ } finally {
524
+ this.gl.bindFramebuffer(GL.FRAMEBUFFER, prevHandle || null);
525
+ this.gl.readBuffer(prevReadBuffer);
526
+ }
527
+ }
409
528
 
410
- return targetArray.buffer as ArrayBuffer;
529
+ /**
530
+ * Attaches a single color subresource to the cached read framebuffer.
531
+ *
532
+ * @note Repeated attachments of the same `(mipLevel, layer)` tuple are skipped.
533
+ */
534
+ private _attachReadSubresource(
535
+ framebuffer: WEBGLFramebuffer,
536
+ mipLevel: number,
537
+ layer: number
538
+ ): void {
539
+ const attachmentKey = `${mipLevel}:${layer}`;
540
+ if (this._framebufferAttachmentKey === attachmentKey) {
541
+ return;
542
+ }
543
+
544
+ switch (this.dimension) {
545
+ case '2d':
546
+ this.gl.framebufferTexture2D(
547
+ GL.FRAMEBUFFER,
548
+ GL.COLOR_ATTACHMENT0,
549
+ GL.TEXTURE_2D,
550
+ this.handle,
551
+ mipLevel
552
+ );
553
+ break;
554
+
555
+ case 'cube':
556
+ this.gl.framebufferTexture2D(
557
+ GL.FRAMEBUFFER,
558
+ GL.COLOR_ATTACHMENT0,
559
+ getWebGLCubeFaceTarget(this.glTarget, this.dimension, layer),
560
+ this.handle,
561
+ mipLevel
562
+ );
563
+ break;
564
+
565
+ case '2d-array':
566
+ case '3d':
567
+ this.gl.framebufferTextureLayer(
568
+ GL.FRAMEBUFFER,
569
+ GL.COLOR_ATTACHMENT0,
570
+ this.handle,
571
+ mipLevel,
572
+ layer
573
+ );
574
+ break;
575
+
576
+ default:
577
+ throw new Error(`${this} color readback does not support ${this.dimension} textures`);
578
+ }
579
+
580
+ if (this.device.props.debug) {
581
+ const status = Number(this.gl.checkFramebufferStatus(GL.FRAMEBUFFER));
582
+ if (status !== Number(GL.FRAMEBUFFER_COMPLETE)) {
583
+ throw new Error(`${framebuffer} incomplete for ${this} readback (${status})`);
584
+ }
585
+ }
586
+
587
+ this._framebufferAttachmentKey = attachmentKey;
411
588
  }
412
589
 
413
590
  /**
@@ -514,6 +691,31 @@ export class WEBGLTexture extends Texture {
514
691
  }
515
692
  }
516
693
 
694
+ function getArrayBufferView(typedArray: ArrayBufferView, byteOffset = 0): ArrayBufferView {
695
+ if (!byteOffset) {
696
+ return typedArray;
697
+ }
698
+
699
+ return new typedArray.constructor(
700
+ typedArray.buffer,
701
+ typedArray.byteOffset + byteOffset,
702
+ (typedArray.byteLength - byteOffset) / typedArray.BYTES_PER_ELEMENT
703
+ ) as ArrayBufferView;
704
+ }
705
+
706
+ function getWebGLTextureSourceElementOffset(
707
+ typedArray: ArrayBufferView,
708
+ byteOffset: number
709
+ ): number {
710
+ if (byteOffset % typedArray.BYTES_PER_ELEMENT !== 0) {
711
+ throw new Error(
712
+ `Texture byteOffset ${byteOffset} must align to typed array element size ${typedArray.BYTES_PER_ELEMENT}`
713
+ );
714
+ }
715
+
716
+ return byteOffset / typedArray.BYTES_PER_ELEMENT;
717
+ }
718
+
517
719
  // INTERNAL HELPERS
518
720
 
519
721
  /** Convert a WebGPU style texture constant to a WebGL style texture constant */
@@ -1,6 +1,6 @@
1
1
  import type {PrimitiveTopology, ShaderLayout, TransformFeedbackProps} from '@luma.gl/core';
2
2
  import {log, TransformFeedback, Buffer, BufferRange} from '@luma.gl/core';
3
- import {GL} from '@luma.gl/constants';
3
+ import {GL} from '@luma.gl/webgl/constants';
4
4
  import {WebGLDevice} from '../webgl-device';
5
5
  import {WEBGLBuffer} from '../../index';
6
6
  import {getGLPrimitive} from '../helpers/webgl-topology-utils';
@@ -5,7 +5,7 @@
5
5
  import type {TypedArray, NumericArray} from '@math.gl/types';
6
6
  import type {Device, Buffer, VertexArrayProps} from '@luma.gl/core';
7
7
  import {VertexArray, getScratchArray} from '@luma.gl/core';
8
- import {GL} from '@luma.gl/constants';
8
+ import {GL} from '@luma.gl/webgl/constants';
9
9
  import {getBrowser} from '@probe.gl/env';
10
10
 
11
11
  import {WebGLDevice} from '../webgl-device';