From a1762cc7440537e453da8553634fcb1508bc9952 Mon Sep 17 00:00:00 2001 From: yunji Date: Tue, 28 May 2024 17:18:18 +0800 Subject: [PATCH 1/5] refactor: remove regl render mode --- .../src/services/config/IConfigService.ts | 4 - packages/renderer/__tests__/index.spec.ts | 2 +- packages/renderer/package.json | 3 +- .../src/{device => }/DeviceAttribute.ts | 0 .../renderer/src/{device => }/DeviceBuffer.ts | 0 .../renderer/src/{device => }/DeviceCache.ts | 0 .../src/{device => }/DeviceElements.ts | 0 .../src/{device => }/DeviceFramebuffer.ts | 0 .../renderer/src/{device => }/DeviceModel.ts | 0 .../src/{device => }/DeviceTexture2D.ts | 0 .../renderer/src/{device => }/constants.ts | 0 packages/renderer/src/device/index.ts | 440 ----------------- packages/renderer/src/index.ts | 442 +++++++++++++++++- packages/renderer/src/regl/ReglAttribute.ts | 44 -- packages/renderer/src/regl/ReglBuffer.ts | 45 -- packages/renderer/src/regl/ReglElements.ts | 37 -- packages/renderer/src/regl/ReglFramebuffer.ts | 51 -- packages/renderer/src/regl/ReglModel.ts | 404 ---------------- .../renderer/src/regl/ReglRenderbuffer.ts | 32 -- packages/renderer/src/regl/ReglTexture2D.ts | 112 ----- packages/renderer/src/regl/constants.ts | 194 -------- packages/renderer/src/regl/index.ts | 286 ------------ .../src/{device => }/utils/HashMap.ts | 0 .../src/{device => }/utils/pipeline.ts | 0 .../src/{device => }/utils/typedarray.ts | 0 .../renderer/src/{device => }/utils/webgl.ts | 0 packages/scene/src/index.ts | 10 +- 27 files changed, 444 insertions(+), 1662 deletions(-) rename packages/renderer/src/{device => }/DeviceAttribute.ts (100%) rename packages/renderer/src/{device => }/DeviceBuffer.ts (100%) rename packages/renderer/src/{device => }/DeviceCache.ts (100%) rename packages/renderer/src/{device => }/DeviceElements.ts (100%) rename packages/renderer/src/{device => }/DeviceFramebuffer.ts (100%) rename packages/renderer/src/{device => }/DeviceModel.ts (100%) rename packages/renderer/src/{device => }/DeviceTexture2D.ts (100%) rename packages/renderer/src/{device => }/constants.ts (100%) delete mode 100644 packages/renderer/src/device/index.ts delete mode 100644 packages/renderer/src/regl/ReglAttribute.ts delete mode 100644 packages/renderer/src/regl/ReglBuffer.ts delete mode 100644 packages/renderer/src/regl/ReglElements.ts delete mode 100644 packages/renderer/src/regl/ReglFramebuffer.ts delete mode 100644 packages/renderer/src/regl/ReglModel.ts delete mode 100644 packages/renderer/src/regl/ReglRenderbuffer.ts delete mode 100644 packages/renderer/src/regl/ReglTexture2D.ts delete mode 100644 packages/renderer/src/regl/constants.ts delete mode 100644 packages/renderer/src/regl/index.ts rename packages/renderer/src/{device => }/utils/HashMap.ts (100%) rename packages/renderer/src/{device => }/utils/pipeline.ts (100%) rename packages/renderer/src/{device => }/utils/typedarray.ts (100%) rename packages/renderer/src/{device => }/utils/webgl.ts (100%) diff --git a/packages/core/src/services/config/IConfigService.ts b/packages/core/src/services/config/IConfigService.ts index e53d18535d0..15887032ae9 100644 --- a/packages/core/src/services/config/IConfigService.ts +++ b/packages/core/src/services/config/IConfigService.ts @@ -16,10 +16,6 @@ export interface ISceneConfig extends IRenderConfig { // TODO: 场景是否支持 stencil mask stencil?: boolean; debug?: boolean; - /** - * Support regl & @antv/g-device-api now - */ - renderer?: 'regl' | 'device'; } export interface IGlobalConfigService { diff --git a/packages/renderer/__tests__/index.spec.ts b/packages/renderer/__tests__/index.spec.ts index 595868f8922..f13284cded6 100644 --- a/packages/renderer/__tests__/index.spec.ts +++ b/packages/renderer/__tests__/index.spec.ts @@ -1,4 +1,4 @@ -import { DeviceRendererService } from '../src/index'; +import { DeviceRendererService } from '../src'; describe('template', () => { it('DeviceRenderer', () => { diff --git a/packages/renderer/package.json b/packages/renderer/package.json index 9200f8726da..18f3558b9dd 100644 --- a/packages/renderer/package.json +++ b/packages/renderer/package.json @@ -23,8 +23,7 @@ "@antv/g-device-api": "^1.6.4", "@antv/l7-core": "workspace:*", "@antv/l7-utils": "workspace:*", - "@babel/runtime": "^7.7.7", - "regl": "1.6.1" + "@babel/runtime": "^7.7.7" }, "devDependencies": { "@antv/l7-test-utils": "workspace:^" diff --git a/packages/renderer/src/device/DeviceAttribute.ts b/packages/renderer/src/DeviceAttribute.ts similarity index 100% rename from packages/renderer/src/device/DeviceAttribute.ts rename to packages/renderer/src/DeviceAttribute.ts diff --git a/packages/renderer/src/device/DeviceBuffer.ts b/packages/renderer/src/DeviceBuffer.ts similarity index 100% rename from packages/renderer/src/device/DeviceBuffer.ts rename to packages/renderer/src/DeviceBuffer.ts diff --git a/packages/renderer/src/device/DeviceCache.ts b/packages/renderer/src/DeviceCache.ts similarity index 100% rename from packages/renderer/src/device/DeviceCache.ts rename to packages/renderer/src/DeviceCache.ts diff --git a/packages/renderer/src/device/DeviceElements.ts b/packages/renderer/src/DeviceElements.ts similarity index 100% rename from packages/renderer/src/device/DeviceElements.ts rename to packages/renderer/src/DeviceElements.ts diff --git a/packages/renderer/src/device/DeviceFramebuffer.ts b/packages/renderer/src/DeviceFramebuffer.ts similarity index 100% rename from packages/renderer/src/device/DeviceFramebuffer.ts rename to packages/renderer/src/DeviceFramebuffer.ts diff --git a/packages/renderer/src/device/DeviceModel.ts b/packages/renderer/src/DeviceModel.ts similarity index 100% rename from packages/renderer/src/device/DeviceModel.ts rename to packages/renderer/src/DeviceModel.ts diff --git a/packages/renderer/src/device/DeviceTexture2D.ts b/packages/renderer/src/DeviceTexture2D.ts similarity index 100% rename from packages/renderer/src/device/DeviceTexture2D.ts rename to packages/renderer/src/DeviceTexture2D.ts diff --git a/packages/renderer/src/device/constants.ts b/packages/renderer/src/constants.ts similarity index 100% rename from packages/renderer/src/device/constants.ts rename to packages/renderer/src/constants.ts diff --git a/packages/renderer/src/device/index.ts b/packages/renderer/src/device/index.ts deleted file mode 100644 index 3095bd00608..00000000000 --- a/packages/renderer/src/device/index.ts +++ /dev/null @@ -1,440 +0,0 @@ -import type { Device, RenderPass, RenderTarget, SwapChain } from '@antv/g-device-api'; -import { - Format, - TextureUsage, - TransparentBlack, - ViewportOrigin, - WebGLDeviceContribution, - WebGPUDeviceContribution, - colorNewFromRGBA, -} from '@antv/g-device-api'; -import type { - IAttribute, - IAttributeInitializationOptions, - IBuffer, - IBufferInitializationOptions, - IClearOptions, - IElements, - IElementsInitializationOptions, - IExtensions, - IFramebuffer, - IFramebufferInitializationOptions, - IModel, - IModelInitializationOptions, - IReadPixelsOptions, - IRenderConfig, - IRendererService, - ITexture2D, - ITexture2DInitializationOptions, -} from '@antv/l7-core'; -import { lodashUtil } from '@antv/l7-utils'; -import DeviceAttribute from './DeviceAttribute'; -import DeviceBuffer from './DeviceBuffer'; -import { RenderCache } from './DeviceCache'; -import DeviceElements from './DeviceElements'; -import DeviceFramebuffer from './DeviceFramebuffer'; -import DeviceModel from './DeviceModel'; -import DeviceTexture2D from './DeviceTexture2D'; -import { isWebGL2 } from './utils/webgl'; -const { isUndefined } = lodashUtil; - -/** - * Device API renderer - */ -export default class DeviceRendererService implements IRendererService { - uniformBuffers: IBuffer[] = []; - extensionObject: IExtensions; - private device: Device; - swapChain: SwapChain; - private $container: HTMLDivElement | null; - private canvas: HTMLCanvasElement; - width: number; - height: number; - private isDirty: boolean; - /** - * Current render pass. - */ - renderPass: RenderPass; - preRenderPass: RenderPass; - mainColorRT: RenderTarget; - mainDepthRT: RenderTarget; - - renderCache: RenderCache; - - /** - * Current FBO. - */ - currentFramebuffer: DeviceFramebuffer | null; - - queryVerdorInfo = () => { - return this.device.queryVendorInfo().platformString; - }; - - private viewportOrigin: ViewportOrigin; - - async init(canvas: HTMLCanvasElement, cfg: IRenderConfig): Promise { - const { enableWebGPU, shaderCompilerPath, antialias } = cfg; - - // this.$container = $container; - this.canvas = canvas; - - const deviceContribution = enableWebGPU - ? new WebGPUDeviceContribution({ - shaderCompilerPath, - }) - : new WebGLDeviceContribution({ - // Use WebGL2 first and downgrade to WebGL1 if WebGL2 is not supported. - targets: ['webgl2', 'webgl1'], - antialias, - onContextLost(e) { - console.warn('context lost', e); - }, - onContextCreationError(e) { - console.warn('context creation error', e); - }, - onContextRestored(e) { - console.warn('context restored', e); - }, - }); - - const swapChain = await deviceContribution.createSwapChain(canvas); - swapChain.configureSwapChain(canvas.width, canvas.height); - this.device = swapChain.getDevice(); - this.swapChain = swapChain; - - this.renderCache = new RenderCache(this.device); - - // Create default RT - this.currentFramebuffer = null; - - this.viewportOrigin = this.device.queryVendorInfo().viewportOrigin; - - // @ts-ignore - const gl = this.device['gl']; - this.extensionObject = { - // @ts-ignore - OES_texture_float: !isWebGL2(gl) && this.device['OES_texture_float'], - }; - - this.createMainColorDepthRT(canvas.width, canvas.height); - } - - private createMainColorDepthRT(width: number, height: number) { - if (this.mainColorRT) { - this.mainColorRT.destroy(); - } - if (this.mainDepthRT) { - this.mainDepthRT.destroy(); - } - - this.mainColorRT = this.device.createRenderTargetFromTexture( - this.device.createTexture({ - format: Format.U8_RGBA_RT, - width, - height, - usage: TextureUsage.RENDER_TARGET, - }), - ); - - this.mainDepthRT = this.device.createRenderTargetFromTexture( - this.device.createTexture({ - format: Format.D24_S8, - width, - height, - usage: TextureUsage.RENDER_TARGET, - }), - ); - } - - beginFrame(): void { - this.device.beginFrame(); - - const { currentFramebuffer, swapChain, mainColorRT, mainDepthRT } = this; - - const colorAttachment = currentFramebuffer - ? currentFramebuffer['colorRenderTarget'] - : mainColorRT; - const colorResolveTo = currentFramebuffer ? null : swapChain.getOnscreenTexture(); - const depthStencilAttachment = currentFramebuffer - ? currentFramebuffer['depthRenderTarget'] - : mainDepthRT; - - const { color = [0, 0, 0, 0], depth = 1, stencil = 0 } = - // @ts-ignore - currentFramebuffer?.clearOptions || {}; - - const colorClearColor = colorAttachment - ? colorNewFromRGBA(color[0] * 255, color[1] * 255, color[2] * 255, color[3]) - : TransparentBlack; - const depthClearValue = depthStencilAttachment ? depth : undefined; - const stencilClearValue = depthStencilAttachment ? stencil : undefined; - - const renderPass = this.device.createRenderPass({ - colorAttachment: [colorAttachment], - colorResolveTo: [colorResolveTo], - colorClearColor: [colorClearColor], - // colorStore: [!!currentFramebuffer], - colorStore: [true], - depthStencilAttachment, - depthClearValue, - stencilClearValue, - }); - this.renderPass = renderPass; - } - - endFrame(): void { - this.device.submitPass(this.renderPass); - this.device.endFrame(); - } - - getPointSizeRange() { - // @ts-ignore - const gl = this.device['gl']; - // FIXME: implement this method in Device API. - return gl.getParameter(gl.ALIASED_POINT_SIZE_RANGE); - } - - public testExtension(name: string) { - // OES_texture_float - return !!this.getGLContext().getExtension(name); - } - - createModel = (options: IModelInitializationOptions): IModel => - new DeviceModel(this.device, options, this); - - createAttribute = (options: IAttributeInitializationOptions): IAttribute => - new DeviceAttribute(this.device, options); - - createBuffer = (options: IBufferInitializationOptions): IBuffer => - new DeviceBuffer(this.device, options); - - createElements = (options: IElementsInitializationOptions): IElements => - new DeviceElements(this.device, options); - - createTexture2D = (options: ITexture2DInitializationOptions): ITexture2D => - new DeviceTexture2D(this.device, options); - - createFramebuffer = (options: IFramebufferInitializationOptions) => - new DeviceFramebuffer(this.device, options); - - useFramebuffer = (framebuffer: IFramebuffer | null, drawCommands: () => void) => { - this.currentFramebuffer = framebuffer as DeviceFramebuffer; - this.beginFrame(); - drawCommands(); - this.endFrame(); - this.currentFramebuffer = null; - }; - - useFramebufferAsync = async ( - framebuffer: IFramebuffer | null, - drawCommands: () => Promise, - ) => { - this.currentFramebuffer = framebuffer as DeviceFramebuffer; - this.preRenderPass = this.renderPass; - this.beginFrame(); - await drawCommands(); - this.endFrame(); - this.currentFramebuffer = null; - this.renderPass = this.preRenderPass; - }; - - clear = (options: IClearOptions) => { - // @see https://github.com/regl-project/regl/blob/gh-pages/API.md#clear-the-draw-buffer - const { color, depth, stencil, framebuffer = null } = options; - if (framebuffer) { - // @ts-ignore - framebuffer.clearOptions = { color, depth, stencil }; - } else { - const platformString = this.queryVerdorInfo(); - if (platformString === 'WebGL1') { - const gl = this.getGLContext(); - if (!isUndefined(stencil)) { - gl.clearStencil(stencil); - gl.clear(gl.STENCIL_BUFFER_BIT); - } else if (!isUndefined(depth)) { - gl.clearDepth(depth); - gl.clear(gl.DEPTH_BUFFER_BIT); - } - } else if (platformString === 'WebGL2') { - const gl = this.getGLContext() as WebGL2RenderingContext; - if (!isUndefined(stencil)) { - gl.clearBufferiv(gl.STENCIL, 0, [stencil]); - } else if (!isUndefined(depth)) { - gl.clearBufferfv(gl.DEPTH, 0, [depth]); - } - } - } - // Recreate render pass - // this.beginFrame(); - }; - - viewport = ({ - // x, - // y, - width, - height, - }: { - x: number; - y: number; - width: number; - height: number; - }) => { - // @see https://observablehq.com/@antv/g-device-api#cell-267 - this.swapChain.configureSwapChain(width, height); - this.createMainColorDepthRT(width, height); - this.width = width; - this.height = height; - }; - - readPixels = (options: IReadPixelsOptions) => { - const { framebuffer, x, y, width, height } = options; - const readback = this.device.createReadback(); - const texture = (framebuffer as DeviceFramebuffer)['colorTexture']; - const result = readback.readTextureSync( - texture, - x, - /** - * Origin is at lower-left corner. Width / height is already multiplied by dpr. - * WebGPU needs flipY - */ - this.viewportOrigin === ViewportOrigin.LOWER_LEFT ? y : this.height - y, - width, - height, - new Uint8Array(width * height * 4), - ) as Uint8Array; - readback.destroy(); - return result; - }; - - readPixelsAsync = async (options: IReadPixelsOptions) => { - const { framebuffer, x, y, width, height } = options; - - const readback = this.device.createReadback(); - const texture = (framebuffer as DeviceFramebuffer)['colorTexture']; - const result = (await readback.readTexture( - texture, - x, - /** - * Origin is at lower-left corner. Width / height is already multiplied by dpr. - * WebGPU needs flipY - */ - this.viewportOrigin === ViewportOrigin.LOWER_LEFT ? y : this.height - y, - width, - height, - new Uint8Array(width * height * 4), - )) as Uint8Array; - - // Since we use U8_RGBA_RT format in render target, need to change bgranorm -> rgba here. - if (this.viewportOrigin !== ViewportOrigin.LOWER_LEFT) { - for (let j = 0; j < result.length; j += 4) { - // Switch b and r components. - const t = result[j]; - result[j] = result[j + 2]; - result[j + 2] = t; - } - } - - readback.destroy(); - - return result; - }; - - getViewportSize = () => { - // FIXME: add viewport size in Device API. - return { - width: this.width, - height: this.height, - }; - }; - - getContainer = () => { - return this.canvas?.parentElement; - }; - - getCanvas = () => { - return this.canvas; - }; - - getGLContext = () => { - // @ts-ignore - return this.device['gl'] as WebGLRenderingContext; - }; - - // TODO: 临时方法 - setState() { - // this.gl({ - // cull: { - // enable: false, - // face: 'back', - // }, - // viewport: { - // x: 0, - // y: 0, - // height: this.width, - // width: this.height, - // }, - // blend: { - // enable: true, - // equation: 'add', - // }, - // framebuffer: null, - // }); - // this.gl._refresh(); - } - - setBaseState() { - // this.gl({ - // cull: { - // enable: false, - // face: 'back', - // }, - // viewport: { - // x: 0, - // y: 0, - // height: this.width, - // width: this.height, - // }, - // blend: { - // enable: false, - // equation: 'add', - // }, - // framebuffer: null, - // }); - // this.gl._refresh(); - } - setCustomLayerDefaults() { - // const gl = this.getGLContext(); - // gl.disable(gl.CULL_FACE); - } - - setDirty(flag: boolean): void { - this.isDirty = flag; - } - - getDirty(): boolean { - return this.isDirty; - } - - destroy = () => { - // this.canvas = null 清除对 webgl 实例的引用 - // @ts-ignore - this.canvas = null; - - this.uniformBuffers?.forEach((buffer) => { - buffer.destroy(); - }); - - this.device.destroy(); - - this.renderCache.destroy(); - - // make sure release webgl context - // this.gl?._gl?.getExtension('WEBGL_lose_context')?.loseContext(); - - // @see https://github.com/regl-project/regl/blob/gh-pages/API.md#clean-up - // this.gl.destroy(); - - // @ts-ignore - // this.gl = null; - }; -} diff --git a/packages/renderer/src/index.ts b/packages/renderer/src/index.ts index 6c33f312633..fb646c657bd 100644 --- a/packages/renderer/src/index.ts +++ b/packages/renderer/src/index.ts @@ -1,4 +1,440 @@ -import DeviceRendererService from './device'; -import ReglRendererService from './regl'; +import type { Device, RenderPass, RenderTarget, SwapChain } from '@antv/g-device-api'; +import { + Format, + TextureUsage, + TransparentBlack, + ViewportOrigin, + WebGLDeviceContribution, + WebGPUDeviceContribution, + colorNewFromRGBA, +} from '@antv/g-device-api'; +import type { + IAttribute, + IAttributeInitializationOptions, + IBuffer, + IBufferInitializationOptions, + IClearOptions, + IElements, + IElementsInitializationOptions, + IExtensions, + IFramebuffer, + IFramebufferInitializationOptions, + IModel, + IModelInitializationOptions, + IReadPixelsOptions, + IRenderConfig, + IRendererService, + ITexture2D, + ITexture2DInitializationOptions, +} from '@antv/l7-core'; +import { lodashUtil } from '@antv/l7-utils'; +import DeviceAttribute from './DeviceAttribute'; +import DeviceBuffer from './DeviceBuffer'; +import { RenderCache } from './DeviceCache'; +import DeviceElements from './DeviceElements'; +import DeviceFramebuffer from './DeviceFramebuffer'; +import DeviceModel from './DeviceModel'; +import DeviceTexture2D from './DeviceTexture2D'; +import { isWebGL2 } from './utils/webgl'; +const { isUndefined } = lodashUtil; -export { DeviceRendererService, ReglRendererService }; +/** + * Device API renderer + */ +export class DeviceRendererService implements IRendererService { + uniformBuffers: IBuffer[] = []; + extensionObject: IExtensions; + private device: Device; + swapChain: SwapChain; + private $container: HTMLDivElement | null; + private canvas: HTMLCanvasElement; + width: number; + height: number; + private isDirty: boolean; + /** + * Current render pass. + */ + renderPass: RenderPass; + preRenderPass: RenderPass; + mainColorRT: RenderTarget; + mainDepthRT: RenderTarget; + + renderCache: RenderCache; + + /** + * Current FBO. + */ + currentFramebuffer: DeviceFramebuffer | null; + + queryVerdorInfo = () => { + return this.device.queryVendorInfo().platformString; + }; + + private viewportOrigin: ViewportOrigin; + + async init(canvas: HTMLCanvasElement, cfg: IRenderConfig): Promise { + const { enableWebGPU, shaderCompilerPath, antialias } = cfg; + + // this.$container = $container; + this.canvas = canvas; + + const deviceContribution = enableWebGPU + ? new WebGPUDeviceContribution({ + shaderCompilerPath, + }) + : new WebGLDeviceContribution({ + // Use WebGL2 first and downgrade to WebGL1 if WebGL2 is not supported. + targets: ['webgl2', 'webgl1'], + antialias, + onContextLost(e) { + console.warn('context lost', e); + }, + onContextCreationError(e) { + console.warn('context creation error', e); + }, + onContextRestored(e) { + console.warn('context restored', e); + }, + }); + + const swapChain = await deviceContribution.createSwapChain(canvas); + swapChain.configureSwapChain(canvas.width, canvas.height); + this.device = swapChain.getDevice(); + this.swapChain = swapChain; + + this.renderCache = new RenderCache(this.device); + + // Create default RT + this.currentFramebuffer = null; + + this.viewportOrigin = this.device.queryVendorInfo().viewportOrigin; + + // @ts-ignore + const gl = this.device['gl']; + this.extensionObject = { + // @ts-ignore + OES_texture_float: !isWebGL2(gl) && this.device['OES_texture_float'], + }; + + this.createMainColorDepthRT(canvas.width, canvas.height); + } + + private createMainColorDepthRT(width: number, height: number) { + if (this.mainColorRT) { + this.mainColorRT.destroy(); + } + if (this.mainDepthRT) { + this.mainDepthRT.destroy(); + } + + this.mainColorRT = this.device.createRenderTargetFromTexture( + this.device.createTexture({ + format: Format.U8_RGBA_RT, + width, + height, + usage: TextureUsage.RENDER_TARGET, + }), + ); + + this.mainDepthRT = this.device.createRenderTargetFromTexture( + this.device.createTexture({ + format: Format.D24_S8, + width, + height, + usage: TextureUsage.RENDER_TARGET, + }), + ); + } + + beginFrame(): void { + this.device.beginFrame(); + + const { currentFramebuffer, swapChain, mainColorRT, mainDepthRT } = this; + + const colorAttachment = currentFramebuffer + ? currentFramebuffer['colorRenderTarget'] + : mainColorRT; + const colorResolveTo = currentFramebuffer ? null : swapChain.getOnscreenTexture(); + const depthStencilAttachment = currentFramebuffer + ? currentFramebuffer['depthRenderTarget'] + : mainDepthRT; + + const { color = [0, 0, 0, 0], depth = 1, stencil = 0 } = + // @ts-ignore + currentFramebuffer?.clearOptions || {}; + + const colorClearColor = colorAttachment + ? colorNewFromRGBA(color[0] * 255, color[1] * 255, color[2] * 255, color[3]) + : TransparentBlack; + const depthClearValue = depthStencilAttachment ? depth : undefined; + const stencilClearValue = depthStencilAttachment ? stencil : undefined; + + const renderPass = this.device.createRenderPass({ + colorAttachment: [colorAttachment], + colorResolveTo: [colorResolveTo], + colorClearColor: [colorClearColor], + // colorStore: [!!currentFramebuffer], + colorStore: [true], + depthStencilAttachment, + depthClearValue, + stencilClearValue, + }); + this.renderPass = renderPass; + } + + endFrame(): void { + this.device.submitPass(this.renderPass); + this.device.endFrame(); + } + + getPointSizeRange() { + // @ts-ignore + const gl = this.device['gl']; + // FIXME: implement this method in Device API. + return gl.getParameter(gl.ALIASED_POINT_SIZE_RANGE); + } + + public testExtension(name: string) { + // OES_texture_float + return !!this.getGLContext().getExtension(name); + } + + createModel = (options: IModelInitializationOptions): IModel => + new DeviceModel(this.device, options, this); + + createAttribute = (options: IAttributeInitializationOptions): IAttribute => + new DeviceAttribute(this.device, options); + + createBuffer = (options: IBufferInitializationOptions): IBuffer => + new DeviceBuffer(this.device, options); + + createElements = (options: IElementsInitializationOptions): IElements => + new DeviceElements(this.device, options); + + createTexture2D = (options: ITexture2DInitializationOptions): ITexture2D => + new DeviceTexture2D(this.device, options); + + createFramebuffer = (options: IFramebufferInitializationOptions) => + new DeviceFramebuffer(this.device, options); + + useFramebuffer = (framebuffer: IFramebuffer | null, drawCommands: () => void) => { + this.currentFramebuffer = framebuffer as DeviceFramebuffer; + this.beginFrame(); + drawCommands(); + this.endFrame(); + this.currentFramebuffer = null; + }; + + useFramebufferAsync = async ( + framebuffer: IFramebuffer | null, + drawCommands: () => Promise, + ) => { + this.currentFramebuffer = framebuffer as DeviceFramebuffer; + this.preRenderPass = this.renderPass; + this.beginFrame(); + await drawCommands(); + this.endFrame(); + this.currentFramebuffer = null; + this.renderPass = this.preRenderPass; + }; + + clear = (options: IClearOptions) => { + // @see https://github.com/regl-project/regl/blob/gh-pages/API.md#clear-the-draw-buffer + const { color, depth, stencil, framebuffer = null } = options; + if (framebuffer) { + // @ts-ignore + framebuffer.clearOptions = { color, depth, stencil }; + } else { + const platformString = this.queryVerdorInfo(); + if (platformString === 'WebGL1') { + const gl = this.getGLContext(); + if (!isUndefined(stencil)) { + gl.clearStencil(stencil); + gl.clear(gl.STENCIL_BUFFER_BIT); + } else if (!isUndefined(depth)) { + gl.clearDepth(depth); + gl.clear(gl.DEPTH_BUFFER_BIT); + } + } else if (platformString === 'WebGL2') { + const gl = this.getGLContext() as WebGL2RenderingContext; + if (!isUndefined(stencil)) { + gl.clearBufferiv(gl.STENCIL, 0, [stencil]); + } else if (!isUndefined(depth)) { + gl.clearBufferfv(gl.DEPTH, 0, [depth]); + } + } + } + // Recreate render pass + // this.beginFrame(); + }; + + viewport = ({ + // x, + // y, + width, + height, + }: { + x: number; + y: number; + width: number; + height: number; + }) => { + // @see https://observablehq.com/@antv/g-device-api#cell-267 + this.swapChain.configureSwapChain(width, height); + this.createMainColorDepthRT(width, height); + this.width = width; + this.height = height; + }; + + readPixels = (options: IReadPixelsOptions) => { + const { framebuffer, x, y, width, height } = options; + const readback = this.device.createReadback(); + const texture = (framebuffer as DeviceFramebuffer)['colorTexture']; + const result = readback.readTextureSync( + texture, + x, + /** + * Origin is at lower-left corner. Width / height is already multiplied by dpr. + * WebGPU needs flipY + */ + this.viewportOrigin === ViewportOrigin.LOWER_LEFT ? y : this.height - y, + width, + height, + new Uint8Array(width * height * 4), + ) as Uint8Array; + readback.destroy(); + return result; + }; + + readPixelsAsync = async (options: IReadPixelsOptions) => { + const { framebuffer, x, y, width, height } = options; + + const readback = this.device.createReadback(); + const texture = (framebuffer as DeviceFramebuffer)['colorTexture']; + const result = (await readback.readTexture( + texture, + x, + /** + * Origin is at lower-left corner. Width / height is already multiplied by dpr. + * WebGPU needs flipY + */ + this.viewportOrigin === ViewportOrigin.LOWER_LEFT ? y : this.height - y, + width, + height, + new Uint8Array(width * height * 4), + )) as Uint8Array; + + // Since we use U8_RGBA_RT format in render target, need to change bgranorm -> rgba here. + if (this.viewportOrigin !== ViewportOrigin.LOWER_LEFT) { + for (let j = 0; j < result.length; j += 4) { + // Switch b and r components. + const t = result[j]; + result[j] = result[j + 2]; + result[j + 2] = t; + } + } + + readback.destroy(); + + return result; + }; + + getViewportSize = () => { + // FIXME: add viewport size in Device API. + return { + width: this.width, + height: this.height, + }; + }; + + getContainer = () => { + return this.canvas?.parentElement; + }; + + getCanvas = () => { + return this.canvas; + }; + + getGLContext = () => { + // @ts-ignore + return this.device['gl'] as WebGLRenderingContext; + }; + + // TODO: 临时方法 + setState() { + // this.gl({ + // cull: { + // enable: false, + // face: 'back', + // }, + // viewport: { + // x: 0, + // y: 0, + // height: this.width, + // width: this.height, + // }, + // blend: { + // enable: true, + // equation: 'add', + // }, + // framebuffer: null, + // }); + // this.gl._refresh(); + } + + setBaseState() { + // this.gl({ + // cull: { + // enable: false, + // face: 'back', + // }, + // viewport: { + // x: 0, + // y: 0, + // height: this.width, + // width: this.height, + // }, + // blend: { + // enable: false, + // equation: 'add', + // }, + // framebuffer: null, + // }); + // this.gl._refresh(); + } + setCustomLayerDefaults() { + // const gl = this.getGLContext(); + // gl.disable(gl.CULL_FACE); + } + + setDirty(flag: boolean): void { + this.isDirty = flag; + } + + getDirty(): boolean { + return this.isDirty; + } + + destroy = () => { + // this.canvas = null 清除对 webgl 实例的引用 + // @ts-ignore + this.canvas = null; + + this.uniformBuffers?.forEach((buffer) => { + buffer.destroy(); + }); + + this.device.destroy(); + + this.renderCache.destroy(); + + // make sure release webgl context + // this.gl?._gl?.getExtension('WEBGL_lose_context')?.loseContext(); + + // @see https://github.com/regl-project/regl/blob/gh-pages/API.md#clean-up + // this.gl.destroy(); + + // @ts-ignore + // this.gl = null; + }; +} diff --git a/packages/renderer/src/regl/ReglAttribute.ts b/packages/renderer/src/regl/ReglAttribute.ts deleted file mode 100644 index 686987bd089..00000000000 --- a/packages/renderer/src/regl/ReglAttribute.ts +++ /dev/null @@ -1,44 +0,0 @@ -import type { IAttribute, IAttributeInitializationOptions, IBuffer } from '@antv/l7-core'; -import type regl from 'regl'; -import type ReglBuffer from './ReglBuffer'; - -/** - * @see https://github.com/regl-project/regl/blob/gh-pages/API.md#attributes - */ -export default class ReglAttribute implements IAttribute { - private attribute: regl.Attribute; - private buffer: IBuffer; - - constructor(gl: regl.Regl, options: IAttributeInitializationOptions) { - const { buffer, offset, stride, normalized, size, divisor } = options; - this.buffer = buffer; - this.attribute = { - buffer: (buffer as ReglBuffer).get(), - offset: offset || 0, - stride: stride || 0, - normalized: normalized || false, - divisor: divisor || 0, - }; - - if (size) { - this.attribute.size = size; - } - } - - public get() { - return this.attribute; - } - - public updateBuffer(options: { - // 用于替换的数据 - data: number[] | number[][] | Uint8Array | Uint16Array | Uint32Array; - // 原 Buffer 替换位置,单位为 byte - offset: number; - }) { - this.buffer.subData(options); - } - - public destroy() { - this.buffer.destroy(); - } -} diff --git a/packages/renderer/src/regl/ReglBuffer.ts b/packages/renderer/src/regl/ReglBuffer.ts deleted file mode 100644 index 7b23b8bf412..00000000000 --- a/packages/renderer/src/regl/ReglBuffer.ts +++ /dev/null @@ -1,45 +0,0 @@ -import type { IBuffer, IBufferInitializationOptions } from '@antv/l7-core'; -import { gl } from '@antv/l7-core'; -import type regl from 'regl'; -import { dataTypeMap, usageMap } from './constants'; - -/** - * adaptor for regl.Buffer - * @see https://github.com/regl-project/regl/blob/gh-pages/API.md#buffers - */ -export default class ReglBuffer implements IBuffer { - private buffer: regl.Buffer; - - private isDestroyed: boolean = false; - - constructor(reGl: regl.Regl, options: IBufferInitializationOptions) { - const { data, usage, type } = options; - this.buffer = reGl.buffer({ - data, - usage: usageMap[usage || gl.STATIC_DRAW], - type: dataTypeMap[type || gl.UNSIGNED_BYTE], - // length: 0, - }); - } - - public get() { - return this.buffer; - } - - public destroy() { - if (!this.isDestroyed) { - this.buffer.destroy(); - } - this.isDestroyed = true; - } - - public subData({ - data, - offset, - }: { - data: number[] | number[][] | Uint8Array | Uint16Array | Uint32Array; - offset: number; - }) { - this.buffer.subdata(data, offset); - } -} diff --git a/packages/renderer/src/regl/ReglElements.ts b/packages/renderer/src/regl/ReglElements.ts deleted file mode 100644 index 541b282b9c3..00000000000 --- a/packages/renderer/src/regl/ReglElements.ts +++ /dev/null @@ -1,37 +0,0 @@ -import type { IElements, IElementsInitializationOptions } from '@antv/l7-core'; -import { gl } from '@antv/l7-core'; -import type regl from 'regl'; -import { dataTypeMap, usageMap } from './constants'; - -/** - * @see https://github.com/regl-project/regl/blob/gh-pages/API.md#elements - */ -export default class ReglElements implements IElements { - private elements: regl.Elements; - - constructor(reGl: regl.Regl, options: IElementsInitializationOptions) { - const { data, usage, type, count } = options; - this.elements = reGl.elements({ - data, - usage: usageMap[usage || gl.STATIC_DRAW], - type: dataTypeMap[type || gl.UNSIGNED_BYTE] as 'uint8' | 'uint16' | 'uint32', - count, - }); - } - - public get() { - return this.elements; - } - - public subData({ - data, - }: { - data: number[] | number[][] | Uint8Array | Uint16Array | Uint32Array; - }) { - this.elements.subdata(data); - } - - public destroy() { - // this.elements.destroy(); - } -} diff --git a/packages/renderer/src/regl/ReglFramebuffer.ts b/packages/renderer/src/regl/ReglFramebuffer.ts deleted file mode 100644 index 8e1cc69d4ad..00000000000 --- a/packages/renderer/src/regl/ReglFramebuffer.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { - IFramebuffer, - IFramebufferInitializationOptions, - IRenderbuffer, - ITexture2D, -} from '@antv/l7-core'; -import type regl from 'regl'; -import type ReglTexture2D from './ReglTexture2D'; - -/** - * adaptor for regl.Framebuffer - * @see https://github.com/regl-project/regl/blob/gh-pages/API.md#framebuffers - */ -export default class ReglFramebuffer implements IFramebuffer { - private framebuffer: regl.Framebuffer; - - constructor(reGl: regl.Regl, options: IFramebufferInitializationOptions) { - const { width, height, color, colors } = options; - - const framebufferOptions: regl.FramebufferOptions = { - width, - height, - }; - - if (Array.isArray(colors)) { - framebufferOptions.colors = colors.map((c: ITexture2D | IRenderbuffer) => - (c as ReglTexture2D).get(), - ); - } - - if (color && typeof color !== 'boolean') { - framebufferOptions.color = (color as ReglTexture2D).get(); - } - - // TODO: depth & stencil - - this.framebuffer = reGl.framebuffer(framebufferOptions); - } - - public get() { - return this.framebuffer; - } - - public destroy() { - this.framebuffer.destroy(); - } - - public resize({ width, height }: { width: number; height: number }) { - this.framebuffer.resize(width, height); - } -} diff --git a/packages/renderer/src/regl/ReglModel.ts b/packages/renderer/src/regl/ReglModel.ts deleted file mode 100644 index 4c6777093b9..00000000000 --- a/packages/renderer/src/regl/ReglModel.ts +++ /dev/null @@ -1,404 +0,0 @@ -import { ClipSpaceNearZ, preprocessShader_GLSL, ViewportOrigin } from '@antv/g-device-api'; -import type { - IAttribute, - IBlendOptions, - IElements, - IModel, - IModelDrawOptions, - IModelInitializationOptions, - IUniform, -} from '@antv/l7-core'; -import { gl, removeDuplicateUniforms } from '@antv/l7-core'; -import { lodashUtil } from '@antv/l7-utils'; -import type regl from 'regl'; -import { - blendEquationMap, - blendFuncMap, - cullFaceMap, - depthFuncMap, - primitiveMap, - stencilFuncMap, - stencilOpMap, -} from './constants'; -import type ReglAttribute from './ReglAttribute'; -import type ReglElements from './ReglElements'; -import type ReglFramebuffer from './ReglFramebuffer'; -import type ReglTexture2D from './ReglTexture2D'; -const { isPlainObject, isTypedArray } = lodashUtil; - -/** - * adaptor for regl.DrawCommand - */ -export default class ReglModel implements IModel { - private reGl: regl.Regl; - private destroyed: boolean = false; - private drawCommand: regl.DrawCommand; - private drawParams: regl.DrawConfig; - private options: IModelInitializationOptions; - private uniforms: { - [key: string]: IUniform; - } = {}; - - constructor(reGl: regl.Regl, options: IModelInitializationOptions) { - this.reGl = reGl; - const { vs, fs, attributes, uniforms, primitive, count, elements, depth, cull, instances } = - options; - - /** - * try to compile GLSL 300 to 100 - */ - const vendorInfo = { - platformString: 'WebGL1', - glslVersion: '#version 100', - explicitBindingLocations: false, - separateSamplerTextures: false, - viewportOrigin: ViewportOrigin.LOWER_LEFT, - clipSpaceNearZ: ClipSpaceNearZ.NEGATIVE_ONE, - supportMRT: false, - }; - - const reglUniforms: { [key: string]: IUniform } = {}; - this.options = options; - if (uniforms) { - this.uniforms = this.extractUniforms(uniforms); - Object.keys(uniforms).forEach((uniformName) => { - // use regl prop API - // @ts-ignore - reglUniforms[uniformName] = reGl.prop(uniformName); - }); - } - - const reglAttributes: { [key: string]: regl.Attribute } = {}; - Object.keys(attributes).forEach((name: string) => { - reglAttributes[name] = (attributes[name] as ReglAttribute).get(); - }); - const frag = removeDuplicateUniforms( - preprocessShader_GLSL(vendorInfo, 'frag', fs, null, false), - ); - - const vert = removeDuplicateUniforms( - preprocessShader_GLSL(vendorInfo, 'vert', vs, null, false), - ); - - const drawParams: regl.DrawConfig = { - attributes: reglAttributes, - frag, - uniforms: reglUniforms, - vert, - // @ts-ignore - colorMask: reGl.prop('colorMask'), - lineWidth: 1, - blend: { - // @ts-ignore - enable: reGl.prop('blend.enable'), - // @ts-ignore - func: reGl.prop('blend.func'), - // @ts-ignore - equation: reGl.prop('blend.equation'), - // @ts-ignore - color: reGl.prop('blend.color'), - }, - stencil: { - // @ts-ignore - enable: reGl.prop('stencil.enable'), - // @ts-ignore - mask: reGl.prop('stencil.mask'), - // @ts-ignore - func: reGl.prop('stencil.func'), - // @ts-ignore - opFront: reGl.prop('stencil.opFront'), - // @ts-ignore - opBack: reGl.prop('stencil.opBack'), - }, - primitive: primitiveMap[primitive === undefined ? gl.TRIANGLES : primitive], - }; - if (instances) { - drawParams.instances = instances; - } - - // Tip: - // elements 中可能包含 count,此时不应传入 - // count 和 elements 相比、count 优先 - if (count) { - drawParams.count = count; - } else if (elements) { - drawParams.elements = (elements as ReglElements).get(); - } - - this.initDepthDrawParams({ depth }, drawParams); - // this.initBlendDrawParams({ blend }, drawParams); - // this.initStencilDrawParams({ stencil }, drawParams); - this.initCullDrawParams({ cull }, drawParams); - this.drawCommand = reGl(drawParams); - this.drawParams = drawParams; - } - - public updateAttributesAndElements( - attributes: { [key: string]: IAttribute }, - elements: IElements, - ) { - const reglAttributes: { [key: string]: regl.Attribute } = {}; - Object.keys(attributes).forEach((name: string) => { - reglAttributes[name] = (attributes[name] as ReglAttribute).get(); - }); - this.drawParams.attributes = reglAttributes; - this.drawParams.elements = (elements as ReglElements).get(); - - this.drawCommand = this.reGl(this.drawParams); - } - - public updateAttributes(attributes: { [key: string]: IAttribute }) { - const reglAttributes: { [key: string]: regl.Attribute } = {}; - Object.keys(attributes).forEach((name: string) => { - reglAttributes[name] = (attributes[name] as ReglAttribute).get(); - }); - this.drawParams.attributes = reglAttributes; - this.drawCommand = this.reGl(this.drawParams); - } - - public addUniforms(uniforms: { [key: string]: IUniform }) { - this.uniforms = { - ...this.uniforms, - ...this.extractUniforms(uniforms), - }; - } - - public draw(options: IModelDrawOptions, pick?: boolean) { - if (this.drawParams.attributes && Object.keys(this.drawParams.attributes).length === 0) { - return; - } - const uniforms: { - [key: string]: IUniform; - } = { - ...this.uniforms, - ...this.extractUniforms(options.uniforms || {}), - }; - const reglDrawProps: { - [key: string]: - | regl.Framebuffer - | regl.Texture2D - | number - | number[] - | Partial - | boolean; - } = {}; - Object.keys(uniforms).forEach((uniformName: string) => { - const type = typeof uniforms[uniformName]; - if ( - type === 'boolean' || - type === 'number' || - Array.isArray(uniforms[uniformName]) || - // @ts-ignore - uniforms[uniformName].BYTES_PER_ELEMENT - ) { - reglDrawProps[uniformName] = uniforms[uniformName] as number | number[] | boolean; - } else { - reglDrawProps[uniformName] = ( - uniforms[uniformName] as ReglFramebuffer | ReglTexture2D - ).get(); - } - }); - // 更新 blend - // @ts-ignore - reglDrawProps.blend = pick // picking 操作不应该使用 blend - ? this.getBlendDrawParams({ - blend: { enable: false }, - }) - : this.getBlendDrawParams(options); - - // 更新stentil 配置 - // @ts-ignore - reglDrawProps.stencil = this.getStencilDrawParams(options); - // @ts-ignore - reglDrawProps.colorMask = this.getColorMaskDrawParams(options, pick); - - // 在进行拾取操作的绘制中,不应该使用叠加模式 - picking 根据拾取的颜色作为判断的输入,而叠加模式会产生新的,在 id 序列中不存在的颜色 - this.drawCommand(reglDrawProps); - } - - public destroy() { - // @ts-ignore - this.drawParams?.elements?.destroy(); - if (this.options.attributes) { - Object.values(this.options.attributes).forEach((attr: any) => { - // @ts-ignore - (attr as ReglAttribute)?.destroy(); - }); - } - this.destroyed = true; - } - - /** - * @see https://github.com/regl-project/regl/blob/gh-pages/API.md#depth-buffer - */ - private initDepthDrawParams( - { depth }: Pick, - drawParams: regl.DrawConfig, - ) { - if (depth) { - drawParams.depth = { - enable: depth.enable === undefined ? true : !!depth.enable, - mask: depth.mask === undefined ? true : !!depth.mask, - func: depthFuncMap[depth.func || gl.LESS], - range: depth.range || [0, 1], - }; - } - } - - private getBlendDrawParams({ blend }: Pick) { - const { enable, func, equation, color = [0, 0, 0, 0] } = blend || {}; - // @ts-ignore - return { - enable: !!enable, - func: { - srcRGB: blendFuncMap[(func && func.srcRGB) || gl.SRC_ALPHA], - srcAlpha: blendFuncMap[(func && func.srcAlpha) || gl.SRC_ALPHA], - dstRGB: blendFuncMap[(func && func.dstRGB) || gl.ONE_MINUS_SRC_ALPHA], - dstAlpha: blendFuncMap[(func && func.dstAlpha) || gl.ONE_MINUS_SRC_ALPHA], - }, - equation: { - rgb: blendEquationMap[(equation && equation.rgb) || gl.FUNC_ADD], - alpha: blendEquationMap[(equation && equation.alpha) || gl.FUNC_ADD], - }, - color, - }; - } - /** - * @see https://github.com/regl-project/regl/blob/gh-pages/API.md#stencil - */ - private getStencilDrawParams({ stencil }: Pick) { - const { - enable, - mask = -1, - func = { - cmp: gl.ALWAYS, - ref: 0, - mask: -1, - }, - opFront = { - fail: gl.KEEP, - zfail: gl.KEEP, - zpass: gl.KEEP, - }, - opBack = { - fail: gl.KEEP, - zfail: gl.KEEP, - zpass: gl.KEEP, - }, - } = stencil || {}; - return { - enable: !!enable, - mask, - func: { - ...func, - cmp: stencilFuncMap[func.cmp], - }, - opFront: { - fail: stencilOpMap[opFront.fail], - zfail: stencilOpMap[opFront.zfail], - zpass: stencilOpMap[opFront.zpass], - }, - opBack: { - fail: stencilOpMap[opBack.fail], - zfail: stencilOpMap[opBack.zfail], - zpass: stencilOpMap[opBack.zpass], - }, - }; - } - - private getColorMaskDrawParams( - { stencil }: Pick, - pick: boolean, - ) { - // TODO: 重构相关参数 - // 掩模模式下,颜色通道全部关闭 - const colorMask = - stencil?.enable && stencil.opFront && !pick - ? [false, false, false, false] - : [true, true, true, true]; // 非掩码模式下,颜色通道全部开启 - return colorMask; - } - - /** - * @see https://github.com/regl-project/regl/blob/gh-pages/API.md#culling - */ - private initCullDrawParams( - { cull }: Pick, - drawParams: regl.DrawConfig, - ) { - if (cull) { - const { enable, face = gl.BACK } = cull; - drawParams.cull = { - enable: !!enable, - face: cullFaceMap[face], - }; - } - } - - /** - * 考虑结构体命名, eg: - * a: { b: 1 } -> 'a.b' - * a: [ { b: 1 } ] -> 'a[0].b' - */ - private extractUniforms(uniforms: { [key: string]: IUniform }): { - [key: string]: IUniform; - } { - const extractedUniforms = {}; - Object.keys(uniforms).forEach((uniformName) => { - this.extractUniformsRecursively(uniformName, uniforms[uniformName], extractedUniforms, ''); - }); - - return extractedUniforms; - } - - private extractUniformsRecursively( - uniformName: string, - uniformValue: IUniform, - uniforms: { - [key: string]: IUniform; - }, - prefix: string, - ) { - if ( - uniformValue === null || - typeof uniformValue === 'number' || // u_A: 1 - typeof uniformValue === 'boolean' || // u_A: false - (Array.isArray(uniformValue) && typeof uniformValue[0] === 'number') || // u_A: [1, 2, 3] - isTypedArray(uniformValue) || // u_A: Float32Array - // @ts-ignore - uniformValue === '' || - 'resize' in uniformValue - ) { - uniforms[`${prefix && prefix + '.'}${uniformName}`] = uniformValue; - return; - } - - // u_Struct.a.b.c - if (isPlainObject(uniformValue)) { - Object.keys(uniformValue).forEach((childName) => { - this.extractUniformsRecursively( - childName, - // @ts-ignore - uniformValue[childName], - uniforms, - `${prefix && prefix + '.'}${uniformName}`, - ); - }); - } - - // u_Struct[0].a - if (Array.isArray(uniformValue)) { - uniformValue.forEach((child, idx) => { - Object.keys(child).forEach((childName) => { - this.extractUniformsRecursively( - childName, - // @ts-ignore - child[childName], - uniforms, - `${prefix && prefix + '.'}${uniformName}[${idx}]`, - ); - }); - }); - } - } -} diff --git a/packages/renderer/src/regl/ReglRenderbuffer.ts b/packages/renderer/src/regl/ReglRenderbuffer.ts deleted file mode 100644 index b56eb2f71e0..00000000000 --- a/packages/renderer/src/regl/ReglRenderbuffer.ts +++ /dev/null @@ -1,32 +0,0 @@ -import type { IRenderbuffer, IRenderbufferInitializationOptions } from '@antv/l7-core'; -import type regl from 'regl'; -import { formatMap } from './constants'; - -/** - * adaptor for regl.Renderbuffer - * @see https://github.com/regl-project/regl/blob/gh-pages/API.md#renderbuffers - */ -export default class ReglRenderbuffer implements IRenderbuffer { - private renderbuffer: regl.Renderbuffer; - - constructor(reGl: regl.Regl, options: IRenderbufferInitializationOptions) { - const { width, height, format } = options; - this.renderbuffer = reGl.renderbuffer({ - width, - height, - format: formatMap[format] as regl.RenderbufferFormat, - }); - } - - public get() { - return this.renderbuffer; - } - - public destroy() { - this.renderbuffer.destroy(); - } - - public resize({ width, height }: { width: number; height: number }) { - this.renderbuffer.resize(width, height); - } -} diff --git a/packages/renderer/src/regl/ReglTexture2D.ts b/packages/renderer/src/regl/ReglTexture2D.ts deleted file mode 100644 index 5e8408e88cc..00000000000 --- a/packages/renderer/src/regl/ReglTexture2D.ts +++ /dev/null @@ -1,112 +0,0 @@ -import type { ITexture2D, ITexture2DInitializationOptions } from '@antv/l7-core'; -import { gl } from '@antv/l7-core'; -import type regl from 'regl'; -import { - colorSpaceMap, - dataTypeMap, - filterMap, - formatMap, - mipmapMap, - wrapModeMap, -} from './constants'; - -/** - * adaptor for regl.Buffer - * @see https://github.com/regl-project/regl/blob/gh-pages/API.md#buffers - */ -export default class ReglTexture2D implements ITexture2D { - private texture: regl.Texture2D; - private width: number; - private height: number; - private isDestroy: boolean = false; - - constructor(reGl: regl.Regl, options: ITexture2DInitializationOptions) { - const { - data, - type = gl.UNSIGNED_BYTE, - width, - height, - flipY = false, - format = gl.RGBA, - mipmap = false, - wrapS = gl.CLAMP_TO_EDGE, - wrapT = gl.CLAMP_TO_EDGE, - aniso = 0, - alignment = 1, - premultiplyAlpha = false, - mag = gl.NEAREST, - min = gl.NEAREST, - colorSpace = gl.BROWSER_DEFAULT_WEBGL, - x = 0, - y = 0, - copy = false, - } = options; - this.width = width; - this.height = height; - - const textureOptions: regl.Texture2DOptions = { - width, - height, - // @ts-ignore - type: dataTypeMap[type], - format: formatMap[format], - wrapS: wrapModeMap[wrapS], - wrapT: wrapModeMap[wrapT], - // @ts-ignore - mag: filterMap[mag], - min: filterMap[min], - alignment, - flipY, - colorSpace: colorSpaceMap[colorSpace], - premultiplyAlpha, - aniso, - - // copy pixels from current bind framebuffer - x, - y, - copy, - }; - - if (data) { - // @ts-ignore - textureOptions.data = data; - } - - if (typeof mipmap === 'number') { - textureOptions.mipmap = mipmapMap[mipmap]; - } else if (typeof mipmap === 'boolean') { - textureOptions.mipmap = mipmap; - } - - this.texture = reGl.texture(textureOptions); - } - - public get() { - return this.texture; - } - public update(props: regl.Texture2DOptions = {}) { - this.texture(props); - } - - public bind() { - // @ts-ignore - this.texture._texture.bind(); - } - - public resize({ width, height }: { width: number; height: number }): void { - this.texture.resize(width, height); - this.width = width; - this.height = height; - } - - public getSize(): [number, number] { - return [this.width, this.height]; - } - - public destroy() { - if (!this.isDestroy) { - this.texture?.destroy(); - } - this.isDestroy = true; - } -} diff --git a/packages/renderer/src/regl/constants.ts b/packages/renderer/src/regl/constants.ts deleted file mode 100644 index a7623c1c48e..00000000000 --- a/packages/renderer/src/regl/constants.ts +++ /dev/null @@ -1,194 +0,0 @@ -/** - * @desc 由于 regl 使用大量字符串而非 WebGL 常量,因此需要映射 - */ -import { gl } from '@antv/l7-core'; -import type regl from 'regl'; - -// @see https://github.com/regl-project/regl/blob/gh-pages/lib/constants/primitives.json -export const primitiveMap: { - [key: string]: - | 'points' - | 'lines' - | 'line loop' - | 'line strip' - | 'triangles' - | 'triangle strip' - | 'triangle fan'; -} = { - [gl.POINTS]: 'points', - [gl.LINES]: 'lines', - [gl.LINE_LOOP]: 'line loop', - [gl.LINE_STRIP]: 'line strip', - [gl.TRIANGLES]: 'triangles', - [gl.TRIANGLE_FAN]: 'triangle fan', - [gl.TRIANGLE_STRIP]: 'triangle strip', -}; - -export const usageMap: { - [key: string]: 'static' | 'dynamic' | 'stream'; -} = { - [gl.STATIC_DRAW]: 'static', - [gl.DYNAMIC_DRAW]: 'dynamic', - [gl.STREAM_DRAW]: 'stream', -}; - -export const dataTypeMap: { - [key: string]: 'int8' | 'int16' | 'int32' | 'uint8' | 'uint16' | 'uint32' | 'float'; -} = { - [gl.BYTE]: 'int8', - // [gl.UNSIGNED_INT]: 'int16', - [gl.INT]: 'int32', - [gl.UNSIGNED_BYTE]: 'uint8', - [gl.UNSIGNED_SHORT]: 'uint16', - [gl.UNSIGNED_INT]: 'uint32', - [gl.FLOAT]: 'float', -}; - -export const formatMap: { - [key: string]: - | 'alpha' - | 'luminance' - | 'luminance alpha' - | 'rgb' - | 'rgba' - | 'rgba4' - | 'rgb5 a1' - | 'rgb565' - | 'depth' - | 'depth stencil'; -} = { - [gl.ALPHA]: 'alpha', - [gl.LUMINANCE]: 'luminance', - [gl.LUMINANCE_ALPHA]: 'luminance alpha', - [gl.RGB]: 'rgb', - [gl.RGBA]: 'rgba', - [gl.RGBA4]: 'rgba4', - [gl.RGB5_A1]: 'rgb5 a1', - [gl.RGB565]: 'rgb565', - [gl.DEPTH_COMPONENT]: 'depth', - [gl.DEPTH_STENCIL]: 'depth stencil', -}; - -export const mipmapMap: { - [key: string]: 'dont care' | 'nice' | 'fast'; -} = { - [gl.DONT_CARE]: 'dont care', - [gl.NICEST]: 'nice', - [gl.FASTEST]: 'fast', -}; - -export const filterMap: { - [key: string]: - | 'nearest' - | 'linear' - | 'mipmap' - | 'nearest mipmap linear' - | 'linear mipmap nearest' - | 'nearest mipmap nearest'; -} = { - [gl.NEAREST]: 'nearest', - [gl.LINEAR]: 'linear', - [gl.LINEAR_MIPMAP_LINEAR]: 'mipmap', - [gl.NEAREST_MIPMAP_LINEAR]: 'nearest mipmap linear', - [gl.LINEAR_MIPMAP_NEAREST]: 'linear mipmap nearest', - [gl.NEAREST_MIPMAP_NEAREST]: 'nearest mipmap nearest', -}; - -export const wrapModeMap: { - [key: string]: 'repeat' | 'clamp' | 'mirror'; -} = { - [gl.REPEAT]: 'repeat', - [gl.CLAMP_TO_EDGE]: 'clamp', - [gl.MIRRORED_REPEAT]: 'mirror', -}; - -export const colorSpaceMap: { - [key: string]: 'none' | 'browser'; -} = { - [gl.NONE]: 'none', - [gl.BROWSER_DEFAULT_WEBGL]: 'browser', -}; - -export const depthFuncMap: { - [key: string]: - | 'never' - | 'always' - | 'less' - | 'lequal' - | 'greater' - | 'gequal' - | 'equal' - | 'notequal'; -} = { - [gl.NEVER]: 'never', - [gl.ALWAYS]: 'always', - [gl.LESS]: 'less', - [gl.LEQUAL]: 'lequal', - [gl.GREATER]: 'greater', - [gl.GEQUAL]: 'gequal', - [gl.EQUAL]: 'equal', - [gl.NOTEQUAL]: 'notequal', -}; - -export const blendEquationMap: { - [key: string]: regl.BlendingEquation; -} = { - [gl.FUNC_ADD]: 'add', - [gl.MIN_EXT]: 'min', - [gl.MAX_EXT]: 'max', - [gl.FUNC_SUBTRACT]: 'subtract', - [gl.FUNC_REVERSE_SUBTRACT]: 'reverse subtract', -}; - -export const blendFuncMap: { - [key: string]: regl.BlendingFunction; -} = { - [gl.ZERO]: 'zero', - [gl.ONE]: 'one', - [gl.SRC_COLOR]: 'src color', - [gl.ONE_MINUS_SRC_COLOR]: 'one minus src color', - [gl.SRC_ALPHA]: 'src alpha', - [gl.ONE_MINUS_SRC_ALPHA]: 'one minus src alpha', - [gl.DST_COLOR]: 'dst color', - [gl.ONE_MINUS_DST_COLOR]: 'one minus dst color', - [gl.DST_ALPHA]: 'dst alpha', - [gl.ONE_MINUS_DST_ALPHA]: 'one minus dst alpha', - [gl.CONSTANT_COLOR]: 'constant color', - [gl.ONE_MINUS_CONSTANT_COLOR]: 'one minus constant color', - [gl.CONSTANT_ALPHA]: 'constant alpha', - [gl.ONE_MINUS_CONSTANT_ALPHA]: 'one minus constant alpha', - [gl.SRC_ALPHA_SATURATE]: 'src alpha saturate', -}; - -export const stencilFuncMap: { - [key: string]: regl.ComparisonOperatorType; -} = { - [gl.NEVER]: 'never', - [gl.ALWAYS]: 'always', - [gl.LESS]: 'less', - [gl.LEQUAL]: 'lequal', - [gl.GREATER]: 'greater', - [gl.GEQUAL]: 'gequal', - [gl.EQUAL]: 'equal', - [gl.NOTEQUAL]: 'notequal', -}; - -export const stencilOpMap: { - [key: string]: regl.StencilOperationType; -} = { - [gl.ZERO]: 'zero', - [gl.KEEP]: 'keep', - [gl.REPLACE]: 'replace', - [gl.INVERT]: 'invert', - [gl.INCR]: 'increment', - [gl.DECR]: 'decrement', - [gl.INCR_WRAP]: 'increment wrap', - [gl.DECR_WRAP]: 'decrement wrap', -}; - -export const cullFaceMap: { - [key: string]: regl.FaceOrientationType; -} = { - [gl.FRONT]: 'front', - [gl.BACK]: 'back', -}; diff --git a/packages/renderer/src/regl/index.ts b/packages/renderer/src/regl/index.ts deleted file mode 100644 index e19a7a94db0..00000000000 --- a/packages/renderer/src/regl/index.ts +++ /dev/null @@ -1,286 +0,0 @@ -/** - * render w/ regl - * @see https://github.com/regl-project/regl/blob/gh-pages/API.md - */ -import type { - IAttribute, - IAttributeInitializationOptions, - IBuffer, - IBufferInitializationOptions, - IClearOptions, - IElements, - IElementsInitializationOptions, - IExtensions, - IFramebuffer, - IFramebufferInitializationOptions, - IModel, - IModelInitializationOptions, - IReadPixelsOptions, - IRenderConfig, - IRendererService, - ITexture2D, - ITexture2DInitializationOptions, -} from '@antv/l7-core'; -import regl from 'regl'; -import ReglAttribute from './ReglAttribute'; -import ReglBuffer from './ReglBuffer'; -import ReglElements from './ReglElements'; -import ReglFramebuffer from './ReglFramebuffer'; -import ReglModel from './ReglModel'; -import ReglTexture2D from './ReglTexture2D'; - -/** - * regl renderer - */ -export default class ReglRendererService implements IRendererService { - uniformBuffers: IBuffer[] = []; - public extensionObject: IExtensions; - private gl: regl.Regl; - private $container: HTMLDivElement | null; - private canvas: HTMLCanvasElement; - private width: number; - private height: number; - private isDirty: boolean; - - queryVerdorInfo = () => { - return 'WebGL1'; - }; - - public async init(canvas: HTMLCanvasElement, cfg: IRenderConfig, gl?: regl.Regl): Promise { - // this.$container = $container; - this.canvas = canvas; - if (gl) { - this.gl = gl; - } else { - // tslint:disable-next-line:typedef - this.gl = await new Promise((resolve, reject) => { - regl({ - canvas: this.canvas, - attributes: { - alpha: true, - // use TAA instead of MSAA - // @see https://www.khronos.org/registry/webgl/specs/1.0/#5.2.1 - antialias: cfg.antialias, - premultipliedAlpha: true, - preserveDrawingBuffer: cfg.preserveDrawingBuffer, - - stencil: cfg.stencil, - }, - // TODO: use extensions - extensions: [ - 'OES_element_index_uint', - 'OES_standard_derivatives', // wireframe - 'ANGLE_instanced_arrays', // VSM shadow map - ], - optionalExtensions: [ - 'oes_texture_float_linear', - 'OES_texture_float', - 'EXT_texture_filter_anisotropic', - 'EXT_blend_minmax', - 'WEBGL_depth_texture', - 'WEBGL_lose_context', - ], - profile: true, - onDone: (err: Error | null, r?: regl.Regl | undefined): void => { - if (err || !r) { - reject(err); - } - // @ts-ignore - resolve(r); - }, - }); - }); - } - - this.extensionObject = { - OES_texture_float: this.testExtension('OES_texture_float'), - }; - } - - public getPointSizeRange() { - return this.gl._gl.getParameter(this.gl._gl.ALIASED_POINT_SIZE_RANGE); - } - - public testExtension(name: string) { - // OES_texture_float - return !!this.getGLContext().getExtension(name); - } - - public createModel = (options: IModelInitializationOptions): IModel => - new ReglModel(this.gl, options); - - public createAttribute = (options: IAttributeInitializationOptions): IAttribute => - new ReglAttribute(this.gl, options); - - public createBuffer = (options: IBufferInitializationOptions): IBuffer => - new ReglBuffer(this.gl, options); - - public createElements = (options: IElementsInitializationOptions): IElements => - new ReglElements(this.gl, options); - - public createTexture2D = (options: ITexture2DInitializationOptions): ITexture2D => - new ReglTexture2D(this.gl, options); - - public createFramebuffer = (options: IFramebufferInitializationOptions) => - new ReglFramebuffer(this.gl, options); - - public useFramebuffer = (framebuffer: IFramebuffer | null, drawCommands: () => void) => { - this.gl({ - framebuffer: framebuffer ? (framebuffer as ReglFramebuffer).get() : null, - })(drawCommands); - }; - - public useFramebufferAsync = async ( - framebuffer: IFramebuffer | null, - drawCommands: () => Promise, - ) => { - this.gl({ - framebuffer: framebuffer ? (framebuffer as ReglFramebuffer).get() : null, - })(drawCommands); - }; - - public clear = (options: IClearOptions) => { - // @see https://github.com/regl-project/regl/blob/gh-pages/API.md#clear-the-draw-buffer - const { color, depth, stencil, framebuffer = null } = options; - const reglClearOptions: regl.ClearOptions = { - color, - depth, - stencil, - }; - - reglClearOptions.framebuffer = - framebuffer === null ? framebuffer : (framebuffer as ReglFramebuffer).get(); - - this.gl?.clear(reglClearOptions); - }; - - public viewport = ({ - x, - y, - width, - height, - }: { - x: number; - y: number; - width: number; - height: number; - }) => { - // use WebGL context directly - // @see https://github.com/regl-project/regl/blob/gh-pages/API.md#unsafe-escape-hatch - this.gl._gl.viewport(x, y, width, height); - this.width = width; - this.height = height; - this.gl._refresh(); - }; - - public readPixels = (options: IReadPixelsOptions) => { - const { framebuffer, x, y, width, height } = options; - const readPixelsOptions: regl.ReadOptions = { - x, - y, - width, - height, - }; - if (framebuffer) { - readPixelsOptions.framebuffer = (framebuffer as ReglFramebuffer).get(); - } - return this.gl.read(readPixelsOptions); - }; - - public readPixelsAsync = async (options: IReadPixelsOptions) => { - return this.readPixels(options); - }; - - public getViewportSize = () => { - return { - width: this.gl._gl.drawingBufferWidth, - height: this.gl._gl.drawingBufferHeight, - }; - }; - - public getContainer = () => { - return this.canvas?.parentElement; - }; - - public getCanvas = () => { - // return this.$container?.getElementsByTagName('canvas')[0] || null; - return this.canvas; - }; - - public getGLContext = () => { - return this.gl._gl; - }; - - // TODO: 临时方法 - public setState() { - this.gl({ - cull: { - enable: false, - face: 'back', - }, - viewport: { - x: 0, - y: 0, - height: this.width, - width: this.height, - }, - blend: { - enable: true, - equation: 'add', - }, - framebuffer: null, - }); - this.gl._refresh(); - } - - public setBaseState() { - this.gl({ - cull: { - enable: false, - face: 'back', - }, - viewport: { - x: 0, - y: 0, - height: this.width, - width: this.height, - }, - blend: { - enable: false, - equation: 'add', - }, - framebuffer: null, - }); - this.gl._refresh(); - } - public setCustomLayerDefaults() { - const gl = this.getGLContext(); - gl.disable(gl.CULL_FACE); - } - - public setDirty(flag: boolean): void { - this.isDirty = flag; - } - - public getDirty(): boolean { - return this.isDirty; - } - - public destroy = () => { - // this.canvas = null 清除对 webgl 实例的引用 - // @ts-ignore - this.canvas = null; - - // make sure release webgl context - this.gl?._gl?.getExtension('WEBGL_lose_context')?.loseContext(); - - // @see https://github.com/regl-project/regl/blob/gh-pages/API.md#clean-up - this.gl.destroy(); - - // @ts-ignore - this.gl = null; - }; - - beginFrame(): void {} - endFrame(): void {} -} diff --git a/packages/renderer/src/device/utils/HashMap.ts b/packages/renderer/src/utils/HashMap.ts similarity index 100% rename from packages/renderer/src/device/utils/HashMap.ts rename to packages/renderer/src/utils/HashMap.ts diff --git a/packages/renderer/src/device/utils/pipeline.ts b/packages/renderer/src/utils/pipeline.ts similarity index 100% rename from packages/renderer/src/device/utils/pipeline.ts rename to packages/renderer/src/utils/pipeline.ts diff --git a/packages/renderer/src/device/utils/typedarray.ts b/packages/renderer/src/utils/typedarray.ts similarity index 100% rename from packages/renderer/src/device/utils/typedarray.ts rename to packages/renderer/src/utils/typedarray.ts diff --git a/packages/renderer/src/device/utils/webgl.ts b/packages/renderer/src/utils/webgl.ts similarity index 100% rename from packages/renderer/src/device/utils/webgl.ts rename to packages/renderer/src/utils/webgl.ts diff --git a/packages/scene/src/index.ts b/packages/scene/src/index.ts index 97215b0f540..2b7c50d5b42 100644 --- a/packages/scene/src/index.ts +++ b/packages/scene/src/index.ts @@ -29,7 +29,7 @@ import type { } from '@antv/l7-core'; import { SceneEventList, createLayerContainer, createSceneContainer } from '@antv/l7-core'; import { MaskLayer, TileLayer } from '@antv/l7-layers'; -import { DeviceRendererService, ReglRendererService } from '@antv/l7-renderer'; +import { DeviceRendererService } from '@antv/l7-renderer'; import type { IProtocolHandler } from '@antv/l7-utils'; import { DOM, SceneConifg } from '@antv/l7-utils'; import type ILayerManager from './ILayerManager'; @@ -64,17 +64,13 @@ class Scene implements IPostProcessingPassPluggable, IMapController, ILayerManag private container: L7Container; public constructor(config: ISceneConfig) { - const { id, map, renderer = 'device' } = config; + const { id, map } = config; // 创建场景容器 const sceneContainer = createSceneContainer(); this.container = sceneContainer; // 绑定地图服务 map.setContainer(sceneContainer, id); - if (renderer === 'regl') { - sceneContainer.rendererService = new ReglRendererService(); - } else { - sceneContainer.rendererService = new DeviceRendererService(); - } + sceneContainer.rendererService = new DeviceRendererService(); // 依赖注入 this.sceneService = sceneContainer.sceneService; From ec627d72f7085d730c436aa008b44ca441e1a142 Mon Sep 17 00:00:00 2001 From: yunji Date: Tue, 28 May 2024 17:22:12 +0800 Subject: [PATCH 2/5] chore: remve renderer --- examples/constants.ts | 1 - examples/main.tsx | 3 --- examples/types.ts | 2 -- 3 files changed, 6 deletions(-) diff --git a/examples/constants.ts b/examples/constants.ts index 4a917134e33..cda0cf6048b 100644 --- a/examples/constants.ts +++ b/examples/constants.ts @@ -2,7 +2,6 @@ import type { GUIOptions, TestCaseBasemap } from './types'; export const DEFAULT_GUI_OPTIONS: GUIOptions = { map: 'Map', - renderer: 'device', animate: false, enableWebGPU: false, }; diff --git a/examples/main.tsx b/examples/main.tsx index 5c701da5189..8399245a33e 100644 --- a/examples/main.tsx +++ b/examples/main.tsx @@ -37,9 +37,6 @@ export const Main = () => { guiRef.current .add(inintGuiOptions, 'map', MAP_TYPES) .onChange((map: GUIOptions['map']) => onChange({ map })); - guiRef.current - .add(inintGuiOptions, 'renderer', ['regl', 'device']) - .onChange((renderer: GUIOptions['renderer']) => onChange({ renderer })); guiRef.current .add(inintGuiOptions, 'enableWebGPU') .onChange((enableWebGPU: GUIOptions['enableWebGPU']) => onChange({ enableWebGPU })); diff --git a/examples/types.ts b/examples/types.ts index 418724fe12c..e9fdd093852 100644 --- a/examples/types.ts +++ b/examples/types.ts @@ -1,10 +1,8 @@ import type { Scene } from '@antv/l7'; -import type { ISceneConfig } from '@antv/l7-core'; import type { Controller, GUI } from 'lil-gui'; export type GUIOptions = { map: TestCaseBasemap; - renderer: ISceneConfig['renderer']; animate: boolean; enableWebGPU: boolean; [keys: string]: any; From 5a8c28cb59f403e63e3b4228baa98693cd6f31ca Mon Sep 17 00:00:00 2001 From: yunji Date: Tue, 28 May 2024 19:23:22 +0800 Subject: [PATCH 3/5] chore: path --- packages/renderer/src/DeviceModel.ts | 2 +- .../renderer/src/DeviceRendererService.ts | 440 +++++++++++++++++ packages/renderer/src/index.ts | 441 +----------------- 3 files changed, 442 insertions(+), 441 deletions(-) create mode 100644 packages/renderer/src/DeviceRendererService.ts diff --git a/packages/renderer/src/DeviceModel.ts b/packages/renderer/src/DeviceModel.ts index 78c7ed5b401..b215e4dece7 100644 --- a/packages/renderer/src/DeviceModel.ts +++ b/packages/renderer/src/DeviceModel.ts @@ -27,11 +27,11 @@ import type { } from '@antv/l7-core'; import { gl } from '@antv/l7-core'; import { lodashUtil } from '@antv/l7-utils'; -import type DeviceRendererService from '.'; import type DeviceAttribute from './DeviceAttribute'; import type DeviceBuffer from './DeviceBuffer'; import type DeviceElements from './DeviceElements'; import DeviceFramebuffer from './DeviceFramebuffer'; +import type { DeviceRendererService } from './DeviceRendererService'; import DeviceTexture2D from './DeviceTexture2D'; import { blendEquationMap, diff --git a/packages/renderer/src/DeviceRendererService.ts b/packages/renderer/src/DeviceRendererService.ts new file mode 100644 index 00000000000..fb646c657bd --- /dev/null +++ b/packages/renderer/src/DeviceRendererService.ts @@ -0,0 +1,440 @@ +import type { Device, RenderPass, RenderTarget, SwapChain } from '@antv/g-device-api'; +import { + Format, + TextureUsage, + TransparentBlack, + ViewportOrigin, + WebGLDeviceContribution, + WebGPUDeviceContribution, + colorNewFromRGBA, +} from '@antv/g-device-api'; +import type { + IAttribute, + IAttributeInitializationOptions, + IBuffer, + IBufferInitializationOptions, + IClearOptions, + IElements, + IElementsInitializationOptions, + IExtensions, + IFramebuffer, + IFramebufferInitializationOptions, + IModel, + IModelInitializationOptions, + IReadPixelsOptions, + IRenderConfig, + IRendererService, + ITexture2D, + ITexture2DInitializationOptions, +} from '@antv/l7-core'; +import { lodashUtil } from '@antv/l7-utils'; +import DeviceAttribute from './DeviceAttribute'; +import DeviceBuffer from './DeviceBuffer'; +import { RenderCache } from './DeviceCache'; +import DeviceElements from './DeviceElements'; +import DeviceFramebuffer from './DeviceFramebuffer'; +import DeviceModel from './DeviceModel'; +import DeviceTexture2D from './DeviceTexture2D'; +import { isWebGL2 } from './utils/webgl'; +const { isUndefined } = lodashUtil; + +/** + * Device API renderer + */ +export class DeviceRendererService implements IRendererService { + uniformBuffers: IBuffer[] = []; + extensionObject: IExtensions; + private device: Device; + swapChain: SwapChain; + private $container: HTMLDivElement | null; + private canvas: HTMLCanvasElement; + width: number; + height: number; + private isDirty: boolean; + /** + * Current render pass. + */ + renderPass: RenderPass; + preRenderPass: RenderPass; + mainColorRT: RenderTarget; + mainDepthRT: RenderTarget; + + renderCache: RenderCache; + + /** + * Current FBO. + */ + currentFramebuffer: DeviceFramebuffer | null; + + queryVerdorInfo = () => { + return this.device.queryVendorInfo().platformString; + }; + + private viewportOrigin: ViewportOrigin; + + async init(canvas: HTMLCanvasElement, cfg: IRenderConfig): Promise { + const { enableWebGPU, shaderCompilerPath, antialias } = cfg; + + // this.$container = $container; + this.canvas = canvas; + + const deviceContribution = enableWebGPU + ? new WebGPUDeviceContribution({ + shaderCompilerPath, + }) + : new WebGLDeviceContribution({ + // Use WebGL2 first and downgrade to WebGL1 if WebGL2 is not supported. + targets: ['webgl2', 'webgl1'], + antialias, + onContextLost(e) { + console.warn('context lost', e); + }, + onContextCreationError(e) { + console.warn('context creation error', e); + }, + onContextRestored(e) { + console.warn('context restored', e); + }, + }); + + const swapChain = await deviceContribution.createSwapChain(canvas); + swapChain.configureSwapChain(canvas.width, canvas.height); + this.device = swapChain.getDevice(); + this.swapChain = swapChain; + + this.renderCache = new RenderCache(this.device); + + // Create default RT + this.currentFramebuffer = null; + + this.viewportOrigin = this.device.queryVendorInfo().viewportOrigin; + + // @ts-ignore + const gl = this.device['gl']; + this.extensionObject = { + // @ts-ignore + OES_texture_float: !isWebGL2(gl) && this.device['OES_texture_float'], + }; + + this.createMainColorDepthRT(canvas.width, canvas.height); + } + + private createMainColorDepthRT(width: number, height: number) { + if (this.mainColorRT) { + this.mainColorRT.destroy(); + } + if (this.mainDepthRT) { + this.mainDepthRT.destroy(); + } + + this.mainColorRT = this.device.createRenderTargetFromTexture( + this.device.createTexture({ + format: Format.U8_RGBA_RT, + width, + height, + usage: TextureUsage.RENDER_TARGET, + }), + ); + + this.mainDepthRT = this.device.createRenderTargetFromTexture( + this.device.createTexture({ + format: Format.D24_S8, + width, + height, + usage: TextureUsage.RENDER_TARGET, + }), + ); + } + + beginFrame(): void { + this.device.beginFrame(); + + const { currentFramebuffer, swapChain, mainColorRT, mainDepthRT } = this; + + const colorAttachment = currentFramebuffer + ? currentFramebuffer['colorRenderTarget'] + : mainColorRT; + const colorResolveTo = currentFramebuffer ? null : swapChain.getOnscreenTexture(); + const depthStencilAttachment = currentFramebuffer + ? currentFramebuffer['depthRenderTarget'] + : mainDepthRT; + + const { color = [0, 0, 0, 0], depth = 1, stencil = 0 } = + // @ts-ignore + currentFramebuffer?.clearOptions || {}; + + const colorClearColor = colorAttachment + ? colorNewFromRGBA(color[0] * 255, color[1] * 255, color[2] * 255, color[3]) + : TransparentBlack; + const depthClearValue = depthStencilAttachment ? depth : undefined; + const stencilClearValue = depthStencilAttachment ? stencil : undefined; + + const renderPass = this.device.createRenderPass({ + colorAttachment: [colorAttachment], + colorResolveTo: [colorResolveTo], + colorClearColor: [colorClearColor], + // colorStore: [!!currentFramebuffer], + colorStore: [true], + depthStencilAttachment, + depthClearValue, + stencilClearValue, + }); + this.renderPass = renderPass; + } + + endFrame(): void { + this.device.submitPass(this.renderPass); + this.device.endFrame(); + } + + getPointSizeRange() { + // @ts-ignore + const gl = this.device['gl']; + // FIXME: implement this method in Device API. + return gl.getParameter(gl.ALIASED_POINT_SIZE_RANGE); + } + + public testExtension(name: string) { + // OES_texture_float + return !!this.getGLContext().getExtension(name); + } + + createModel = (options: IModelInitializationOptions): IModel => + new DeviceModel(this.device, options, this); + + createAttribute = (options: IAttributeInitializationOptions): IAttribute => + new DeviceAttribute(this.device, options); + + createBuffer = (options: IBufferInitializationOptions): IBuffer => + new DeviceBuffer(this.device, options); + + createElements = (options: IElementsInitializationOptions): IElements => + new DeviceElements(this.device, options); + + createTexture2D = (options: ITexture2DInitializationOptions): ITexture2D => + new DeviceTexture2D(this.device, options); + + createFramebuffer = (options: IFramebufferInitializationOptions) => + new DeviceFramebuffer(this.device, options); + + useFramebuffer = (framebuffer: IFramebuffer | null, drawCommands: () => void) => { + this.currentFramebuffer = framebuffer as DeviceFramebuffer; + this.beginFrame(); + drawCommands(); + this.endFrame(); + this.currentFramebuffer = null; + }; + + useFramebufferAsync = async ( + framebuffer: IFramebuffer | null, + drawCommands: () => Promise, + ) => { + this.currentFramebuffer = framebuffer as DeviceFramebuffer; + this.preRenderPass = this.renderPass; + this.beginFrame(); + await drawCommands(); + this.endFrame(); + this.currentFramebuffer = null; + this.renderPass = this.preRenderPass; + }; + + clear = (options: IClearOptions) => { + // @see https://github.com/regl-project/regl/blob/gh-pages/API.md#clear-the-draw-buffer + const { color, depth, stencil, framebuffer = null } = options; + if (framebuffer) { + // @ts-ignore + framebuffer.clearOptions = { color, depth, stencil }; + } else { + const platformString = this.queryVerdorInfo(); + if (platformString === 'WebGL1') { + const gl = this.getGLContext(); + if (!isUndefined(stencil)) { + gl.clearStencil(stencil); + gl.clear(gl.STENCIL_BUFFER_BIT); + } else if (!isUndefined(depth)) { + gl.clearDepth(depth); + gl.clear(gl.DEPTH_BUFFER_BIT); + } + } else if (platformString === 'WebGL2') { + const gl = this.getGLContext() as WebGL2RenderingContext; + if (!isUndefined(stencil)) { + gl.clearBufferiv(gl.STENCIL, 0, [stencil]); + } else if (!isUndefined(depth)) { + gl.clearBufferfv(gl.DEPTH, 0, [depth]); + } + } + } + // Recreate render pass + // this.beginFrame(); + }; + + viewport = ({ + // x, + // y, + width, + height, + }: { + x: number; + y: number; + width: number; + height: number; + }) => { + // @see https://observablehq.com/@antv/g-device-api#cell-267 + this.swapChain.configureSwapChain(width, height); + this.createMainColorDepthRT(width, height); + this.width = width; + this.height = height; + }; + + readPixels = (options: IReadPixelsOptions) => { + const { framebuffer, x, y, width, height } = options; + const readback = this.device.createReadback(); + const texture = (framebuffer as DeviceFramebuffer)['colorTexture']; + const result = readback.readTextureSync( + texture, + x, + /** + * Origin is at lower-left corner. Width / height is already multiplied by dpr. + * WebGPU needs flipY + */ + this.viewportOrigin === ViewportOrigin.LOWER_LEFT ? y : this.height - y, + width, + height, + new Uint8Array(width * height * 4), + ) as Uint8Array; + readback.destroy(); + return result; + }; + + readPixelsAsync = async (options: IReadPixelsOptions) => { + const { framebuffer, x, y, width, height } = options; + + const readback = this.device.createReadback(); + const texture = (framebuffer as DeviceFramebuffer)['colorTexture']; + const result = (await readback.readTexture( + texture, + x, + /** + * Origin is at lower-left corner. Width / height is already multiplied by dpr. + * WebGPU needs flipY + */ + this.viewportOrigin === ViewportOrigin.LOWER_LEFT ? y : this.height - y, + width, + height, + new Uint8Array(width * height * 4), + )) as Uint8Array; + + // Since we use U8_RGBA_RT format in render target, need to change bgranorm -> rgba here. + if (this.viewportOrigin !== ViewportOrigin.LOWER_LEFT) { + for (let j = 0; j < result.length; j += 4) { + // Switch b and r components. + const t = result[j]; + result[j] = result[j + 2]; + result[j + 2] = t; + } + } + + readback.destroy(); + + return result; + }; + + getViewportSize = () => { + // FIXME: add viewport size in Device API. + return { + width: this.width, + height: this.height, + }; + }; + + getContainer = () => { + return this.canvas?.parentElement; + }; + + getCanvas = () => { + return this.canvas; + }; + + getGLContext = () => { + // @ts-ignore + return this.device['gl'] as WebGLRenderingContext; + }; + + // TODO: 临时方法 + setState() { + // this.gl({ + // cull: { + // enable: false, + // face: 'back', + // }, + // viewport: { + // x: 0, + // y: 0, + // height: this.width, + // width: this.height, + // }, + // blend: { + // enable: true, + // equation: 'add', + // }, + // framebuffer: null, + // }); + // this.gl._refresh(); + } + + setBaseState() { + // this.gl({ + // cull: { + // enable: false, + // face: 'back', + // }, + // viewport: { + // x: 0, + // y: 0, + // height: this.width, + // width: this.height, + // }, + // blend: { + // enable: false, + // equation: 'add', + // }, + // framebuffer: null, + // }); + // this.gl._refresh(); + } + setCustomLayerDefaults() { + // const gl = this.getGLContext(); + // gl.disable(gl.CULL_FACE); + } + + setDirty(flag: boolean): void { + this.isDirty = flag; + } + + getDirty(): boolean { + return this.isDirty; + } + + destroy = () => { + // this.canvas = null 清除对 webgl 实例的引用 + // @ts-ignore + this.canvas = null; + + this.uniformBuffers?.forEach((buffer) => { + buffer.destroy(); + }); + + this.device.destroy(); + + this.renderCache.destroy(); + + // make sure release webgl context + // this.gl?._gl?.getExtension('WEBGL_lose_context')?.loseContext(); + + // @see https://github.com/regl-project/regl/blob/gh-pages/API.md#clean-up + // this.gl.destroy(); + + // @ts-ignore + // this.gl = null; + }; +} diff --git a/packages/renderer/src/index.ts b/packages/renderer/src/index.ts index fb646c657bd..2f88eaecad5 100644 --- a/packages/renderer/src/index.ts +++ b/packages/renderer/src/index.ts @@ -1,440 +1 @@ -import type { Device, RenderPass, RenderTarget, SwapChain } from '@antv/g-device-api'; -import { - Format, - TextureUsage, - TransparentBlack, - ViewportOrigin, - WebGLDeviceContribution, - WebGPUDeviceContribution, - colorNewFromRGBA, -} from '@antv/g-device-api'; -import type { - IAttribute, - IAttributeInitializationOptions, - IBuffer, - IBufferInitializationOptions, - IClearOptions, - IElements, - IElementsInitializationOptions, - IExtensions, - IFramebuffer, - IFramebufferInitializationOptions, - IModel, - IModelInitializationOptions, - IReadPixelsOptions, - IRenderConfig, - IRendererService, - ITexture2D, - ITexture2DInitializationOptions, -} from '@antv/l7-core'; -import { lodashUtil } from '@antv/l7-utils'; -import DeviceAttribute from './DeviceAttribute'; -import DeviceBuffer from './DeviceBuffer'; -import { RenderCache } from './DeviceCache'; -import DeviceElements from './DeviceElements'; -import DeviceFramebuffer from './DeviceFramebuffer'; -import DeviceModel from './DeviceModel'; -import DeviceTexture2D from './DeviceTexture2D'; -import { isWebGL2 } from './utils/webgl'; -const { isUndefined } = lodashUtil; - -/** - * Device API renderer - */ -export class DeviceRendererService implements IRendererService { - uniformBuffers: IBuffer[] = []; - extensionObject: IExtensions; - private device: Device; - swapChain: SwapChain; - private $container: HTMLDivElement | null; - private canvas: HTMLCanvasElement; - width: number; - height: number; - private isDirty: boolean; - /** - * Current render pass. - */ - renderPass: RenderPass; - preRenderPass: RenderPass; - mainColorRT: RenderTarget; - mainDepthRT: RenderTarget; - - renderCache: RenderCache; - - /** - * Current FBO. - */ - currentFramebuffer: DeviceFramebuffer | null; - - queryVerdorInfo = () => { - return this.device.queryVendorInfo().platformString; - }; - - private viewportOrigin: ViewportOrigin; - - async init(canvas: HTMLCanvasElement, cfg: IRenderConfig): Promise { - const { enableWebGPU, shaderCompilerPath, antialias } = cfg; - - // this.$container = $container; - this.canvas = canvas; - - const deviceContribution = enableWebGPU - ? new WebGPUDeviceContribution({ - shaderCompilerPath, - }) - : new WebGLDeviceContribution({ - // Use WebGL2 first and downgrade to WebGL1 if WebGL2 is not supported. - targets: ['webgl2', 'webgl1'], - antialias, - onContextLost(e) { - console.warn('context lost', e); - }, - onContextCreationError(e) { - console.warn('context creation error', e); - }, - onContextRestored(e) { - console.warn('context restored', e); - }, - }); - - const swapChain = await deviceContribution.createSwapChain(canvas); - swapChain.configureSwapChain(canvas.width, canvas.height); - this.device = swapChain.getDevice(); - this.swapChain = swapChain; - - this.renderCache = new RenderCache(this.device); - - // Create default RT - this.currentFramebuffer = null; - - this.viewportOrigin = this.device.queryVendorInfo().viewportOrigin; - - // @ts-ignore - const gl = this.device['gl']; - this.extensionObject = { - // @ts-ignore - OES_texture_float: !isWebGL2(gl) && this.device['OES_texture_float'], - }; - - this.createMainColorDepthRT(canvas.width, canvas.height); - } - - private createMainColorDepthRT(width: number, height: number) { - if (this.mainColorRT) { - this.mainColorRT.destroy(); - } - if (this.mainDepthRT) { - this.mainDepthRT.destroy(); - } - - this.mainColorRT = this.device.createRenderTargetFromTexture( - this.device.createTexture({ - format: Format.U8_RGBA_RT, - width, - height, - usage: TextureUsage.RENDER_TARGET, - }), - ); - - this.mainDepthRT = this.device.createRenderTargetFromTexture( - this.device.createTexture({ - format: Format.D24_S8, - width, - height, - usage: TextureUsage.RENDER_TARGET, - }), - ); - } - - beginFrame(): void { - this.device.beginFrame(); - - const { currentFramebuffer, swapChain, mainColorRT, mainDepthRT } = this; - - const colorAttachment = currentFramebuffer - ? currentFramebuffer['colorRenderTarget'] - : mainColorRT; - const colorResolveTo = currentFramebuffer ? null : swapChain.getOnscreenTexture(); - const depthStencilAttachment = currentFramebuffer - ? currentFramebuffer['depthRenderTarget'] - : mainDepthRT; - - const { color = [0, 0, 0, 0], depth = 1, stencil = 0 } = - // @ts-ignore - currentFramebuffer?.clearOptions || {}; - - const colorClearColor = colorAttachment - ? colorNewFromRGBA(color[0] * 255, color[1] * 255, color[2] * 255, color[3]) - : TransparentBlack; - const depthClearValue = depthStencilAttachment ? depth : undefined; - const stencilClearValue = depthStencilAttachment ? stencil : undefined; - - const renderPass = this.device.createRenderPass({ - colorAttachment: [colorAttachment], - colorResolveTo: [colorResolveTo], - colorClearColor: [colorClearColor], - // colorStore: [!!currentFramebuffer], - colorStore: [true], - depthStencilAttachment, - depthClearValue, - stencilClearValue, - }); - this.renderPass = renderPass; - } - - endFrame(): void { - this.device.submitPass(this.renderPass); - this.device.endFrame(); - } - - getPointSizeRange() { - // @ts-ignore - const gl = this.device['gl']; - // FIXME: implement this method in Device API. - return gl.getParameter(gl.ALIASED_POINT_SIZE_RANGE); - } - - public testExtension(name: string) { - // OES_texture_float - return !!this.getGLContext().getExtension(name); - } - - createModel = (options: IModelInitializationOptions): IModel => - new DeviceModel(this.device, options, this); - - createAttribute = (options: IAttributeInitializationOptions): IAttribute => - new DeviceAttribute(this.device, options); - - createBuffer = (options: IBufferInitializationOptions): IBuffer => - new DeviceBuffer(this.device, options); - - createElements = (options: IElementsInitializationOptions): IElements => - new DeviceElements(this.device, options); - - createTexture2D = (options: ITexture2DInitializationOptions): ITexture2D => - new DeviceTexture2D(this.device, options); - - createFramebuffer = (options: IFramebufferInitializationOptions) => - new DeviceFramebuffer(this.device, options); - - useFramebuffer = (framebuffer: IFramebuffer | null, drawCommands: () => void) => { - this.currentFramebuffer = framebuffer as DeviceFramebuffer; - this.beginFrame(); - drawCommands(); - this.endFrame(); - this.currentFramebuffer = null; - }; - - useFramebufferAsync = async ( - framebuffer: IFramebuffer | null, - drawCommands: () => Promise, - ) => { - this.currentFramebuffer = framebuffer as DeviceFramebuffer; - this.preRenderPass = this.renderPass; - this.beginFrame(); - await drawCommands(); - this.endFrame(); - this.currentFramebuffer = null; - this.renderPass = this.preRenderPass; - }; - - clear = (options: IClearOptions) => { - // @see https://github.com/regl-project/regl/blob/gh-pages/API.md#clear-the-draw-buffer - const { color, depth, stencil, framebuffer = null } = options; - if (framebuffer) { - // @ts-ignore - framebuffer.clearOptions = { color, depth, stencil }; - } else { - const platformString = this.queryVerdorInfo(); - if (platformString === 'WebGL1') { - const gl = this.getGLContext(); - if (!isUndefined(stencil)) { - gl.clearStencil(stencil); - gl.clear(gl.STENCIL_BUFFER_BIT); - } else if (!isUndefined(depth)) { - gl.clearDepth(depth); - gl.clear(gl.DEPTH_BUFFER_BIT); - } - } else if (platformString === 'WebGL2') { - const gl = this.getGLContext() as WebGL2RenderingContext; - if (!isUndefined(stencil)) { - gl.clearBufferiv(gl.STENCIL, 0, [stencil]); - } else if (!isUndefined(depth)) { - gl.clearBufferfv(gl.DEPTH, 0, [depth]); - } - } - } - // Recreate render pass - // this.beginFrame(); - }; - - viewport = ({ - // x, - // y, - width, - height, - }: { - x: number; - y: number; - width: number; - height: number; - }) => { - // @see https://observablehq.com/@antv/g-device-api#cell-267 - this.swapChain.configureSwapChain(width, height); - this.createMainColorDepthRT(width, height); - this.width = width; - this.height = height; - }; - - readPixels = (options: IReadPixelsOptions) => { - const { framebuffer, x, y, width, height } = options; - const readback = this.device.createReadback(); - const texture = (framebuffer as DeviceFramebuffer)['colorTexture']; - const result = readback.readTextureSync( - texture, - x, - /** - * Origin is at lower-left corner. Width / height is already multiplied by dpr. - * WebGPU needs flipY - */ - this.viewportOrigin === ViewportOrigin.LOWER_LEFT ? y : this.height - y, - width, - height, - new Uint8Array(width * height * 4), - ) as Uint8Array; - readback.destroy(); - return result; - }; - - readPixelsAsync = async (options: IReadPixelsOptions) => { - const { framebuffer, x, y, width, height } = options; - - const readback = this.device.createReadback(); - const texture = (framebuffer as DeviceFramebuffer)['colorTexture']; - const result = (await readback.readTexture( - texture, - x, - /** - * Origin is at lower-left corner. Width / height is already multiplied by dpr. - * WebGPU needs flipY - */ - this.viewportOrigin === ViewportOrigin.LOWER_LEFT ? y : this.height - y, - width, - height, - new Uint8Array(width * height * 4), - )) as Uint8Array; - - // Since we use U8_RGBA_RT format in render target, need to change bgranorm -> rgba here. - if (this.viewportOrigin !== ViewportOrigin.LOWER_LEFT) { - for (let j = 0; j < result.length; j += 4) { - // Switch b and r components. - const t = result[j]; - result[j] = result[j + 2]; - result[j + 2] = t; - } - } - - readback.destroy(); - - return result; - }; - - getViewportSize = () => { - // FIXME: add viewport size in Device API. - return { - width: this.width, - height: this.height, - }; - }; - - getContainer = () => { - return this.canvas?.parentElement; - }; - - getCanvas = () => { - return this.canvas; - }; - - getGLContext = () => { - // @ts-ignore - return this.device['gl'] as WebGLRenderingContext; - }; - - // TODO: 临时方法 - setState() { - // this.gl({ - // cull: { - // enable: false, - // face: 'back', - // }, - // viewport: { - // x: 0, - // y: 0, - // height: this.width, - // width: this.height, - // }, - // blend: { - // enable: true, - // equation: 'add', - // }, - // framebuffer: null, - // }); - // this.gl._refresh(); - } - - setBaseState() { - // this.gl({ - // cull: { - // enable: false, - // face: 'back', - // }, - // viewport: { - // x: 0, - // y: 0, - // height: this.width, - // width: this.height, - // }, - // blend: { - // enable: false, - // equation: 'add', - // }, - // framebuffer: null, - // }); - // this.gl._refresh(); - } - setCustomLayerDefaults() { - // const gl = this.getGLContext(); - // gl.disable(gl.CULL_FACE); - } - - setDirty(flag: boolean): void { - this.isDirty = flag; - } - - getDirty(): boolean { - return this.isDirty; - } - - destroy = () => { - // this.canvas = null 清除对 webgl 实例的引用 - // @ts-ignore - this.canvas = null; - - this.uniformBuffers?.forEach((buffer) => { - buffer.destroy(); - }); - - this.device.destroy(); - - this.renderCache.destroy(); - - // make sure release webgl context - // this.gl?._gl?.getExtension('WEBGL_lose_context')?.loseContext(); - - // @see https://github.com/regl-project/regl/blob/gh-pages/API.md#clean-up - // this.gl.destroy(); - - // @ts-ignore - // this.gl = null; - }; -} +export { DeviceRendererService } from './DeviceRendererService'; From 6aa756b0b20df3be74f2859b62ce6be18fbfa1f8 Mon Sep 17 00:00:00 2001 From: lvisei Date: Fri, 31 May 2024 16:37:13 +0800 Subject: [PATCH 4/5] chore: add changeset --- .changeset/brave-nails-wave.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/brave-nails-wave.md diff --git a/.changeset/brave-nails-wave.md b/.changeset/brave-nails-wave.md new file mode 100644 index 00000000000..05dd03de17f --- /dev/null +++ b/.changeset/brave-nails-wave.md @@ -0,0 +1,7 @@ +--- +"@antv/l7-core": patch +"@antv/l7-renderer": patch +"@antv/l7-scene": patch +--- + +refactor: remove regl render mode From 1202414fea23588f800db065c3156f77afdd16ad Mon Sep 17 00:00:00 2001 From: yunji Date: Fri, 31 May 2024 16:40:06 +0800 Subject: [PATCH 5/5] chore: format style --- .changeset/brave-nails-wave.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.changeset/brave-nails-wave.md b/.changeset/brave-nails-wave.md index 05dd03de17f..c425682cf9e 100644 --- a/.changeset/brave-nails-wave.md +++ b/.changeset/brave-nails-wave.md @@ -1,7 +1,7 @@ --- -"@antv/l7-core": patch -"@antv/l7-renderer": patch -"@antv/l7-scene": patch +'@antv/l7-core': patch +'@antv/l7-renderer': patch +'@antv/l7-scene': patch --- refactor: remove regl render mode