UNPKG

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
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; }