@luma.gl/core 9.2.6 → 9.3.0-alpha.4
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.
- package/dist/adapter/canvas-context.d.ts +23 -3
- package/dist/adapter/canvas-context.d.ts.map +1 -1
- package/dist/adapter/canvas-context.js +77 -15
- package/dist/adapter/canvas-context.js.map +1 -1
- package/dist/adapter/device.d.ts +5 -5
- package/dist/adapter/device.d.ts.map +1 -1
- package/dist/adapter/device.js +12 -2
- package/dist/adapter/device.js.map +1 -1
- package/dist/adapter/luma.js +1 -1
- package/dist/adapter/luma.js.map +1 -1
- package/dist/adapter/resources/command-encoder.d.ts +5 -5
- package/dist/adapter/resources/command-encoder.d.ts.map +1 -1
- package/dist/adapter/resources/fence.d.ts +16 -0
- package/dist/adapter/resources/fence.d.ts.map +1 -0
- package/dist/adapter/resources/fence.js +15 -0
- package/dist/adapter/resources/fence.js.map +1 -0
- package/dist/adapter/resources/framebuffer.d.ts.map +1 -1
- package/dist/adapter/resources/framebuffer.js +15 -12
- package/dist/adapter/resources/framebuffer.js.map +1 -1
- package/dist/adapter/resources/resource.d.ts +5 -0
- package/dist/adapter/resources/resource.d.ts.map +1 -1
- package/dist/adapter/resources/resource.js +3 -0
- package/dist/adapter/resources/resource.js.map +1 -1
- package/dist/adapter/resources/shader.js +27 -25
- package/dist/adapter/resources/shader.js.map +1 -1
- package/dist/adapter/resources/texture.d.ts +97 -24
- package/dist/adapter/resources/texture.d.ts.map +1 -1
- package/dist/adapter/resources/texture.js +116 -10
- package/dist/adapter/resources/texture.js.map +1 -1
- package/dist/adapter-utils/format-compiler-log.d.ts.map +1 -1
- package/dist/adapter-utils/format-compiler-log.js +23 -15
- package/dist/adapter-utils/format-compiler-log.js.map +1 -1
- package/dist/dist.dev.js +695 -279
- package/dist/dist.min.js +10 -9
- package/dist/index.cjs +481 -161
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/portable/uniform-buffer-layout.d.ts +13 -4
- package/dist/portable/uniform-buffer-layout.d.ts.map +1 -1
- package/dist/portable/uniform-buffer-layout.js +88 -55
- package/dist/portable/uniform-buffer-layout.js.map +1 -1
- package/dist/shadertypes/data-types/decode-data-types.d.ts.map +1 -1
- package/dist/shadertypes/data-types/decode-data-types.js +2 -1
- package/dist/shadertypes/data-types/decode-data-types.js.map +1 -1
- package/dist/shadertypes/data-types/shader-types.d.ts +5 -7
- package/dist/shadertypes/data-types/shader-types.d.ts.map +1 -1
- package/dist/shadertypes/textures/pixel-utils.js +4 -4
- package/dist/shadertypes/textures/pixel-utils.js.map +1 -1
- package/dist/shadertypes/textures/texture-format-decoder.d.ts +25 -8
- package/dist/shadertypes/textures/texture-format-decoder.d.ts.map +1 -1
- package/dist/shadertypes/textures/texture-format-decoder.js +60 -34
- package/dist/shadertypes/textures/texture-format-decoder.js.map +1 -1
- package/dist/shadertypes/textures/texture-formats.d.ts +43 -16
- package/dist/shadertypes/textures/texture-formats.d.ts.map +1 -1
- package/dist/shadertypes/textures/texture-formats.js.map +1 -1
- package/dist/shadertypes/textures/texture-layout.d.ts +5 -0
- package/dist/shadertypes/textures/texture-layout.d.ts.map +1 -0
- package/dist/shadertypes/textures/texture-layout.js +41 -0
- package/dist/shadertypes/textures/texture-layout.js.map +1 -0
- package/dist/utils/assert.d.ts +5 -0
- package/dist/utils/assert.d.ts.map +1 -0
- package/dist/utils/assert.js +17 -0
- package/dist/utils/assert.js.map +1 -0
- package/package.json +5 -5
- package/src/adapter/canvas-context.ts +87 -20
- package/src/adapter/device.ts +23 -5
- package/src/adapter/resources/command-buffer.ts +1 -1
- package/src/adapter/resources/command-encoder.ts +7 -7
- package/src/adapter/resources/fence.ts +30 -0
- package/src/adapter/resources/framebuffer.ts +15 -12
- package/src/adapter/resources/resource.ts +5 -0
- package/src/adapter/resources/shader.ts +28 -28
- package/src/adapter/resources/texture.ts +176 -28
- package/src/adapter-utils/format-compiler-log.ts +23 -15
- package/src/index.ts +12 -2
- package/src/portable/uniform-buffer-layout.ts +122 -63
- package/src/shadertypes/data-types/decode-data-types.ts +2 -1
- package/src/shadertypes/data-types/shader-types.ts +14 -7
- package/src/shadertypes/textures/pixel-utils.ts +4 -4
- package/src/shadertypes/textures/texture-format-decoder.ts +97 -42
- package/src/shadertypes/textures/texture-formats.ts +54 -15
- package/src/shadertypes/textures/texture-layout.ts +60 -0
- package/src/utils/assert.ts +18 -0
package/src/adapter/device.ts
CHANGED
|
@@ -24,6 +24,7 @@ import type {CommandBuffer} from './resources/command-buffer';
|
|
|
24
24
|
import type {VertexArray, VertexArrayProps} from './resources/vertex-array';
|
|
25
25
|
import type {TransformFeedback, TransformFeedbackProps} from './resources/transform-feedback';
|
|
26
26
|
import type {QuerySet, QuerySetProps} from './resources/query-set';
|
|
27
|
+
import type {Fence} from './resources/fence';
|
|
27
28
|
|
|
28
29
|
import {getVertexFormatInfo} from '../shadertypes/vertex-arrays/decode-vertex-format';
|
|
29
30
|
import {textureFormatDecoder} from '../shadertypes/textures/texture-format-decoder';
|
|
@@ -400,7 +401,7 @@ export abstract class Device {
|
|
|
400
401
|
/** True if this device has been reused during device creation (app has multiple references) */
|
|
401
402
|
_reused: boolean = false;
|
|
402
403
|
/** Used by other luma.gl modules to store data on the device */
|
|
403
|
-
|
|
404
|
+
private _moduleData: Record<string, Record<string, unknown>> = {};
|
|
404
405
|
|
|
405
406
|
// Capabilities
|
|
406
407
|
|
|
@@ -451,9 +452,6 @@ export abstract class Device {
|
|
|
451
452
|
return textureCaps;
|
|
452
453
|
}
|
|
453
454
|
|
|
454
|
-
/** Return the implementation specific alignment for a texture format. 1 on WebGL, 256 on WebGPU */
|
|
455
|
-
abstract getTextureByteAlignment(): number;
|
|
456
|
-
|
|
457
455
|
/** Calculates the number of mip levels for a texture of width, height and in case of 3d textures only, depth */
|
|
458
456
|
getMipLevelCount(width: number, height: number, depth3d: number = 1): number {
|
|
459
457
|
const maxSize = Math.max(width, height, depth3d);
|
|
@@ -548,7 +546,13 @@ export abstract class Device {
|
|
|
548
546
|
const isHandled = this.props.onError(error, context);
|
|
549
547
|
if (!isHandled) {
|
|
550
548
|
// Note: Returns a function that must be called: `device.reportError(...)()`
|
|
551
|
-
return log.error(
|
|
549
|
+
return log.error(
|
|
550
|
+
this.type === 'webgl' ? '%cWebGL' : '%cWebGPU',
|
|
551
|
+
'color: white; background: red; padding: 2px 6px; border-radius: 3px;',
|
|
552
|
+
error.message,
|
|
553
|
+
context,
|
|
554
|
+
...args
|
|
555
|
+
);
|
|
552
556
|
}
|
|
553
557
|
return () => {};
|
|
554
558
|
}
|
|
@@ -622,6 +626,11 @@ or create a device with the 'debug: true' prop.`;
|
|
|
622
626
|
|
|
623
627
|
abstract createQuerySet(props: QuerySetProps): QuerySet;
|
|
624
628
|
|
|
629
|
+
/** Create a fence sync object */
|
|
630
|
+
createFence(): Fence {
|
|
631
|
+
throw new Error('createFence() not implemented');
|
|
632
|
+
}
|
|
633
|
+
|
|
625
634
|
/** Create a RenderPass using the default CommandEncoder */
|
|
626
635
|
beginRenderPass(props?: RenderPassProps): RenderPass {
|
|
627
636
|
return this.commandEncoder.beginRenderPass(props);
|
|
@@ -711,6 +720,15 @@ or create a device with the 'debug: true' prop.`;
|
|
|
711
720
|
throw new Error('not implemented');
|
|
712
721
|
}
|
|
713
722
|
|
|
723
|
+
// INTERNAL LUMA.GL METHODS
|
|
724
|
+
|
|
725
|
+
getModuleData<ModuleDataT extends Record<string, unknown>>(moduleName: string): ModuleDataT {
|
|
726
|
+
this._moduleData[moduleName] ||= {};
|
|
727
|
+
return this._moduleData[moduleName] as ModuleDataT;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
// INTERNAL HELPERS
|
|
731
|
+
|
|
714
732
|
// IMPLEMENTATION
|
|
715
733
|
|
|
716
734
|
/** Helper to get the canvas context props */
|
|
@@ -11,7 +11,7 @@ import {Resource, ResourceProps} from './resource';
|
|
|
11
11
|
// // onSubmittedWorkDone(): Promise<undefined>;
|
|
12
12
|
|
|
13
13
|
// writeBuffer(options: WriteBufferOptions): void;
|
|
14
|
-
// writeTexture(options:
|
|
14
|
+
// writeTexture(options: TextureWriteOptions): void;
|
|
15
15
|
|
|
16
16
|
// // copyExternalImageToTexture(
|
|
17
17
|
// // GPUImageCopyExternalImage source,
|
|
@@ -27,11 +27,11 @@ export type CopyBufferToTextureOptions = {
|
|
|
27
27
|
byteOffset?: number;
|
|
28
28
|
destinationTexture: Texture;
|
|
29
29
|
mipLevel?: number; // = 0;
|
|
30
|
-
origin?: [number, number, number]
|
|
30
|
+
origin?: [number, number, number];
|
|
31
31
|
aspect?: 'all' | 'stencil-only' | 'depth-only';
|
|
32
32
|
bytesPerRow: number;
|
|
33
33
|
rowsPerImage: number;
|
|
34
|
-
size: [number, number, number]
|
|
34
|
+
size: [number, number, number];
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
export type CopyTextureToBufferOptions = {
|
|
@@ -49,7 +49,7 @@ export type CopyTextureToBufferOptions = {
|
|
|
49
49
|
width?: number;
|
|
50
50
|
height?: number;
|
|
51
51
|
depthOrArrayLayers?: number;
|
|
52
|
-
origin?: number
|
|
52
|
+
origin?: [number, number, number];
|
|
53
53
|
|
|
54
54
|
/** Destination buffer */
|
|
55
55
|
destinationBuffer: Buffer;
|
|
@@ -74,7 +74,7 @@ export type CopyTextureToTextureOptions = {
|
|
|
74
74
|
/** Mip-map level of the texture to copy to/from. (Default 0) */
|
|
75
75
|
mipLevel?: number;
|
|
76
76
|
/** Defines the origin of the copy - the minimum corner of the texture sub-region to copy from. */
|
|
77
|
-
origin?: number
|
|
77
|
+
origin?: [number, number, number];
|
|
78
78
|
/** Defines which aspects of the {@link GPUImageCopyTexture#texture} to copy to/from. */
|
|
79
79
|
aspect?: 'all' | 'stencil-only' | 'depth-only';
|
|
80
80
|
|
|
@@ -83,7 +83,7 @@ export type CopyTextureToTextureOptions = {
|
|
|
83
83
|
/** Mip-map level of the texture to copy to/from. (Default 0) */
|
|
84
84
|
destinationMipLevel?: number;
|
|
85
85
|
/** Defines the origin of the copy - the minimum corner of the texture sub-region to copy to. */
|
|
86
|
-
destinationOrigin?: number
|
|
86
|
+
destinationOrigin?: [number, number, number];
|
|
87
87
|
/** Defines which aspects of the {@link GPUImageCopyTexture#texture} to copy to/from. */
|
|
88
88
|
destinationAspect?: 'all' | 'stencil-only' | 'depth-only';
|
|
89
89
|
|
|
@@ -113,7 +113,7 @@ export type ClearTextureOptions = {
|
|
|
113
113
|
// size?: number;
|
|
114
114
|
// };
|
|
115
115
|
|
|
116
|
-
// export type
|
|
116
|
+
// export type TextureWriteOptions = {
|
|
117
117
|
// destination: Texture;
|
|
118
118
|
// mipLevel?: number; // = 0;
|
|
119
119
|
// origin?: [number, number, number] | number[];
|
|
@@ -166,7 +166,7 @@ export abstract class CommandEncoder extends Resource<CommandEncoderProps> {
|
|
|
166
166
|
/** Add a command that clears a texture mip level. */
|
|
167
167
|
// abstract clearTexture(options: ClearTextureOptions): void;
|
|
168
168
|
|
|
169
|
-
// abstract readTexture(options:
|
|
169
|
+
// abstract readTexture(options: TextureReadOptions): Promise<TypedArray>;
|
|
170
170
|
|
|
171
171
|
/** Reads results from a query set into a GPU buffer. Values are 64 bits so byteLength must be querySet.props.count * 8 */
|
|
172
172
|
abstract resolveQuerySet(
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// luma.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
import type {Device} from '../device';
|
|
6
|
+
import {Resource, type ResourceProps} from './resource';
|
|
7
|
+
|
|
8
|
+
export type FenceProps = ResourceProps;
|
|
9
|
+
|
|
10
|
+
/** Synchronization primitive that resolves when GPU work is completed */
|
|
11
|
+
export abstract class Fence extends Resource<FenceProps> {
|
|
12
|
+
static override defaultProps: Required<FenceProps> = {
|
|
13
|
+
...Resource.defaultProps
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
[Symbol.toStringTag]: string = 'WEBGLFence';
|
|
17
|
+
|
|
18
|
+
/** Promise that resolves when the fence is signaled */
|
|
19
|
+
abstract readonly signaled: Promise<void>;
|
|
20
|
+
|
|
21
|
+
constructor(device: Device, props: FenceProps = {}) {
|
|
22
|
+
super(device, props, Fence.defaultProps);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Destroy the fence and release any resources */
|
|
26
|
+
abstract override destroy(): void;
|
|
27
|
+
|
|
28
|
+
/** Check if the fence has been signaled */
|
|
29
|
+
abstract isSignaled(): boolean;
|
|
30
|
+
}
|
|
@@ -56,7 +56,12 @@ export abstract class Framebuffer extends Resource<FramebufferProps> {
|
|
|
56
56
|
const depthStencilAttachment =
|
|
57
57
|
this.depthStencilAttachment && this.depthStencilAttachment.texture.clone(size);
|
|
58
58
|
|
|
59
|
-
return this.device.createFramebuffer({
|
|
59
|
+
return this.device.createFramebuffer({
|
|
60
|
+
...this.props,
|
|
61
|
+
...size,
|
|
62
|
+
colorAttachments,
|
|
63
|
+
depthStencilAttachment
|
|
64
|
+
});
|
|
60
65
|
}
|
|
61
66
|
|
|
62
67
|
/**
|
|
@@ -146,17 +151,15 @@ export abstract class Framebuffer extends Resource<FramebufferProps> {
|
|
|
146
151
|
* and destroys existing textures if owned
|
|
147
152
|
*/
|
|
148
153
|
protected resizeAttachments(width: number, height: number): void {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}
|
|
159
|
-
}
|
|
154
|
+
this.colorAttachments.forEach((colorAttachment, i) => {
|
|
155
|
+
const resizedTexture = colorAttachment.texture.clone({
|
|
156
|
+
width,
|
|
157
|
+
height
|
|
158
|
+
});
|
|
159
|
+
this.destroyAttachedResource(colorAttachment);
|
|
160
|
+
this.colorAttachments[i] = resizedTexture.view;
|
|
161
|
+
this.attachResource(resizedTexture.view);
|
|
162
|
+
});
|
|
160
163
|
|
|
161
164
|
if (this.depthStencilAttachment) {
|
|
162
165
|
const resizedTexture = this.depthStencilAttachment.texture.clone({
|
|
@@ -33,10 +33,15 @@ export abstract class Resource<Props extends ResourceProps> {
|
|
|
33
33
|
|
|
34
34
|
/** props.id, for debugging. */
|
|
35
35
|
id: string;
|
|
36
|
+
/** The props that this resource was created with */
|
|
36
37
|
readonly props: Required<Props>;
|
|
38
|
+
/** User data object, reserved for the application */
|
|
37
39
|
readonly userData: Record<string, unknown> = {};
|
|
40
|
+
/** The device that this resource is associated with */
|
|
38
41
|
abstract readonly device: Device;
|
|
42
|
+
/** The handle for the underlying resource, e.g. WebGL object or WebGPU handle */
|
|
39
43
|
abstract readonly handle: unknown;
|
|
44
|
+
/** The device that this resource is associated with - TODO can we remove this dup? */
|
|
40
45
|
private _device: Device;
|
|
41
46
|
|
|
42
47
|
/** Whether this resource has been destroyed */
|
|
@@ -106,38 +106,38 @@ export abstract class Shader extends Resource<ShaderProps> {
|
|
|
106
106
|
|
|
107
107
|
const shaderName: string = shaderId; // getShaderName(this.source) || ;
|
|
108
108
|
const shaderTitle: string = `${this.stage} shader "${shaderName}"`;
|
|
109
|
-
|
|
109
|
+
const htmlLog = formatCompilerLog(messages, this.source, {showSourceCode: 'all', html: true});
|
|
110
110
|
// Show translated source if available
|
|
111
111
|
const translatedSource = this.getTranslatedSource();
|
|
112
|
+
|
|
113
|
+
const container = document.createElement('div');
|
|
114
|
+
container.innerHTML = `\
|
|
115
|
+
<h1>Compilation error in ${shaderTitle}</h1>
|
|
116
|
+
<div style="display:flex;position:fixed;top:10px;right:20px;gap:2px;">
|
|
117
|
+
<button id="copy">Copy source</button><br/>
|
|
118
|
+
<button id="close">Close</button>
|
|
119
|
+
</div>
|
|
120
|
+
<code><pre>${htmlLog}</pre></code>`;
|
|
112
121
|
if (translatedSource) {
|
|
113
|
-
|
|
122
|
+
container.innerHTML += `<br /><h1>Translated Source</h1><br /><br /><code><pre>${translatedSource}</pre></code>`;
|
|
114
123
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
button.
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
errors[0]?.scrollIntoView();
|
|
132
|
-
|
|
133
|
-
// TODO - add a small embedded copy button (instead of main button)
|
|
134
|
-
button.onclick = () => {
|
|
135
|
-
// const source = this.source.replaceAll('\n', '<br />');
|
|
136
|
-
const dataURI = `data:text/plain,${encodeURIComponent(this.source)}`;
|
|
137
|
-
navigator.clipboard.writeText(dataURI);
|
|
124
|
+
container.style.top = '0';
|
|
125
|
+
container.style.left = '0';
|
|
126
|
+
container.style.background = 'white';
|
|
127
|
+
container.style.position = 'fixed';
|
|
128
|
+
container.style.zIndex = '9999';
|
|
129
|
+
container.style.maxWidth = '100vw';
|
|
130
|
+
container.style.maxHeight = '100vh';
|
|
131
|
+
container.style.overflowY = 'auto';
|
|
132
|
+
document.body.appendChild(container);
|
|
133
|
+
const error = container.querySelector('.luma-compiler-log-error');
|
|
134
|
+
error?.scrollIntoView();
|
|
135
|
+
(container.querySelector('button#close') as HTMLButtonElement).onclick = () => {
|
|
136
|
+
container.remove();
|
|
137
|
+
};
|
|
138
|
+
(container.querySelector('button#copy') as HTMLButtonElement).onclick = () => {
|
|
139
|
+
navigator.clipboard.writeText(this.source);
|
|
138
140
|
};
|
|
139
|
-
|
|
140
|
-
// TODO - add a small embedded close button
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
static override defaultProps: Required<ShaderProps> = {
|
|
@@ -162,5 +162,5 @@ function getShaderIdFromProps(props: ShaderProps): string {
|
|
|
162
162
|
function getShaderName(shader: string, defaultName: string = 'unnamed'): string {
|
|
163
163
|
const SHADER_NAME_REGEXP = /#define[\s*]SHADER_NAME[\s*]([A-Za-z0-9_-]+)[\s*]/;
|
|
164
164
|
const match = SHADER_NAME_REGEXP.exec(shader);
|
|
165
|
-
return match
|
|
165
|
+
return match?.[1] ?? defaultName;
|
|
166
166
|
}
|
|
@@ -2,14 +2,19 @@
|
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
|
-
import {TypedArray} from '@math.gl/types';
|
|
6
|
-
import type
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
import {ExternalImage} from '../../image-utils/image-types';
|
|
5
|
+
import {type TypedArray} from '@math.gl/types';
|
|
6
|
+
import {type Device} from '../device';
|
|
7
|
+
import {
|
|
8
|
+
type TextureFormat,
|
|
9
|
+
type TextureMemoryLayout
|
|
10
|
+
} from '../../shadertypes/textures/texture-formats';
|
|
11
|
+
import {type ExternalImage} from '../../image-utils/image-types';
|
|
12
|
+
import {type TextureView, type TextureViewProps} from './texture-view';
|
|
13
|
+
import {Resource, type ResourceProps} from './resource';
|
|
14
|
+
import {Sampler, type SamplerProps} from './sampler';
|
|
15
|
+
import {Buffer} from './buffer';
|
|
12
16
|
import {log} from '../../utils/log';
|
|
17
|
+
import {textureFormatDecoder} from '../../shadertypes/textures/texture-format-decoder';
|
|
13
18
|
|
|
14
19
|
/** Options for Texture.copyExternalImage */
|
|
15
20
|
export type CopyExternalImageOptions = {
|
|
@@ -65,18 +70,40 @@ export type CopyImageDataOptions = {
|
|
|
65
70
|
aspect?: 'all' | 'stencil-only' | 'depth-only';
|
|
66
71
|
};
|
|
67
72
|
|
|
68
|
-
|
|
73
|
+
export type TextureReadOptions = {
|
|
74
|
+
x?: number;
|
|
75
|
+
y?: number;
|
|
76
|
+
z?: number;
|
|
77
|
+
width?: number;
|
|
78
|
+
height?: number;
|
|
79
|
+
depthOrArrayLayers?: number;
|
|
80
|
+
mipLevel?: number;
|
|
81
|
+
aspect?: 'all' | 'stencil-only' | 'depth-only';
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export type TextureWriteOptions = {
|
|
85
|
+
x?: number;
|
|
86
|
+
y?: number;
|
|
87
|
+
z?: number;
|
|
88
|
+
width?: number;
|
|
89
|
+
height?: number;
|
|
90
|
+
depthOrArrayLayers?: number;
|
|
91
|
+
mipLevel?: number;
|
|
92
|
+
aspect?: 'all' | 'stencil-only' | 'depth-only';
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const BASE_DIMENSIONS = {
|
|
69
96
|
'1d': '1d',
|
|
70
97
|
'2d': '2d',
|
|
71
98
|
'2d-array': '2d',
|
|
72
99
|
cube: '2d',
|
|
73
100
|
'cube-array': '2d',
|
|
74
101
|
'3d': '3d'
|
|
75
|
-
}
|
|
102
|
+
} as const satisfies Record<string, '1d' | '2d' | '3d'>;
|
|
76
103
|
|
|
77
104
|
/** Texture properties */
|
|
78
105
|
export type TextureProps = ResourceProps & {
|
|
79
|
-
/** @deprecated Use
|
|
106
|
+
/** @deprecated Use DynamicTexture to create textures with data. */
|
|
80
107
|
data?: ExternalImage | TypedArray | null;
|
|
81
108
|
/** Dimension of this texture. Defaults to '2d' */
|
|
82
109
|
dimension?: '1d' | '2d' | '2d-array' | 'cube' | 'cube-array' | '3d';
|
|
@@ -130,19 +157,26 @@ export abstract class Texture extends Resource<TextureProps> {
|
|
|
130
157
|
/** format of this texture */
|
|
131
158
|
readonly format: TextureFormat;
|
|
132
159
|
/** width in pixels of this texture */
|
|
133
|
-
width: number;
|
|
160
|
+
readonly width: number;
|
|
134
161
|
/** height in pixels of this texture */
|
|
135
|
-
height: number;
|
|
162
|
+
readonly height: number;
|
|
136
163
|
/** depth of this texture */
|
|
137
|
-
depth: number;
|
|
164
|
+
readonly depth: number;
|
|
138
165
|
/** mip levels in this texture */
|
|
139
|
-
mipLevels: number;
|
|
166
|
+
readonly mipLevels: number;
|
|
167
|
+
/** Rows are multiples of this length, padded with extra bytes if needed */
|
|
168
|
+
readonly byteAlignment: number;
|
|
140
169
|
/** Default sampler for this texture */
|
|
141
170
|
abstract sampler: Sampler;
|
|
142
171
|
/** Default view for this texture */
|
|
143
172
|
abstract view: TextureView;
|
|
144
173
|
|
|
145
|
-
/**
|
|
174
|
+
/** The ready promise is always resolved. It is provided for type compatibility with DynamicTexture. */
|
|
175
|
+
readonly ready: Promise<Texture> = Promise.resolve(this);
|
|
176
|
+
/** isReady is always true. It is provided for type compatibility with DynamicTexture. */
|
|
177
|
+
readonly isReady: boolean = true;
|
|
178
|
+
|
|
179
|
+
/** "Time" of last update. Monotonically increasing timestamp. TODO move to DynamicTexture? */
|
|
146
180
|
updateTimestamp: number;
|
|
147
181
|
|
|
148
182
|
override get [Symbol.toStringTag](): string {
|
|
@@ -154,7 +188,7 @@ export abstract class Texture extends Resource<TextureProps> {
|
|
|
154
188
|
}
|
|
155
189
|
|
|
156
190
|
/** Do not use directly. Create with device.createTexture() */
|
|
157
|
-
constructor(device: Device, props: TextureProps) {
|
|
191
|
+
constructor(device: Device, props: TextureProps, backendProps?: {byteAlignment?: number}) {
|
|
158
192
|
props = Texture.normalizeProps(device, props);
|
|
159
193
|
super(device, props, Texture.defaultProps);
|
|
160
194
|
this.dimension = this.props.dimension;
|
|
@@ -167,6 +201,10 @@ export abstract class Texture extends Resource<TextureProps> {
|
|
|
167
201
|
this.depth = this.props.depth;
|
|
168
202
|
this.mipLevels = this.props.mipLevels;
|
|
169
203
|
|
|
204
|
+
if (this.dimension === 'cube') {
|
|
205
|
+
this.depth = 6;
|
|
206
|
+
}
|
|
207
|
+
|
|
170
208
|
// Calculate size, if not provided
|
|
171
209
|
if (this.props.width === undefined || this.props.height === undefined) {
|
|
172
210
|
if (device.isExternalImage(props.data)) {
|
|
@@ -178,38 +216,122 @@ export abstract class Texture extends Resource<TextureProps> {
|
|
|
178
216
|
this.height = 1;
|
|
179
217
|
if (this.props.width === undefined || this.props.height === undefined) {
|
|
180
218
|
log.warn(
|
|
181
|
-
`${this} created with undefined width or height. This is deprecated. Use
|
|
219
|
+
`${this} created with undefined width or height. This is deprecated. Use DynamicTexture instead.`
|
|
182
220
|
)();
|
|
183
221
|
}
|
|
184
222
|
}
|
|
185
223
|
}
|
|
186
224
|
|
|
225
|
+
this.byteAlignment = backendProps?.byteAlignment || 1;
|
|
226
|
+
|
|
187
227
|
// TODO - perhaps this should be set on async write completion?
|
|
188
228
|
this.updateTimestamp = device.incrementTimestamp();
|
|
189
229
|
}
|
|
190
230
|
|
|
231
|
+
/**
|
|
232
|
+
* Create a new texture with the same parameters and optionally a different size
|
|
233
|
+
* @note Textures are immutable and cannot be resized after creation, but we can create a similar texture with the same parameters but a new size.
|
|
234
|
+
* @note Does not copy contents of the texture
|
|
235
|
+
*/
|
|
236
|
+
clone(size?: {width: number; height: number}): Texture {
|
|
237
|
+
return this.device.createTexture({...this.props, ...size});
|
|
238
|
+
}
|
|
239
|
+
|
|
191
240
|
/** Set sampler props associated with this texture */
|
|
192
241
|
setSampler(sampler: Sampler | SamplerProps): void {
|
|
193
242
|
this.sampler = sampler instanceof Sampler ? sampler : this.device.createSampler(sampler);
|
|
194
243
|
}
|
|
244
|
+
|
|
195
245
|
/** Create a texture view for this texture */
|
|
196
246
|
abstract createView(props: TextureViewProps): TextureView;
|
|
247
|
+
|
|
197
248
|
/** Copy an image (e.g an ImageBitmap) into the texture */
|
|
198
249
|
abstract copyExternalImage(options: CopyExternalImageOptions): {width: number; height: number};
|
|
250
|
+
|
|
199
251
|
/** Copy raw image data (bytes) into the texture */
|
|
200
252
|
abstract copyImageData(options: CopyImageDataOptions): void;
|
|
201
|
-
/** Generate mipmaps (WebGL only) */
|
|
202
|
-
abstract generateMipmapsWebGL(): void;
|
|
203
253
|
|
|
204
254
|
/**
|
|
205
|
-
*
|
|
206
|
-
* @
|
|
207
|
-
* @note Does not copy contents of the texture
|
|
255
|
+
* Calculates the memory layout of the texture, required when reading and writing data.
|
|
256
|
+
* @return the memory layout of the texture, in particular bytesPerRow which includes required padding
|
|
208
257
|
*/
|
|
209
|
-
|
|
210
|
-
|
|
258
|
+
computeMemoryLayout(options_: TextureReadOptions = {}): TextureMemoryLayout {
|
|
259
|
+
const options = this._normalizeTextureReadOptions(options_);
|
|
260
|
+
const {width = this.width, height = this.height, depthOrArrayLayers = this.depth} = options;
|
|
261
|
+
const {format, byteAlignment} = this;
|
|
262
|
+
|
|
263
|
+
// TODO - does the overriding above make sense?
|
|
264
|
+
// return textureFormatDecoder.computeMemoryLayout(this);
|
|
265
|
+
return textureFormatDecoder.computeMemoryLayout({
|
|
266
|
+
format,
|
|
267
|
+
width,
|
|
268
|
+
height,
|
|
269
|
+
depth: depthOrArrayLayers,
|
|
270
|
+
byteAlignment
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Read the contents of a texture into a GPU Buffer.
|
|
276
|
+
* @returns A Buffer containing the texture data.
|
|
277
|
+
*
|
|
278
|
+
* @note The memory layout of the texture data is determined by the texture format and dimensions.
|
|
279
|
+
* @note The application can call Texture.computeMemoryLayout() to compute the layout.
|
|
280
|
+
* @note The application can call Buffer.readAsync()
|
|
281
|
+
* @note If not supplied a buffer will be created and the application needs to call Buffer.destroy
|
|
282
|
+
*/
|
|
283
|
+
readBuffer(options?: TextureReadOptions, buffer?: Buffer): Buffer {
|
|
284
|
+
throw new Error('readBuffer not implemented');
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Reads data from a texture into an ArrayBuffer.
|
|
289
|
+
* @returns An ArrayBuffer containing the texture data.
|
|
290
|
+
*
|
|
291
|
+
* @note The memory layout of the texture data is determined by the texture format and dimensions.
|
|
292
|
+
* @note The application can call Texture.computeMemoryLayout() to compute the layout.
|
|
293
|
+
*/
|
|
294
|
+
readDataAsync(options?: TextureReadOptions): Promise<ArrayBuffer> {
|
|
295
|
+
throw new Error('readBuffer not implemented');
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Writes an GPU Buffer into a texture.
|
|
300
|
+
*
|
|
301
|
+
* @note The memory layout of the texture data is determined by the texture format and dimensions.
|
|
302
|
+
* @note The application can call Texture.computeMemoryLayout() to compute the layout.
|
|
303
|
+
*/
|
|
304
|
+
writeBuffer(buffer: Buffer, options?: TextureWriteOptions): void {
|
|
305
|
+
throw new Error('readBuffer not implemented');
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Writes an array buffer into a texture.
|
|
310
|
+
*
|
|
311
|
+
* @note The memory layout of the texture data is determined by the texture format and dimensions.
|
|
312
|
+
* @note The application can call Texture.computeMemoryLayout() to compute the layout.
|
|
313
|
+
*/
|
|
314
|
+
writeData(data: ArrayBuffer | ArrayBufferView, options?: TextureWriteOptions): void {
|
|
315
|
+
throw new Error('readBuffer not implemented');
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// IMPLEMENTATION SPECIFIC
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* WebGL can read data synchronously.
|
|
322
|
+
* @note While it is convenient, the performance penalty is very significant
|
|
323
|
+
*/
|
|
324
|
+
readDataSyncWebGL(options?: TextureReadOptions): ArrayBuffer | ArrayBufferView {
|
|
325
|
+
throw new Error('readDataSyncWebGL not available');
|
|
211
326
|
}
|
|
212
327
|
|
|
328
|
+
/** Generate mipmaps (WebGL only) */
|
|
329
|
+
generateMipmapsWebGL(): void {
|
|
330
|
+
throw new Error('generateMipmapsWebGL not available');
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// HELPERS
|
|
334
|
+
|
|
213
335
|
/** Ensure we have integer coordinates */
|
|
214
336
|
protected static normalizeProps(device: Device, props: TextureProps): TextureProps {
|
|
215
337
|
const newProps = {...props};
|
|
@@ -225,8 +347,6 @@ export abstract class Texture extends Resource<TextureProps> {
|
|
|
225
347
|
return newProps;
|
|
226
348
|
}
|
|
227
349
|
|
|
228
|
-
// HELPERS
|
|
229
|
-
|
|
230
350
|
/** Initialize texture with supplied props */
|
|
231
351
|
// eslint-disable-next-line max-statements
|
|
232
352
|
_initializeData(data: TextureProps['data']): void {
|
|
@@ -290,13 +410,30 @@ export abstract class Texture extends Resource<TextureProps> {
|
|
|
290
410
|
return options;
|
|
291
411
|
}
|
|
292
412
|
|
|
293
|
-
|
|
413
|
+
_normalizeTextureReadOptions(options_: TextureReadOptions): Required<TextureReadOptions> {
|
|
414
|
+
const {width, height} = this;
|
|
415
|
+
const options = {...Texture.defaultTextureReadOptions, width, height, ...options_};
|
|
416
|
+
// WebGL will error if we try to copy outside the bounds of the texture
|
|
417
|
+
options.width = Math.min(options.width, this.width - options.x);
|
|
418
|
+
options.height = Math.min(options.height, this.height - options.y);
|
|
419
|
+
return options;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
_normalizeTextureWriteOptions(options_: TextureWriteOptions): Required<TextureWriteOptions> {
|
|
423
|
+
const {width, height} = this;
|
|
424
|
+
const options = {...Texture.defaultTextureReadOptions, width, height, ...options_};
|
|
425
|
+
// WebGL will error if we try to copy outside the bounds of the texture
|
|
426
|
+
options.width = Math.min(options.width, this.width - options.x);
|
|
427
|
+
options.height = Math.min(options.height, this.height - options.y);
|
|
428
|
+
return options;
|
|
429
|
+
}
|
|
430
|
+
|
|
294
431
|
static override defaultProps: Required<TextureProps> = {
|
|
295
432
|
...Resource.defaultProps,
|
|
296
433
|
data: null,
|
|
297
434
|
dimension: '2d',
|
|
298
435
|
format: 'rgba8unorm',
|
|
299
|
-
usage: Texture.
|
|
436
|
+
usage: Texture.SAMPLE | Texture.RENDER | Texture.COPY_DST,
|
|
300
437
|
width: undefined!,
|
|
301
438
|
height: undefined!,
|
|
302
439
|
depth: 1,
|
|
@@ -335,4 +472,15 @@ export abstract class Texture extends Resource<TextureProps> {
|
|
|
335
472
|
premultipliedAlpha: false,
|
|
336
473
|
flipY: false
|
|
337
474
|
};
|
|
475
|
+
|
|
476
|
+
protected static defaultTextureReadOptions: Required<TextureReadOptions> = {
|
|
477
|
+
x: 0,
|
|
478
|
+
y: 0,
|
|
479
|
+
z: 0,
|
|
480
|
+
width: undefined!,
|
|
481
|
+
height: undefined!,
|
|
482
|
+
depthOrArrayLayers: 1,
|
|
483
|
+
mipLevel: 0,
|
|
484
|
+
aspect: 'all'
|
|
485
|
+
};
|
|
338
486
|
}
|
|
@@ -21,25 +21,33 @@ export function formatCompilerLog(
|
|
|
21
21
|
switch (options?.showSourceCode || 'no') {
|
|
22
22
|
case 'all':
|
|
23
23
|
// Parse the error - note: browser and driver dependent
|
|
24
|
-
let
|
|
24
|
+
let currentMessageIndex = 0;
|
|
25
25
|
for (let lineNum = 1; lineNum <= lines.length; lineNum++) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
formattedLog +=
|
|
26
|
+
const line = lines[lineNum - 1];
|
|
27
|
+
const currentMessage = log[currentMessageIndex];
|
|
28
|
+
if (line && currentMessage) {
|
|
29
|
+
formattedLog += getNumberedLine(line, lineNum, options);
|
|
30
|
+
}
|
|
31
|
+
while (log.length > currentMessageIndex && currentMessage.lineNum === lineNum) {
|
|
32
|
+
const message = log[currentMessageIndex++];
|
|
33
|
+
if (message) {
|
|
34
|
+
formattedLog += formatCompilerMessage(message, lines, message.lineNum, {
|
|
35
|
+
...options,
|
|
36
|
+
inlineSource: false
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// Print any remaining messages
|
|
42
|
+
while (log.length > currentMessageIndex) {
|
|
43
|
+
const message = log[currentMessageIndex++];
|
|
44
|
+
if (message) {
|
|
45
|
+
formattedLog += formatCompilerMessage(message, [], 0, {
|
|
30
46
|
...options,
|
|
31
47
|
inlineSource: false
|
|
32
48
|
});
|
|
33
49
|
}
|
|
34
50
|
}
|
|
35
|
-
// Print any remaining messages
|
|
36
|
-
while (log.length > currentMessage) {
|
|
37
|
-
const message = log[currentMessage++];
|
|
38
|
-
formattedLog += formatCompilerMessage(message, [], 0, {
|
|
39
|
-
...options,
|
|
40
|
-
inlineSource: false
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
51
|
return formattedLog;
|
|
44
52
|
|
|
45
53
|
case 'issues':
|
|
@@ -75,9 +83,9 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
75
83
|
|
|
76
84
|
`;
|
|
77
85
|
}
|
|
78
|
-
const color = message.type === 'error' ? 'red' : '
|
|
86
|
+
const color = message.type === 'error' ? 'red' : 'orange';
|
|
79
87
|
return options?.html
|
|
80
|
-
? `<div class='luma-compiler-log
|
|
88
|
+
? `<div class='luma-compiler-log-${message.type}' style="color:${color};"><b> ${message.type.toUpperCase()}: ${
|
|
81
89
|
message.message
|
|
82
90
|
}</b></div>`
|
|
83
91
|
: `${message.type.toUpperCase()}: ${message.message}`;
|