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/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;
     }
 }
+