package com.glview.hwui; import com.glview.graphics.Bitmap; import com.glview.hwui.op.DisplayListData; import com.glview.hwui.op.RenderNodeOp; /** * * * enum DirtyPropertyMask { GENERIC = 1 << 1, TRANSLATION_X = 1 << 2, TRANSLATION_Y = 1 << 3, TRANSLATION_Z = 1 << 4, SCALE_X = 1 << 5, SCALE_Y = 1 << 6, ROTATION = 1 << 7, ROTATION_X = 1 << 8, ROTATION_Y = 1 << 9, X = 1 << 10, Y = 1 << 11, Z = 1 << 12, ALPHA = 1 << 13, DISPLAY_LIST = 1 << 14, }; * * * @author lijing.lj */ public class RenderNode { boolean mValid = false; /** * The cached display list which needs to sync to {@link #mDisplayListData}. * @see #replay(GLCanvas) * @see #mNeedsDisplayListDataSync */ DisplayListData mStageDisplayListData = null; /** * Recorded operations that will be replayed, use {@link StatefullBaseCanvas} to do the real gl operations. * @see #replay(GLCanvas) */ DisplayListData mDisplayListData = null; boolean mNeedsDisplayListDataSync = false; final byte[] mDisplayListDataLock = new byte[0]; final byte[] mStageDisplayListDataLock = new byte[0]; RenderProperties mRenderProperties = new RenderProperties(this); public RenderNode() { } public boolean isValid() { return mValid; } public void destroy() { if (!mValid) return; mValid = false; recycleDisplayListData(true); } /** * Recycle the current display list when {@link #destroy()} called * or the display list will be recreated. * @see #replay(GLCanvas) * * @param destory */ void recycleDisplayListData(boolean destory) { DisplayListData displayListData = mDisplayListData; synchronized (mDisplayListDataLock) { mDisplayListData = null; } recycleDisplayListData(displayListData, destory); } void recycleDisplayListData(DisplayListData displayListData, boolean destory) { if (displayListData != null) { CanvasOp op = displayListData.mCanvasOps; while (op != null) { if (destory && (op instanceof RenderNodeOp)) { ((RenderNodeOp) op).destroyRenderNode(); } CanvasOp next = op.mNext; op.recycle(); op = next; } displayListData.recycle(); } } /** * Start recording, obtain a GLRecordingCanvas. * @param w * @param h * @return */ public GLCanvas start(int w, int h) { mRenderProperties.setSize(w, h); return GLRecordingCanvas.obtain(this); } /** * End recording, the display list needs to be recreate. * Set {@link #mNeedsDisplayListDataSync} to true to notice * render thread that the display list will be sync. * @param endCanvas */ public void end(GLCanvas endCanvas) { if (!(endCanvas instanceof GLRecordingCanvas)) { throw new IllegalArgumentException("Passed an invalid canvas to end!"); } GLRecordingCanvas canvas = (GLRecordingCanvas) endCanvas; DisplayListData op = canvas.endRecording(); synchronized (mStageDisplayListDataLock) { if (mStageDisplayListData != null) { recycleDisplayListData(mStageDisplayListData, false); } mStageDisplayListData = op; mNeedsDisplayListDataSync = true; } canvas.recycle(); mValid = true; } public float getTranslationX() { return mRenderProperties.getTranslationX(); } public boolean setTranslationX(float translationX) { return mRenderProperties.setTranslationX(translationX); } public float getTranslationY() { return mRenderProperties.getTranslationY(); } public boolean setTranslationY(float translationY) { return mRenderProperties.setTranslationY(translationY); } public float getTranslationZ() { return mRenderProperties.getTranslationZ(); } public boolean setTranslationZ(float translationZ) { return mRenderProperties.setTranslationZ(translationZ); } public float getLeft() { return mRenderProperties.getLeft(); } public boolean setLeft(float left) { return mRenderProperties.setLeft(left); } public float getTop() { return mRenderProperties.getTop(); } public boolean setTop(float top) { return mRenderProperties.setTop(top); } public float getRight() { return mRenderProperties.getRight(); } public boolean setRight(float right) { return mRenderProperties.setRight(right); } public float getBottom() { return mRenderProperties.getBottom(); } public boolean setBottom(float bottom) { return mRenderProperties.setBottom(bottom); } public boolean setLeftTopRightBottom(float left, float top, float right, float bottom) { return setLeft(left) | setTop(top) | setRight(right) | setBottom(bottom); } public float getScaleX() { return mRenderProperties.getScaleX(); } public boolean setScaleX(float scaleX) { return mRenderProperties.setScaleX(scaleX); } public float getScaleY() { return mRenderProperties.getScaleY(); } public boolean setScaleY(float scaleY) { return mRenderProperties.setScaleY(scaleY); } public float getRotation() { return mRenderProperties.getRotation(); } public boolean setRotation(float rotation) { return mRenderProperties.setRotation(rotation); } public float getRotationX() { return mRenderProperties.getRotationX(); } public boolean setRotationX(float rotationX) { return mRenderProperties.setRotationX(rotationX); } public float getRotationY() { return mRenderProperties.getRotationY(); } public boolean setRotationY(float rotationY) { return mRenderProperties.setRotationY(rotationY); } public float getAlpha() { return mRenderProperties.getAlpha(); } public boolean setAlpha(float alpha) { return mRenderProperties.setAlpha(alpha); } public int getLayerType() { return mRenderProperties.getLayerType(); } public boolean setLayerType(int layerType) { return mRenderProperties.setLayerType(layerType); } public RenderProperties properties() { return mRenderProperties; } /* * This method runs in RenderThread. */ void replay(GLCanvas canvas) { if (mRenderProperties.skipRender()) return; // apply properties transform mRenderProperties.applyRenderProperties(canvas); // DisplayList has been changed by GLThread, sync it to RenderThread if (mNeedsDisplayListDataSync) { recycleDisplayListData(false); mDisplayListData = mStageDisplayListData; synchronized (mStageDisplayListDataLock) { mStageDisplayListData = null; mNeedsDisplayListDataSync = false; } mRenderProperties.mNeedsLayerSync = true; } mRenderProperties.updateRenderLayer(canvas); render(canvas); // restore properties transform mRenderProperties.restoreRenderProperties(canvas); } private void render(GLCanvas canvas) { if (!mRenderProperties.renderLayer(canvas)) { renderWithoutLayer(canvas); } } void renderWithoutLayer(GLCanvas canvas) { synchronized (mDisplayListDataLock) { DisplayListData displayListData = mDisplayListData; if (displayListData != null) { CanvasOp op = displayListData.mCanvasOps; while (op != null) { op.replay(canvas); op = op.mNext; } } } } public Bitmap buildDrawingCache(GLCanvas canvas) { try { if (mRenderProperties.skipRender()) return null; // DisplayList has been changed by GLThread, sync it to RenderThread if (mNeedsDisplayListDataSync) { recycleDisplayListData(false); mDisplayListData = mStageDisplayListData; synchronized (mStageDisplayListDataLock) { mStageDisplayListData = null; mNeedsDisplayListDataSync = false; } mRenderProperties.mNeedsLayerSync = true; } return mRenderProperties.buildDrawingCache(canvas); } finally { canvas.restoreToCount(0); } } }