路人甲Java / 待分類 / 白鷺引擎渲染優化 - CacheAsBitmap

0 0

   

白鷺引擎渲染優化 - CacheAsBitmap

2020-03-10  路人甲Java

CacheAsBitmap

這篇文章要從 egret 中的對象基類 DisplayObject 實例屬性 cacheAsBitmap 說起。官方文檔建議靜態的UI使用建議設置 cacheAsBitmap 為 true 減少重繪次數。

如果設置為 true,則 Egret 運行時將緩存顯示對象的內部位圖表示形式。此緩存可以提高包含復雜矢量內容的顯示對象的性能。

  • 將 cacheAsBitmap 屬性設置為 true 后,呈現并不更改,但是,顯示對象將自動執行像素貼緊。執行速度可能會大大加快,
  • 具體取決于顯示對象內容的復雜性。最好將 cacheAsBitmap 屬性與主要具有靜態內容且不頻繁縮放或旋轉的顯示對象一起使用。

為了一探究竟 cacheAsBitmap 是如何緩存和減少重繪次數,簡單分析下源碼。

// class DisplayObject
public set cacheAsBitmap(value: boolean) {
    ……
    self.$setHasDisplayList(value);
}

public $setHasDisplayList(value: boolean): void {
    ……
    if (value) {
        let displayList = sys.DisplayList.create(self);
        if (displayList) {
            this.$displayList = displayList;
            this.$cacheDirty = true;
        }
    }
    else {
        this.$displayList = null;
    }
}

可以看到設置 cacheAsBitmap 屬性轉化為設置 $displayList ,而這個屬性值是 DisplayList 的實例,先不關心實例做了什么,等后續看到再展開。

DrawDisplayObject

找到了實際作用的屬性 $displayList ,要在繪制圖像方法中看這個屬性到底起到了什么作用。我的辦法比較笨,在全局搜 $displayList 屬性,還好出現的文件不算多。在 class WebGLRenderer 中找到了繪制一個顯示對象的方法 drawDisplayObject
簡單來說 WebGLRenderer 這個類的作用就是當判斷當前環境為 webgl 時使用的渲染類,跟它相對應的是 CanvasRenderer 類。

private drawDisplayObject(displayObject: DisplayObject, buffer: WebGLRenderBuffer, offsetX: number, offsetY: number, isStage?: boolean): number {
    // drawcall 表示繪制次數
    let drawCalls = 0;
    // 表示當前渲染節點
    let node: sys.RenderNode;
    let displayList = displayObject.$displayList;
    // isStage表示是否添加到舞臺對象
    if (displayList && !isStage) {
        if (displayObject.$cacheDirty || displayObject.$renderDirty ||
            displayList.$canvasScaleX != sys.DisplayList.$canvasScaleX ||
            displayList.$canvasScaleY != sys.DisplayList.$canvasScaleY) {
            // 當渲染節點比例發生變化時,需要繪制根節點顯示對象到目標畫布,返回draw的次數。
            drawCalls += displayList.drawToSurface();
        }
        node = displayList.$renderNode;
    }
    else {
        // $renderDirty為true表示更換了渲染節點,需要重新獲取渲染節點和清空drawData數據
        if (displayObject.$renderDirty) {
            node = displayObject.$getRenderNode();
        }
        else {
            node = displayObject.$renderNode;
        }
    }
 ……

isStage表示是否添加到舞臺對象,根據文檔,有且只有一個文檔類容器會被添加到stage容器中
image.png

先來看 drawDisplayObject 前半部分的代碼,可以看到設置了 cacheAsBitmap 與否決定了node 與 drawCall 的計算方式。

// drawDisplayObject方法
...
displayObject.$cacheDirty = false;
    if (node) {
        drawCalls++;
        buffer.$offsetX = offsetX;
        buffer.$offsetY = offsetY;
        // 這里是根據node type來做一些渲染,不影響drawcall
        switch (node.type) {
            case sys.RenderNodeType.BitmapNode:
                this.renderBitmap(<sys.BitmapNode>node, buffer);
                break;
        }
        buffer.$offsetX = 0;
        buffer.$offsetY = 0;
    }
    if (displayList && !isStage) {
        return drawCalls;
    }
    ...

這段代碼中當渲染節點存在時增加一次 drawCall,然后如果 isStage 為false 且 cacheAsBitmap為true 函數就返回了,不進行后續的計算。于是全局搜了一下 drawDisplayObject 的調用,只有在主動調用render方法的時候 isStage 才為 true,意味著每一次render如果設置了cacheAsBitmap為true,到這里就不再產生渲染次數了。

image.png

// drawDisplayObject方法剩下的代碼
let children = displayObject.$children;
if (children) {
    if (displayObject.sortableChildren && displayObject.$sortDirty) {
        //繪制排序
        displayObject.sortChildren();
    }
    let length = children.length;
    for (let i = 0; i < length; i++) {
        let child = children[i];
        let offsetX2;
        let offsetY2;
        let tempAlpha;
        let tempTintColor;
        if (child.$alpha != 1) {
            tempAlpha = buffer.globalAlpha;
            buffer.globalAlpha *= child.$alpha;
        }
        if (child.tint !== 0xFFFFFF) {
            tempTintColor = buffer.globalTintColor;
            buffer.globalTintColor = child.$tintRGB;
        }
        let savedMatrix: Matrix;
        if (child.$useTranslate) {
            let m = child.$getMatrix();
            offsetX2 = offsetX + child.$x;
            offsetY2 = offsetY + child.$y;
            let m2 = buffer.globalMatrix;
            savedMatrix = Matrix.create();
            savedMatrix.a = m2.a;
            savedMatrix.b = m2.b;
            savedMatrix.c = m2.c;
            savedMatrix.d = m2.d;
            savedMatrix.tx = m2.tx;
            savedMatrix.ty = m2.ty;
            buffer.transform(m.a, m.b, m.c, m.d, offsetX2, offsetY2);
            offsetX2 = -child.$anchorOffsetX;
            offsetY2 = -child.$anchorOffsetY;
        }
        else {
            offsetX2 = offsetX + child.$x - child.$anchorOffsetX;
            offsetY2 = offsetY + child.$y - child.$anchorOffsetY;
        }
        switch (child.$renderMode) {
            case RenderMode.NONE:
                break;
            case RenderMode.FILTER:
                drawCalls += this.drawWithFilter(child, buffer, offsetX2, offsetY2);
                break;
            case RenderMode.CLIP:
                drawCalls += this.drawWithClip(child, buffer, offsetX2, offsetY2);
                break;
            case RenderMode.SCROLLRECT:
                drawCalls += this.drawWithScrollRect(child, buffer, offsetX2, offsetY2);
                break;
            default:
                drawCalls += this.drawDisplayObject(child, buffer, offsetX2, offsetY2);
                break;
        }
        if (tempAlpha) {
            buffer.globalAlpha = tempAlpha;
        }
        if (tempTintColor) {
            buffer.globalTintColor = tempTintColor;
        }
        if (savedMatrix) {
            let m = buffer.globalMatrix;
            m.a = savedMatrix.a;
            m.b = savedMatrix.b;
            m.c = savedMatrix.c;
            m.d = savedMatrix.d;
            m.tx = savedMatrix.tx;
            m.ty = savedMatrix.ty;
            Matrix.release(savedMatrix);
        }
    }
}
return drawCalls;

剩下的代碼是對當前渲染節點的子節點進行渲染計算,也就是說,設置了 cacheAsBitMap 的 DisplayObject 每次render只對子節點進行一次渲染。

小結

從源碼分析了為什么 cacheAsBitMap 設置為 true 時可以減少ui的渲染次數,每次render通過減少子節點的渲染。因此將動靜態節點分層然后在靜態層設置 cacheAsBitMap 能夠有效減少渲染次數。

    本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發布,不代表本站觀點。如發現有害或侵權內容,請點擊這里 或 撥打24小時舉報電話:4000070609 與我們聯系。

    猜你喜歡

    0條評論

    發表

    請遵守用戶 評論公約

    類似文章 更多
    喜歡該文的人也喜歡 更多

    fun888 <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <文本链> <文本链> <文本链> <文本链> <文本链> <文本链>