Fix some issues in gpu device with perspective. Add a gm that would have caught them.
Review URL: http://codereview.appspot.com/4994048/
git-svn-id: http://skia.googlecode.com/svn/trunk@2256 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gm/pathfillpersp.cpp b/gm/pathfillpersp.cpp
new file mode 100644
index 0000000..00326fd
--- /dev/null
+++ b/gm/pathfillpersp.cpp
@@ -0,0 +1,123 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "gm.h"
+
+namespace skiagm {
+
+class FillTypePerspGM : public GM {
+ SkPath fPath;
+public:
+ FillTypePerspGM() {
+ const SkScalar radius = SkIntToScalar(45);
+ fPath.addCircle(SkIntToScalar(50), SkIntToScalar(50), radius);
+ fPath.addCircle(SkIntToScalar(100), SkIntToScalar(100), radius);
+ }
+
+protected:
+ virtual SkString onShortName() {
+ return SkString("filltypespersp");
+ }
+
+ virtual SkISize onISize() {
+ return make_isize(835, 840);
+ }
+
+ void showPath(SkCanvas* canvas, int x, int y, SkPath::FillType ft,
+ SkScalar scale, const SkPaint& paint) {
+
+ const SkRect r = { 0, 0, SkIntToScalar(150), SkIntToScalar(150) };
+
+ canvas->save();
+ canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
+ canvas->clipRect(r);
+ canvas->drawColor(SK_ColorWHITE);
+ fPath.setFillType(ft);
+ canvas->translate(r.centerX(), r.centerY());
+ canvas->scale(scale, scale);
+ canvas->translate(-r.centerX(), -r.centerY());
+ canvas->drawPath(fPath, paint);
+ canvas->restore();
+ }
+
+ void showFour(SkCanvas* canvas, SkScalar scale, bool aa) {
+
+ SkPaint paint;
+ SkPoint center = SkPoint::Make(SkIntToScalar(100), SkIntToScalar(100));
+ SkColor colors[] = {SK_ColorBLUE, SK_ColorRED, SK_ColorGREEN};
+ SkScalar pos[] = {0, SK_ScalarHalf, SK_Scalar1};
+ SkShader* s = SkGradientShader::CreateRadial(center,
+ SkIntToScalar(100),
+ colors,
+ pos,
+ SK_ARRAY_COUNT(colors),
+ SkShader::kClamp_TileMode);
+ paint.setShader(s)->unref();
+ paint.setAntiAlias(aa);
+
+ showPath(canvas, 0, 0, SkPath::kWinding_FillType,
+ scale, paint);
+ showPath(canvas, 200, 0, SkPath::kEvenOdd_FillType,
+ scale, paint);
+ showPath(canvas, 00, 200, SkPath::kInverseWinding_FillType,
+ scale, paint);
+ showPath(canvas, 200, 200, SkPath::kInverseEvenOdd_FillType,
+ scale, paint);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ // do perspective drawPaint as the background;
+ SkPaint bkgnrd;
+ SkPoint center = SkPoint::Make(SkIntToScalar(100), SkIntToScalar(100));
+ SkColor colors[] = {SK_ColorBLACK, SK_ColorGREEN, SK_ColorYELLOW, SK_ColorWHITE};
+ SkScalar pos[] = {0, SK_ScalarHalf / 2, 3 * SK_ScalarHalf / 2, SK_Scalar1};
+ SkShader* s = SkGradientShader::CreateRadial(center,
+ SkIntToScalar(1000),
+ colors,
+ pos,
+ SK_ARRAY_COUNT(colors),
+ SkShader::kClamp_TileMode);
+ bkgnrd.setShader(s)->unref();
+ canvas->save();
+ canvas->translate(SkIntToScalar(100), SkIntToScalar(100));
+ SkMatrix mat;
+ mat.reset();
+ mat.setPerspY(SK_Scalar1 / 300);
+ canvas->concat(mat);
+ canvas->drawPaint(bkgnrd);
+ canvas->restore();
+
+ // draw the paths in perspective
+ SkMatrix persp;
+ persp.reset();
+ persp.setPerspX(-SK_Scalar1 / 300);
+ canvas->concat(persp);
+
+ canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
+ const SkScalar scale = SkIntToScalar(5)/4;
+
+ showFour(canvas, SK_Scalar1, false);
+ canvas->translate(SkIntToScalar(450), 0);
+ showFour(canvas, scale, paint);
+
+ canvas->translate(SkIntToScalar(-450), SkIntToScalar(450));
+ showFour(canvas, SK_Scalar1, true);
+ canvas->translate(SkIntToScalar(450), 0);
+ showFour(canvas, scale, paint);
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new FillTypeGM; }
+static GMRegistry reg(MyFactory);
+
+}
+
diff --git a/gpu/src/GrContext.cpp b/gpu/src/GrContext.cpp
index 8eb8c63..6de3169 100644
--- a/gpu/src/GrContext.cpp
+++ b/gpu/src/GrContext.cpp
@@ -18,6 +18,7 @@
#include "GrResourceCache.h"
#include "GrStencilBuffer.h"
#include "GrTextStrike.h"
+#include "SkTLazy.h"
#include "SkTrace.h"
// Using MSAA seems to be slower for some yet unknown reason.
@@ -592,22 +593,37 @@
GrIntToScalar(getRenderTarget()->height()));
GrAutoMatrix am;
GrMatrix inverse;
+ SkTLazy<GrPaint> tmpPaint;
+ const GrPaint* p = &paint;
// We attempt to map r by the inverse matrix and draw that. mapRect will
// map the four corners and bound them with a new rect. This will not
// produce a correct result for some perspective matrices.
- if (!this->getMatrix().hasPerspective() &&
- fGpu->getViewInverse(&inverse)) {
+ if (!this->getMatrix().hasPerspective()) {
+ if (!fGpu->getViewInverse(&inverse)) {
+ GrPrintf("Could not invert matrix");
+ return;
+ }
inverse.mapRect(&r);
} else {
+ if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
+ if (!fGpu->getViewInverse(&inverse)) {
+ GrPrintf("Could not invert matrix");
+ return;
+ }
+ tmpPaint.set(paint);
+ tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
+ p = tmpPaint.get();
+ }
am.set(this, GrMatrix::I());
}
- GrPaint tmpPaint;
- const GrPaint* p = &paint;
// by definition this fills the entire clip, no need for AA
if (paint.fAntiAlias) {
- tmpPaint = paint;
- tmpPaint.fAntiAlias = false;
- p = &tmpPaint;
+ if (!tmpPaint.isValid()) {
+ tmpPaint.set(paint);
+ p = tmpPaint.get();
+ }
+ GrAssert(p == tmpPaint.get());
+ tmpPaint.get()->fAntiAlias = false;
}
this->drawRect(*p, r);
}
diff --git a/gpu/src/GrDefaultPathRenderer.cpp b/gpu/src/GrDefaultPathRenderer.cpp
index 278c751..fd56c07 100644
--- a/gpu/src/GrDefaultPathRenderer.cpp
+++ b/gpu/src/GrDefaultPathRenderer.cpp
@@ -509,8 +509,19 @@
GrIntToScalar(fTarget->getRenderTarget()->width()),
GrIntToScalar(fTarget->getRenderTarget()->height()));
GrMatrix vmi;
- if (fTarget->getViewInverse(&vmi)) {
+ // mapRect through persp matrix may not be correct
+ if (!fTarget->getViewMatrix().hasPerspective() &&
+ fTarget->getViewInverse(&vmi)) {
vmi.mapRect(&bounds);
+ } else {
+ if (stages) {
+ if (!fTarget->getViewInverse(&vmi)) {
+ GrPrintf("Could not invert matrix.");
+ return;
+ }
+ fTarget->preConcatSamplerMatrices(stages, vmi);
+ }
+ fTarget->setViewMatrix(GrMatrix::I());
}
} else {
bounds = fPath->getBounds();
diff --git a/gyp/gm.gyp b/gyp/gm.gyp
index 0c9f145..cd4defd 100644
--- a/gyp/gm.gyp
+++ b/gyp/gm.gyp
@@ -15,6 +15,7 @@
'../gm/complexclip.cpp',
'../gm/complexclip2.cpp',
'../gm/filltypes.cpp',
+ '../gm/filltypespersp.cpp',
'../gm/gmmain.cpp',
'../gm/gradients.cpp',
'../gm/lcdtext.cpp',
diff --git a/include/core/SkTLazy.h b/include/core/SkTLazy.h
index 752d43b..5747da0 100644
--- a/include/core/SkTLazy.h
+++ b/include/core/SkTLazy.h
@@ -29,14 +29,15 @@
}
SkTLazy(const SkTLazy<T>& src) : fPtr(NULL) {
- const T* ptr = src.get();
- if (ptr) {
- fPtr = new (fStorage) T(*ptr);
+ if (src.isValid()) {
+ fPtr = new (fStorage) T(*src->get());
+ } else {
+ fPtr = NULL;
}
}
~SkTLazy() {
- if (fPtr) {
+ if (this->isValid()) {
fPtr->~T();
}
}
@@ -48,13 +49,13 @@
* always returned.
*/
T* init() {
- if (fPtr) {
+ if (this->isValid()) {
fPtr->~T();
}
fPtr = new (fStorage) T;
return fPtr;
}
-
+
/**
* Copy src into this, and return a pointer to a copy of it. Note this
* will always return the same pointer, so if it is called on a lazy that
@@ -62,19 +63,25 @@
* contents.
*/
T* set(const T& src) {
- if (fPtr) {
+ if (this->isValid()) {
*fPtr = src;
} else {
fPtr = new (fStorage) T(src);
}
return fPtr;
}
+
+ /**
+ * Returns true if a valid object has been initialized in the SkTLazy,
+ * false otherwise.
+ */
+ bool isValid() const { return NULL != fPtr; }
/**
* Returns either NULL, or a copy of the object that was passed to
* set() or the constructor.
*/
- T* get() const { return fPtr; }
+ T* get() const { SkASSERT(this->isValid()); return fPtr; }
private:
T* fPtr; // NULL or fStorage