am f40b8a93: Merge "Fully deferred displaylist replay" into jb-mr2-dev

* commit 'f40b8a939fef0a19b40188f007a3364311d6dabf':
  Fully deferred displaylist replay
This commit is contained in:
Chris Craik
2013-03-15 22:55:54 +00:00
committed by Android Git Automerger
10 changed files with 737 additions and 363 deletions

View File

@@ -103,14 +103,9 @@ void Caches::initFont() {
void Caches::initExtensions() {
if (mExtensions.hasDebugMarker()) {
eventMark = glInsertEventMarkerEXT;
if ((drawDeferDisabled || drawReorderDisabled)) {
startMark = glPushGroupMarkerEXT;
endMark = glPopGroupMarkerEXT;
} else {
startMark = startMarkNull;
endMark = endMarkNull;
}
startMark = glPushGroupMarkerEXT;
endMark = glPopGroupMarkerEXT;
} else {
eventMark = eventMarkNull;
startMark = startMarkNull;

View File

@@ -32,15 +32,15 @@
namespace android {
namespace uirenderer {
/////////////////////////////////////////////////////////////////////////////////
// Operation Batches
/////////////////////////////////////////////////////////////////////////////////
class DrawOpBatch {
public:
DrawOpBatch() {
mOps.clear();
}
DrawOpBatch() { mOps.clear(); }
~DrawOpBatch() {
mOps.clear();
}
virtual ~DrawOpBatch() { mOps.clear(); }
void add(DrawOp* op) {
// NOTE: ignore empty bounds special case, since we don't merge across those ops
@@ -48,8 +48,9 @@ public:
mOps.add(op);
}
bool intersects(Rect& rect) {
virtual 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
@@ -64,27 +65,217 @@ public:
return false;
}
Vector<DrawOp*> mOps;
virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty) {
DEFER_LOGD("replaying draw batch %p", this);
status_t status = DrawGlInfo::kStatusDone;
DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
for (unsigned int i = 0; i < mOps.size(); i++) {
DrawOp* op = mOps[i];
renderer.restoreDisplayState(op->state, kStateDeferFlag_Draw);
#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
renderer.eventMark(strlen(op->name()), op->name());
#endif
status |= op->applyDraw(renderer, dirty, 0, op->state.mMultipliedAlpha);
logBuffer.writeCommand(0, op->name());
}
return status;
}
inline int count() const { return mOps.size(); }
private:
Vector<DrawOp*> mOps;
Rect mBounds;
};
void DeferredDisplayList::clear() {
class StateOpBatch : public DrawOpBatch {
public:
// creates a single operation batch
StateOpBatch(StateOp* op) : mOp(op) {}
bool intersects(Rect& rect) {
// if something checks for intersection, it's trying to go backwards across a state op,
// something not currently supported - state ops are always barriers
CRASH();
return false;
}
virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty) {
DEFER_LOGD("replaying state op batch %p", this);
renderer.restoreDisplayState(mOp->state, 0);
// use invalid save count because it won't be used at flush time - RestoreToCountOp is the
// only one to use it, and we don't use that class at flush time, instead calling
// renderer.restoreToCount directly
int saveCount = -1;
mOp->applyState(renderer, saveCount);
return DrawGlInfo::kStatusDone;
}
private:
StateOp* mOp;
};
class RestoreToCountBatch : public DrawOpBatch {
public:
RestoreToCountBatch(int restoreCount) : mRestoreCount(restoreCount) {}
bool intersects(Rect& rect) {
// if something checks for intersection, it's trying to go backwards across a state op,
// something not currently supported - state ops are always barriers
CRASH();
return false;
}
virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty) {
DEFER_LOGD("batch %p restoring to count %d", this, mRestoreCount);
renderer.restoreToCount(mRestoreCount);
return DrawGlInfo::kStatusDone;
}
private:
/*
* The count used here represents the flush() time saveCount. This is as opposed to the
* DisplayList record time, or defer() time values (which are RestoreToCountOp's mCount, and
* (saveCount + mCount) respectively). Since the count is different from the original
* RestoreToCountOp, we don't store a pointer to the op, as elsewhere.
*/
const int mRestoreCount;
};
/////////////////////////////////////////////////////////////////////////////////
// DeferredDisplayList
/////////////////////////////////////////////////////////////////////////////////
void DeferredDisplayList::resetBatchingState() {
for (int i = 0; i < kOpBatch_Count; i++) {
mBatchIndices[i] = -1;
}
}
void DeferredDisplayList::clear() {
resetBatchingState();
mComplexClipStackStart = -1;
for (unsigned int i = 0; i < mBatches.size(); i++) {
delete mBatches[i];
}
mBatches.clear();
mSaveStack.clear();
}
void DeferredDisplayList::add(DrawOp* op, bool disallowReorder) {
if (CC_UNLIKELY(disallowReorder)) {
if (!mBatches.isEmpty()) {
mBatches[0]->add(op);
return;
/////////////////////////////////////////////////////////////////////////////////
// Operation adding
/////////////////////////////////////////////////////////////////////////////////
int DeferredDisplayList::getStateOpDeferFlags() const {
// For both clipOp and save(Layer)Op, we don't want to save drawing info, and only want to save
// the clip if we aren't recording a complex clip (and can thus trust it to be a rect)
return recordingComplexClip() ? 0 : kStateDeferFlag_Clip;
}
int DeferredDisplayList::getDrawOpDeferFlags() const {
return kStateDeferFlag_Draw | getStateOpDeferFlags();
}
/**
* When an clipping operation occurs that could cause a complex clip, record the operation and all
* subsequent clipOps, save/restores (if the clip flag is set). During a flush, instead of loading
* the clip from deferred state, we play back all of the relevant state operations that generated
* the complex clip.
*
* Note that we don't need to record the associated restore operation, since operations at defer
* time record whether they should store the renderer's current clip
*/
void DeferredDisplayList::addClip(OpenGLRenderer& renderer, ClipOp* op) {
if (recordingComplexClip() || op->canCauseComplexClip() || !renderer.hasRectToRectTransform()) {
DEFER_LOGD("%p Received complex clip operation %p", this, op);
// NOTE: defer clip op before setting mComplexClipStackStart so previous clip is recorded
storeStateOpBarrier(renderer, op);
if (!recordingComplexClip()) {
mComplexClipStackStart = renderer.getSaveCount() - 1;
DEFER_LOGD(" Starting complex clip region, start is %d", mComplexClipStackStart);
}
}
}
/**
* For now, we record save layer operations as barriers in the batch list, preventing drawing
* operations from reordering around the saveLayer and it's associated restore()
*
* In the future, we should send saveLayer commands (if they can be played out of order) and their
* contained drawing operations to a seperate list of batches, so that they may draw at the
* beginning of the frame. This would avoid targetting and removing an FBO in the middle of a frame.
*
* saveLayer operations should be pulled to the beginning of the frame if the canvas doesn't have a
* complex clip, and if the flags (kClip_SaveFlag & kClipToLayer_SaveFlag) are set.
*/
void DeferredDisplayList::addSaveLayer(OpenGLRenderer& renderer,
SaveLayerOp* op, int newSaveCount) {
DEFER_LOGD("%p adding saveLayerOp %p, flags %x, new count %d",
this, op, op->getFlags(), newSaveCount);
storeStateOpBarrier(renderer, op);
mSaveStack.push(newSaveCount);
}
/**
* Takes save op and it's return value - the new save count - and stores it into the stream as a
* barrier if it's needed to properly modify a complex clip
*/
void DeferredDisplayList::addSave(OpenGLRenderer& renderer, SaveOp* op, int newSaveCount) {
int saveFlags = op->getFlags();
DEFER_LOGD("%p adding saveOp %p, flags %x, new count %d", this, op, saveFlags, newSaveCount);
if (recordingComplexClip() && (saveFlags & SkCanvas::kClip_SaveFlag)) {
// store and replay the save operation, as it may be needed to correctly playback the clip
DEFER_LOGD(" adding save barrier with new save count %d", newSaveCount);
storeStateOpBarrier(renderer, op);
mSaveStack.push(newSaveCount);
}
}
/**
* saveLayer() commands must be associated with a restoreToCount batch that will clean up and draw
* the layer in the deferred list
*
* other save() commands which occur as children of a snapshot with complex clip will be deferred,
* and must be restored
*
* Either will act as a barrier to draw operation reordering, as we want to play back layer
* save/restore and complex canvas modifications (including save/restore) in order.
*/
void DeferredDisplayList::addRestoreToCount(OpenGLRenderer& renderer, int newSaveCount) {
DEFER_LOGD("%p addRestoreToCount %d", this, newSaveCount);
if (recordingComplexClip() && newSaveCount <= mComplexClipStackStart) {
mComplexClipStackStart = -1;
resetBatchingState();
}
if (mSaveStack.isEmpty() || newSaveCount > mSaveStack.top()) {
return;
}
while (!mSaveStack.isEmpty() && mSaveStack.top() >= newSaveCount) mSaveStack.pop();
storeRestoreToCountBarrier(mSaveStack.size() + 1);
}
void DeferredDisplayList::addDrawOp(OpenGLRenderer& renderer, DrawOp* op) {
if (renderer.storeDisplayState(op->state, getDrawOpDeferFlags())) {
return; // quick rejected
}
op->onDrawOpDeferred(renderer);
if (CC_UNLIKELY(renderer.getCaches().drawReorderDisabled)) {
// TODO: elegant way to reuse batches?
DrawOpBatch* b = new DrawOpBatch();
b->add(op);
mBatches.add(b);
@@ -138,9 +329,41 @@ void DeferredDisplayList::add(DrawOp* op, bool disallowReorder) {
targetBatch->add(op);
}
status_t DeferredDisplayList::flush(OpenGLRenderer& renderer, Rect& dirty, int32_t flags,
uint32_t level) {
ATRACE_CALL();
void DeferredDisplayList::storeStateOpBarrier(OpenGLRenderer& renderer, StateOp* op) {
DEFER_LOGD("%p adding state op barrier at pos %d", this, mBatches.size());
renderer.storeDisplayState(op->state, getStateOpDeferFlags());
mBatches.add(new StateOpBatch(op));
resetBatchingState();
}
void DeferredDisplayList::storeRestoreToCountBarrier(int newSaveCount) {
DEFER_LOGD("%p adding restore to count %d barrier, pos %d",
this, newSaveCount, mBatches.size());
mBatches.add(new RestoreToCountBatch(newSaveCount));
resetBatchingState();
}
/////////////////////////////////////////////////////////////////////////////////
// Replay / flush
/////////////////////////////////////////////////////////////////////////////////
static status_t replayBatchList(Vector<DrawOpBatch*>& batchList,
OpenGLRenderer& renderer, Rect& dirty) {
status_t status = DrawGlInfo::kStatusDone;
int opCount = 0;
for (unsigned int i = 0; i < batchList.size(); i++) {
status |= batchList[i]->replay(renderer, dirty);
opCount += batchList[i]->count();
}
DEFER_LOGD("--flushed, drew %d batches (total %d ops)", batchList.size(), opCount);
return status;
}
status_t DeferredDisplayList::flush(OpenGLRenderer& renderer, Rect& dirty) {
ATRACE_NAME("flush drawing commands");
status_t status = DrawGlInfo::kStatusDone;
if (isEmpty()) return status; // nothing to flush
@@ -148,29 +371,12 @@ status_t DeferredDisplayList::flush(OpenGLRenderer& renderer, Rect& dirty, int32
DEFER_LOGD("--flushing");
renderer.eventMark("Flush");
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.restoreToCount(1);
renderer.restoreDisplayState(op->state);
status |= replayBatchList(mBatches, renderer, dirty);
#if DEBUG_DEFER
op->output(2);
#endif
status |= op->applyDraw(renderer, dirty, level,
op->state.mMultipliedAlpha >= 0, op->state.mMultipliedAlpha);
opCount++;
}
}
DEFER_LOGD("--flush complete, returning %x", status);
DEFER_LOGD("--flushed, drew %d batches (total %d ops)", mBatches.size(), opCount);
renderer.restoreToCount(restoreTo);
renderer.setDrawModifiers(restoreDrawModifiers);
clear();
return status;
}

View File

@@ -26,10 +26,13 @@
namespace android {
namespace uirenderer {
class ClipOp;
class DrawOp;
class SaveOp;
class SaveLayerOp;
class StateOp;
class DrawOpBatch;
class OpenGLRenderer;
class SkiaShader;
class DeferredDisplayList {
public:
@@ -55,18 +58,42 @@ public:
* 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);
status_t flush(OpenGLRenderer& renderer, Rect& dirty);
void addClip(OpenGLRenderer& renderer, ClipOp* op);
void addSaveLayer(OpenGLRenderer& renderer, SaveLayerOp* op, int newSaveCount);
void addSave(OpenGLRenderer& renderer, SaveOp* op, int newSaveCount);
void addRestoreToCount(OpenGLRenderer& renderer, int newSaveCount);
/**
* 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);
void addDrawOp(OpenGLRenderer& renderer, DrawOp* op);
private:
/*
* Resets the batching back-pointers, creating a barrier in the operation stream so that no ops
* added in the future will be inserted into a batch that already exist.
*/
void resetBatchingState();
void clear();
void storeStateOpBarrier(OpenGLRenderer& renderer, StateOp* op);
void storeRestoreToCountBarrier(int newSaveCount);
bool recordingComplexClip() const { return mComplexClipStackStart >= 0; }
int getStateOpDeferFlags() const;
int getDrawOpDeferFlags() const;
/*
*
* at defer time, stores the savecount of save/saveLayer ops that were
*/
Vector<int> mSaveStack;
int mComplexClipStackStart;
Vector<DrawOpBatch*> mBatches;
int mBatchIndices[kOpBatch_Count];

View File

@@ -61,6 +61,12 @@ void DisplayList::destroyDisplayListDeferred(DisplayList* displayList) {
void DisplayList::clearResources() {
mDisplayListData = NULL;
mClipRectOp = NULL;
mSaveLayerOp = NULL;
mSaveOp = NULL;
mRestoreToCountOp = NULL;
delete mTransformMatrix;
delete mTransformCamera;
delete mTransformMatrix3D;
@@ -156,6 +162,13 @@ void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorde
return;
}
// allocate reusable ops for state-deferral
LinearAllocator& alloc = mDisplayListData->allocator;
mClipRectOp = new (alloc) ClipRectOp();
mSaveLayerOp = new (alloc) SaveLayerOp();
mSaveOp = new (alloc) SaveOp();
mRestoreToCountOp = new (alloc) RestoreToCountOp();
mFunctorCount = recorder.getFunctorCount();
Caches& caches = Caches::getInstance();
@@ -318,7 +331,7 @@ void DisplayList::updateMatrix() {
}
}
void DisplayList::outputViewProperties(uint32_t level) {
void DisplayList::outputViewProperties(const int level) {
updateMatrix();
if (mLeft != 0 || mTop != 0) {
ALOGD("%*sTranslate (left, top) %d, %d", level * 2, "", mLeft, mTop);
@@ -358,10 +371,17 @@ void DisplayList::outputViewProperties(uint32_t level) {
}
}
status_t DisplayList::setViewProperties(OpenGLRenderer& renderer, Rect& dirty,
int32_t flags, uint32_t level, DeferredDisplayList* deferredList) {
status_t status = DrawGlInfo::kStatusDone;
#if DEBUG_DISPLAYLIST
/*
* For property operations, we pass a savecount of 0, since the operations aren't part of the
* displaylist, and thus don't have to compensate for the record-time/playback-time discrepancy in
* base saveCount (i.e., how RestoreToCount uses saveCount + mCount)
*/
#define PROPERTY_SAVECOUNT 0
template <class T>
void DisplayList::setViewProperties(OpenGLRenderer& renderer, T& handler,
const int level) {
#if DEBUG_DISPLAY_LIST
outputViewProperties(level);
#endif
updateMatrix();
@@ -381,86 +401,121 @@ status_t DisplayList::setViewProperties(OpenGLRenderer& renderer, Rect& dirty,
}
}
if (mAlpha < 1 && !mCaching) {
if (deferredList) {
// flush since we'll either enter a Layer, or set alpha, both not supported in deferral
status |= deferredList->flush(renderer, dirty, flags, level);
}
if (!mHasOverlappingRendering) {
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;
int saveFlags = SkCanvas::kHasAlphaLayer_SaveFlag;
if (mClipChildren) {
flags |= SkCanvas::kClipToLayer_SaveFlag;
saveFlags |= SkCanvas::kClipToLayer_SaveFlag;
}
renderer.saveLayerAlpha(0, 0, mRight - mLeft, mBottom - mTop,
mMultipliedAlpha, flags);
handler(mSaveLayerOp->reinit(0, 0, mRight - mLeft, mBottom - mTop,
mMultipliedAlpha, SkXfermode::kSrcOver_Mode, saveFlags), PROPERTY_SAVECOUNT);
}
}
if (mClipChildren && !mCaching) {
if (deferredList && CC_UNLIKELY(!renderer.hasRectToRectTransform())) {
// flush, since clip will likely be a region
status |= deferredList->flush(renderer, dirty, flags, level);
}
renderer.clipRect(0, 0, mRight - mLeft, mBottom - mTop,
SkRegion::kIntersect_Op);
handler(mClipRectOp->reinit(0, 0, mRight - mLeft, mBottom - mTop, SkRegion::kIntersect_Op),
PROPERTY_SAVECOUNT);
}
return status;
}
status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level,
DeferredDisplayList* deferredList) {
status_t drawGlStatus = DrawGlInfo::kStatusDone;
class DeferOperationHandler {
public:
DeferOperationHandler(DeferStateStruct& deferStruct, int multipliedAlpha, int level)
: mDeferStruct(deferStruct), mMultipliedAlpha(multipliedAlpha), mLevel(level) {}
inline void operator()(DisplayListOp* operation, int saveCount) {
operation->defer(mDeferStruct, saveCount, mLevel, mMultipliedAlpha);
}
private:
DeferStateStruct& mDeferStruct;
const int mMultipliedAlpha;
const int mLevel;
};
void DisplayList::defer(DeferStateStruct& deferStruct, const int level) {
DeferOperationHandler handler(deferStruct, mCaching ? mMultipliedAlpha : -1, level);
iterate<DeferOperationHandler>(deferStruct.mRenderer, handler, level);
}
class ReplayOperationHandler {
public:
ReplayOperationHandler(ReplayStateStruct& replayStruct, int multipliedAlpha, int level)
: mReplayStruct(replayStruct), mMultipliedAlpha(multipliedAlpha), mLevel(level) {}
inline void operator()(DisplayListOp* operation, int saveCount) {
#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
replayStruct.mRenderer.eventMark(operation->name());
#endif
operation->replay(mReplayStruct, saveCount, mLevel, mMultipliedAlpha);
}
private:
ReplayStateStruct& mReplayStruct;
const int mMultipliedAlpha;
const int mLevel;
};
void DisplayList::replay(ReplayStateStruct& replayStruct, const int level) {
ReplayOperationHandler handler(replayStruct, mCaching ? mMultipliedAlpha : -1, level);
replayStruct.mRenderer.startMark(mName.string());
iterate<ReplayOperationHandler>(replayStruct.mRenderer, handler, level);
replayStruct.mRenderer.endMark();
DISPLAY_LIST_LOGD("%*sDone (%p, %s), returning %d", level * 2, "", this, mName.string(),
replayStruct.mDrawGlStatus);
}
/**
* This function serves both defer and replay modes, and will organize the displayList's component
* operations for a single frame:
*
* Every 'simple' operation that affects just the matrix and alpha (or other factors of
* DeferredDisplayState) may be issued directly to the renderer, but complex operations (with custom
* defer logic) and operations in displayListOps are issued through the 'handler' which handles the
* defer vs replay logic, per operation
*/
template <class T>
void DisplayList::iterate(OpenGLRenderer& renderer, T& handler, const int level) {
if (mSize == 0 || mAlpha <= 0) {
DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, mName.string());
return;
}
#if DEBUG_DISPLAY_LIST
Rect* clipRect = renderer.getClipRect();
DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), clipRect: %.0f, %.f, %.0f, %.0f",
(level+1)*2, "", this, mName.string(), clipRect->left, clipRect->top,
level * 2, "", this, mName.string(), clipRect->left, clipRect->top,
clipRect->right, clipRect->bottom);
#endif
renderer.startMark(mName.string());
int restoreTo = renderer.getSaveCount();
handler(mSaveOp->reinit(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag),
PROPERTY_SAVECOUNT);
int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
DISPLAY_LIST_LOGD("%*sSave %d %d", level * 2, "",
DISPLAY_LIST_LOGD("%*sSave %d %d", (level + 1) * 2, "",
SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo);
drawGlStatus |= setViewProperties(renderer, dirty, flags, level, deferredList);
setViewProperties<T>(renderer, handler, level + 1);
if (renderer.quickRejectNoScissor(0, 0, mWidth, mHeight)) {
DISPLAY_LIST_LOGD("%*sRestoreToCount %d", level * 2, "", restoreTo);
renderer.restoreToCount(restoreTo);
renderer.endMark();
return drawGlStatus;
handler(mRestoreToCountOp->reinit(restoreTo), PROPERTY_SAVECOUNT);
return;
}
DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
int saveCount = renderer.getSaveCount() - 1;
for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
DisplayListOp *op = mDisplayListData->displayListOps[i];
#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
renderer.eventMark(strlen(op->name()), op->name());
#endif
drawGlStatus |= op->replay(renderer, dirty, flags,
saveCount, level, mCaching, mMultipliedAlpha, deferredList);
handler(op, saveCount);
logBuffer.writeCommand(level, op->name());
}
DISPLAY_LIST_LOGD("%*sRestoreToCount %d", level * 2, "", restoreTo);
DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo);
handler(mRestoreToCountOp->reinit(restoreTo), PROPERTY_SAVECOUNT);
renderer.restoreToCount(restoreTo);
renderer.endMark();
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;
}
}; // namespace uirenderer

View File

@@ -24,6 +24,8 @@
#include <SkCamera.h>
#include <SkMatrix.h>
#include <private/hwui/DrawGlInfo.h>
#include <utils/RefBase.h>
#include <utils/SortedVector.h>
#include <utils/String8.h>
@@ -57,10 +59,33 @@ class Layer;
class SkiaColorFilter;
class SkiaShader;
class ClipRectOp;
class SaveLayerOp;
class SaveOp;
class RestoreToCountOp;
struct DeferStateStruct {
DeferStateStruct(DeferredDisplayList& deferredList, OpenGLRenderer& renderer, int replayFlags)
: mDeferredList(deferredList), mRenderer(renderer), mReplayFlags(replayFlags) {}
DeferredDisplayList& mDeferredList;
OpenGLRenderer& mRenderer;
const int mReplayFlags;
};
struct ReplayStateStruct {
ReplayStateStruct(OpenGLRenderer& renderer, Rect& dirty, int replayFlags)
: mRenderer(renderer), mDirty(dirty), mReplayFlags(replayFlags),
mDrawGlStatus(DrawGlInfo::kStatusDone) {}
OpenGLRenderer& mRenderer;
Rect& mDirty;
const int mReplayFlags;
status_t mDrawGlStatus;
};
/**
* Refcounted structure that holds data used in display list stream
*/
class DisplayListData: public LightRefBase<DisplayListData> {
class DisplayListData : public LightRefBase<DisplayListData> {
public:
LinearAllocator allocator;
Vector<DisplayListOp*> displayListOps;
@@ -79,9 +104,6 @@ public:
kReplayFlag_ClipChildren = 0x1
};
status_t setViewProperties(OpenGLRenderer& renderer, Rect& dirty,
int32_t flags, uint32_t level, DeferredDisplayList* deferredList);
void outputViewProperties(uint32_t level);
ANDROID_API size_t getSize();
ANDROID_API static void destroyDisplayListDeferred(DisplayList* displayList);
@@ -89,8 +111,9 @@ public:
void initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing = false);
status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level = 0,
DeferredDisplayList* deferredList = NULL);
void defer(DeferStateStruct& deferStruct, const int level);
void replay(ReplayStateStruct& replayStruct, const int level);
void output(uint32_t level = 0);
@@ -426,6 +449,14 @@ public:
}
private:
void outputViewProperties(const int level);
template <class T>
inline void setViewProperties(OpenGLRenderer& renderer, T& handler, const int level);
template <class T>
inline void iterate(OpenGLRenderer& renderer, T& handler, const int level);
void init();
void clearResources();
@@ -490,6 +521,22 @@ private:
SkMatrix* mStaticMatrix;
SkMatrix* mAnimationMatrix;
bool mCaching;
/**
* State operations - needed to defer displayList property operations (for example, when setting
* an alpha causes a SaveLayerAlpha to occur). These operations point into mDisplayListData's
* allocation, or null if uninitialized.
*
* These are initialized (via friend constructors) when a displayList is issued in either replay
* or deferred mode. If replaying, the ops are not used until the next frame. If deferring, the
* ops may be stored in the DeferredDisplayList to be played back a second time.
*
* They should be used at most once per frame (one call to iterate)
*/
ClipRectOp* mClipRectOp;
SaveLayerOp* mSaveLayerOp;
SaveOp* mSaveOp;
RestoreToCountOp* mRestoreToCountOp;
}; // class DisplayList
}; // namespace uirenderer

View File

@@ -78,17 +78,26 @@ public:
kOpLogFlag_JSON = 0x2 // TODO: add?
};
// If a DeferredDisplayList is supplied, DrawOps will be stored until the list is flushed
// NOTE: complex clips and layers 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 defer(DeferStateStruct& deferStruct, int saveCount,
int level, int multipliedAlpha) = 0;
virtual void output(int level, uint32_t flags = 0) = 0;
virtual void replay(ReplayStateStruct& replayStruct, int saveCount,
int level, int multipliedAlpha) = 0;
virtual void output(int level, uint32_t logFlags = 0) = 0;
// NOTE: it would be nice to declare constants and overriding the implementation in each op to
// point at the constants, but that seems to require a .cpp file
virtual const char* name() = 0;
/**
* Stores the relevant canvas state of the object between deferral and replay (if the canvas
* state supports being stored) See OpenGLRenderer::simpleClipAndState()
*
* TODO: don't reserve space for StateOps that won't be deferred
*/
DeferredDisplayState state;
};
class StateOp : public DisplayListOp {
@@ -97,28 +106,22 @@ public:
virtual ~StateOp() {}
virtual void defer(DeferStateStruct& deferStruct, int saveCount,
int level, int multipliedAlpha) {
// default behavior only affects immediate, deferrable state, issue directly to renderer
applyState(deferStruct.mRenderer, saveCount);
}
/**
* 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 (deferredList && requiresDrawOpFlush(renderer)) {
// 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 replay(ReplayStateStruct& replayStruct, int saveCount,
int level, int multipliedAlpha) {
applyState(replayStruct.mRenderer, saveCount);
}
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(OpenGLRenderer& renderer) { return false; }
};
class DrawOp : public DisplayListOp {
@@ -126,36 +129,35 @@ public:
DrawOp(SkPaint* paint)
: mPaint(paint), mQuickRejected(false) {}
/** 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;
virtual void defer(DeferStateStruct& deferStruct, int saveCount,
int level, int multipliedAlpha) {
if (mQuickRejected &&
CC_LIKELY(deferStruct.mReplayFlags & DisplayList::kReplayFlag_ClipChildren)) {
return;
}
if (!deferredList || 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.getCaches().drawReorderDisabled);
onDrawOpDeferred(renderer);
}
return DrawGlInfo::kStatusDone;
deferStruct.mDeferredList.addDrawOp(deferStruct.mRenderer, this);
}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
bool caching, int multipliedAlpha) = 0;
virtual void replay(ReplayStateStruct& replayStruct, int saveCount,
int level, int multipliedAlpha) {
if (mQuickRejected &&
CC_LIKELY(replayStruct.mReplayFlags & DisplayList::kReplayFlag_ClipChildren)) {
return;
}
replayStruct.mDrawGlStatus |= applyDraw(replayStruct.mRenderer, replayStruct.mDirty,
level, multipliedAlpha);
}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
int multipliedAlpha) = 0;
virtual void onDrawOpDeferred(OpenGLRenderer& renderer) {
}
@@ -174,11 +176,6 @@ public:
float strokeWidthOutset() { return mPaint->getStrokeWidth() * 0.5f; }
/**
* 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, bool alwaysCopy = false) {
return renderer.filterPaint(mPaint, alwaysCopy);
@@ -225,88 +222,113 @@ protected:
///////////////////////////////////////////////////////////////////////////////
class SaveOp : public StateOp {
friend class DisplayList; // give DisplayList private constructor/reinit access
public:
SaveOp(int flags)
: mFlags(flags) {}
virtual void defer(DeferStateStruct& deferStruct, int saveCount,
int level, int multipliedAlpha) {
int newSaveCount = deferStruct.mRenderer.save(mFlags);
deferStruct.mDeferredList.addSave(deferStruct.mRenderer, this, newSaveCount);
}
virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
renderer.save(mFlags);
}
virtual void output(int level, uint32_t flags = 0) {
virtual void output(int level, uint32_t logFlags) {
OP_LOG("Save flags %x", mFlags);
}
virtual const char* name() { return "Save"; }
int getFlags() const { return mFlags; }
private:
SaveOp() {}
DisplayListOp* reinit(int flags) {
mFlags = flags;
return this;
}
int mFlags;
};
class RestoreToCountOp : public StateOp {
friend class DisplayList; // give DisplayList private constructor/reinit access
public:
RestoreToCountOp(int count)
: mCount(count) {}
virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
renderer.restoreToCount(saveCount + mCount);
virtual void defer(DeferStateStruct& deferStruct, int saveCount,
int level, int multipliedAlpha) {
deferStruct.mDeferredList.addRestoreToCount(deferStruct.mRenderer, saveCount + mCount);
deferStruct.mRenderer.restoreToCount(saveCount + mCount);
}
virtual void output(int level, uint32_t flags = 0) {
virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
renderer.restoreToCount(saveCount + mCount);
}
virtual void output(int level, uint32_t logFlags) {
OP_LOG("Restore to count %d", mCount);
}
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:
RestoreToCountOp() {}
DisplayListOp* reinit(int count) {
mCount = count;
return this;
}
int mCount;
};
class SaveLayerOp : public StateOp {
friend class DisplayList; // give DisplayList private constructor/reinit access
public:
SaveLayerOp(float left, float top, float right, float bottom, SkPaint* paint, int flags)
: mArea(left, top, right, bottom), mPaint(paint), mFlags(flags) {}
SaveLayerOp(float left, float top, float right, float bottom,
int alpha, SkXfermode::Mode mode, int flags)
: mArea(left, top, right, bottom), mAlpha(alpha), mMode(mode), mFlags(flags) {}
virtual void defer(DeferStateStruct& deferStruct, int saveCount,
int level, int multipliedAlpha) {
// NOTE: don't bother with actual saveLayer, instead issuing it at flush time
int newSaveCount = deferStruct.mRenderer.save(mFlags);
deferStruct.mDeferredList.addSaveLayer(deferStruct.mRenderer, this, newSaveCount);
}
virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
SkPaint* paint = renderer.filterPaint(mPaint);
renderer.saveLayer(mArea.left, mArea.top, mArea.right, mArea.bottom, paint, mFlags);
renderer.saveLayer(mArea.left, mArea.top, mArea.right, mArea.bottom, mAlpha, mMode, mFlags);
}
virtual void output(int level, uint32_t flags = 0) {
OP_LOG("SaveLayer of area " RECT_STRING, RECT_ARGS(mArea));
virtual void output(int level, uint32_t logFlags) {
OP_LOG("SaveLayer%s of area " RECT_STRING,
(isSaveLayerAlpha() ? "Alpha" : ""),RECT_ARGS(mArea));
}
virtual const char* name() { return "SaveLayer"; }
virtual bool requiresDrawOpFlush(OpenGLRenderer& renderer) { return true; }
virtual const char* name() { return isSaveLayerAlpha() ? "SaveLayerAlpha" : "SaveLayer"; }
int getFlags() { return mFlags; }
private:
Rect mArea;
SkPaint* mPaint;
int mFlags;
};
class SaveLayerAlphaOp : public StateOp {
public:
SaveLayerAlphaOp(float left, float top, float right, float bottom, int alpha, int flags)
: mArea(left, top, right, bottom), mAlpha(alpha), mFlags(flags) {}
virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
renderer.saveLayerAlpha(mArea.left, mArea.top, mArea.right, mArea.bottom, mAlpha, mFlags);
// Special case, reserved for direct DisplayList usage
SaveLayerOp() {}
DisplayListOp* reinit(float left, float top, float right, float bottom,
int alpha, SkXfermode::Mode mode, int flags) {
mArea.set(left, top, right, bottom);
mAlpha = alpha;
mMode = mode;
mFlags = flags;
return this;
}
virtual void output(int level, uint32_t flags = 0) {
OP_LOG("SaveLayerAlpha of area " RECT_STRING, RECT_ARGS(mArea));
}
virtual const char* name() { return "SaveLayerAlpha"; }
virtual bool requiresDrawOpFlush(OpenGLRenderer& renderer) { return true; }
private:
bool isSaveLayerAlpha() { return mAlpha < 255 && mMode == SkXfermode::kSrcOver_Mode; }
Rect mArea;
int mAlpha;
SkXfermode::Mode mMode;
int mFlags;
};
@@ -319,7 +341,7 @@ public:
renderer.translate(mDx, mDy);
}
virtual void output(int level, uint32_t flags = 0) {
virtual void output(int level, uint32_t logFlags) {
OP_LOG("Translate by %f %f", mDx, mDy);
}
@@ -339,7 +361,7 @@ public:
renderer.rotate(mDegrees);
}
virtual void output(int level, uint32_t flags = 0) {
virtual void output(int level, uint32_t logFlags) {
OP_LOG("Rotate by %f degrees", mDegrees);
}
@@ -358,7 +380,7 @@ public:
renderer.scale(mSx, mSy);
}
virtual void output(int level, uint32_t flags = 0) {
virtual void output(int level, uint32_t logFlags) {
OP_LOG("Scale by %f %f", mSx, mSy);
}
@@ -378,7 +400,7 @@ public:
renderer.skew(mSx, mSy);
}
virtual void output(int level, uint32_t flags = 0) {
virtual void output(int level, uint32_t logFlags) {
OP_LOG("Skew by %f %f", mSx, mSy);
}
@@ -398,7 +420,7 @@ public:
renderer.setMatrix(mMatrix);
}
virtual void output(int level, uint32_t flags = 0) {
virtual void output(int level, uint32_t logFlags) {
OP_LOG("SetMatrix " MATRIX_STRING, MATRIX_ARGS(mMatrix));
}
@@ -417,7 +439,7 @@ public:
renderer.concatMatrix(mMatrix);
}
virtual void output(int level, uint32_t flags = 0) {
virtual void output(int level, uint32_t logFlags) {
OP_LOG("ConcatMatrix " MATRIX_STRING, MATRIX_ARGS(mMatrix));
}
@@ -427,75 +449,97 @@ private:
SkMatrix* mMatrix;
};
class ClipRectOp : public StateOp {
class ClipOp : public StateOp {
public:
ClipOp(SkRegion::Op op) : mOp(op) {}
virtual void defer(DeferStateStruct& deferStruct, int saveCount,
int level, int multipliedAlpha) {
// NOTE: must defer op BEFORE applying state, since it may read clip
deferStruct.mDeferredList.addClip(deferStruct.mRenderer, this);
// TODO: Can we avoid applying complex clips at defer time?
applyState(deferStruct.mRenderer, saveCount);
}
bool canCauseComplexClip() {
return ((mOp != SkRegion::kIntersect_Op) && (mOp != SkRegion::kReplace_Op)) || !isRect();
}
protected:
ClipOp() {}
virtual bool isRect() { return false; }
SkRegion::Op mOp;
};
class ClipRectOp : public ClipOp {
friend class DisplayList; // give DisplayList private constructor/reinit access
public:
ClipRectOp(float left, float top, float right, float bottom, SkRegion::Op op)
: mArea(left, top, right, bottom), mOp(op) {}
: ClipOp(op), mArea(left, top, right, bottom) {}
virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
renderer.clipRect(mArea.left, mArea.top, mArea.right, mArea.bottom, mOp);
}
virtual void output(int level, uint32_t flags = 0) {
virtual void output(int level, uint32_t logFlags) {
OP_LOG("ClipRect " RECT_STRING, RECT_ARGS(mArea));
}
virtual const char* name() { return "ClipRect"; }
virtual bool requiresDrawOpFlush(OpenGLRenderer& renderer) {
// TODO: currently, we flush when we *might* cause a clip region to exist. Ideally, we
// should only flush when a non-rectangular clip would result
return !renderer.hasRectToRectTransform() || !hasRectToRectOp();
}
protected:
virtual bool isRect() { return true; }
private:
inline bool hasRectToRectOp() {
return mOp == SkRegion::kIntersect_Op || mOp == SkRegion::kReplace_Op;
ClipRectOp() {}
DisplayListOp* reinit(float left, float top, float right, float bottom, SkRegion::Op op) {
mOp = op;
mArea.set(left, top, right, bottom);
return this;
}
Rect mArea;
SkRegion::Op mOp;
};
class ClipPathOp : public StateOp {
class ClipPathOp : public ClipOp {
public:
ClipPathOp(SkPath* path, SkRegion::Op op)
: mPath(path), mOp(op) {}
: ClipOp(op), mPath(path) {}
virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
renderer.clipPath(mPath, mOp);
}
virtual void output(int level, uint32_t flags = 0) {
virtual void output(int level, uint32_t logFlags) {
SkRect bounds = mPath->getBounds();
OP_LOG("ClipPath bounds " RECT_STRING,
bounds.left(), bounds.top(), bounds.right(), bounds.bottom());
}
virtual const char* name() { return "ClipPath"; }
virtual bool requiresDrawOpFlush(OpenGLRenderer& renderer) { return true; }
private:
SkPath* mPath;
SkRegion::Op mOp;
};
class ClipRegionOp : public StateOp {
class ClipRegionOp : public ClipOp {
public:
ClipRegionOp(SkRegion* region, SkRegion::Op op)
: mRegion(region), mOp(op) {}
: ClipOp(op), mRegion(region) {}
virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
renderer.clipRegion(mRegion, mOp);
}
virtual void output(int level, uint32_t flags = 0) {
virtual void output(int level, uint32_t logFlags) {
SkIRect bounds = mRegion->getBounds();
OP_LOG("ClipRegion bounds %d %d %d %d",
bounds.left(), bounds.top(), bounds.right(), bounds.bottom());
}
virtual const char* name() { return "ClipRegion"; }
virtual bool requiresDrawOpFlush(OpenGLRenderer& renderer) { return true; }
private:
SkRegion* mRegion;
@@ -508,7 +552,7 @@ public:
renderer.resetShader();
}
virtual void output(int level, uint32_t flags = 0) {
virtual void output(int level, uint32_t logFlags) {
OP_LOGS("ResetShader");
}
@@ -523,7 +567,7 @@ public:
renderer.setupShader(mShader);
}
virtual void output(int level, uint32_t flags = 0) {
virtual void output(int level, uint32_t logFlags) {
OP_LOG("SetupShader, shader %p", mShader);
}
@@ -539,7 +583,7 @@ public:
renderer.resetColorFilter();
}
virtual void output(int level, uint32_t flags = 0) {
virtual void output(int level, uint32_t logFlags) {
OP_LOGS("ResetColorFilter");
}
@@ -555,7 +599,7 @@ public:
renderer.setupColorFilter(mColorFilter);
}
virtual void output(int level, uint32_t flags = 0) {
virtual void output(int level, uint32_t logFlags) {
OP_LOG("SetupColorFilter, filter %p", mColorFilter);
}
@@ -571,7 +615,7 @@ public:
renderer.resetShadow();
}
virtual void output(int level, uint32_t flags = 0) {
virtual void output(int level, uint32_t logFlags) {
OP_LOGS("ResetShadow");
}
@@ -587,7 +631,7 @@ public:
renderer.setupShadow(mRadius, mDx, mDy, mColor);
}
virtual void output(int level, uint32_t flags = 0) {
virtual void output(int level, uint32_t logFlags) {
OP_LOG("SetupShadow, radius %f, %f, %f, color %#x", mRadius, mDx, mDy, mColor);
}
@@ -606,7 +650,7 @@ public:
renderer.resetPaintFilter();
}
virtual void output(int level, uint32_t flags = 0) {
virtual void output(int level, uint32_t logFlags) {
OP_LOGS("ResetPaintFilter");
}
@@ -622,7 +666,7 @@ public:
renderer.setupPaintFilter(mClearBits, mSetBits);
}
virtual void output(int level, uint32_t flags = 0) {
virtual void output(int level, uint32_t logFlags) {
OP_LOG("SetupPaintFilter, clear %#x, set %#x", mClearBits, mSetBits);
}
@@ -645,9 +689,9 @@ public:
paint),
mBitmap(bitmap) {}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
bool caching, int multipliedAlpha) {
bool makeCopy = caching && multipliedAlpha < 255;
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
int multipliedAlpha) {
bool makeCopy = multipliedAlpha >= 0 && multipliedAlpha < 255;
SkPaint* paint = getPaint(renderer, makeCopy);
if (makeCopy) {
// The paint is safe to modify since we're working on a copy
@@ -657,7 +701,7 @@ public:
return ret;
}
virtual void output(int level, uint32_t flags) {
virtual void output(int level, uint32_t logFlags) {
OP_LOG("Draw bitmap %p at %f %f", mBitmap, mLocalBounds.left, mLocalBounds.top);
}
@@ -679,12 +723,12 @@ public:
transform.mapRect(mLocalBounds);
}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
bool caching, int multipliedAlpha) {
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
int multipliedAlpha) {
return renderer.drawBitmap(mBitmap, mMatrix, getPaint(renderer));
}
virtual void output(int level, uint32_t flags) {
virtual void output(int level, uint32_t logFlags) {
OP_LOG("Draw bitmap %p matrix " MATRIX_STRING, mBitmap, MATRIX_ARGS(mMatrix));
}
@@ -705,14 +749,14 @@ public:
: DrawBoundedOp(dstLeft, dstTop, dstRight, dstBottom, paint),
mBitmap(bitmap), mSrc(srcLeft, srcTop, srcRight, srcBottom) {}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
bool caching, int multipliedAlpha) {
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
int multipliedAlpha) {
return renderer.drawBitmap(mBitmap, mSrc.left, mSrc.top, mSrc.right, mSrc.bottom,
mLocalBounds.left, mLocalBounds.top, mLocalBounds.right, mLocalBounds.bottom,
getPaint(renderer));
}
virtual void output(int level, uint32_t flags) {
virtual void output(int level, uint32_t logFlags) {
OP_LOG("Draw bitmap %p src="RECT_STRING", dst="RECT_STRING,
mBitmap, RECT_ARGS(mSrc), RECT_ARGS(mLocalBounds));
}
@@ -732,13 +776,13 @@ public:
DrawBitmapDataOp(SkBitmap* bitmap, float left, float top, SkPaint* paint)
: DrawBitmapOp(bitmap, left, top, paint) {}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
bool caching, int multipliedAlpha) {
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
int multipliedAlpha) {
return renderer.drawBitmapData(mBitmap, mLocalBounds.left,
mLocalBounds.top, getPaint(renderer));
}
virtual void output(int level, uint32_t flags) {
virtual void output(int level, uint32_t logFlags) {
OP_LOG("Draw bitmap %p", mBitmap);
}
@@ -756,13 +800,13 @@ public:
mBitmap(bitmap), mMeshWidth(meshWidth), mMeshHeight(meshHeight),
mVertices(vertices), mColors(colors) {}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
bool caching, int multipliedAlpha) {
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
int multipliedAlpha) {
return renderer.drawBitmapMesh(mBitmap, mMeshWidth, mMeshHeight,
mVertices, mColors, getPaint(renderer));
}
virtual void output(int level, uint32_t flags) {
virtual void output(int level, uint32_t logFlags) {
OP_LOG("Draw bitmap %p mesh %d x %d", mBitmap, mMeshWidth, mMeshHeight);
}
@@ -790,8 +834,8 @@ public:
mColors(colors), mxDivsCount(width), myDivsCount(height),
mNumColors(numColors), mAlpha(alpha), mMode(mode) {};
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
bool caching, int multipliedAlpha) {
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
int multipliedAlpha) {
// NOTE: not calling the virtual method, which takes a paint
return renderer.drawPatch(mBitmap, mxDivs, myDivs, mColors,
mxDivsCount, myDivsCount, mNumColors,
@@ -799,7 +843,7 @@ public:
mLocalBounds.right, mLocalBounds.bottom, mAlpha, mMode);
}
virtual void output(int level, uint32_t flags) {
virtual void output(int level, uint32_t logFlags) {
OP_LOG("Draw patch "RECT_STRING, RECT_ARGS(mLocalBounds));
}
@@ -825,12 +869,12 @@ public:
DrawColorOp(int color, SkXfermode::Mode mode)
: DrawOp(0), mColor(color), mMode(mode) {};
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
bool caching, int multipliedAlpha) {
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
int multipliedAlpha) {
return renderer.drawColor(mColor, mMode);
}
virtual void output(int level, uint32_t flags) {
virtual void output(int level, uint32_t logFlags) {
OP_LOG("Draw color %#x, mode %d", mColor, mMode);
}
@@ -869,13 +913,13 @@ public:
DrawRectOp(float left, float top, float right, float bottom, SkPaint* paint)
: DrawStrokableOp(left, top, right, bottom, paint) {}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
bool caching, int multipliedAlpha) {
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
int multipliedAlpha) {
return renderer.drawRect(mLocalBounds.left, mLocalBounds.top,
mLocalBounds.right, mLocalBounds.bottom, getPaint(renderer));
}
virtual void output(int level, uint32_t flags) {
virtual void output(int level, uint32_t logFlags) {
OP_LOG("Draw Rect "RECT_STRING, RECT_ARGS(mLocalBounds));
}
@@ -888,12 +932,12 @@ public:
: DrawBoundedOp(rects, count, paint),
mRects(rects), mCount(count) {}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
bool caching, int multipliedAlpha) {
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
int multipliedAlpha) {
return renderer.drawRects(mRects, mCount, getPaint(renderer));
}
virtual void output(int level, uint32_t flags) {
virtual void output(int level, uint32_t logFlags) {
OP_LOG("Draw Rects count %d", mCount);
}
@@ -914,13 +958,13 @@ public:
float rx, float ry, SkPaint* paint)
: DrawStrokableOp(left, top, right, bottom, paint), mRx(rx), mRy(ry) {}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
bool caching, int multipliedAlpha) {
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
int multipliedAlpha) {
return renderer.drawRoundRect(mLocalBounds.left, mLocalBounds.top,
mLocalBounds.right, mLocalBounds.bottom, mRx, mRy, getPaint(renderer));
}
virtual void output(int level, uint32_t flags) {
virtual void output(int level, uint32_t logFlags) {
OP_LOG("Draw RoundRect "RECT_STRING", rx %f, ry %f", RECT_ARGS(mLocalBounds), mRx, mRy);
}
@@ -937,12 +981,12 @@ public:
: DrawStrokableOp(x - radius, y - radius, x + radius, y + radius, paint),
mX(x), mY(y), mRadius(radius) {}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
bool caching, int multipliedAlpha) {
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
int multipliedAlpha) {
return renderer.drawCircle(mX, mY, mRadius, getPaint(renderer));
}
virtual void output(int level, uint32_t flags) {
virtual void output(int level, uint32_t logFlags) {
OP_LOG("Draw Circle x %f, y %f, r %f", mX, mY, mRadius);
}
@@ -959,13 +1003,13 @@ public:
DrawOvalOp(float left, float top, float right, float bottom, SkPaint* paint)
: DrawStrokableOp(left, top, right, bottom, paint) {}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
bool caching, int multipliedAlpha) {
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
int multipliedAlpha) {
return renderer.drawOval(mLocalBounds.left, mLocalBounds.top,
mLocalBounds.right, mLocalBounds.bottom, getPaint(renderer));
}
virtual void output(int level, uint32_t flags) {
virtual void output(int level, uint32_t logFlags) {
OP_LOG("Draw Oval "RECT_STRING, RECT_ARGS(mLocalBounds));
}
@@ -979,14 +1023,14 @@ public:
: DrawStrokableOp(left, top, right, bottom, paint),
mStartAngle(startAngle), mSweepAngle(sweepAngle), mUseCenter(useCenter) {}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
bool caching, int multipliedAlpha) {
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
int multipliedAlpha) {
return renderer.drawArc(mLocalBounds.left, mLocalBounds.top,
mLocalBounds.right, mLocalBounds.bottom,
mStartAngle, mSweepAngle, mUseCenter, getPaint(renderer));
}
virtual void output(int level, uint32_t flags) {
virtual void output(int level, uint32_t logFlags) {
OP_LOG("Draw Arc "RECT_STRING", start %f, sweep %f, useCenter %d",
RECT_ARGS(mLocalBounds), mStartAngle, mSweepAngle, mUseCenter);
}
@@ -1011,8 +1055,8 @@ public:
mLocalBounds.set(left, top, left + width, top + height);
}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
bool caching, int multipliedAlpha) {
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
int multipliedAlpha) {
return renderer.drawPath(mPath, getPaint(renderer));
}
@@ -1021,7 +1065,7 @@ public:
renderer.getCaches().pathCache.precache(mPath, paint);
}
virtual void output(int level, uint32_t flags) {
virtual void output(int level, uint32_t logFlags) {
OP_LOG("Draw Path %p in "RECT_STRING, mPath, RECT_ARGS(mLocalBounds));
}
@@ -1042,12 +1086,12 @@ public:
mLocalBounds.outset(strokeWidthOutset());
}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
bool caching, int multipliedAlpha) {
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
int multipliedAlpha) {
return renderer.drawLines(mPoints, mCount, getPaint(renderer));
}
virtual void output(int level, uint32_t flags) {
virtual void output(int level, uint32_t logFlags) {
OP_LOG("Draw Lines count %d", mCount);
}
@@ -1069,12 +1113,12 @@ public:
DrawPointsOp(float* points, int count, SkPaint* paint)
: DrawLinesOp(points, count, paint) {}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
bool caching, int multipliedAlpha) {
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
int multipliedAlpha) {
return renderer.drawPoints(mPoints, mCount, getPaint(renderer));
}
virtual void output(int level, uint32_t flags) {
virtual void output(int level, uint32_t logFlags) {
OP_LOG("Draw Points count %d", mCount);
}
@@ -1086,7 +1130,7 @@ public:
DrawSomeTextOp(const char* text, int bytesCount, int count, SkPaint* paint)
: DrawOp(paint), mText(text), mBytesCount(bytesCount), mCount(count) {};
virtual void output(int level, uint32_t flags) {
virtual void output(int level, uint32_t logFlags) {
OP_LOG("Draw some text, %d bytes", mBytesCount);
}
@@ -1116,8 +1160,8 @@ public:
/* TODO: inherit from DrawBounded and init mLocalBounds */
}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
bool caching, int multipliedAlpha) {
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
int multipliedAlpha) {
return renderer.drawTextOnPath(mText, mBytesCount, mCount, mPath,
mHOffset, mVOffset, getPaint(renderer));
}
@@ -1138,8 +1182,8 @@ public:
/* TODO: inherit from DrawBounded and init mLocalBounds */
}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
bool caching, int multipliedAlpha) {
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
int multipliedAlpha) {
return renderer.drawPosText(mText, mBytesCount, mCount, mPositions, getPaint(renderer));
}
@@ -1187,13 +1231,13 @@ public:
}
}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
bool caching, int multipliedAlpha) {
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
int multipliedAlpha) {
return renderer.drawText(mText, mBytesCount, mCount, mX, mY,
mPositions, getPaint(renderer), mLength);
}
virtual void output(int level, uint32_t flags) {
virtual void output(int level, uint32_t logFlags) {
OP_LOG("Draw Text of count %d, bytes %d", mCount, mBytesCount);
}
@@ -1225,15 +1269,15 @@ public:
DrawFunctorOp(Functor* functor)
: DrawOp(0), mFunctor(functor) {}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
bool caching, int multipliedAlpha) {
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
int multipliedAlpha) {
renderer.startMark("GL functor");
status_t ret = renderer.callDrawGLFunction(mFunctor, dirty);
renderer.endMark();
return ret;
}
virtual void output(int level, uint32_t flags) {
virtual void output(int level, uint32_t logFlags) {
OP_LOG("Draw Functor %p", mFunctor);
}
@@ -1249,21 +1293,26 @@ public:
: DrawBoundedOp(0, 0, displayList->getWidth(), displayList->getHeight(), 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) {
virtual void defer(DeferStateStruct& deferStruct, int saveCount,
int level, int multipliedAlpha) {
if (mDisplayList && mDisplayList->isRenderable()) {
return mDisplayList->replay(renderer, dirty, mFlags, level + 1, deferredList);
mDisplayList->defer(deferStruct, level + 1);
}
return DrawGlInfo::kStatusDone;
}
// NOT USED, since replay is overridden
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
bool caching, int multipliedAlpha) { return DrawGlInfo::kStatusDone; }
virtual void replay(ReplayStateStruct& replayStruct, int saveCount,
int level, int multipliedAlpha) {
if (mDisplayList && mDisplayList->isRenderable()) {
mDisplayList->replay(replayStruct, level + 1);
}
}
virtual void output(int level, uint32_t flags) {
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
int multipliedAlpha) { return DrawGlInfo::kStatusDone; }
virtual void output(int level, uint32_t logFlags) {
OP_LOG("Draw Display List %p, flags %#x", mDisplayList, mFlags);
if (mDisplayList && (flags & kOpLogFlag_Recurse)) {
if (mDisplayList && (logFlags & kOpLogFlag_Recurse)) {
mDisplayList->output(level + 1);
}
}
@@ -1280,11 +1329,11 @@ public:
DrawLayerOp(Layer* layer, float x, float y, SkPaint* paint)
: DrawOp(paint), mLayer(layer), mX(x), mY(y) {}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
bool caching, int multipliedAlpha) {
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
int multipliedAlpha) {
int oldAlpha = -1;
if (caching && multipliedAlpha < 255) {
if (multipliedAlpha >= 0 && multipliedAlpha < 255) {
oldAlpha = mLayer->getAlpha();
mLayer->setAlpha(multipliedAlpha);
}
@@ -1295,7 +1344,7 @@ public:
return ret;
}
virtual void output(int level, uint32_t flags) {
virtual void output(int level, uint32_t logFlags) {
OP_LOG("Draw Layer %p at %f %f", mLayer, mX, mY);
}

View File

@@ -175,14 +175,8 @@ void DisplayListRenderer::restoreToCount(int saveCount) {
}
int DisplayListRenderer::saveLayer(float left, float top, float right, float bottom,
SkPaint* p, int flags) {
addStateOp(new (alloc()) SaveLayerOp(left, top, right, bottom, p, flags));
return OpenGLRenderer::save(flags);
}
int DisplayListRenderer::saveLayerAlpha(float left, float top, float right, float bottom,
int alpha, int flags) {
addStateOp(new (alloc()) SaveLayerAlphaOp(left, top, right, bottom, alpha, flags));
int alpha, SkXfermode::Mode mode, int flags) {
addStateOp(new (alloc()) SaveLayerOp(left, top, right, bottom, alpha, mode, flags));
return OpenGLRenderer::save(flags);
}

View File

@@ -79,9 +79,7 @@ public:
virtual void restoreToCount(int saveCount);
virtual int saveLayer(float left, float top, float right, float bottom,
SkPaint* p, int flags);
virtual int saveLayerAlpha(float left, float top, float right, float bottom,
int alpha, int flags);
int alpha, SkXfermode::Mode mode, int flags);
virtual void translate(float dx, float dy);
virtual void rotate(float degrees);

View File

@@ -635,38 +635,17 @@ bool OpenGLRenderer::restoreSnapshot() {
///////////////////////////////////////////////////////////////////////////////
int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,
SkPaint* p, int flags) {
int alpha, SkXfermode::Mode mode, int flags) {
const GLuint previousFbo = mSnapshot->fbo;
const int count = saveSnapshot(flags);
if (!mSnapshot->isIgnored()) {
int alpha = 255;
SkXfermode::Mode mode;
if (p) {
alpha = p->getAlpha();
mode = getXfermode(p->getXfermode());
} else {
mode = SkXfermode::kSrcOver_Mode;
}
createLayer(left, top, right, bottom, alpha, mode, flags, previousFbo);
}
return count;
}
int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bottom,
int alpha, int flags) {
if (alpha >= 255) {
return saveLayer(left, top, right, bottom, NULL, flags);
} else {
SkPaint paint;
paint.setAlpha(alpha);
return saveLayer(left, top, right, bottom, &paint, flags);
}
}
/**
* Layers are viewed by Skia are slightly different than layers in image editing
* programs (for instance.) When a layer is created, previously created layers
@@ -1225,36 +1204,48 @@ void OpenGLRenderer::clearLayerRegions() {
// State Deferral
///////////////////////////////////////////////////////////////////////////////
bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state) {
bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDeferFlags) {
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;
if (stateDeferFlags & kStateDeferFlag_Draw) {
// state has bounds initialized in local coordinates
if (!state.mBounds.isEmpty()) {
currentMatrix.mapRect(state.mBounds);
if (!state.mBounds.intersect(currentClip)) {
// quick rejected
return true;
}
} else {
state.mBounds.set(currentClip);
}
} else {
state.mBounds.set(currentClip);
state.mDrawModifiers = mDrawModifiers;
state.mAlpha = mSnapshot->alpha;
}
state.mClip.set(currentClip);
if (stateDeferFlags & kStateDeferFlag_Clip) {
state.mClip.set(currentClip);
} else {
state.mClip.setEmpty();
}
// transform always deferred
state.mMatrix.load(currentMatrix);
state.mDrawModifiers = mDrawModifiers;
return false;
}
void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state) {
void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, int stateDeferFlags) {
currentTransform().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;
if (stateDeferFlags & kStateDeferFlag_Draw) {
mDrawModifiers = state.mDrawModifiers;
mSnapshot->alpha = state.mAlpha;
}
if (!state.mClip.isEmpty()) { //stateDeferFlags & kStateDeferFlag_Clip) {
mSnapshot->setClip(state.mClip.left, state.mClip.top, state.mClip.right, state.mClip.bottom);
dirtyClip();
}
}
///////////////////////////////////////////////////////////////////////////////
@@ -1805,16 +1796,21 @@ void OpenGLRenderer::finishDrawTexture() {
// Drawing
///////////////////////////////////////////////////////////////////////////////
status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t flags) {
status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty,
int32_t replayFlags) {
// All the usual checks and setup operations (quickReject, setupDraw, etc.)
// will be performed by the display list itself
if (displayList && displayList->isRenderable()) {
if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
return displayList->replay(*this, dirty, flags, 0);
ReplayStateStruct replayStruct(*this, dirty, replayFlags);
displayList->replay(replayStruct, 0);
return replayStruct.mDrawGlStatus;
}
DeferredDisplayList deferredList;
return displayList->replay(*this, dirty, flags, 0, &deferredList);
DeferStateStruct deferStruct(deferredList, *this, replayFlags);
displayList->defer(deferStruct, 0);
return deferredList.flush(*this, dirty);
}
return DrawGlInfo::kStatusDone;

View File

@@ -65,6 +65,11 @@ struct DrawModifiers {
int mPaintFilterSetBits;
};
enum StateDeferFlags {
kStateDeferFlag_Draw = 0x1,
kStateDeferFlag_Clip = 0x2
};
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)
@@ -72,8 +77,8 @@ struct DeferredDisplayState {
// the below are set and used by the OpenGLRenderer at record and deferred playback
Rect mClip;
mat4 mMatrix;
SkiaShader* mShader;
DrawModifiers mDrawModifiers;
float mAlpha;
};
///////////////////////////////////////////////////////////////////////////////
@@ -188,10 +193,18 @@ public:
virtual void restore();
virtual void restoreToCount(int saveCount);
ANDROID_API int saveLayer(float left, float top, float right, float bottom,
SkPaint* paint, int flags) {
SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode;
if (paint) mode = getXfermode(paint->getXfermode());
return saveLayer(left, top, right, bottom, paint ? paint->getAlpha() : 255, mode, flags);
}
ANDROID_API int saveLayerAlpha(float left, float top, float right, float bottom,
int alpha, int flags) {
return saveLayer(left, top, right, bottom, alpha, SkXfermode::kSrcOver_Mode, flags);
}
virtual int saveLayer(float left, float top, float right, float bottom,
SkPaint* p, int flags);
virtual int saveLayerAlpha(float left, float top, float right, float bottom,
int alpha, int flags);
int alpha, SkXfermode::Mode mode, int flags);
virtual void translate(float dx, float dy);
virtual void rotate(float degrees);
@@ -211,7 +224,7 @@ public:
virtual bool clipRegion(SkRegion* region, SkRegion::Op op);
virtual Rect* getClipRect();
virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t flags);
virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t replayFlags);
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);
@@ -261,21 +274,10 @@ public:
SkPaint* filterPaint(SkPaint* paint, bool alwaysCopy = false);
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 storeDisplayState(DeferredDisplayState& state);
void restoreDisplayState(const DeferredDisplayState& state);
const DrawModifiers& getDrawModifiers() { return mDrawModifiers; }
void setDrawModifiers(const DrawModifiers& drawModifiers) { mDrawModifiers = drawModifiers; }
bool storeDisplayState(DeferredDisplayState& state, int stateDeferFlags);
void restoreDisplayState(const DeferredDisplayState& state, int stateDeferFlags);
// TODO: what does this mean? no perspective? no rotate?
ANDROID_API bool isCurrentTransformSimple() {
return mSnapshot->transform->isSimple();
}
@@ -284,6 +286,11 @@ public:
return mCaches;
}
// simple rect clip
bool isCurrentClipSimple() {
return mSnapshot->clipRegion->isEmpty();
}
/**
* Sets the alpha on the current snapshot. This alpha value will be modulated
* with other alpha values when drawing primitives.