@luma.gl/webgl 9.2.6 → 9.3.0-alpha.10

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 (247) hide show
  1. package/dist/adapter/converters/device-parameters.d.ts +1 -1
  2. package/dist/adapter/converters/device-parameters.d.ts.map +1 -1
  3. package/dist/adapter/converters/device-parameters.js +4 -1
  4. package/dist/adapter/converters/device-parameters.js.map +1 -1
  5. package/dist/adapter/converters/sampler-parameters.d.ts +1 -1
  6. package/dist/adapter/converters/sampler-parameters.d.ts.map +1 -1
  7. package/dist/adapter/converters/sampler-parameters.js +1 -1
  8. package/dist/adapter/converters/sampler-parameters.js.map +1 -1
  9. package/dist/adapter/converters/shader-formats.d.ts +1 -64
  10. package/dist/adapter/converters/shader-formats.d.ts.map +1 -1
  11. package/dist/adapter/converters/shader-formats.js +1 -64
  12. package/dist/adapter/converters/shader-formats.js.map +1 -1
  13. package/dist/adapter/converters/webgl-shadertypes.d.ts +1 -3
  14. package/dist/adapter/converters/webgl-shadertypes.d.ts.map +1 -1
  15. package/dist/adapter/converters/webgl-shadertypes.js +1 -6
  16. package/dist/adapter/converters/webgl-shadertypes.js.map +1 -1
  17. package/dist/adapter/converters/webgl-texture-table.d.ts +8 -4
  18. package/dist/adapter/converters/webgl-texture-table.d.ts.map +1 -1
  19. package/dist/adapter/converters/webgl-texture-table.js +122 -58
  20. package/dist/adapter/converters/webgl-texture-table.js.map +1 -1
  21. package/dist/adapter/converters/webgl-vertex-formats.d.ts +1 -1
  22. package/dist/adapter/converters/webgl-vertex-formats.d.ts.map +1 -1
  23. package/dist/adapter/converters/webgl-vertex-formats.js +1 -1
  24. package/dist/adapter/converters/webgl-vertex-formats.js.map +1 -1
  25. package/dist/adapter/device-helpers/webgl-device-features.d.ts +1 -1
  26. package/dist/adapter/device-helpers/webgl-device-features.d.ts.map +1 -1
  27. package/dist/adapter/device-helpers/webgl-device-features.js +1 -2
  28. package/dist/adapter/device-helpers/webgl-device-features.js.map +1 -1
  29. package/dist/adapter/device-helpers/webgl-device-info.d.ts +1 -1
  30. package/dist/adapter/device-helpers/webgl-device-info.d.ts.map +1 -1
  31. package/dist/adapter/device-helpers/webgl-device-info.js +6 -1
  32. package/dist/adapter/device-helpers/webgl-device-info.js.map +1 -1
  33. package/dist/adapter/device-helpers/webgl-device-limits.d.ts +1 -1
  34. package/dist/adapter/device-helpers/webgl-device-limits.d.ts.map +1 -1
  35. package/dist/adapter/device-helpers/webgl-device-limits.js +1 -1
  36. package/dist/adapter/device-helpers/webgl-device-limits.js.map +1 -1
  37. package/dist/adapter/helpers/format-utils.d.ts +1 -1
  38. package/dist/adapter/helpers/format-utils.d.ts.map +1 -1
  39. package/dist/adapter/helpers/format-utils.js +1 -1
  40. package/dist/adapter/helpers/format-utils.js.map +1 -1
  41. package/dist/adapter/helpers/get-shader-layout-from-glsl.js +36 -22
  42. package/dist/adapter/helpers/get-shader-layout-from-glsl.js.map +1 -1
  43. package/dist/adapter/helpers/parse-shader-compiler-log.d.ts +1 -1
  44. package/dist/adapter/helpers/parse-shader-compiler-log.d.ts.map +1 -1
  45. package/dist/adapter/helpers/parse-shader-compiler-log.js +20 -0
  46. package/dist/adapter/helpers/parse-shader-compiler-log.js.map +1 -1
  47. package/dist/adapter/helpers/set-uniform.d.ts +1 -1
  48. package/dist/adapter/helpers/set-uniform.d.ts.map +1 -1
  49. package/dist/adapter/helpers/set-uniform.js +1 -1
  50. package/dist/adapter/helpers/set-uniform.js.map +1 -1
  51. package/dist/adapter/helpers/webgl-texture-utils.d.ts +1 -1
  52. package/dist/adapter/helpers/webgl-texture-utils.d.ts.map +1 -1
  53. package/dist/adapter/helpers/webgl-texture-utils.js +4 -4
  54. package/dist/adapter/helpers/webgl-texture-utils.js.map +1 -1
  55. package/dist/adapter/helpers/webgl-topology-utils.d.ts +1 -1
  56. package/dist/adapter/helpers/webgl-topology-utils.d.ts.map +1 -1
  57. package/dist/adapter/helpers/webgl-topology-utils.js +1 -1
  58. package/dist/adapter/helpers/webgl-topology-utils.js.map +1 -1
  59. package/dist/adapter/resources/webgl-buffer.d.ts +1 -1
  60. package/dist/adapter/resources/webgl-buffer.d.ts.map +1 -1
  61. package/dist/adapter/resources/webgl-buffer.js +20 -5
  62. package/dist/adapter/resources/webgl-buffer.js.map +1 -1
  63. package/dist/adapter/resources/webgl-command-buffer.d.ts +3 -4
  64. package/dist/adapter/resources/webgl-command-buffer.d.ts.map +1 -1
  65. package/dist/adapter/resources/webgl-command-buffer.js +29 -39
  66. package/dist/adapter/resources/webgl-command-buffer.js.map +1 -1
  67. package/dist/adapter/resources/webgl-command-encoder.d.ts +6 -5
  68. package/dist/adapter/resources/webgl-command-encoder.d.ts.map +1 -1
  69. package/dist/adapter/resources/webgl-command-encoder.js +23 -8
  70. package/dist/adapter/resources/webgl-command-encoder.js.map +1 -1
  71. package/dist/adapter/resources/webgl-fence.d.ts +14 -0
  72. package/dist/adapter/resources/webgl-fence.d.ts.map +1 -0
  73. package/dist/adapter/resources/webgl-fence.js +49 -0
  74. package/dist/adapter/resources/webgl-fence.js.map +1 -0
  75. package/dist/adapter/resources/webgl-framebuffer.d.ts +3 -1
  76. package/dist/adapter/resources/webgl-framebuffer.d.ts.map +1 -1
  77. package/dist/adapter/resources/webgl-framebuffer.js +10 -1
  78. package/dist/adapter/resources/webgl-framebuffer.js.map +1 -1
  79. package/dist/adapter/resources/webgl-query-set.d.ts +37 -31
  80. package/dist/adapter/resources/webgl-query-set.d.ts.map +1 -1
  81. package/dist/adapter/resources/webgl-query-set.js +247 -96
  82. package/dist/adapter/resources/webgl-query-set.js.map +1 -1
  83. package/dist/adapter/resources/webgl-render-pass.d.ts +1 -1
  84. package/dist/adapter/resources/webgl-render-pass.d.ts.map +1 -1
  85. package/dist/adapter/resources/webgl-render-pass.js +28 -11
  86. package/dist/adapter/resources/webgl-render-pass.js.map +1 -1
  87. package/dist/adapter/resources/webgl-render-pipeline.d.ts +17 -21
  88. package/dist/adapter/resources/webgl-render-pipeline.d.ts.map +1 -1
  89. package/dist/adapter/resources/webgl-render-pipeline.js +70 -169
  90. package/dist/adapter/resources/webgl-render-pipeline.js.map +1 -1
  91. package/dist/adapter/resources/webgl-sampler.d.ts +1 -1
  92. package/dist/adapter/resources/webgl-sampler.d.ts.map +1 -1
  93. package/dist/adapter/resources/webgl-sampler.js +1 -1
  94. package/dist/adapter/resources/webgl-sampler.js.map +1 -1
  95. package/dist/adapter/resources/webgl-shader.d.ts +1 -1
  96. package/dist/adapter/resources/webgl-shader.d.ts.map +1 -1
  97. package/dist/adapter/resources/webgl-shader.js +15 -8
  98. package/dist/adapter/resources/webgl-shader.js.map +1 -1
  99. package/dist/adapter/resources/webgl-shared-render-pipeline.d.ts +24 -0
  100. package/dist/adapter/resources/webgl-shared-render-pipeline.d.ts.map +1 -0
  101. package/dist/adapter/resources/webgl-shared-render-pipeline.js +155 -0
  102. package/dist/adapter/resources/webgl-shared-render-pipeline.js.map +1 -0
  103. package/dist/adapter/resources/webgl-texture.d.ts +42 -4
  104. package/dist/adapter/resources/webgl-texture.d.ts.map +1 -1
  105. package/dist/adapter/resources/webgl-texture.js +286 -62
  106. package/dist/adapter/resources/webgl-texture.js.map +1 -1
  107. package/dist/adapter/resources/webgl-transform-feedback.js +6 -6
  108. package/dist/adapter/resources/webgl-transform-feedback.js.map +1 -1
  109. package/dist/adapter/resources/webgl-vertex-array.d.ts +2 -2
  110. package/dist/adapter/resources/webgl-vertex-array.d.ts.map +1 -1
  111. package/dist/adapter/resources/webgl-vertex-array.js +1 -1
  112. package/dist/adapter/resources/webgl-vertex-array.js.map +1 -1
  113. package/dist/adapter/webgl-adapter.d.ts.map +1 -1
  114. package/dist/adapter/webgl-adapter.js +22 -23
  115. package/dist/adapter/webgl-adapter.js.map +1 -1
  116. package/dist/adapter/webgl-canvas-context.d.ts +2 -2
  117. package/dist/adapter/webgl-canvas-context.d.ts.map +1 -1
  118. package/dist/adapter/webgl-canvas-context.js +16 -6
  119. package/dist/adapter/webgl-canvas-context.js.map +1 -1
  120. package/dist/adapter/webgl-device.d.ts +10 -5
  121. package/dist/adapter/webgl-device.d.ts.map +1 -1
  122. package/dist/adapter/webgl-device.js +75 -28
  123. package/dist/adapter/webgl-device.js.map +1 -1
  124. package/dist/adapter/webgl-presentation-context.d.ts +21 -0
  125. package/dist/adapter/webgl-presentation-context.d.ts.map +1 -0
  126. package/dist/adapter/webgl-presentation-context.js +64 -0
  127. package/dist/adapter/webgl-presentation-context.js.map +1 -0
  128. package/dist/constants/index.d.ts +3 -0
  129. package/dist/constants/index.d.ts.map +1 -0
  130. package/dist/constants/index.js +5 -0
  131. package/dist/constants/index.js.map +1 -0
  132. package/dist/constants/webgl-constants.d.ts +822 -0
  133. package/dist/constants/webgl-constants.d.ts.map +1 -0
  134. package/dist/constants/webgl-constants.js +928 -0
  135. package/dist/constants/webgl-constants.js.map +1 -0
  136. package/dist/constants/webgl-types.d.ts +480 -0
  137. package/dist/constants/webgl-types.d.ts.map +1 -0
  138. package/dist/constants/webgl-types.js +6 -0
  139. package/dist/constants/webgl-types.js.map +1 -0
  140. package/dist/context/debug/spector.d.ts.map +1 -1
  141. package/dist/context/debug/spector.js +4 -4
  142. package/dist/context/debug/spector.js.map +1 -1
  143. package/dist/context/debug/webgl-developer-tools.js +7 -7
  144. package/dist/context/debug/webgl-developer-tools.js.map +1 -1
  145. package/dist/context/helpers/create-browser-context.d.ts.map +1 -1
  146. package/dist/context/helpers/create-browser-context.js +46 -36
  147. package/dist/context/helpers/create-browser-context.js.map +1 -1
  148. package/dist/context/helpers/webgl-context-data.d.ts +5 -1
  149. package/dist/context/helpers/webgl-context-data.d.ts.map +1 -1
  150. package/dist/context/helpers/webgl-context-data.js +9 -10
  151. package/dist/context/helpers/webgl-context-data.js.map +1 -1
  152. package/dist/context/helpers/webgl-extensions.d.ts +1 -1
  153. package/dist/context/helpers/webgl-extensions.d.ts.map +1 -1
  154. package/dist/context/parameters/unified-parameter-api.d.ts +2 -2
  155. package/dist/context/parameters/unified-parameter-api.d.ts.map +1 -1
  156. package/dist/context/parameters/unified-parameter-api.js +2 -2
  157. package/dist/context/parameters/unified-parameter-api.js.map +1 -1
  158. package/dist/context/parameters/webgl-parameter-tables.d.ts +1 -1
  159. package/dist/context/parameters/webgl-parameter-tables.d.ts.map +1 -1
  160. package/dist/context/parameters/webgl-parameter-tables.js +1 -1
  161. package/dist/context/parameters/webgl-parameter-tables.js.map +1 -1
  162. package/dist/context/polyfills/polyfill-webgl1-extensions.js +1 -1
  163. package/dist/context/polyfills/polyfill-webgl1-extensions.js.map +1 -1
  164. package/dist/context/state-tracker/webgl-state-tracker.js +2 -2
  165. package/dist/context/state-tracker/webgl-state-tracker.js.map +1 -1
  166. package/dist/dist.dev.js +1897 -999
  167. package/dist/dist.min.js +2 -2
  168. package/dist/index.cjs +3 -5255
  169. package/dist/index.cjs.map +4 -4
  170. package/dist/index.d.ts +3 -0
  171. package/dist/index.d.ts.map +1 -1
  172. package/dist/index.js +2 -0
  173. package/dist/index.js.map +1 -1
  174. package/dist/utils/fill-array.js +1 -1
  175. package/dist/utils/fill-array.js.map +1 -1
  176. package/dist/webgl-constants.d.ts +2 -0
  177. package/dist/webgl-constants.d.ts.map +1 -0
  178. package/dist/webgl-constants.js +5 -0
  179. package/dist/webgl-constants.js.map +1 -0
  180. package/dist/webgl-types.d.ts +2 -0
  181. package/dist/webgl-types.d.ts.map +1 -0
  182. package/dist/{types.js → webgl-types.js} +1 -1
  183. package/dist/webgl-types.js.map +1 -0
  184. package/package.json +19 -5
  185. package/src/adapter/converters/device-parameters.ts +6 -2
  186. package/src/adapter/converters/sampler-parameters.ts +1 -1
  187. package/src/adapter/converters/shader-formats.ts +1 -66
  188. package/src/adapter/converters/webgl-shadertypes.ts +1 -9
  189. package/src/adapter/converters/webgl-texture-table.ts +160 -68
  190. package/src/adapter/converters/webgl-vertex-formats.ts +1 -1
  191. package/src/adapter/device-helpers/webgl-device-features.ts +2 -3
  192. package/src/adapter/device-helpers/webgl-device-info.ts +7 -1
  193. package/src/adapter/device-helpers/webgl-device-limits.ts +1 -1
  194. package/src/adapter/helpers/format-utils.ts +1 -1
  195. package/src/adapter/helpers/get-shader-layout-from-glsl.ts +44 -24
  196. package/src/adapter/helpers/parse-shader-compiler-log.ts +23 -1
  197. package/src/adapter/helpers/set-uniform.ts +1 -1
  198. package/src/adapter/helpers/webgl-texture-utils.ts +4 -4
  199. package/src/adapter/helpers/webgl-topology-utils.ts +1 -1
  200. package/src/adapter/resources/webgl-buffer.ts +17 -5
  201. package/src/adapter/resources/webgl-command-buffer.ts +44 -48
  202. package/src/adapter/resources/webgl-command-encoder.ts +28 -11
  203. package/src/adapter/resources/webgl-fence.ts +55 -0
  204. package/src/adapter/resources/webgl-framebuffer.ts +12 -1
  205. package/src/adapter/resources/webgl-query-set.ts +295 -101
  206. package/src/adapter/resources/webgl-render-pass.ts +30 -13
  207. package/src/adapter/resources/webgl-render-pipeline.ts +102 -198
  208. package/src/adapter/resources/webgl-sampler.ts +1 -1
  209. package/src/adapter/resources/webgl-shader.ts +15 -8
  210. package/src/adapter/resources/webgl-shared-render-pipeline.ts +211 -0
  211. package/src/adapter/resources/webgl-texture.ts +455 -81
  212. package/src/adapter/resources/webgl-transform-feedback.ts +6 -6
  213. package/src/adapter/resources/webgl-vertex-array.ts +1 -1
  214. package/src/adapter/webgl-adapter.ts +26 -24
  215. package/src/adapter/webgl-canvas-context.ts +19 -8
  216. package/src/adapter/webgl-device.ts +91 -35
  217. package/src/adapter/webgl-presentation-context.ts +93 -0
  218. package/src/constants/index.d.ts.map +1 -0
  219. package/src/constants/index.js.map +1 -0
  220. package/src/constants/index.ts +31 -0
  221. package/src/constants/webgl-constants.d.ts.map +1 -0
  222. package/src/constants/webgl-constants.js.map +1 -0
  223. package/src/constants/webgl-constants.ts +1051 -0
  224. package/src/constants/webgl-types.d.ts.map +1 -0
  225. package/src/constants/webgl-types.js.map +1 -0
  226. package/src/constants/webgl-types.ts +813 -0
  227. package/src/context/debug/spector.ts +4 -4
  228. package/src/context/debug/webgl-developer-tools.ts +16 -7
  229. package/src/context/helpers/create-browser-context.ts +54 -43
  230. package/src/context/helpers/webgl-context-data.ts +17 -11
  231. package/src/context/helpers/webgl-extensions.ts +1 -1
  232. package/src/context/parameters/unified-parameter-api.ts +3 -3
  233. package/src/context/parameters/webgl-parameter-tables.ts +1 -1
  234. package/src/context/polyfills/polyfill-webgl1-extensions.ts +1 -1
  235. package/src/context/state-tracker/webgl-state-tracker.ts +2 -2
  236. package/src/index.ts +27 -0
  237. package/src/utils/fill-array.ts +1 -1
  238. package/src/webgl-constants.d.ts.map +1 -0
  239. package/src/webgl-constants.js.map +1 -0
  240. package/src/webgl-constants.ts +5 -0
  241. package/src/webgl-types.d.ts.map +1 -0
  242. package/src/webgl-types.js.map +1 -0
  243. package/src/webgl-types.ts +29 -0
  244. package/dist/types.d.ts +0 -11
  245. package/dist/types.d.ts.map +0 -1
  246. package/dist/types.js.map +0 -1
  247. package/src/types.ts +0 -14
@@ -1,175 +1,369 @@
1
- // WebGL2 Query (also handles disjoint timer extensions)
1
+ // WebGL2 QuerySet (also handles disjoint timer extensions)
2
2
  import {QuerySet, QuerySetProps} from '@luma.gl/core';
3
- import {GL} from '@luma.gl/constants';
3
+ import {GL} from '@luma.gl/webgl/constants';
4
4
  import {WebGLDevice} from '../webgl-device';
5
5
 
6
+ type WebGLPendingQuery = {
7
+ handle: WebGLQuery;
8
+ promise: Promise<bigint> | null;
9
+ result: bigint | null;
10
+ disjoint: boolean;
11
+ cancelled: boolean;
12
+ pollRequestId: number | null;
13
+ resolve: ((value: bigint) => void) | null;
14
+ reject: ((error: Error) => void) | null;
15
+ };
16
+
17
+ type WebGLTimestampPair = {
18
+ activeQuery: WebGLPendingQuery | null;
19
+ completedQueries: WebGLPendingQuery[];
20
+ };
21
+
6
22
  /**
7
23
  * Asynchronous queries for different kinds of information
8
24
  */
9
25
  export class WEBGLQuerySet extends QuerySet {
10
26
  readonly device: WebGLDevice;
11
- readonly handle: WebGLQuery;
27
+ readonly handle: WebGLQuery | null;
12
28
 
13
- target: number | null = null;
14
- _queryPending = false;
15
- _pollingPromise: Promise<any> | null = null;
29
+ protected _timestampPairs: WebGLTimestampPair[] = [];
30
+ protected _pendingReads: Set<WebGLPendingQuery> = new Set();
31
+ protected _occlusionQuery: WebGLPendingQuery | null = null;
32
+ protected _occlusionActive = false;
16
33
 
17
34
  override get [Symbol.toStringTag](): string {
18
- return 'Query';
35
+ return 'QuerySet';
19
36
  }
20
37
 
21
- // Create a query class
22
38
  constructor(device: WebGLDevice, props: QuerySetProps) {
23
39
  super(device, props);
24
40
  this.device = device;
25
41
 
26
- if (props.count > 1) {
27
- throw new Error('WebGL QuerySet can only have one value');
42
+ if (props.type === 'timestamp') {
43
+ if (props.count < 2) {
44
+ throw new Error('Timestamp QuerySet requires at least two query slots');
45
+ }
46
+ this._timestampPairs = new Array(Math.ceil(props.count / 2))
47
+ .fill(null)
48
+ .map(() => ({activeQuery: null, completedQueries: []}));
49
+ this.handle = null;
50
+ } else {
51
+ if (props.count > 1) {
52
+ throw new Error('WebGL occlusion QuerySet can only have one value');
53
+ }
54
+ const handle = this.device.gl.createQuery();
55
+ if (!handle) {
56
+ throw new Error('WebGL query not supported');
57
+ }
58
+ this.handle = handle;
28
59
  }
29
60
 
30
- const handle = this.device.gl.createQuery();
31
- if (!handle) {
32
- throw new Error('WebGL query not supported');
33
- }
34
- this.handle = handle;
35
61
  Object.seal(this);
36
62
  }
37
63
 
38
- override destroy() {
39
- this.device.gl.deleteQuery(this.handle);
40
- }
64
+ override destroy(): void {
65
+ if (this.destroyed) {
66
+ return;
67
+ }
41
68
 
42
- // FOR RENDER PASS AND COMMAND ENCODER
69
+ if (this.handle) {
70
+ this.device.gl.deleteQuery(this.handle);
71
+ }
43
72
 
44
- /**
45
- * Shortcut for timer query (dependent on extension in both WebGL1 and 2)
46
- * Measures GPU time delta between this call and a matching `end` call in the
47
- * GPU instruction stream.
48
- */
49
- beginTimestampQuery(): void {
50
- return this._begin(GL.TIME_ELAPSED_EXT);
51
- }
73
+ for (const pair of this._timestampPairs) {
74
+ if (pair.activeQuery) {
75
+ this._cancelPendingQuery(pair.activeQuery);
76
+ this.device.gl.deleteQuery(pair.activeQuery.handle);
77
+ }
78
+ for (const query of pair.completedQueries) {
79
+ this._cancelPendingQuery(query);
80
+ this.device.gl.deleteQuery(query.handle);
81
+ }
82
+ }
52
83
 
53
- endTimestampQuery(): void {
54
- this._end();
84
+ if (this._occlusionQuery) {
85
+ this._cancelPendingQuery(this._occlusionQuery);
86
+ this.device.gl.deleteQuery(this._occlusionQuery.handle);
87
+ }
88
+
89
+ for (const query of Array.from(this._pendingReads)) {
90
+ this._cancelPendingQuery(query);
91
+ }
92
+
93
+ this.destroyResource();
55
94
  }
56
95
 
57
- // Shortcut for occlusion queries
58
- beginOcclusionQuery(options?: {conservative?: boolean}): void {
59
- return this._begin(
60
- options?.conservative ? GL.ANY_SAMPLES_PASSED_CONSERVATIVE : GL.ANY_SAMPLES_PASSED
61
- );
96
+ isResultAvailable(queryIndex?: number): boolean {
97
+ if (this.props.type === 'timestamp') {
98
+ if (queryIndex === undefined) {
99
+ return this._timestampPairs.some((_, pairIndex) =>
100
+ this._isTimestampPairAvailable(pairIndex)
101
+ );
102
+ }
103
+ return this._isTimestampPairAvailable(this._getTimestampPairIndex(queryIndex));
104
+ }
105
+
106
+ if (!this._occlusionQuery) {
107
+ return false;
108
+ }
109
+
110
+ return this._pollQueryAvailability(this._occlusionQuery);
62
111
  }
63
112
 
64
- endOcclusionQuery() {
65
- this._end();
113
+ async readResults(options?: {firstQuery?: number; queryCount?: number}): Promise<bigint[]> {
114
+ const firstQuery = options?.firstQuery || 0;
115
+ const queryCount = options?.queryCount || this.props.count - firstQuery;
116
+ this._validateRange(firstQuery, queryCount);
117
+
118
+ if (this.props.type === 'timestamp') {
119
+ const results = new Array<bigint>(queryCount).fill(0n);
120
+ const startPairIndex = Math.floor(firstQuery / 2);
121
+ const endPairIndex = Math.floor((firstQuery + queryCount - 1) / 2);
122
+
123
+ for (let pairIndex = startPairIndex; pairIndex <= endPairIndex; pairIndex++) {
124
+ const duration = await this._consumeTimestampPairResult(pairIndex);
125
+ const beginSlot = pairIndex * 2;
126
+ const endSlot = beginSlot + 1;
127
+
128
+ if (beginSlot >= firstQuery && beginSlot < firstQuery + queryCount) {
129
+ results[beginSlot - firstQuery] = 0n;
130
+ }
131
+ if (endSlot >= firstQuery && endSlot < firstQuery + queryCount) {
132
+ results[endSlot - firstQuery] = duration;
133
+ }
134
+ }
135
+
136
+ return results;
137
+ }
138
+
139
+ if (!this._occlusionQuery) {
140
+ throw new Error('Occlusion query has not been started');
141
+ }
142
+
143
+ return [await this._consumeQueryResult(this._occlusionQuery)];
66
144
  }
67
145
 
68
- // Shortcut for transformFeedbackQuery
69
- beginTransformFeedbackQuery(): void {
70
- return this._begin(GL.TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
146
+ async readTimestampDuration(beginIndex: number, endIndex: number): Promise<number> {
147
+ if (this.props.type !== 'timestamp') {
148
+ throw new Error('Timestamp durations require a timestamp QuerySet');
149
+ }
150
+ if (beginIndex < 0 || endIndex >= this.props.count || endIndex <= beginIndex) {
151
+ throw new Error('Timestamp duration range is out of bounds');
152
+ }
153
+ if (beginIndex % 2 !== 0 || endIndex !== beginIndex + 1) {
154
+ throw new Error('WebGL timestamp durations require adjacent even/odd query indices');
155
+ }
156
+
157
+ const result = await this._consumeTimestampPairResult(this._getTimestampPairIndex(beginIndex));
158
+ return Number(result) / 1e6;
71
159
  }
72
160
 
73
- endTransformFeedbackQuery(): void {
74
- this._end();
161
+ beginOcclusionQuery(): void {
162
+ if (this.props.type !== 'occlusion') {
163
+ throw new Error('Occlusion queries require an occlusion QuerySet');
164
+ }
165
+ if (!this.handle) {
166
+ throw new Error('WebGL occlusion query is not available');
167
+ }
168
+ if (this._occlusionActive) {
169
+ throw new Error('Occlusion query is already active');
170
+ }
171
+
172
+ this.device.gl.beginQuery(GL.ANY_SAMPLES_PASSED, this.handle);
173
+ this._occlusionQuery = {
174
+ handle: this.handle,
175
+ promise: null,
176
+ result: null,
177
+ disjoint: false,
178
+ cancelled: false,
179
+ pollRequestId: null,
180
+ resolve: null,
181
+ reject: null
182
+ };
183
+ this._occlusionActive = true;
75
184
  }
76
185
 
77
- async resolveQuery(): Promise<bigint[]> {
78
- const value = await this.pollQuery();
79
- return [value];
186
+ endOcclusionQuery(): void {
187
+ if (!this._occlusionActive) {
188
+ throw new Error('Occlusion query is not active');
189
+ }
190
+
191
+ this.device.gl.endQuery(GL.ANY_SAMPLES_PASSED);
192
+ this._occlusionActive = false;
80
193
  }
81
194
 
82
- // PRIVATE METHODS
195
+ writeTimestamp(queryIndex: number): void {
196
+ if (this.props.type !== 'timestamp') {
197
+ throw new Error('Timestamp writes require a timestamp QuerySet');
198
+ }
199
+
200
+ const pairIndex = this._getTimestampPairIndex(queryIndex);
201
+ const pair = this._timestampPairs[pairIndex];
202
+
203
+ if (queryIndex % 2 === 0) {
204
+ if (pair.activeQuery) {
205
+ throw new Error('Timestamp query pair is already active');
206
+ }
83
207
 
84
- /**
85
- * Due to OpenGL API limitations, after calling `begin()` on one Query
86
- * instance, `end()` must be called on that same instance before
87
- * calling `begin()` on another query. While there can be multiple
88
- * outstanding queries representing disjoint `begin()`/`end()` intervals.
89
- * It is not possible to interleave or overlap `begin` and `end` calls.
90
- */
91
- protected _begin(target: number): void {
92
- // Don't start a new query if one is already active.
93
- if (this._queryPending) {
208
+ const handle = this.device.gl.createQuery();
209
+ if (!handle) {
210
+ throw new Error('WebGL query not supported');
211
+ }
212
+
213
+ const query: WebGLPendingQuery = {
214
+ handle,
215
+ promise: null,
216
+ result: null,
217
+ disjoint: false,
218
+ cancelled: false,
219
+ pollRequestId: null,
220
+ resolve: null,
221
+ reject: null
222
+ };
223
+
224
+ this.device.gl.beginQuery(GL.TIME_ELAPSED_EXT, handle);
225
+ pair.activeQuery = query;
94
226
  return;
95
227
  }
96
228
 
97
- this.target = target;
98
- this.device.gl.beginQuery(this.target, this.handle);
229
+ if (!pair.activeQuery) {
230
+ throw new Error('Timestamp query pair was ended before it was started');
231
+ }
99
232
 
100
- return;
233
+ this.device.gl.endQuery(GL.TIME_ELAPSED_EXT);
234
+ pair.completedQueries.push(pair.activeQuery);
235
+ pair.activeQuery = null;
101
236
  }
102
237
 
103
- // ends the current query
104
- protected _end(): void {
105
- // Can't end a new query if the last one hasn't been resolved.
106
- if (this._queryPending) {
107
- return;
238
+ protected _validateRange(firstQuery: number, queryCount: number): void {
239
+ if (firstQuery < 0 || queryCount < 0 || firstQuery + queryCount > this.props.count) {
240
+ throw new Error('Query read range is out of bounds');
108
241
  }
242
+ }
109
243
 
110
- if (this.target) {
111
- this.device.gl.endQuery(this.target);
112
- this.target = null;
113
- this._queryPending = true;
244
+ protected _getTimestampPairIndex(queryIndex: number): number {
245
+ if (queryIndex < 0 || queryIndex >= this.props.count) {
246
+ throw new Error('Query index is out of bounds');
114
247
  }
115
- return;
248
+
249
+ return Math.floor(queryIndex / 2);
116
250
  }
117
251
 
118
- // Returns true if the query result is available
119
- isResultAvailable(): boolean {
120
- if (!this._queryPending) {
252
+ protected _isTimestampPairAvailable(pairIndex: number): boolean {
253
+ const pair = this._timestampPairs[pairIndex];
254
+ if (!pair || pair.completedQueries.length === 0) {
121
255
  return false;
122
256
  }
123
257
 
258
+ return this._pollQueryAvailability(pair.completedQueries[0]);
259
+ }
260
+
261
+ protected _pollQueryAvailability(query: WebGLPendingQuery): boolean {
262
+ if (query.cancelled || this.destroyed) {
263
+ query.result = 0n;
264
+ return true;
265
+ }
266
+
267
+ if (query.result !== null || query.disjoint) {
268
+ return true;
269
+ }
270
+
124
271
  const resultAvailable = this.device.gl.getQueryParameter(
125
- this.handle,
272
+ query.handle,
126
273
  GL.QUERY_RESULT_AVAILABLE
127
274
  );
128
- if (resultAvailable) {
129
- this._queryPending = false;
275
+ if (!resultAvailable) {
276
+ return false;
130
277
  }
131
- return resultAvailable;
132
- }
133
278
 
134
- // Timing query is disjoint, i.e. results are invalid
135
- isTimerDisjoint(): boolean {
136
- return this.device.gl.getParameter(GL.GPU_DISJOINT_EXT);
279
+ const isDisjoint = Boolean(this.device.gl.getParameter(GL.GPU_DISJOINT_EXT));
280
+ query.disjoint = isDisjoint;
281
+ query.result = isDisjoint
282
+ ? 0n
283
+ : BigInt(this.device.gl.getQueryParameter(query.handle, GL.QUERY_RESULT));
284
+ return true;
137
285
  }
138
286
 
139
- // Returns query result.
140
- getResult(): any {
141
- return this.device.gl.getQueryParameter(this.handle, GL.QUERY_RESULT);
142
- }
287
+ protected async _consumeTimestampPairResult(pairIndex: number): Promise<bigint> {
288
+ const pair = this._timestampPairs[pairIndex];
289
+ if (!pair || pair.completedQueries.length === 0) {
290
+ throw new Error('Timestamp query pair has no completed result');
291
+ }
143
292
 
144
- // Returns the query result, converted to milliseconds to match JavaScript conventions.
145
- getTimerMilliseconds() {
146
- return this.getResult() / 1e6;
293
+ const query = pair.completedQueries.shift()!;
294
+
295
+ try {
296
+ return await this._consumeQueryResult(query);
297
+ } finally {
298
+ this.device.gl.deleteQuery(query.handle);
299
+ }
147
300
  }
148
301
 
149
- // Polls the query
150
- pollQuery(limit: number = Number.POSITIVE_INFINITY): Promise<any> {
151
- if (this._pollingPromise) {
152
- return this._pollingPromise;
302
+ protected _consumeQueryResult(query: WebGLPendingQuery): Promise<bigint> {
303
+ if (query.promise) {
304
+ return query.promise;
153
305
  }
154
306
 
155
- let counter = 0;
307
+ this._pendingReads.add(query);
308
+ query.promise = new Promise((resolve, reject) => {
309
+ query.resolve = resolve;
310
+ query.reject = reject;
156
311
 
157
- this._pollingPromise = new Promise((resolve, reject) => {
158
312
  const poll = () => {
159
- if (this.isResultAvailable()) {
160
- resolve(this.getResult());
161
- this._pollingPromise = null;
162
- } else if (counter++ > limit) {
163
- reject('Timed out');
164
- this._pollingPromise = null;
313
+ query.pollRequestId = null;
314
+
315
+ if (query.cancelled || this.destroyed) {
316
+ this._pendingReads.delete(query);
317
+ query.promise = null;
318
+ query.resolve = null;
319
+ query.reject = null;
320
+ resolve(0n);
321
+ return;
322
+ }
323
+
324
+ if (!this._pollQueryAvailability(query)) {
325
+ query.pollRequestId = this._requestAnimationFrame(poll);
326
+ return;
327
+ }
328
+
329
+ this._pendingReads.delete(query);
330
+ query.promise = null;
331
+ query.resolve = null;
332
+ query.reject = null;
333
+ if (query.disjoint) {
334
+ reject(new Error('GPU timestamp query was invalidated by a disjoint event'));
165
335
  } else {
166
- requestAnimationFrame(poll);
336
+ resolve(query.result || 0n);
167
337
  }
168
338
  };
169
339
 
170
- requestAnimationFrame(poll);
340
+ poll();
171
341
  });
172
342
 
173
- return this._pollingPromise;
343
+ return query.promise;
344
+ }
345
+
346
+ protected _cancelPendingQuery(query: WebGLPendingQuery): void {
347
+ this._pendingReads.delete(query);
348
+ query.cancelled = true;
349
+ if (query.pollRequestId !== null) {
350
+ this._cancelAnimationFrame(query.pollRequestId);
351
+ query.pollRequestId = null;
352
+ }
353
+ if (query.resolve) {
354
+ const resolve = query.resolve;
355
+ query.promise = null;
356
+ query.resolve = null;
357
+ query.reject = null;
358
+ resolve(0n);
359
+ }
360
+ }
361
+
362
+ protected _requestAnimationFrame(callback: FrameRequestCallback): number {
363
+ return requestAnimationFrame(callback);
364
+ }
365
+
366
+ protected _cancelAnimationFrame(requestId: number): void {
367
+ cancelAnimationFrame(requestId);
174
368
  }
175
369
  }
@@ -5,7 +5,7 @@
5
5
  import {NumericArray, NumberArray4} from '@math.gl/types';
6
6
  import {RenderPass, RenderPassProps, RenderPassParameters} from '@luma.gl/core';
7
7
  import {WebGLDevice} from '../webgl-device';
8
- import {GL, GLParameters} from '@luma.gl/constants';
8
+ import {GL, GLParameters} from '@luma.gl/webgl/constants';
9
9
  import {withGLParameters} from '../../context/state-tracker/with-parameters';
10
10
  import {setGLParameters} from '../../context/parameters/unified-parameter-api';
11
11
  import {WEBGLQuerySet} from './webgl-query-set';
@@ -23,13 +23,21 @@ export class WEBGLRenderPass extends RenderPass {
23
23
  constructor(device: WebGLDevice, props: RenderPassProps) {
24
24
  super(device, props);
25
25
  this.device = device;
26
+ const webglFramebuffer = this.props.framebuffer as WEBGLFramebuffer | null;
27
+ const isDefaultFramebuffer = !webglFramebuffer || webglFramebuffer.handle === null;
28
+
29
+ if (isDefaultFramebuffer) {
30
+ // Treat an explicit wrapper around the default framebuffer the same as the
31
+ // implicit default path so draw buffer and viewport state stay valid.
32
+ device.getDefaultCanvasContext()._resizeDrawingBufferIfNeeded();
33
+ }
26
34
 
27
35
  // If no viewport is provided, apply reasonably defaults
28
36
  let viewport: NumberArray4 | undefined;
29
37
  if (!props?.parameters?.viewport) {
30
- if (props?.framebuffer) {
38
+ if (!isDefaultFramebuffer) {
31
39
  // Set the viewport to the size of the framebuffer
32
- const {width, height} = props.framebuffer;
40
+ const {width, height} = webglFramebuffer;
33
41
  viewport = [0, 0, width, height];
34
42
  } else {
35
43
  // Instead of using our own book-keeping, we can just read the values from the WebGL context
@@ -43,24 +51,36 @@ export class WEBGLRenderPass extends RenderPass {
43
51
  this.setParameters({viewport, ...this.props.parameters});
44
52
 
45
53
  // Specify mapping of draw buffer locations to color attachments
46
- const webglFramebuffer = this.props.framebuffer as WEBGLFramebuffer;
47
54
  // Default framebuffers can only be set to GL.BACK or GL.NONE
48
- if (this.props.framebuffer && webglFramebuffer?.handle) {
49
- const drawBuffers = this.props.framebuffer.colorAttachments.map(
50
- (_, i) => GL.COLOR_ATTACHMENT0 + i
51
- );
55
+ if (!isDefaultFramebuffer) {
56
+ const drawBuffers = webglFramebuffer.colorAttachments.map((_, i) => GL.COLOR_ATTACHMENT0 + i);
52
57
  this.device.gl.drawBuffers(drawBuffers);
53
58
  } else {
59
+ // Default framebuffer only supports GL.BACK/GL.NONE draw buffers, even when
60
+ // passed through an explicit framebuffer wrapper.
54
61
  this.device.gl.drawBuffers([GL.BACK]);
55
62
  }
56
63
 
57
64
  // Hack - for now WebGL draws in "immediate mode" (instead of queueing the operations)...
58
65
  this.clear();
66
+
67
+ if (this.props.timestampQuerySet && this.props.beginTimestampIndex !== undefined) {
68
+ const webglQuerySet = this.props.timestampQuerySet as WEBGLQuerySet;
69
+ webglQuerySet.writeTimestamp(this.props.beginTimestampIndex);
70
+ }
59
71
  }
60
72
 
61
73
  end(): void {
74
+ if (this.destroyed) {
75
+ return;
76
+ }
77
+ if (this.props.timestampQuerySet && this.props.endTimestampIndex !== undefined) {
78
+ const webglQuerySet = this.props.timestampQuerySet as WEBGLQuerySet;
79
+ webglQuerySet.writeTimestamp(this.props.endTimestampIndex);
80
+ }
62
81
  this.device.popState();
63
82
  // should add commands to CommandEncoder.
83
+ this.destroy();
64
84
  }
65
85
 
66
86
  pushDebugGroup(groupLabel: string): void {}
@@ -110,12 +130,9 @@ export class WEBGLRenderPass extends RenderPass {
110
130
  if (parameters.blendConstant) {
111
131
  glParameters.blendColor = parameters.blendConstant;
112
132
  }
113
- if (parameters.stencilReference) {
114
- // eslint-disable-next-line no-console
115
- console.warn('RenderPassParameters.stencilReference not yet implemented in WebGL');
116
- // parameters.stencilFunc = [func, ref, mask];
117
- // Does this work?
133
+ if (parameters.stencilReference !== undefined) {
118
134
  glParameters[GL.STENCIL_REF] = parameters.stencilReference;
135
+ glParameters[GL.STENCIL_BACK_REF] = parameters.stencilReference;
119
136
  }
120
137
 
121
138
  if ('colorMask' in parameters) {