@luma.gl/webgl 9.1.0-alpha.14 → 9.1.0-alpha.16

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 (47) 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/helpers/webgl-texture-utils.d.ts +24 -22
  4. package/dist/adapter/helpers/webgl-texture-utils.d.ts.map +1 -1
  5. package/dist/adapter/helpers/webgl-texture-utils.js +6 -224
  6. package/dist/adapter/resources/webgl-command-buffer.js +15 -15
  7. package/dist/adapter/resources/webgl-framebuffer.d.ts +2 -3
  8. package/dist/adapter/resources/webgl-framebuffer.d.ts.map +1 -1
  9. package/dist/adapter/resources/webgl-framebuffer.js +10 -11
  10. package/dist/adapter/resources/webgl-render-pipeline.d.ts +1 -1
  11. package/dist/adapter/resources/webgl-render-pipeline.d.ts.map +1 -1
  12. package/dist/adapter/resources/webgl-render-pipeline.js +24 -11
  13. package/dist/adapter/resources/webgl-shader.d.ts +1 -0
  14. package/dist/adapter/resources/webgl-shader.d.ts.map +1 -1
  15. package/dist/adapter/resources/webgl-shader.js +6 -4
  16. package/dist/adapter/webgl-adapter.d.ts.map +1 -1
  17. package/dist/adapter/webgl-adapter.js +4 -10
  18. package/dist/adapter/webgl-device.d.ts +1 -2
  19. package/dist/adapter/webgl-device.d.ts.map +1 -1
  20. package/dist/adapter/webgl-device.js +33 -14
  21. package/dist/context/debug/spector-types.js +1 -1
  22. package/dist/context/debug/spector.d.ts +5 -5
  23. package/dist/context/debug/spector.d.ts.map +1 -1
  24. package/dist/context/debug/spector.js +6 -6
  25. package/dist/context/debug/webgl-developer-tools.d.ts +1 -3
  26. package/dist/context/debug/webgl-developer-tools.d.ts.map +1 -1
  27. package/dist/context/debug/webgl-developer-tools.js +4 -19
  28. package/dist/context/helpers/create-browser-context.d.ts +6 -22
  29. package/dist/context/helpers/create-browser-context.d.ts.map +1 -1
  30. package/dist/context/helpers/create-browser-context.js +26 -32
  31. package/dist/dist.dev.js +1762 -1749
  32. package/dist/dist.min.js +2 -2
  33. package/dist/index.cjs +1660 -1653
  34. package/dist/index.cjs.map +4 -4
  35. package/package.json +4 -4
  36. package/src/adapter/converters/device-parameters.ts +3 -3
  37. package/src/adapter/helpers/webgl-texture-utils.ts +33 -30
  38. package/src/adapter/resources/webgl-command-buffer.ts +16 -16
  39. package/src/adapter/resources/webgl-framebuffer.ts +12 -12
  40. package/src/adapter/resources/webgl-render-pipeline.ts +26 -11
  41. package/src/adapter/resources/webgl-shader.ts +7 -5
  42. package/src/adapter/webgl-adapter.ts +4 -12
  43. package/src/adapter/webgl-device.ts +67 -40
  44. package/src/context/debug/spector-types.ts +1 -1
  45. package/src/context/debug/spector.ts +11 -11
  46. package/src/context/debug/webgl-developer-tools.ts +5 -31
  47. package/src/context/helpers/create-browser-context.ts +39 -64
package/dist/index.cjs CHANGED
@@ -2,9 +2,9 @@ var __defProp = Object.defineProperty;
2
2
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
4
4
  var __hasOwnProp = Object.prototype.hasOwnProperty;
5
- var __export = (target, all) => {
5
+ var __export = (target2, all) => {
6
6
  for (var name in all)
7
- __defProp(target, name, { get: all[name], enumerable: true });
7
+ __defProp(target2, name, { get: all[name], enumerable: true });
8
8
  };
9
9
  var __copyProps = (to, from, except, desc) => {
10
10
  if (from && typeof from === "object" || typeof from === "function") {
@@ -137,8 +137,8 @@ var enable = (gl, value, key) => value ? gl.enable(key) : gl.disable(key);
137
137
  var hint = (gl, value, key) => gl.hint(key, value);
138
138
  var pixelStorei = (gl, value, key) => gl.pixelStorei(key, value);
139
139
  var bindFramebuffer = (gl, value, key) => {
140
- const target = key === 36006 ? 36009 : 36008;
141
- return gl.bindFramebuffer(target, value);
140
+ const target2 = key === 36006 ? 36009 : 36008;
141
+ return gl.bindFramebuffer(target2, value);
142
142
  };
143
143
  var bindBuffer = (gl, value, key) => {
144
144
  const bindingMap = {
@@ -340,17 +340,17 @@ var GL_HOOKED_SETTERS = {
340
340
  useProgram: (update, value) => update({
341
341
  [35725]: value
342
342
  }),
343
- bindRenderbuffer: (update, target, value) => update({
343
+ bindRenderbuffer: (update, target2, value) => update({
344
344
  [36007]: value
345
345
  }),
346
- bindTransformFeedback: (update, target, value) => update({
346
+ bindTransformFeedback: (update, target2, value) => update({
347
347
  [36389]: value
348
348
  }),
349
349
  bindVertexArray: (update, value) => update({
350
350
  [34229]: value
351
351
  }),
352
- bindFramebuffer: (update, target, framebuffer) => {
353
- switch (target) {
352
+ bindFramebuffer: (update, target2, framebuffer) => {
353
+ switch (target2) {
354
354
  case 36160:
355
355
  return update({
356
356
  [36006]: framebuffer,
@@ -364,14 +364,14 @@ var GL_HOOKED_SETTERS = {
364
364
  return null;
365
365
  }
366
366
  },
367
- bindBuffer: (update, target, buffer) => {
367
+ bindBuffer: (update, target2, buffer) => {
368
368
  const pname = {
369
369
  [34962]: [34964],
370
370
  [36662]: [36662],
371
371
  [36663]: [36663],
372
372
  [35051]: [35053],
373
373
  [35052]: [35055]
374
- }[target];
374
+ }[target2];
375
375
  if (pname) {
376
376
  return update({ [pname]: buffer });
377
377
  }
@@ -719,33 +719,27 @@ function installProgramSpy(gl) {
719
719
  }
720
720
 
721
721
  // dist/context/helpers/create-browser-context.js
722
- var DEFAULT_CONTEXT_PROPS = {
723
- powerPreference: "high-performance",
724
- // After all, most apps are using WebGL for performance reasons
725
- // eslint-disable-next-line no-console
726
- onContextLost: () => console.error("WebGL context lost"),
727
- // eslint-disable-next-line no-console
728
- onContextRestored: () => console.info("WebGL context restored")
729
- };
730
- function createBrowserContext(canvas, props) {
731
- props = { ...DEFAULT_CONTEXT_PROPS, ...props };
732
- let errorMessage = null;
733
- const onCreateError = (error) => errorMessage = error.statusMessage || errorMessage;
734
- canvas.addEventListener("webglcontextcreationerror", onCreateError, false);
722
+ function createBrowserContext(canvas, props, webglContextAttributes) {
723
+ const errorMessage = null;
724
+ const webglProps = {
725
+ preserveDrawingBuffer: true,
726
+ // failIfMajorPerformanceCaveat: true,
727
+ ...webglContextAttributes
728
+ };
735
729
  let gl = null;
736
- gl ||= canvas.getContext("webgl2", props);
737
- canvas.removeEventListener("webglcontextcreationerror", onCreateError, false);
730
+ gl ||= canvas.getContext("webgl2", webglProps);
731
+ if (!gl && !webglContextAttributes.failIfMajorPerformanceCaveat) {
732
+ webglProps.failIfMajorPerformanceCaveat = false;
733
+ gl = canvas.getContext("webgl", webglProps);
734
+ gl.luma ||= {};
735
+ gl.luma.softwareRenderer = true;
736
+ }
738
737
  if (!gl) {
739
738
  throw new Error(`Failed to create WebGL context: ${errorMessage || "Unknown error"}`);
740
739
  }
741
- if (props.onContextLost) {
742
- const { onContextLost } = props;
743
- canvas.addEventListener("webglcontextlost", (event) => onContextLost(event), false);
744
- }
745
- if (props.onContextRestored) {
746
- const { onContextRestored } = props;
747
- canvas.addEventListener("webglcontextrestored", (event) => onContextRestored(event), false);
748
- }
740
+ const { onContextLost, onContextRestored } = props;
741
+ canvas.addEventListener("webglcontextlost", (event) => onContextLost(event), false);
742
+ canvas.addEventListener("webglcontextrestored", (event) => onContextRestored(event), false);
749
743
  return gl;
750
744
  }
751
745
 
@@ -1406,1755 +1400,1743 @@ var WebGLDeviceLimits = class extends import_core3.DeviceLimits {
1406
1400
  };
1407
1401
 
1408
1402
  // dist/adapter/webgl-canvas-context.js
1409
- var import_core10 = require("@luma.gl/core");
1403
+ var import_core5 = require("@luma.gl/core");
1410
1404
 
1411
1405
  // dist/adapter/resources/webgl-framebuffer.js
1412
- var import_core9 = require("@luma.gl/core");
1413
- var import_constants13 = require("@luma.gl/constants");
1414
-
1415
- // dist/adapter/resources/webgl-texture.js
1416
- var import_core8 = require("@luma.gl/core");
1417
- var import_constants12 = require("@luma.gl/constants");
1418
-
1419
- // dist/context/state-tracker/with-parameters.js
1420
- function withGLParameters(gl, parameters, func) {
1421
- if (isObjectEmpty2(parameters)) {
1422
- return func(gl);
1423
- }
1424
- const { nocatch = true } = parameters;
1425
- const webglState = WebGLStateTracker.get(gl);
1426
- webglState.push();
1427
- setGLParameters(gl, parameters);
1428
- let value;
1429
- if (nocatch) {
1430
- value = func(gl);
1431
- webglState.pop();
1432
- } else {
1433
- try {
1434
- value = func(gl);
1435
- } finally {
1436
- webglState.pop();
1437
- }
1438
- }
1439
- return value;
1440
- }
1441
- function isObjectEmpty2(object) {
1442
- for (const key in object) {
1443
- return false;
1444
- }
1445
- return true;
1446
- }
1447
-
1448
- // dist/adapter/converters/sampler-parameters.js
1449
- var import_constants7 = require("@luma.gl/constants");
1450
-
1451
- // dist/adapter/converters/device-parameters.js
1452
1406
  var import_core4 = require("@luma.gl/core");
1453
1407
  var import_constants6 = require("@luma.gl/constants");
1454
- function withDeviceAndGLParameters(device, parameters, glParameters, func) {
1455
- if (isObjectEmpty3(parameters)) {
1456
- return func(device);
1457
- }
1458
- const webglDevice = device;
1459
- webglDevice.pushState();
1460
- try {
1461
- setDeviceParameters(device, parameters);
1462
- setGLParameters(webglDevice.gl, glParameters);
1463
- return func(device);
1464
- } finally {
1465
- webglDevice.popState();
1408
+ var WEBGLFramebuffer = class extends import_core4.Framebuffer {
1409
+ device;
1410
+ gl;
1411
+ handle;
1412
+ colorAttachments = [];
1413
+ depthStencilAttachment = null;
1414
+ constructor(device, props) {
1415
+ super(device, props);
1416
+ const isDefaultFramebuffer = props.handle === null;
1417
+ this.device = device;
1418
+ this.gl = device.gl;
1419
+ this.handle = this.props.handle || isDefaultFramebuffer ? this.props.handle : this.gl.createFramebuffer();
1420
+ if (!isDefaultFramebuffer) {
1421
+ device.setSpectorMetadata(this.handle, { id: this.props.id, props: this.props });
1422
+ this.autoCreateAttachmentTextures();
1423
+ this.updateAttachments();
1424
+ }
1466
1425
  }
1467
- }
1468
- function withDeviceParameters(device, parameters, func) {
1469
- if (isObjectEmpty3(parameters)) {
1470
- return func(device);
1426
+ /** destroys any auto created resources etc. */
1427
+ destroy() {
1428
+ super.destroy();
1429
+ if (!this.destroyed && this.handle !== null) {
1430
+ this.gl.deleteFramebuffer(this.handle);
1431
+ }
1471
1432
  }
1472
- const webglDevice = device;
1473
- webglDevice.pushState();
1474
- try {
1475
- setDeviceParameters(device, parameters);
1476
- return func(device);
1477
- } finally {
1478
- webglDevice.popState();
1433
+ updateAttachments() {
1434
+ const prevHandle = this.gl.bindFramebuffer(36160, this.handle);
1435
+ for (let i = 0; i < this.colorAttachments.length; ++i) {
1436
+ const attachment = this.colorAttachments[i];
1437
+ if (attachment) {
1438
+ const attachmentPoint = 36064 + i;
1439
+ this._attachTextureView(attachmentPoint, attachment);
1440
+ }
1441
+ }
1442
+ if (this.depthStencilAttachment) {
1443
+ const attachmentPoint = getDepthStencilAttachmentWebGL(this.depthStencilAttachment.props.format);
1444
+ this._attachTextureView(attachmentPoint, this.depthStencilAttachment);
1445
+ }
1446
+ if (this.props.check !== false) {
1447
+ const status = this.gl.checkFramebufferStatus(36160);
1448
+ if (status !== 36053) {
1449
+ throw new Error(`Framebuffer ${_getFrameBufferStatus(status)}`);
1450
+ }
1451
+ }
1452
+ this.gl.bindFramebuffer(36160, prevHandle);
1479
1453
  }
1480
- }
1481
- function setDeviceParameters(device, parameters) {
1482
- const webglDevice = device;
1483
- const { gl } = webglDevice;
1484
- if (parameters.cullMode) {
1485
- switch (parameters.cullMode) {
1486
- case "none":
1487
- gl.disable(2884);
1454
+ // PRIVATE
1455
+ /** In WebGL we must use renderbuffers for depth/stencil attachments (unless we have extensions) */
1456
+ // protected override createDepthStencilTexture(format: TextureFormat): Texture {
1457
+ // // return new WEBGLRenderbuffer(this.device, {
1458
+ // return new WEBGLTexture(this.device, {
1459
+ // id: `${this.id}-depth-stencil`,
1460
+ // format,
1461
+ // width: this.width,
1462
+ // height: this.height,
1463
+ // mipmaps: false
1464
+ // });
1465
+ // }
1466
+ /**
1467
+ * @param attachment
1468
+ * @param texture
1469
+ * @param layer = 0 - index into WEBGLTextureArray and Texture3D or face for `TextureCubeMap`
1470
+ * @param level = 0 - mipmapLevel
1471
+ */
1472
+ _attachTextureView(attachment, textureView) {
1473
+ const { gl } = this.device;
1474
+ const { texture } = textureView;
1475
+ const level = textureView.props.baseMipLevel;
1476
+ const layer = textureView.props.baseArrayLayer;
1477
+ gl.bindTexture(texture.glTarget, texture.handle);
1478
+ switch (texture.glTarget) {
1479
+ case 35866:
1480
+ case 32879:
1481
+ gl.framebufferTextureLayer(36160, attachment, texture.handle, level, layer);
1488
1482
  break;
1489
- case "front":
1490
- gl.enable(2884);
1491
- gl.cullFace(1028);
1483
+ case 34067:
1484
+ const face = mapIndexToCubeMapFace(layer);
1485
+ gl.framebufferTexture2D(36160, attachment, face, texture.handle, level);
1492
1486
  break;
1493
- case "back":
1494
- gl.enable(2884);
1495
- gl.cullFace(1029);
1487
+ case 3553:
1488
+ gl.framebufferTexture2D(36160, attachment, 3553, texture.handle, level);
1496
1489
  break;
1490
+ default:
1491
+ throw new Error("Illegal texture type");
1497
1492
  }
1493
+ gl.bindTexture(texture.glTarget, null);
1498
1494
  }
1499
- if (parameters.frontFace) {
1500
- gl.frontFace(map("frontFace", parameters.frontFace, {
1501
- ccw: 2305,
1502
- cw: 2304
1503
- }));
1495
+ };
1496
+ function mapIndexToCubeMapFace(layer) {
1497
+ return layer < 34069 ? layer + 34069 : layer;
1498
+ }
1499
+ function _getFrameBufferStatus(status) {
1500
+ switch (status) {
1501
+ case 36053:
1502
+ return "success";
1503
+ case 36054:
1504
+ return "Mismatched attachments";
1505
+ case 36055:
1506
+ return "No attachments";
1507
+ case 36057:
1508
+ return "Height/width mismatch";
1509
+ case 36061:
1510
+ return "Unsupported or split attachments";
1511
+ case 36182:
1512
+ return "Samples mismatch";
1513
+ default:
1514
+ return `${status}`;
1504
1515
  }
1505
- if (parameters.unclippedDepth) {
1506
- if (device.features.has("depth-clip-control")) {
1507
- gl.enable(34383);
1508
- }
1516
+ }
1517
+
1518
+ // dist/adapter/webgl-canvas-context.js
1519
+ var WebGLCanvasContext = class extends import_core5.CanvasContext {
1520
+ device;
1521
+ format = "rgba8unorm";
1522
+ depthStencilFormat = "depth24plus";
1523
+ presentationSize;
1524
+ _framebuffer = null;
1525
+ constructor(device, props) {
1526
+ super(props);
1527
+ this.device = device;
1528
+ this.presentationSize = [-1, -1];
1529
+ this._setAutoCreatedCanvasId(`${this.device.id}-canvas`);
1530
+ this.update();
1509
1531
  }
1510
- if (parameters.depthBias !== void 0) {
1511
- gl.enable(32823);
1512
- gl.polygonOffset(parameters.depthBias, parameters.depthBiasSlopeScale || 0);
1532
+ getCurrentFramebuffer() {
1533
+ this.update();
1534
+ this._framebuffer = this._framebuffer || new WEBGLFramebuffer(this.device, { handle: null });
1535
+ return this._framebuffer;
1513
1536
  }
1514
- if (parameters.provokingVertex) {
1515
- if (device.features.has("provoking-vertex-webgl")) {
1516
- const extensions = webglDevice.getExtension("WEBGL_provoking_vertex");
1517
- const ext = extensions.WEBGL_provoking_vertex;
1518
- const vertex = map("provokingVertex", parameters.provokingVertex, {
1519
- first: 36429,
1520
- last: 36430
1521
- });
1522
- ext == null ? void 0 : ext.provokingVertexWEBGL(vertex);
1537
+ /** Resizes and updates render targets if necessary */
1538
+ update() {
1539
+ const size = this.getPixelSize();
1540
+ const sizeChanged = size[0] !== this.presentationSize[0] || size[1] !== this.presentationSize[1];
1541
+ if (sizeChanged) {
1542
+ this.presentationSize = size;
1543
+ this.resize();
1523
1544
  }
1524
1545
  }
1525
- if (parameters.polygonMode || parameters.polygonOffsetLine) {
1526
- if (device.features.has("polygon-mode-webgl")) {
1527
- if (parameters.polygonMode) {
1528
- const extensions = webglDevice.getExtension("WEBGL_polygon_mode");
1529
- const ext = extensions.WEBGL_polygon_mode;
1530
- const mode = map("polygonMode", parameters.polygonMode, {
1531
- fill: 6914,
1532
- line: 6913
1533
- });
1534
- ext == null ? void 0 : ext.polygonModeWEBGL(1028, mode);
1535
- ext == null ? void 0 : ext.polygonModeWEBGL(1029, mode);
1536
- }
1537
- if (parameters.polygonOffsetLine) {
1538
- gl.enable(10754);
1539
- }
1546
+ /**
1547
+ * Resize the canvas' drawing buffer.
1548
+ *
1549
+ * Can match the canvas CSS size, and optionally also consider devicePixelRatio
1550
+ * Can be called every frame
1551
+ *
1552
+ * Regardless of size, the drawing buffer will always be scaled to the viewport, but
1553
+ * for best visual results, usually set to either:
1554
+ * canvas CSS width x canvas CSS height
1555
+ * canvas CSS width * devicePixelRatio x canvas CSS height * devicePixelRatio
1556
+ * See http://webgl2fundamentals.org/webgl/lessons/webgl-resizing-the-canvas.html
1557
+ */
1558
+ resize(options) {
1559
+ if (!this.device.gl)
1560
+ return;
1561
+ if (this.canvas) {
1562
+ const devicePixelRatio = this.getDevicePixelRatio(options == null ? void 0 : options.useDevicePixels);
1563
+ this.setDevicePixelRatio(devicePixelRatio, options);
1564
+ return;
1540
1565
  }
1541
1566
  }
1542
- if (device.features.has("shader-clip-cull-distance-webgl")) {
1543
- if (parameters.clipDistance0) {
1544
- gl.enable(12288);
1545
- }
1546
- if (parameters.clipDistance1) {
1547
- gl.enable(12289);
1548
- }
1549
- if (parameters.clipDistance2) {
1550
- gl.enable(12290);
1551
- }
1552
- if (parameters.clipDistance3) {
1553
- gl.enable(12291);
1554
- }
1555
- if (parameters.clipDistance4) {
1556
- gl.enable(12292);
1557
- }
1558
- if (parameters.clipDistance5) {
1559
- gl.enable(12293);
1560
- }
1561
- if (parameters.clipDistance6) {
1562
- gl.enable(12294);
1563
- }
1564
- if (parameters.clipDistance7) {
1565
- gl.enable(12295);
1566
- }
1567
+ commit() {
1567
1568
  }
1568
- if (parameters.depthWriteEnabled !== void 0) {
1569
- gl.depthMask(mapBoolean("depthWriteEnabled", parameters.depthWriteEnabled));
1569
+ };
1570
+
1571
+ // dist/context/debug/spector.js
1572
+ var import_core6 = require("@luma.gl/core");
1573
+
1574
+ // dist/utils/load-script.js
1575
+ async function loadScript(scriptUrl, scriptId) {
1576
+ const head = document.getElementsByTagName("head")[0];
1577
+ if (!head) {
1578
+ throw new Error("loadScript");
1570
1579
  }
1571
- if (parameters.depthCompare) {
1572
- parameters.depthCompare !== "always" ? gl.enable(2929) : gl.disable(2929);
1573
- gl.depthFunc(convertCompareFunction("depthCompare", parameters.depthCompare));
1580
+ const script = document.createElement("script");
1581
+ script.setAttribute("type", "text/javascript");
1582
+ script.setAttribute("src", scriptUrl);
1583
+ if (scriptId) {
1584
+ script.id = scriptId;
1574
1585
  }
1575
- if (parameters.stencilWriteMask) {
1576
- const mask = parameters.stencilWriteMask;
1577
- gl.stencilMaskSeparate(1028, mask);
1578
- gl.stencilMaskSeparate(1029, mask);
1586
+ return new Promise((resolve, reject) => {
1587
+ script.onload = resolve;
1588
+ script.onerror = (error) => reject(new Error(`Unable to load script '${scriptUrl}': ${error}`));
1589
+ head.appendChild(script);
1590
+ });
1591
+ }
1592
+
1593
+ // dist/context/debug/spector.js
1594
+ var LOG_LEVEL = 1;
1595
+ var spector = null;
1596
+ var initialized = false;
1597
+ var DEFAULT_SPECTOR_PROPS = {
1598
+ debugSpectorJS: import_core6.log.get("debug-spectorjs"),
1599
+ // https://github.com/BabylonJS/Spector.js#basic-usage
1600
+ // https://forum.babylonjs.com/t/spectorcdn-is-temporarily-off/48241
1601
+ // spectorUrl: 'https://spectorcdn.babylonjs.com/spector.bundle.js';
1602
+ debugSpectorJSUrl: "https://cdn.jsdelivr.net/npm/spectorjs@0.9.30/dist/spector.bundle.js",
1603
+ gl: void 0
1604
+ };
1605
+ async function loadSpectorJS(props) {
1606
+ if (!globalThis.SPECTOR) {
1607
+ try {
1608
+ await loadScript(props.debugSpectorJSUrl || DEFAULT_SPECTOR_PROPS.debugSpectorJSUrl);
1609
+ } catch (error) {
1610
+ import_core6.log.warn(String(error));
1611
+ }
1579
1612
  }
1580
- if (parameters.stencilReadMask) {
1581
- import_core4.log.warn("stencilReadMask not supported under WebGL");
1613
+ }
1614
+ function initializeSpectorJS(props) {
1615
+ var _a;
1616
+ props = { ...DEFAULT_SPECTOR_PROPS, ...props };
1617
+ if (!props.debugSpectorJS) {
1618
+ return null;
1582
1619
  }
1583
- if (parameters.stencilCompare) {
1584
- const mask = parameters.stencilReadMask || 4294967295;
1585
- const glValue = convertCompareFunction("depthCompare", parameters.stencilCompare);
1586
- parameters.stencilCompare !== "always" ? gl.enable(2960) : gl.disable(2960);
1587
- gl.stencilFuncSeparate(1028, glValue, 0, mask);
1588
- gl.stencilFuncSeparate(1029, glValue, 0, mask);
1620
+ if (!spector && globalThis.SPECTOR && !((_a = globalThis.luma) == null ? void 0 : _a.spector)) {
1621
+ import_core6.log.probe(LOG_LEVEL, "SPECTOR found and initialized. Start with `luma.spector.displayUI()`")();
1622
+ const { Spector: SpectorJS } = globalThis.SPECTOR;
1623
+ spector = new SpectorJS();
1624
+ if (globalThis.luma) {
1625
+ globalThis.luma.spector = spector;
1626
+ }
1589
1627
  }
1590
- if (parameters.stencilPassOperation && parameters.stencilFailOperation && parameters.stencilDepthFailOperation) {
1591
- const dppass = convertStencilOperation("stencilPassOperation", parameters.stencilPassOperation);
1592
- const sfail = convertStencilOperation("stencilFailOperation", parameters.stencilFailOperation);
1593
- const dpfail = convertStencilOperation("stencilDepthFailOperation", parameters.stencilDepthFailOperation);
1594
- gl.stencilOpSeparate(1028, sfail, dpfail, dppass);
1595
- gl.stencilOpSeparate(1029, sfail, dpfail, dppass);
1628
+ if (!spector) {
1629
+ return null;
1596
1630
  }
1597
- switch (parameters.blend) {
1598
- case true:
1599
- gl.enable(3042);
1600
- break;
1601
- case false:
1602
- gl.disable(3042);
1603
- break;
1604
- default:
1631
+ if (!initialized) {
1632
+ initialized = true;
1633
+ spector.spyCanvases();
1634
+ spector == null ? void 0 : spector.onCaptureStarted.add((capture) => import_core6.log.info("Spector capture started:", capture)());
1635
+ spector == null ? void 0 : spector.onCapture.add((capture) => {
1636
+ import_core6.log.info("Spector capture complete:", capture)();
1637
+ spector == null ? void 0 : spector.getResultUI();
1638
+ spector == null ? void 0 : spector.resultView.display();
1639
+ spector == null ? void 0 : spector.resultView.addCapture(capture);
1640
+ });
1605
1641
  }
1606
- if (parameters.blendColorOperation || parameters.blendAlphaOperation) {
1607
- const colorEquation = convertBlendOperationToEquation("blendColorOperation", parameters.blendColorOperation || "add");
1608
- const alphaEquation = convertBlendOperationToEquation("blendAlphaOperation", parameters.blendAlphaOperation || "add");
1609
- gl.blendEquationSeparate(colorEquation, alphaEquation);
1610
- const colorSrcFactor = convertBlendFactorToFunction("blendColorSrcFactor", parameters.blendColorSrcFactor || "one");
1611
- const colorDstFactor = convertBlendFactorToFunction("blendColorDstFactor", parameters.blendColorDstFactor || "zero");
1612
- const alphaSrcFactor = convertBlendFactorToFunction("blendAlphaSrcFactor", parameters.blendAlphaSrcFactor || "one");
1613
- const alphaDstFactor = convertBlendFactorToFunction("blendAlphaDstFactor", parameters.blendAlphaDstFactor || "zero");
1614
- gl.blendFuncSeparate(colorSrcFactor, colorDstFactor, alphaSrcFactor, alphaDstFactor);
1642
+ if (props.gl) {
1643
+ const gl = props.gl;
1644
+ const device = gl.device;
1645
+ spector == null ? void 0 : spector.startCapture(props.gl, 500);
1646
+ gl.device = device;
1647
+ new Promise((resolve) => setTimeout(resolve, 2e3)).then((_) => {
1648
+ import_core6.log.info("Spector capture stopped after 2 seconds")();
1649
+ spector == null ? void 0 : spector.stopCapture();
1650
+ });
1615
1651
  }
1652
+ return spector;
1616
1653
  }
1617
- function convertCompareFunction(parameter, value) {
1618
- return map(parameter, value, {
1619
- never: 512,
1620
- less: 513,
1621
- equal: 514,
1622
- "less-equal": 515,
1623
- greater: 516,
1624
- "not-equal": 517,
1625
- "greater-equal": 518,
1626
- always: 519
1627
- });
1628
- }
1629
- function convertStencilOperation(parameter, value) {
1630
- return map(parameter, value, {
1631
- keep: 7680,
1632
- zero: 0,
1633
- replace: 7681,
1634
- invert: 5386,
1635
- "increment-clamp": 7682,
1636
- "decrement-clamp": 7683,
1637
- "increment-wrap": 34055,
1638
- "decrement-wrap": 34056
1639
- });
1654
+
1655
+ // dist/context/debug/webgl-developer-tools.js
1656
+ var import_core7 = require("@luma.gl/core");
1657
+ var import_constants7 = require("@luma.gl/constants");
1658
+ var import_env = require("@probe.gl/env");
1659
+ var WEBGL_DEBUG_CDN_URL = "https://unpkg.com/webgl-debug@2.0.1/index.js";
1660
+ function getWebGLContextData(gl) {
1661
+ gl.luma = gl.luma || {};
1662
+ return gl.luma;
1640
1663
  }
1641
- function convertBlendOperationToEquation(parameter, value) {
1642
- return map(parameter, value, {
1643
- add: 32774,
1644
- subtract: 32778,
1645
- "reverse-subtract": 32779,
1646
- min: 32775,
1647
- max: 32776
1648
- });
1664
+ async function loadWebGLDeveloperTools() {
1665
+ if ((0, import_env.isBrowser)() && !globalThis.WebGLDebugUtils) {
1666
+ globalThis.global = globalThis.global || globalThis;
1667
+ globalThis.global.module = {};
1668
+ await loadScript(WEBGL_DEBUG_CDN_URL);
1669
+ }
1649
1670
  }
1650
- function convertBlendFactorToFunction(parameter, value) {
1651
- return map(parameter, value, {
1652
- one: 1,
1653
- zero: 0,
1654
- "src-color": 768,
1655
- "one-minus-src-color": 769,
1656
- "dst-color": 774,
1657
- "one-minus-dst-color": 775,
1658
- "src-alpha": 770,
1659
- "one-minus-src-alpha": 771,
1660
- "dst-alpha": 772,
1661
- "one-minus-dst-alpha": 773,
1662
- "src-alpha-saturated": 776,
1663
- "constant-color": 32769,
1664
- "one-minus-constant-color": 32770,
1665
- "constant-alpha": 32771,
1666
- "one-minus-constant-alpha": 32772
1667
- });
1671
+ function makeDebugContext(gl, props = {}) {
1672
+ return props.debugWebGL ? getDebugContext(gl, props) : getRealContext(gl);
1668
1673
  }
1669
- function message(parameter, value) {
1670
- return `Illegal parameter ${value} for ${parameter}`;
1674
+ function getRealContext(gl) {
1675
+ const data = getWebGLContextData(gl);
1676
+ return data.realContext ? data.realContext : gl;
1671
1677
  }
1672
- function map(parameter, value, valueMap) {
1673
- if (!(value in valueMap)) {
1674
- throw new Error(message(parameter, value));
1678
+ function getDebugContext(gl, props) {
1679
+ if (!globalThis.WebGLDebugUtils) {
1680
+ import_core7.log.warn("webgl-debug not loaded")();
1681
+ return gl;
1675
1682
  }
1676
- return valueMap[value];
1683
+ const data = getWebGLContextData(gl);
1684
+ if (data.debugContext) {
1685
+ return data.debugContext;
1686
+ }
1687
+ globalThis.WebGLDebugUtils.init({ ...import_constants7.GL, ...gl });
1688
+ const glDebug = globalThis.WebGLDebugUtils.makeDebugContext(gl, onGLError.bind(null, props), onValidateGLFunc.bind(null, props));
1689
+ for (const key in import_constants7.GL) {
1690
+ if (!(key in glDebug) && typeof import_constants7.GL[key] === "number") {
1691
+ glDebug[key] = import_constants7.GL[key];
1692
+ }
1693
+ }
1694
+ class WebGLDebugContext {
1695
+ }
1696
+ Object.setPrototypeOf(glDebug, Object.getPrototypeOf(gl));
1697
+ Object.setPrototypeOf(WebGLDebugContext, glDebug);
1698
+ const debugContext = Object.create(WebGLDebugContext);
1699
+ data.realContext = gl;
1700
+ data.debugContext = debugContext;
1701
+ debugContext.debug = true;
1702
+ return debugContext;
1677
1703
  }
1678
- function mapBoolean(parameter, value) {
1679
- return value;
1704
+ function getFunctionString(functionName, functionArgs) {
1705
+ functionArgs = Array.from(functionArgs).map((arg) => arg === void 0 ? "undefined" : arg);
1706
+ let args = globalThis.WebGLDebugUtils.glFunctionArgsToString(functionName, functionArgs);
1707
+ args = `${args.slice(0, 100)}${args.length > 100 ? "..." : ""}`;
1708
+ return `gl.${functionName}(${args})`;
1680
1709
  }
1681
- function isObjectEmpty3(obj) {
1682
- let isEmpty = true;
1683
- for (const key in obj) {
1684
- isEmpty = false;
1685
- break;
1686
- }
1687
- return isEmpty;
1710
+ function onGLError(props, err, functionName, args) {
1711
+ args = Array.from(args).map((arg) => arg === void 0 ? "undefined" : arg);
1712
+ const errorMessage = globalThis.WebGLDebugUtils.glEnumToString(err);
1713
+ const functionArgs = globalThis.WebGLDebugUtils.glFunctionArgsToString(functionName, args);
1714
+ const message2 = `${errorMessage} in gl.${functionName}(${functionArgs})`;
1715
+ import_core7.log.error(message2)();
1716
+ debugger;
1688
1717
  }
1689
-
1690
- // dist/adapter/converters/sampler-parameters.js
1691
- function convertSamplerParametersToWebGL(props) {
1692
- const params = {};
1693
- if (props.addressModeU) {
1694
- params[10242] = convertAddressMode(props.addressModeU);
1718
+ function onValidateGLFunc(props, functionName, functionArgs) {
1719
+ let functionString = "";
1720
+ if (import_core7.log.level >= 1) {
1721
+ functionString = getFunctionString(functionName, functionArgs);
1722
+ import_core7.log.log(1, functionString)();
1695
1723
  }
1696
- if (props.addressModeV) {
1697
- params[10243] = convertAddressMode(props.addressModeV);
1724
+ for (const arg of functionArgs) {
1725
+ if (arg === void 0) {
1726
+ functionString = functionString || getFunctionString(functionName, functionArgs);
1727
+ debugger;
1728
+ }
1698
1729
  }
1699
- if (props.addressModeW) {
1700
- params[32882] = convertAddressMode(props.addressModeW);
1730
+ }
1731
+
1732
+ // dist/utils/uid.js
1733
+ var uidCounters = {};
1734
+ function uid(id = "id") {
1735
+ uidCounters[id] = uidCounters[id] || 1;
1736
+ const count = uidCounters[id]++;
1737
+ return `${id}-${count}`;
1738
+ }
1739
+
1740
+ // dist/adapter/resources/webgl-buffer.js
1741
+ var import_core8 = require("@luma.gl/core");
1742
+ var import_constants8 = require("@luma.gl/constants");
1743
+ var WEBGLBuffer = class extends import_core8.Buffer {
1744
+ device;
1745
+ gl;
1746
+ handle;
1747
+ /** Target in OpenGL defines the type of buffer */
1748
+ glTarget;
1749
+ /** Usage is a hint on how frequently the buffer will be updates */
1750
+ glUsage;
1751
+ /** Index type is needed when issuing draw calls, so we pre-compute it */
1752
+ glIndexType = 5123;
1753
+ /** Number of bytes allocated on the GPU for this buffer */
1754
+ byteLength;
1755
+ /** Number of bytes used */
1756
+ bytesUsed;
1757
+ constructor(device, props = {}) {
1758
+ super(device, props);
1759
+ this.device = device;
1760
+ this.gl = this.device.gl;
1761
+ const handle = typeof props === "object" ? props.handle : void 0;
1762
+ this.handle = handle || this.gl.createBuffer();
1763
+ device.setSpectorMetadata(this.handle, { ...this.props, data: typeof this.props.data });
1764
+ this.glTarget = getWebGLTarget(this.props.usage);
1765
+ this.glUsage = getWebGLUsage(this.props.usage);
1766
+ this.glIndexType = this.props.indexType === "uint32" ? 5125 : 5123;
1767
+ if (props.data) {
1768
+ this._initWithData(props.data, props.byteOffset, props.byteLength);
1769
+ } else {
1770
+ this._initWithByteLength(props.byteLength || 0);
1771
+ }
1701
1772
  }
1702
- if (props.magFilter) {
1703
- params[10240] = convertMaxFilterMode(props.magFilter);
1773
+ // PRIVATE METHODS
1774
+ /** Allocate a new buffer and initialize to contents of typed array */
1775
+ _initWithData(data, byteOffset = 0, byteLength = data.byteLength + byteOffset) {
1776
+ const glTarget = this.glTarget;
1777
+ this.gl.bindBuffer(glTarget, this.handle);
1778
+ this.gl.bufferData(glTarget, byteLength, this.glUsage);
1779
+ this.gl.bufferSubData(glTarget, byteOffset, data);
1780
+ this.gl.bindBuffer(glTarget, null);
1781
+ this.bytesUsed = byteLength;
1782
+ this.byteLength = byteLength;
1783
+ this._setDebugData(data, byteOffset, byteLength);
1784
+ this.trackAllocatedMemory(byteLength);
1704
1785
  }
1705
- if (props.minFilter || props.mipmapFilter) {
1706
- params[10241] = convertMinFilterMode(props.minFilter || "linear", props.mipmapFilter);
1786
+ // Allocate a GPU buffer of specified size.
1787
+ _initWithByteLength(byteLength) {
1788
+ let data = byteLength;
1789
+ if (byteLength === 0) {
1790
+ data = new Float32Array(0);
1791
+ }
1792
+ const glTarget = this.glTarget;
1793
+ this.gl.bindBuffer(glTarget, this.handle);
1794
+ this.gl.bufferData(glTarget, data, this.glUsage);
1795
+ this.gl.bindBuffer(glTarget, null);
1796
+ this.bytesUsed = byteLength;
1797
+ this.byteLength = byteLength;
1798
+ this._setDebugData(null, 0, byteLength);
1799
+ this.trackAllocatedMemory(byteLength);
1800
+ return this;
1707
1801
  }
1708
- if (props.lodMinClamp !== void 0) {
1709
- params[33082] = props.lodMinClamp;
1802
+ destroy() {
1803
+ if (!this.destroyed && this.handle) {
1804
+ this.removeStats();
1805
+ this.trackDeallocatedMemory();
1806
+ this.gl.deleteBuffer(this.handle);
1807
+ this.destroyed = true;
1808
+ this.handle = null;
1809
+ }
1710
1810
  }
1711
- if (props.lodMaxClamp !== void 0) {
1712
- params[33083] = props.lodMaxClamp;
1811
+ write(data, byteOffset = 0) {
1812
+ const srcOffset = 0;
1813
+ const byteLength = void 0;
1814
+ const glTarget = 36663;
1815
+ this.gl.bindBuffer(glTarget, this.handle);
1816
+ if (srcOffset !== 0 || byteLength !== void 0) {
1817
+ this.gl.bufferSubData(glTarget, byteOffset, data, srcOffset, byteLength);
1818
+ } else {
1819
+ this.gl.bufferSubData(glTarget, byteOffset, data);
1820
+ }
1821
+ this.gl.bindBuffer(glTarget, null);
1822
+ this._setDebugData(data, byteOffset, data.byteLength);
1713
1823
  }
1714
- if (props.type === "comparison-sampler") {
1715
- params[34892] = 34894;
1824
+ /** Asynchronously read data from the buffer */
1825
+ async readAsync(byteOffset = 0, byteLength) {
1826
+ return this.readSyncWebGL(byteOffset, byteLength);
1716
1827
  }
1717
- if (props.compare) {
1718
- params[34893] = convertCompareFunction("compare", props.compare);
1828
+ /** Synchronously read data from the buffer. WebGL only. */
1829
+ readSyncWebGL(byteOffset = 0, byteLength) {
1830
+ byteLength = byteLength ?? this.byteLength - byteOffset;
1831
+ const data = new Uint8Array(byteLength);
1832
+ const dstOffset = 0;
1833
+ this.gl.bindBuffer(36662, this.handle);
1834
+ this.gl.getBufferSubData(36662, byteOffset, data, dstOffset, byteLength);
1835
+ this.gl.bindBuffer(36662, null);
1836
+ this._setDebugData(data, byteOffset, byteLength);
1837
+ return data;
1719
1838
  }
1720
- if (props.maxAnisotropy) {
1721
- params[34046] = props.maxAnisotropy;
1839
+ };
1840
+ function getWebGLTarget(usage) {
1841
+ if (usage & import_core8.Buffer.INDEX) {
1842
+ return 34963;
1722
1843
  }
1723
- return params;
1724
- }
1725
- function convertAddressMode(addressMode) {
1726
- switch (addressMode) {
1727
- case "clamp-to-edge":
1728
- return 33071;
1729
- case "repeat":
1730
- return 10497;
1731
- case "mirror-repeat":
1732
- return 33648;
1844
+ if (usage & import_core8.Buffer.VERTEX) {
1845
+ return 34962;
1733
1846
  }
1734
- }
1735
- function convertMaxFilterMode(maxFilter) {
1736
- switch (maxFilter) {
1737
- case "nearest":
1738
- return 9728;
1739
- case "linear":
1740
- return 9729;
1847
+ if (usage & import_core8.Buffer.UNIFORM) {
1848
+ return 35345;
1741
1849
  }
1850
+ return 34962;
1742
1851
  }
1743
- function convertMinFilterMode(minFilter, mipmapFilter) {
1744
- if (!mipmapFilter) {
1745
- return convertMaxFilterMode(minFilter);
1852
+ function getWebGLUsage(usage) {
1853
+ if (usage & import_core8.Buffer.INDEX) {
1854
+ return 35044;
1746
1855
  }
1747
- switch (minFilter) {
1748
- case "nearest":
1749
- return mipmapFilter === "nearest" ? 9984 : 9986;
1750
- case "linear":
1751
- return mipmapFilter === "nearest" ? 9985 : 9987;
1856
+ if (usage & import_core8.Buffer.VERTEX) {
1857
+ return 35044;
1858
+ }
1859
+ if (usage & import_core8.Buffer.UNIFORM) {
1860
+ return 35048;
1752
1861
  }
1862
+ return 35044;
1753
1863
  }
1754
1864
 
1755
- // dist/adapter/resources/webgl-sampler.js
1756
- var import_core5 = require("@luma.gl/core");
1757
- var import_constants8 = require("@luma.gl/constants");
1758
- var WEBGLSampler = class extends import_core5.Sampler {
1865
+ // dist/adapter/resources/webgl-shader.js
1866
+ var import_core9 = require("@luma.gl/core");
1867
+ var import_constants9 = require("@luma.gl/constants");
1868
+
1869
+ // dist/adapter/helpers/parse-shader-compiler-log.js
1870
+ function parseShaderCompilerLog(errLog) {
1871
+ const lines = errLog.split(/\r?\n/);
1872
+ const messages = [];
1873
+ for (const line of lines) {
1874
+ if (line.length <= 1) {
1875
+ continue;
1876
+ }
1877
+ const segments = line.split(":");
1878
+ if (segments.length === 2) {
1879
+ const [messageType2, message2] = segments;
1880
+ messages.push({
1881
+ message: message2.trim(),
1882
+ type: getMessageType(messageType2),
1883
+ lineNum: 0,
1884
+ linePos: 0
1885
+ });
1886
+ continue;
1887
+ }
1888
+ const [messageType, linePosition, lineNumber, ...rest] = segments;
1889
+ let lineNum = parseInt(lineNumber, 10);
1890
+ if (isNaN(lineNum)) {
1891
+ lineNum = 0;
1892
+ }
1893
+ let linePos = parseInt(linePosition, 10);
1894
+ if (isNaN(linePos)) {
1895
+ linePos = 0;
1896
+ }
1897
+ messages.push({
1898
+ message: rest.join(":").trim(),
1899
+ type: getMessageType(messageType),
1900
+ lineNum,
1901
+ linePos
1902
+ // TODO
1903
+ });
1904
+ }
1905
+ return messages;
1906
+ }
1907
+ function getMessageType(messageType) {
1908
+ const MESSAGE_TYPES = ["warning", "error", "info"];
1909
+ const lowerCaseType = messageType.toLowerCase();
1910
+ return MESSAGE_TYPES.includes(lowerCaseType) ? lowerCaseType : "info";
1911
+ }
1912
+
1913
+ // dist/adapter/resources/webgl-shader.js
1914
+ var WEBGLShader = class extends import_core9.Shader {
1759
1915
  device;
1760
1916
  handle;
1761
- parameters;
1762
1917
  constructor(device, props) {
1763
1918
  super(device, props);
1764
1919
  this.device = device;
1765
- this.parameters = convertSamplerParametersToWebGL(props);
1766
- this.handle = this.handle || this.device.gl.createSampler();
1767
- this._setSamplerParameters(this.parameters);
1920
+ switch (this.props.stage) {
1921
+ case "vertex":
1922
+ this.handle = this.props.handle || this.device.gl.createShader(35633);
1923
+ break;
1924
+ case "fragment":
1925
+ this.handle = this.props.handle || this.device.gl.createShader(35632);
1926
+ break;
1927
+ default:
1928
+ throw new Error(this.props.stage);
1929
+ }
1930
+ this._compile(this.source);
1768
1931
  }
1769
1932
  destroy() {
1770
1933
  if (this.handle) {
1771
- this.device.gl.deleteSampler(this.handle);
1772
- this.handle = void 0;
1934
+ this.removeStats();
1935
+ this.device.gl.deleteShader(this.handle);
1936
+ this.destroyed = true;
1773
1937
  }
1774
1938
  }
1775
- toString() {
1776
- return `Sampler(${this.id},${JSON.stringify(this.props)})`;
1939
+ get asyncCompilationStatus() {
1940
+ return this._waitForCompilationComplete().then(() => this.compilationStatus);
1777
1941
  }
1778
- /** Set sampler parameters on the sampler */
1779
- _setSamplerParameters(parameters) {
1780
- for (const [pname, value] of Object.entries(parameters)) {
1781
- const param = Number(pname);
1782
- switch (param) {
1783
- case 33082:
1784
- case 33083:
1785
- this.device.gl.samplerParameterf(this.handle, param, value);
1786
- break;
1787
- default:
1788
- this.device.gl.samplerParameteri(this.handle, param, value);
1789
- break;
1790
- }
1791
- }
1942
+ async getCompilationInfo() {
1943
+ await this._waitForCompilationComplete();
1944
+ return this.getCompilationInfoSync();
1792
1945
  }
1793
- };
1794
-
1795
- // dist/adapter/resources/webgl-texture-view.js
1796
- var import_core6 = require("@luma.gl/core");
1797
- var WEBGLTextureView = class extends import_core6.TextureView {
1798
- device;
1799
- gl;
1800
- handle;
1801
- // Does not have a WebGL representation
1802
- texture;
1803
- constructor(device, props) {
1804
- super(device, { ...import_core6.Texture.defaultProps, ...props });
1805
- this.device = device;
1806
- this.gl = this.device.gl;
1807
- this.handle = null;
1808
- this.texture = props.texture;
1946
+ getCompilationInfoSync() {
1947
+ const shaderLog = this.device.gl.getShaderInfoLog(this.handle);
1948
+ return shaderLog ? parseShaderCompilerLog(shaderLog) : [];
1949
+ }
1950
+ getTranslatedSource() {
1951
+ const extensions = this.device.getExtension("WEBGL_debug_shaders");
1952
+ const ext = extensions.WEBGL_debug_shaders;
1953
+ return (ext == null ? void 0 : ext.getTranslatedShaderSource(this.handle)) || null;
1954
+ }
1955
+ // PRIVATE METHODS
1956
+ /** Compile a shader and get compilation status */
1957
+ async _compile(source) {
1958
+ source = source.startsWith("#version ") ? source : `#version 300 es
1959
+ ${source}`;
1960
+ const { gl } = this.device;
1961
+ gl.shaderSource(this.handle, source);
1962
+ gl.compileShader(this.handle);
1963
+ if (import_core9.log.level === 0) {
1964
+ this.compilationStatus = "pending";
1965
+ return;
1966
+ }
1967
+ if (!this.device.features.has("compilation-status-async-webgl")) {
1968
+ this._getCompilationStatus();
1969
+ this.debugShader();
1970
+ if (this.compilationStatus === "error") {
1971
+ throw new Error(`GLSL compilation errors in ${this.props.stage} shader ${this.props.id}`);
1972
+ }
1973
+ return;
1974
+ }
1975
+ import_core9.log.once(1, "Shader compilation is asynchronous")();
1976
+ await this._waitForCompilationComplete();
1977
+ import_core9.log.info(2, `Shader ${this.id} - async compilation complete: ${this.compilationStatus}`)();
1978
+ this._getCompilationStatus();
1979
+ this.debugShader();
1980
+ }
1981
+ /** Use KHR_parallel_shader_compile extension if available */
1982
+ async _waitForCompilationComplete() {
1983
+ const waitMs = async (ms) => await new Promise((resolve) => setTimeout(resolve, ms));
1984
+ const DELAY_MS = 10;
1985
+ if (!this.device.features.has("compilation-status-async-webgl")) {
1986
+ await waitMs(DELAY_MS);
1987
+ return;
1988
+ }
1989
+ const { gl } = this.device;
1990
+ for (; ; ) {
1991
+ const complete = gl.getShaderParameter(this.handle, 37297);
1992
+ if (complete) {
1993
+ return;
1994
+ }
1995
+ await waitMs(DELAY_MS);
1996
+ }
1997
+ }
1998
+ /**
1999
+ * Get the shader compilation status
2000
+ * TODO - Load log even when no error reported, to catch warnings?
2001
+ * https://gamedev.stackexchange.com/questions/30429/how-to-detect-glsl-warnings
2002
+ */
2003
+ _getCompilationStatus() {
2004
+ this.compilationStatus = this.device.gl.getShaderParameter(this.handle, 35713) ? "success" : "error";
1809
2005
  }
1810
2006
  };
1811
2007
 
1812
- // dist/adapter/helpers/webgl-texture-utils.js
1813
- var import_core7 = require("@luma.gl/core");
2008
+ // dist/adapter/resources/webgl-sampler.js
2009
+ var import_core11 = require("@luma.gl/core");
2010
+ var import_constants12 = require("@luma.gl/constants");
2011
+
2012
+ // dist/adapter/converters/sampler-parameters.js
1814
2013
  var import_constants11 = require("@luma.gl/constants");
1815
2014
 
1816
- // dist/adapter/helpers/typed-array-utils.js
1817
- var import_constants9 = require("@luma.gl/constants");
1818
- var ERR_TYPE_DEDUCTION = "Failed to deduce GL constant from typed array";
1819
- function getGLTypeFromTypedArray(arrayOrType) {
1820
- const type = ArrayBuffer.isView(arrayOrType) ? arrayOrType.constructor : arrayOrType;
1821
- switch (type) {
1822
- case Float32Array:
1823
- return 5126;
1824
- case Uint16Array:
1825
- return 5123;
1826
- case Uint32Array:
1827
- return 5125;
1828
- case Uint8Array:
1829
- return 5121;
1830
- case Uint8ClampedArray:
1831
- return 5121;
1832
- case Int8Array:
1833
- return 5120;
1834
- case Int16Array:
1835
- return 5122;
1836
- case Int32Array:
1837
- return 5124;
1838
- default:
1839
- throw new Error(ERR_TYPE_DEDUCTION);
2015
+ // dist/adapter/converters/device-parameters.js
2016
+ var import_core10 = require("@luma.gl/core");
2017
+ var import_constants10 = require("@luma.gl/constants");
2018
+ function withDeviceAndGLParameters(device, parameters, glParameters, func) {
2019
+ if (isObjectEmpty2(parameters)) {
2020
+ return func(device);
1840
2021
  }
1841
- }
1842
- function getTypedArrayFromGLType(glType, options) {
1843
- const { clamped = true } = options || {};
1844
- switch (glType) {
1845
- case 5126:
1846
- return Float32Array;
1847
- case 5123:
1848
- case 33635:
1849
- case 32819:
1850
- case 32820:
1851
- return Uint16Array;
1852
- case 5125:
1853
- return Uint32Array;
1854
- case 5121:
1855
- return clamped ? Uint8ClampedArray : Uint8Array;
1856
- case 5120:
1857
- return Int8Array;
1858
- case 5122:
1859
- return Int16Array;
1860
- case 5124:
1861
- return Int32Array;
1862
- default:
1863
- throw new Error("Failed to deduce typed array type from GL constant");
2022
+ const webglDevice = device;
2023
+ webglDevice.pushState();
2024
+ try {
2025
+ setDeviceParameters(device, parameters);
2026
+ setGLParameters(webglDevice.gl, glParameters);
2027
+ return func(device);
2028
+ } finally {
2029
+ webglDevice.popState();
1864
2030
  }
1865
2031
  }
1866
-
1867
- // dist/adapter/helpers/format-utils.js
1868
- var import_constants10 = require("@luma.gl/constants");
1869
- function glFormatToComponents(format) {
1870
- switch (format) {
1871
- case 6406:
1872
- case 33326:
1873
- case 6403:
1874
- return 1;
1875
- case 33328:
1876
- case 33319:
1877
- return 2;
1878
- case 6407:
1879
- case 34837:
1880
- return 3;
1881
- case 6408:
1882
- case 34836:
1883
- return 4;
1884
- default:
1885
- return 0;
2032
+ function withDeviceParameters(device, parameters, func) {
2033
+ if (isObjectEmpty2(parameters)) {
2034
+ return func(device);
1886
2035
  }
1887
- }
1888
- function glTypeToBytes(type) {
1889
- switch (type) {
1890
- case 5121:
1891
- return 1;
1892
- case 33635:
1893
- case 32819:
1894
- case 32820:
1895
- return 2;
1896
- case 5126:
1897
- return 4;
1898
- default:
1899
- return 0;
2036
+ const webglDevice = device;
2037
+ webglDevice.pushState();
2038
+ try {
2039
+ setDeviceParameters(device, parameters);
2040
+ return func(device);
2041
+ } finally {
2042
+ webglDevice.popState();
1900
2043
  }
1901
2044
  }
1902
-
1903
- // dist/adapter/helpers/webgl-texture-utils.js
1904
- function initializeTextureStorage(gl, levels, options) {
1905
- const { dimension, width, height, depth = 0 } = options;
1906
- const { glInternalFormat } = options;
1907
- const glTarget = options.glTarget;
1908
- switch (dimension) {
1909
- case "2d-array":
1910
- case "3d":
1911
- gl.texStorage3D(glTarget, levels, glInternalFormat, width, height, depth);
1912
- break;
1913
- default:
1914
- gl.texStorage2D(glTarget, levels, glInternalFormat, width, height);
2045
+ function setDeviceParameters(device, parameters) {
2046
+ const webglDevice = device;
2047
+ const { gl } = webglDevice;
2048
+ if (parameters.cullMode) {
2049
+ switch (parameters.cullMode) {
2050
+ case "none":
2051
+ gl.disable(2884);
2052
+ break;
2053
+ case "front":
2054
+ gl.enable(2884);
2055
+ gl.cullFace(1028);
2056
+ break;
2057
+ case "back":
2058
+ gl.enable(2884);
2059
+ gl.cullFace(1029);
2060
+ break;
2061
+ }
1915
2062
  }
1916
- }
1917
- function copyExternalImageToMipLevel(gl, handle, image, options) {
1918
- const { width, height } = options;
1919
- const { dimension, depth = 0, mipLevel = 0 } = options;
1920
- const { x = 0, y = 0, z = 0 } = options;
1921
- const { glFormat, glType } = options;
1922
- const glTarget = getWebGLCubeFaceTarget(options.glTarget, dimension, depth);
1923
- switch (dimension) {
1924
- case "2d-array":
1925
- case "3d":
1926
- gl.bindTexture(glTarget, handle);
1927
- gl.texSubImage3D(glTarget, mipLevel, x, y, z, width, height, depth, glFormat, glType, image);
1928
- gl.bindTexture(glTarget, null);
1929
- break;
1930
- case "2d":
1931
- case "cube":
1932
- gl.bindTexture(glTarget, handle);
1933
- gl.texSubImage2D(glTarget, mipLevel, x, y, width, height, glFormat, glType, image);
1934
- gl.bindTexture(glTarget, null);
1935
- break;
1936
- default:
1937
- throw new Error(dimension);
2063
+ if (parameters.frontFace) {
2064
+ gl.frontFace(map("frontFace", parameters.frontFace, {
2065
+ ccw: 2305,
2066
+ cw: 2304
2067
+ }));
1938
2068
  }
1939
- }
1940
- function copyCPUDataToMipLevel(gl, typedArray, options) {
1941
- const { dimension, width, height, depth = 0, mipLevel = 0, byteOffset = 0 } = options;
1942
- const { x = 0, y = 0, z = 0 } = options;
1943
- const { glFormat, glType, compressed } = options;
1944
- const glTarget = getWebGLCubeFaceTarget(options.glTarget, dimension, depth);
1945
- switch (dimension) {
1946
- case "2d-array":
1947
- case "3d":
1948
- if (compressed) {
1949
- gl.compressedTexSubImage3D(glTarget, mipLevel, x, y, z, width, height, depth, glFormat, typedArray, byteOffset);
1950
- } else {
1951
- gl.texSubImage3D(glTarget, mipLevel, x, y, z, width, height, depth, glFormat, glType, typedArray, byteOffset);
1952
- }
1953
- break;
1954
- case "2d":
1955
- case "cube":
1956
- if (compressed) {
1957
- gl.compressedTexSubImage2D(glTarget, mipLevel, x, y, width, height, glFormat, typedArray, byteOffset);
1958
- } else {
1959
- gl.texSubImage2D(glTarget, mipLevel, x, y, width, height, glFormat, glType, typedArray, byteOffset);
1960
- }
1961
- break;
1962
- default:
1963
- throw new Error(dimension);
2069
+ if (parameters.unclippedDepth) {
2070
+ if (device.features.has("depth-clip-control")) {
2071
+ gl.enable(34383);
2072
+ }
1964
2073
  }
1965
- }
1966
- function getWebGLTextureTarget(dimension) {
1967
- switch (dimension) {
1968
- case "1d":
1969
- break;
1970
- case "2d":
1971
- return 3553;
1972
- case "3d":
1973
- return 32879;
1974
- case "cube":
1975
- return 34067;
1976
- case "2d-array":
1977
- return 35866;
1978
- case "cube-array":
2074
+ if (parameters.depthBias !== void 0) {
2075
+ gl.enable(32823);
2076
+ gl.polygonOffset(parameters.depthBias, parameters.depthBiasSlopeScale || 0);
2077
+ }
2078
+ if (parameters.provokingVertex) {
2079
+ if (device.features.has("provoking-vertex-webgl")) {
2080
+ const extensions = webglDevice.getExtension("WEBGL_provoking_vertex");
2081
+ const ext = extensions.WEBGL_provoking_vertex;
2082
+ const vertex = map("provokingVertex", parameters.provokingVertex, {
2083
+ first: 36429,
2084
+ last: 36430
2085
+ });
2086
+ ext == null ? void 0 : ext.provokingVertexWEBGL(vertex);
2087
+ }
2088
+ }
2089
+ if (parameters.polygonMode || parameters.polygonOffsetLine) {
2090
+ if (device.features.has("polygon-mode-webgl")) {
2091
+ if (parameters.polygonMode) {
2092
+ const extensions = webglDevice.getExtension("WEBGL_polygon_mode");
2093
+ const ext = extensions.WEBGL_polygon_mode;
2094
+ const mode = map("polygonMode", parameters.polygonMode, {
2095
+ fill: 6914,
2096
+ line: 6913
2097
+ });
2098
+ ext == null ? void 0 : ext.polygonModeWEBGL(1028, mode);
2099
+ ext == null ? void 0 : ext.polygonModeWEBGL(1029, mode);
2100
+ }
2101
+ if (parameters.polygonOffsetLine) {
2102
+ gl.enable(10754);
2103
+ }
2104
+ }
2105
+ }
2106
+ if (device.features.has("shader-clip-cull-distance-webgl")) {
2107
+ if (parameters.clipDistance0) {
2108
+ gl.enable(12288);
2109
+ }
2110
+ if (parameters.clipDistance1) {
2111
+ gl.enable(12289);
2112
+ }
2113
+ if (parameters.clipDistance2) {
2114
+ gl.enable(12290);
2115
+ }
2116
+ if (parameters.clipDistance3) {
2117
+ gl.enable(12291);
2118
+ }
2119
+ if (parameters.clipDistance4) {
2120
+ gl.enable(12292);
2121
+ }
2122
+ if (parameters.clipDistance5) {
2123
+ gl.enable(12293);
2124
+ }
2125
+ if (parameters.clipDistance6) {
2126
+ gl.enable(12294);
2127
+ }
2128
+ if (parameters.clipDistance7) {
2129
+ gl.enable(12295);
2130
+ }
2131
+ }
2132
+ if (parameters.depthWriteEnabled !== void 0) {
2133
+ gl.depthMask(mapBoolean("depthWriteEnabled", parameters.depthWriteEnabled));
2134
+ }
2135
+ if (parameters.depthCompare) {
2136
+ parameters.depthCompare !== "always" ? gl.enable(2929) : gl.disable(2929);
2137
+ gl.depthFunc(convertCompareFunction("depthCompare", parameters.depthCompare));
2138
+ }
2139
+ if (parameters.stencilWriteMask) {
2140
+ const mask = parameters.stencilWriteMask;
2141
+ gl.stencilMaskSeparate(1028, mask);
2142
+ gl.stencilMaskSeparate(1029, mask);
2143
+ }
2144
+ if (parameters.stencilReadMask) {
2145
+ import_core10.log.warn("stencilReadMask not supported under WebGL");
2146
+ }
2147
+ if (parameters.stencilCompare) {
2148
+ const mask = parameters.stencilReadMask || 4294967295;
2149
+ const glValue = convertCompareFunction("depthCompare", parameters.stencilCompare);
2150
+ parameters.stencilCompare !== "always" ? gl.enable(2960) : gl.disable(2960);
2151
+ gl.stencilFuncSeparate(1028, glValue, 0, mask);
2152
+ gl.stencilFuncSeparate(1029, glValue, 0, mask);
2153
+ }
2154
+ if (parameters.stencilPassOperation && parameters.stencilFailOperation && parameters.stencilDepthFailOperation) {
2155
+ const dppass = convertStencilOperation("stencilPassOperation", parameters.stencilPassOperation);
2156
+ const sfail = convertStencilOperation("stencilFailOperation", parameters.stencilFailOperation);
2157
+ const dpfail = convertStencilOperation("stencilDepthFailOperation", parameters.stencilDepthFailOperation);
2158
+ gl.stencilOpSeparate(1028, sfail, dpfail, dppass);
2159
+ gl.stencilOpSeparate(1029, sfail, dpfail, dppass);
2160
+ }
2161
+ switch (parameters.blend) {
2162
+ case true:
2163
+ gl.enable(3042);
2164
+ break;
2165
+ case false:
2166
+ gl.disable(3042);
1979
2167
  break;
2168
+ default:
1980
2169
  }
1981
- throw new Error(dimension);
1982
- }
1983
- function getWebGLCubeFaceTarget(glTarget, dimension, level) {
1984
- return dimension === "cube" ? 34069 + level : glTarget;
1985
- }
1986
- function readPixelsToArray(source, options) {
1987
- var _a, _b, _c, _d, _e, _f;
1988
- const {
1989
- sourceX = 0,
1990
- sourceY = 0,
1991
- sourceAttachment = 36064
1992
- // TODO - support gl.readBuffer
1993
- } = options || {};
1994
- let {
1995
- target = null,
1996
- // following parameters are auto deduced if not provided
1997
- sourceWidth,
1998
- sourceHeight,
1999
- sourceDepth,
2000
- sourceFormat,
2001
- sourceType
2002
- } = options || {};
2003
- const { framebuffer, deleteFramebuffer } = getFramebuffer(source);
2004
- const { gl, handle } = framebuffer;
2005
- const attachment = sourceAttachment - 36064;
2006
- sourceWidth ||= framebuffer.width;
2007
- sourceHeight ||= framebuffer.height;
2008
- sourceDepth = ((_b = (_a = framebuffer.colorAttachments[attachment]) == null ? void 0 : _a.texture) == null ? void 0 : _b.depth) || 1;
2009
- sourceFormat ||= ((_d = (_c = framebuffer.colorAttachments[attachment]) == null ? void 0 : _c.texture) == null ? void 0 : _d.glFormat) || 6408;
2010
- sourceType ||= ((_f = (_e = framebuffer.colorAttachments[attachment]) == null ? void 0 : _e.texture) == null ? void 0 : _f.glType) || 5121;
2011
- target = getPixelArray(target, sourceType, sourceFormat, sourceWidth, sourceHeight, sourceDepth);
2012
- sourceType = sourceType || getGLTypeFromTypedArray(target);
2013
- const prevHandle = gl.bindFramebuffer(36160, handle);
2014
- gl.readPixels(sourceX, sourceY, sourceWidth, sourceHeight, sourceFormat, sourceType, target);
2015
- gl.bindFramebuffer(36160, prevHandle || null);
2016
- if (deleteFramebuffer) {
2017
- framebuffer.destroy();
2170
+ if (parameters.blendColorOperation || parameters.blendAlphaOperation) {
2171
+ const colorEquation = convertBlendOperationToEquation("blendColorOperation", parameters.blendColorOperation || "add");
2172
+ const alphaEquation = convertBlendOperationToEquation("blendAlphaOperation", parameters.blendAlphaOperation || "add");
2173
+ gl.blendEquationSeparate(colorEquation, alphaEquation);
2174
+ const colorSrcFactor = convertBlendFactorToFunction("blendColorSrcFactor", parameters.blendColorSrcFactor || "one");
2175
+ const colorDstFactor = convertBlendFactorToFunction("blendColorDstFactor", parameters.blendColorDstFactor || "zero");
2176
+ const alphaSrcFactor = convertBlendFactorToFunction("blendAlphaSrcFactor", parameters.blendAlphaSrcFactor || "one");
2177
+ const alphaDstFactor = convertBlendFactorToFunction("blendAlphaDstFactor", parameters.blendAlphaDstFactor || "zero");
2178
+ gl.blendFuncSeparate(colorSrcFactor, colorDstFactor, alphaSrcFactor, alphaDstFactor);
2018
2179
  }
2019
- return target;
2020
2180
  }
2021
- function readPixelsToBuffer(source, options) {
2022
- const { target, sourceX = 0, sourceY = 0, sourceFormat = 6408, targetByteOffset = 0 } = options || {};
2023
- let { sourceWidth, sourceHeight, sourceType } = options || {};
2024
- const { framebuffer, deleteFramebuffer } = getFramebuffer(source);
2025
- sourceWidth = sourceWidth || framebuffer.width;
2026
- sourceHeight = sourceHeight || framebuffer.height;
2027
- const webglFramebuffer = framebuffer;
2028
- sourceType = sourceType || 5121;
2029
- let webglBufferTarget = target;
2030
- if (!webglBufferTarget) {
2031
- const components = glFormatToComponents(sourceFormat);
2032
- const byteCount = glTypeToBytes(sourceType);
2033
- const byteLength = targetByteOffset + sourceWidth * sourceHeight * components * byteCount;
2034
- webglBufferTarget = webglFramebuffer.device.createBuffer({ byteLength });
2035
- }
2036
- const commandEncoder = source.device.createCommandEncoder();
2037
- commandEncoder.copyTextureToBuffer({
2038
- source,
2039
- width: sourceWidth,
2040
- height: sourceHeight,
2041
- origin: [sourceX, sourceY],
2042
- destination: webglBufferTarget,
2043
- byteOffset: targetByteOffset
2181
+ function convertCompareFunction(parameter, value) {
2182
+ return map(parameter, value, {
2183
+ never: 512,
2184
+ less: 513,
2185
+ equal: 514,
2186
+ "less-equal": 515,
2187
+ greater: 516,
2188
+ "not-equal": 517,
2189
+ "greater-equal": 518,
2190
+ always: 519
2044
2191
  });
2045
- commandEncoder.destroy();
2046
- if (deleteFramebuffer) {
2047
- framebuffer.destroy();
2048
- }
2049
- return webglBufferTarget;
2050
2192
  }
2051
- function getFramebuffer(source) {
2052
- if (!(source instanceof import_core7.Framebuffer)) {
2053
- return { framebuffer: toFramebuffer(source), deleteFramebuffer: true };
2054
- }
2055
- return { framebuffer: source, deleteFramebuffer: false };
2193
+ function convertStencilOperation(parameter, value) {
2194
+ return map(parameter, value, {
2195
+ keep: 7680,
2196
+ zero: 0,
2197
+ replace: 7681,
2198
+ invert: 5386,
2199
+ "increment-clamp": 7682,
2200
+ "decrement-clamp": 7683,
2201
+ "increment-wrap": 34055,
2202
+ "decrement-wrap": 34056
2203
+ });
2056
2204
  }
2057
- function toFramebuffer(texture, props) {
2058
- const { device, width, height, id } = texture;
2059
- const framebuffer = device.createFramebuffer({
2060
- ...props,
2061
- id: `framebuffer-for-${id}`,
2062
- width,
2063
- height,
2064
- colorAttachments: [texture]
2205
+ function convertBlendOperationToEquation(parameter, value) {
2206
+ return map(parameter, value, {
2207
+ add: 32774,
2208
+ subtract: 32778,
2209
+ "reverse-subtract": 32779,
2210
+ min: 32775,
2211
+ max: 32776
2065
2212
  });
2066
- return framebuffer;
2067
2213
  }
2068
- function getPixelArray(pixelArray, type, format, width, height, depth) {
2069
- if (pixelArray) {
2070
- return pixelArray;
2071
- }
2072
- type = type || 5121;
2073
- const ArrayType = getTypedArrayFromGLType(type, { clamped: false });
2074
- const components = glFormatToComponents(format);
2075
- return new ArrayType(width * height * components);
2214
+ function convertBlendFactorToFunction(parameter, value) {
2215
+ return map(parameter, value, {
2216
+ one: 1,
2217
+ zero: 0,
2218
+ "src-color": 768,
2219
+ "one-minus-src-color": 769,
2220
+ "dst-color": 774,
2221
+ "one-minus-dst-color": 775,
2222
+ "src-alpha": 770,
2223
+ "one-minus-src-alpha": 771,
2224
+ "dst-alpha": 772,
2225
+ "one-minus-dst-alpha": 773,
2226
+ "src-alpha-saturated": 776,
2227
+ "constant-color": 32769,
2228
+ "one-minus-constant-color": 32770,
2229
+ "constant-alpha": 32771,
2230
+ "one-minus-constant-alpha": 32772
2231
+ });
2076
2232
  }
2077
-
2078
- // dist/adapter/resources/webgl-texture.js
2079
- function normalizeTextureData(data, options) {
2080
- let lodArray;
2081
- if (ArrayBuffer.isView(data)) {
2082
- lodArray = [
2083
- {
2084
- // ts-expect-error does data really need to be Uint8ClampedArray?
2085
- data,
2086
- width: options.width,
2087
- height: options.height
2088
- // depth: options.depth
2089
- }
2090
- ];
2091
- } else if (!Array.isArray(data)) {
2092
- lodArray = [data];
2093
- } else {
2094
- lodArray = data;
2095
- }
2096
- return lodArray;
2233
+ function message(parameter, value) {
2234
+ return `Illegal parameter ${value} for ${parameter}`;
2097
2235
  }
2098
- var WEBGLTexture = class extends import_core8.Texture {
2099
- MAX_ATTRIBUTES;
2100
- device;
2101
- gl;
2102
- handle;
2103
- sampler = void 0;
2104
- // TODO - currently unused in WebGL. Create dummy sampler?
2105
- view = void 0;
2106
- // TODO - currently unused in WebGL. Create dummy view?
2107
- mipmaps = false;
2108
- /**
2109
- * @note `target` cannot be modified by bind:
2110
- * textures are special because when you first bind them to a target,
2111
- * When you first bind a texture as a GL_TEXTURE_2D, you are saying that this texture is a 2D texture.
2112
- * And it will always be a 2D texture; this state cannot be changed ever.
2113
- * A texture that was first bound as a GL_TEXTURE_2D, must always be bound as a GL_TEXTURE_2D;
2114
- * attempting to bind it as GL_TEXTURE_3D will give rise to a run-time error
2115
- */
2116
- glTarget;
2117
- // Texture type
2118
- /** The WebGL format - essentially channel structure */
2119
- glFormat;
2120
- /** The WebGL data format - the type of each channel */
2121
- glType;
2122
- /** The WebGL constant corresponding to the WebGPU style constant in format */
2123
- glInternalFormat;
2124
- /** Whether the internal format is compressed */
2125
- compressed;
2126
- // data;
2127
- // inherited props
2128
- // dimension: ...
2129
- // format: GLTextureTarget;
2130
- // width: number = undefined;
2131
- // height: number = undefined;
2132
- // depth: number = undefined;
2133
- // state
2134
- /** Texture binding slot */
2135
- textureUnit = 0;
2136
- /** For automatically updating video */
2137
- _video = null;
2138
- constructor(device, props) {
2139
- props = import_core8.Texture._fixProps(props);
2140
- super(device, { ...import_core8.Texture.defaultProps, ...props, data: void 0 });
2141
- this.device = device;
2142
- this.gl = this.device.gl;
2143
- this.glTarget = getWebGLTextureTarget(this.props.dimension);
2144
- const format = getTextureFormatWebGL(this.props.format);
2145
- this.glInternalFormat = format.internalFormat;
2146
- this.glFormat = format.format;
2147
- this.glType = format.type;
2148
- this.compressed = format.compressed;
2149
- if (typeof HTMLVideoElement !== "undefined" && props.data instanceof HTMLVideoElement && // @ts-expect-error
2150
- props.data.readyState < HTMLVideoElement.HAVE_METADATA) {
2151
- const video = props.data;
2152
- this._video = null;
2153
- video.addEventListener("loadeddata", () => this.initialize(props));
2154
- }
2155
- this.initialize({ ...this.props, data: props.data });
2156
- Object.seal(this);
2157
- }
2158
- /**
2159
- * Initialize texture with supplied props
2160
- */
2161
- // eslint-disable-next-line max-statements
2162
- initialize(props = {}) {
2163
- this.handle = this.props.handle || this.gl.createTexture();
2164
- this.device.setSpectorMetadata(this.handle, { ...this.props, data: typeof this.props.data });
2165
- const data = props.data;
2166
- let { width, height } = props;
2167
- if (!width || !height) {
2168
- const textureSize = import_core8.Texture.getTextureDataSize(data);
2169
- width = (textureSize == null ? void 0 : textureSize.width) || 1;
2170
- height = (textureSize == null ? void 0 : textureSize.height) || 1;
2171
- }
2172
- this.width = width;
2173
- this.height = height;
2174
- this.depth = props.depth;
2175
- this.setSampler(props.sampler);
2176
- this.view = new WEBGLTextureView(this.device, { ...this.props, texture: this });
2177
- this.bind();
2178
- if (!this.props.data) {
2179
- initializeTextureStorage(this.gl, this.mipLevels, this);
2180
- }
2181
- if (props.data) {
2182
- switch (props.dimension) {
2183
- case "1d":
2184
- this.setTexture1DData(props.data);
2185
- break;
2186
- case "2d":
2187
- this.setTexture2DData(props.data);
2188
- break;
2189
- case "3d":
2190
- this.setTexture3DData(props.data);
2191
- break;
2192
- case "cube":
2193
- this.setTextureCubeData(props.data);
2194
- break;
2195
- case "2d-array":
2196
- this.setTextureArrayData(props.data);
2197
- break;
2198
- case "cube-array":
2199
- this.setTextureCubeArrayData(props.data);
2200
- break;
2201
- default:
2202
- throw new Error(props.dimension);
2203
- }
2204
- }
2205
- this.mipmaps = Boolean(props.mipmaps);
2206
- if (this.mipmaps) {
2207
- this.generateMipmap();
2208
- }
2209
- }
2210
- /*
2211
- initializeCube(props?: TextureProps): void {
2212
- const {mipmaps = true} = props; // , parameters = {} as Record<GL, any>} = props;
2213
-
2214
- // Store props for accessors
2215
- // this.props = props;
2216
-
2217
- // @ts-expect-error
2218
- this.setCubeMapData(props).then(() => {
2219
- // TODO - should genMipmap() be called on the cubemap or on the faces?
2220
- // TODO - without generateMipmap() cube textures do not work at all!!! Why?
2221
- if (mipmaps) {
2222
- this.generateMipmap(props);
2223
- }
2224
-
2225
- this.setSampler(props.sampler);
2226
-
2227
- // v8 compatibility?
2228
- // const {parameters = {} as Record<GL, any>} = props;
2229
- // this._setSamplerParameters(parameters);
2230
- });
2231
- }
2232
- */
2233
- destroy() {
2234
- if (this.handle) {
2235
- this.gl.deleteTexture(this.handle);
2236
- this.removeStats();
2237
- this.trackDeallocatedMemory("Texture");
2238
- this.destroyed = true;
2239
- }
2240
- }
2241
- toString() {
2242
- return `Texture(${this.id},${this.width}x${this.height})`;
2243
- }
2244
- createView(props) {
2245
- return new WEBGLTextureView(this.device, { ...props, texture: this });
2246
- }
2247
- setSampler(sampler = {}) {
2248
- let samplerProps;
2249
- if (sampler instanceof WEBGLSampler) {
2250
- this.sampler = sampler;
2251
- samplerProps = sampler.props;
2252
- } else {
2253
- this.sampler = new WEBGLSampler(this.device, sampler);
2254
- samplerProps = sampler;
2255
- }
2256
- const parameters = convertSamplerParametersToWebGL(samplerProps);
2257
- this._setSamplerParameters(parameters);
2258
- }
2259
- /** Update external texture (video frame or canvas) */
2260
- update() {
2261
- import_core8.log.warn("Texture.update() not implemented");
2262
- }
2263
- // Call to regenerate mipmaps after modifying texture(s)
2264
- generateMipmap(params = {}) {
2265
- if (!this.props.data) {
2266
- return;
2267
- }
2268
- this.mipmaps = true;
2269
- this.gl.bindTexture(this.glTarget, this.handle);
2270
- withGLParameters(this.gl, params, () => {
2271
- this.gl.generateMipmap(this.glTarget);
2272
- });
2273
- this.gl.bindTexture(this.glTarget, null);
2274
- }
2275
- // Image Data Setters
2276
- copyExternalImage(options) {
2277
- const size = import_core8.Texture.getExternalImageSize(options.image);
2278
- const opts = { ...import_core8.Texture.defaultCopyExternalImageOptions, ...size, ...options };
2279
- const { image, depth, mipLevel, x, y, z } = opts;
2280
- let { width, height } = opts;
2281
- const { dimension, glTarget, glFormat, glInternalFormat, glType } = this;
2282
- width = Math.min(width, size.width - x);
2283
- height = Math.min(height, size.height - y);
2284
- if (options.sourceX || options.sourceY) {
2285
- throw new Error("WebGL does not yet support sourceX/sourceY in copyExternalImage; requires copyTexSubImage2D from a framebuffer");
2286
- }
2287
- copyExternalImageToMipLevel(this.device.gl, this.handle, image, {
2288
- dimension,
2289
- mipLevel,
2290
- x,
2291
- y,
2292
- z,
2293
- width,
2294
- height,
2295
- depth,
2296
- glFormat,
2297
- glInternalFormat,
2298
- glType,
2299
- glTarget
2300
- });
2301
- return { width: opts.width, height: opts.height };
2302
- }
2303
- setTexture1DData(data) {
2304
- throw new Error("setTexture1DData not supported in WebGL.");
2305
- }
2306
- /** Set a simple texture */
2307
- setTexture2DData(lodData, depth = 0) {
2308
- this.bind();
2309
- const lodArray = normalizeTextureData(lodData, this);
2310
- if (lodArray.length > 1 && this.props.mipmaps !== false) {
2311
- import_core8.log.warn(`Texture ${this.id} mipmap and multiple LODs.`)();
2312
- }
2313
- for (let lodLevel = 0; lodLevel < lodArray.length; lodLevel++) {
2314
- const imageData = lodArray[lodLevel];
2315
- this._setMipLevel(depth, lodLevel, imageData);
2316
- }
2317
- this.unbind();
2318
- }
2319
- /**
2320
- * Sets a 3D texture
2321
- * @param data
2322
- */
2323
- setTexture3DData(data) {
2324
- if (this.props.dimension !== "3d") {
2325
- throw new Error(this.id);
2326
- }
2327
- if (ArrayBuffer.isView(data)) {
2328
- this.bind();
2329
- copyCPUDataToMipLevel(this.device.gl, data, this);
2330
- this.unbind();
2331
- }
2332
- }
2333
- /**
2334
- * Set a Texture Cube Data
2335
- * @todo - could support TextureCubeArray with depth
2336
- * @param data
2337
- * @param index
2338
- */
2339
- setTextureCubeData(data, depth = 0) {
2340
- if (this.props.dimension !== "cube") {
2341
- throw new Error(this.id);
2342
- }
2343
- for (const face of import_core8.Texture.CubeFaces) {
2344
- this.setTextureCubeFaceData(data[face], face);
2345
- }
2346
- }
2347
- /**
2348
- * Sets an entire texture array
2349
- * @param data
2350
- */
2351
- setTextureArrayData(data) {
2352
- if (this.props.dimension !== "2d-array") {
2353
- throw new Error(this.id);
2354
- }
2355
- throw new Error("setTextureArrayData not implemented.");
2356
- }
2357
- /**
2358
- * Sets an entire texture cube array
2359
- * @param data
2360
- */
2361
- setTextureCubeArrayData(data) {
2362
- throw new Error("setTextureCubeArrayData not supported in WebGL2.");
2363
- }
2364
- setTextureCubeFaceData(lodData, face, depth = 0) {
2365
- if (Array.isArray(lodData) && lodData.length > 1 && this.props.mipmaps !== false) {
2366
- import_core8.log.warn(`${this.id} has mipmap and multiple LODs.`)();
2367
- }
2368
- const faceDepth = import_core8.Texture.CubeFaces.indexOf(face);
2369
- this.setTexture2DData(lodData, faceDepth);
2370
- }
2371
- // INTERNAL METHODS
2372
- /** @todo update this method to accept LODs */
2373
- setImageDataForFace(options) {
2374
- const {
2375
- face,
2376
- width,
2377
- height,
2378
- pixels,
2379
- data,
2380
- format = 6408,
2381
- type = 5121
2382
- // generateMipmap = false // TODO
2383
- } = options;
2384
- const { gl } = this;
2385
- const imageData = pixels || data;
2386
- this.bind();
2387
- if (imageData instanceof Promise) {
2388
- imageData.then((resolvedImageData) => this.setImageDataForFace(Object.assign({}, options, {
2389
- face,
2390
- data: resolvedImageData,
2391
- pixels: resolvedImageData
2392
- })));
2393
- } else if (this.width || this.height) {
2394
- gl.texImage2D(face, 0, format, width, height, 0, format, type, imageData);
2395
- } else {
2396
- gl.texImage2D(face, 0, format, format, type, imageData);
2397
- }
2398
- }
2399
- _getImageDataMap(faceData) {
2400
- for (let i = 0; i < import_core8.Texture.CubeFaces.length; ++i) {
2401
- const faceName = import_core8.Texture.CubeFaces[i];
2402
- if (faceData[faceName]) {
2403
- faceData[34069 + i] = faceData[faceName];
2404
- delete faceData[faceName];
2405
- }
2406
- }
2407
- return faceData;
2408
- }
2409
- // RESOURCE METHODS
2410
- /**
2411
- * Sets sampler parameters on texture
2412
- */
2413
- _setSamplerParameters(parameters) {
2414
- import_core8.log.log(1, "texture sampler parameters", parameters)();
2415
- this.gl.bindTexture(this.glTarget, this.handle);
2416
- for (const [pname, pvalue] of Object.entries(parameters)) {
2417
- const param = Number(pname);
2418
- const value = pvalue;
2419
- switch (param) {
2420
- case 33082:
2421
- case 33083:
2422
- this.gl.texParameterf(this.glTarget, param, value);
2423
- break;
2424
- case 10241:
2425
- this.gl.texParameteri(this.glTarget, param, value);
2426
- break;
2427
- case 10242:
2428
- case 10243:
2429
- this.gl.texParameteri(this.glTarget, param, value);
2430
- break;
2431
- case 34046:
2432
- if (this.device.features.has("texture-filterable-anisotropic-webgl")) {
2433
- this.gl.texParameteri(this.glTarget, param, value);
2434
- }
2435
- break;
2436
- default:
2437
- this.gl.texParameteri(this.glTarget, param, value);
2438
- break;
2439
- }
2440
- }
2441
- this.gl.bindTexture(this.glTarget, null);
2442
- }
2443
- // CLASSIC
2444
- /*
2445
- setCubeMapData(options: {
2446
- width: number;
2447
- height: number;
2448
- data: Record<GL, Texture2DData> | Record<TextureCubeFace, Texture2DData>;
2449
- format?: any;
2450
- type?: any;
2451
- /** @deprecated Use .data *
2452
- pixels: any;
2453
- }): void {
2454
- const {gl} = this;
2455
-
2456
- const {width, height, pixels, data, format = GL.RGBA, type = GL.UNSIGNED_BYTE} = options;
2457
-
2458
- // pixel data (imageDataMap) is an Object from Face to Image or Promise.
2459
- // For example:
2460
- // {
2461
- // GL.TEXTURE_CUBE_MAP_POSITIVE_X : Image-or-Promise,
2462
- // GL.TEXTURE_CUBE_MAP_NEGATIVE_X : Image-or-Promise,
2463
- // ... }
2464
- // To provide multiple level-of-details (LODs) this can be Face to Array
2465
- // of Image or Promise, like this
2466
- // {
2467
- // GL.TEXTURE_CUBE_MAP_POSITIVE_X : [Image-or-Promise-LOD-0, Image-or-Promise-LOD-1],
2468
- // GL.TEXTURE_CUBE_MAP_NEGATIVE_X : [Image-or-Promise-LOD-0, Image-or-Promise-LOD-1],
2469
- // ... }
2470
-
2471
- const imageDataMap = this._getImageDataMap(pixels || data);
2472
-
2473
- const resolvedFaces = WEBGLTexture.FACES.map(face => {
2474
- const facePixels = imageDataMap[face];
2475
- return Array.isArray(facePixels) ? facePixels : [facePixels];
2476
- });
2477
- this.bind();
2478
-
2479
- WEBGLTexture.FACES.forEach((face, index) => {
2480
- if (resolvedFaces[index].length > 1 && this.props.mipmaps !== false) {
2481
- // If the user provides multiple LODs, then automatic mipmap
2482
- // generation generateMipmap() should be disabled to avoid overwritting them.
2483
- log.warn(`${this.id} has mipmap and multiple LODs.`)();
2484
- }
2485
- resolvedFaces[index].forEach((image, lodLevel) => {
2486
- // TODO: adjust width & height for LOD!
2487
- if (width && height) {
2488
- gl.texImage2D(face, lodLevel, format, width, height, 0 /* border*, format, type, image);
2489
- } else {
2490
- gl.texImage2D(face, lodLevel, format, format, type, image);
2491
- }
2492
- });
2493
- });
2494
-
2495
- this.unbind();
2496
- }
2497
- */
2498
- // INTERNAL SETTERS
2499
- /**
2500
- * Copy a region of data from a CPU memory buffer into this texture.
2501
- * @todo - GLUnpackParameters parameters
2502
- */
2503
- _setMipLevel(depth, mipLevel, textureData, glTarget = this.glTarget) {
2504
- if (import_core8.Texture.isExternalImage(textureData)) {
2505
- copyExternalImageToMipLevel(this.device.gl, this.handle, textureData, {
2506
- ...this,
2507
- depth,
2508
- mipLevel,
2509
- glTarget
2510
- });
2511
- return;
2512
- }
2513
- if (import_core8.Texture.isTextureLevelData(textureData)) {
2514
- copyCPUDataToMipLevel(this.device.gl, textureData.data, {
2515
- ...this,
2516
- depth,
2517
- mipLevel,
2518
- glTarget
2519
- });
2520
- return;
2521
- }
2522
- throw new Error("Texture: invalid image data");
2236
+ function map(parameter, value, valueMap) {
2237
+ if (!(value in valueMap)) {
2238
+ throw new Error(message(parameter, value));
2523
2239
  }
2524
- // HELPERS
2525
- getActiveUnit() {
2526
- return this.gl.getParameter(34016) - 33984;
2240
+ return valueMap[value];
2241
+ }
2242
+ function mapBoolean(parameter, value) {
2243
+ return value;
2244
+ }
2245
+ function isObjectEmpty2(obj) {
2246
+ let isEmpty = true;
2247
+ for (const key in obj) {
2248
+ isEmpty = false;
2249
+ break;
2527
2250
  }
2528
- bind(textureUnit) {
2529
- const { gl } = this;
2530
- if (textureUnit !== void 0) {
2531
- this.textureUnit = textureUnit;
2532
- gl.activeTexture(33984 + textureUnit);
2533
- }
2534
- gl.bindTexture(this.glTarget, this.handle);
2535
- return textureUnit;
2251
+ return isEmpty;
2252
+ }
2253
+
2254
+ // dist/adapter/converters/sampler-parameters.js
2255
+ function convertSamplerParametersToWebGL(props) {
2256
+ const params = {};
2257
+ if (props.addressModeU) {
2258
+ params[10242] = convertAddressMode(props.addressModeU);
2536
2259
  }
2537
- unbind(textureUnit) {
2538
- const { gl } = this;
2539
- if (textureUnit !== void 0) {
2540
- this.textureUnit = textureUnit;
2541
- gl.activeTexture(33984 + textureUnit);
2542
- }
2543
- gl.bindTexture(this.glTarget, null);
2544
- return textureUnit;
2260
+ if (props.addressModeV) {
2261
+ params[10243] = convertAddressMode(props.addressModeV);
2545
2262
  }
2546
- };
2547
-
2548
- // dist/adapter/resources/webgl-framebuffer.js
2549
- var WEBGLFramebuffer = class extends import_core9.Framebuffer {
2550
- device;
2551
- gl;
2552
- handle;
2553
- colorAttachments = [];
2554
- depthStencilAttachment = null;
2555
- constructor(device, props) {
2556
- super(device, props);
2557
- const isDefaultFramebuffer = props.handle === null;
2558
- this.device = device;
2559
- this.gl = device.gl;
2560
- this.handle = this.props.handle || isDefaultFramebuffer ? this.props.handle : this.gl.createFramebuffer();
2561
- if (!isDefaultFramebuffer) {
2562
- device.setSpectorMetadata(this.handle, { id: this.props.id, props: this.props });
2563
- this.autoCreateAttachmentTextures();
2564
- this.updateAttachments();
2565
- }
2263
+ if (props.addressModeW) {
2264
+ params[32882] = convertAddressMode(props.addressModeW);
2566
2265
  }
2567
- /** destroys any auto created resources etc. */
2568
- destroy() {
2569
- super.destroy();
2570
- if (!this.destroyed && this.handle !== null) {
2571
- this.gl.deleteFramebuffer(this.handle);
2572
- }
2266
+ if (props.magFilter) {
2267
+ params[10240] = convertMaxFilterMode(props.magFilter);
2573
2268
  }
2574
- updateAttachments() {
2575
- const prevHandle = this.gl.bindFramebuffer(36160, this.handle);
2576
- for (let i = 0; i < this.colorAttachments.length; ++i) {
2577
- const attachment = this.colorAttachments[i];
2578
- if (attachment) {
2579
- const attachmentPoint = 36064 + i;
2580
- this._attachTextureView(attachmentPoint, attachment);
2581
- }
2582
- }
2583
- if (this.depthStencilAttachment) {
2584
- const attachmentPoint = getDepthStencilAttachmentWebGL(this.depthStencilAttachment.props.format);
2585
- this._attachTextureView(attachmentPoint, this.depthStencilAttachment);
2586
- }
2587
- if (this.props.check !== false) {
2588
- const status = this.gl.checkFramebufferStatus(36160);
2589
- if (status !== 36053) {
2590
- throw new Error(`Framebuffer ${_getFrameBufferStatus(status)}`);
2591
- }
2592
- }
2593
- this.gl.bindFramebuffer(36160, prevHandle);
2269
+ if (props.minFilter || props.mipmapFilter) {
2270
+ params[10241] = convertMinFilterMode(props.minFilter || "linear", props.mipmapFilter);
2594
2271
  }
2595
- // PRIVATE
2596
- /** In WebGL we must use renderbuffers for depth/stencil attachments (unless we have extensions) */
2597
- createDepthStencilTexture(format) {
2598
- return new WEBGLTexture(this.device, {
2599
- id: `${this.id}-depth-stencil`,
2600
- format,
2601
- width: this.width,
2602
- height: this.height,
2603
- mipmaps: false
2604
- });
2272
+ if (props.lodMinClamp !== void 0) {
2273
+ params[33082] = props.lodMinClamp;
2605
2274
  }
2606
- /**
2607
- * @param attachment
2608
- * @param texture
2609
- * @param layer = 0 - index into WEBGLTextureArray and Texture3D or face for `TextureCubeMap`
2610
- * @param level = 0 - mipmapLevel
2611
- */
2612
- _attachTextureView(attachment, textureView) {
2613
- const { gl } = this.device;
2614
- const { texture } = textureView;
2615
- const level = textureView.props.baseMipLevel;
2616
- const layer = textureView.props.baseArrayLayer;
2617
- gl.bindTexture(texture.glTarget, texture.handle);
2618
- switch (texture.glTarget) {
2619
- case 35866:
2620
- case 32879:
2621
- gl.framebufferTextureLayer(36160, attachment, texture.handle, level, layer);
2622
- break;
2623
- case 34067:
2624
- const face = mapIndexToCubeMapFace(layer);
2625
- gl.framebufferTexture2D(36160, attachment, face, texture.handle, level);
2626
- break;
2627
- case 3553:
2628
- gl.framebufferTexture2D(36160, attachment, 3553, texture.handle, level);
2629
- break;
2630
- default:
2631
- throw new Error("Illegal texture type");
2632
- }
2633
- gl.bindTexture(texture.glTarget, null);
2275
+ if (props.lodMaxClamp !== void 0) {
2276
+ params[33083] = props.lodMaxClamp;
2634
2277
  }
2635
- };
2636
- function mapIndexToCubeMapFace(layer) {
2637
- return layer < 34069 ? layer + 34069 : layer;
2278
+ if (props.type === "comparison-sampler") {
2279
+ params[34892] = 34894;
2280
+ }
2281
+ if (props.compare) {
2282
+ params[34893] = convertCompareFunction("compare", props.compare);
2283
+ }
2284
+ if (props.maxAnisotropy) {
2285
+ params[34046] = props.maxAnisotropy;
2286
+ }
2287
+ return params;
2638
2288
  }
2639
- function _getFrameBufferStatus(status) {
2640
- switch (status) {
2641
- case 36053:
2642
- return "success";
2643
- case 36054:
2644
- return "Mismatched attachments";
2645
- case 36055:
2646
- return "No attachments";
2647
- case 36057:
2648
- return "Height/width mismatch";
2649
- case 36061:
2650
- return "Unsupported or split attachments";
2651
- case 36182:
2652
- return "Samples mismatch";
2653
- default:
2654
- return `${status}`;
2289
+ function convertAddressMode(addressMode) {
2290
+ switch (addressMode) {
2291
+ case "clamp-to-edge":
2292
+ return 33071;
2293
+ case "repeat":
2294
+ return 10497;
2295
+ case "mirror-repeat":
2296
+ return 33648;
2297
+ }
2298
+ }
2299
+ function convertMaxFilterMode(maxFilter) {
2300
+ switch (maxFilter) {
2301
+ case "nearest":
2302
+ return 9728;
2303
+ case "linear":
2304
+ return 9729;
2305
+ }
2306
+ }
2307
+ function convertMinFilterMode(minFilter, mipmapFilter) {
2308
+ if (!mipmapFilter) {
2309
+ return convertMaxFilterMode(minFilter);
2310
+ }
2311
+ switch (minFilter) {
2312
+ case "nearest":
2313
+ return mipmapFilter === "nearest" ? 9984 : 9986;
2314
+ case "linear":
2315
+ return mipmapFilter === "nearest" ? 9985 : 9987;
2655
2316
  }
2656
2317
  }
2657
2318
 
2658
- // dist/adapter/webgl-canvas-context.js
2659
- var WebGLCanvasContext = class extends import_core10.CanvasContext {
2319
+ // dist/adapter/resources/webgl-sampler.js
2320
+ var WEBGLSampler = class extends import_core11.Sampler {
2660
2321
  device;
2661
- format = "rgba8unorm";
2662
- depthStencilFormat = "depth24plus";
2663
- presentationSize;
2664
- _framebuffer = null;
2322
+ handle;
2323
+ parameters;
2665
2324
  constructor(device, props) {
2666
- super(props);
2325
+ super(device, props);
2667
2326
  this.device = device;
2668
- this.presentationSize = [-1, -1];
2669
- this._setAutoCreatedCanvasId(`${this.device.id}-canvas`);
2670
- this.update();
2327
+ this.parameters = convertSamplerParametersToWebGL(props);
2328
+ this.handle = this.handle || this.device.gl.createSampler();
2329
+ this._setSamplerParameters(this.parameters);
2671
2330
  }
2672
- getCurrentFramebuffer() {
2673
- this.update();
2674
- this._framebuffer = this._framebuffer || new WEBGLFramebuffer(this.device, { handle: null });
2675
- return this._framebuffer;
2331
+ destroy() {
2332
+ if (this.handle) {
2333
+ this.device.gl.deleteSampler(this.handle);
2334
+ this.handle = void 0;
2335
+ }
2676
2336
  }
2677
- /** Resizes and updates render targets if necessary */
2678
- update() {
2679
- const size = this.getPixelSize();
2680
- const sizeChanged = size[0] !== this.presentationSize[0] || size[1] !== this.presentationSize[1];
2681
- if (sizeChanged) {
2682
- this.presentationSize = size;
2683
- this.resize();
2337
+ toString() {
2338
+ return `Sampler(${this.id},${JSON.stringify(this.props)})`;
2339
+ }
2340
+ /** Set sampler parameters on the sampler */
2341
+ _setSamplerParameters(parameters) {
2342
+ for (const [pname, value] of Object.entries(parameters)) {
2343
+ const param = Number(pname);
2344
+ switch (param) {
2345
+ case 33082:
2346
+ case 33083:
2347
+ this.device.gl.samplerParameterf(this.handle, param, value);
2348
+ break;
2349
+ default:
2350
+ this.device.gl.samplerParameteri(this.handle, param, value);
2351
+ break;
2352
+ }
2684
2353
  }
2685
2354
  }
2686
- /**
2687
- * Resize the canvas' drawing buffer.
2688
- *
2689
- * Can match the canvas CSS size, and optionally also consider devicePixelRatio
2690
- * Can be called every frame
2691
- *
2692
- * Regardless of size, the drawing buffer will always be scaled to the viewport, but
2693
- * for best visual results, usually set to either:
2694
- * canvas CSS width x canvas CSS height
2695
- * canvas CSS width * devicePixelRatio x canvas CSS height * devicePixelRatio
2696
- * See http://webgl2fundamentals.org/webgl/lessons/webgl-resizing-the-canvas.html
2697
- */
2698
- resize(options) {
2699
- if (!this.device.gl)
2700
- return;
2701
- if (this.canvas) {
2702
- const devicePixelRatio = this.getDevicePixelRatio(options == null ? void 0 : options.useDevicePixels);
2703
- this.setDevicePixelRatio(devicePixelRatio, options);
2704
- return;
2355
+ };
2356
+
2357
+ // dist/adapter/resources/webgl-texture.js
2358
+ var import_core14 = require("@luma.gl/core");
2359
+ var import_constants16 = require("@luma.gl/constants");
2360
+
2361
+ // dist/context/state-tracker/with-parameters.js
2362
+ function withGLParameters(gl, parameters, func) {
2363
+ if (isObjectEmpty3(parameters)) {
2364
+ return func(gl);
2365
+ }
2366
+ const { nocatch = true } = parameters;
2367
+ const webglState = WebGLStateTracker.get(gl);
2368
+ webglState.push();
2369
+ setGLParameters(gl, parameters);
2370
+ let value;
2371
+ if (nocatch) {
2372
+ value = func(gl);
2373
+ webglState.pop();
2374
+ } else {
2375
+ try {
2376
+ value = func(gl);
2377
+ } finally {
2378
+ webglState.pop();
2705
2379
  }
2706
2380
  }
2707
- commit() {
2381
+ return value;
2382
+ }
2383
+ function isObjectEmpty3(object) {
2384
+ for (const key in object) {
2385
+ return false;
2386
+ }
2387
+ return true;
2388
+ }
2389
+
2390
+ // dist/adapter/resources/webgl-texture-view.js
2391
+ var import_core12 = require("@luma.gl/core");
2392
+ var WEBGLTextureView = class extends import_core12.TextureView {
2393
+ device;
2394
+ gl;
2395
+ handle;
2396
+ // Does not have a WebGL representation
2397
+ texture;
2398
+ constructor(device, props) {
2399
+ super(device, { ...import_core12.Texture.defaultProps, ...props });
2400
+ this.device = device;
2401
+ this.gl = this.device.gl;
2402
+ this.handle = null;
2403
+ this.texture = props.texture;
2708
2404
  }
2709
2405
  };
2710
2406
 
2711
- // dist/context/debug/spector.js
2712
- var import_core11 = require("@luma.gl/core");
2407
+ // dist/adapter/helpers/webgl-texture-utils.js
2408
+ var import_core13 = require("@luma.gl/core");
2409
+ var import_constants15 = require("@luma.gl/constants");
2713
2410
 
2714
- // dist/utils/load-script.js
2715
- async function loadScript(scriptUrl, scriptId) {
2716
- const head = document.getElementsByTagName("head")[0];
2717
- if (!head) {
2718
- throw new Error("loadScript");
2411
+ // dist/adapter/helpers/typed-array-utils.js
2412
+ var import_constants13 = require("@luma.gl/constants");
2413
+ var ERR_TYPE_DEDUCTION = "Failed to deduce GL constant from typed array";
2414
+ function getGLTypeFromTypedArray(arrayOrType) {
2415
+ const type = ArrayBuffer.isView(arrayOrType) ? arrayOrType.constructor : arrayOrType;
2416
+ switch (type) {
2417
+ case Float32Array:
2418
+ return 5126;
2419
+ case Uint16Array:
2420
+ return 5123;
2421
+ case Uint32Array:
2422
+ return 5125;
2423
+ case Uint8Array:
2424
+ return 5121;
2425
+ case Uint8ClampedArray:
2426
+ return 5121;
2427
+ case Int8Array:
2428
+ return 5120;
2429
+ case Int16Array:
2430
+ return 5122;
2431
+ case Int32Array:
2432
+ return 5124;
2433
+ default:
2434
+ throw new Error(ERR_TYPE_DEDUCTION);
2719
2435
  }
2720
- const script = document.createElement("script");
2721
- script.setAttribute("type", "text/javascript");
2722
- script.setAttribute("src", scriptUrl);
2723
- if (scriptId) {
2724
- script.id = scriptId;
2436
+ }
2437
+ function getTypedArrayFromGLType(glType, options) {
2438
+ const { clamped = true } = options || {};
2439
+ switch (glType) {
2440
+ case 5126:
2441
+ return Float32Array;
2442
+ case 5123:
2443
+ case 33635:
2444
+ case 32819:
2445
+ case 32820:
2446
+ return Uint16Array;
2447
+ case 5125:
2448
+ return Uint32Array;
2449
+ case 5121:
2450
+ return clamped ? Uint8ClampedArray : Uint8Array;
2451
+ case 5120:
2452
+ return Int8Array;
2453
+ case 5122:
2454
+ return Int16Array;
2455
+ case 5124:
2456
+ return Int32Array;
2457
+ default:
2458
+ throw new Error("Failed to deduce typed array type from GL constant");
2725
2459
  }
2726
- return new Promise((resolve, reject) => {
2727
- script.onload = resolve;
2728
- script.onerror = (error) => reject(new Error(`Unable to load script '${scriptUrl}': ${error}`));
2729
- head.appendChild(script);
2730
- });
2731
2460
  }
2732
2461
 
2733
- // dist/context/debug/spector.js
2734
- var LOG_LEVEL = 1;
2735
- var spector = null;
2736
- var initialized = false;
2737
- var DEFAULT_SPECTOR_PROPS = {
2738
- debugWithSpectorJS: import_core11.log.get("spector") || import_core11.log.get("spectorjs"),
2739
- // https://github.com/BabylonJS/Spector.js#basic-usage
2740
- // https://forum.babylonjs.com/t/spectorcdn-is-temporarily-off/48241
2741
- // spectorUrl: 'https://spectorcdn.babylonjs.com/spector.bundle.js';
2742
- spectorUrl: "https://cdn.jsdelivr.net/npm/spectorjs@0.9.30/dist/spector.bundle.js",
2743
- gl: void 0
2744
- };
2745
- async function loadSpectorJS(props) {
2746
- if (!globalThis.SPECTOR) {
2747
- try {
2748
- await loadScript(props.spectorUrl || DEFAULT_SPECTOR_PROPS.spectorUrl);
2749
- } catch (error) {
2750
- import_core11.log.warn(String(error));
2751
- }
2462
+ // dist/adapter/helpers/format-utils.js
2463
+ var import_constants14 = require("@luma.gl/constants");
2464
+ function glFormatToComponents(format) {
2465
+ switch (format) {
2466
+ case 6406:
2467
+ case 33326:
2468
+ case 6403:
2469
+ return 1;
2470
+ case 33328:
2471
+ case 33319:
2472
+ return 2;
2473
+ case 6407:
2474
+ case 34837:
2475
+ return 3;
2476
+ case 6408:
2477
+ case 34836:
2478
+ return 4;
2479
+ default:
2480
+ return 0;
2752
2481
  }
2753
2482
  }
2754
- function initializeSpectorJS(props) {
2755
- var _a;
2756
- props = { ...DEFAULT_SPECTOR_PROPS, ...props };
2757
- if (!props.debugWithSpectorJS) {
2758
- return null;
2759
- }
2760
- if (!spector && globalThis.SPECTOR && !((_a = globalThis.luma) == null ? void 0 : _a.spector)) {
2761
- import_core11.log.probe(LOG_LEVEL, "SPECTOR found and initialized. Start with `luma.spector.displayUI()`")();
2762
- const { Spector } = globalThis.SPECTOR;
2763
- spector = new Spector();
2764
- if (globalThis.luma) {
2765
- globalThis.luma.spector = spector;
2766
- }
2767
- }
2768
- if (!spector) {
2769
- return null;
2483
+ function glTypeToBytes(type) {
2484
+ switch (type) {
2485
+ case 5121:
2486
+ return 1;
2487
+ case 33635:
2488
+ case 32819:
2489
+ case 32820:
2490
+ return 2;
2491
+ case 5126:
2492
+ return 4;
2493
+ default:
2494
+ return 0;
2770
2495
  }
2771
- if (!initialized) {
2772
- initialized = true;
2773
- spector.spyCanvases();
2774
- spector == null ? void 0 : spector.onCaptureStarted.add((capture) => import_core11.log.info("Spector capture started:", capture)());
2775
- spector == null ? void 0 : spector.onCapture.add((capture) => {
2776
- import_core11.log.info("Spector capture complete:", capture)();
2777
- spector == null ? void 0 : spector.getResultUI();
2778
- spector == null ? void 0 : spector.resultView.display();
2779
- spector == null ? void 0 : spector.resultView.addCapture(capture);
2780
- });
2496
+ }
2497
+
2498
+ // dist/adapter/helpers/webgl-texture-utils.js
2499
+ function initializeTextureStorage(gl, levels, options) {
2500
+ const { dimension, width, height, depth = 0 } = options;
2501
+ const { glInternalFormat } = options;
2502
+ const glTarget = options.glTarget;
2503
+ switch (dimension) {
2504
+ case "2d-array":
2505
+ case "3d":
2506
+ gl.texStorage3D(glTarget, levels, glInternalFormat, width, height, depth);
2507
+ break;
2508
+ default:
2509
+ gl.texStorage2D(glTarget, levels, glInternalFormat, width, height);
2781
2510
  }
2782
- if (props.gl) {
2783
- const gl = props.gl;
2784
- const device = gl.device;
2785
- spector == null ? void 0 : spector.startCapture(props.gl, 500);
2786
- gl.device = device;
2787
- new Promise((resolve) => setTimeout(resolve, 2e3)).then((_) => {
2788
- import_core11.log.info("Spector capture stopped after 2 seconds")();
2789
- spector == null ? void 0 : spector.stopCapture();
2790
- });
2511
+ }
2512
+ function copyExternalImageToMipLevel(gl, handle, image, options) {
2513
+ const { width, height } = options;
2514
+ const { dimension, depth = 0, mipLevel = 0 } = options;
2515
+ const { x = 0, y = 0, z = 0 } = options;
2516
+ const { glFormat, glType } = options;
2517
+ const glTarget = getWebGLCubeFaceTarget(options.glTarget, dimension, depth);
2518
+ switch (dimension) {
2519
+ case "2d-array":
2520
+ case "3d":
2521
+ gl.bindTexture(glTarget, handle);
2522
+ gl.texSubImage3D(glTarget, mipLevel, x, y, z, width, height, depth, glFormat, glType, image);
2523
+ gl.bindTexture(glTarget, null);
2524
+ break;
2525
+ case "2d":
2526
+ case "cube":
2527
+ gl.bindTexture(glTarget, handle);
2528
+ gl.texSubImage2D(glTarget, mipLevel, x, y, width, height, glFormat, glType, image);
2529
+ gl.bindTexture(glTarget, null);
2530
+ break;
2531
+ default:
2532
+ throw new Error(dimension);
2791
2533
  }
2792
- return spector;
2793
2534
  }
2794
-
2795
- // dist/context/debug/webgl-developer-tools.js
2796
- var import_core12 = require("@luma.gl/core");
2797
- var import_constants14 = require("@luma.gl/constants");
2798
- var import_env = require("@probe.gl/env");
2799
- var WEBGL_DEBUG_CDN_URL = "https://unpkg.com/webgl-debug@2.0.1/index.js";
2800
- function getWebGLContextData(gl) {
2801
- gl.luma = gl.luma || {};
2802
- return gl.luma;
2535
+ function copyCPUDataToMipLevel(gl, typedArray, options) {
2536
+ const { dimension, width, height, depth = 0, mipLevel = 0, byteOffset = 0 } = options;
2537
+ const { x = 0, y = 0, z = 0 } = options;
2538
+ const { glFormat, glType, compressed } = options;
2539
+ const glTarget = getWebGLCubeFaceTarget(options.glTarget, dimension, depth);
2540
+ switch (dimension) {
2541
+ case "2d-array":
2542
+ case "3d":
2543
+ if (compressed) {
2544
+ gl.compressedTexSubImage3D(glTarget, mipLevel, x, y, z, width, height, depth, glFormat, typedArray, byteOffset);
2545
+ } else {
2546
+ gl.texSubImage3D(glTarget, mipLevel, x, y, z, width, height, depth, glFormat, glType, typedArray, byteOffset);
2547
+ }
2548
+ break;
2549
+ case "2d":
2550
+ case "cube":
2551
+ if (compressed) {
2552
+ gl.compressedTexSubImage2D(glTarget, mipLevel, x, y, width, height, glFormat, typedArray, byteOffset);
2553
+ } else {
2554
+ gl.texSubImage2D(glTarget, mipLevel, x, y, width, height, glFormat, glType, typedArray, byteOffset);
2555
+ }
2556
+ break;
2557
+ default:
2558
+ throw new Error(dimension);
2559
+ }
2803
2560
  }
2804
- async function loadWebGLDeveloperTools() {
2805
- if ((0, import_env.isBrowser)() && !globalThis.WebGLDebugUtils) {
2806
- globalThis.global = globalThis.global || globalThis;
2807
- globalThis.global.module = {};
2808
- await loadScript(WEBGL_DEBUG_CDN_URL);
2561
+ function getWebGLTextureTarget(dimension) {
2562
+ switch (dimension) {
2563
+ case "1d":
2564
+ break;
2565
+ case "2d":
2566
+ return 3553;
2567
+ case "3d":
2568
+ return 32879;
2569
+ case "cube":
2570
+ return 34067;
2571
+ case "2d-array":
2572
+ return 35866;
2573
+ case "cube-array":
2574
+ break;
2809
2575
  }
2576
+ throw new Error(dimension);
2810
2577
  }
2811
- function makeDebugContext(gl, props = {}) {
2812
- return props.debug ? getDebugContext(gl, props) : getRealContext(gl);
2813
- }
2814
- function getRealContext(gl) {
2815
- const data = getWebGLContextData(gl);
2816
- return data.realContext ? data.realContext : gl;
2578
+ function getWebGLCubeFaceTarget(glTarget, dimension, level) {
2579
+ return dimension === "cube" ? 34069 + level : glTarget;
2817
2580
  }
2818
- function getDebugContext(gl, props) {
2819
- if (!globalThis.WebGLDebugUtils) {
2820
- import_core12.log.warn("webgl-debug not loaded")();
2821
- return gl;
2581
+ function readPixelsToArray(source, options) {
2582
+ var _a, _b, _c, _d, _e, _f;
2583
+ const {
2584
+ sourceX = 0,
2585
+ sourceY = 0,
2586
+ sourceAttachment = 36064
2587
+ // TODO - support gl.readBuffer
2588
+ } = options || {};
2589
+ let {
2590
+ target: target2 = null,
2591
+ // following parameters are auto deduced if not provided
2592
+ sourceWidth,
2593
+ sourceHeight,
2594
+ sourceDepth,
2595
+ sourceFormat,
2596
+ sourceType
2597
+ } = options || {};
2598
+ const { framebuffer, deleteFramebuffer } = getFramebuffer(source);
2599
+ const { gl, handle } = framebuffer;
2600
+ const attachment = sourceAttachment - 36064;
2601
+ sourceWidth ||= framebuffer.width;
2602
+ sourceHeight ||= framebuffer.height;
2603
+ sourceDepth = ((_b = (_a = framebuffer.colorAttachments[attachment]) == null ? void 0 : _a.texture) == null ? void 0 : _b.depth) || 1;
2604
+ sourceFormat ||= ((_d = (_c = framebuffer.colorAttachments[attachment]) == null ? void 0 : _c.texture) == null ? void 0 : _d.glFormat) || 6408;
2605
+ sourceType ||= ((_f = (_e = framebuffer.colorAttachments[attachment]) == null ? void 0 : _e.texture) == null ? void 0 : _f.glType) || 5121;
2606
+ target2 = getPixelArray(target2, sourceType, sourceFormat, sourceWidth, sourceHeight, sourceDepth);
2607
+ sourceType = sourceType || getGLTypeFromTypedArray(target2);
2608
+ const prevHandle = gl.bindFramebuffer(36160, handle);
2609
+ gl.readPixels(sourceX, sourceY, sourceWidth, sourceHeight, sourceFormat, sourceType, target2);
2610
+ gl.bindFramebuffer(36160, prevHandle || null);
2611
+ if (deleteFramebuffer) {
2612
+ framebuffer.destroy();
2822
2613
  }
2823
- const data = getWebGLContextData(gl);
2824
- if (data.debugContext) {
2825
- return data.debugContext;
2614
+ return target2;
2615
+ }
2616
+ function readPixelsToBuffer(source, options) {
2617
+ const { target: target2, sourceX = 0, sourceY = 0, sourceFormat = 6408, targetByteOffset = 0 } = options || {};
2618
+ let { sourceWidth, sourceHeight, sourceType } = options || {};
2619
+ const { framebuffer, deleteFramebuffer } = getFramebuffer(source);
2620
+ sourceWidth = sourceWidth || framebuffer.width;
2621
+ sourceHeight = sourceHeight || framebuffer.height;
2622
+ const webglFramebuffer = framebuffer;
2623
+ sourceType = sourceType || 5121;
2624
+ let webglBufferTarget = target2;
2625
+ if (!webglBufferTarget) {
2626
+ const components = glFormatToComponents(sourceFormat);
2627
+ const byteCount = glTypeToBytes(sourceType);
2628
+ const byteLength = targetByteOffset + sourceWidth * sourceHeight * components * byteCount;
2629
+ webglBufferTarget = webglFramebuffer.device.createBuffer({ byteLength });
2826
2630
  }
2827
- globalThis.WebGLDebugUtils.init({ ...import_constants14.GL, ...gl });
2828
- const glDebug = globalThis.WebGLDebugUtils.makeDebugContext(gl, onGLError.bind(null, props), onValidateGLFunc.bind(null, props));
2829
- for (const key in import_constants14.GL) {
2830
- if (!(key in glDebug) && typeof import_constants14.GL[key] === "number") {
2831
- glDebug[key] = import_constants14.GL[key];
2832
- }
2631
+ const commandEncoder = source.device.createCommandEncoder();
2632
+ commandEncoder.copyTextureToBuffer({
2633
+ sourceTexture: source,
2634
+ width: sourceWidth,
2635
+ height: sourceHeight,
2636
+ origin: [sourceX, sourceY],
2637
+ destinationBuffer: webglBufferTarget,
2638
+ byteOffset: targetByteOffset
2639
+ });
2640
+ commandEncoder.destroy();
2641
+ if (deleteFramebuffer) {
2642
+ framebuffer.destroy();
2833
2643
  }
2834
- class WebGLDebugContext {
2644
+ return webglBufferTarget;
2645
+ }
2646
+ function getFramebuffer(source) {
2647
+ if (!(source instanceof import_core13.Framebuffer)) {
2648
+ return { framebuffer: toFramebuffer(source), deleteFramebuffer: true };
2835
2649
  }
2836
- Object.setPrototypeOf(glDebug, Object.getPrototypeOf(gl));
2837
- Object.setPrototypeOf(WebGLDebugContext, glDebug);
2838
- const debugContext = Object.create(WebGLDebugContext);
2839
- data.realContext = gl;
2840
- data.debugContext = debugContext;
2841
- debugContext.debug = true;
2842
- return debugContext;
2650
+ return { framebuffer: source, deleteFramebuffer: false };
2843
2651
  }
2844
- function getFunctionString(functionName, functionArgs) {
2845
- functionArgs = Array.from(functionArgs).map((arg) => arg === void 0 ? "undefined" : arg);
2846
- let args = globalThis.WebGLDebugUtils.glFunctionArgsToString(functionName, functionArgs);
2847
- args = `${args.slice(0, 100)}${args.length > 100 ? "..." : ""}`;
2848
- return `gl.${functionName}(${args})`;
2652
+ function toFramebuffer(texture, props) {
2653
+ const { device, width, height, id } = texture;
2654
+ const framebuffer = device.createFramebuffer({
2655
+ ...props,
2656
+ id: `framebuffer-for-${id}`,
2657
+ width,
2658
+ height,
2659
+ colorAttachments: [texture]
2660
+ });
2661
+ return framebuffer;
2849
2662
  }
2850
- function onGLError(props, err, functionName, args) {
2851
- args = Array.from(args).map((arg) => arg === void 0 ? "undefined" : arg);
2852
- const errorMessage = globalThis.WebGLDebugUtils.glEnumToString(err);
2853
- const functionArgs = globalThis.WebGLDebugUtils.glFunctionArgsToString(functionName, args);
2854
- const message2 = `${errorMessage} in gl.${functionName}(${functionArgs})`;
2855
- import_core12.log.error(message2)();
2856
- debugger;
2857
- if (props.throwOnError) {
2858
- throw new Error(message2);
2663
+ function getPixelArray(pixelArray, type, format, width, height, depth) {
2664
+ if (pixelArray) {
2665
+ return pixelArray;
2859
2666
  }
2667
+ type = type || 5121;
2668
+ const ArrayType = getTypedArrayFromGLType(type, { clamped: false });
2669
+ const components = glFormatToComponents(format);
2670
+ return new ArrayType(width * height * components);
2860
2671
  }
2861
- function onValidateGLFunc(props, functionName, functionArgs) {
2862
- let functionString = "";
2863
- if (import_core12.log.level >= 1) {
2864
- functionString = getFunctionString(functionName, functionArgs);
2865
- import_core12.log.log(1, functionString)();
2866
- }
2867
- if (props.break && props.break.length > 0) {
2868
- functionString = functionString || getFunctionString(functionName, functionArgs);
2869
- const isBreakpoint = props.break.every((breakOn) => functionString.indexOf(breakOn) !== -1);
2870
- if (isBreakpoint) {
2871
- debugger;
2872
- }
2873
- }
2874
- for (const arg of functionArgs) {
2875
- if (arg === void 0) {
2876
- functionString = functionString || getFunctionString(functionName, functionArgs);
2877
- if (props.throwOnError) {
2878
- throw new Error(`Undefined argument: ${functionString}`);
2879
- } else {
2880
- import_core12.log.error(`Undefined argument: ${functionString}`)();
2881
- debugger;
2672
+
2673
+ // dist/adapter/resources/webgl-texture.js
2674
+ function normalizeTextureData(data, options) {
2675
+ let lodArray;
2676
+ if (ArrayBuffer.isView(data)) {
2677
+ lodArray = [
2678
+ {
2679
+ // ts-expect-error does data really need to be Uint8ClampedArray?
2680
+ data,
2681
+ width: options.width,
2682
+ height: options.height
2683
+ // depth: options.depth
2882
2684
  }
2883
- }
2685
+ ];
2686
+ } else if (!Array.isArray(data)) {
2687
+ lodArray = [data];
2688
+ } else {
2689
+ lodArray = data;
2884
2690
  }
2691
+ return lodArray;
2885
2692
  }
2886
-
2887
- // dist/utils/uid.js
2888
- var uidCounters = {};
2889
- function uid(id = "id") {
2890
- uidCounters[id] = uidCounters[id] || 1;
2891
- const count = uidCounters[id]++;
2892
- return `${id}-${count}`;
2893
- }
2894
-
2895
- // dist/adapter/resources/webgl-buffer.js
2896
- var import_core13 = require("@luma.gl/core");
2897
- var import_constants15 = require("@luma.gl/constants");
2898
- var WEBGLBuffer = class extends import_core13.Buffer {
2693
+ var WEBGLTexture = class extends import_core14.Texture {
2694
+ MAX_ATTRIBUTES;
2899
2695
  device;
2900
2696
  gl;
2901
2697
  handle;
2902
- /** Target in OpenGL defines the type of buffer */
2698
+ sampler = void 0;
2699
+ // TODO - currently unused in WebGL. Create dummy sampler?
2700
+ view = void 0;
2701
+ // TODO - currently unused in WebGL. Create dummy view?
2702
+ mipmaps = false;
2703
+ /**
2704
+ * @note `target` cannot be modified by bind:
2705
+ * textures are special because when you first bind them to a target,
2706
+ * When you first bind a texture as a GL_TEXTURE_2D, you are saying that this texture is a 2D texture.
2707
+ * And it will always be a 2D texture; this state cannot be changed ever.
2708
+ * A texture that was first bound as a GL_TEXTURE_2D, must always be bound as a GL_TEXTURE_2D;
2709
+ * attempting to bind it as GL_TEXTURE_3D will give rise to a run-time error
2710
+ */
2903
2711
  glTarget;
2904
- /** Usage is a hint on how frequently the buffer will be updates */
2905
- glUsage;
2906
- /** Index type is needed when issuing draw calls, so we pre-compute it */
2907
- glIndexType = 5123;
2908
- /** Number of bytes allocated on the GPU for this buffer */
2909
- byteLength;
2910
- /** Number of bytes used */
2911
- bytesUsed;
2912
- constructor(device, props = {}) {
2913
- super(device, props);
2712
+ // Texture type
2713
+ /** The WebGL format - essentially channel structure */
2714
+ glFormat;
2715
+ /** The WebGL data format - the type of each channel */
2716
+ glType;
2717
+ /** The WebGL constant corresponding to the WebGPU style constant in format */
2718
+ glInternalFormat;
2719
+ /** Whether the internal format is compressed */
2720
+ compressed;
2721
+ // data;
2722
+ // inherited props
2723
+ // dimension: ...
2724
+ // format: GLTextureTarget;
2725
+ // width: number = undefined;
2726
+ // height: number = undefined;
2727
+ // depth: number = undefined;
2728
+ // state
2729
+ /** Texture binding slot */
2730
+ textureUnit = 0;
2731
+ /** For automatically updating video */
2732
+ _video = null;
2733
+ constructor(device, props) {
2734
+ props = import_core14.Texture._fixProps(props);
2735
+ super(device, { ...import_core14.Texture.defaultProps, ...props, data: void 0 });
2914
2736
  this.device = device;
2915
2737
  this.gl = this.device.gl;
2916
- const handle = typeof props === "object" ? props.handle : void 0;
2917
- this.handle = handle || this.gl.createBuffer();
2918
- device.setSpectorMetadata(this.handle, { ...this.props, data: typeof this.props.data });
2919
- this.glTarget = getWebGLTarget(this.props.usage);
2920
- this.glUsage = getWebGLUsage(this.props.usage);
2921
- this.glIndexType = this.props.indexType === "uint32" ? 5125 : 5123;
2922
- if (props.data) {
2923
- this._initWithData(props.data, props.byteOffset, props.byteLength);
2924
- } else {
2925
- this._initWithByteLength(props.byteLength || 0);
2738
+ this.glTarget = getWebGLTextureTarget(this.props.dimension);
2739
+ const format = getTextureFormatWebGL(this.props.format);
2740
+ this.glInternalFormat = format.internalFormat;
2741
+ this.glFormat = format.format;
2742
+ this.glType = format.type;
2743
+ this.compressed = format.compressed;
2744
+ if (typeof HTMLVideoElement !== "undefined" && props.data instanceof HTMLVideoElement && // @ts-expect-error
2745
+ props.data.readyState < HTMLVideoElement.HAVE_METADATA) {
2746
+ const video = props.data;
2747
+ this._video = null;
2748
+ video.addEventListener("loadeddata", () => this.initialize(props));
2749
+ }
2750
+ this.initialize({ ...this.props, data: props.data });
2751
+ Object.seal(this);
2752
+ }
2753
+ /**
2754
+ * Initialize texture with supplied props
2755
+ */
2756
+ // eslint-disable-next-line max-statements
2757
+ initialize(props = {}) {
2758
+ this.handle = this.props.handle || this.gl.createTexture();
2759
+ this.device.setSpectorMetadata(this.handle, { ...this.props, data: typeof this.props.data });
2760
+ const data = props.data;
2761
+ let { width, height } = props;
2762
+ if (!width || !height) {
2763
+ const textureSize = import_core14.Texture.getTextureDataSize(data);
2764
+ width = (textureSize == null ? void 0 : textureSize.width) || 1;
2765
+ height = (textureSize == null ? void 0 : textureSize.height) || 1;
2766
+ }
2767
+ this.width = width;
2768
+ this.height = height;
2769
+ this.depth = props.depth;
2770
+ this.setSampler(props.sampler);
2771
+ this.view = new WEBGLTextureView(this.device, { ...this.props, texture: this });
2772
+ this.bind();
2773
+ if (!this.props.data) {
2774
+ initializeTextureStorage(this.gl, this.mipLevels, this);
2926
2775
  }
2927
- }
2928
- // PRIVATE METHODS
2929
- /** Allocate a new buffer and initialize to contents of typed array */
2930
- _initWithData(data, byteOffset = 0, byteLength = data.byteLength + byteOffset) {
2931
- const glTarget = this.glTarget;
2932
- this.gl.bindBuffer(glTarget, this.handle);
2933
- this.gl.bufferData(glTarget, byteLength, this.glUsage);
2934
- this.gl.bufferSubData(glTarget, byteOffset, data);
2935
- this.gl.bindBuffer(glTarget, null);
2936
- this.bytesUsed = byteLength;
2937
- this.byteLength = byteLength;
2938
- this._setDebugData(data, byteOffset, byteLength);
2939
- this.trackAllocatedMemory(byteLength);
2940
- }
2941
- // Allocate a GPU buffer of specified size.
2942
- _initWithByteLength(byteLength) {
2943
- let data = byteLength;
2944
- if (byteLength === 0) {
2945
- data = new Float32Array(0);
2776
+ if (props.data) {
2777
+ switch (props.dimension) {
2778
+ case "1d":
2779
+ this.setTexture1DData(props.data);
2780
+ break;
2781
+ case "2d":
2782
+ this.setTexture2DData(props.data);
2783
+ break;
2784
+ case "3d":
2785
+ this.setTexture3DData(props.data);
2786
+ break;
2787
+ case "cube":
2788
+ this.setTextureCubeData(props.data);
2789
+ break;
2790
+ case "2d-array":
2791
+ this.setTextureArrayData(props.data);
2792
+ break;
2793
+ case "cube-array":
2794
+ this.setTextureCubeArrayData(props.data);
2795
+ break;
2796
+ default:
2797
+ throw new Error(props.dimension);
2798
+ }
2799
+ }
2800
+ this.mipmaps = Boolean(props.mipmaps);
2801
+ if (this.mipmaps) {
2802
+ this.generateMipmap();
2946
2803
  }
2947
- const glTarget = this.glTarget;
2948
- this.gl.bindBuffer(glTarget, this.handle);
2949
- this.gl.bufferData(glTarget, data, this.glUsage);
2950
- this.gl.bindBuffer(glTarget, null);
2951
- this.bytesUsed = byteLength;
2952
- this.byteLength = byteLength;
2953
- this._setDebugData(null, 0, byteLength);
2954
- this.trackAllocatedMemory(byteLength);
2955
- return this;
2956
2804
  }
2805
+ /*
2806
+ initializeCube(props?: TextureProps): void {
2807
+ const {mipmaps = true} = props; // , parameters = {} as Record<GL, any>} = props;
2808
+
2809
+ // Store props for accessors
2810
+ // this.props = props;
2811
+
2812
+ // @ts-expect-error
2813
+ this.setCubeMapData(props).then(() => {
2814
+ // TODO - should genMipmap() be called on the cubemap or on the faces?
2815
+ // TODO - without generateMipmap() cube textures do not work at all!!! Why?
2816
+ if (mipmaps) {
2817
+ this.generateMipmap(props);
2818
+ }
2819
+
2820
+ this.setSampler(props.sampler);
2821
+
2822
+ // v8 compatibility?
2823
+ // const {parameters = {} as Record<GL, any>} = props;
2824
+ // this._setSamplerParameters(parameters);
2825
+ });
2826
+ }
2827
+ */
2957
2828
  destroy() {
2958
- if (!this.destroyed && this.handle) {
2829
+ if (this.handle) {
2830
+ this.gl.deleteTexture(this.handle);
2959
2831
  this.removeStats();
2960
- this.trackDeallocatedMemory();
2961
- this.gl.deleteBuffer(this.handle);
2832
+ this.trackDeallocatedMemory("Texture");
2962
2833
  this.destroyed = true;
2963
- this.handle = null;
2964
- }
2965
- }
2966
- write(data, byteOffset = 0) {
2967
- const srcOffset = 0;
2968
- const byteLength = void 0;
2969
- const glTarget = 36663;
2970
- this.gl.bindBuffer(glTarget, this.handle);
2971
- if (srcOffset !== 0 || byteLength !== void 0) {
2972
- this.gl.bufferSubData(glTarget, byteOffset, data, srcOffset, byteLength);
2973
- } else {
2974
- this.gl.bufferSubData(glTarget, byteOffset, data);
2975
2834
  }
2976
- this.gl.bindBuffer(glTarget, null);
2977
- this._setDebugData(data, byteOffset, data.byteLength);
2978
- }
2979
- /** Asynchronously read data from the buffer */
2980
- async readAsync(byteOffset = 0, byteLength) {
2981
- return this.readSyncWebGL(byteOffset, byteLength);
2982
2835
  }
2983
- /** Synchronously read data from the buffer. WebGL only. */
2984
- readSyncWebGL(byteOffset = 0, byteLength) {
2985
- byteLength = byteLength ?? this.byteLength - byteOffset;
2986
- const data = new Uint8Array(byteLength);
2987
- const dstOffset = 0;
2988
- this.gl.bindBuffer(36662, this.handle);
2989
- this.gl.getBufferSubData(36662, byteOffset, data, dstOffset, byteLength);
2990
- this.gl.bindBuffer(36662, null);
2991
- this._setDebugData(data, byteOffset, byteLength);
2992
- return data;
2836
+ toString() {
2837
+ return `Texture(${this.id},${this.width}x${this.height})`;
2993
2838
  }
2994
- };
2995
- function getWebGLTarget(usage) {
2996
- if (usage & import_core13.Buffer.INDEX) {
2997
- return 34963;
2839
+ createView(props) {
2840
+ return new WEBGLTextureView(this.device, { ...props, texture: this });
2998
2841
  }
2999
- if (usage & import_core13.Buffer.VERTEX) {
3000
- return 34962;
2842
+ setSampler(sampler = {}) {
2843
+ let samplerProps;
2844
+ if (sampler instanceof WEBGLSampler) {
2845
+ this.sampler = sampler;
2846
+ samplerProps = sampler.props;
2847
+ } else {
2848
+ this.sampler = new WEBGLSampler(this.device, sampler);
2849
+ samplerProps = sampler;
2850
+ }
2851
+ const parameters = convertSamplerParametersToWebGL(samplerProps);
2852
+ this._setSamplerParameters(parameters);
3001
2853
  }
3002
- if (usage & import_core13.Buffer.UNIFORM) {
3003
- return 35345;
2854
+ /** Update external texture (video frame or canvas) */
2855
+ update() {
2856
+ import_core14.log.warn("Texture.update() not implemented");
3004
2857
  }
3005
- return 34962;
3006
- }
3007
- function getWebGLUsage(usage) {
3008
- if (usage & import_core13.Buffer.INDEX) {
3009
- return 35044;
2858
+ // Call to regenerate mipmaps after modifying texture(s)
2859
+ generateMipmap(params = {}) {
2860
+ if (!this.props.data) {
2861
+ return;
2862
+ }
2863
+ this.mipmaps = true;
2864
+ this.gl.bindTexture(this.glTarget, this.handle);
2865
+ withGLParameters(this.gl, params, () => {
2866
+ this.gl.generateMipmap(this.glTarget);
2867
+ });
2868
+ this.gl.bindTexture(this.glTarget, null);
3010
2869
  }
3011
- if (usage & import_core13.Buffer.VERTEX) {
3012
- return 35044;
2870
+ // Image Data Setters
2871
+ copyExternalImage(options) {
2872
+ const size = import_core14.Texture.getExternalImageSize(options.image);
2873
+ const opts = { ...import_core14.Texture.defaultCopyExternalImageOptions, ...size, ...options };
2874
+ const { image, depth, mipLevel, x, y, z } = opts;
2875
+ let { width, height } = opts;
2876
+ const { dimension, glTarget, glFormat, glInternalFormat, glType } = this;
2877
+ width = Math.min(width, size.width - x);
2878
+ height = Math.min(height, size.height - y);
2879
+ if (options.sourceX || options.sourceY) {
2880
+ throw new Error("WebGL does not yet support sourceX/sourceY in copyExternalImage; requires copyTexSubImage2D from a framebuffer");
2881
+ }
2882
+ copyExternalImageToMipLevel(this.device.gl, this.handle, image, {
2883
+ dimension,
2884
+ mipLevel,
2885
+ x,
2886
+ y,
2887
+ z,
2888
+ width,
2889
+ height,
2890
+ depth,
2891
+ glFormat,
2892
+ glInternalFormat,
2893
+ glType,
2894
+ glTarget
2895
+ });
2896
+ return { width: opts.width, height: opts.height };
3013
2897
  }
3014
- if (usage & import_core13.Buffer.UNIFORM) {
3015
- return 35048;
2898
+ setTexture1DData(data) {
2899
+ throw new Error("setTexture1DData not supported in WebGL.");
3016
2900
  }
3017
- return 35044;
3018
- }
3019
-
3020
- // dist/adapter/resources/webgl-shader.js
3021
- var import_core14 = require("@luma.gl/core");
3022
- var import_constants16 = require("@luma.gl/constants");
3023
-
3024
- // dist/adapter/helpers/parse-shader-compiler-log.js
3025
- function parseShaderCompilerLog(errLog) {
3026
- const lines = errLog.split(/\r?\n/);
3027
- const messages = [];
3028
- for (const line of lines) {
3029
- if (line.length <= 1) {
3030
- continue;
3031
- }
3032
- const segments = line.split(":");
3033
- if (segments.length === 2) {
3034
- const [messageType2, message2] = segments;
3035
- messages.push({
3036
- message: message2.trim(),
3037
- type: getMessageType(messageType2),
3038
- lineNum: 0,
3039
- linePos: 0
3040
- });
3041
- continue;
3042
- }
3043
- const [messageType, linePosition, lineNumber, ...rest] = segments;
3044
- let lineNum = parseInt(lineNumber, 10);
3045
- if (isNaN(lineNum)) {
3046
- lineNum = 0;
2901
+ /** Set a simple texture */
2902
+ setTexture2DData(lodData, depth = 0) {
2903
+ this.bind();
2904
+ const lodArray = normalizeTextureData(lodData, this);
2905
+ if (lodArray.length > 1 && this.props.mipmaps !== false) {
2906
+ import_core14.log.warn(`Texture ${this.id} mipmap and multiple LODs.`)();
3047
2907
  }
3048
- let linePos = parseInt(linePosition, 10);
3049
- if (isNaN(linePos)) {
3050
- linePos = 0;
2908
+ for (let lodLevel = 0; lodLevel < lodArray.length; lodLevel++) {
2909
+ const imageData = lodArray[lodLevel];
2910
+ this._setMipLevel(depth, lodLevel, imageData);
3051
2911
  }
3052
- messages.push({
3053
- message: rest.join(":").trim(),
3054
- type: getMessageType(messageType),
3055
- lineNum,
3056
- linePos
3057
- // TODO
3058
- });
2912
+ this.unbind();
3059
2913
  }
3060
- return messages;
3061
- }
3062
- function getMessageType(messageType) {
3063
- const MESSAGE_TYPES = ["warning", "error", "info"];
3064
- const lowerCaseType = messageType.toLowerCase();
3065
- return MESSAGE_TYPES.includes(lowerCaseType) ? lowerCaseType : "info";
3066
- }
3067
-
3068
- // dist/adapter/resources/webgl-shader.js
3069
- var WEBGLShader = class extends import_core14.Shader {
3070
- device;
3071
- handle;
3072
- constructor(device, props) {
3073
- super(device, props);
3074
- this.device = device;
3075
- switch (this.props.stage) {
3076
- case "vertex":
3077
- this.handle = this.props.handle || this.device.gl.createShader(35633);
3078
- break;
3079
- case "fragment":
3080
- this.handle = this.props.handle || this.device.gl.createShader(35632);
3081
- break;
3082
- default:
3083
- throw new Error(this.props.stage);
2914
+ /**
2915
+ * Sets a 3D texture
2916
+ * @param data
2917
+ */
2918
+ setTexture3DData(data) {
2919
+ if (this.props.dimension !== "3d") {
2920
+ throw new Error(this.id);
2921
+ }
2922
+ if (ArrayBuffer.isView(data)) {
2923
+ this.bind();
2924
+ copyCPUDataToMipLevel(this.device.gl, data, this);
2925
+ this.unbind();
3084
2926
  }
3085
- this._compile(this.source);
3086
2927
  }
3087
- destroy() {
3088
- if (this.handle) {
3089
- this.removeStats();
3090
- this.device.gl.deleteShader(this.handle);
3091
- this.destroyed = true;
2928
+ /**
2929
+ * Set a Texture Cube Data
2930
+ * @todo - could support TextureCubeArray with depth
2931
+ * @param data
2932
+ * @param index
2933
+ */
2934
+ setTextureCubeData(data, depth = 0) {
2935
+ if (this.props.dimension !== "cube") {
2936
+ throw new Error(this.id);
2937
+ }
2938
+ for (const face of import_core14.Texture.CubeFaces) {
2939
+ this.setTextureCubeFaceData(data[face], face);
3092
2940
  }
3093
2941
  }
3094
- async getCompilationInfo() {
3095
- await this._waitForCompilationComplete();
3096
- return this.getCompilationInfoSync();
2942
+ /**
2943
+ * Sets an entire texture array
2944
+ * @param data
2945
+ */
2946
+ setTextureArrayData(data) {
2947
+ if (this.props.dimension !== "2d-array") {
2948
+ throw new Error(this.id);
2949
+ }
2950
+ throw new Error("setTextureArrayData not implemented.");
3097
2951
  }
3098
- getCompilationInfoSync() {
3099
- const log12 = this.device.gl.getShaderInfoLog(this.handle);
3100
- return log12 ? parseShaderCompilerLog(log12) : [];
2952
+ /**
2953
+ * Sets an entire texture cube array
2954
+ * @param data
2955
+ */
2956
+ setTextureCubeArrayData(data) {
2957
+ throw new Error("setTextureCubeArrayData not supported in WebGL2.");
3101
2958
  }
3102
- getTranslatedSource() {
3103
- const extensions = this.device.getExtension("WEBGL_debug_shaders");
3104
- const ext = extensions.WEBGL_debug_shaders;
3105
- return (ext == null ? void 0 : ext.getTranslatedShaderSource(this.handle)) || null;
2959
+ setTextureCubeFaceData(lodData, face, depth = 0) {
2960
+ if (Array.isArray(lodData) && lodData.length > 1 && this.props.mipmaps !== false) {
2961
+ import_core14.log.warn(`${this.id} has mipmap and multiple LODs.`)();
2962
+ }
2963
+ const faceDepth = import_core14.Texture.CubeFaces.indexOf(face);
2964
+ this.setTexture2DData(lodData, faceDepth);
3106
2965
  }
3107
- // PRIVATE METHODS
3108
- /** Compile a shader and get compilation status */
3109
- async _compile(source) {
3110
- const addGLSLVersion = (source2) => source2.startsWith("#version ") ? source2 : `#version 300 es
3111
- ${source2}`;
3112
- source = addGLSLVersion(source);
3113
- const { gl } = this.device;
3114
- gl.shaderSource(this.handle, source);
3115
- gl.compileShader(this.handle);
3116
- if (import_core14.log.level === 0) {
3117
- this.compilationStatus = "pending";
3118
- return;
2966
+ // INTERNAL METHODS
2967
+ /** @todo update this method to accept LODs */
2968
+ setImageDataForFace(options) {
2969
+ const {
2970
+ face,
2971
+ width,
2972
+ height,
2973
+ pixels,
2974
+ data,
2975
+ format = 6408,
2976
+ type = 5121
2977
+ // generateMipmap = false // TODO
2978
+ } = options;
2979
+ const { gl } = this;
2980
+ const imageData = pixels || data;
2981
+ this.bind();
2982
+ if (imageData instanceof Promise) {
2983
+ imageData.then((resolvedImageData) => this.setImageDataForFace(Object.assign({}, options, {
2984
+ face,
2985
+ data: resolvedImageData,
2986
+ pixels: resolvedImageData
2987
+ })));
2988
+ } else if (this.width || this.height) {
2989
+ gl.texImage2D(face, 0, format, width, height, 0, format, type, imageData);
2990
+ } else {
2991
+ gl.texImage2D(face, 0, format, format, type, imageData);
3119
2992
  }
3120
- if (!this.device.features.has("compilation-status-async-webgl")) {
3121
- this._getCompilationStatus();
3122
- this.debugShader();
3123
- if (this.compilationStatus === "error") {
3124
- throw new Error(`GLSL compilation errors in ${this.props.stage} shader ${this.props.id}`);
2993
+ }
2994
+ _getImageDataMap(faceData) {
2995
+ for (let i = 0; i < import_core14.Texture.CubeFaces.length; ++i) {
2996
+ const faceName = import_core14.Texture.CubeFaces[i];
2997
+ if (faceData[faceName]) {
2998
+ faceData[34069 + i] = faceData[faceName];
2999
+ delete faceData[faceName];
3125
3000
  }
3126
- return;
3127
3001
  }
3128
- import_core14.log.once(1, "Shader compilation is asynchronous")();
3129
- await this._waitForCompilationComplete();
3130
- import_core14.log.info(2, `Shader ${this.id} - async compilation complete: ${this.compilationStatus}`)();
3131
- this._getCompilationStatus();
3132
- this.debugShader();
3002
+ return faceData;
3133
3003
  }
3134
- /** Use KHR_parallel_shader_compile extension if available */
3135
- async _waitForCompilationComplete() {
3136
- const waitMs = async (ms) => await new Promise((resolve) => setTimeout(resolve, ms));
3137
- const DELAY_MS = 10;
3138
- if (!this.device.features.has("compilation-status-async-webgl")) {
3139
- await waitMs(DELAY_MS);
3140
- return;
3141
- }
3142
- const { gl } = this.device;
3143
- for (; ; ) {
3144
- const complete = gl.getShaderParameter(this.handle, 37297);
3145
- if (complete) {
3146
- return;
3004
+ // RESOURCE METHODS
3005
+ /**
3006
+ * Sets sampler parameters on texture
3007
+ */
3008
+ _setSamplerParameters(parameters) {
3009
+ import_core14.log.log(1, "texture sampler parameters", parameters)();
3010
+ this.gl.bindTexture(this.glTarget, this.handle);
3011
+ for (const [pname, pvalue] of Object.entries(parameters)) {
3012
+ const param = Number(pname);
3013
+ const value = pvalue;
3014
+ switch (param) {
3015
+ case 33082:
3016
+ case 33083:
3017
+ this.gl.texParameterf(this.glTarget, param, value);
3018
+ break;
3019
+ case 10241:
3020
+ this.gl.texParameteri(this.glTarget, param, value);
3021
+ break;
3022
+ case 10242:
3023
+ case 10243:
3024
+ this.gl.texParameteri(this.glTarget, param, value);
3025
+ break;
3026
+ case 34046:
3027
+ if (this.device.features.has("texture-filterable-anisotropic-webgl")) {
3028
+ this.gl.texParameteri(this.glTarget, param, value);
3029
+ }
3030
+ break;
3031
+ default:
3032
+ this.gl.texParameteri(this.glTarget, param, value);
3033
+ break;
3147
3034
  }
3148
- await waitMs(DELAY_MS);
3149
3035
  }
3036
+ this.gl.bindTexture(this.glTarget, null);
3150
3037
  }
3038
+ // CLASSIC
3039
+ /*
3040
+ setCubeMapData(options: {
3041
+ width: number;
3042
+ height: number;
3043
+ data: Record<GL, Texture2DData> | Record<TextureCubeFace, Texture2DData>;
3044
+ format?: any;
3045
+ type?: any;
3046
+ /** @deprecated Use .data *
3047
+ pixels: any;
3048
+ }): void {
3049
+ const {gl} = this;
3050
+
3051
+ const {width, height, pixels, data, format = GL.RGBA, type = GL.UNSIGNED_BYTE} = options;
3052
+
3053
+ // pixel data (imageDataMap) is an Object from Face to Image or Promise.
3054
+ // For example:
3055
+ // {
3056
+ // GL.TEXTURE_CUBE_MAP_POSITIVE_X : Image-or-Promise,
3057
+ // GL.TEXTURE_CUBE_MAP_NEGATIVE_X : Image-or-Promise,
3058
+ // ... }
3059
+ // To provide multiple level-of-details (LODs) this can be Face to Array
3060
+ // of Image or Promise, like this
3061
+ // {
3062
+ // GL.TEXTURE_CUBE_MAP_POSITIVE_X : [Image-or-Promise-LOD-0, Image-or-Promise-LOD-1],
3063
+ // GL.TEXTURE_CUBE_MAP_NEGATIVE_X : [Image-or-Promise-LOD-0, Image-or-Promise-LOD-1],
3064
+ // ... }
3065
+
3066
+ const imageDataMap = this._getImageDataMap(pixels || data);
3067
+
3068
+ const resolvedFaces = WEBGLTexture.FACES.map(face => {
3069
+ const facePixels = imageDataMap[face];
3070
+ return Array.isArray(facePixels) ? facePixels : [facePixels];
3071
+ });
3072
+ this.bind();
3073
+
3074
+ WEBGLTexture.FACES.forEach((face, index) => {
3075
+ if (resolvedFaces[index].length > 1 && this.props.mipmaps !== false) {
3076
+ // If the user provides multiple LODs, then automatic mipmap
3077
+ // generation generateMipmap() should be disabled to avoid overwritting them.
3078
+ log.warn(`${this.id} has mipmap and multiple LODs.`)();
3079
+ }
3080
+ resolvedFaces[index].forEach((image, lodLevel) => {
3081
+ // TODO: adjust width & height for LOD!
3082
+ if (width && height) {
3083
+ gl.texImage2D(face, lodLevel, format, width, height, 0 /* border*, format, type, image);
3084
+ } else {
3085
+ gl.texImage2D(face, lodLevel, format, format, type, image);
3086
+ }
3087
+ });
3088
+ });
3089
+
3090
+ this.unbind();
3091
+ }
3092
+ */
3093
+ // INTERNAL SETTERS
3151
3094
  /**
3152
- * Get the shader compilation status
3153
- * TODO - Load log even when no error reported, to catch warnings?
3154
- * https://gamedev.stackexchange.com/questions/30429/how-to-detect-glsl-warnings
3095
+ * Copy a region of data from a CPU memory buffer into this texture.
3096
+ * @todo - GLUnpackParameters parameters
3155
3097
  */
3156
- _getCompilationStatus() {
3157
- this.compilationStatus = this.device.gl.getShaderParameter(this.handle, 35713) ? "success" : "error";
3098
+ _setMipLevel(depth, mipLevel, textureData, glTarget = this.glTarget) {
3099
+ if (import_core14.Texture.isExternalImage(textureData)) {
3100
+ copyExternalImageToMipLevel(this.device.gl, this.handle, textureData, {
3101
+ ...this,
3102
+ depth,
3103
+ mipLevel,
3104
+ glTarget
3105
+ });
3106
+ return;
3107
+ }
3108
+ if (import_core14.Texture.isTextureLevelData(textureData)) {
3109
+ copyCPUDataToMipLevel(this.device.gl, textureData.data, {
3110
+ ...this,
3111
+ depth,
3112
+ mipLevel,
3113
+ glTarget
3114
+ });
3115
+ return;
3116
+ }
3117
+ throw new Error("Texture: invalid image data");
3118
+ }
3119
+ // HELPERS
3120
+ getActiveUnit() {
3121
+ return this.gl.getParameter(34016) - 33984;
3122
+ }
3123
+ bind(textureUnit) {
3124
+ const { gl } = this;
3125
+ if (textureUnit !== void 0) {
3126
+ this.textureUnit = textureUnit;
3127
+ gl.activeTexture(33984 + textureUnit);
3128
+ }
3129
+ gl.bindTexture(this.glTarget, this.handle);
3130
+ return textureUnit;
3131
+ }
3132
+ unbind(textureUnit) {
3133
+ const { gl } = this;
3134
+ if (textureUnit !== void 0) {
3135
+ this.textureUnit = textureUnit;
3136
+ gl.activeTexture(33984 + textureUnit);
3137
+ }
3138
+ gl.bindTexture(this.glTarget, null);
3139
+ return textureUnit;
3158
3140
  }
3159
3141
  };
3160
3142
 
@@ -3780,9 +3762,9 @@ var WEBGLRenderPipeline = class extends import_core16.RenderPipeline {
3780
3762
  */
3781
3763
  setBindings(bindings, options) {
3782
3764
  for (const [name, value] of Object.entries(bindings)) {
3783
- const binding = this.shaderLayout.bindings.find((binding2) => binding2.name === name) || this.shaderLayout.bindings.find((binding2) => binding2.name === `${name}Uniforms`);
3765
+ const binding = this.shaderLayout.bindings.find((binding_) => binding_.name === name) || this.shaderLayout.bindings.find((binding_) => binding_.name === `${name}Uniforms`);
3784
3766
  if (!binding) {
3785
- const validBindings = this.shaderLayout.bindings.map((binding2) => `"${binding2.name}"`).join(", ");
3767
+ const validBindings = this.shaderLayout.bindings.map((binding_) => `"${binding_.name}"`).join(", ");
3786
3768
  if (!(options == null ? void 0 : options.disableWarnings)) {
3787
3769
  import_core16.log.warn(`No binding "${name}" in render pipeline "${this.id}", expected one of ${validBindings}`, value)();
3788
3770
  }
@@ -3907,21 +3889,34 @@ var WEBGLRenderPipeline = class extends import_core16.RenderPipeline {
3907
3889
  this._reportLinkStatus(status);
3908
3890
  }
3909
3891
  /** Report link status. First, check for shader compilation failures if linking fails */
3910
- _reportLinkStatus(status) {
3892
+ async _reportLinkStatus(status) {
3911
3893
  var _a;
3912
3894
  switch (status) {
3913
3895
  case "success":
3914
3896
  return;
3915
3897
  default:
3916
- if (this.vs.compilationStatus === "error") {
3917
- this.vs.debugShader();
3918
- throw new Error(`Error during compilation of shader ${this.vs.id}`);
3898
+ switch (this.vs.compilationStatus) {
3899
+ case "error":
3900
+ this.vs.debugShader();
3901
+ throw new Error(`Error during compilation of shader ${this.vs.id}`);
3902
+ case "pending":
3903
+ this.vs.asyncCompilationStatus.then(() => this.vs.debugShader());
3904
+ break;
3905
+ case "success":
3906
+ break;
3919
3907
  }
3920
- if (((_a = this.fs) == null ? void 0 : _a.compilationStatus) === "error") {
3921
- this.fs.debugShader();
3922
- throw new Error(`Error during compilation of shader ${this.fs.id}`);
3908
+ switch ((_a = this.fs) == null ? void 0 : _a.compilationStatus) {
3909
+ case "error":
3910
+ this.fs.debugShader();
3911
+ throw new Error(`Error during compilation of shader ${this.fs.id}`);
3912
+ case "pending":
3913
+ this.fs.asyncCompilationStatus.then(() => this.fs.debugShader());
3914
+ break;
3915
+ case "success":
3916
+ break;
3923
3917
  }
3924
- throw new Error(`Error during ${status}: ${this.device.gl.getProgramInfoLog(this.handle)}`);
3918
+ const linkErrorLog = this.device.gl.getProgramInfoLog(this.handle);
3919
+ throw new Error(`Error during ${status}: ${linkErrorLog}`);
3925
3920
  }
3926
3921
  }
3927
3922
  /**
@@ -4111,8 +4106,8 @@ var WEBGLCommandBuffer = class extends import_core17.CommandBuffer {
4111
4106
  }
4112
4107
  };
4113
4108
  function _copyBufferToBuffer(device, options) {
4114
- const source = options.source;
4115
- const destination = options.destination;
4109
+ const source = options.sourceBuffer;
4110
+ const destination = options.destinationBuffer;
4116
4111
  device.gl.bindBuffer(36662, source.handle);
4117
4112
  device.gl.bindBuffer(36663, destination.handle);
4118
4113
  device.gl.copyBufferSubData(36662, 36663, options.sourceOffset ?? 0, options.destinationOffset ?? 0, options.size);
@@ -4125,20 +4120,20 @@ function _copyBufferToTexture(device, options) {
4125
4120
  function _copyTextureToBuffer(device, options) {
4126
4121
  const {
4127
4122
  /** Texture to copy to/from. */
4128
- source,
4123
+ sourceTexture,
4129
4124
  /** Mip-map level of the texture to copy to/from. (Default 0) */
4130
4125
  mipLevel = 0,
4131
4126
  /** Defines which aspects of the texture to copy to/from. */
4132
4127
  aspect = "all",
4133
4128
  /** Width to copy */
4134
- width = options.source.width,
4129
+ width = options.sourceTexture.width,
4135
4130
  /** Height to copy */
4136
- height = options.source.height,
4131
+ height = options.sourceTexture.height,
4137
4132
  depthOrArrayLayers = 0,
4138
4133
  /** Defines the origin of the copy - the minimum corner of the texture sub-region to copy to/from. */
4139
4134
  origin = [0, 0],
4140
4135
  /** Destination buffer */
4141
- destination,
4136
+ destinationBuffer,
4142
4137
  /** Offset, in bytes, from the beginning of the buffer to the start of the image data (default 0) */
4143
4138
  byteOffset = 0,
4144
4139
  /**
@@ -4154,15 +4149,15 @@ function _copyTextureToBuffer(device, options) {
4154
4149
  rowsPerImage
4155
4150
  } = options;
4156
4151
  if (aspect !== "all") {
4157
- throw new Error("not supported");
4152
+ throw new Error("aspect not supported in WebGL");
4158
4153
  }
4159
4154
  if (mipLevel !== 0 || depthOrArrayLayers !== 0 || bytesPerRow || rowsPerImage) {
4160
4155
  throw new Error("not implemented");
4161
4156
  }
4162
- const { framebuffer, destroyFramebuffer } = getFramebuffer2(source);
4157
+ const { framebuffer, destroyFramebuffer } = getFramebuffer2(sourceTexture);
4163
4158
  let prevHandle;
4164
4159
  try {
4165
- const webglBuffer = destination;
4160
+ const webglBuffer = destinationBuffer;
4166
4161
  const sourceWidth = width || framebuffer.width;
4167
4162
  const sourceHeight = height || framebuffer.height;
4168
4163
  const sourceParams = getTextureFormatWebGL(framebuffer.colorAttachments[0].texture.props.format);
@@ -4184,7 +4179,7 @@ function _copyTextureToBuffer(device, options) {
4184
4179
  function _copyTextureToTexture(device, options) {
4185
4180
  const {
4186
4181
  /** Texture to copy to/from. */
4187
- source,
4182
+ sourceTexture,
4188
4183
  /** Mip-map level of the texture to copy to (Default 0) */
4189
4184
  destinationMipLevel = 0,
4190
4185
  /** Defines which aspects of the texture to copy to/from. */
@@ -4194,7 +4189,7 @@ function _copyTextureToTexture(device, options) {
4194
4189
  /** Defines the origin of the copy - the minimum corner of the texture sub-region to copy to. */
4195
4190
  destinationOrigin = [0, 0],
4196
4191
  /** Texture to copy to/from. */
4197
- destination
4192
+ destinationTexture
4198
4193
  /** Mip-map level of the texture to copy to/from. (Default 0) */
4199
4194
  // destinationMipLevel = options.mipLevel,
4200
4195
  /** Defines the origin of the copy - the minimum corner of the texture sub-region to copy to/from. */
@@ -4203,18 +4198,18 @@ function _copyTextureToTexture(device, options) {
4203
4198
  // destinationAspect = options.aspect,
4204
4199
  } = options;
4205
4200
  let {
4206
- width = options.destination.width,
4207
- height = options.destination.height
4201
+ width = options.destinationTexture.width,
4202
+ height = options.destinationTexture.height
4208
4203
  // depthOrArrayLayers = 0
4209
4204
  } = options;
4210
- const { framebuffer, destroyFramebuffer } = getFramebuffer2(source);
4205
+ const { framebuffer, destroyFramebuffer } = getFramebuffer2(sourceTexture);
4211
4206
  const [sourceX, sourceY] = origin;
4212
4207
  const [destinationX, destinationY, destinationZ] = destinationOrigin;
4213
4208
  const prevHandle = device.gl.bindFramebuffer(36160, framebuffer.handle);
4214
4209
  let texture = null;
4215
4210
  let textureTarget;
4216
- if (destination instanceof WEBGLTexture) {
4217
- texture = destination;
4211
+ if (destinationTexture instanceof WEBGLTexture) {
4212
+ texture = destinationTexture;
4218
4213
  width = Number.isFinite(width) ? width : texture.width;
4219
4214
  height = Number.isFinite(height) ? height : texture.height;
4220
4215
  texture.bind(0);
@@ -4301,19 +4296,19 @@ var import_env2 = require("@probe.gl/env");
4301
4296
 
4302
4297
  // dist/utils/fill-array.js
4303
4298
  function fillArray(options) {
4304
- const { target, source, start = 0, count = 1 } = options;
4299
+ const { target: target2, source, start = 0, count = 1 } = options;
4305
4300
  const length = source.length;
4306
4301
  const total = count * length;
4307
4302
  let copied = 0;
4308
4303
  for (let i = start; copied < length; copied++) {
4309
- target[i++] = source[copied];
4304
+ target2[i++] = source[copied];
4310
4305
  }
4311
4306
  while (copied < total) {
4312
4307
  if (copied < total - copied) {
4313
- target.copyWithin(start + copied, start, start + copied);
4308
+ target2.copyWithin(start + copied, start, start + copied);
4314
4309
  copied *= 2;
4315
4310
  } else {
4316
- target.copyWithin(start + copied, start, start + total - copied);
4311
+ target2.copyWithin(start + copied, start, start + total - copied);
4317
4312
  copied = total;
4318
4313
  }
4319
4314
  }
@@ -4729,11 +4724,11 @@ var WEBGLQuerySet = class extends import_core21.QuerySet {
4729
4724
  * outstanding queries representing disjoint `begin()`/`end()` intervals.
4730
4725
  * It is not possible to interleave or overlap `begin` and `end` calls.
4731
4726
  */
4732
- _begin(target) {
4727
+ _begin(target2) {
4733
4728
  if (this._queryPending) {
4734
4729
  return;
4735
4730
  }
4736
- this.target = target;
4731
+ this.target = target2;
4737
4732
  this.device.gl.beginQuery(this.target, this.handle);
4738
4733
  return;
4739
4734
  }
@@ -4864,36 +4859,52 @@ var WebGLDevice = class extends import_core23.Device {
4864
4859
  constructor(props) {
4865
4860
  var _a, _b;
4866
4861
  super({ ...props, id: props.id || uid("webgl-device") });
4867
- const device = (_a = props.gl) == null ? void 0 : _a.device;
4862
+ if (!props.createCanvasContext) {
4863
+ throw new Error("WebGLDevice requires props.createCanvasContext to be set");
4864
+ }
4865
+ const canvasContextProps = props.createCanvasContext === true ? {} : props.createCanvasContext;
4866
+ let device = (_b = (_a = canvasContextProps.canvas) == null ? void 0 : _a.gl) == null ? void 0 : _b.device;
4868
4867
  if (device) {
4869
4868
  throw new Error(`WebGL context already attached to device ${device.id}`);
4870
4869
  }
4871
- const canvas = ((_b = props.gl) == null ? void 0 : _b.canvas) || props.canvas;
4872
- this.canvasContext = new WebGLCanvasContext(this, { ...props, canvas });
4870
+ this.canvasContext = new WebGLCanvasContext(this, canvasContextProps);
4873
4871
  this.lost = new Promise((resolve) => {
4874
4872
  this._resolveContextLost = resolve;
4875
4873
  });
4876
- this.handle = createBrowserContext(this.canvasContext.canvas, {
4877
- ...props,
4874
+ const webglContextAttributes = { ...props.webgl };
4875
+ if (canvasContextProps.alphaMode === "premultiplied") {
4876
+ webglContextAttributes.premultipliedAlpha = true;
4877
+ }
4878
+ if (props.powerPreference !== void 0) {
4879
+ webglContextAttributes.powerPreference = props.powerPreference;
4880
+ }
4881
+ const gl = createBrowserContext(this.canvasContext.canvas, {
4878
4882
  onContextLost: (event) => {
4879
4883
  var _a2;
4880
4884
  return (_a2 = this._resolveContextLost) == null ? void 0 : _a2.call(this, {
4881
4885
  reason: "destroyed",
4882
4886
  message: "Entered sleep mode, or too many apps or browser tabs are using the GPU."
4883
4887
  });
4884
- }
4885
- });
4886
- this.gl = this.handle;
4887
- if (!this.handle) {
4888
+ },
4889
+ // eslint-disable-next-line no-console
4890
+ onContextRestored: (event) => console.log("WebGL context restored")
4891
+ }, webglContextAttributes);
4892
+ if (!gl) {
4888
4893
  throw new Error("WebGL context creation failed");
4889
4894
  }
4895
+ device = gl.device;
4896
+ if (device) {
4897
+ throw new Error(`WebGL context already attached to device ${device.id}`);
4898
+ }
4899
+ this.handle = gl;
4900
+ this.gl = gl;
4890
4901
  this.spectorJS = initializeSpectorJS({ ...this.props, gl: this.handle });
4891
4902
  this.gl.device = this;
4892
4903
  this.gl._version = 2;
4893
4904
  this.info = getDeviceInfo(this.gl, this._extensions);
4894
4905
  this.limits = new WebGLDeviceLimits(this.gl);
4895
- this.features = new WebGLDeviceFeatures(this.gl, this._extensions, this.props.disabledFeatures);
4896
- if (this.props.initalizeFeatures) {
4906
+ this.features = new WebGLDeviceFeatures(this.gl, this._extensions, this.props._disabledFeatures);
4907
+ if (this.props._initializeFeatures) {
4897
4908
  this.features.initializeFeatures();
4898
4909
  }
4899
4910
  this.canvasContext.resize();
@@ -4901,8 +4912,8 @@ var WebGLDevice = class extends import_core23.Device {
4901
4912
  log: (...args) => import_core23.log.log(1, ...args)()
4902
4913
  });
4903
4914
  glState.trackState(this.gl, { copyState: false });
4904
- if (props.debug) {
4905
- this.gl = makeDebugContext(this.gl, { ...props, throwOnError: true });
4915
+ if (props.debugWebGL) {
4916
+ this.gl = makeDebugContext(this.gl, { ...props });
4906
4917
  this.debug = true;
4907
4918
  import_core23.log.level = Math.max(import_core23.log.level, 1);
4908
4919
  import_core23.log.warn("WebGL debug mode activated. Performance reduced.")();
@@ -4931,7 +4942,7 @@ var WebGLDevice = class extends import_core23.Device {
4931
4942
  throw new Error("WebGL only supports a single canvas");
4932
4943
  }
4933
4944
  createBuffer(props) {
4934
- const newProps = this._getBufferProps(props);
4945
+ const newProps = this._normalizeBufferProps(props);
4935
4946
  return new WEBGLBuffer(this, newProps);
4936
4947
  }
4937
4948
  createTexture(props) {
@@ -5275,27 +5286,23 @@ var WebGLAdapter = class extends import_core24.Adapter {
5275
5286
  if (!isWebGL(gl)) {
5276
5287
  throw new Error("Invalid WebGL2RenderingContext");
5277
5288
  }
5278
- return new WebGLDevice({ gl });
5289
+ return new WebGLDevice({ _handle: gl });
5279
5290
  }
5280
5291
  async create(props = {}) {
5281
5292
  import_core24.log.groupCollapsed(LOG_LEVEL2, "WebGLDevice created")();
5282
5293
  const promises = [];
5283
- if (props.debug) {
5294
+ if (props.debugWebGL) {
5284
5295
  promises.push(loadWebGLDeveloperTools());
5285
5296
  }
5286
- if (props.debugWithSpectorJS) {
5297
+ if (props.debugSpectorJS) {
5287
5298
  promises.push(loadSpectorJS(props));
5288
5299
  }
5289
- if (typeof props.canvas === "string") {
5290
- promises.push(import_core24.CanvasContext.pageLoaded);
5291
- }
5292
5300
  const results = await Promise.allSettled(promises);
5293
5301
  for (const result of results) {
5294
5302
  if (result.status === "rejected") {
5295
5303
  import_core24.log.error(`Failed to initialize debug libraries ${result.reason}`)();
5296
5304
  }
5297
5305
  }
5298
- import_core24.log.probe(LOG_LEVEL2 + 1, "DOM is loaded")();
5299
5306
  const device = new WebGLDevice(props);
5300
5307
  const message2 = `Created ${device.type}${device.debug ? " debug" : ""} context: ${device.info.vendor}, ${device.info.renderer} for canvas: ${device.canvasContext.id}`;
5301
5308
  import_core24.log.probe(LOG_LEVEL2, message2)();