From 5257570997ae2c7871b3133a3828ba0b4ab3c753 Mon Sep 17 00:00:00 2001 From: "yuqi.pyq" Date: Mon, 25 Sep 2023 09:57:42 +0800 Subject: [PATCH] fix: set default offset of IndexBuffer --- examples/demos/draw-index.ts | 150 +++++++++++++++++++++++++++++++++++ examples/demos/index.ts | 1 + src/api/utils/index.ts | 1 + src/api/utils/typedarray.ts | 28 +++++++ src/webgl/Device.ts | 2 +- src/webgl/Texture.ts | 8 +- 6 files changed, 185 insertions(+), 5 deletions(-) create mode 100644 examples/demos/draw-index.ts create mode 100644 src/api/utils/typedarray.ts diff --git a/examples/demos/draw-index.ts b/examples/demos/draw-index.ts new file mode 100644 index 0000000..48c7215 --- /dev/null +++ b/examples/demos/draw-index.ts @@ -0,0 +1,150 @@ +import { + DeviceContribution, + VertexStepMode, + Format, + TransparentWhite, + BufferUsage, + BufferFrequencyHint, + TextureUsage, +} from '../../src'; +import { initExample } from './utils'; + +export async function render( + deviceContribution: DeviceContribution, + $canvas: HTMLCanvasElement, + useRAF = true, +) { + // create swap chain and get device + const swapChain = (await deviceContribution.createSwapChain($canvas))!; + // TODO: resize + swapChain.configureSwapChain($canvas.width, $canvas.height); + const device = swapChain.getDevice(); + + const program = device.createProgram({ + vertex: { + glsl: ` +layout(location = 0) in vec2 a_Position; + +void main() { + gl_Position = vec4(a_Position, 0.0, 1.0); +} +`, + }, + fragment: { + glsl: ` +out vec4 outputColor; + +void main() { + outputColor = vec4(1.0, 0.0, 0.0, 1.0); +} +`, + }, + }); + + const vertexBuffer = device.createBuffer({ + viewOrSize: new Float32Array([0, 0.5, -0.5, -0.5, 0.5, -0.5]), + usage: BufferUsage.VERTEX, + hint: BufferFrequencyHint.DYNAMIC, + }); + device.setResourceName(vertexBuffer, 'a_Position'); + + const indexBuffer = device.createBuffer({ + viewOrSize: new Uint32Array([0, 1, 2]), + usage: BufferUsage.INDEX, + hint: BufferFrequencyHint.STATIC, + }); + + const inputLayout = device.createInputLayout({ + vertexBufferDescriptors: [ + { + arrayStride: 4 * 2, + stepMode: VertexStepMode.VERTEX, + attributes: [ + { + shaderLocation: 0, + offset: 0, + format: Format.F32_RG, + }, + ], + }, + ], + indexBufferFormat: Format.U32_R, + program, + }); + + const pipeline = device.createRenderPipeline({ + inputLayout, + program, + colorAttachmentFormats: [Format.U8_RGBA_RT], + }); + + const renderTarget = device.createRenderTargetFromTexture( + device.createTexture({ + format: Format.U8_RGBA_RT, + width: $canvas.width, + height: $canvas.height, + usage: TextureUsage.RENDER_TARGET, + }), + ); + device.setResourceName(renderTarget, 'Main Render Target'); + + let id: number; + const frame = () => { + /** + * An application should call getCurrentTexture() in the same task that renders to the canvas texture. + * Otherwise, the texture could get destroyed by these steps before the application is finished rendering to it. + */ + const onscreenTexture = swapChain.getOnscreenTexture(); + + const renderPass = device.createRenderPass({ + colorAttachment: [renderTarget], + colorResolveTo: [onscreenTexture], + colorClearColor: [TransparentWhite], + }); + + renderPass.setPipeline(pipeline); + renderPass.setVertexInput( + inputLayout, + [ + { + buffer: vertexBuffer, + }, + ], + { + buffer: indexBuffer, + }, + ); + renderPass.setViewport(0, 0, $canvas.width, $canvas.height); + renderPass.draw(3); + + device.submitPass(renderPass); + if (useRAF) { + id = requestAnimationFrame(frame); + } + }; + + frame(); + + return () => { + if (useRAF && id) { + cancelAnimationFrame(id); + } + program.destroy(); + vertexBuffer.destroy(); + indexBuffer.destroy(); + inputLayout.destroy(); + pipeline.destroy(); + renderTarget.destroy(); + device.destroy(); + + // For debug. + device.checkForLeaks(); + }; +} + +export async function DrawIndex($container: HTMLDivElement) { + return initExample($container, render, { + targets: ['webgl1', 'webgl2', 'webgpu'], + default: 'webgl2', + }); +} diff --git a/examples/demos/index.ts b/examples/demos/index.ts index d2c17c5..93770eb 100644 --- a/examples/demos/index.ts +++ b/examples/demos/index.ts @@ -1,5 +1,6 @@ export { PrimitiveTopologyPoints } from './primitive-topology-points'; export { PrimitiveTopologyTriangles } from './primitive-topology-triangles'; +export { DrawIndex } from './draw-index'; export { MSAA } from './msaa'; export { RotatingCube } from './rotating-cube'; export { TwoCubes } from './two-cubes'; diff --git a/src/api/utils/index.ts b/src/api/utils/index.ts index 7691972..fe62697 100644 --- a/src/api/utils/index.ts +++ b/src/api/utils/index.ts @@ -4,3 +4,4 @@ export * from './depth'; export * from './states'; export * from './hash'; export * from './uniform'; +export * from './typedarray'; diff --git a/src/api/utils/typedarray.ts b/src/api/utils/typedarray.ts new file mode 100644 index 0000000..e580b3a --- /dev/null +++ b/src/api/utils/typedarray.ts @@ -0,0 +1,28 @@ +const dtypes = { + '[object Int8Array]': 5120, + '[object Int16Array]': 5122, + '[object Int32Array]': 5124, + '[object Uint8Array]': 5121, + '[object Uint8ClampedArray]': 5121, + '[object Uint16Array]': 5123, + '[object Uint32Array]': 5125, + '[object Float32Array]': 5126, + '[object Float64Array]': 5121, + '[object ArrayBuffer]': 5121, +}; + +export type TypedArray = + | Int8Array + | Uint8Array + | Uint8ClampedArray + | Int16Array + | Uint16Array + | Int32Array + | Uint32Array + | Float32Array + | Float64Array; + +// eslint-disable-next-line +export function isTypedArray(x: any): x is TypedArray { + return Object.prototype.toString.call(x) in dtypes; +} diff --git a/src/webgl/Device.ts b/src/webgl/Device.ts index 776887b..d8e6d02 100644 --- a/src/webgl/Device.ts +++ b/src/webgl/Device.ts @@ -2087,7 +2087,7 @@ export class Device_GL implements SwapChain, Device { const buffer = indexBuffer.buffer as Buffer_GL; assert(buffer.usage === BufferUsage.INDEX); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, getPlatformBuffer(buffer)); - this.currentIndexBufferByteOffset = indexBuffer.offset; + this.currentIndexBufferByteOffset = indexBuffer.offset || 0; } else { this.currentIndexBufferByteOffset = null; } diff --git a/src/webgl/Texture.ts b/src/webgl/Texture.ts index 2590d5d..0bc3a1c 100644 --- a/src/webgl/Texture.ts +++ b/src/webgl/Texture.ts @@ -12,6 +12,7 @@ import { getFormatSamplerKind, getFormatTypeFlags, isPowerOfTwo, + isTypedArray, } from '../api'; import type { Device_GL } from './Device'; import { ResourceBase_GL } from './ResourceBase'; @@ -223,8 +224,7 @@ export class Texture_GL extends ResourceBase_GL implements Texture { this.gl_target === GL.TEXTURE_3D || this.gl_target === GL.TEXTURE_2D_ARRAY; const isCube = this.gl_target === GL.TEXTURE_CUBE_MAP; - // @ts-ignore - const isTypedArray = levelDatas[0].buffer; + const isTA = isTypedArray(levelDatas[0]); this.device.setActiveTexture(gl.TEXTURE0); this.device['currentTextures'][0] = null; @@ -233,7 +233,7 @@ export class Texture_GL extends ResourceBase_GL implements Texture { let width: number; let height: number; - if (isTypedArray) { + if (isTA) { width = this.width; height = this.height; } else { @@ -312,7 +312,7 @@ export class Texture_GL extends ResourceBase_GL implements Texture { } } else { // WebGL1: upload Array & Image separately - if (isTypedArray) { + if (isTA) { (gl as WebGLRenderingContext).texImage2D( gl_target, lod,