| /* |
| * 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 "DisplayListRenderer.h" |
| |
| namespace android { |
| namespace uirenderer { |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Defines |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| #define PATH_HEAP_SIZE 64 |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Helpers |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| PathHeap::PathHeap(): mHeap(PATH_HEAP_SIZE * sizeof(SkPath)) { |
| } |
| |
| PathHeap::PathHeap(SkFlattenableReadBuffer& buffer): mHeap(PATH_HEAP_SIZE * sizeof(SkPath)) { |
| int count = buffer.readS32(); |
| |
| mPaths.setCount(count); |
| SkPath** ptr = mPaths.begin(); |
| SkPath* p = (SkPath*) mHeap.allocThrow(count * sizeof(SkPath)); |
| |
| for (int i = 0; i < count; i++) { |
| new (p) SkPath; |
| p->unflatten(buffer); |
| *ptr++ = p; |
| p++; |
| } |
| } |
| |
| PathHeap::~PathHeap() { |
| SkPath** iter = mPaths.begin(); |
| SkPath** stop = mPaths.end(); |
| while (iter < stop) { |
| (*iter)->~SkPath(); |
| iter++; |
| } |
| } |
| |
| int PathHeap::append(const SkPath& path) { |
| SkPath* p = (SkPath*) mHeap.allocThrow(sizeof(SkPath)); |
| new (p) SkPath(path); |
| *mPaths.append() = p; |
| return mPaths.count(); |
| } |
| |
| void PathHeap::flatten(SkFlattenableWriteBuffer& buffer) const { |
| int count = mPaths.count(); |
| |
| buffer.write32(count); |
| SkPath** iter = mPaths.begin(); |
| SkPath** stop = mPaths.end(); |
| while (iter < stop) { |
| (*iter)->flatten(buffer); |
| iter++; |
| } |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Display list |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| const char* DisplayList::OP_NAMES[] = { |
| "AcquireContext", |
| "ReleaseContext", |
| "Save", |
| "Restore", |
| "RestoreToCount", |
| "SaveLayer", |
| "SaveLayerAlpha", |
| "Translate", |
| "Rotate", |
| "Scale", |
| "SetMatrix", |
| "ConcatMatrix", |
| "ClipRect", |
| "DrawDisplayList", |
| "DrawLayer", |
| "DrawBitmap", |
| "DrawBitmapMatrix", |
| "DrawBitmapRect", |
| "DrawBitmapMesh", |
| "DrawPatch", |
| "DrawColor", |
| "DrawRect", |
| "DrawRoundRect", |
| "DrawCircle", |
| "DrawPath", |
| "DrawLines", |
| "DrawText", |
| "ResetShader", |
| "SetupShader", |
| "ResetColorFilter", |
| "SetupColorFilter", |
| "ResetShadow", |
| "SetupShadow" |
| }; |
| |
| DisplayList::DisplayList(const DisplayListRenderer& recorder) { |
| initFromDisplayListRenderer(recorder); |
| } |
| |
| DisplayList::~DisplayList() { |
| sk_free((void*) mReader.base()); |
| |
| 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 < mShaders.size(); i++) { |
| caches.resourceCache.decrementRefcount(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 < mMatrices.size(); i++) { |
| delete mMatrices.itemAt(i); |
| } |
| mMatrices.clear(); |
| |
| if (mPathHeap) { |
| for (int i = 0; i < mPathHeap->count(); i++) { |
| caches.pathCache.removeDeferred(&(*mPathHeap)[i]); |
| } |
| mPathHeap->safeUnref(); |
| } |
| } |
| |
| void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorder) { |
| const SkWriter32& writer = recorder.writeStream(); |
| init(); |
| |
| if (writer.size() == 0) { |
| return; |
| } |
| |
| size_t size = writer.size(); |
| void* buffer = sk_malloc_throw(size); |
| writer.flatten(buffer); |
| mReader.setMemory(buffer, size); |
| |
| mRCPlayback.reset(&recorder.mRCRecorder); |
| mRCPlayback.setupBuffer(mReader); |
| |
| mTFPlayback.reset(&recorder.mTFRecorder); |
| mTFPlayback.setupBuffer(mReader); |
| |
| 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<SkiaShader*> &shaders = recorder.getShaders(); |
| for (size_t i = 0; i < shaders.size(); i++) { |
| SkiaShader* shader = shaders.itemAt(i); |
| mShaders.add(shader); |
| caches.resourceCache.incrementRefcount(shader); |
| } |
| |
| const Vector<SkPaint*> &paints = recorder.getPaints(); |
| for (size_t i = 0; i < paints.size(); i++) { |
| mPaints.add(paints.itemAt(i)); |
| } |
| |
| const Vector<SkMatrix*> &matrices = recorder.getMatrices(); |
| for (size_t i = 0; i < matrices.size(); i++) { |
| mMatrices.add(matrices.itemAt(i)); |
| } |
| |
| mPathHeap = recorder.mPathHeap; |
| if (mPathHeap) { |
| mPathHeap->safeRef(); |
| } |
| } |
| |
| void DisplayList::init() { |
| mPathHeap = NULL; |
| } |
| |
| void DisplayList::replay(OpenGLRenderer& renderer, uint32_t level) { |
| 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'; |
| DISPLAY_LIST_LOGD("%sStart display list (%p)", (char*) indent + 2, this); |
| #endif |
| |
| int saveCount = renderer.getSaveCount() - 1; |
| while (!mReader.eof()) { |
| int op = mReader.readInt(); |
| DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); |
| |
| switch (op) { |
| case AcquireContext: { |
| renderer.acquireContext(); |
| } |
| break; |
| case ReleaseContext: { |
| renderer.releaseContext(); |
| } |
| break; |
| case Save: { |
| renderer.save(getInt()); |
| } |
| break; |
| case Restore: { |
| renderer.restore(); |
| } |
| break; |
| case RestoreToCount: { |
| renderer.restoreToCount(saveCount + getInt()); |
| } |
| break; |
| case SaveLayer: { |
| renderer.saveLayer(getFloat(), getFloat(), getFloat(), getFloat(), |
| getPaint(), getInt()); |
| } |
| break; |
| case SaveLayerAlpha: { |
| renderer.saveLayerAlpha(getFloat(), getFloat(), getFloat(), getFloat(), |
| getInt(), getInt()); |
| } |
| break; |
| case Translate: { |
| renderer.translate(getFloat(), getFloat()); |
| } |
| break; |
| case Rotate: { |
| renderer.rotate(getFloat()); |
| } |
| break; |
| case Scale: { |
| renderer.scale(getFloat(), getFloat()); |
| } |
| break; |
| case Skew: { |
| renderer.skew(getFloat(), getFloat()); |
| } |
| break; |
| case SetMatrix: { |
| renderer.setMatrix(getMatrix()); |
| } |
| break; |
| case ConcatMatrix: { |
| renderer.concatMatrix(getMatrix()); |
| } |
| break; |
| case ClipRect: { |
| renderer.clipRect(getFloat(), getFloat(), getFloat(), getFloat(), |
| (SkRegion::Op) getInt()); |
| } |
| break; |
| case DrawDisplayList: { |
| renderer.drawDisplayList(getDisplayList(), level + 1); |
| } |
| break; |
| case DrawLayer: { |
| renderer.drawLayer((Layer*) getInt(), getFloat(), getFloat(), getPaint()); |
| } |
| break; |
| case DrawBitmap: { |
| renderer.drawBitmap(getBitmap(), getFloat(), getFloat(), getPaint()); |
| } |
| break; |
| case DrawBitmapMatrix: { |
| renderer.drawBitmap(getBitmap(), getMatrix(), getPaint()); |
| } |
| break; |
| case DrawBitmapRect: { |
| renderer.drawBitmap(getBitmap(), getFloat(), getFloat(), getFloat(), getFloat(), |
| getFloat(), getFloat(), getFloat(), getFloat(), getPaint()); |
| } |
| 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; |
| |
| renderer.drawBitmapMesh(bitmap, meshWidth, meshHeight, vertices, colors, getPaint()); |
| } |
| 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); |
| |
| renderer.drawPatch(bitmap, xDivs, yDivs, colors, xDivsCount, yDivsCount, |
| numColors, getFloat(), getFloat(), getFloat(), getFloat(), getPaint()); |
| } |
| break; |
| case DrawColor: { |
| renderer.drawColor(getInt(), (SkXfermode::Mode) getInt()); |
| } |
| break; |
| case DrawRect: { |
| renderer.drawRect(getFloat(), getFloat(), getFloat(), getFloat(), getPaint()); |
| } |
| break; |
| case DrawRoundRect: { |
| renderer.drawRoundRect(getFloat(), getFloat(), getFloat(), getFloat(), |
| getFloat(), getFloat(), getPaint()); |
| } |
| break; |
| case DrawCircle: { |
| renderer.drawCircle(getFloat(), getFloat(), getFloat(), getPaint()); |
| } |
| break; |
| case DrawPath: { |
| renderer.drawPath(getPath(), getPaint()); |
| } |
| break; |
| case DrawLines: { |
| int count = 0; |
| float* points = getFloats(count); |
| renderer.drawLines(points, count, getPaint()); |
| } |
| break; |
| case DrawText: { |
| getText(&text); |
| renderer.drawText(text.text(), text.length(), getInt(), |
| getFloat(), getFloat(), getPaint()); |
| } |
| break; |
| case ResetShader: { |
| renderer.resetShader(); |
| } |
| break; |
| case SetupShader: { |
| renderer.setupShader(getShader()); |
| } |
| break; |
| case ResetColorFilter: { |
| renderer.resetColorFilter(); |
| } |
| break; |
| case SetupColorFilter: { |
| renderer.setupColorFilter(getColorFilter()); |
| } |
| break; |
| case ResetShadow: { |
| renderer.resetShadow(); |
| } |
| break; |
| case SetupShadow: { |
| renderer.setupShadow(getFloat(), getFloat(), getFloat(), getInt()); |
| } |
| break; |
| } |
| } |
| |
| DISPLAY_LIST_LOGD("%sDone", (char*) indent + 2); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Base structure |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| DisplayListRenderer::DisplayListRenderer(): |
| mHeap(HEAP_BLOCK_SIZE), mWriter(MIN_WRITER_SIZE) { |
| mPathHeap = NULL; |
| mDisplayList = NULL; |
| } |
| |
| DisplayListRenderer::~DisplayListRenderer() { |
| reset(); |
| } |
| |
| void DisplayListRenderer::reset() { |
| if (mPathHeap) { |
| mPathHeap->unref(); |
| mPathHeap = NULL; |
| } |
| |
| mWriter.reset(); |
| mHeap.reset(); |
| |
| mRCRecorder.reset(); |
| mTFRecorder.reset(); |
| |
| Caches& caches = Caches::getInstance(); |
| for (size_t i = 0; i < mBitmapResources.size(); i++) { |
| SkBitmap* resource = mBitmapResources.itemAt(i); |
| caches.resourceCache.decrementRefcount(resource); |
| } |
| mBitmapResources.clear(); |
| |
| for (size_t i = 0; i < mShaders.size(); i++) { |
| caches.resourceCache.decrementRefcount(mShaders.itemAt(i)); |
| } |
| mShaders.clear(); |
| mShaderMap.clear(); |
| |
| mPaints.clear(); |
| mPaintMap.clear(); |
| mMatrices.clear(); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Operations |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| DisplayList* DisplayListRenderer::getDisplayList() { |
| if (mDisplayList == NULL) { |
| mDisplayList = new DisplayList(*this); |
| } else { |
| mDisplayList->initFromDisplayListRenderer(*this); |
| } |
| return mDisplayList; |
| } |
| |
| void DisplayListRenderer::setViewport(int width, int height) { |
| mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1); |
| |
| mWidth = width; |
| mHeight = height; |
| } |
| |
| void DisplayListRenderer::prepare(bool opaque) { |
| mSnapshot = new Snapshot(mFirstSnapshot, |
| SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); |
| mSaveCount = 1; |
| mSnapshot->setClip(0.0f, 0.0f, mWidth, mHeight); |
| } |
| |
| void DisplayListRenderer::acquireContext() { |
| addOp(DisplayList::AcquireContext); |
| OpenGLRenderer::acquireContext(); |
| } |
| |
| void DisplayListRenderer::releaseContext() { |
| addOp(DisplayList::ReleaseContext); |
| OpenGLRenderer::releaseContext(); |
| } |
| |
| int DisplayListRenderer::save(int flags) { |
| addOp(DisplayList::Save); |
| addInt(flags); |
| return OpenGLRenderer::save(flags); |
| } |
| |
| void DisplayListRenderer::restore() { |
| addOp(DisplayList::Restore); |
| OpenGLRenderer::restore(); |
| } |
| |
| void DisplayListRenderer::restoreToCount(int saveCount) { |
| addOp(DisplayList::RestoreToCount); |
| addInt(saveCount); |
| 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) { |
| addOp(DisplayList::Translate); |
| addPoint(dx, dy); |
| 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); |
| } |
| |
| void DisplayListRenderer::drawDisplayList(DisplayList* displayList, uint32_t level) { |
| addOp(DisplayList::DrawDisplayList); |
| addDisplayList(displayList); |
| } |
| |
| void DisplayListRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) { |
| addOp(DisplayList::DrawLayer); |
| addInt((int) layer); |
| addPoint(x, y); |
| addPaint(paint); |
| } |
| |
| void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, |
| SkPaint* paint) { |
| addOp(DisplayList::DrawBitmap); |
| addBitmap(bitmap); |
| addPoint(left, top); |
| addPaint(paint); |
| } |
| |
| void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, |
| SkPaint* paint) { |
| addOp(DisplayList::DrawBitmapMatrix); |
| addBitmap(bitmap); |
| addMatrix(matrix); |
| addPaint(paint); |
| } |
| |
| void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop, |
| float srcRight, float srcBottom, float dstLeft, float dstTop, |
| float dstRight, float dstBottom, SkPaint* paint) { |
| addOp(DisplayList::DrawBitmapRect); |
| addBitmap(bitmap); |
| addBounds(srcLeft, srcTop, srcRight, srcBottom); |
| addBounds(dstLeft, dstTop, dstRight, dstBottom); |
| addPaint(paint); |
| } |
| |
| void 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); |
| } |
| |
| void 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) { |
| addOp(DisplayList::DrawPatch); |
| addBitmap(bitmap); |
| addInts(xDivs, width); |
| addInts(yDivs, height); |
| addUInts(colors, numColors); |
| addBounds(left, top, right, bottom); |
| addPaint(paint); |
| } |
| |
| void DisplayListRenderer::drawColor(int color, SkXfermode::Mode mode) { |
| addOp(DisplayList::DrawColor); |
| addInt(color); |
| addInt(mode); |
| } |
| |
| void DisplayListRenderer::drawRect(float left, float top, float right, float bottom, |
| SkPaint* paint) { |
| addOp(DisplayList::DrawRect); |
| addBounds(left, top, right, bottom); |
| addPaint(paint); |
| } |
| |
| void DisplayListRenderer::drawRoundRect(float left, float top, float right, float bottom, |
| float rx, float ry, SkPaint* paint) { |
| addOp(DisplayList::DrawRoundRect); |
| addBounds(left, top, right, bottom); |
| addPoint(rx, ry); |
| addPaint(paint); |
| } |
| |
| void DisplayListRenderer::drawCircle(float x, float y, float radius, SkPaint* paint) { |
| addOp(DisplayList::DrawCircle); |
| addPoint(x, y); |
| addFloat(radius); |
| addPaint(paint); |
| } |
| |
| void DisplayListRenderer::drawPath(SkPath* path, SkPaint* paint) { |
| addOp(DisplayList::DrawPath); |
| addPath(path); |
| addPaint(paint); |
| } |
| |
| void DisplayListRenderer::drawLines(float* points, int count, SkPaint* paint) { |
| addOp(DisplayList::DrawLines); |
| addFloats(points, count); |
| addPaint(paint); |
| } |
| |
| void DisplayListRenderer::drawText(const char* text, int bytesCount, int count, |
| float x, float y, SkPaint* paint) { |
| addOp(DisplayList::DrawText); |
| addText(text, bytesCount); |
| addInt(count); |
| addPoint(x, y); |
| addPaint(paint); |
| } |
| |
| 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); |
| } |
| |
| }; // namespace uirenderer |
| }; // namespace android |