Per-draw super sampling. Disabled, path only, 2x2 only
Review URL: http://codereview.appspot.com/4452048/
git-svn-id: http://skia.googlecode.com/svn/trunk@1186 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/include/GrContext.h b/gpu/include/GrContext.h
index cbe9e12..495eff4 100644
--- a/gpu/include/GrContext.h
+++ b/gpu/include/GrContext.h
@@ -605,6 +605,26 @@
GrPathIter* path,
GrPathFill fill);
+ struct OffscreenRecord;
+ // we currently only expose stage 0 through the paint so use stage 1. We
+ // use stage 1 for the offscreen.
+ enum {
+ kOffscreenStage = 1,
+ };
+
+ // sets up target to draw coverage to the supersampled render target
+ bool setupOffscreenAAPass1(GrDrawTarget* target,
+ bool requireStencil,
+ OffscreenRecord* record);
+
+ // sets up target to sample coverage of supersampled render target back
+ // to the main render target using stage kOffscreenStage.
+ void setupOffscreenAAPass2(GrDrawTarget* target,
+ const GrPaint& paint,
+ OffscreenRecord* record);
+
+ // cleans up from supersample aa drawing
+ void endOffscreenAA(GrDrawTarget* target, OffscreenRecord* record);
};
/**
diff --git a/gpu/include/GrDrawTarget.h b/gpu/include/GrDrawTarget.h
index 1be2601..e021a93 100644
--- a/gpu/include/GrDrawTarget.h
+++ b/gpu/include/GrDrawTarget.h
@@ -276,6 +276,18 @@
void preConcatViewMatrix(const GrMatrix& m);
/**
+ * Multiplies the current view matrix by a matrix
+ *
+ * After this call V' = m*V where V is the old view matrix,
+ * m is the parameter to this function, and V' is the new view matrix.
+ * (We consider positions to be column vectors so position vector p is
+ * transformed by matrix X as p' = X*p.)
+ *
+ * @param m the matrix used to modify the view matrix.
+ */
+ void postConcatViewMatrix(const GrMatrix& m);
+
+ /**
* Retrieves the current view matrix
* @return the current view matrix.
*/
@@ -728,9 +740,17 @@
class AutoStateRestore : ::GrNoncopyable {
public:
+ AutoStateRestore();
AutoStateRestore(GrDrawTarget* target);
~AutoStateRestore();
+ /**
+ * if this object is already saving state for param target then
+ * this does nothing. Otherise, it restores previously saved state on
+ * previous target (if any) and saves current state on param target.
+ */
+ void set(GrDrawTarget* target);
+
private:
GrDrawTarget* fDrawTarget;
SavedDrawState fDrawState;
diff --git a/gpu/include/GrPathRenderer.h b/gpu/include/GrPathRenderer.h
index 91d9086..03092b6 100644
--- a/gpu/include/GrPathRenderer.h
+++ b/gpu/include/GrPathRenderer.h
@@ -109,6 +109,12 @@
}
/**
+ * @return true if the path renderer can perform anti-aliasing (aside from
+ * having FSAA enabled for a render target)
+ */
+ virtual bool supportsAA() { return false; }
+
+ /**
* This is called to install a custom path renderer in every GrContext at
* create time. The default implementation in GrCreatePathRenderer_none.cpp
* returns NULL. Link against another implementation to install your own.
diff --git a/gpu/src/GrContext.cpp b/gpu/src/GrContext.cpp
index 52db9c3..8acb3dc 100644
--- a/gpu/src/GrContext.cpp
+++ b/gpu/src/GrContext.cpp
@@ -26,6 +26,8 @@
#include "GrBufferAllocPool.h"
#include "GrPathRenderer.h"
+#define ENABLE_SSAA 0
+
#define DEFER_TEXT_RENDERING 1
#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
@@ -105,7 +107,6 @@
////////////////////////////////////////////////////////////////////////////////
-
enum {
kNPOTBit = 0x1,
kFilterBit = 0x2,
@@ -415,6 +416,97 @@
////////////////////////////////////////////////////////////////////////////////
+struct GrContext::OffscreenRecord {
+ OffscreenRecord() { fEntry = NULL; }
+ ~OffscreenRecord() { GrAssert(NULL == fEntry); }
+
+ GrTextureEntry* fEntry;
+ GrDrawTarget::SavedDrawState fSavedState;
+};
+
+bool GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
+ bool requireStencil,
+ OffscreenRecord* record) {
+#if !ENABLE_SSAA
+ return false;
+#endif
+
+ GrAssert(NULL == record->fEntry);
+
+ int width = this->getRenderTarget()->width();
+ int height = this->getRenderTarget()->height();
+
+ GrTextureDesc desc;
+ desc.fAALevel = kNone_GrAALevel;
+ if (requireStencil) {
+ desc.fFlags = kRenderTarget_GrTextureFlagBit;
+ } else {
+ desc.fFlags = kRenderTarget_GrTextureFlagBit |
+ kNoStencil_GrTextureFlagBit;
+ }
+
+ desc.fWidth = 2 * width;
+ desc.fHeight = 2 * height;
+ desc.fFormat = kRGBA_8888_GrPixelConfig;
+
+ record->fEntry = this->lockKeylessTexture(desc);
+ if (NULL == record->fEntry) {
+ return false;
+ }
+ GrRenderTarget* offscreen = record->fEntry->texture()->asRenderTarget();
+ GrAssert(NULL != offscreen);
+
+ target->saveCurrentDrawState(&record->fSavedState);
+
+ GrPaint tempPaint;
+ tempPaint.reset();
+ SetPaint(tempPaint, target);
+ target->setRenderTarget(offscreen);
+
+ GrMatrix scaleM;
+ scaleM.setScale(2 * GR_Scalar1, 2 * GR_Scalar1);
+ target->postConcatViewMatrix(scaleM);
+
+ // clip gets applied in second pass
+ target->disableState(GrDrawTarget::kClip_StateBit);
+
+ target->clear(0x0);
+ return true;
+}
+
+void GrContext::setupOffscreenAAPass2(GrDrawTarget* target,
+ const GrPaint& paint,
+ OffscreenRecord* record) {
+
+ GrAssert(NULL != record->fEntry);
+ GrTexture* offscreen = record->fEntry->texture();
+ GrAssert(NULL != offscreen);
+
+ target->restoreDrawState(record->fSavedState);
+
+ target->setViewMatrix(GrMatrix::I());
+ target->setTexture(kOffscreenStage, offscreen);
+ GrMatrix scaleM;
+
+ scaleM.setScale(GR_Scalar1 / target->getRenderTarget()->width(),
+ GR_Scalar1 / target->getRenderTarget()->height());
+
+ // use bilinear filtering to get downsample
+ GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
+ GrSamplerState::kClamp_WrapMode,
+ scaleM, true);
+ target->setSamplerState(kOffscreenStage, sampler);
+}
+
+void GrContext::endOffscreenAA(GrDrawTarget* target, OffscreenRecord* record) {
+ this->unlockTexture(record->fEntry);
+ record->fEntry = NULL;
+
+ target->restoreDrawState(record->fSavedState);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
/* create a triangle strip that strokes the specified triangle. There are 8
unique vertices, but we repreat the last 2 to close up. Alternatively we
could use an indices array, and then only send 8 verts, but not sure that
@@ -899,24 +991,45 @@
}
-////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
void GrContext::drawPath(const GrPaint& paint,
GrPathIter* path,
GrPathFill fill,
const GrPoint* translate) {
-
GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
+ GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
+ if (paint.fAntiAlias &&
+ !this->getRenderTarget()->isMultisampled() &&
+ !pr->supportsAA()) {
+
+ OffscreenRecord record;
+ bool needsStencil = pr->requiresStencilPass(target, path, fill);
+ if (this->setupOffscreenAAPass1(target, needsStencil, &record)) {
+ pr->drawPath(target, 0, path, fill, translate);
+
+ this->setupOffscreenAAPass2(target, paint, &record);
+
+ int stages = (NULL != paint.getTexture()) ? 0x1 : 0x0;
+ stages |= (1 << kOffscreenStage);
+ GrRect dstRect(0, 0,
+ target->getRenderTarget()->width(),
+ target->getRenderTarget()->height());
+ target->drawSimpleRect(dstRect, NULL, stages);
+
+ this->endOffscreenAA(target, &record);
+ return;
+ }
+ }
GrDrawTarget::StageBitfield enabledStages = 0;
if (NULL != paint.getTexture()) {
enabledStages |= 1;
}
- GrPathRenderer* pr = getPathRenderer(target, path, fill);
+
pr->drawPath(target, enabledStages, path, fill, translate);
}
-
void GrContext::drawPath(const GrPaint& paint,
const GrPath& path,
GrPathFill fill,
@@ -1205,3 +1318,4 @@
return &fDefaultPathRenderer;
}
}
+
diff --git a/gpu/src/GrDrawTarget.cpp b/gpu/src/GrDrawTarget.cpp
index 7c8e1c8..c33f15c 100644
--- a/gpu/src/GrDrawTarget.cpp
+++ b/gpu/src/GrDrawTarget.cpp
@@ -335,6 +335,10 @@
fCurrDrawState.fViewMatrix.preConcat(matrix);
}
+void GrDrawTarget::postConcatViewMatrix(const GrMatrix& matrix) {
+ fCurrDrawState.fViewMatrix.postConcat(matrix);
+}
+
const GrMatrix& GrDrawTarget::getViewMatrix() const {
return fCurrDrawState.fViewMatrix;
}
@@ -581,6 +585,9 @@
}
///////////////////////////////////////////////////////////////////////////////
+GrDrawTarget::AutoStateRestore::AutoStateRestore() {
+ fDrawTarget = NULL;
+}
GrDrawTarget::AutoStateRestore::AutoStateRestore(GrDrawTarget* target) {
fDrawTarget = target;
@@ -595,3 +602,14 @@
}
}
+void GrDrawTarget::AutoStateRestore::set(GrDrawTarget* target) {
+ if (target != fDrawTarget) {
+ if (NULL != fDrawTarget) {
+ fDrawTarget->restoreDrawState(fDrawState);
+ }
+ if (NULL != target) {
+ fDrawTarget->saveCurrentDrawState(&fDrawState);
+ }
+ fDrawTarget = target;
+ }
+}