@luma.gl/webgl 9.1.0-alpha.15 → 9.1.0-alpha.17

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 (69) hide show
  1. package/dist/adapter/converters/device-parameters.d.ts +3 -3
  2. package/dist/adapter/converters/device-parameters.d.ts.map +1 -1
  3. package/dist/adapter/converters/sampler-parameters.js +6 -4
  4. package/dist/adapter/converters/texture-formats.d.ts +49 -11
  5. package/dist/adapter/converters/texture-formats.d.ts.map +1 -1
  6. package/dist/adapter/converters/texture-formats.js +150 -160
  7. package/dist/adapter/helpers/format-utils.d.ts.map +1 -1
  8. package/dist/adapter/helpers/format-utils.js +6 -0
  9. package/dist/adapter/helpers/webgl-texture-utils.d.ts +34 -30
  10. package/dist/adapter/helpers/webgl-texture-utils.d.ts.map +1 -1
  11. package/dist/adapter/helpers/webgl-texture-utils.js +52 -256
  12. package/dist/adapter/resources/webgl-command-buffer.d.ts +59 -2
  13. package/dist/adapter/resources/webgl-command-buffer.d.ts.map +1 -1
  14. package/dist/adapter/resources/webgl-command-buffer.js +87 -31
  15. package/dist/adapter/resources/webgl-command-encoder.d.ts.map +1 -1
  16. package/dist/adapter/resources/webgl-command-encoder.js +3 -0
  17. package/dist/adapter/resources/webgl-external-texture.js +14 -0
  18. package/dist/adapter/resources/webgl-framebuffer.d.ts.map +1 -1
  19. package/dist/adapter/resources/webgl-framebuffer.js +1 -2
  20. package/dist/adapter/resources/webgl-render-pass.d.ts.map +1 -1
  21. package/dist/adapter/resources/webgl-render-pass.js +38 -20
  22. package/dist/adapter/resources/webgl-render-pipeline.d.ts +1 -1
  23. package/dist/adapter/resources/webgl-render-pipeline.d.ts.map +1 -1
  24. package/dist/adapter/resources/webgl-render-pipeline.js +30 -16
  25. package/dist/adapter/resources/webgl-shader.d.ts +1 -0
  26. package/dist/adapter/resources/webgl-shader.d.ts.map +1 -1
  27. package/dist/adapter/resources/webgl-shader.js +7 -5
  28. package/dist/adapter/resources/webgl-texture.d.ts +8 -14
  29. package/dist/adapter/resources/webgl-texture.d.ts.map +1 -1
  30. package/dist/adapter/resources/webgl-texture.js +119 -208
  31. package/dist/adapter/webgl-adapter.d.ts.map +1 -1
  32. package/dist/adapter/webgl-adapter.js +4 -10
  33. package/dist/adapter/webgl-device.d.ts +8 -3
  34. package/dist/adapter/webgl-device.d.ts.map +1 -1
  35. package/dist/adapter/webgl-device.js +53 -22
  36. package/dist/context/debug/spector-types.js +1 -1
  37. package/dist/context/debug/spector.d.ts +5 -5
  38. package/dist/context/debug/spector.d.ts.map +1 -1
  39. package/dist/context/debug/spector.js +6 -6
  40. package/dist/context/debug/webgl-developer-tools.d.ts +2 -3
  41. package/dist/context/debug/webgl-developer-tools.d.ts.map +1 -1
  42. package/dist/context/debug/webgl-developer-tools.js +6 -19
  43. package/dist/context/helpers/create-browser-context.d.ts +6 -22
  44. package/dist/context/helpers/create-browser-context.d.ts.map +1 -1
  45. package/dist/context/helpers/create-browser-context.js +40 -32
  46. package/dist/dist.dev.js +366 -400
  47. package/dist/dist.min.js +2 -2
  48. package/dist/index.cjs +341 -384
  49. package/dist/index.cjs.map +3 -3
  50. package/package.json +4 -4
  51. package/src/adapter/converters/device-parameters.ts +3 -3
  52. package/src/adapter/converters/sampler-parameters.ts +6 -4
  53. package/src/adapter/converters/texture-formats.ts +171 -177
  54. package/src/adapter/helpers/format-utils.ts +6 -0
  55. package/src/adapter/helpers/webgl-texture-utils.ts +99 -75
  56. package/src/adapter/resources/webgl-command-buffer.ts +124 -40
  57. package/src/adapter/resources/webgl-command-encoder.ts +6 -0
  58. package/src/adapter/resources/webgl-external-texture.ts +14 -0
  59. package/src/adapter/resources/webgl-framebuffer.ts +1 -2
  60. package/src/adapter/resources/webgl-render-pass.ts +44 -23
  61. package/src/adapter/resources/webgl-render-pipeline.ts +32 -16
  62. package/src/adapter/resources/webgl-shader.ts +8 -6
  63. package/src/adapter/resources/webgl-texture.ts +126 -235
  64. package/src/adapter/webgl-adapter.ts +4 -12
  65. package/src/adapter/webgl-device.ts +88 -48
  66. package/src/context/debug/spector-types.ts +1 -1
  67. package/src/context/debug/spector.ts +11 -11
  68. package/src/context/debug/webgl-developer-tools.ts +8 -31
  69. package/src/context/helpers/create-browser-context.ts +53 -63
@@ -6,24 +6,24 @@
6
6
  // WebGL... the texture API from hell... hopefully made simpler
7
7
  //
8
8
 
9
+ import {TypedArray} from '@math.gl/types';
9
10
  import type {ExternalImage} from '@luma.gl/core';
10
11
  import {Buffer, Texture, Framebuffer, FramebufferProps} from '@luma.gl/core';
11
-
12
12
  import {
13
13
  GL,
14
14
  GLTextureTarget,
15
15
  GLTextureCubeMapTarget,
16
16
  GLTexelDataFormat,
17
- GLPixelType
17
+ GLPixelType,
18
+ GLDataType
18
19
  } from '@luma.gl/constants';
19
20
 
20
- import {TypedArray} from '@math.gl/types';
21
-
22
21
  import {WEBGLFramebuffer} from '../resources/webgl-framebuffer';
23
22
  import {getGLTypeFromTypedArray, getTypedArrayFromGLType} from './typed-array-utils';
24
23
  import {glFormatToComponents, glTypeToBytes} from './format-utils';
25
24
  import {WEBGLBuffer} from '../resources/webgl-buffer';
26
25
  import {WEBGLTexture} from '../resources/webgl-texture';
26
+ import {withGLParameters} from '../../context/state-tracker/with-parameters';
27
27
 
28
28
  /** A "border" parameter is required in many WebGL texture APIs, but must always be 0... */
29
29
  const BORDER = 0;
@@ -120,7 +120,7 @@ export function copyExternalImageToMipLevel(
120
120
  gl: WebGL2RenderingContext,
121
121
  handle: WebGLTexture,
122
122
  image: ExternalImage,
123
- options: WebGLCopyTextureOptions
123
+ options: WebGLCopyTextureOptions & {flipY?: boolean}
124
124
  ): void {
125
125
  const {width, height} = options;
126
126
  const {dimension, depth = 0, mipLevel = 0} = options;
@@ -129,26 +129,29 @@ export function copyExternalImageToMipLevel(
129
129
 
130
130
  const glTarget = getWebGLCubeFaceTarget(options.glTarget, dimension, depth);
131
131
 
132
- switch (dimension) {
133
- case '2d-array':
134
- case '3d':
135
- gl.bindTexture(glTarget, handle);
136
- // prettier-ignore
137
- gl.texSubImage3D(glTarget, mipLevel, x, y, z, width, height, depth, glFormat, glType, image);
138
- gl.bindTexture(glTarget, null);
139
- break;
132
+ const glParameters = options.flipY ? {[GL.UNPACK_FLIP_Y_WEBGL]: true} : {};
133
+ withGLParameters(gl, glParameters, () => {
134
+ switch (dimension) {
135
+ case '2d-array':
136
+ case '3d':
137
+ gl.bindTexture(glTarget, handle);
138
+ // prettier-ignore
139
+ gl.texSubImage3D(glTarget, mipLevel, x, y, z, width, height, depth, glFormat, glType, image);
140
+ gl.bindTexture(glTarget, null);
141
+ break;
140
142
 
141
- case '2d':
142
- case 'cube':
143
- gl.bindTexture(glTarget, handle);
144
- // prettier-ignore
145
- gl.texSubImage2D(glTarget, mipLevel, x, y, width, height, glFormat, glType, image);
146
- gl.bindTexture(glTarget, null);
147
- break;
143
+ case '2d':
144
+ case 'cube':
145
+ gl.bindTexture(glTarget, handle);
146
+ // prettier-ignore
147
+ gl.texSubImage2D(glTarget, mipLevel, x, y, width, height, glFormat, glType, image);
148
+ gl.bindTexture(glTarget, null);
149
+ break;
148
150
 
149
- default:
150
- throw new Error(dimension);
151
- }
151
+ default:
152
+ throw new Error(dimension);
153
+ }
154
+ });
152
155
  }
153
156
 
154
157
  /**
@@ -278,7 +281,7 @@ export function getWebGLCubeFaceTarget(
278
281
  * Wrapper for the messy WebGL texture API
279
282
  *
280
283
  export function clearMipLevel(gl: WebGL2RenderingContext, options: WebGLSetTextureOptions): void {
281
- const {dimension, width, height, depth = 0, level = 0} = options;
284
+ const {dimension, width, height, depth = 0, mipLevel = 0} = options;
282
285
  const {glInternalFormat, glFormat, glType, compressed} = options;
283
286
  const glTarget = getWebGLCubeFaceTarget(options.glTarget, dimension, depth);
284
287
 
@@ -287,10 +290,10 @@ export function clearMipLevel(gl: WebGL2RenderingContext, options: WebGLSetTextu
287
290
  case '3d':
288
291
  if (compressed) {
289
292
  // prettier-ignore
290
- gl.compressedTexImage3D(glTarget, level, glInternalFormat, width, height, depth, BORDER, null);
293
+ gl.compressedTexImage3D(glTarget, mipLevel, glInternalFormat, width, height, depth, BORDER, null);
291
294
  } else {
292
295
  // prettier-ignore
293
- gl.texImage3D( glTarget, level, glInternalFormat, width, height, depth, BORDER, glFormat, glType, null);
296
+ gl.texImage3D( glTarget, mipLevel, glInternalFormat, width, height, depth, BORDER, glFormat, glType, null);
294
297
  }
295
298
  break;
296
299
 
@@ -298,10 +301,10 @@ export function clearMipLevel(gl: WebGL2RenderingContext, options: WebGLSetTextu
298
301
  case 'cube':
299
302
  if (compressed) {
300
303
  // prettier-ignore
301
- gl.compressedTexImage2D(glTarget, level, glInternalFormat, width, height, BORDER, null);
304
+ gl.compressedTexImage2D(glTarget, mipLevel, glInternalFormat, width, height, BORDER, null);
302
305
  } else {
303
306
  // prettier-ignore
304
- gl.texImage2D(glTarget, level, glInternalFormat, width, height, BORDER, glFormat, glType, null);
307
+ gl.texImage2D(glTarget, mipLevel, glInternalFormat, width, height, BORDER, glFormat, glType, null);
305
308
  }
306
309
  break;
307
310
 
@@ -309,6 +312,7 @@ export function clearMipLevel(gl: WebGL2RenderingContext, options: WebGLSetTextu
309
312
  throw new Error(dimension);
310
313
  }
311
314
  }
315
+ */
312
316
 
313
317
  /**
314
318
  * Set a texture mip level to the contents of an external image.
@@ -490,6 +494,30 @@ export function setMipLevelFromGPUBuffer(
490
494
  gl.bindBuffer(GL.PIXEL_UNPACK_BUFFER, null);
491
495
  }
492
496
  */
497
+ export type ReadPixelsToArrayOptions = {
498
+ sourceX?: number;
499
+ sourceY?: number;
500
+ sourceFormat?: number;
501
+ sourceAttachment?: number;
502
+ target?: Uint8Array | Uint16Array | Float32Array;
503
+ // following parameters are auto deduced if not provided
504
+ sourceWidth?: number;
505
+ sourceHeight?: number;
506
+ sourceDepth?: number;
507
+ sourceType?: number;
508
+ };
509
+
510
+ export type ReadPixelsToBufferOptions = {
511
+ sourceX?: number;
512
+ sourceY?: number;
513
+ sourceFormat?: number;
514
+ target?: Buffer; // A new Buffer object is created when not provided.
515
+ targetByteOffset?: number; // byte offset in buffer object
516
+ // following parameters are auto deduced if not provided
517
+ sourceWidth?: number;
518
+ sourceHeight?: number;
519
+ sourceType?: number;
520
+ };
493
521
 
494
522
  /**
495
523
  * Copies data from a type or a Texture object into ArrayBuffer object.
@@ -504,23 +532,12 @@ export function setMipLevelFromGPUBuffer(
504
532
  */
505
533
  export function readPixelsToArray(
506
534
  source: Framebuffer | Texture,
507
- options?: {
508
- sourceX?: number;
509
- sourceY?: number;
510
- sourceFormat?: number;
511
- sourceAttachment?: number;
512
- target?: Uint8Array | Uint16Array | Float32Array;
513
- // following parameters are auto deduced if not provided
514
- sourceWidth?: number;
515
- sourceHeight?: number;
516
- sourceDepth?: number;
517
- sourceType?: number;
518
- }
535
+ options?: ReadPixelsToArrayOptions
519
536
  ): Uint8Array | Uint16Array | Float32Array {
520
537
  const {
521
538
  sourceX = 0,
522
539
  sourceY = 0,
523
- sourceAttachment = GL.COLOR_ATTACHMENT0 // TODO - support gl.readBuffer
540
+ sourceAttachment = 0 // TODO - support gl.readBuffer
524
541
  } = options || {};
525
542
  let {
526
543
  target = null,
@@ -535,21 +552,19 @@ export function readPixelsToArray(
535
552
  const {framebuffer, deleteFramebuffer} = getFramebuffer(source);
536
553
  // assert(framebuffer);
537
554
  const {gl, handle} = framebuffer;
538
- const attachment = sourceAttachment - GL.COLOR_ATTACHMENT0;
539
555
 
540
556
  sourceWidth ||= framebuffer.width;
541
557
  sourceHeight ||= framebuffer.height;
542
558
 
543
- // TODO - Set and unset gl.readBuffer
544
- // if (sourceAttachment === GL.COLOR_ATTACHMENT0 && handle === null) {
545
- // sourceAttachment = GL.FRONT;
546
- // }
547
-
548
- sourceDepth = framebuffer.colorAttachments[attachment]?.texture?.depth || 1;
559
+ const texture = framebuffer.colorAttachments[sourceAttachment]?.texture;
560
+ if (!texture) {
561
+ throw new Error(`Invalid framebuffer attachment ${sourceAttachment}`);
562
+ }
563
+ sourceDepth = texture?.depth || 1;
549
564
 
550
- sourceFormat ||= framebuffer.colorAttachments[attachment]?.texture?.glFormat || GL.RGBA;
565
+ sourceFormat ||= texture?.glFormat || GL.RGBA;
551
566
  // Deduce the type from color attachment if not provided.
552
- sourceType ||= framebuffer.colorAttachments[attachment]?.texture?.glType || GL.UNSIGNED_BYTE;
567
+ sourceType ||= texture?.glType || GL.UNSIGNED_BYTE;
553
568
 
554
569
  // Deduce type and allocated pixelArray if needed
555
570
  target = getPixelArray(target, sourceType, sourceFormat, sourceWidth, sourceHeight, sourceDepth);
@@ -557,13 +572,31 @@ export function readPixelsToArray(
557
572
  // Pixel array available, if necessary, deduce type from it.
558
573
  sourceType = sourceType || getGLTypeFromTypedArray(target);
559
574
 
560
- const prevHandle = gl.bindFramebuffer(GL.FRAMEBUFFER, handle);
575
+ // Note: luma.gl overrides bindFramebuffer so that we can reliably restore the previous framebuffer (this is the only function for which we do that)
576
+ const prevHandle = gl.bindFramebuffer(
577
+ GL.FRAMEBUFFER,
578
+ handle
579
+ ) as unknown as WebGLFramebuffer | null;
580
+
581
+ // Select the color attachment to read from
582
+ gl.readBuffer(gl.COLOR_ATTACHMENT0 + sourceAttachment);
583
+
584
+ // There is a lot of hedging in the WebGL2 spec about what formats are guaranteed to be readable
585
+ // (It should always be possible to read RGBA/UNSIGNED_BYTE, but most other combinations are not guaranteed)
586
+ // Querying is possible but expensive:
587
+ // const {device} = framebuffer;
588
+ // texture.glReadFormat ||= gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT);
589
+ // texture.glReadType ||= gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE);
590
+ // console.log('params', device.getGLKey(texture.glReadFormat), device.getGLKey(texture.glReadType));
591
+
561
592
  gl.readPixels(sourceX, sourceY, sourceWidth, sourceHeight, sourceFormat, sourceType, target);
562
- // @ts-expect-error
593
+ gl.readBuffer(gl.COLOR_ATTACHMENT0);
563
594
  gl.bindFramebuffer(GL.FRAMEBUFFER, prevHandle || null);
595
+
564
596
  if (deleteFramebuffer) {
565
597
  framebuffer.destroy();
566
598
  }
599
+
567
600
  return target;
568
601
  }
569
602
 
@@ -576,17 +609,7 @@ export function readPixelsToArray(
576
609
  */
577
610
  export function readPixelsToBuffer(
578
611
  source: Framebuffer | Texture,
579
- options?: {
580
- sourceX?: number;
581
- sourceY?: number;
582
- sourceFormat?: number;
583
- target?: Buffer; // A new Buffer object is created when not provided.
584
- targetByteOffset?: number; // byte offset in buffer object
585
- // following parameters are auto deduced if not provided
586
- sourceWidth?: number;
587
- sourceHeight?: number;
588
- sourceType?: number;
589
- }
612
+ options?: ReadPixelsToBufferOptions
590
613
  ): WEBGLBuffer {
591
614
  const {
592
615
  target,
@@ -620,11 +643,11 @@ export function readPixelsToBuffer(
620
643
  // TODO(donmccurdy): Do we have tests to confirm this is working?
621
644
  const commandEncoder = source.device.createCommandEncoder();
622
645
  commandEncoder.copyTextureToBuffer({
623
- source: source as Texture,
646
+ sourceTexture: source as Texture,
624
647
  width: sourceWidth,
625
648
  height: sourceHeight,
626
649
  origin: [sourceX, sourceY],
627
- destination: webglBufferTarget,
650
+ destinationBuffer: webglBufferTarget,
628
651
  byteOffset: targetByteOffset
629
652
  });
630
653
  commandEncoder.destroy();
@@ -642,8 +665,8 @@ export function readPixelsToBuffer(
642
665
  */
643
666
  // eslint-disable-next-line complexity, max-statements
644
667
  export function copyToTexture(
645
- source: Framebuffer | Texture,
646
- target: Texture | GL,
668
+ sourceTexture: Framebuffer | Texture,
669
+ destinationTexture: Texture | GL,
647
670
  options?: {
648
671
  sourceX?: number;
649
672
  sourceY?: number;
@@ -673,7 +696,7 @@ export function copyToTexture(
673
696
  height // defaults to target height
674
697
  } = options || {};
675
698
 
676
- const {framebuffer, deleteFramebuffer} = getFramebuffer(source);
699
+ const {framebuffer, deleteFramebuffer} = getFramebuffer(sourceTexture);
677
700
  // assert(framebuffer);
678
701
  const webglFramebuffer = framebuffer;
679
702
  const {device, handle} = webglFramebuffer;
@@ -690,8 +713,8 @@ export function copyToTexture(
690
713
  // assert(target);
691
714
  let texture: WEBGLTexture | null = null;
692
715
  let textureTarget: GL;
693
- if (target instanceof WEBGLTexture) {
694
- texture = target;
716
+ if (destinationTexture instanceof WEBGLTexture) {
717
+ texture = destinationTexture;
695
718
  width = Number.isFinite(width) ? width : texture.width;
696
719
  height = Number.isFinite(height) ? height : texture.height;
697
720
  texture?.bind(0);
@@ -785,8 +808,8 @@ export function toFramebuffer(texture: Texture, props?: FramebufferProps): WEBGL
785
808
  // eslint-disable-next-line max-params
786
809
  function getPixelArray(
787
810
  pixelArray,
788
- type,
789
- format,
811
+ glType: GLDataType | GLPixelType,
812
+ glFormat: GL,
790
813
  width: number,
791
814
  height: number,
792
815
  depth?: number
@@ -794,10 +817,11 @@ function getPixelArray(
794
817
  if (pixelArray) {
795
818
  return pixelArray;
796
819
  }
820
+ // const formatInfo = decodeTextureFormat(format);
797
821
  // Allocate pixel array if not already available, using supplied type
798
- type = type || GL.UNSIGNED_BYTE;
799
- const ArrayType = getTypedArrayFromGLType(type, {clamped: false});
800
- const components = glFormatToComponents(format);
822
+ glType ||= GL.UNSIGNED_BYTE;
823
+ const ArrayType = getTypedArrayFromGLType(glType, {clamped: false});
824
+ const components = glFormatToComponents(glFormat);
801
825
  // TODO - check for composite type (components = 1).
802
826
  return new ArrayType(width * height * components) as Uint8Array | Uint16Array | Float32Array;
803
827
  }
@@ -7,9 +7,18 @@ import type {
7
7
  CopyBufferToTextureOptions,
8
8
  CopyTextureToBufferOptions,
9
9
  CopyTextureToTextureOptions
10
+ // ClearTextureOptions,
11
+ // ReadTextureOptions
10
12
  } from '@luma.gl/core';
11
13
  import {CommandBuffer, Texture, Framebuffer} from '@luma.gl/core';
12
- import {GL} from '@luma.gl/constants';
14
+ import {
15
+ GL,
16
+ GLTextureTarget,
17
+ GLTextureCubeMapTarget
18
+ // GLTexelDataFormat,
19
+ // GLPixelType,
20
+ // GLDataType
21
+ } from '@luma.gl/constants';
13
22
 
14
23
  import {WebGLDevice} from '../webgl-device';
15
24
  import {WEBGLBuffer} from './webgl-buffer';
@@ -37,11 +46,23 @@ type CopyTextureToTextureCommand = {
37
46
  options: CopyTextureToTextureOptions;
38
47
  };
39
48
 
49
+ type ClearTextureCommand = {
50
+ name: 'clear-texture';
51
+ options: {}; // ClearTextureOptions;
52
+ };
53
+
54
+ type ReadTextureCommand = {
55
+ name: 'read-texture';
56
+ options: {}; // ReadTextureOptions;
57
+ };
58
+
40
59
  type Command =
41
60
  | CopyBufferToBufferCommand
42
61
  | CopyBufferToTextureCommand
43
62
  | CopyTextureToBufferCommand
44
- | CopyTextureToTextureCommand;
63
+ | CopyTextureToTextureCommand
64
+ | ClearTextureCommand
65
+ | ReadTextureCommand;
45
66
 
46
67
  export class WEBGLCommandBuffer extends CommandBuffer {
47
68
  device: WebGLDevice;
@@ -67,14 +88,19 @@ export class WEBGLCommandBuffer extends CommandBuffer {
67
88
  case 'copy-texture-to-texture':
68
89
  _copyTextureToTexture(this.device, command.options);
69
90
  break;
91
+ // case 'clear-texture':
92
+ // _clearTexture(this.device, command.options);
93
+ // break;
94
+ default:
95
+ throw new Error(command.name);
70
96
  }
71
97
  }
72
98
  }
73
99
  }
74
100
 
75
101
  function _copyBufferToBuffer(device: WebGLDevice, options: CopyBufferToBufferOptions): void {
76
- const source = options.source as WEBGLBuffer;
77
- const destination = options.destination as WEBGLBuffer;
102
+ const source = options.sourceBuffer as WEBGLBuffer;
103
+ const destination = options.destinationBuffer as WEBGLBuffer;
78
104
 
79
105
  // {In WebGL2 we can p}erform the copy on the GPU
80
106
  // Use GL.COPY_READ_BUFFER+GL.COPY_WRITE_BUFFER avoid disturbing other targets and locking type
@@ -106,22 +132,22 @@ function _copyBufferToTexture(device: WebGLDevice, options: CopyBufferToTextureO
106
132
  function _copyTextureToBuffer(device: WebGLDevice, options: CopyTextureToBufferOptions): void {
107
133
  const {
108
134
  /** Texture to copy to/from. */
109
- source,
135
+ sourceTexture,
110
136
  /** Mip-map level of the texture to copy to/from. (Default 0) */
111
137
  mipLevel = 0,
112
138
  /** Defines which aspects of the texture to copy to/from. */
113
139
  aspect = 'all',
114
140
 
115
141
  /** Width to copy */
116
- width = options.source.width,
142
+ width = options.sourceTexture.width,
117
143
  /** Height to copy */
118
- height = options.source.height,
144
+ height = options.sourceTexture.height,
119
145
  depthOrArrayLayers = 0,
120
146
  /** Defines the origin of the copy - the minimum corner of the texture sub-region to copy to/from. */
121
147
  origin = [0, 0],
122
148
 
123
149
  /** Destination buffer */
124
- destination,
150
+ destinationBuffer,
125
151
  /** Offset, in bytes, from the beginning of the buffer to the start of the image data (default 0) */
126
152
  byteOffset = 0,
127
153
  /**
@@ -139,7 +165,7 @@ function _copyTextureToBuffer(device: WebGLDevice, options: CopyTextureToBufferO
139
165
 
140
166
  // TODO - Not possible to read just stencil or depth part in WebGL?
141
167
  if (aspect !== 'all') {
142
- throw new Error('not supported');
168
+ throw new Error('aspect not supported in WebGL');
143
169
  }
144
170
 
145
171
  // TODO - mipLevels are set when attaching texture to framebuffer
@@ -148,10 +174,10 @@ function _copyTextureToBuffer(device: WebGLDevice, options: CopyTextureToBufferO
148
174
  }
149
175
 
150
176
  // Asynchronous read (PIXEL_PACK_BUFFER) is WebGL2 only feature
151
- const {framebuffer, destroyFramebuffer} = getFramebuffer(source);
177
+ const {framebuffer, destroyFramebuffer} = getFramebuffer(sourceTexture);
152
178
  let prevHandle: WebGLFramebuffer | null | undefined;
153
179
  try {
154
- const webglBuffer = destination as WEBGLBuffer;
180
+ const webglBuffer = destinationBuffer as WEBGLBuffer;
155
181
  const sourceWidth = width || framebuffer.width;
156
182
  const sourceHeight = height || framebuffer.height;
157
183
  const sourceParams = getTextureFormatWebGL(
@@ -220,7 +246,7 @@ export function readPixelsToBuffer(
220
246
  function _copyTextureToTexture(device: WebGLDevice, options: CopyTextureToTextureOptions): void {
221
247
  const {
222
248
  /** Texture to copy to/from. */
223
- source,
249
+ sourceTexture,
224
250
  /** Mip-map level of the texture to copy to (Default 0) */
225
251
  destinationMipLevel = 0,
226
252
  /** Defines which aspects of the texture to copy to/from. */
@@ -232,7 +258,7 @@ function _copyTextureToTexture(device: WebGLDevice, options: CopyTextureToTextur
232
258
  destinationOrigin = [0, 0],
233
259
 
234
260
  /** Texture to copy to/from. */
235
- destination
261
+ destinationTexture
236
262
  /** Mip-map level of the texture to copy to/from. (Default 0) */
237
263
  // destinationMipLevel = options.mipLevel,
238
264
  /** Defines the origin of the copy - the minimum corner of the texture sub-region to copy to/from. */
@@ -242,12 +268,12 @@ function _copyTextureToTexture(device: WebGLDevice, options: CopyTextureToTextur
242
268
  } = options;
243
269
 
244
270
  let {
245
- width = options.destination.width,
246
- height = options.destination.height
271
+ width = options.destinationTexture.width,
272
+ height = options.destinationTexture.height
247
273
  // depthOrArrayLayers = 0
248
274
  } = options;
249
275
 
250
- const {framebuffer, destroyFramebuffer} = getFramebuffer(source);
276
+ const {framebuffer, destroyFramebuffer} = getFramebuffer(sourceTexture);
251
277
  const [sourceX, sourceY] = origin;
252
278
  const [destinationX, destinationY, destinationZ] = destinationOrigin;
253
279
 
@@ -261,8 +287,8 @@ function _copyTextureToTexture(device: WebGLDevice, options: CopyTextureToTextur
261
287
 
262
288
  let texture: WEBGLTexture = null;
263
289
  let textureTarget: GL;
264
- if (destination instanceof WEBGLTexture) {
265
- texture = destination;
290
+ if (destinationTexture instanceof WEBGLTexture) {
291
+ texture = destinationTexture;
266
292
  width = Number.isFinite(width) ? width : texture.width;
267
293
  height = Number.isFinite(height) ? height : texture.height;
268
294
  texture.bind(0);
@@ -311,7 +337,82 @@ function _copyTextureToTexture(device: WebGLDevice, options: CopyTextureToTextur
311
337
  }
312
338
  }
313
339
 
314
- // Returns number of components in a specific readPixels WebGL format
340
+ /** Clear one mip level of a texture *
341
+ function _clearTexture(device: WebGLDevice, options: ClearTextureOptions) {
342
+ const BORDER = 0;
343
+ const {dimension, width, height, depth = 0, mipLevel = 0} = options;
344
+ const {glInternalFormat, glFormat, glType, compressed} = options;
345
+ const glTarget = getWebGLCubeFaceTarget(options.glTarget, dimension, depth);
346
+
347
+ switch (dimension) {
348
+ case '2d-array':
349
+ case '3d':
350
+ if (compressed) {
351
+ // prettier-ignore
352
+ device.gl.compressedTexImage3D(glTarget, mipLevel, glInternalFormat, width, height, depth, BORDER, null);
353
+ } else {
354
+ // prettier-ignore
355
+ device.gl.texImage3D( glTarget, mipLevel, glInternalFormat, width, height, depth, BORDER, glFormat, glType, null);
356
+ }
357
+ break;
358
+
359
+ case '2d':
360
+ case 'cube':
361
+ if (compressed) {
362
+ // prettier-ignore
363
+ device.gl.compressedTexImage2D(glTarget, mipLevel, glInternalFormat, width, height, BORDER, null);
364
+ } else {
365
+ // prettier-ignore
366
+ device.gl.texImage2D(glTarget, mipLevel, glInternalFormat, width, height, BORDER, glFormat, glType, null);
367
+ }
368
+ break;
369
+
370
+ default:
371
+ throw new Error(dimension);
372
+ }
373
+ }
374
+ */
375
+
376
+ // function _readTexture(device: WebGLDevice, options: CopyTextureToBufferOptions) {}
377
+
378
+ // HELPERS
379
+
380
+ /**
381
+ * In WebGL, cube maps specify faces by overriding target instead of using the depth parameter.
382
+ * @note We still bind the texture using GL.TEXTURE_CUBE_MAP, but we need to use the face-specific target when setting mip levels.
383
+ * @returns glTarget unchanged, if dimension !== 'cube'.
384
+ */
385
+ export function getWebGLCubeFaceTarget(
386
+ glTarget: GLTextureTarget,
387
+ dimension: '1d' | '2d' | '2d-array' | 'cube' | 'cube-array' | '3d',
388
+ level: number
389
+ ): GLTextureTarget | GLTextureCubeMapTarget {
390
+ return dimension === 'cube' ? GL.TEXTURE_CUBE_MAP_POSITIVE_X + level : glTarget;
391
+ }
392
+
393
+ /** Wrap a texture in a framebuffer so that we can use WebGL APIs that work on framebuffers */
394
+ function getFramebuffer(source: Texture | Framebuffer): {
395
+ framebuffer: WEBGLFramebuffer;
396
+ destroyFramebuffer: boolean;
397
+ } {
398
+ if (source instanceof Texture) {
399
+ const {width, height, id} = source;
400
+ const framebuffer = source.device.createFramebuffer({
401
+ id: `framebuffer-for-${id}`,
402
+ width,
403
+ height,
404
+ colorAttachments: [source]
405
+ }) as unknown as WEBGLFramebuffer;
406
+
407
+ return {framebuffer, destroyFramebuffer: true};
408
+ }
409
+ return {framebuffer: source as unknown as WEBGLFramebuffer, destroyFramebuffer: false};
410
+ }
411
+
412
+ /**
413
+ * Returns number of components in a specific readPixels WebGL format
414
+ * @todo use shadertypes utils instead?
415
+ */
315
416
  export function glFormatToComponents(format): 1 | 2 | 3 | 4 {
316
417
  switch (format) {
317
418
  case GL.ALPHA:
@@ -333,7 +434,10 @@ export function glFormatToComponents(format): 1 | 2 | 3 | 4 {
333
434
  }
334
435
  }
335
436
 
336
- // Return byte count for given readPixels WebGL type
437
+ /**
438
+ * Return byte count for given readPixels WebGL type
439
+ * @todo use shadertypes utils instead?
440
+ */
337
441
  export function glTypeToBytes(type: GL): 1 | 2 | 4 {
338
442
  switch (type) {
339
443
  case GL.UNSIGNED_BYTE:
@@ -349,23 +453,3 @@ export function glTypeToBytes(type: GL): 1 | 2 | 4 {
349
453
  throw new Error('GLType');
350
454
  }
351
455
  }
352
-
353
- // Helper methods
354
-
355
- function getFramebuffer(source: Texture | Framebuffer): {
356
- framebuffer: WEBGLFramebuffer;
357
- destroyFramebuffer: boolean;
358
- } {
359
- if (source instanceof Texture) {
360
- const {width, height, id} = source;
361
- const framebuffer = source.device.createFramebuffer({
362
- id: `framebuffer-for-${id}`,
363
- width,
364
- height,
365
- colorAttachments: [source]
366
- }) as unknown as WEBGLFramebuffer;
367
-
368
- return {framebuffer, destroyFramebuffer: true};
369
- }
370
- return {framebuffer: source as unknown as WEBGLFramebuffer, destroyFramebuffer: false};
371
- }
@@ -8,6 +8,8 @@ import type {
8
8
  CopyBufferToTextureOptions,
9
9
  CopyTextureToBufferOptions,
10
10
  CopyTextureToTextureOptions,
11
+ // ClearTextureOptions,
12
+ // ReadTextureOptions,
11
13
  QuerySet,
12
14
  Buffer
13
15
  } from '@luma.gl/core';
@@ -52,6 +54,10 @@ export class WEBGLCommandEncoder extends CommandEncoder {
52
54
  this.commandBuffer.commands.push({name: 'copy-texture-to-texture', options});
53
55
  }
54
56
 
57
+ // clearTexture(options: ClearTextureOptions): void {
58
+ // this.commandBuffer.commands.push({name: 'copy-texture-to-texture', options});
59
+ // }
60
+
55
61
  override pushDebugGroup(groupLabel: string): void {}
56
62
  override popDebugGroup() {}
57
63
 
@@ -72,6 +72,20 @@ export class WEBGLExternalTexture extends WEBGLTexture {
72
72
  data.addEventListener('loadeddata', () => this.initialize(props));
73
73
  return this;
74
74
  }
75
+ }
76
+
77
+ initialize() {
78
+ // TODO - Video handling, move to ExternalTexture?
79
+ // if (isVideo) {
80
+ // this._video = {
81
+ // video: data,
82
+ // // TODO - should we be using the sampler parameters here?
83
+ // parameters: {},
84
+ // // @ts-expect-error HTMLVideoElement.HAVE_CURRENT_DATA is not declared
85
+ // lastTime: data.readyState >= HTMLVideoElement.HAVE_CURRENT_DATA ? data.currentTime : -1
86
+ // };
87
+ // }
88
+ }
75
89
 
76
90
  update(): this {
77
91
  if (this._video) {
@@ -77,8 +77,7 @@ export class WEBGLFramebuffer extends Framebuffer {
77
77
  }
78
78
 
79
79
  /** Check the status */
80
- // @ts-expect-error
81
- if (this.props.check !== false) {
80
+ if (this.device.props.debug) {
82
81
  const status = this.gl.checkFramebufferStatus(GL.FRAMEBUFFER) as GL;
83
82
  if (status !== GL.FRAMEBUFFER_COMPLETE) {
84
83
  throw new Error(`Framebuffer ${_getFrameBufferStatus(status)}`);