Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Mesh change IndexBuffer、VertexBuffer、VertexElements bug( need to update VAO) #719

Merged
merged 16 commits into from
Mar 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions packages/core/src/graphic/Mesh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export abstract class Mesh extends RefObject {
/** @internal */
_glIndexByteCount: number;
/** @internal */
_bufferStructChanged: boolean;
/** @internal */
_platformPrimitive: IPlatformPrimitive;

/** @internal */
Expand Down Expand Up @@ -183,6 +185,7 @@ export abstract class Mesh extends RefObject {
*/
_draw(shaderProgram: ShaderProgram, subMesh: SubMesh): void {
this._platformPrimitive.draw(shaderProgram, subMesh);
this._bufferStructChanged = false;
}

/**
Expand Down Expand Up @@ -213,16 +216,20 @@ export abstract class Mesh extends RefObject {
for (let i = 0, n = elements.length; i < n; i++) {
this._addVertexElement(elements[i]);
}
this._bufferStructChanged = true;
}

protected _setIndexBufferBinding(binding: IndexBufferBinding | null): void {
const lastBinding = this._indexBufferBinding;
if (binding) {
this._indexBufferBinding = binding;
this._glIndexType = BufferUtil._getGLIndexType(binding.format);
this._glIndexByteCount = BufferUtil._getGLIndexByteCount(binding.format);
(!lastBinding || lastBinding._buffer !== binding._buffer) && (this._bufferStructChanged = true);
} else {
this._indexBufferBinding = null;
this._glIndexType = undefined;
lastBinding && (this._bufferStructChanged = true);
}
}

Expand Down
85 changes: 45 additions & 40 deletions packages/rhi-webgl/src/GLPrimitive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,46 +6,49 @@ import { WebGLRenderer } from "./WebGLRenderer";
/**
* Improvement of VAO:
* 1) WebGL2.0 must support VAO, almost all devices support vao extensions in webgl1.0, we can use PollyFill,only keep VAO mode.
* 2) VAO implementation now has bugs, change IndexBuffer、VertexBuffer、VertexElements need to update VAO.
*/

/**
* @internal
* GL platform primitive.
*/
export class GLPrimitive implements IPlatformPrimitive {
protected attribLocArray: number[] = [];
protected readonly _primitive: Mesh;
protected readonly canUseInstancedArrays: boolean;
private _attribLocArray: number[] = [];
private readonly _primitive: Mesh;
private readonly _canUseInstancedArrays: boolean;

private gl: (WebGLRenderingContext & WebGLExtension) | WebGL2RenderingContext;
private vao: Map<number, WebGLVertexArrayObject> = new Map();
private _gl: (WebGLRenderingContext & WebGLExtension) | WebGL2RenderingContext;
private _vaoMap: Map<number, WebGLVertexArrayObject> = new Map();
private readonly _useVao: boolean;

constructor(rhi: WebGLRenderer, primitive: Mesh) {
this._primitive = primitive;
this.canUseInstancedArrays = rhi.canIUse(GLCapabilityType.instancedArrays);
this._canUseInstancedArrays = rhi.canIUse(GLCapabilityType.instancedArrays);
this._useVao = rhi.canIUse(GLCapabilityType.vertexArrayObject);
this.gl = rhi.gl;
this._gl = rhi.gl;
}

/**
* Draw the primitive.
*/
draw(shaderProgram: any, subMesh: SubMesh): void {
const gl = this.gl;
const gl = this._gl;
const primitive = this._primitive;
// @ts-ignore
const useVao = this._useVao && primitive._enableVAO;

if (useVao) {
if (!this.vao.has(shaderProgram.id)) {
this.registerVAO(shaderProgram);
// @ts-ignore
if (primitive._bufferStructChanged) {
this._clearVAO();
}
const vao = this.vao.get(shaderProgram.id);
if (!this._vaoMap.has(shaderProgram.id)) {
this._registerVAO(shaderProgram);
}
const vao = this._vaoMap.get(shaderProgram.id);
gl.bindVertexArray(vao);
} else {
this.bindBufferAndAttrib(shaderProgram);
this._bindBufferAndAttrib(shaderProgram);
}

// @ts-ignore
Expand All @@ -66,9 +69,9 @@ export class GLPrimitive implements IPlatformPrimitive {
gl.drawArrays(topology, start, count);
}
} else {
if (this.canUseInstancedArrays) {
if (this._canUseInstancedArrays) {
if (_indexBufferBinding) {
if (this._useVao) {
if (useVao) {
gl.drawElementsInstanced(topology, count, _glIndexType, start * _glIndexByteCount, _instanceCount);
} else {
const { _nativeBuffer } = _indexBufferBinding.buffer;
Expand All @@ -84,34 +87,28 @@ export class GLPrimitive implements IPlatformPrimitive {
}
}

// unbind
if (this._useVao) {
// Unbind
if (useVao) {
gl.bindVertexArray(null);
} else {
this.disableAttrib();
this._disableAttrib();
}
}

destroy() {
if (this._useVao) {
const gl = this.gl;
this.vao.forEach((vao) => {
gl.deleteVertexArray(vao);
});
this.vao.clear();
}
destroy(): void {
this._useVao && this._clearVAO();
}

/**
* Bind buffer and attribute.
*/
protected bindBufferAndAttrib(shaderProgram: any): void {
const gl = this.gl;
private _bindBufferAndAttrib(shaderProgram: any): void {
const gl = this._gl;
const primitive = this._primitive;
// @ts-ignore
const vertexBufferBindings = primitive._vertexBufferBindings;

this.attribLocArray.length = 0;
this._attribLocArray.length = 0;
const attributeLocation = shaderProgram.attributeLocation;
// @ts-ignore
const attributes = primitive._vertexElementMap;
Expand All @@ -136,10 +133,10 @@ export class GLPrimitive implements IPlatformPrimitive {
gl.enableVertexAttribArray(loc);
const elementInfo = element._glElementInfo;
gl.vertexAttribPointer(loc, elementInfo.size, elementInfo.type, elementInfo.normalized, stride, element.offset);
if (this.canUseInstancedArrays) {
if (this._canUseInstancedArrays) {
gl.vertexAttribDivisor(loc, element.instanceStepRate);
}
this.attribLocArray.push(loc);
this._attribLocArray.push(loc);
} else {
Logger.warn("vertex attribute not found: " + name);
}
Expand All @@ -148,15 +145,15 @@ export class GLPrimitive implements IPlatformPrimitive {
gl.bindBuffer(gl.ARRAY_BUFFER, null);
}

protected disableAttrib() {
const gl = this.gl;
for (let i = 0, l = this.attribLocArray.length; i < l; i++) {
gl.disableVertexAttribArray(this.attribLocArray[i]);
private _disableAttrib() {
const gl = this._gl;
for (let i = 0, l = this._attribLocArray.length; i < l; i++) {
gl.disableVertexAttribArray(this._attribLocArray[i]);
}
}

private registerVAO(shaderProgram: any): void {
const gl = this.gl;
private _registerVAO(shaderProgram: any): void {
const gl = this._gl;
const vao = gl.createVertexArray();

/** register VAO */
Expand All @@ -167,13 +164,21 @@ export class GLPrimitive implements IPlatformPrimitive {
if (_indexBufferBinding) {
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, _indexBufferBinding.buffer._nativeBuffer);
}
this.bindBufferAndAttrib(shaderProgram);
this._bindBufferAndAttrib(shaderProgram);

/** unbind */
gl.bindVertexArray(null);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
this.disableAttrib();
this._disableAttrib();

this._vaoMap.set(shaderProgram.id, vao);
}

this.vao.set(shaderProgram.id, vao);
private _clearVAO(): void {
const gl = this._gl;
this._vaoMap.forEach((vao) => {
gl.deleteVertexArray(vao);
});
this._vaoMap.clear();
}
}