Skip to content

Commit

Permalink
chore: Prep for Texture refactor (#1968)
Browse files Browse the repository at this point in the history
  • Loading branch information
ibgreen committed Feb 26, 2024
1 parent ae36d56 commit d02bcc5
Show file tree
Hide file tree
Showing 14 changed files with 114 additions and 34 deletions.
3 changes: 2 additions & 1 deletion .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ module.exports = getESLintConfig({
'default-case': ['warn'],
'no-eq-null': ['warn'],
eqeqeq: ['warn'],
radix: 0
radix: 0,
'spaced-comment': ["error", "always", { "exceptions": ["/ <"] }]
// 'accessor-pairs': ['error', {getWithoutSet: false, setWithoutGet: false}]
},

Expand Down
16 changes: 8 additions & 8 deletions examples/api/cubemap/app.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {Device, loadImage, glsl} from '@luma.gl/core';
import {AnimationLoopTemplate, AnimationProps, CubeGeometry, Model, ModelProps} from '@luma.gl/engine';
import {GL} from '@luma.gl/constants';
import {Matrix4, radians} from '@math.gl/core';

const INFO_HTML = `
Expand Down Expand Up @@ -102,18 +101,19 @@ export default class AppAnimationLoopTemplate extends AnimationLoopTemplate {
const cubemap = device.createTexture({
dimension: 'cube',
mipmaps: true,
// @ts-ignore
data: {
[GL.TEXTURE_CUBE_MAP_POSITIVE_X]: loadImage('sky-posx.png'),
[GL.TEXTURE_CUBE_MAP_NEGATIVE_X]: loadImage('sky-negx.png'),
[GL.TEXTURE_CUBE_MAP_POSITIVE_Y]: loadImage('sky-posy.png'),
[GL.TEXTURE_CUBE_MAP_NEGATIVE_Y]: loadImage('sky-negy.png'),
[GL.TEXTURE_CUBE_MAP_POSITIVE_Z]: loadImage('sky-posz.png'),
[GL.TEXTURE_CUBE_MAP_NEGATIVE_Z]: loadImage('sky-negz.png')
'+X': loadImage('sky-posx.png'),
'-X': loadImage('sky-negx.png'),
'+Y': loadImage('sky-posy.png'),
'-Y': loadImage('sky-negy.png'),
'+Z': loadImage('sky-posz.png'),
'-Z': loadImage('sky-negz.png')
}
});

const texture = device.createTexture({
data: 'vis-logo.png',
data: loadImage('vis-logo.png'),
mipmaps: true,
sampler: {
magFilter: 'linear',
Expand Down
4 changes: 2 additions & 2 deletions examples/tutorials/hello-cube/app.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// luma.gl, MIT license
import {glsl, UniformStore, NumberArray, ShaderUniformType} from '@luma.gl/core';
import {glsl, UniformStore, NumberArray, ShaderUniformType, loadImage} from '@luma.gl/core';
import {AnimationLoopTemplate, AnimationProps, Model, CubeGeometry} from '@luma.gl/engine';
import {Matrix4} from '@math.gl/core';

Expand Down Expand Up @@ -70,7 +70,7 @@ export default class AppAnimationLoopTemplate extends AnimationLoopTemplate {
super();

const texture = device.createTexture({
data: 'vis-logo.png',
data: loadImage('vis-logo.png'),
mipmaps: true,
sampler: device.createSampler({
minFilter: 'linear',
Expand Down
5 changes: 2 additions & 3 deletions examples/tutorials/lighting/app.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {glsl, NumberArray} from '@luma.gl/core';
import {glsl, NumberArray, loadImage} from '@luma.gl/core';
import {AnimationLoopTemplate, AnimationProps, Model, CubeGeometry, _ShaderInputs} from '@luma.gl/engine';
import {phongMaterial, lighting, ShaderModule} from '@luma.gl/shadertools';
import {Matrix4} from '@math.gl/core';
Expand Down Expand Up @@ -75,7 +75,6 @@ const app: ShaderModule<AppUniforms, AppUniforms> = {
}
};


// APPLICATION

const eyePosition = [0, 0, 5];
Expand Down Expand Up @@ -112,7 +111,7 @@ export default class AppAnimationLoopTemplate extends AnimationLoopTemplate {
}
});

const texture = device.createTexture({data: 'vis-logo.png'});
const texture = device.createTexture({data: loadImage('vis-logo.png')});

this.model = new Model(device, {
vs,
Expand Down
2 changes: 2 additions & 0 deletions modules/constants/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ export {GL} from './webgl-constants';

// WebGL types
export type {
GLTextureTarget,
GLTextureCubeMapTarget,
GLPrimitiveTopology,
GLPrimitive,
GLDataType,
Expand Down
21 changes: 19 additions & 2 deletions modules/constants/src/webgl-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export type NumberArray = number[] | TypedArray;
export type NumericArray = TypedArray | number[];

/** TypeScript type covering all typed arrays */

export type TypedArray =
| Int8Array
| Uint8Array
Expand All @@ -27,6 +28,22 @@ export type TypedArray =
/** We don't know the type of Framebuffer at this stage */
type Framebuffer = unknown;

/** All possible texture targets */
export type GLTextureTarget =
| GL.TEXTURE_2D
| GL.TEXTURE_CUBE_MAP
| GL.TEXTURE_2D_ARRAY
| GL.TEXTURE_3D;

/** All possible cube face targets for textImage2D */
export type GLTextureCubeMapTarget =
| GL.TEXTURE_CUBE_MAP_POSITIVE_X
| GL.TEXTURE_CUBE_MAP_NEGATIVE_X
| GL.TEXTURE_CUBE_MAP_POSITIVE_Y
| GL.TEXTURE_CUBE_MAP_NEGATIVE_Y
| GL.TEXTURE_CUBE_MAP_POSITIVE_Z
| GL.TEXTURE_CUBE_MAP_NEGATIVE_Z;

/** Rendering primitives. Constants passed to drawElements() or drawArrays() to specify what kind of primitive to render. */
export type GLPrimitiveTopology =
| GL.POINTS
Expand All @@ -50,9 +67,9 @@ export type GLDataType =
| GL.SHORT
| GL.INT;

/** Pixel Type */
/** Pixel Data Type */
export type GLPixelType =
| GL.UNSIGNED_BYTE
| GLDataType
| GL.UNSIGNED_SHORT_5_6_5
| GL.UNSIGNED_SHORT_4_4_4_4
| GL.UNSIGNED_SHORT_5_5_5_1;
Expand Down
12 changes: 11 additions & 1 deletion modules/core-tests/test/adapter/device.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// luma.gl, MIT license
import test from 'tape-promise/tape';
import {getWebGLTestDevices} from '@luma.gl/test-utils';
import {getWebGLTestDevices, getTestDevices} from '@luma.gl/test-utils';

// import {luma} from '@luma.gl/core';

Expand All @@ -13,6 +13,16 @@ test('WebGLDevice#info', (t) => {
t.end();
});

// Minimal test, extensive test in texture-formats.spec
test('WebGLDevice#isTextureFormatCompressed', async (t) => {
for (const device of await getTestDevices()) {
// Just sanity check two types
t.equal(device.isTextureFormatCompressed('rgba8unorm'), false);
t.equal(device.isTextureFormatCompressed('bc3-rgba-unorm'), true)
}
t.end();
});

test('WebGLDevice#lost (Promise)', async (t) => {
// const device = await luma.createDevice({webgl2: false});

Expand Down
18 changes: 12 additions & 6 deletions modules/core-tests/test/adapter/resources/texture.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,18 +132,24 @@ function testFormatDeduction(t, device: Device) {
}
}

test.skip('WebGL#Texture format deduction', t => {
testFormatDeduction(t, webglDevice);
test.skip('WebGL#Texture format deduction', async (t) => {
for (const device of await getTestDevices()) {
testFormatDeduction(t, device);
}
t.end();
});

test.skip('WebGL#Texture format creation', t => {
testFormatCreation(t, webglDevice);
test.skip('WebGL#Texture format creation', async (t) => {
for (const device of await getTestDevices()) {
testFormatCreation(t, device);
}
t.end();
});

test.skip('WebGL#Texture format creation with data', t => {
testFormatCreation(t, webglDevice, true);
test.skip('WebGL#Texture format creation with data', async (t) => {
for (const device of await getTestDevices()) {
testFormatCreation(t, device, true);
}
t.end();
});

Expand Down
13 changes: 13 additions & 0 deletions modules/core-tests/test/adapter/texture-formats.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import test from 'tape-promise/tape';
import {getTestDevices} from '@luma.gl/test-utils';

// import {luma} from '@luma.gl/core';

// TODO - add full reference table, more exhaustive test
test('WebGLDevice#isTextureFormatCompressed', async (t) => {
for (const device of await getTestDevices()) {
t.equal(device.isTextureFormatCompressed('rgba8unorm'), false);
t.equal(device.isTextureFormatCompressed('bc3-rgba-unorm'), true)
}
t.end();
});
3 changes: 3 additions & 0 deletions modules/core-tests/test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ import './adapter/device-helpers/set-device-parameters.spec';
// import './adapter/webgl-canvas-context.spec';

// Resources
import './adapter/texture-formats.spec';

// Resources - TODO these tests only depend on Device and could move to API...
import './adapter/resources/buffer.spec';
import './adapter/resources/command-buffer.spec';
import './adapter/resources/framebuffer.spec';
Expand Down
33 changes: 25 additions & 8 deletions modules/core/src/adapter/device.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import type {CommandEncoder, CommandEncoderProps} from './resources/command-enco
import type {VertexArray, VertexArrayProps} from './resources/vertex-array';
import type {TransformFeedback, TransformFeedbackProps} from './resources/transform-feedback';

import {isTextureFormatCompressed} from './type-utils/decode-texture-format';

/**
* Identifies the GPU vendor and driver.
* @note Chrome WebGPU does not provide much information, though more can be enabled with
Expand Down Expand Up @@ -105,7 +107,7 @@ export abstract class DeviceLimits {
abstract maxComputeWorkgroupSizeZ: number;
/** max ComputeWorkgroupsPerDimension */
abstract maxComputeWorkgroupsPerDimension: number;
};
}

/** Set-like class for features (lets apps check for WebGL / WebGPU extensions) */
export class DeviceFeatures {
Expand All @@ -130,7 +132,6 @@ export type DeviceFeature =
| WebGLDeviceFeature
| WebGLCompressedTextureFeatures;


export type WebGPUDeviceFeature =
| 'depth-clip-control'
| 'indirect-first-instance'
Expand All @@ -144,8 +145,8 @@ export type WebGPUDeviceFeature =
| 'texture-compression-bc'
| 'texture-compression-etc2'
| 'texture-compression-astc';
// | 'depth-clamping' // removed from the WebGPU spec...
// | 'pipeline-statistics-query' // removed from the WebGPU spec...
// | 'depth-clamping' // removed from the WebGPU spec...
// | 'pipeline-statistics-query' // removed from the WebGPU spec...

export type WebGLDeviceFeature =
// webgl extension features
Expand All @@ -156,7 +157,7 @@ export type WebGLDeviceFeature =

// GLSL extension features
| 'shader-noperspective-interpolation-webgl' // Vertex outputs & fragment inputs can have a `noperspective` interpolation qualifier.
| 'shader-conservative-depth-webgl' // GLSL `gl_FragDepth` qualifiers `depth_unchanged` etc can enable early depth test
| 'shader-conservative-depth-webgl' // GLSL `gl_FragDepth` qualifiers `depth_unchanged` etc can enable early depth test
| 'shader-clip-cull-distance-webgl' // Makes gl_ClipDistance and gl_CullDistance available in shaders

// texture rendering
Expand Down Expand Up @@ -202,8 +203,9 @@ export type DeviceProps = {
// preserveDrawingBuffer?: boolean; // Default render target buffers will not be automatically cleared and will preserve their values until cleared or overwritten
// failIfMajorPerformanceCaveat?: boolean; // Do not create if the system performance is low.

onError?: (error: Error) => unknown;
/** Instrument context (at the expense of performance) */
debug?: boolean;
debug?: boolean;
/** Initialize the SpectorJS WebGL debugger */
spector?: boolean;

Expand Down Expand Up @@ -239,7 +241,10 @@ export abstract class Device {
// preserveDrawingBuffer: undefined,
// failIfMajorPerformanceCaveat: undefined

gl: null
gl: null,

// Callbacks
onError: (error: Error) => log.error(error.message)
};

get [Symbol.toStringTag](): string {
Expand Down Expand Up @@ -286,6 +291,11 @@ export abstract class Device {
/** Check if device supports rendering to a specific texture format */
abstract isTextureFormatRenderable(format: TextureFormat): boolean;

/** Check if a specific texture format is GPU compressed */
isTextureFormatCompressed(format: TextureFormat): boolean {
return isTextureFormatCompressed(format);
}

// Device loss

/** `true` if device is already lost */
Expand Down Expand Up @@ -437,7 +447,14 @@ export abstract class Device {
throw new Error('not implemented');
}

// Implementation
// IMPLEMENTATION

// Error Handling

/** Report unhandled device errors */
onError(error: Error) {
this.props.onError(error);
}

protected _getBufferProps(props: BufferProps | ArrayBuffer | ArrayBufferView): BufferProps {
if (props instanceof ArrayBuffer || ArrayBuffer.isView(props)) {
Expand Down
13 changes: 13 additions & 0 deletions modules/core/src/adapter/type-utils/decode-texture-format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ import {TextureFormat} from '../types/texture-formats';
import {VertexType} from '../types/vertex-formats';
import {decodeVertexType} from './decode-data-type';


// prettier-ignore
const COMPRESSED_TEXTURE_FORMAT_PREFIXES = [
'bc1', 'bc2', 'bc3', 'bc4', 'bc5', 'bc6', 'bc7', 'etc1', 'etc2', 'eac', 'atc', 'astc', 'pvrtc'
];

const REGEX = /^(rg?b?a?)([0-9]*)([a-z]*)(-srgb)?(-webgl|-unsized)?$/;

export type DecodedTextureFormat = {
Expand All @@ -17,6 +23,13 @@ export type DecodedTextureFormat = {
normalized: boolean;
}

/**
* Returns true if a texture format is GPU compressed
*/
export function isTextureFormatCompressed(textureFormat: TextureFormat): boolean {
return COMPRESSED_TEXTURE_FORMAT_PREFIXES.some(prefix => textureFormat.startsWith(prefix));
}

/**
* Decodes a vertex format, returning type, components, byte length and flags (integer, signed, normalized)
*/
Expand Down
2 changes: 1 addition & 1 deletion modules/core/src/utils/load-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export async function loadImage(
url: string,
opts?: {crossOrigin?: string}
): Promise<HTMLImageElement> {
return new Promise((resolve, reject) => {
return await new Promise((resolve, reject) => {
try {
const image = new Image();
image.onload = () => resolve(image);
Expand Down
3 changes: 1 addition & 2 deletions modules/webgpu/src/adapter/webgpu-canvas-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ export class WebGPUCanvasContext extends CanvasContext {
readonly device: WebGPUDevice;
readonly gpuCanvasContext: GPUCanvasContext;
/** Format of returned textures: "bgra8unorm", "rgba8unorm", "rgba16float". */
// @ts-ignore - TODO - fix this
readonly format: TextureFormat = navigator.gpu.getPreferredCanvasFormat();
readonly format: TextureFormat = navigator.gpu.getPreferredCanvasFormat() as TextureFormat;
/** Default stencil format for depth textures */
depthStencilFormat: TextureFormat = 'depth24plus';

Expand Down

0 comments on commit d02bcc5

Please sign in to comment.