s2maps-gpu
Version:
S2 Maps GPU - An open source, high-performance, and GPU-accelerated map engine for rendering large-scale, interactive maps.
276 lines (275 loc) • 10.7 kB
TypeScript
import type { ColorArray } from 'style/color/index.js';
import type { ColorMode } from 's2/s2Map.js';
import type { GlyphImages } from 'workers/source/glyphSource.js';
import type { MapOptions } from 'ui/s2mapUI.js';
import type { Painter } from 'gpu/painter.spec.js';
import type { SpriteImageMessage } from 'workers/worker.spec.js';
import type { Tile } from 'source/tile.spec.js';
import type { GPUType, Projection } from 'style/style.spec.js';
import type { MaskSource, TileMaskSource } from 'gpu/workflows/workflow.spec.js';
/** A Presentation guideline */
export interface Presentation {
width: number;
height: number;
depthOrArrayLayers: number;
}
/** A padded buffer guide */
export interface PaddedBuffer {
data: Uint8Array;
width: number;
height: number;
}
/**
* # WebGPU Context
*
* Wrapper to manage state and GPU calls for a WebGPU context
*/
export default class WebGPUContext {
#private;
ready: boolean;
type: GPUType;
renderer: string;
gpu: GPUCanvasContext;
device: GPUDevice;
presentation: Presentation;
painter: Painter;
devicePixelRatio: number;
interactive: boolean;
projection: Projection;
format: GPUTextureFormat;
masks: Map<number, MaskSource>;
sampleCount: number;
clearColorRGBA: ColorArray;
nullTexture: GPUTexture;
sharedTexture: GPUTexture;
interactiveBindGroupLayout: GPUBindGroupLayout;
interactiveBindGroup: GPUBindGroup;
maskPatternBindGroupLayout: GPUBindGroupLayout;
defaultSampler: GPUSampler;
patternSampler: GPUSampler;
frameBindGroupLayout: GPUBindGroupLayout;
featureBindGroupLayout: GPUBindGroupLayout;
frameBufferBindGroup: GPUBindGroup;
commandEncoder: GPUCommandEncoder;
passEncoder: GPURenderPassEncoder;
computePass: GPUComputePassEncoder;
colorMode: ColorMode;
stencilRef: number;
currPipeline: undefined | GPURenderPipeline | GPUComputePipeline;
findingFeature: boolean;
defaultBlend: GPUBlendState;
/**
* @param context - The WebGPU context
* @param options - map options
* @param painter - The painter that will use this context to manage rendering state
*/
constructor(context: GPUCanvasContext, options: MapOptions, painter: Painter);
/** A setup method to connect to the GPU and prepare the context */
connectGPU(): Promise<void>;
/**
* @param view - the view matrix
* @param matrix - the projection matrix
*/
newScene(view: Float32Array, matrix: Float32Array): void;
/** Clear the interaction buffer */
clearInteractBuffer(): void;
/** Finish the scene by letting the device know all commands are ready to be run */
finish(): void;
/**
* Setup a render pipeline
* @param pipeline - the render pipeline
*/
setRenderPipeline(pipeline: GPURenderPipeline): void;
/**
* Setup a compute pipeline
* @param pipeline - the compute pipeline
*/
setComputePipeline(pipeline: GPUComputePipeline): void;
/**
* Set a clear color
* @param clearColor - the clear color
*/
setClearColor(clearColor: ColorArray): void;
/**
* Set the colorblind mode
* @param mode - the colorblind mode
*/
setColorBlindMode(mode: ColorMode): void;
/**
* Set the device pixel ratio
* @param devicePixelRatio - the device pixel ratio
*/
setDevicePixelRatio(devicePixelRatio?: number): void;
/**
* Build a GPU Buffer
* https://programmer.ink/think/several-best-practices-of-webgpu.html
* BEST PRACTICE 1: Use the label attribute where it can be used
* BEST PRACTICE 5: Buffer data upload (give priority to writeBuffer() API,
* which avoids extra buffer replication operation.)
* @param label - buffer label
* @param inputArray - buffer data
* @param inUsage - how the buffer is used
* @param size - buffer size
* @returns the WebGPU buffer
*/
buildGPUBuffer(label: string, inputArray: BufferSource | SharedArrayBuffer, inUsage: number, size?: number): GPUBuffer;
/**
* Duplicate a GPU Buffer
* @param inputBuffer - the input buffer
* @param commandEncoder - the command encoder
* @returns the duplicated buffer
*/
duplicateGPUBuffer(inputBuffer: GPUBuffer, commandEncoder: GPUCommandEncoder): GPUBuffer;
/**
* Build a padded buffer
* @param input - the input buffer
* @param width - the width of the buffer
* @param height - the height of the buffer
* @returns the padded buffer
*/
buildPaddedBuffer(input: ArrayBuffer, width: number, height: number): PaddedBuffer;
/**
* Get a collection of IDs pointing to the features found at the mouse position
* @param _x - x mouse position
* @param _y - y mouse position
* @returns the collection of features found
*/
getFeatureAtMousePosition(_x: number, _y: number): Promise<number[]>;
/**
* Resize the canvas and context
* @param cb - callback function to be executed when resize is eventually called
*/
resize(cb: () => void): void;
/**
* Set the interactive state
* @param interactive - the interactive state (true means it is interactive)
*/
setInteractive(interactive: boolean): void;
/**
* Set the projection (S2 or WM)
* @param projection - the projection
*/
setProjection(projection: Projection): void;
/**
* Get the mask for a tile
* the zoom determines the number of divisions necessary to maintain a visually
* asthetic spherical shape. As we zoom in, the tiles are practically flat,
* so division is less useful.
* 0, 1 => 16 ; 2, 3 => 8 ; 4, 5 => 4 ; 6, 7 => 2 ; 8+ => 1
* context stores masks so we don't keep recreating them and put excess stress and memory on the GPU
* @param division - number of division to slice the geometry by
* @param tile - the tile to create the mask for
* @returns the mask
*/
getMask(division: number, tile: Tile): TileMaskSource;
/**
* Get the depth position of a layer
* @param layerIndex - the layer index
* @returns the depth position
*/
getDepthPosition(layerIndex: number): number;
/**
* Set the stencil reference
* @param stencilRef - the stencil reference
*/
setStencilReference(stencilRef: number): void;
/**
* Build a new sampler
* @param filter - filter type: "linear" | "nearest"
* @param repeatU - repeat the sampler in the U direction
* @param repeatV - repeat the sampler in the V direction
* @returns the new sampler
*/
buildSampler(filter?: 'linear' | 'nearest', repeatU?: boolean, repeatV?: boolean): GPUSampler;
/**
* Build a new texture
* @param imageData - the raw image data to inject to the texture
* @param width - width of the texture
* @param height - height of the texture
* @param depthOrArrayLayers - depth of the texture
* @param srcOrigin - origin starting position of the source texture
* @param dstOrigin - destination starting position of the GPU texture
* @param format - format of the texture
* @param commandEncoder - command encoder to use
* @returns the new texture
*/
buildTexture(imageData: null | GPUTexture | BufferSource | SharedArrayBuffer | ImageBitmap, width: number, height?: number, depthOrArrayLayers?: number, srcOrigin?: {
x: number;
y: number;
}, dstOrigin?: {
x: number;
y: number;
z: number;
}, format?: GPUTextureFormat, commandEncoder?: GPUCommandEncoder): GPUTexture;
/**
* Upload texture data to the GPU
* @param texture - input Texture buffer
* @param imageData - input image data
* @param width - width of the texture
* @param height - height of the texture
* @param srcOrigin - origin starting position of the source data
* @param dstOrigin - destination starting position of the GPU texture
* @param depthOrArrayLayers - depth of the texture
* @param commandEncoder - command encoder to use
*/
uploadTextureData(texture: GPUTexture, imageData: GPUTexture | BufferSource | SharedArrayBuffer | ImageBitmap, width: number, // width of copy size
height: number, // height of copy size
srcOrigin?: {
x: number;
y: number;
}, dstOrigin?: {
x: number;
y: number;
z: number;
}, depthOrArrayLayers?: number, commandEncoder?: GPUCommandEncoder): void;
/** @returns a Uint8ClampedArray of the current screen */
getRenderData(): Promise<Uint8ClampedArray>;
/**
* Download texture data
* @param texture - input texture
* @param width - width of the texture to download
* @param height - height of the texture to download
* @returns a Uint8ClampedArray of the texture
*/
downloadTextureData(texture: GPUTexture, width: number, height: number): Promise<Uint8ClampedArray>;
/**
* Build a new layout
* https://programmer.ink/think/several-best-practices-of-webgpu.html
* BEST PRACTICE 7: shared resource binding group and binding group layout object
* @param name - layout name
* @param bindings - layout bindings
* @param visibility - layout visibility
* @returns a new bind group layout
*/
buildLayout(name: string, bindings: GPUBufferBindingType[], visibility?: number): GPUBindGroupLayout;
/**
* Build a new bind group
* @param name - bind group name
* @param layout - bind group layout
* @param bindings - bind group bindings
* @returns a new bind group
*/
buildGroup(name: string, layout: GPUBindGroupLayout, bindings: GPUBuffer[]): GPUBindGroup;
/**
* Inject a glyph/icon image to the GPU
* @param maxHeight - the maximum height of the texture
* @param images - the glyph/icon images
* @returns true if the texture that stores the data was resized
*/
injectImages(maxHeight: number, images: GlyphImages): boolean;
/**
* Inject a sprite image
* @param message - the sprite image message containing the raw image data and it's shape
* @returns true if the texture that stores the data was resized
*/
injectSpriteImage(message: SpriteImageMessage): boolean;
/**
* Build a new pattern bind group
* @param fillTexturePositions - the fill texture positions
* @param texture - the texture to bind
* @returns a new pattern bind group
*/
createPatternBindGroup(fillTexturePositions: GPUBuffer, texture?: GPUTexture): GPUBindGroup;
/** Destroy/cleanup the context */
destroy(): void;
}