浏览代码

fix some performance issue of canvas

/main
kg 6 年前
当前提交
294cb3c2
共有 8 个文件被更改,包括 174 次插入90 次删除
  1. 3
      Runtime/Resources/UIWidgets_canvas_convexFill.shader
  2. 5
      Runtime/Resources/UIWidgets_canvas_fill0.shader
  3. 3
      Runtime/Resources/UIWidgets_canvas_stroke0.shader
  4. 3
      Runtime/Resources/UIWidgets_canvas_tex.shader
  5. 10
      Runtime/ui/matrix.cs
  6. 67
      Runtime/ui/painting/canvas_clip.cs
  7. 49
      Runtime/ui/painting/canvas_impl.cs
  8. 124
      Runtime/ui/painting/canvas_shader.cs

3
Runtime/Resources/UIWidgets_canvas_convexFill.shader


Properties {
_SrcBlend("_SrcBlend", Int) = 1 // One
_DstBlend("_DstBlend", Int) = 10 // OneMinusSrcAlpha
_StencilComp("_StencilComp", Float) = 3 // - Equal, 8 - Always
}
SubShader {

Stencil {
Ref 128
Comp Equal
Comp [_StencilComp]
}
Pass { // 0, color

5
Runtime/Resources/UIWidgets_canvas_fill0.shader


Shader "UIWidgets/canvas_fill0"
{
Properties {
_StencilComp("_StencilComp", Float) = 3 // - Equal, 8 - Always
}
SubShader {

ColorMask 0
Stencil {
Ref 128
CompFront Equal
CompBack Equal
CompFront [_StencilComp]
CompBack [_StencilComp]
ReadMask 128
WriteMask 127
PassFront IncrWrap

3
Runtime/Resources/UIWidgets_canvas_stroke0.shader


Properties {
_SrcBlend("_SrcBlend", Int) = 1 // One
_DstBlend("_DstBlend", Int) = 10 // OneMinusSrcAlpha
_StencilComp("_StencilComp", Float) = 3 // - Equal, 8 - Always
}
SubShader {

Stencil {
Ref 128
Comp Equal
Comp [_StencilComp]
Pass IncrSat
}

3
Runtime/Resources/UIWidgets_canvas_tex.shader


Properties {
_SrcBlend("_SrcBlend", Int) = 1 // One
_DstBlend("_DstBlend", Int) = 10 // OneMinusSrcAlpha
_StencilComp("_StencilComp", Float) = 3 // - Equal, 8 - Always
}
SubShader {

Stencil {
Ref 128
Comp Equal
Comp [_StencilComp]
}
Pass { // 0, color

10
Runtime/ui/matrix.cs


}
else {
var points = new[] {
new Offset(src.left, src.top),
new Offset(src.right, src.top),
new Offset(src.right, src.bottom),
new Offset(src.left, src.bottom),
this.mapXY((float) src.left, (float) src.top),
this.mapXY((float) src.right, (float) src.top),
this.mapXY((float) src.right, (float) src.bottom),
this.mapXY((float) src.left, (float) src.bottom),
this.mapPoints(points);
var minX = points[0].dx;
var minY = points[0].dy;

67
Runtime/ui/painting/canvas_clip.cs


return this._genId;
}
bool _convexContains(float x, float y) {
if (this.mesh.vertices.Count <= 2) {
return false;
}
if (this.mesh.matrix != null) {
if (this._invMat == null) {
this._invMat = Matrix3.I();
this.mesh.matrix.invert(this._invMat); // ignore if not invertible for now.
}
var offset = this._invMat.mapXY(x, y);
x = (float) offset.dx;
y = (float) offset.dy;
}
for (var i = 0; i < this.mesh.vertices.Count; i++) {
var p0 = this.mesh.vertices[i];
var p1 = this.mesh.vertices[i == this.mesh.vertices.Count - 1 ? 0 : i + 1];
if (PathUtils.triarea2(p0.x, p0.y, p1.x, p1.y, x, y) < 0.0f) {
return false;
}
}
return true;
}
// bool _convexContains(float x, float y) {
// if (this.mesh.vertices.Count <= 2) {
// return false;
// }
//
// if (this.mesh.matrix != null) {
// if (this._invMat == null) {
// this._invMat = Matrix3.I();
// this.mesh.matrix.invert(this._invMat); // ignore if not invertible for now.
// }
//
// var offset = this._invMat.mapXY(x, y);
// x = (float) offset.dx;
// y = (float) offset.dy;
// }
//
// for (var i = 0; i < this.mesh.vertices.Count; i++) {
// var p0 = this.mesh.vertices[i];
// var p1 = this.mesh.vertices[i == this.mesh.vertices.Count - 1 ? 0 : i + 1];
//
// if (PathUtils.triarea2(p0.x, p0.y, p1.x, p1.y, x, y) < 0.0f) {
// return false;
// }
// }
//
// return true;
// }
public bool contains(Rect rect) {
if (this.isRect) {

if (this.convex) {
return this._convexContains((float) rect.left, (float) rect.top) &&
this._convexContains((float) rect.left, (float) rect.bottom) &&
this._convexContains((float) rect.right, (float) rect.top) &&
this._convexContains((float) rect.right, (float) rect.bottom);
}
// this seems to be inefficient. disable it for now.
// if (this.convex) {
// return this._convexContains((float) rect.left, (float) rect.top) &&
// this._convexContains((float) rect.left, (float) rect.bottom) &&
// this._convexContains((float) rect.right, (float) rect.top) &&
// this._convexContains((float) rect.right, (float) rect.bottom);
// }
return false;
}

49
Runtime/ui/painting/canvas_impl.cs


//var path = new Path();
}
void _tryAddScissor(RenderLayer layer, Rect scissor) {
if (scissor == layer.lastScissor) {
return;
}
layer.draws.Add(new RenderScissor {
deviceScissor = scissor,
});
layer.lastScissor = scissor;
}
bool _applyClip(Rect queryBounds) {
var layer = this._getLayer();
var layerBounds = layer.layerBounds;

var physicalRect = Rect.fromLTRB(0, 0, layer.width, layer.height);
if (scissor == layerBounds) {
layer.draws.Add(new RenderScissor {
deviceScissor = physicalRect,
});
this._tryAddScissor(layer, null);
} else {
var deviceScissor = Rect.fromLTRB(
scissor.left - layerBounds.left, layerBounds.bottom - scissor.bottom,

return false;
}
layer.draws.Add(new RenderScissor {
deviceScissor = deviceScissor,
});
this._tryAddScissor(layer, deviceScissor);
if (this._mustRenderClip(reducedClip.maskGenID(), reducedClip.scissor)) {
var boundsMesh = new MeshMesh(reducedClip.scissor);
layer.draws.Add(CanvasShader.stencilClear(layer, boundsMesh));
var maskGenID = reducedClip.maskGenID();
if (this._mustRenderClip(maskGenID, reducedClip.scissor)) {
if (maskGenID == ClipStack.wideOpenGenID) {
layer.ignoreClip = true;
} else {
layer.ignoreClip = false;
foreach (var maskElement in reducedClip.maskElements) {
layer.draws.Add(CanvasShader.stencil0(layer, maskElement.mesh));
layer.draws.Add(CanvasShader.stencil1(layer, boundsMesh));
var boundsMesh = new MeshMesh(reducedClip.scissor);
layer.draws.Add(CanvasShader.stencilClear(layer, boundsMesh));
foreach (var maskElement in reducedClip.maskElements) {
layer.draws.Add(CanvasShader.stencil0(layer, maskElement.mesh));
layer.draws.Add(CanvasShader.stencil1(layer, boundsMesh));
}
this._setLastClipGenId(reducedClip.maskGenID(), reducedClip.scissor);
this._setLastClipGenId(maskGenID, reducedClip.scissor);
}
return true;

}
break;
case RenderScissor cmd:
cmdBuf.EnableScissorRect(cmd.deviceScissor.toRect());
if (cmd.deviceScissor == null) {
cmdBuf.DisableScissorRect();
} else {
cmdBuf.EnableScissorRect(cmd.deviceScissor.toRect());
}
break;
}
}

bool _mustRenderClip(uint clipGenId, Rect clipBounds) {
var layer = this._getLayer();
return layer.lastClipGenId != clipGenId || layer.lastClipBounds != clipBounds;
}

public readonly ClipStack clipStack = new ClipStack();
public uint lastClipGenId;
public Rect lastClipBounds;
public Rect lastScissor;
public bool ignoreClip;
Vector4? _viewport;

124
Runtime/ui/painting/canvas_shader.cs


using System;
using Unity.UIWidgets.painting;
using UnityEngine;
using UnityEngine.Rendering;
class MaterialByBlendMode {
static class MaterialProps {
public MaterialByBlendMode(Shader shader) {
this._shader = shader;
}
readonly Shader _shader;
readonly Material[] _materials = new Material[30];
public Material getMaterial(BlendMode op) {
var mat = this._materials[(int) op];
if (mat) {
return mat;
}
mat = new Material(this._shader) {hideFlags = HideFlags.HideAndDontSave};
this._materials[(int) op] = mat;
static readonly int _stencilComp = Shader.PropertyToID("_StencilComp");
if (op == BlendMode.srcOver) {
public static void set(Material mat, BlendMode op) {
if (op == BlendMode.srcOver) {
mat.SetInt(_srcBlend, (int) UnityEngine.Rendering.BlendMode.One);
mat.SetInt(_dstBlend, (int) UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
} else if (op == BlendMode.srcIn) {

mat.SetInt(_srcBlend, (int) UnityEngine.Rendering.BlendMode.One);
mat.SetInt(_dstBlend, (int) UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
}
}
public static void set(Material mat, CompareFunction op) {
mat.SetFloat(_stencilComp, (int) op);
}
}
class MaterialByBlendMode {
public MaterialByBlendMode(Shader shader) {
this._shader = shader;
}
readonly Shader _shader;
readonly Material[] _materials = new Material[30];
public Material getMaterial(BlendMode op) {
var key = (int) op;
var mat = this._materials[key];
if (mat) {
return mat;
}
mat = new Material(this._shader) {hideFlags = HideFlags.HideAndDontSave};
MaterialProps.set(mat, op);
this._materials[key] = mat;
class MaterialByStencilComp {
public MaterialByStencilComp(Shader shader) {
this._shader = shader;
}
readonly Shader _shader;
readonly Material[] _materials = new Material[2];
public Material getMaterial(bool ignoreClip) {
var key = ignoreClip ? 1 : 0;
var mat = this._materials[key];
if (mat) {
return mat;
}
mat = new Material(this._shader) {hideFlags = HideFlags.HideAndDontSave};
MaterialProps.set(mat, ignoreClip ? CompareFunction.Always : CompareFunction.Equal);
this._materials[key] = mat;
return mat;
}
}
class MaterialByBlendModeStencilComp {
public MaterialByBlendModeStencilComp(Shader shader) {
this._shader = shader;
}
readonly Shader _shader;
readonly Material[] _materials = new Material[30 * 2];
public Material getMaterial(BlendMode blend, bool ignoreClip) {
var key = (int) blend * 2 + (ignoreClip ? 1 : 0);
var mat = this._materials[key];
if (mat) {
return mat;
}
mat = new Material(this._shader) {hideFlags = HideFlags.HideAndDontSave};
MaterialProps.set(mat, blend);
MaterialProps.set(mat, ignoreClip ? CompareFunction.Always : CompareFunction.Equal);
this._materials[key] = mat;
return mat;
}
}
static readonly MaterialByBlendMode _convexFillMat;
static readonly Material _fill0Mat;
static readonly MaterialByBlendModeStencilComp _convexFillMat;
static readonly MaterialByStencilComp _fill0Mat;
static readonly MaterialByBlendMode _stroke0Mat;
static readonly MaterialByBlendModeStencilComp _stroke0Mat;
static readonly MaterialByBlendMode _texMat;
static readonly MaterialByBlendModeStencilComp _texMat;
static readonly Material _stencilMat;
static readonly Material _filterMat;

throw new Exception("UIWidgets/canvas_filter not found");
}
_convexFillMat = new MaterialByBlendMode(convexFillShader);
_fill0Mat = new Material(fill0Shader) {hideFlags = HideFlags.HideAndDontSave};
_convexFillMat = new MaterialByBlendModeStencilComp(convexFillShader);
_fill0Mat = new MaterialByStencilComp(fill0Shader);
_stroke0Mat = new MaterialByBlendMode(stroke0Shader);
_stroke0Mat = new MaterialByBlendModeStencilComp(stroke0Shader);
_texMat = new MaterialByBlendMode(texShader);
_texMat = new MaterialByBlendModeStencilComp(texShader);
_stencilMat = new Material(stencilShader) {hideFlags = HideFlags.HideAndDontSave};
_filterMat = new Material(filterShader) {hideFlags = HideFlags.HideAndDontSave};
}

Vector4 viewport = layer.viewport;
Matrix3 ctm = layer.states[layer.states.Count - 1].matrix;
var mat = _convexFillMat.getMaterial(paint.blendMode);
var mat = _convexFillMat.getMaterial(paint.blendMode, layer.ignoreClip);
_getShaderPassAndProps(viewport, ctm, paint, 1.0f, out var pass, out var props);
return new CommandBufferCanvas.RenderDraw {

public static CommandBufferCanvas.RenderDraw fill0(CommandBufferCanvas.RenderLayer layer, MeshMesh mesh) {
Vector4 viewport = layer.viewport;
var mat = _fill0Mat;
var mat = _fill0Mat.getMaterial(layer.ignoreClip);
var pass = 0;
var props = new MaterialPropertyBlock();

Vector4 viewport = layer.viewport;
Matrix3 ctm = layer.states[layer.states.Count - 1].matrix;
var mat = _stroke0Mat.getMaterial(paint.blendMode);
var mat = _stroke0Mat.getMaterial(paint.blendMode, layer.ignoreClip);
_getShaderPassAndProps(viewport, ctm, paint, alpha, out var pass, out var props);
return new CommandBufferCanvas.RenderDraw {

Vector4 viewport = layer.viewport;
Matrix3 ctm = layer.states[layer.states.Count - 1].matrix;
var mat = _texMat.getMaterial(paint.blendMode);
var mat = _texMat.getMaterial(paint.blendMode, layer.ignoreClip);
_getShaderPassAndProps(viewport, ctm, paint, 1.0f, out var pass, out var props);
props.SetTexture("_tex", image.texture);
props.SetInt("_texMode", image.texture is RenderTexture ? 1 : 0); // pre alpha if RT else post alpha

Matrix3 ctm = layer.states[layer.states.Count - 1].matrix;
var mat = _texMat.getMaterial(paint.blendMode);
var mat = _texMat.getMaterial(paint.blendMode, layer.ignoreClip);
_getShaderPassAndProps(viewport, ctm, paint, 1.0f, out var pass, out var props);
props.SetInt("_texMode", 1); // pre alpha

Vector4 viewport = layer.viewport;
Matrix3 ctm = layer.states[layer.states.Count - 1].matrix;
var mat = _texMat.getMaterial(paint.blendMode);
var mat = _texMat.getMaterial(paint.blendMode, layer.ignoreClip);
_getShaderPassAndProps(viewport, ctm, paint, 1.0f, out var pass, out var props);
props.SetTexture("_tex", tex);
props.SetInt("_texMode", 2); // alpha only

正在加载...
取消
保存