/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "OpenGLRenderer" #include <SkCamera.h> #include <private/hwui/DrawGlInfo.h> #include "DisplayListLogBuffer.h" #include "DisplayListRenderer.h" #include "Caches.h" namespace android { namespace uirenderer { /////////////////////////////////////////////////////////////////////////////// // Display list /////////////////////////////////////////////////////////////////////////////// const char* DisplayList::OP_NAMES[] = { "Save", "Restore", "RestoreToCount", "SaveLayer", "SaveLayerAlpha", "Translate", "Rotate", "Scale", "Skew", "SetMatrix", "ConcatMatrix", "ClipRect", "DrawDisplayList", "DrawLayer", "DrawBitmap", "DrawBitmapMatrix", "DrawBitmapRect", "DrawBitmapData", "DrawBitmapMesh", "DrawPatch", "DrawColor", "DrawRect", "DrawRoundRect", "DrawCircle", "DrawOval", "DrawArc", "DrawPath", "DrawLines", "DrawPoints", "DrawText", "DrawTextOnPath", "DrawPosText", "ResetShader", "SetupShader", "ResetColorFilter", "SetupColorFilter", "ResetShadow", "SetupShadow", "ResetPaintFilter", "SetupPaintFilter", "DrawGLFunction" }; void DisplayList::outputLogBuffer(int fd) { DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance(); if (logBuffer.isEmpty()) { return; } FILE *file = fdopen(fd, "a"); fprintf(file, "\nRecent DisplayList operations\n"); logBuffer.outputCommands(file, OP_NAMES); String8 cachesLog; Caches::getInstance().dumpMemoryUsage(cachesLog); fprintf(file, "\nCaches:\n%s", cachesLog.string()); fprintf(file, "\n"); fflush(file); } DisplayList::DisplayList(const DisplayListRenderer& recorder) : mTransformMatrix(NULL), mTransformCamera(NULL), mTransformMatrix3D(NULL), mStaticMatrix(NULL), mAnimationMatrix(NULL) { initFromDisplayListRenderer(recorder); } DisplayList::~DisplayList() { clearResources(); } void DisplayList::initProperties() { mLeft = 0; mTop = 0; mRight = 0; mBottom = 0; mClipChildren = true; mAlpha = 1; mMultipliedAlpha = 255; mHasOverlappingRendering = true; mTranslationX = 0; mTranslationY = 0; mRotation = 0; mRotationX = 0; mRotationY= 0; mScaleX = 1; mScaleY = 1; mPivotX = 0; mPivotY = 0; mCameraDistance = 0; mMatrixDirty = false; mMatrixFlags = 0; mPrevWidth = -1; mPrevHeight = -1; mWidth = 0; mHeight = 0; mPivotExplicitlySet = false; mCaching = false; } void DisplayList::destroyDisplayListDeferred(DisplayList* displayList) { if (displayList) { DISPLAY_LIST_LOGD("Deferring display list destruction"); Caches::getInstance().deleteDisplayListDeferred(displayList); } } void DisplayList::clearResources() { sk_free((void*) mReader.base()); delete mTransformMatrix; delete mTransformCamera; delete mTransformMatrix3D; delete mStaticMatrix; delete mAnimationMatrix; mTransformMatrix = NULL; mTransformCamera = NULL; mTransformMatrix3D = NULL; mStaticMatrix = NULL; mAnimationMatrix = NULL; Caches& caches = Caches::getInstance(); for (size_t i = 0; i < mBitmapResources.size(); i++) { caches.resourceCache.decrementRefcount(mBitmapResources.itemAt(i)); } mBitmapResources.clear(); for (size_t i = 0; i < mOwnedBitmapResources.size(); i++) { SkBitmap* bitmap = mOwnedBitmapResources.itemAt(i); caches.resourceCache.decrementRefcount(bitmap); caches.resourceCache.destructor(bitmap); } mOwnedBitmapResources.clear(); for (size_t i = 0; i < mFilterResources.size(); i++) { caches.resourceCache.decrementRefcount(mFilterResources.itemAt(i)); } mFilterResources.clear(); for (size_t i = 0; i < mShaders.size(); i++) { caches.resourceCache.decrementRefcount(mShaders.itemAt(i)); caches.resourceCache.destructor(mShaders.itemAt(i)); } mShaders.clear(); for (size_t i = 0; i < mPaints.size(); i++) { delete mPaints.itemAt(i); } mPaints.clear(); for (size_t i = 0; i < mPaths.size(); i++) { SkPath* path = mPaths.itemAt(i); caches.pathCache.remove(path); delete path; } mPaths.clear(); for (size_t i = 0; i < mSourcePaths.size(); i++) { caches.resourceCache.decrementRefcount(mSourcePaths.itemAt(i)); } mSourcePaths.clear(); for (size_t i = 0; i < mMatrices.size(); i++) { delete mMatrices.itemAt(i); } mMatrices.clear(); } void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing) { const SkWriter32& writer = recorder.writeStream(); init(); if (writer.size() == 0) { return; } if (reusing) { // re-using display list - clear out previous allocations clearResources(); } initProperties(); mSize = writer.size(); void* buffer = sk_malloc_throw(mSize); writer.flatten(buffer); mReader.setMemory(buffer, mSize); Caches& caches = Caches::getInstance(); const Vector<SkBitmap*>& bitmapResources = recorder.getBitmapResources(); for (size_t i = 0; i < bitmapResources.size(); i++) { SkBitmap* resource = bitmapResources.itemAt(i); mBitmapResources.add(resource); caches.resourceCache.incrementRefcount(resource); } const Vector<SkBitmap*> &ownedBitmapResources = recorder.getOwnedBitmapResources(); for (size_t i = 0; i < ownedBitmapResources.size(); i++) { SkBitmap* resource = ownedBitmapResources.itemAt(i); mOwnedBitmapResources.add(resource); caches.resourceCache.incrementRefcount(resource); } const Vector<SkiaColorFilter*>& filterResources = recorder.getFilterResources(); for (size_t i = 0; i < filterResources.size(); i++) { SkiaColorFilter* resource = filterResources.itemAt(i); mFilterResources.add(resource); caches.resourceCache.incrementRefcount(resource); } const Vector<SkiaShader*>& shaders = recorder.getShaders(); for (size_t i = 0; i < shaders.size(); i++) { SkiaShader* resource = shaders.itemAt(i); mShaders.add(resource); caches.resourceCache.incrementRefcount(resource); } const Vector<SkPaint*>& paints = recorder.getPaints(); for (size_t i = 0; i < paints.size(); i++) { mPaints.add(paints.itemAt(i)); } const Vector<SkPath*>& paths = recorder.getPaths(); for (size_t i = 0; i < paths.size(); i++) { mPaths.add(paths.itemAt(i)); } const SortedVector<SkPath*>& sourcePaths = recorder.getSourcePaths(); for (size_t i = 0; i < sourcePaths.size(); i++) { mSourcePaths.add(sourcePaths.itemAt(i)); caches.resourceCache.incrementRefcount(sourcePaths.itemAt(i)); } const Vector<SkMatrix*>& matrices = recorder.getMatrices(); for (size_t i = 0; i < matrices.size(); i++) { mMatrices.add(matrices.itemAt(i)); } } void DisplayList::init() { mSize = 0; mIsRenderable = true; } size_t DisplayList::getSize() { return mSize; } /** * This function is a simplified version of replay(), where we simply retrieve and log the * display list. This function should remain in sync with the replay() function. */ void DisplayList::output(OpenGLRenderer& renderer, uint32_t level) { TextContainer text; uint32_t count = (level + 1) * 2; char indent[count + 1]; for (uint32_t i = 0; i < count; i++) { indent[i] = ' '; } indent[count] = '\0'; ALOGD("%sStart display list (%p, %s, render=%d)", (char*) indent + 2, this, mName.string(), isRenderable()); ALOGD("%s%s %d", indent, "Save", SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); int saveCount = renderer.getSaveCount() - 1; outputViewProperties(renderer, (char*) indent); mReader.rewind(); while (!mReader.eof()) { int op = mReader.readInt(); if (op & OP_MAY_BE_SKIPPED_MASK) { int skip = mReader.readInt(); ALOGD("%sSkip %d", (char*) indent, skip); op &= ~OP_MAY_BE_SKIPPED_MASK; } switch (op) { case DrawGLFunction: { Functor *functor = (Functor *) getInt(); ALOGD("%s%s %p", (char*) indent, OP_NAMES[op], functor); } break; case Save: { int rendererNum = getInt(); ALOGD("%s%s %d", (char*) indent, OP_NAMES[op], rendererNum); } break; case Restore: { ALOGD("%s%s", (char*) indent, OP_NAMES[op]); } break; case RestoreToCount: { int restoreCount = saveCount + getInt(); ALOGD("%s%s %d", (char*) indent, OP_NAMES[op], restoreCount); } break; case SaveLayer: { float f1 = getFloat(); float f2 = getFloat(); float f3 = getFloat(); float f4 = getFloat(); SkPaint* paint = getPaint(renderer); int flags = getInt(); ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p, 0x%x", (char*) indent, OP_NAMES[op], f1, f2, f3, f4, paint, flags); } break; case SaveLayerAlpha: { float f1 = getFloat(); float f2 = getFloat(); float f3 = getFloat(); float f4 = getFloat(); int alpha = getInt(); int flags = getInt(); ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", (char*) indent, OP_NAMES[op], f1, f2, f3, f4, alpha, flags); } break; case Translate: { float f1 = getFloat(); float f2 = getFloat(); ALOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], f1, f2); } break; case Rotate: { float rotation = getFloat(); ALOGD("%s%s %.2f", (char*) indent, OP_NAMES[op], rotation); } break; case Scale: { float sx = getFloat(); float sy = getFloat(); ALOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], sx, sy); } break; case Skew: { float sx = getFloat(); float sy = getFloat(); ALOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], sx, sy); } break; case SetMatrix: { SkMatrix* matrix = getMatrix(); ALOGD("%s%s %p", (char*) indent, OP_NAMES[op], matrix); } break; case ConcatMatrix: { SkMatrix* matrix = getMatrix(); ALOGD("%s%s new concat %p: [%f, %f, %f] [%f, %f, %f] [%f, %f, %f]", (char*) indent, OP_NAMES[op], matrix, matrix->get(0), matrix->get(1), matrix->get(2), matrix->get(3), matrix->get(4), matrix->get(5), matrix->get(6), matrix->get(7), matrix->get(8)); } break; case ClipRect: { float f1 = getFloat(); float f2 = getFloat(); float f3 = getFloat(); float f4 = getFloat(); int regionOp = getInt(); ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d", (char*) indent, OP_NAMES[op], f1, f2, f3, f4, regionOp); } break; case DrawDisplayList: { DisplayList* displayList = getDisplayList(); int32_t flags = getInt(); ALOGD("%s%s %p, %dx%d, 0x%x %d", (char*) indent, OP_NAMES[op], displayList, mWidth, mHeight, flags, level + 1); renderer.outputDisplayList(displayList, level + 1); } break; case DrawLayer: { Layer* layer = (Layer*) getInt(); float x = getFloat(); float y = getFloat(); SkPaint* paint = getPaint(renderer); ALOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op], layer, x, y, paint); } break; case DrawBitmap: { SkBitmap* bitmap = getBitmap(); float x = getFloat(); float y = getFloat(); SkPaint* paint = getPaint(renderer); ALOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op], bitmap, x, y, paint); } break; case DrawBitmapMatrix: { SkBitmap* bitmap = getBitmap(); SkMatrix* matrix = getMatrix(); SkPaint* paint = getPaint(renderer); ALOGD("%s%s %p, %p, %p", (char*) indent, OP_NAMES[op], bitmap, matrix, paint); } break; case DrawBitmapRect: { SkBitmap* bitmap = getBitmap(); float f1 = getFloat(); float f2 = getFloat(); float f3 = getFloat(); float f4 = getFloat(); float f5 = getFloat(); float f6 = getFloat(); float f7 = getFloat(); float f8 = getFloat(); SkPaint* paint = getPaint(renderer); ALOGD("%s%s %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op], bitmap, f1, f2, f3, f4, f5, f6, f7, f8, paint); } break; case DrawBitmapData: { SkBitmap* bitmap = getBitmapData(); float x = getFloat(); float y = getFloat(); SkPaint* paint = getPaint(renderer); ALOGD("%s%s %.2f, %.2f, %p", (char*) indent, OP_NAMES[op], x, y, paint); } break; case DrawBitmapMesh: { int verticesCount = 0; uint32_t colorsCount = 0; SkBitmap* bitmap = getBitmap(); uint32_t meshWidth = getInt(); uint32_t meshHeight = getInt(); float* vertices = getFloats(verticesCount); bool hasColors = getInt(); int* colors = hasColors ? getInts(colorsCount) : NULL; SkPaint* paint = getPaint(renderer); ALOGD("%s%s", (char*) indent, OP_NAMES[op]); } break; case DrawPatch: { int32_t* xDivs = NULL; int32_t* yDivs = NULL; uint32_t* colors = NULL; uint32_t xDivsCount = 0; uint32_t yDivsCount = 0; int8_t numColors = 0; SkBitmap* bitmap = getBitmap(); xDivs = getInts(xDivsCount); yDivs = getInts(yDivsCount); colors = getUInts(numColors); float left = getFloat(); float top = getFloat(); float right = getFloat(); float bottom = getFloat(); SkPaint* paint = getPaint(renderer); ALOGD("%s%s %.2f, %.2f, %.2f, %.2f", (char*) indent, OP_NAMES[op], left, top, right, bottom); } break; case DrawColor: { int color = getInt(); int xferMode = getInt(); ALOGD("%s%s 0x%x %d", (char*) indent, OP_NAMES[op], color, xferMode); } break; case DrawRect: { float f1 = getFloat(); float f2 = getFloat(); float f3 = getFloat(); float f4 = getFloat(); SkPaint* paint = getPaint(renderer); ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op], f1, f2, f3, f4, paint); } break; case DrawRoundRect: { float f1 = getFloat(); float f2 = getFloat(); float f3 = getFloat(); float f4 = getFloat(); float f5 = getFloat(); float f6 = getFloat(); SkPaint* paint = getPaint(renderer); ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, paint); } break; case DrawCircle: { float f1 = getFloat(); float f2 = getFloat(); float f3 = getFloat(); SkPaint* paint = getPaint(renderer); ALOGD("%s%s %.2f, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op], f1, f2, f3, paint); } break; case DrawOval: { float f1 = getFloat(); float f2 = getFloat(); float f3 = getFloat(); float f4 = getFloat(); SkPaint* paint = getPaint(renderer); ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op], f1, f2, f3, f4, paint); } break; case DrawArc: { float f1 = getFloat(); float f2 = getFloat(); float f3 = getFloat(); float f4 = getFloat(); float f5 = getFloat(); float f6 = getFloat(); int i1 = getInt(); SkPaint* paint = getPaint(renderer); ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %d, %p", (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, i1, paint); } break; case DrawPath: { SkPath* path = getPath(); SkPaint* paint = getPaint(renderer); ALOGD("%s%s %p, %p", (char*) indent, OP_NAMES[op], path, paint); } break; case DrawLines: { int count = 0; float* points = getFloats(count); SkPaint* paint = getPaint(renderer); ALOGD("%s%s", (char*) indent, OP_NAMES[op]); } break; case DrawPoints: { int count = 0; float* points = getFloats(count); SkPaint* paint = getPaint(renderer); ALOGD("%s%s", (char*) indent, OP_NAMES[op]); } break; case DrawText: { getText(&text); int32_t count = getInt(); float x = getFloat(); float y = getFloat(); SkPaint* paint = getPaint(renderer); float length = getFloat(); ALOGD("%s%s %s, %d, %d, %.2f, %.2f, %p, %.2f", (char*) indent, OP_NAMES[op], text.text(), text.length(), count, x, y, paint, length); } break; case DrawTextOnPath: { getText(&text); int32_t count = getInt(); SkPath* path = getPath(); float hOffset = getFloat(); float vOffset = getFloat(); SkPaint* paint = getPaint(renderer); ALOGD("%s%s %s, %d, %d, %p", (char*) indent, OP_NAMES[op], text.text(), text.length(), count, paint); } break; case DrawPosText: { getText(&text); int count = getInt(); int positionsCount = 0; float* positions = getFloats(positionsCount); SkPaint* paint = getPaint(renderer); ALOGD("%s%s %s, %d, %d, %p", (char*) indent, OP_NAMES[op], text.text(), text.length(), count, paint); } case ResetShader: { ALOGD("%s%s", (char*) indent, OP_NAMES[op]); } break; case SetupShader: { SkiaShader* shader = getShader(); ALOGD("%s%s %p", (char*) indent, OP_NAMES[op], shader); } break; case ResetColorFilter: { ALOGD("%s%s", (char*) indent, OP_NAMES[op]); } break; case SetupColorFilter: { SkiaColorFilter *colorFilter = getColorFilter(); ALOGD("%s%s %p", (char*) indent, OP_NAMES[op], colorFilter); } break; case ResetShadow: { ALOGD("%s%s", (char*) indent, OP_NAMES[op]); } break; case SetupShadow: { float radius = getFloat(); float dx = getFloat(); float dy = getFloat(); int color = getInt(); ALOGD("%s%s %.2f, %.2f, %.2f, 0x%x", (char*) indent, OP_NAMES[op], radius, dx, dy, color); } break; case ResetPaintFilter: { ALOGD("%s%s", (char*) indent, OP_NAMES[op]); } break; case SetupPaintFilter: { int clearBits = getInt(); int setBits = getInt(); ALOGD("%s%s 0x%x, 0x%x", (char*) indent, OP_NAMES[op], clearBits, setBits); } break; default: ALOGD("Display List error: op not handled: %s%s", (char*) indent, OP_NAMES[op]); break; } } ALOGD("%sDone (%p, %s)", (char*) indent + 2, this, mName.string()); } void DisplayList::updateMatrix() { if (mMatrixDirty) { if (!mTransformMatrix) { mTransformMatrix = new SkMatrix(); } if (mMatrixFlags == 0 || mMatrixFlags == TRANSLATION) { mTransformMatrix->reset(); } else { if (!mPivotExplicitlySet) { if (mWidth != mPrevWidth || mHeight != mPrevHeight) { mPrevWidth = mWidth; mPrevHeight = mHeight; mPivotX = mPrevWidth / 2; mPivotY = mPrevHeight / 2; } } if ((mMatrixFlags & ROTATION_3D) == 0) { mTransformMatrix->setTranslate(mTranslationX, mTranslationY); mTransformMatrix->preRotate(mRotation, mPivotX, mPivotY); mTransformMatrix->preScale(mScaleX, mScaleY, mPivotX, mPivotY); } else { if (!mTransformCamera) { mTransformCamera = new Sk3DView(); mTransformMatrix3D = new SkMatrix(); } mTransformMatrix->reset(); mTransformCamera->save(); mTransformMatrix->preScale(mScaleX, mScaleY, mPivotX, mPivotY); mTransformCamera->rotateX(mRotationX); mTransformCamera->rotateY(mRotationY); mTransformCamera->rotateZ(-mRotation); mTransformCamera->getMatrix(mTransformMatrix3D); mTransformMatrix3D->preTranslate(-mPivotX, -mPivotY); mTransformMatrix3D->postTranslate(mPivotX + mTranslationX, mPivotY + mTranslationY); mTransformMatrix->postConcat(*mTransformMatrix3D); mTransformCamera->restore(); } } mMatrixDirty = false; } } void DisplayList::outputViewProperties(OpenGLRenderer& renderer, char* indent) { updateMatrix(); if (mLeft != 0 || mTop != 0) { ALOGD("%s%s %d, %d", indent, "Translate (left, top)", mLeft, mTop); } if (mStaticMatrix) { ALOGD("%s%s %p: [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f]", indent, "ConcatMatrix (static)", mStaticMatrix, mStaticMatrix->get(0), mStaticMatrix->get(1), mStaticMatrix->get(2), mStaticMatrix->get(3), mStaticMatrix->get(4), mStaticMatrix->get(5), mStaticMatrix->get(6), mStaticMatrix->get(7), mStaticMatrix->get(8)); } if (mAnimationMatrix) { ALOGD("%s%s %p: [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f]", indent, "ConcatMatrix (animation)", mAnimationMatrix, mAnimationMatrix->get(0), mAnimationMatrix->get(1), mAnimationMatrix->get(2), mAnimationMatrix->get(3), mAnimationMatrix->get(4), mAnimationMatrix->get(5), mAnimationMatrix->get(6), mAnimationMatrix->get(7), mAnimationMatrix->get(8)); } if (mMatrixFlags != 0) { if (mMatrixFlags == TRANSLATION) { ALOGD("%s%s %f, %f", indent, "Translate", mTranslationX, mTranslationY); } else { ALOGD("%s%s %p: [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f]", indent, "ConcatMatrix", mTransformMatrix, mTransformMatrix->get(0), mTransformMatrix->get(1), mTransformMatrix->get(2), mTransformMatrix->get(3), mTransformMatrix->get(4), mTransformMatrix->get(5), mTransformMatrix->get(6), mTransformMatrix->get(7), mTransformMatrix->get(8)); } } if (mAlpha < 1 && !mCaching) { // TODO: should be able to store the size of a DL at record time and not // have to pass it into this call. In fact, this information might be in the // location/size info that we store with the new native transform data. int flags = SkCanvas::kHasAlphaLayer_SaveFlag; if (mClipChildren) { flags |= SkCanvas::kClipToLayer_SaveFlag; } ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", indent, "SaveLayerAlpha", (float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop, mMultipliedAlpha, flags); } if (mClipChildren) { ALOGD("%s%s %.2f, %.2f, %.2f, %.2f", indent, "ClipRect", 0.0f, 0.0f, (float) mRight - mLeft, (float) mBottom - mTop); } } void DisplayList::setViewProperties(OpenGLRenderer& renderer, uint32_t level) { #if DEBUG_DISPLAY_LIST uint32_t count = (level + 1) * 2; char indent[count + 1]; for (uint32_t i = 0; i < count; i++) { indent[i] = ' '; } indent[count] = '\0'; #endif updateMatrix(); if (mLeft != 0 || mTop != 0) { DISPLAY_LIST_LOGD("%s%s %d, %d", indent, "Translate (left, top)", mLeft, mTop); renderer.translate(mLeft, mTop); } if (mStaticMatrix) { DISPLAY_LIST_LOGD( "%s%s %p: [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f]", indent, "ConcatMatrix (static)", mStaticMatrix, mStaticMatrix->get(0), mStaticMatrix->get(1), mStaticMatrix->get(2), mStaticMatrix->get(3), mStaticMatrix->get(4), mStaticMatrix->get(5), mStaticMatrix->get(6), mStaticMatrix->get(7), mStaticMatrix->get(8)); renderer.concatMatrix(mStaticMatrix); } else if (mAnimationMatrix) { DISPLAY_LIST_LOGD( "%s%s %p: [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f]", indent, "ConcatMatrix (animation)", mAnimationMatrix, mAnimationMatrix->get(0), mAnimationMatrix->get(1), mAnimationMatrix->get(2), mAnimationMatrix->get(3), mAnimationMatrix->get(4), mAnimationMatrix->get(5), mAnimationMatrix->get(6), mAnimationMatrix->get(7), mAnimationMatrix->get(8)); renderer.concatMatrix(mAnimationMatrix); } if (mMatrixFlags != 0) { if (mMatrixFlags == TRANSLATION) { DISPLAY_LIST_LOGD("%s%s %f, %f", indent, "Translate", mTranslationX, mTranslationY); renderer.translate(mTranslationX, mTranslationY); } else { DISPLAY_LIST_LOGD( "%s%s %p: [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f]", indent, "ConcatMatrix", mTransformMatrix, mTransformMatrix->get(0), mTransformMatrix->get(1), mTransformMatrix->get(2), mTransformMatrix->get(3), mTransformMatrix->get(4), mTransformMatrix->get(5), mTransformMatrix->get(6), mTransformMatrix->get(7), mTransformMatrix->get(8)); renderer.concatMatrix(mTransformMatrix); } } if (mAlpha < 1 && !mCaching) { if (!mHasOverlappingRendering) { DISPLAY_LIST_LOGD("%s%s %.2f", indent, "SetAlpha", mAlpha); renderer.setAlpha(mAlpha); } else { // TODO: should be able to store the size of a DL at record time and not // have to pass it into this call. In fact, this information might be in the // location/size info that we store with the new native transform data. int flags = SkCanvas::kHasAlphaLayer_SaveFlag; if (mClipChildren) { flags |= SkCanvas::kClipToLayer_SaveFlag; } DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", indent, "SaveLayerAlpha", (float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop, mMultipliedAlpha, flags); renderer.saveLayerAlpha(0, 0, mRight - mLeft, mBottom - mTop, mMultipliedAlpha, flags); } } if (mClipChildren) { DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f", indent, "ClipRect", 0.0f, 0.0f, (float) mRight - mLeft, (float) mBottom - mTop); renderer.clipRect(0, 0, mRight - mLeft, mBottom - mTop, SkRegion::kIntersect_Op); } } /** * Changes to replay(), specifically those involving opcode or parameter changes, should be mimicked * in the output() function, since that function processes the same list of opcodes for the * purposes of logging display list info for a given view. */ status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level) { status_t drawGlStatus = DrawGlInfo::kStatusDone; TextContainer text; mReader.rewind(); #if DEBUG_DISPLAY_LIST uint32_t count = (level + 1) * 2; char indent[count + 1]; for (uint32_t i = 0; i < count; i++) { indent[i] = ' '; } indent[count] = '\0'; Rect* clipRect = renderer.getClipRect(); DISPLAY_LIST_LOGD("%sStart display list (%p, %s), clipRect: %.0f, %.f, %.0f, %.0f", (char*) indent + 2, this, mName.string(), clipRect->left, clipRect->top, clipRect->right, clipRect->bottom); #endif renderer.startMark(mName.string()); int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); DISPLAY_LIST_LOGD("%s%s %d %d", indent, "Save", SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo); setViewProperties(renderer, level); if (renderer.quickReject(0, 0, mWidth, mHeight)) { DISPLAY_LIST_LOGD("%s%s %d", (char*) indent, "RestoreToCount", restoreTo); renderer.restoreToCount(restoreTo); renderer.endMark(); return drawGlStatus; } DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance(); int saveCount = renderer.getSaveCount() - 1; while (!mReader.eof()) { int op = mReader.readInt(); if (op & OP_MAY_BE_SKIPPED_MASK) { int32_t skip = mReader.readInt(); if (CC_LIKELY(flags & kReplayFlag_ClipChildren)) { mReader.skip(skip); DISPLAY_LIST_LOGD("%s%s skipping %d bytes", (char*) indent, OP_NAMES[op & ~OP_MAY_BE_SKIPPED_MASK], skip); continue; } else { op &= ~OP_MAY_BE_SKIPPED_MASK; } } logBuffer.writeCommand(level, op); switch (op) { case DrawGLFunction: { Functor *functor = (Functor *) getInt(); DISPLAY_LIST_LOGD("%s%s %p", (char*) indent, OP_NAMES[op], functor); renderer.startMark("GL functor"); drawGlStatus |= renderer.callDrawGLFunction(functor, dirty); renderer.endMark(); } break; case Save: { int32_t rendererNum = getInt(); DISPLAY_LIST_LOGD("%s%s %d", (char*) indent, OP_NAMES[op], rendererNum); renderer.save(rendererNum); } break; case Restore: { DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); renderer.restore(); } break; case RestoreToCount: { int32_t restoreCount = saveCount + getInt(); DISPLAY_LIST_LOGD("%s%s %d", (char*) indent, OP_NAMES[op], restoreCount); renderer.restoreToCount(restoreCount); } break; case SaveLayer: { float f1 = getFloat(); float f2 = getFloat(); float f3 = getFloat(); float f4 = getFloat(); SkPaint* paint = getPaint(renderer); int32_t flags = getInt(); DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p, 0x%x", (char*) indent, OP_NAMES[op], f1, f2, f3, f4, paint, flags); renderer.saveLayer(f1, f2, f3, f4, paint, flags); } break; case SaveLayerAlpha: { float f1 = getFloat(); float f2 = getFloat(); float f3 = getFloat(); float f4 = getFloat(); int32_t alpha = getInt(); int32_t flags = getInt(); DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", (char*) indent, OP_NAMES[op], f1, f2, f3, f4, alpha, flags); renderer.saveLayerAlpha(f1, f2, f3, f4, alpha, flags); } break; case Translate: { float f1 = getFloat(); float f2 = getFloat(); DISPLAY_LIST_LOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], f1, f2); renderer.translate(f1, f2); } break; case Rotate: { float rotation = getFloat(); DISPLAY_LIST_LOGD("%s%s %.2f", (char*) indent, OP_NAMES[op], rotation); renderer.rotate(rotation); } break; case Scale: { float sx = getFloat(); float sy = getFloat(); DISPLAY_LIST_LOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], sx, sy); renderer.scale(sx, sy); } break; case Skew: { float sx = getFloat(); float sy = getFloat(); DISPLAY_LIST_LOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], sx, sy); renderer.skew(sx, sy); } break; case SetMatrix: { SkMatrix* matrix = getMatrix(); DISPLAY_LIST_LOGD("%s%s %p", (char*) indent, OP_NAMES[op], matrix); renderer.setMatrix(matrix); } break; case ConcatMatrix: { SkMatrix* matrix = getMatrix(); DISPLAY_LIST_LOGD( "%s%s %p: [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f]", (char*) indent, OP_NAMES[op], matrix, matrix->get(0), matrix->get(1), matrix->get(2), matrix->get(3), matrix->get(4), matrix->get(5), matrix->get(6), matrix->get(7), matrix->get(8)); renderer.concatMatrix(matrix); } break; case ClipRect: { float f1 = getFloat(); float f2 = getFloat(); float f3 = getFloat(); float f4 = getFloat(); int32_t regionOp = getInt(); DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d", (char*) indent, OP_NAMES[op], f1, f2, f3, f4, regionOp); renderer.clipRect(f1, f2, f3, f4, (SkRegion::Op) regionOp); } break; case DrawDisplayList: { DisplayList* displayList = getDisplayList(); int32_t flags = getInt(); DISPLAY_LIST_LOGD("%s%s %p, %dx%d, 0x%x %d", (char*) indent, OP_NAMES[op], displayList, mWidth, mHeight, flags, level + 1); drawGlStatus |= renderer.drawDisplayList(displayList, dirty, flags, level + 1); } break; case DrawLayer: { Layer* layer = (Layer*) getInt(); float x = getFloat(); float y = getFloat(); SkPaint* paint = getPaint(renderer); if (mCaching) { paint->setAlpha(mMultipliedAlpha); } DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op], layer, x, y, paint); drawGlStatus |= renderer.drawLayer(layer, x, y, paint); } break; case DrawBitmap: { SkBitmap* bitmap = getBitmap(); float x = getFloat(); float y = getFloat(); SkPaint* paint = getPaint(renderer); if (mCaching) { paint->setAlpha(mMultipliedAlpha); } DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op], bitmap, x, y, paint); drawGlStatus |= renderer.drawBitmap(bitmap, x, y, paint); } break; case DrawBitmapMatrix: { SkBitmap* bitmap = getBitmap(); SkMatrix* matrix = getMatrix(); SkPaint* paint = getPaint(renderer); DISPLAY_LIST_LOGD("%s%s %p, %p, %p", (char*) indent, OP_NAMES[op], bitmap, matrix, paint); drawGlStatus |= renderer.drawBitmap(bitmap, matrix, paint); } break; case DrawBitmapRect: { SkBitmap* bitmap = getBitmap(); float f1 = getFloat(); float f2 = getFloat(); float f3 = getFloat(); float f4 = getFloat(); float f5 = getFloat(); float f6 = getFloat(); float f7 = getFloat(); float f8 = getFloat(); SkPaint* paint = getPaint(renderer); DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op], bitmap, f1, f2, f3, f4, f5, f6, f7, f8,paint); drawGlStatus |= renderer.drawBitmap(bitmap, f1, f2, f3, f4, f5, f6, f7, f8, paint); } break; case DrawBitmapData: { SkBitmap* bitmap = getBitmapData(); float x = getFloat(); float y = getFloat(); SkPaint* paint = getPaint(renderer); DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op], bitmap, x, y, paint); drawGlStatus |= renderer.drawBitmap(bitmap, x, y, paint); } break; case DrawBitmapMesh: { int32_t verticesCount = 0; uint32_t colorsCount = 0; SkBitmap* bitmap = getBitmap(); uint32_t meshWidth = getInt(); uint32_t meshHeight = getInt(); float* vertices = getFloats(verticesCount); bool hasColors = getInt(); int32_t* colors = hasColors ? getInts(colorsCount) : NULL; SkPaint* paint = getPaint(renderer); DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); drawGlStatus |= renderer.drawBitmapMesh(bitmap, meshWidth, meshHeight, vertices, colors, paint); } break; case DrawPatch: { int32_t* xDivs = NULL; int32_t* yDivs = NULL; uint32_t* colors = NULL; uint32_t xDivsCount = 0; uint32_t yDivsCount = 0; int8_t numColors = 0; SkBitmap* bitmap = getBitmap(); xDivs = getInts(xDivsCount); yDivs = getInts(yDivsCount); colors = getUInts(numColors); float left = getFloat(); float top = getFloat(); float right = getFloat(); float bottom = getFloat(); SkPaint* paint = getPaint(renderer); DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); drawGlStatus |= renderer.drawPatch(bitmap, xDivs, yDivs, colors, xDivsCount, yDivsCount, numColors, left, top, right, bottom, paint); } break; case DrawColor: { int32_t color = getInt(); int32_t xferMode = getInt(); DISPLAY_LIST_LOGD("%s%s 0x%x %d", (char*) indent, OP_NAMES[op], color, xferMode); drawGlStatus |= renderer.drawColor(color, (SkXfermode::Mode) xferMode); } break; case DrawRect: { float f1 = getFloat(); float f2 = getFloat(); float f3 = getFloat(); float f4 = getFloat(); SkPaint* paint = getPaint(renderer); DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op], f1, f2, f3, f4, paint); drawGlStatus |= renderer.drawRect(f1, f2, f3, f4, paint); } break; case DrawRoundRect: { float f1 = getFloat(); float f2 = getFloat(); float f3 = getFloat(); float f4 = getFloat(); float f5 = getFloat(); float f6 = getFloat(); SkPaint* paint = getPaint(renderer); DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, paint); drawGlStatus |= renderer.drawRoundRect(f1, f2, f3, f4, f5, f6, paint); } break; case DrawCircle: { float f1 = getFloat(); float f2 = getFloat(); float f3 = getFloat(); SkPaint* paint = getPaint(renderer); DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op], f1, f2, f3, paint); drawGlStatus |= renderer.drawCircle(f1, f2, f3, paint); } break; case DrawOval: { float f1 = getFloat(); float f2 = getFloat(); float f3 = getFloat(); float f4 = getFloat(); SkPaint* paint = getPaint(renderer); DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op], f1, f2, f3, f4, paint); drawGlStatus |= renderer.drawOval(f1, f2, f3, f4, paint); } break; case DrawArc: { float f1 = getFloat(); float f2 = getFloat(); float f3 = getFloat(); float f4 = getFloat(); float f5 = getFloat(); float f6 = getFloat(); int32_t i1 = getInt(); SkPaint* paint = getPaint(renderer); DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %d, %p", (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, i1, paint); drawGlStatus |= renderer.drawArc(f1, f2, f3, f4, f5, f6, i1 == 1, paint); } break; case DrawPath: { SkPath* path = getPath(); SkPaint* paint = getPaint(renderer); DISPLAY_LIST_LOGD("%s%s %p, %p", (char*) indent, OP_NAMES[op], path, paint); drawGlStatus |= renderer.drawPath(path, paint); } break; case DrawLines: { int32_t count = 0; float* points = getFloats(count); SkPaint* paint = getPaint(renderer); DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); drawGlStatus |= renderer.drawLines(points, count, paint); } break; case DrawPoints: { int32_t count = 0; float* points = getFloats(count); SkPaint* paint = getPaint(renderer); DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); drawGlStatus |= renderer.drawPoints(points, count, paint); } break; case DrawText: { getText(&text); int32_t count = getInt(); float x = getFloat(); float y = getFloat(); SkPaint* paint = getPaint(renderer); float length = getFloat(); DISPLAY_LIST_LOGD("%s%s %s, %d, %d, %.2f, %.2f, %p, %.2f", (char*) indent, OP_NAMES[op], text.text(), text.length(), count, x, y, paint, length); drawGlStatus |= renderer.drawText(text.text(), text.length(), count, x, y, paint, length); } break; case DrawTextOnPath: { getText(&text); int32_t count = getInt(); SkPath* path = getPath(); float hOffset = getFloat(); float vOffset = getFloat(); SkPaint* paint = getPaint(renderer); DISPLAY_LIST_LOGD("%s%s %s, %d, %d, %p", (char*) indent, OP_NAMES[op], text.text(), text.length(), count, paint); drawGlStatus |= renderer.drawTextOnPath(text.text(), text.length(), count, path, hOffset, vOffset, paint); } break; case DrawPosText: { getText(&text); int32_t count = getInt(); int32_t positionsCount = 0; float* positions = getFloats(positionsCount); SkPaint* paint = getPaint(renderer); DISPLAY_LIST_LOGD("%s%s %s, %d, %d, %p", (char*) indent, OP_NAMES[op], text.text(), text.length(), count, paint); drawGlStatus |= renderer.drawPosText(text.text(), text.length(), count, positions, paint); } break; case ResetShader: { DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); renderer.resetShader(); } break; case SetupShader: { SkiaShader* shader = getShader(); DISPLAY_LIST_LOGD("%s%s %p", (char*) indent, OP_NAMES[op], shader); renderer.setupShader(shader); } break; case ResetColorFilter: { DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); renderer.resetColorFilter(); } break; case SetupColorFilter: { SkiaColorFilter *colorFilter = getColorFilter(); DISPLAY_LIST_LOGD("%s%s %p", (char*) indent, OP_NAMES[op], colorFilter); renderer.setupColorFilter(colorFilter); } break; case ResetShadow: { DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); renderer.resetShadow(); } break; case SetupShadow: { float radius = getFloat(); float dx = getFloat(); float dy = getFloat(); int32_t color = getInt(); DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, 0x%x", (char*) indent, OP_NAMES[op], radius, dx, dy, color); renderer.setupShadow(radius, dx, dy, color); } break; case ResetPaintFilter: { DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); renderer.resetPaintFilter(); } break; case SetupPaintFilter: { int32_t clearBits = getInt(); int32_t setBits = getInt(); DISPLAY_LIST_LOGD("%s%s 0x%x, 0x%x", (char*) indent, OP_NAMES[op], clearBits, setBits); renderer.setupPaintFilter(clearBits, setBits); } break; default: DISPLAY_LIST_LOGD("Display List error: op not handled: %s%s", (char*) indent, OP_NAMES[op]); break; } } DISPLAY_LIST_LOGD("%s%s %d", (char*) indent, "RestoreToCount", restoreTo); renderer.restoreToCount(restoreTo); renderer.endMark(); DISPLAY_LIST_LOGD("%sDone (%p, %s), returning %d", (char*) indent + 2, this, mName.string(), drawGlStatus); return drawGlStatus; } /////////////////////////////////////////////////////////////////////////////// // Base structure /////////////////////////////////////////////////////////////////////////////// DisplayListRenderer::DisplayListRenderer() : mWriter(MIN_WRITER_SIZE), mTranslateX(0.0f), mTranslateY(0.0f), mHasTranslate(false), mHasDrawOps(false) { } DisplayListRenderer::~DisplayListRenderer() { reset(); } void DisplayListRenderer::reset() { mWriter.reset(); Caches& caches = Caches::getInstance(); for (size_t i = 0; i < mBitmapResources.size(); i++) { caches.resourceCache.decrementRefcount(mBitmapResources.itemAt(i)); } mBitmapResources.clear(); for (size_t i = 0; i < mOwnedBitmapResources.size(); i++) { SkBitmap* bitmap = mOwnedBitmapResources.itemAt(i); caches.resourceCache.decrementRefcount(bitmap); } mOwnedBitmapResources.clear(); for (size_t i = 0; i < mFilterResources.size(); i++) { caches.resourceCache.decrementRefcount(mFilterResources.itemAt(i)); } mFilterResources.clear(); for (size_t i = 0; i < mShaders.size(); i++) { caches.resourceCache.decrementRefcount(mShaders.itemAt(i)); } mShaders.clear(); mShaderMap.clear(); for (size_t i = 0; i < mSourcePaths.size(); i++) { caches.resourceCache.decrementRefcount(mSourcePaths.itemAt(i)); } mSourcePaths.clear(); mPaints.clear(); mPaintMap.clear(); mPaths.clear(); mPathMap.clear(); mMatrices.clear(); mHasDrawOps = false; } /////////////////////////////////////////////////////////////////////////////// // Operations /////////////////////////////////////////////////////////////////////////////// DisplayList* DisplayListRenderer::getDisplayList(DisplayList* displayList) { if (!displayList) { displayList = new DisplayList(*this); } else { displayList->initFromDisplayListRenderer(*this, true); } displayList->setRenderable(mHasDrawOps); return displayList; } bool DisplayListRenderer::isDeferred() { return true; } void DisplayListRenderer::setViewport(int width, int height) { mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1); mWidth = width; mHeight = height; } int DisplayListRenderer::prepareDirty(float left, float top, float right, float bottom, bool opaque) { mSnapshot = new Snapshot(mFirstSnapshot, SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); mSaveCount = 1; mSnapshot->setClip(0.0f, 0.0f, mWidth, mHeight); mRestoreSaveCount = -1; return DrawGlInfo::kStatusDone; // No invalidate needed at record-time } void DisplayListRenderer::finish() { insertRestoreToCount(); insertTranlate(); } void DisplayListRenderer::interrupt() { } void DisplayListRenderer::resume() { } status_t DisplayListRenderer::callDrawGLFunction(Functor *functor, Rect& dirty) { // Ignore dirty during recording, it matters only when we replay addOp(DisplayList::DrawGLFunction); addInt((int) functor); return DrawGlInfo::kStatusDone; // No invalidate needed at record-time } int DisplayListRenderer::save(int flags) { addOp(DisplayList::Save); addInt(flags); return OpenGLRenderer::save(flags); } void DisplayListRenderer::restore() { if (mRestoreSaveCount < 0) { restoreToCount(getSaveCount() - 1); return; } mRestoreSaveCount--; insertTranlate(); OpenGLRenderer::restore(); } void DisplayListRenderer::restoreToCount(int saveCount) { mRestoreSaveCount = saveCount; insertTranlate(); OpenGLRenderer::restoreToCount(saveCount); } int DisplayListRenderer::saveLayer(float left, float top, float right, float bottom, SkPaint* p, int flags) { addOp(DisplayList::SaveLayer); addBounds(left, top, right, bottom); addPaint(p); addInt(flags); return OpenGLRenderer::save(flags); } int DisplayListRenderer::saveLayerAlpha(float left, float top, float right, float bottom, int alpha, int flags) { addOp(DisplayList::SaveLayerAlpha); addBounds(left, top, right, bottom); addInt(alpha); addInt(flags); return OpenGLRenderer::save(flags); } void DisplayListRenderer::translate(float dx, float dy) { mHasTranslate = true; mTranslateX += dx; mTranslateY += dy; insertRestoreToCount(); OpenGLRenderer::translate(dx, dy); } void DisplayListRenderer::rotate(float degrees) { addOp(DisplayList::Rotate); addFloat(degrees); OpenGLRenderer::rotate(degrees); } void DisplayListRenderer::scale(float sx, float sy) { addOp(DisplayList::Scale); addPoint(sx, sy); OpenGLRenderer::scale(sx, sy); } void DisplayListRenderer::skew(float sx, float sy) { addOp(DisplayList::Skew); addPoint(sx, sy); OpenGLRenderer::skew(sx, sy); } void DisplayListRenderer::setMatrix(SkMatrix* matrix) { addOp(DisplayList::SetMatrix); addMatrix(matrix); OpenGLRenderer::setMatrix(matrix); } void DisplayListRenderer::concatMatrix(SkMatrix* matrix) { addOp(DisplayList::ConcatMatrix); addMatrix(matrix); OpenGLRenderer::concatMatrix(matrix); } bool DisplayListRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) { addOp(DisplayList::ClipRect); addBounds(left, top, right, bottom); addInt(op); return OpenGLRenderer::clipRect(left, top, right, bottom, op); } status_t DisplayListRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t flags, uint32_t level) { // dirty is an out parameter and should not be recorded, // it matters only when replaying the display list addOp(DisplayList::DrawDisplayList); addDisplayList(displayList); addInt(flags); return DrawGlInfo::kStatusDone; } status_t DisplayListRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) { addOp(DisplayList::DrawLayer); addInt((int) layer); addPoint(x, y); addPaint(paint); return DrawGlInfo::kStatusDone; } status_t DisplayListRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint) { const bool reject = quickReject(left, top, left + bitmap->width(), top + bitmap->height()); uint32_t* location = addOp(DisplayList::DrawBitmap, reject); addBitmap(bitmap); addPoint(left, top); addPaint(paint); addSkip(location); return DrawGlInfo::kStatusDone; } status_t DisplayListRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint) { Rect r(0.0f, 0.0f, bitmap->width(), bitmap->height()); const mat4 transform(*matrix); transform.mapRect(r); const bool reject = quickReject(r.left, r.top, r.right, r.bottom); uint32_t* location = addOp(DisplayList::DrawBitmapMatrix, reject); addBitmap(bitmap); addMatrix(matrix); addPaint(paint); addSkip(location); return DrawGlInfo::kStatusDone; } status_t DisplayListRenderer::drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop, float srcRight, float srcBottom, float dstLeft, float dstTop, float dstRight, float dstBottom, SkPaint* paint) { const bool reject = quickReject(dstLeft, dstTop, dstRight, dstBottom); uint32_t* location = addOp(DisplayList::DrawBitmapRect, reject); addBitmap(bitmap); addBounds(srcLeft, srcTop, srcRight, srcBottom); addBounds(dstLeft, dstTop, dstRight, dstBottom); addPaint(paint); addSkip(location); return DrawGlInfo::kStatusDone; } status_t DisplayListRenderer::drawBitmapData(SkBitmap* bitmap, float left, float top, SkPaint* paint) { const bool reject = quickReject(left, top, left + bitmap->width(), bitmap->height()); uint32_t* location = addOp(DisplayList::DrawBitmapData, reject); addBitmapData(bitmap); addPoint(left, top); addPaint(paint); addSkip(location); return DrawGlInfo::kStatusDone; } status_t DisplayListRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHeight, float* vertices, int* colors, SkPaint* paint) { addOp(DisplayList::DrawBitmapMesh); addBitmap(bitmap); addInt(meshWidth); addInt(meshHeight); addFloats(vertices, (meshWidth + 1) * (meshHeight + 1) * 2); if (colors) { addInt(1); addInts(colors, (meshWidth + 1) * (meshHeight + 1)); } else { addInt(0); } addPaint(paint); return DrawGlInfo::kStatusDone; } status_t DisplayListRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs, const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors, float left, float top, float right, float bottom, SkPaint* paint) { const bool reject = quickReject(left, top, right, bottom); uint32_t* location = addOp(DisplayList::DrawPatch, reject); addBitmap(bitmap); addInts(xDivs, width); addInts(yDivs, height); addUInts(colors, numColors); addBounds(left, top, right, bottom); addPaint(paint); addSkip(location); return DrawGlInfo::kStatusDone; } status_t DisplayListRenderer::drawColor(int color, SkXfermode::Mode mode) { addOp(DisplayList::DrawColor); addInt(color); addInt(mode); return DrawGlInfo::kStatusDone; } status_t DisplayListRenderer::drawRect(float left, float top, float right, float bottom, SkPaint* paint) { const bool reject = paint->getStyle() == SkPaint::kFill_Style && quickReject(left, top, right, bottom); uint32_t* location = addOp(DisplayList::DrawRect, reject); addBounds(left, top, right, bottom); addPaint(paint); addSkip(location); return DrawGlInfo::kStatusDone; } status_t DisplayListRenderer::drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, SkPaint* paint) { const bool reject = paint->getStyle() == SkPaint::kFill_Style && quickReject(left, top, right, bottom); uint32_t* location = addOp(DisplayList::DrawRoundRect, reject); addBounds(left, top, right, bottom); addPoint(rx, ry); addPaint(paint); addSkip(location); return DrawGlInfo::kStatusDone; } status_t DisplayListRenderer::drawCircle(float x, float y, float radius, SkPaint* paint) { addOp(DisplayList::DrawCircle); addPoint(x, y); addFloat(radius); addPaint(paint); return DrawGlInfo::kStatusDone; } status_t DisplayListRenderer::drawOval(float left, float top, float right, float bottom, SkPaint* paint) { addOp(DisplayList::DrawOval); addBounds(left, top, right, bottom); addPaint(paint); return DrawGlInfo::kStatusDone; } status_t DisplayListRenderer::drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, bool useCenter, SkPaint* paint) { addOp(DisplayList::DrawArc); addBounds(left, top, right, bottom); addPoint(startAngle, sweepAngle); addInt(useCenter ? 1 : 0); addPaint(paint); return DrawGlInfo::kStatusDone; } status_t DisplayListRenderer::drawPath(SkPath* path, SkPaint* paint) { float left, top, offset; uint32_t width, height; computePathBounds(path, paint, left, top, offset, width, height); const bool reject = quickReject(left - offset, top - offset, width, height); uint32_t* location = addOp(DisplayList::DrawPath, reject); addPath(path); addPaint(paint); addSkip(location); return DrawGlInfo::kStatusDone; } status_t DisplayListRenderer::drawLines(float* points, int count, SkPaint* paint) { addOp(DisplayList::DrawLines); addFloats(points, count); addPaint(paint); return DrawGlInfo::kStatusDone; } status_t DisplayListRenderer::drawPoints(float* points, int count, SkPaint* paint) { addOp(DisplayList::DrawPoints); addFloats(points, count); addPaint(paint); return DrawGlInfo::kStatusDone; } status_t DisplayListRenderer::drawText(const char* text, int bytesCount, int count, float x, float y, SkPaint* paint, float length) { if (!text || count <= 0) return DrawGlInfo::kStatusDone; // TODO: We should probably make a copy of the paint instead of modifying // it; modifying the paint will change its generationID the first // time, which might impact caches. More investigation needed to // see if it matters. // If we make a copy, then drawTextDecorations() should *not* make // its own copy as it does right now. // Beware: this needs Glyph encoding (already done on the Paint constructor) paint->setAntiAlias(true); if (length < 0.0f) length = paint->measureText(text, bytesCount); bool reject = false; if (CC_LIKELY(paint->getTextAlign() == SkPaint::kLeft_Align)) { SkPaint::FontMetrics metrics; paint->getFontMetrics(&metrics, 0.0f); reject = quickReject(x, y + metrics.fTop, x + length, y + metrics.fBottom); } uint32_t* location = addOp(DisplayList::DrawText, reject); addText(text, bytesCount); addInt(count); addPoint(x, y); addPaint(paint); addFloat(length); addSkip(location); return DrawGlInfo::kStatusDone; } status_t DisplayListRenderer::drawTextOnPath(const char* text, int bytesCount, int count, SkPath* path, float hOffset, float vOffset, SkPaint* paint) { if (!text || count <= 0) return DrawGlInfo::kStatusDone; addOp(DisplayList::DrawTextOnPath); addText(text, bytesCount); addInt(count); addPath(path); addFloat(hOffset); addFloat(vOffset); paint->setAntiAlias(true); addPaint(paint); return DrawGlInfo::kStatusDone; } status_t DisplayListRenderer::drawPosText(const char* text, int bytesCount, int count, const float* positions, SkPaint* paint) { if (!text || count <= 0) return DrawGlInfo::kStatusDone; addOp(DisplayList::DrawPosText); addText(text, bytesCount); addInt(count); addFloats(positions, count * 2); paint->setAntiAlias(true); addPaint(paint); return DrawGlInfo::kStatusDone; } void DisplayListRenderer::resetShader() { addOp(DisplayList::ResetShader); } void DisplayListRenderer::setupShader(SkiaShader* shader) { addOp(DisplayList::SetupShader); addShader(shader); } void DisplayListRenderer::resetColorFilter() { addOp(DisplayList::ResetColorFilter); } void DisplayListRenderer::setupColorFilter(SkiaColorFilter* filter) { addOp(DisplayList::SetupColorFilter); addColorFilter(filter); } void DisplayListRenderer::resetShadow() { addOp(DisplayList::ResetShadow); } void DisplayListRenderer::setupShadow(float radius, float dx, float dy, int color) { addOp(DisplayList::SetupShadow); addFloat(radius); addPoint(dx, dy); addInt(color); } void DisplayListRenderer::resetPaintFilter() { addOp(DisplayList::ResetPaintFilter); } void DisplayListRenderer::setupPaintFilter(int clearBits, int setBits) { addOp(DisplayList::SetupPaintFilter); addInt(clearBits); addInt(setBits); } }; // namespace uirenderer }; // namespace android