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

Refactor 2d render pipeline #1708

Open
wants to merge 78 commits into
base: dev/1.3
Choose a base branch
from

Conversation

singlecoder
Copy link
Member

@singlecoder singlecoder commented Aug 22, 2023

for (let i = 0; i < charCount; ++i) {
const charRenderData = charRenderDatas[i];
const spriteRenderData = spriteRenderDataPool.getFromPool();
spriteRenderData.set(this, material, charRenderData.renderData, charRenderData.texture, i);
charsData[i] = spriteRenderData;
spriteRenderData.set(this, material, charRenderData.renderData, charRenderData.texture);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

charRenderData.usage = RenderDataUsage.Sprite;

@@ -70,6 +71,9 @@ export class Camera extends Component {
_renderPipeline: BasicRenderPipeline;
/** @internal */
@ignoreClone
_batcherManager: BatcherManager;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not in BasicRenderPipeline.

}

commitRenderData(context: RenderContext, data: RenderData | Array<RenderData>): void {
if (!data) return;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line can be deleted.

/** @internal */
_meshCount: number = 1;
/** @internal */
_subMeshPool: ClassPool<SubMesh> = new ClassPool(SubMesh);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be a static variable.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be a static variable.

has deleted


commitRenderData(context: RenderContext, data: SpriteRenderData): void {
if (this._preSpriteRenderData) {
if (this._vertexCount + data.verticesData.vertexCount > Batcher2D.MAX_VERTEX_COUNT) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to judge index

@cptbtptpbcptdtptp
Copy link
Collaborator

cptbtptpbcptdtptp commented Aug 28, 2023

There is a doubt that the current BatchManager is subordinate to the Camera. When the number of cameras increases, the memory occupied by Batch2D will also increase multiple times.
image
The same is true for SpriteMaskBatcher

this._cascadedShadowCaster = new CascadedShadowCasterPass(camera);
this._depthOnlyPass = new DepthOnlyPass(engine);
this._spriteMaskManager = new SpriteMaskManager(camera.engine);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it better to put SpriteMaskManager in Scene? Because :

  1. Mask does not depend on rendering timing.
  2. More memory efficient.

@singlecoder singlecoder changed the base branch from dev/1.1 to main September 13, 2023 09:46
batcher.freeChunk(renderer._chunk);
renderer._chunk = batcher.allocateChunk(4);
} else {
renderer._chunk = batcher.allocateChunk(4);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same code

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

positions[i] ||= new Vector3();
uvs[i] ||= new Vector2();
const batcher =
renderer instanceof SpriteRenderer
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instanceof is not good!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But this is not a high-frequency called function

}
verticesData.triangles = SimpleSpriteAssembler._rectangleTriangles;
renderer._chunk._indices = this._rectangleTriangles;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dirty code, opt like this!

static resetData(renderer: SpriteRenderer | SpriteMask): void {
    const batcher =
      renderer instanceof SpriteRenderer
        ? renderer.engine._batcherManager._batcher2D
        : renderer.engine._spriteMaskManager._batcher;

    const lastChunk = renderer._chunk;
    if (lastChunk) {
      batcher.freeChunk(lastChunk);
    }
    
    const chunk = batcher.allocateChunk(4);
    chunk._indices = this._rectangleTriangles;
    renderer._chunk = chunk;
  }

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}

static updatePositions(renderer: SpriteRenderer | SpriteMask): void {
const { width, height, sprite } = renderer;
const { x: pivotX, y: pivotY } = sprite.pivot;
// Renderer's worldMatrix;
const { _worldMatrix: worldMatrix } = SimpleSpriteAssembler;
const { _worldMatrix: worldMatrix } = this;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clear comments, remove ; .

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

* @internal
*/
export class MBChunk implements IPoolElement {
_mbId: number = -1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bunch of weird and wordy names!!!

index += 9;
vertices[index] = right;
vertices[index + 1] = top;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better per and less code

static updateUVs(renderer: SpriteRenderer | SpriteMask): void {
    const spriteUVs = renderer.sprite._getUVs();
    const { x: left, y: bottom } = spriteUVs[0];
    const { x: right, y: top } = spriteUVs[3];
    
    const chunk = renderer._chunk;
    const vertices = chunk._meshBuffer._vertices;
    const index = chunk._vEntry.start + 3;

    vertices[index] = left;
    vertices[index + 1] = bottom;

    vertices[index + 10] = right;
    vertices[index + 11] = bottom;

    vertices[index + 20] = left;
    vertices[index + 21] = top;

    vertices[index + 30] = right;
    vertices[index + 31] = top;
  }

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}
verticesData.triangles = SlicedSpriteAssembler._rectangleTriangles;
renderer._chunk._indices = this._rectangleTriangles;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same with SimpleSpriteAssembler

index += 9;
}
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before has BUG when set uv in updatePositions?

vertices[index + 3] = a;
index += 9;
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

static updateColor(renderer: SpriteRenderer): void {
    const chunk = renderer._chunk;
    const vertices = chunk._meshBuffer._vertices;
    const color = renderer.color;
    let index = chunk._vEntry.start + 5;
    for (let i = 0; i < 16; ++i) {
      color.copyToArray(vertices, index);
      index += 9;
    }
  }

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding one more API call compared to direct invocation

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And r g b a should be get repeat in loop

indicesCount += 6;
}
}
this.resetData(renderer, vertexCount, indicesCount);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code of this quality should not exist in the CR stage

const uvB = uvColumn.get(doubleJ);
const uvR = uvRow.get(2 * i + 1);
const uvT = uvColumn.get(doubleJ + 1);
if (isNaN(uvL) || isNaN(uvL) || isNaN(uvR) || isNaN(uvT)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isNaN(xxx) seems strange

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This block, I just reused the existing code

vertices[index + 3] = a;
index += 9;
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refer to previous suggestions

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the same as my opinion

// @ts-ignore
this._updateTransformShaderData(context, Matrix._identity);
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just don't want use worldMatrix?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_updateTransformShaderData consumes a lot of performance,for 2d with default material, just use renderer_MVPMat

renderData.set(this, material, this._verticesData);
engine._spriteMaskManager.addMask(this);
const renderData = engine._spriteRenderDataPool.getFromPool();
const { _chunk: chunk } = this;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not recommended to declare a single variable cache like this

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can not understand

@@ -284,13 +294,13 @@ export class SpriteRenderer extends Renderer {
* @internal
*/
override _updateShaderData(context: RenderContext, onlyMVP: boolean): void {
if (onlyMVP) {
if (this.getMaterial() === this.engine._spriteDefaultMaterial || onlyMVP) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why add this.getMaterial() === this.engine._spriteDefaultMaterial this condition?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Custom material may be use other matrix

this._resetSubFont();
}
return this._subFont;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

为什么公开这个接口?作用是什么?你如何对用户描述?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be internal, has change

@@ -354,13 +370,13 @@ export class TextRenderer extends Renderer {
* @internal
*/
override _updateShaderData(context: RenderContext, onlyMVP: boolean): void {
if (onlyMVP) {
if (this.getMaterial() === this.engine._spriteDefaultMaterial || onlyMVP) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same with before

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Custom material may be use other matrix

const worldPosition0 = TextRenderer._worldPositions[0];
const worldPosition1 = TextRenderer._worldPositions[1];
const worldPosition2 = TextRenderer._worldPositions[2];
const worldPosition3 = TextRenderer._worldPositions[3];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't make stupid mistakes

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what do you mean ??

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

vertices[index + 1] = position.y;
vertices[index + 2] = position.z;
index += 9;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

      const worldPositions = TextRenderer._worldPositions;
      ...
      const { chunk } = charRenderInfo;
      const vertices = chunk._meshBuffer._vertices;
      const index = chunk._vEntry.start;
      for (let i = 0; i < 4; ++i) {
        worldPositions[i].copyToArray(vertices, index + 9 * i);
      }

vertices[index + 2] = r;
vertices[index + 3] = g;
vertices[index + 4] = b;
vertices[index + 5] = a;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opt!!!

@@ -1,4 +1,3 @@
export { Font } from "./Font";
export { TextRenderer } from "./TextRenderer";
// Export for CanvasRenderer plugin.
export { TextUtils } from "./TextUtils";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can delete now?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

of cause, CanvasRenderer has deleted

@@ -268,6 +264,9 @@ export class Engine extends EventDispatcher {
this._textDefaultFont = Font.createFromOS(this, "Arial");
this._textDefaultFont.isGCIgnored = true;

this.inputManager = new InputManager(this);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merge error?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

???

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

this._preElement = null;
}

batch(srcElements, dstElements): void {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still 2D specialization logic

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RenderElement, sorry, i forget write, want batch logic write here, now, only 2D

/** @internal */
_componentInstanceId: number;
/** @internal */
_distanceForSort: number;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a internal class, why use internal property?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will change


/**
* Render queue.
*/
export class RenderQueue {
private static _textureProperty: ShaderProperty = ShaderProperty.getByName("renderer_SpriteTexture");

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you define a render property in Renderqueue?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for text that with multi-texture, i do not have any good idea now

} else {
return distanceDiff;
}
return dataA._distanceForSort - dataB._distanceForSort || instanceIdDiff;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not OK?

 return (
      dataA._priority - dataB._priority ||
      dataA._distanceForSort - dataB._distanceForSort ||
      dataA._componentInstanceId - dataB._componentInstanceId ||
      dataA._materialPriority - dataB._materialPriority
    );

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, in some case, the same renderer wo want control the sort just for material priority, link lottie or spine

// TextRenderer may be has multi-texture.
const isText = usage === RenderDataUsage.Text;
// @ts-ignore
isText && rendererData.setTexture(RenderQueue._textureProperty, data.texture);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No!!!!! This configuration should be done at the upper level

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't has a good idea how to handle a text renderer with multi-texture right now

const { usage } = data;
const needMask = usage === RenderDataUsage.Sprite || usage === RenderDataUsage.Text;
const renderer = data.component;
needMask && spriteMaskManager.preRender(camera, <SpriteRenderer>renderer);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Type is not write

compileMacros
);
const { usage } = data;
const needMask = usage === RenderDataUsage.Sprite || usage === RenderDataUsage.Text;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SpriteMask is still very specialized!

import { SpriteMaskBatcher } from "./SpriteMaskBatcher";
import { SpriteMaskRenderData } from "./SpriteMaskRenderData";
import { StencilOperation } from "../shader";
import { SpriteMaskBatcher } from "./batcher/SpriteMaskBatcher";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to discuss!!!

}

set(
override set(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Further abstraction is needed. In addition, this is a common class between text and elves. The current definition is unreasonable.

import { RenderDataUsage } from "../enums/RenderDataUsage";
import { Batcher2D } from "./Batcher2D";

export class BatcherManager {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the value of this class?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

future, i want handle all batch logic in batch function

/**
* @internal
*/
export class MeshBuffer {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vague definition, and needs to be redesigned!!!!!!!!!

import { SpriteRenderData } from "../SpriteRenderData";
import { Batcher2D } from "./Batcher2D";

export class SpriteMaskBatcher extends Batcher2D {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically no design, may need to be rewritten

*/
export class MeshBuffer {
/** @internal */
_mesh: BufferMesh;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use Primitive

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Development

Successfully merging this pull request may close these issues.

Optimize 2D rendering pipeline
3 participants