From 06afe7b5a1ef03bfc6494c51ab2a1f7a386de5c2 Mon Sep 17 00:00:00 2001 From: "bsalomon@google.com" Date: Tue, 26 Apr 2011 15:31:40 +0000 Subject: [PATCH] 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 --- gpu/include/GrContext.h | 20 +++++++ gpu/include/GrDrawTarget.h | 20 +++++++ gpu/include/GrPathRenderer.h | 6 +++ gpu/src/GrContext.cpp | 126 ++++++++++++++++++++++++++++++++++++++++--- gpu/src/GrDrawTarget.cpp | 18 +++++++ 5 files changed, 184 insertions(+), 6 deletions(-) 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 @@ private: 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 @@ public: 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 @@ public: 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 @@ public: } /** + * @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 @@ void GrContext::freeGpuResources() { //////////////////////////////////////////////////////////////////////////////// - enum { kNPOTBit = 0x1, kFilterBit = 0x2, @@ -415,6 +416,97 @@ void GrContext::drawPaint(const GrPaint& paint) { //////////////////////////////////////////////////////////////////////////////// +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::drawVertices(const GrPaint& paint, } -//////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// 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 @@ GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target, 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 @@ void GrDrawTarget::preConcatViewMatrix(const GrMatrix& matrix) { 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 @@ void GrDrawTarget::SetRectVertices(const GrRect& rect, } /////////////////////////////////////////////////////////////////////////////// +GrDrawTarget::AutoStateRestore::AutoStateRestore() { + fDrawTarget = NULL; +} GrDrawTarget::AutoStateRestore::AutoStateRestore(GrDrawTarget* target) { fDrawTarget = target; @@ -595,3 +602,14 @@ GrDrawTarget::AutoStateRestore::~AutoStateRestore() { } } +void GrDrawTarget::AutoStateRestore::set(GrDrawTarget* target) { + if (target != fDrawTarget) { + if (NULL != fDrawTarget) { + fDrawTarget->restoreDrawState(fDrawState); + } + if (NULL != target) { + fDrawTarget->saveCurrentDrawState(&fDrawState); + } + fDrawTarget = target; + } +} -- 2.7.4