am ad82f20d: Merge "DisplayList draw operation reordering"

* commit 'ad82f20d2382396f5ac75fdf6f7db5c4da1c4c23':
  DisplayList draw operation reordering
This commit is contained in:
Chris Craik
2013-02-19 09:56:33 -08:00
committed by Android Git Automerger
13 changed files with 621 additions and 103 deletions

View File

@@ -12,6 +12,7 @@ ifeq ($(USE_OPENGL_RENDERER),true)
GammaFontRenderer.cpp \
Caches.cpp \
DisplayList.cpp \
DeferredDisplayList.cpp \
DisplayListLogBuffer.cpp \
DisplayListRenderer.cpp \
Dither.cpp \

View File

@@ -74,6 +74,9 @@
// Turn on to enable additional debugging in the font renderers
#define DEBUG_FONT_RENDERER 0
// Turn on to log draw operation batching and deferral information
#define DEBUG_DEFER 0
// Turn on to dump display list state
#define DEBUG_DISPLAY_LIST 0

View File

@@ -0,0 +1,176 @@
/*
* Copyright (C) 2013 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"
#define ATRACE_TAG ATRACE_TAG_VIEW
#include <utils/Trace.h>
#include "Debug.h"
#include "DisplayListOp.h"
#include "OpenGLRenderer.h"
#if DEBUG_DEFER
#define DEFER_LOGD(...) ALOGD(__VA_ARGS__)
#else
#define DEFER_LOGD(...)
#endif
namespace android {
namespace uirenderer {
class DrawOpBatch {
public:
DrawOpBatch() {
mOps.clear();
}
~DrawOpBatch() {
mOps.clear();
}
void add(DrawOp* op) {
// NOTE: ignore empty bounds special case, since we don't merge across those ops
mBounds.unionWith(op->state.mBounds);
mOps.add(op);
}
bool intersects(Rect& rect) {
if (!rect.intersects(mBounds)) return false;
for (unsigned int i = 0; i < mOps.size(); i++) {
if (rect.intersects(mOps[i]->state.mBounds)) {
#if DEBUG_DEFER
DEFER_LOGD("op intersects with op %p with bounds %f %f %f %f:", mOps[i],
mOps[i]->state.mBounds.left, mOps[i]->state.mBounds.top,
mOps[i]->state.mBounds.right, mOps[i]->state.mBounds.bottom);
mOps[i]->output(2);
#endif
return true;
}
}
return false;
}
Vector<DrawOp*> mOps;
private:
Rect mBounds;
};
void DeferredDisplayList::clear() {
for (int i = 0; i < kOpBatch_Count; i++) {
mBatchIndices[i] = -1;
}
for (unsigned int i = 0; i < mBatches.size(); i++) {
delete mBatches[i];
}
mBatches.clear();
}
void DeferredDisplayList::add(DrawOp* op, bool disallowReorder) {
if (CC_UNLIKELY(disallowReorder)) {
if (!mBatches.isEmpty()) {
mBatches[0]->add(op);
return;
}
DrawOpBatch* b = new DrawOpBatch();
b->add(op);
mBatches.add(b);
return;
}
// disallowReorder isn't set, so find the latest batch of the new op's type, and try to merge
// the new op into it
DrawOpBatch* targetBatch = NULL;
int batchId = op->getBatchId();
if (!mBatches.isEmpty()) {
if (op->state.mBounds.isEmpty()) {
// don't know the bounds for op, so add to last batch and start from scratch on next op
mBatches.top()->add(op);
for (int i = 0; i < kOpBatch_Count; i++) {
mBatchIndices[i] = -1;
}
#if DEBUG_DEFER
DEFER_LOGD("Warning: Encountered op with empty bounds, resetting batches");
op->output(2);
#endif
return;
}
if (batchId >= 0 && mBatchIndices[batchId] != -1) {
int targetIndex = mBatchIndices[batchId];
targetBatch = mBatches[targetIndex];
// iterate back toward target to see if anything drawn since should overlap the new op
for (int i = mBatches.size() - 1; i > targetIndex; i--) {
DrawOpBatch* overBatch = mBatches[i];
if (overBatch->intersects(op->state.mBounds)) {
targetBatch = NULL;
#if DEBUG_DEFER
DEFER_LOGD("op couldn't join batch %d, was intersected by batch %d",
targetIndex, i);
op->output(2);
#endif
break;
}
}
}
}
if (!targetBatch) {
targetBatch = new DrawOpBatch();
mBatches.add(targetBatch);
if (batchId >= 0) {
mBatchIndices[batchId] = mBatches.size() - 1;
}
}
targetBatch->add(op);
}
status_t DeferredDisplayList::flush(OpenGLRenderer& renderer, Rect& dirty, int32_t flags,
uint32_t level) {
ATRACE_CALL();
status_t status = DrawGlInfo::kStatusDone;
if (isEmpty()) return status; // nothing to flush
DEFER_LOGD("--flushing");
DrawModifiers restoreDrawModifiers = renderer.getDrawModifiers();
int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
int opCount = 0;
for (unsigned int i = 0; i < mBatches.size(); i++) {
DrawOpBatch* batch = mBatches[i];
for (unsigned int j = 0; j < batch->mOps.size(); j++) {
DrawOp* op = batch->mOps[j];
renderer.restoreDisplayState(op->state);
#if DEBUG_DEFER
op->output(2);
#endif
status |= op->applyDraw(renderer, dirty, level,
op->state.mMultipliedAlpha >= 0, op->state.mMultipliedAlpha);
opCount++;
}
}
DEFER_LOGD("--flushed, drew %d batches (total %d ops)", mBatches.size(), opCount);
renderer.restoreToCount(restoreTo);
renderer.setDrawModifiers(restoreDrawModifiers);
clear();
return status;
}
}; // namespace uirenderer
}; // namespace android

View File

@@ -0,0 +1,78 @@
/*
* Copyright (C) 2013 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.
*/
#ifndef ANDROID_HWUI_DEFERRED_DISPLAY_LIST_H
#define ANDROID_HWUI_DEFERRED_DISPLAY_LIST_H
#include <utils/Errors.h>
#include <utils/Vector.h>
#include "Matrix.h"
#include "Rect.h"
namespace android {
namespace uirenderer {
class DrawOp;
class DrawOpBatch;
class OpenGLRenderer;
class SkiaShader;
class DeferredDisplayList {
public:
DeferredDisplayList() { clear(); }
~DeferredDisplayList() { clear(); }
enum OpBatchId {
kOpBatch_None = -1, // Don't batch
kOpBatch_Bitmap,
kOpBatch_Patch,
kOpBatch_AlphaVertices,
kOpBatch_Vertices,
kOpBatch_AlphaMaskTexture,
kOpBatch_Text,
kOpBatch_ColorText,
kOpBatch_Count, // Add other batch ids before this
};
bool isEmpty() { return mBatches.isEmpty(); }
/**
* Plays back all of the draw ops recorded into batches to the renderer.
* Adjusts the state of the renderer as necessary, and restores it when complete
*/
status_t flush(OpenGLRenderer& renderer, Rect& dirty, int32_t flags,
uint32_t level);
/**
* Add a draw op into the DeferredDisplayList, reordering as needed (for performance) if
* disallowReorder is false, respecting draw order when overlaps occur
*/
void add(DrawOp* op, bool disallowReorder);
private:
void clear();
Vector<DrawOpBatch*> mBatches;
int mBatchIndices[kOpBatch_Count];
};
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_HWUI_DEFERRED_DISPLAY_LIST_H

View File

@@ -14,6 +14,7 @@
* limitations under the License.
*/
#include "Debug.h"
#include "DisplayList.h"
#include "DisplayListOp.h"
#include "DisplayListLogBuffer.h"
@@ -386,7 +387,8 @@ void DisplayList::setViewProperties(OpenGLRenderer& renderer, uint32_t level) {
}
}
status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level) {
status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level,
DeferredDisplayList* deferredList) {
status_t drawGlStatus = DrawGlInfo::kStatusDone;
#if DEBUG_DISPLAY_LIST
@@ -401,6 +403,12 @@ status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flag
int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
DISPLAY_LIST_LOGD("%*sSave %d %d", level * 2, "",
SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo);
if (mAlpha < 1 && !mCaching && CC_LIKELY(deferredList)) {
// flush before a saveLayerAlpha/setAlpha
// TODO: make this cleaner
drawGlStatus |= deferredList->flush(renderer, dirty, flags, level);
}
setViewProperties(renderer, level);
if (renderer.quickRejectNoScissor(0, 0, mWidth, mHeight)) {
@@ -418,8 +426,13 @@ status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flag
Caches::getInstance().eventMark(strlen(op->name()), op->name());
#endif
drawGlStatus |= op->replay(renderer, dirty, flags,
saveCount, level, mCaching, mMultipliedAlpha);
if (deferredList) {
drawGlStatus |= op->replay(renderer, dirty, flags,
saveCount, level, mCaching, mMultipliedAlpha, *deferredList);
} else {
drawGlStatus |= op->replay(renderer, dirty, flags,
saveCount, level, mCaching, mMultipliedAlpha);
}
logBuffer.writeCommand(level, op->name());
}
@@ -429,6 +442,11 @@ status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flag
DISPLAY_LIST_LOGD("%*sDone (%p, %s), returning %d", (level + 1) * 2, "", this, mName.string(),
drawGlStatus);
if (!level && CC_LIKELY(deferredList)) {
drawGlStatus |= deferredList->flush(renderer, dirty, flags, level);
}
return drawGlStatus;
}

View File

@@ -44,6 +44,7 @@ class SkRegion;
namespace android {
namespace uirenderer {
class DeferredDisplayList;
class DisplayListOp;
class DisplayListRenderer;
class OpenGLRenderer;
@@ -83,7 +84,8 @@ public:
void initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing = false);
status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level = 0);
status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level = 0,
DeferredDisplayList* deferredList = NULL);
void output(uint32_t level = 0);

View File

@@ -22,6 +22,7 @@
#include <private/hwui/DrawGlInfo.h>
#include "OpenGLRenderer.h"
#include "DeferredDisplayList.h"
#include "DisplayListRenderer.h"
#include "utils/LinearAllocator.h"
@@ -43,7 +44,6 @@
#define OP_LOGS(s) OP_LOG("%s", s)
#define OP_LOG(s, ...) ALOGD( "%*s" s, level * 2, "", __VA_ARGS__ )
namespace android {
namespace uirenderer {
@@ -74,11 +74,15 @@ public:
kOpLogFlag_JSON = 0x2 // TODO: add?
};
//TODO: for draw batching, DrawOps should override a virtual sub-method, with
// DrawOps::apply deferring operations to a different list if possible
virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount,
uint32_t level, bool caching, int multipliedAlpha) = 0;
// same as replay above, but draw operations will defer into the deferredList if possible
// NOTE: colorfilters, paintfilters, shaders, shadow, and complex clips prevent deferral
virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount,
uint32_t level, bool caching, int multipliedAlpha,
DeferredDisplayList& deferredList) = 0;
virtual void output(int level, uint32_t flags = 0) = 0;
// NOTE: it would be nice to declare constants and overriding the implementation in each op to
@@ -98,7 +102,28 @@ public:
return DrawGlInfo::kStatusDone;
}
/**
* State operations are applied directly to the renderer, but can cause the deferred drawing op
* list to flush
*/
virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount,
uint32_t level, bool caching, int multipliedAlpha, DeferredDisplayList& deferredList) {
status_t status = DrawGlInfo::kStatusDone;
if (requiresDrawOpFlush()) {
// will be setting renderer state that affects ops in deferredList, so flush list first
status |= deferredList.flush(renderer, dirty, flags, level);
}
applyState(renderer, saveCount);
return status;
}
virtual void applyState(OpenGLRenderer& renderer, int saveCount) = 0;
/**
* Returns true if it affects renderer drawing state in such a way to break deferral
* see OpenGLRenderer::disallowDeferral()
*/
virtual bool requiresDrawOpFlush() { return false; }
};
class DrawOp : public DisplayListOp {
@@ -115,6 +140,33 @@ public:
return applyDraw(renderer, dirty, level, caching, multipliedAlpha);
}
/** Draw operations are stored in the deferredList with information necessary for playback */
virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount,
uint32_t level, bool caching, int multipliedAlpha, DeferredDisplayList& deferredList) {
if (mQuickRejected && CC_LIKELY(flags & DisplayList::kReplayFlag_ClipChildren)) {
return DrawGlInfo::kStatusDone;
}
if (renderer.disallowDeferral()) {
// dispatch draw immediately, since the renderer's state is too complex for deferral
return applyDraw(renderer, dirty, level, caching, multipliedAlpha);
}
if (!caching) multipliedAlpha = -1;
state.mMultipliedAlpha = multipliedAlpha;
if (!getLocalBounds(state.mBounds)) {
// empty bounds signify bounds can't be calculated
state.mBounds.setEmpty();
}
if (!renderer.storeDisplayState(state)) {
// op wasn't quick-rejected, so defer
deferredList.add(this, renderer.disallowReorder());
}
return DrawGlInfo::kStatusDone;
}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
bool caching, int multipliedAlpha) = 0;
@@ -125,6 +177,19 @@ public:
void setQuickRejected(bool quickRejected) { mQuickRejected = quickRejected; }
bool getQuickRejected() { return mQuickRejected; }
/** Batching disabled by default, turned on for individual ops */
virtual DeferredDisplayList::OpBatchId getBatchId() {
return DeferredDisplayList::kOpBatch_None;
}
float strokeWidthOutset() { return mPaint->getStrokeWidth() * 0.5f; }
public:
/**
* Stores the relevant canvas state of the object between deferral and replay (if the canvas
* state supports being stored) See OpenGLRenderer::simpleClipAndState()
*/
DeferredDisplayState state;
protected:
SkPaint* getPaint(OpenGLRenderer& renderer) {
return renderer.filterPaint(mPaint);
@@ -191,6 +256,8 @@ public:
}
virtual const char* name() { return "RestoreToCount"; }
// Note: don't have to return true for requiresDrawOpFlush - even though restore can create a
// complex clip, the clip and matrix are overridden by DeferredDisplayList::flush()
private:
int mCount;
@@ -211,6 +278,7 @@ public:
}
virtual const char* name() { return "SaveLayer"; }
virtual bool requiresDrawOpFlush() { return true; }
private:
Rect mArea;
@@ -232,6 +300,8 @@ public:
}
virtual const char* name() { return "SaveLayerAlpha"; }
virtual bool requiresDrawOpFlush() { return true; }
private:
Rect mArea;
int mAlpha;
@@ -391,6 +461,7 @@ public:
}
virtual const char* name() { return "ClipPath"; }
virtual bool requiresDrawOpFlush() { return true; }
private:
SkPath* mPath;
@@ -413,6 +484,7 @@ public:
}
virtual const char* name() { return "ClipRegion"; }
virtual bool requiresDrawOpFlush() { return true; }
private:
SkRegion* mRegion;
@@ -582,6 +654,9 @@ public:
}
virtual const char* name() { return "DrawBitmap"; }
virtual DeferredDisplayList::OpBatchId getBatchId() {
return DeferredDisplayList::kOpBatch_Bitmap;
}
protected:
SkBitmap* mBitmap;
@@ -606,6 +681,9 @@ public:
}
virtual const char* name() { return "DrawBitmap"; }
virtual DeferredDisplayList::OpBatchId getBatchId() {
return DeferredDisplayList::kOpBatch_Bitmap;
}
private:
SkBitmap* mBitmap;
@@ -632,6 +710,9 @@ public:
}
virtual const char* name() { return "DrawBitmapRect"; }
virtual DeferredDisplayList::OpBatchId getBatchId() {
return DeferredDisplayList::kOpBatch_Bitmap;
}
private:
SkBitmap* mBitmap;
@@ -654,6 +735,9 @@ public:
}
virtual const char* name() { return "DrawBitmapData"; }
virtual DeferredDisplayList::OpBatchId getBatchId() {
return DeferredDisplayList::kOpBatch_Bitmap;
}
};
class DrawBitmapMeshOp : public DrawOp {
@@ -674,6 +758,9 @@ public:
}
virtual const char* name() { return "DrawBitmapMesh"; }
virtual DeferredDisplayList::OpBatchId getBatchId() {
return DeferredDisplayList::kOpBatch_Bitmap;
}
private:
SkBitmap* mBitmap;
@@ -708,6 +795,9 @@ public:
}
virtual const char* name() { return "DrawPatch"; }
virtual DeferredDisplayList::OpBatchId getBatchId() {
return DeferredDisplayList::kOpBatch_Patch;
}
private:
SkBitmap* mBitmap;
@@ -748,15 +838,21 @@ public:
: DrawBoundedOp(left, top, right, bottom, paint) {};
bool getLocalBounds(Rect& localBounds) {
localBounds.set(mLocalBounds);
if (mPaint && mPaint->getStyle() != SkPaint::kFill_Style) {
float outset = mPaint->getStrokeWidth() * 0.5f;
localBounds.set(mLocalBounds.left - outset, mLocalBounds.top - outset,
mLocalBounds.right + outset, mLocalBounds.bottom + outset);
} else {
localBounds.set(mLocalBounds);
localBounds.outset(strokeWidthOutset());
}
return true;
}
virtual DeferredDisplayList::OpBatchId getBatchId() {
if (mPaint->getPathEffect()) {
return DeferredDisplayList::kOpBatch_AlphaMaskTexture;
}
return mPaint->isAntiAlias() ?
DeferredDisplayList::kOpBatch_AlphaVertices :
DeferredDisplayList::kOpBatch_Vertices;
}
};
class DrawRectOp : public DrawStrokableOp {
@@ -793,6 +889,10 @@ public:
virtual const char* name() { return "DrawRects"; }
virtual DeferredDisplayList::OpBatchId getBatchId() {
return DeferredDisplayList::kOpBatch_Vertices;
}
private:
const float* mRects;
int mCount;
@@ -912,22 +1012,24 @@ public:
virtual const char* name() { return "DrawPath"; }
virtual DeferredDisplayList::OpBatchId getBatchId() {
return DeferredDisplayList::kOpBatch_AlphaMaskTexture;
}
private:
SkPath* mPath;
};
class DrawLinesOp : public DrawOp {
class DrawLinesOp : public DrawBoundedOp {
public:
DrawLinesOp(float* points, int count, SkPaint* paint)
: DrawOp(paint), mPoints(points), mCount(count) {
/* TODO: inherit from DrawBoundedOp and calculate localbounds something like:
: DrawBoundedOp(paint), mPoints(points), mCount(count) {
for (int i = 0; i < count; i += 2) {
mLocalBounds.left = fminf(mLocalBounds.left, points[i]);
mLocalBounds.right = fmaxf(mLocalBounds.right, points[i]);
mLocalBounds.top = fminf(mLocalBounds.top, points[i+1]);
mLocalBounds.bottom = fmaxf(mLocalBounds.bottom, points[i+1]);
}
*/
mLocalBounds.outset(strokeWidthOutset());
}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
@@ -941,6 +1043,12 @@ public:
virtual const char* name() { return "DrawLines"; }
virtual DeferredDisplayList::OpBatchId getBatchId() {
return mPaint->isAntiAlias() ?
DeferredDisplayList::kOpBatch_AlphaVertices :
DeferredDisplayList::kOpBatch_Vertices;
}
protected:
float* mPoints;
int mCount;
@@ -971,6 +1079,12 @@ public:
virtual void output(int level, uint32_t flags) {
OP_LOG("Draw some text, %d bytes", mBytesCount);
}
virtual DeferredDisplayList::OpBatchId getBatchId() {
return mPaint->getColor() == 0xff000000 ?
DeferredDisplayList::kOpBatch_Text :
DeferredDisplayList::kOpBatch_ColorText;
}
protected:
const char* mText;
int mBytesCount;
@@ -1042,6 +1156,12 @@ public:
virtual const char* name() { return "DrawText"; }
virtual DeferredDisplayList::OpBatchId getBatchId() {
return mPaint->getColor() == 0xff000000 ?
DeferredDisplayList::kOpBatch_Text :
DeferredDisplayList::kOpBatch_ColorText;
}
private:
const char* mText;
int mBytesCount;
@@ -1083,9 +1203,21 @@ class DrawDisplayListOp : public DrawOp {
public:
DrawDisplayListOp(DisplayList* displayList, int flags)
: DrawOp(0), mDisplayList(displayList), mFlags(flags) {}
virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount,
uint32_t level, bool caching, int multipliedAlpha, DeferredDisplayList& deferredList) {
if (mDisplayList && mDisplayList->isRenderable()) {
return mDisplayList->replay(renderer, dirty, mFlags, level + 1, &deferredList);
}
return DrawGlInfo::kStatusDone;
}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
bool caching, int multipliedAlpha) {
return renderer.drawDisplayList(mDisplayList, dirty, mFlags, level + 1);
if (mDisplayList && mDisplayList->isRenderable()) {
return mDisplayList->replay(renderer, dirty, mFlags, level + 1);
}
return DrawGlInfo::kStatusDone;
}
virtual void output(int level, uint32_t flags) {

View File

@@ -21,6 +21,7 @@
#include <private/hwui/DrawGlInfo.h>
#include "DisplayList.h"
#include "DeferredDisplayList.h"
#include "DisplayListLogBuffer.h"
#include "DisplayListOp.h"
#include "DisplayListRenderer.h"
@@ -239,7 +240,7 @@ bool DisplayListRenderer::clipRegion(SkRegion* region, SkRegion::Op op) {
}
status_t DisplayListRenderer::drawDisplayList(DisplayList* displayList,
Rect& dirty, int32_t flags, uint32_t level) {
Rect& dirty, int32_t flags) {
// dirty is an out parameter and should not be recorded,
// it matters only when replaying the display list

View File

@@ -47,15 +47,12 @@ namespace uirenderer {
// Display list
///////////////////////////////////////////////////////////////////////////////
class DeferredDisplayList;
class DisplayListRenderer;
class DisplayListOp;
class DrawOp;
class StateOp;
///////////////////////////////////////////////////////////////////////////////
// Renderer
///////////////////////////////////////////////////////////////////////////////
/**
* Records drawing commands in a display list for latter playback.
*/
@@ -98,8 +95,7 @@ public:
virtual bool clipPath(SkPath* path, SkRegion::Op op);
virtual bool clipRegion(SkRegion* region, SkRegion::Op op);
virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t flags,
uint32_t level = 0);
virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t flags);
virtual status_t drawLayer(Layer* layer, float x, float y, SkPaint* paint);
virtual status_t drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
virtual status_t drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);

View File

@@ -32,6 +32,7 @@
#include <ui/Rect.h>
#include "OpenGLRenderer.h"
#include "DeferredDisplayList.h"
#include "DisplayListRenderer.h"
#include "PathTessellator.h"
#include "Properties.h"
@@ -111,16 +112,18 @@ static const Blender gBlendsSwap[] = {
OpenGLRenderer::OpenGLRenderer():
mCaches(Caches::getInstance()), mExtensions(Extensions::getInstance()) {
mShader = NULL;
mColorFilter = NULL;
mHasShadow = false;
mHasDrawFilter = false;
mDrawModifiers.mShader = NULL;
mDrawModifiers.mColorFilter = NULL;
mDrawModifiers.mHasShadow = false;
mDrawModifiers.mHasDrawFilter = false;
memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices));
mFirstSnapshot = new Snapshot;
mScissorOptimizationDisabled = false;
mDrawDeferDisabled = false;
mDrawReorderDisabled = false;
}
OpenGLRenderer::~OpenGLRenderer() {
@@ -137,6 +140,20 @@ void OpenGLRenderer::initProperties() {
} else {
INIT_LOGD(" Scissor optimization enabled");
}
if (property_get(PROPERTY_DISABLE_DRAW_DEFER, property, "false")) {
mDrawDeferDisabled = !strcasecmp(property, "true");
INIT_LOGD(" Draw defer %s", mDrawDeferDisabled ? "disabled" : "enabled");
} else {
INIT_LOGD(" Draw defer enabled");
}
if (property_get(PROPERTY_DISABLE_DRAW_REORDER, property, "false")) {
mDrawReorderDisabled = !strcasecmp(property, "true");
INIT_LOGD(" Draw reorder %s", mDrawReorderDisabled ? "disabled" : "enabled");
} else {
INIT_LOGD(" Draw reorder enabled");
}
}
///////////////////////////////////////////////////////////////////////////////
@@ -770,7 +787,7 @@ bool OpenGLRenderer::createLayer(float left, float top, float right, float botto
layer->layer.set(bounds);
layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->getHeight()),
bounds.getWidth() / float(layer->getWidth()), 0.0f);
layer->setColorFilter(mColorFilter);
layer->setColorFilter(mDrawModifiers.mColorFilter);
layer->setBlend(true);
layer->setDirty(false);
@@ -1203,6 +1220,40 @@ void OpenGLRenderer::clearLayerRegions() {
}
}
///////////////////////////////////////////////////////////////////////////////
// State Deferral
///////////////////////////////////////////////////////////////////////////////
bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state) {
const Rect& currentClip = *(mSnapshot->clipRect);
const mat4& currentMatrix = *(mSnapshot->transform);
// state only has bounds initialized in local coordinates
if (!state.mBounds.isEmpty()) {
currentMatrix.mapRect(state.mBounds);
if (!state.mBounds.intersect(currentClip)) {
// quick rejected
return true;
}
}
state.mClip.set(currentClip);
state.mMatrix.load(currentMatrix);
state.mDrawModifiers = mDrawModifiers;
return false;
}
void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state) {
mSnapshot->transform->load(state.mMatrix);
// NOTE: a clip RECT will be saved and restored, but DeferredDisplayState doesn't support
// complex clips. In the future, we should add support for deferral of operations clipped by
// these. for now, we don't defer with complex clips (see OpenGLRenderer::disallowDeferral())
mSnapshot->setClip(state.mClip.left, state.mClip.top, state.mClip.right, state.mClip.bottom);
dirtyClip();
mDrawModifiers = state.mDrawModifiers;
}
///////////////////////////////////////////////////////////////////////////////
// Transforms
///////////////////////////////////////////////////////////////////////////////
@@ -1452,7 +1503,7 @@ void OpenGLRenderer::setupDraw(bool clear) {
if (clear) clearLayerRegions();
// Make sure setScissor & setStencil happen at the beginning of
// this method
if (mDirtyClip) {
if (mDirtyClip && mCaches.scissorEnabled) {
setScissorFromClip();
setStencilFromClip();
}
@@ -1524,14 +1575,14 @@ void OpenGLRenderer::setupDrawColor(float r, float g, float b, float a) {
}
void OpenGLRenderer::setupDrawShader() {
if (mShader) {
mShader->describe(mDescription, mExtensions);
if (mDrawModifiers.mShader) {
mDrawModifiers.mShader->describe(mDescription, mExtensions);
}
}
void OpenGLRenderer::setupDrawColorFilter() {
if (mColorFilter) {
mColorFilter->describe(mDescription, mExtensions);
if (mDrawModifiers.mColorFilter) {
mDrawModifiers.mColorFilter->describe(mDescription, mExtensions);
}
}
@@ -1547,16 +1598,19 @@ void OpenGLRenderer::setupDrawBlending(SkXfermode::Mode mode, bool swapSrcDst) {
// When the blending mode is kClear_Mode, we need to use a modulate color
// argb=1,0,0,0
accountForClear(mode);
chooseBlending((mColorSet && mColorA < 1.0f) || (mShader && mShader->blend()), mode,
mDescription, swapSrcDst);
bool blend = (mColorSet && mColorA < 1.0f) ||
(mDrawModifiers.mShader && mDrawModifiers.mShader->blend());
chooseBlending(blend, mode, mDescription, swapSrcDst);
}
void OpenGLRenderer::setupDrawBlending(bool blend, SkXfermode::Mode mode, bool swapSrcDst) {
// When the blending mode is kClear_Mode, we need to use a modulate color
// argb=1,0,0,0
accountForClear(mode);
chooseBlending(blend || (mColorSet && mColorA < 1.0f) || (mShader && mShader->blend()) ||
(mColorFilter && mColorFilter->blend()), mode, mDescription, swapSrcDst);
blend |= (mColorSet && mColorA < 1.0f) ||
(mDrawModifiers.mShader && mDrawModifiers.mShader->blend()) ||
(mDrawModifiers.mColorFilter && mDrawModifiers.mColorFilter->blend());
chooseBlending(blend, mode, mDescription, swapSrcDst);
}
void OpenGLRenderer::setupDrawProgram() {
@@ -1609,7 +1663,7 @@ void OpenGLRenderer::setupDrawPointUniforms() {
}
void OpenGLRenderer::setupDrawColorUniforms() {
if ((mColorSet && !mShader) || (mShader && mSetShaderColor)) {
if ((mColorSet && !mDrawModifiers.mShader) || (mDrawModifiers.mShader && mSetShaderColor)) {
mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA);
}
}
@@ -1621,23 +1675,25 @@ void OpenGLRenderer::setupDrawPureColorUniforms() {
}
void OpenGLRenderer::setupDrawShaderUniforms(bool ignoreTransform) {
if (mShader) {
if (mDrawModifiers.mShader) {
if (ignoreTransform) {
mModelView.loadInverse(*mSnapshot->transform);
}
mShader->setupProgram(mCaches.currentProgram, mModelView, *mSnapshot, &mTextureUnit);
mDrawModifiers.mShader->setupProgram(mCaches.currentProgram,
mModelView, *mSnapshot, &mTextureUnit);
}
}
void OpenGLRenderer::setupDrawShaderIdentityUniforms() {
if (mShader) {
mShader->setupProgram(mCaches.currentProgram, mIdentity, *mSnapshot, &mTextureUnit);
if (mDrawModifiers.mShader) {
mDrawModifiers.mShader->setupProgram(mCaches.currentProgram,
mIdentity, *mSnapshot, &mTextureUnit);
}
}
void OpenGLRenderer::setupDrawColorFilterUniforms() {
if (mColorFilter) {
mColorFilter->setupProgram(mCaches.currentProgram);
if (mDrawModifiers.mColorFilter) {
mDrawModifiers.mColorFilter->setupProgram(mCaches.currentProgram);
}
}
@@ -1726,21 +1782,24 @@ void OpenGLRenderer::finishDrawTexture() {
// Drawing
///////////////////////////////////////////////////////////////////////////////
status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList,
Rect& dirty, int32_t flags, uint32_t level) {
status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t flags) {
// All the usual checks and setup operations (quickReject, setupDraw, etc.)
// will be performed by the display list itself
if (displayList && displayList->isRenderable()) {
return displayList->replay(*this, dirty, flags, level);
if (CC_UNLIKELY(mDrawDeferDisabled)) {
return displayList->replay(*this, dirty, flags, 0);
}
DeferredDisplayList deferredList;
return displayList->replay(*this, dirty, flags, 0, &deferredList);
}
return DrawGlInfo::kStatusDone;
}
void OpenGLRenderer::outputDisplayList(DisplayList* displayList, uint32_t level) {
void OpenGLRenderer::outputDisplayList(DisplayList* displayList) {
if (displayList) {
displayList->output(level);
displayList->output(0);
}
}
@@ -1990,7 +2049,7 @@ status_t OpenGLRenderer::drawBitmap(SkBitmap* bitmap,
// Apply a scale transform on the canvas only when a shader is in use
// Skia handles the ratio between the dst and src rects as a scale factor
// when a shader is set
bool useScaleTransform = mShader && scaled;
bool useScaleTransform = mDrawModifiers.mShader && scaled;
bool ignoreTransform = false;
if (CC_LIKELY(mSnapshot->transform->isPureTranslate() && !useScaleTransform)) {
@@ -2445,15 +2504,15 @@ void OpenGLRenderer::drawTextShadow(SkPaint* paint, const char* text, int bytesC
// if shader-based correction is enabled
mCaches.dropShadowCache.setFontRenderer(fontRenderer);
const ShadowTexture* shadow = mCaches.dropShadowCache.get(
paint, text, bytesCount, count, mShadowRadius, positions);
paint, text, bytesCount, count, mDrawModifiers.mShadowRadius, positions);
const AutoTexture autoCleanup(shadow);
const float sx = x - shadow->left + mShadowDx;
const float sy = y - shadow->top + mShadowDy;
const float sx = x - shadow->left + mDrawModifiers.mShadowDx;
const float sy = y - shadow->top + mDrawModifiers.mShadowDy;
const int shadowAlpha = ((mShadowColor >> 24) & 0xFF) * mSnapshot->alpha;
int shadowColor = mShadowColor;
if (mShader) {
const int shadowAlpha = ((mDrawModifiers.mShadowColor >> 24) & 0xFF) * mSnapshot->alpha;
int shadowColor = mDrawModifiers.mShadowColor;
if (mDrawModifiers.mShader) {
shadowColor = 0xffffffff;
}
@@ -2501,7 +2560,7 @@ status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count
SkXfermode::Mode mode;
getAlphaAndMode(paint, &alpha, &mode);
if (CC_UNLIKELY(mHasShadow)) {
if (CC_UNLIKELY(mDrawModifiers.mHasShadow)) {
drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
alpha, mode, 0.0f, 0.0f);
}
@@ -2592,7 +2651,7 @@ status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
SkXfermode::Mode mode;
getAlphaAndMode(paint, &alpha, &mode);
if (CC_UNLIKELY(mHasShadow)) {
if (CC_UNLIKELY(mDrawModifiers.mHasShadow)) {
drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer, alpha, mode,
oldX, oldY);
}
@@ -2748,8 +2807,8 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* pain
mCaches.activeTexture(0);
if (CC_LIKELY(!layer->region.isEmpty())) {
SkiaColorFilter* oldFilter = mColorFilter;
mColorFilter = layer->getColorFilter();
SkiaColorFilter* oldFilter = mDrawModifiers.mColorFilter;
mDrawModifiers.mColorFilter = layer->getColorFilter();
if (layer->region.isRect()) {
composeLayerRect(layer, layer->regionRect);
@@ -2788,7 +2847,7 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* pain
#endif
}
mColorFilter = oldFilter;
mDrawModifiers.mColorFilter = oldFilter;
if (layer->debugDrawUpdate) {
layer->debugDrawUpdate = false;
@@ -2809,13 +2868,13 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* pain
///////////////////////////////////////////////////////////////////////////////
void OpenGLRenderer::resetShader() {
mShader = NULL;
mDrawModifiers.mShader = NULL;
}
void OpenGLRenderer::setupShader(SkiaShader* shader) {
mShader = shader;
if (mShader) {
mShader->set(&mCaches.textureCache, &mCaches.gradientCache);
mDrawModifiers.mShader = shader;
if (mDrawModifiers.mShader) {
mDrawModifiers.mShader->set(&mCaches.textureCache, &mCaches.gradientCache);
}
}
@@ -2824,11 +2883,11 @@ void OpenGLRenderer::setupShader(SkiaShader* shader) {
///////////////////////////////////////////////////////////////////////////////
void OpenGLRenderer::resetColorFilter() {
mColorFilter = NULL;
mDrawModifiers.mColorFilter = NULL;
}
void OpenGLRenderer::setupColorFilter(SkiaColorFilter* filter) {
mColorFilter = filter;
mDrawModifiers.mColorFilter = filter;
}
///////////////////////////////////////////////////////////////////////////////
@@ -2836,15 +2895,15 @@ void OpenGLRenderer::setupColorFilter(SkiaColorFilter* filter) {
///////////////////////////////////////////////////////////////////////////////
void OpenGLRenderer::resetShadow() {
mHasShadow = false;
mDrawModifiers.mHasShadow = false;
}
void OpenGLRenderer::setupShadow(float radius, float dx, float dy, int color) {
mHasShadow = true;
mShadowRadius = radius;
mShadowDx = dx;
mShadowDy = dy;
mShadowColor = color;
mDrawModifiers.mHasShadow = true;
mDrawModifiers.mShadowRadius = radius;
mDrawModifiers.mShadowDx = dx;
mDrawModifiers.mShadowDy = dy;
mDrawModifiers.mShadowColor = color;
}
///////////////////////////////////////////////////////////////////////////////
@@ -2852,22 +2911,23 @@ void OpenGLRenderer::setupShadow(float radius, float dx, float dy, int color) {
///////////////////////////////////////////////////////////////////////////////
void OpenGLRenderer::resetPaintFilter() {
mHasDrawFilter = false;
mDrawModifiers.mHasDrawFilter = false;
}
void OpenGLRenderer::setupPaintFilter(int clearBits, int setBits) {
mHasDrawFilter = true;
mPaintFilterClearBits = clearBits & SkPaint::kAllFlags;
mPaintFilterSetBits = setBits & SkPaint::kAllFlags;
mDrawModifiers.mHasDrawFilter = true;
mDrawModifiers.mPaintFilterClearBits = clearBits & SkPaint::kAllFlags;
mDrawModifiers.mPaintFilterSetBits = setBits & SkPaint::kAllFlags;
}
SkPaint* OpenGLRenderer::filterPaint(SkPaint* paint) {
if (CC_LIKELY(!mHasDrawFilter || !paint)) return paint;
if (CC_LIKELY(!mDrawModifiers.mHasDrawFilter || !paint)) return paint;
uint32_t flags = paint->getFlags();
mFilteredPaint = *paint;
mFilteredPaint.setFlags((flags & ~mPaintFilterClearBits) | mPaintFilterSetBits);
mFilteredPaint.setFlags((flags & ~mDrawModifiers.mPaintFilterClearBits) |
mDrawModifiers.mPaintFilterSetBits);
return &mFilteredPaint;
}
@@ -2967,7 +3027,7 @@ status_t OpenGLRenderer::drawRects(const float* rects, int count, SkPaint* paint
int color = paint->getColor();
// If a shader is set, preserve only the alpha
if (mShader) {
if (mDrawModifiers.mShader) {
color |= 0x00ffffff;
}
SkXfermode::Mode mode = getXfermode(paint->getXfermode());
@@ -3040,7 +3100,7 @@ status_t OpenGLRenderer::drawColorRects(const float* rects, int count, int color
void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
int color, SkXfermode::Mode mode, bool ignoreTransform) {
// If a shader is set, preserve only the alpha
if (mShader) {
if (mDrawModifiers.mShader) {
color |= 0x00ffffff;
}

View File

@@ -48,6 +48,34 @@
namespace android {
namespace uirenderer {
struct DrawModifiers {
SkiaShader* mShader;
SkiaColorFilter* mColorFilter;
// Drop shadow
bool mHasShadow;
float mShadowRadius;
float mShadowDx;
float mShadowDy;
int mShadowColor;
// Draw filters
bool mHasDrawFilter;
int mPaintFilterClearBits;
int mPaintFilterSetBits;
};
struct DeferredDisplayState {
Rect mBounds; // local bounds, mapped with matrix to be in screen space coordinates, clipped.
int mMultipliedAlpha; // -1 if invalid (because caching not set)
// the below are set and used by the OpenGLRenderer at record and deferred playback
Rect mClip;
mat4 mMatrix;
SkiaShader* mShader;
DrawModifiers mDrawModifiers;
};
///////////////////////////////////////////////////////////////////////////////
// Renderer
///////////////////////////////////////////////////////////////////////////////
@@ -182,9 +210,8 @@ public:
virtual bool clipRegion(SkRegion* region, SkRegion::Op op);
virtual Rect* getClipRect();
virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t flags,
uint32_t level = 0);
virtual void outputDisplayList(DisplayList* displayList, uint32_t level = 0);
virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t flags);
virtual void outputDisplayList(DisplayList* displayList);
virtual status_t drawLayer(Layer* layer, float x, float y, SkPaint* paint);
virtual status_t drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
virtual status_t drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
@@ -233,6 +260,23 @@ public:
SkPaint* filterPaint(SkPaint* paint);
bool disallowDeferral() {
// returns true if the OpenGLRenderer's state can be completely represented by
// a DeferredDisplayState object
return !mSnapshot->clipRegion->isEmpty() ||
mSnapshot->alpha < 1.0 ||
(mSnapshot->flags & Snapshot::kFlagIsLayer) ||
(mSnapshot->flags & Snapshot::kFlagFboTarget); // ensure we're not in a layer
}
bool disallowReorder() { return mDrawReorderDisabled; }
bool storeDisplayState(DeferredDisplayState& state);
void restoreDisplayState(const DeferredDisplayState& state);
const DrawModifiers& getDrawModifiers() { return mDrawModifiers; }
void setDrawModifiers(const DrawModifiers& drawModifiers) { mDrawModifiers = drawModifiers; }
ANDROID_API bool isCurrentTransformSimple() {
return mSnapshot->transform->isSimple();
}
@@ -868,26 +912,11 @@ private:
// State used to define the clipping region
sp<Snapshot> mTilingSnapshot;
// Shaders
SkiaShader* mShader;
// Color filters
SkiaColorFilter* mColorFilter;
// Used to draw textured quads
TextureVertex mMeshVertices[4];
// Drop shadow
bool mHasShadow;
float mShadowRadius;
float mShadowDx;
float mShadowDy;
int mShadowColor;
// Draw filters
bool mHasDrawFilter;
int mPaintFilterClearBits;
int mPaintFilterSetBits;
// shader, filters, and shadow
DrawModifiers mDrawModifiers;
SkPaint mFilteredPaint;
// Various caches
@@ -925,6 +954,8 @@ private:
// See PROPERTY_DISABLE_SCISSOR_OPTIMIZATION in
// Properties.h
bool mScissorOptimizationDisabled;
bool mDrawDeferDisabled;
bool mDrawReorderDisabled;
// No-ops start/endTiling when set
bool mSuppressTiling;

View File

@@ -82,6 +82,19 @@ enum DebugLevel {
*/
#define PROPERTY_DISABLE_SCISSOR_OPTIMIZATION "ro.hwui.disable_scissor_opt"
/**
* Disables draw operation deferral if set to "true", forcing draw
* commands to be issued to OpenGL in order, and processed in sequence
* with state-manipulation canvas commands.
*/
#define PROPERTY_DISABLE_DRAW_DEFER "debug.hwui.disable_draw_defer"
/**
* Used to disable draw operation reordering when deferring draw operations
* Has no effect if PROPERTY_DISABLE_DRAW_DEFER is set to "true"
*/
#define PROPERTY_DISABLE_DRAW_REORDER "debug.hwui.disable_draw_reorder"
// These properties are defined in mega-bytes
#define PROPERTY_TEXTURE_CACHE_SIZE "ro.hwui.texture_cache_size"
#define PROPERTY_LAYER_CACHE_SIZE "ro.hwui.layer_cache_size"

View File

@@ -159,6 +159,13 @@ public:
bottom += dy;
}
void outset(float delta) {
left -= delta;
top -= delta;
right += delta;
bottom += delta;
}
void snapToPixelBoundaries() {
left = floorf(left + 0.5f);
top = floorf(top + 0.5f);