Fix quickReject's handling of AA ramp geometry

By having quickReject round out the window-space geometry bounds, we
prevent the AA perimeter (which falls outside the local bounds passed
in) from drawing outside the clip.

Change-Id: I8ee36be9039a9c47906815ee2f0dbaa5eb910b82
This commit is contained in:
Chris Craik
2013-07-30 19:05:20 -07:00
parent cb9accefb1
commit 5e49b307eb
5 changed files with 52 additions and 12 deletions

View File

@@ -79,7 +79,7 @@ public:
/**
* Add a draw op into the DeferredDisplayList, reordering as needed (for performance) if
* disallowReorder is false, respecting draw order when overlaps occur
* disallowReorder is false, respecting draw order when overlaps occur.
*/
void addDrawOp(OpenGLRenderer& renderer, DrawOp* op);

View File

@@ -180,7 +180,11 @@ public:
*/
virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo) {}
// returns true if bounds exist
/**
* Query the conservative, local bounds (unmapped) bounds of the op.
*
* returns true if bounds exist
*/
virtual bool getLocalBounds(Rect& localBounds) { return false; }
// TODO: better refine localbounds usage

View File

@@ -1414,6 +1414,10 @@ bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDef
if (!state.mBounds.isEmpty()) {
currentMatrix.mapRect(state.mBounds);
Rect clippedBounds(state.mBounds);
// NOTE: if we ever want to use this clipping info to drive whether the scissor
// is used, it should more closely duplicate the quickReject logic (in how it uses
// snapToPixelBoundaries)
if(!clippedBounds.intersect(currentClip)) {
// quick rejected
return true;
@@ -1608,14 +1612,21 @@ const Rect& OpenGLRenderer::getClipBounds() {
}
bool OpenGLRenderer::quickRejectNoScissor(float left, float top, float right, float bottom,
bool* clipRequired) {
bool snapOut, bool* clipRequired) {
if (mSnapshot->isIgnored() || bottom <= top || right <= left) {
return true;
}
Rect r(left, top, right, bottom);
currentTransform().mapRect(r);
r.snapToPixelBoundaries();
if (snapOut) {
// snapOut is generally used to account for 1 pixel ramp (in window coordinates)
// outside of the provided rect boundaries in tessellated AA geometry
r.snapOutToPixelBoundaries();
} else {
r.snapToPixelBoundaries();
}
Rect clipRect(*mSnapshot->clipRect);
clipRect.snapToPixelBoundaries();
@@ -1628,17 +1639,21 @@ bool OpenGLRenderer::quickRejectNoScissor(float left, float top, float right, fl
bool OpenGLRenderer::quickRejectPreStroke(float left, float top, float right, float bottom,
SkPaint* paint) {
// AA geometry will likely have a ramp around it (not accounted for in local bounds). Snap out
// the final mapped rect to ensure correct clipping behavior for the ramp.
bool snapOut = paint->isAntiAlias();
if (paint->getStyle() != SkPaint::kFill_Style) {
float outset = paint->getStrokeWidth() * 0.5f;
return quickReject(left - outset, top - outset, right + outset, bottom + outset);
return quickReject(left - outset, top - outset, right + outset, bottom + outset, snapOut);
} else {
return quickReject(left, top, right, bottom);
return quickReject(left, top, right, bottom, snapOut);
}
}
bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom) {
bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom, bool snapOut) {
bool clipRequired = false;
if (quickRejectNoScissor(left, top, right, bottom, &clipRequired)) {
if (quickRejectNoScissor(left, top, right, bottom, snapOut, &clipRequired)) {
return true;
}
@@ -3115,7 +3130,7 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
bool clipRequired = false;
const bool rejected = quickRejectNoScissor(x, y,
x + layer->layer.getWidth(), y + layer->layer.getHeight(), &clipRequired);
x + layer->layer.getWidth(), y + layer->layer.getHeight(), false, &clipRequired);
if (rejected) {
if (transform && !transform->isIdentity()) {

View File

@@ -256,14 +256,15 @@ public:
ANDROID_API const Rect& getClipBounds();
/**
* Performs a quick reject but adjust the bounds to account for stroke width if necessary
* Performs a quick reject but adjust the bounds to account for stroke width if necessary,
* and handling snapOut for AA geometry.
*/
bool quickRejectPreStroke(float left, float top, float right, float bottom, SkPaint* paint);
/**
* Returns false and sets scissor based upon bounds if drawing won't be clipped out
*/
bool quickReject(float left, float top, float right, float bottom);
bool quickReject(float left, float top, float right, float bottom, bool snapOut = false);
bool quickReject(const Rect& bounds) {
return quickReject(bounds.left, bounds.top, bounds.right, bounds.bottom);
}
@@ -273,7 +274,7 @@ public:
* clipRequired will be only set if not rejected
*/
ANDROID_API bool quickRejectNoScissor(float left, float top, float right, float bottom,
bool* clipRequired = NULL);
bool snapOut = false, bool* clipRequired = NULL);
bool quickRejectNoScissor(const Rect& bounds, bool* clipRequired = NULL) {
return quickRejectNoScissor(bounds.left, bounds.top, bounds.right, bounds.bottom,
clipRequired);
@@ -340,6 +341,12 @@ public:
SkPaint* filterPaint(SkPaint* paint);
/**
* Store the current display state (most importantly, the current clip and transform), and
* additionally map the state's bounds from local to window coordinates.
*
* Returns true if quick-rejected
*/
bool storeDisplayState(DeferredDisplayState& state, int stateDeferFlags);
void restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore = false);
void setupMergedMultiDraw(const Rect* clipRect);

View File

@@ -170,6 +170,20 @@ public:
bottom += delta;
}
/**
* Similar to snapToPixelBoundaries, but used for AA geometry with a ramp perimeter.
*
* We inset the data by a fudge factor of slightly over 1/16 (similar to when drawing non-AA
* lines) before rounding out so that insignificant amounts of ramp geometry (esp. from rounding
* errors) are ignored.
*/
void snapOutToPixelBoundaries() {
left = floorf(left + 0.065f);
top = floorf(top + 0.065f);
right = ceilf(right - 0.065f);
bottom = ceilf(bottom - 0.065f);
}
void snapToPixelBoundaries() {
left = floorf(left + 0.5f);
top = floorf(top + 0.5f);