diff options
author | bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2011-05-02 12:53:34 +0000 |
---|---|---|
committer | bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2011-05-02 12:53:34 +0000 |
commit | 8295dc1474db279df08d816b2115e807c681fad5 (patch) | |
tree | 5b5df977f1ae697b0b0279af749e6a79f0c3443c | |
parent | 152612938020fa46999f33668027d5bc0f7afd18 (diff) |
4x4 SSAA with improvements in determination of when to apply. Still disabled at compile time.
Review URL: http://codereview.appspot.com/4445075/
git-svn-id: http://skia.googlecode.com/svn/trunk@1218 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r-- | gpu/include/GrContext.h | 17 | ||||
-rw-r--r-- | gpu/include/GrContext_impl.h | 74 | ||||
-rw-r--r-- | gpu/include/GrDrawTarget.h | 2 | ||||
-rw-r--r-- | gpu/include/GrGpu.h | 6 | ||||
-rw-r--r-- | gpu/include/GrPathRenderer.h | 4 | ||||
-rw-r--r-- | gpu/include/GrRect.h | 60 | ||||
-rw-r--r-- | gpu/include/GrTexture.h | 29 | ||||
-rw-r--r-- | gpu/src/GrContext.cpp | 299 | ||||
-rw-r--r-- | gpu/src/GrGLTexture.cpp | 1 | ||||
-rw-r--r-- | gpu/src/GrGpuGL.cpp | 52 | ||||
-rw-r--r-- | gpu/src/GrGpuGL.h | 4 | ||||
-rw-r--r-- | gpu/src/GrTexture.cpp | 22 | ||||
-rw-r--r-- | samplecode/SampleVertices.cpp | 19 |
13 files changed, 386 insertions, 203 deletions
diff --git a/gpu/include/GrContext.h b/gpu/include/GrContext.h index 214fc0543f..faf535f553 100644 --- a/gpu/include/GrContext.h +++ b/gpu/include/GrContext.h @@ -614,21 +614,23 @@ private: kOffscreenStage = 1, }; + bool doOffscreenAA(GrDrawTarget* target, + const GrPaint& paint, + bool isLines) const; + // sets up target to draw coverage to the supersampled render target bool setupOffscreenAAPass1(GrDrawTarget* target, bool requireStencil, + const GrIRect& boundRect, OffscreenRecord* record); // sets up target to sample coverage of supersampled render target back // to the main render target using stage kOffscreenStage. - // caller should set view matrix to matrix used for this pass prior to - // calling. - void setupOffscreenAAPass2(GrDrawTarget* target, - const GrPaint& paint, - OffscreenRecord* record); + void offscreenAAPass2(GrDrawTarget* target, + const GrPaint& paint, + const GrIRect& boundRect, + OffscreenRecord* record); - // cleans up from supersample aa drawing - void endOffscreenAA(GrDrawTarget* target, OffscreenRecord* record); }; /** @@ -655,3 +657,4 @@ private: #endif #include "GrContext_impl.h" + diff --git a/gpu/include/GrContext_impl.h b/gpu/include/GrContext_impl.h index b0faa2cb2c..0fa3b8d298 100644 --- a/gpu/include/GrContext_impl.h +++ b/gpu/include/GrContext_impl.h @@ -18,10 +18,11 @@ #define GrContext_impl_DEFINED struct GrContext::OffscreenRecord { - OffscreenRecord() { fEntry = NULL; } - ~OffscreenRecord() { GrAssert(NULL == fEntry); } + OffscreenRecord() { fEntry0 = NULL; fEntry1 = NULL; } + ~OffscreenRecord() { GrAssert(NULL == fEntry0 && NULL == fEntry1); } - GrTextureEntry* fEntry; + GrTextureEntry* fEntry0; + GrTextureEntry* fEntry1; GrDrawTarget::SavedDrawState fSavedState; }; @@ -52,16 +53,6 @@ inline void GrContext::drawCustomVertices(const GrPaint& paint, layout |= GrDrawTarget::kColor_VertexLayoutBit; } - bool doOffscreenAA = false; - OffscreenRecord record; - if (paint.fAntiAlias && - !this->getRenderTarget()->isMultisampled() && - !(GrIsPrimTypeLines(primitiveType) && fGpu->supportsAALines()) && - this->setupOffscreenAAPass1(target, false, &record)) { - doOffscreenAA = true; - layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(kOffscreenStage); - } - int vertexCount = posSrc.count(); int indexCount = (NULL != idxSrc) ? idxSrc->count() : 0; @@ -94,51 +85,30 @@ inline void GrContext::drawCustomVertices(const GrPaint& paint, idxSrc->writeValue(i, indices + i); } + bool doAA = false; + OffscreenRecord record; + GrIRect bounds; + + if (-1 == texOffsets[0] && -1 == colorOffset && + this->doOffscreenAA(target, paint, GrIsPrimTypeLines(primitiveType))) { + GrRect b; + b.setBounds(geo.positions(), vertexCount); + target->getViewMatrix().mapRect(&b); + b.roundOut(&bounds); + if (this->setupOffscreenAAPass1(target, false, bounds, &record)) { + doAA = true; + } + } + if (NULL == idxSrc) { target->drawNonIndexed(primitiveType, 0, vertexCount); } else { target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount); } - if (doOffscreenAA) { - // draw to the offscreen - if (NULL != indices) { - target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount); - } else { - target->drawNonIndexed(primitiveType, 0, vertexCount); - } - // When there are custom texture coordinates we can't just draw - // a quad to sample the offscreen. Instead we redraw the geometry to - // specify the texture coords. This isn't quite right either, primitives - // will only be eroded at the edges, not expanded into partial pixels. - bool useRect = 0 == (layout & GrDrawTarget::StageTexCoordVertexLayoutBit(0,0)); - if (useRect) { - target->setViewMatrix(GrMatrix::I()); - } - this->setupOffscreenAAPass2(target, paint, &record); - if (useRect) { - geo.set(NULL, 0, 0, 0); - 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); - target->drawSimpleRect(dstRect, NULL, stages); - } else { - if (NULL != indices) { - target->drawIndexed (primitiveType, 0, 0, vertexCount, indexCount); - } else { - target->drawNonIndexed(primitiveType, 0, vertexCount); - } - } - this->endOffscreenAA(target, &record); - } else { - if (NULL != indices) { - target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount); - } else { - target->drawNonIndexed(primitiveType, 0, vertexCount); - } + if (doAA) { + geo.set(NULL, 0, 0, 0); // have to release geom before can draw again + this->offscreenAAPass2(target, paint, bounds, &record); } } diff --git a/gpu/include/GrDrawTarget.h b/gpu/include/GrDrawTarget.h index c971e717b7..6c92071322 100644 --- a/gpu/include/GrDrawTarget.h +++ b/gpu/include/GrDrawTarget.h @@ -551,7 +551,7 @@ public: * of vertices to be filled by caller. The next draw will read * these vertices. * - * if indecCount is nonzero, *indices will be the array of indices + * if indexCount is nonzero, *indices will be the array of indices * to be filled by caller. The next indexed draw will read from * these indices. * diff --git a/gpu/include/GrGpu.h b/gpu/include/GrGpu.h index 590712bd48..16bb6b6933 100644 --- a/gpu/include/GrGpu.h +++ b/gpu/include/GrGpu.h @@ -229,6 +229,11 @@ public: * value. */ int minRenderTargetHeight() const { return fMinRenderTargetHeight; } + + /** + * Reports whether full scene anti-aliasing is supported. + */ + bool supportsFullsceneAA() const { return fFSAASupport; } /** * Returns true if NPOT textures can be created @@ -391,6 +396,7 @@ protected: bool fTwoSidedStencilSupport; bool fStencilWrapOpsSupport; bool fAALineSupport; + bool fFSAASupport; // set by subclass to true if index and vertex buffers can be locked, false // otherwise. diff --git a/gpu/include/GrPathRenderer.h b/gpu/include/GrPathRenderer.h index 03092b6118..21cab6bb1a 100644 --- a/gpu/include/GrPathRenderer.h +++ b/gpu/include/GrPathRenderer.h @@ -112,7 +112,9 @@ 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; } + virtual bool supportsAA(GrDrawTarget* target, + GrPathIter* path, + GrPathFill fill) { return false; } /** * This is called to install a custom path renderer in every GrContext at diff --git a/gpu/include/GrRect.h b/gpu/include/GrRect.h index 8a63cdc690..7d03396bac 100644 --- a/gpu/include/GrRect.h +++ b/gpu/include/GrRect.h @@ -63,6 +63,11 @@ struct GrIRect { fRight = fBottom = GR_Int32Max; } + void setLargestInverted() { + fLeft = fTop = GR_Int32Max; + fRight = fBottom = GR_Int32Min; + } + bool quickReject(int l, int t, int r, int b) const { return l >= fRight || fLeft >= r || t >= fBottom || fTop >= b; } @@ -95,6 +100,35 @@ struct GrIRect { } } + bool intersectWith(int left, int top, + int right, int bottom) { + if (fRight < left || + fLeft > right || + fBottom < top || + fTop > bottom) { + this->setEmpty(); + return false; + } else { + fLeft = GrMax(fLeft, left); + fRight = GrMin(fRight, right); + fTop = GrMax(fTop, top); + fBottom = GrMin(fBottom, bottom); + return true; + } + } + + /** + * Enlarge the rectangle to include rect. + */ + void growToInclude(const GrIRect& rect) { + GrAssert(!rect.isEmpty()); + fLeft = GrMin(rect.fLeft, fLeft); + fRight = GrMax(rect.fRight, fRight); + + fTop = GrMin(rect.fTop, fTop); + fBottom = GrMax(rect.fBottom, fBottom); + } + friend bool operator==(const GrIRect& a, const GrIRect& b) { return 0 == memcmp(&a, &b, sizeof(a)); } @@ -118,6 +152,11 @@ struct GrIRect { fTop <= r.fTop && fBottom >= r.fBottom; } + + static const GrIRect& EmptyIRect() { + static const GrIRect gEmpty(0,0,0,0); + return gEmpty; + } }; struct GrIRect16 { @@ -367,17 +406,36 @@ struct GrRect { * Sets this rect to the intersection with a clip rect. If there is no * intersection then this rect will be made empty. */ - void intersectWith(const GrRect& clipRect) { + bool intersectWith(const GrRect& clipRect) { if (fRight < clipRect.fLeft || fLeft > clipRect.fRight || fBottom < clipRect.fTop || fTop > clipRect.fBottom) { this->setEmpty(); + return false; } else { fLeft = GrMax(fLeft, clipRect.fLeft); fRight = GrMin(fRight, clipRect.fRight); fTop = GrMax(fTop, clipRect.fTop); fBottom = GrMin(fBottom, clipRect.fBottom); + return true; + } + } + + bool intersectWith(GrScalar left, GrScalar top, + GrScalar right, GrScalar bottom) { + if (fRight < left || + fLeft > right || + fBottom < top || + fTop > bottom) { + this->setEmpty(); + return false; + } else { + fLeft = GrMax(fLeft, left); + fRight = GrMin(fRight, right); + fTop = GrMax(fTop, top); + fBottom = GrMin(fBottom, bottom); + return true; } } diff --git a/gpu/include/GrTexture.h b/gpu/include/GrTexture.h index 6d4f4d76a9..0e2f369621 100644 --- a/gpu/include/GrTexture.h +++ b/gpu/include/GrTexture.h @@ -65,21 +65,31 @@ public: * when the render target has been modified outside of Gr. Only meaningful * for Gr-created RT/Textures and Platform RT/Textures created with the * kGrCanResolve flag. + * @param rect a rect bounding the area needing resolve. NULL indicates + * the whole RT needs resolving. */ - void flagAsNeedingResolve() { - fNeedsResolve = kCanResolve_ResolveType == getResolveType(); - } + void flagAsNeedingResolve(const GrIRect* rect = NULL); + + /** + * Call to override the region that needs to be resolved. + */ + void overrideResolveRect(const GrIRect rect); /** * Call to indicate that GrRenderTarget was externally resolved. This may * allow Gr to skip a redundant resolve step. */ - void flagAsResolved() { fNeedsResolve = false; } + void flagAsResolved() { fResolveRect.setLargestInverted(); } /** * @return true if the GrRenderTarget requires MSAA resolving */ - bool needsResolve() { return fNeedsResolve; } + bool needsResolve() const { return !fResolveRect.isEmpty(); } + + /** + * Returns a rect bounding the region needing resolving. + */ + const GrIRect& getResolveRect() const { return fResolveRect; } /** * Reads a rectangle of pixels from the render target. @@ -119,8 +129,9 @@ protected: , fHeight(height) , fStencilBits(stencilBits) , fIsMultisampled(isMultisampled) - , fNeedsResolve(false) - {} + { + fResolveRect.setLargestInverted(); + } friend class GrTexture; // When a texture unrefs an owned rendertarget this func @@ -133,14 +144,14 @@ protected: fTexture = NULL; } +private: GrTexture* fTexture; // not ref'ed int fWidth; int fHeight; int fStencilBits; bool fIsMultisampled; - bool fNeedsResolve; + GrIRect fResolveRect; -private: // GrGpu keeps a cached clip in the render target to avoid redundantly // rendering the clip into the same stencil buffer. friend class GrGpu; diff --git a/gpu/src/GrContext.cpp b/gpu/src/GrContext.cpp index d3904e00a6..2263172c52 100644 --- a/gpu/src/GrContext.cpp +++ b/gpu/src/GrContext.cpp @@ -26,7 +26,7 @@ #include "GrBufferAllocPool.h" #include "GrPathRenderer.h" -#define ENABLE_SSAA 0 +#define ENABLE_OFFSCREEN_AA 0 #define DEFER_TEXT_RENDERING 1 @@ -414,20 +414,49 @@ void GrContext::drawPaint(const GrPaint& paint) { //////////////////////////////////////////////////////////////////////////////// +bool GrContext::doOffscreenAA(GrDrawTarget* target, + const GrPaint& paint, + bool isLines) const { +#if !ENABLE_OFFSCREEN_AA + return false; +#else + if (!paint.fAntiAlias) { + return false; + } + if (isLines && fGpu->supportsAALines()) { + return false; + } + if (target->getRenderTarget()->isMultisampled()) { + return false; + } + // we have to be sure that the blend equation is expressible + // as simple src / dst coeffecients when the source + // is already modulated by the coverage fraction. + // We could use dual-source blending to get the correct per-pixel + // dst coeffecient for the remaining cases. + if (kISC_BlendCoeff != paint.fDstBlendCoeff && + kOne_BlendCoeff != paint.fDstBlendCoeff && + kISA_BlendCoeff != paint.fDstBlendCoeff) { + return false; + } + return true; +#endif +} + bool GrContext::setupOffscreenAAPass1(GrDrawTarget* target, bool requireStencil, + const GrIRect& boundRect, OffscreenRecord* record) { -#if !ENABLE_SSAA - return false; -#endif + GrAssert(ENABLE_OFFSCREEN_AA); - GrAssert(NULL == record->fEntry); + GrAssert(NULL == record->fEntry0); + GrAssert(NULL == record->fEntry1); - int width = this->getRenderTarget()->width(); - int height = this->getRenderTarget()->height(); + int boundW = boundRect.width(); + int boundH = boundRect.height(); + int size = GrMax(64, (int)GrNextPow2(GrMax(boundW, boundH))); GrTextureDesc desc; - desc.fAALevel = kNone_GrAALevel; if (requireStencil) { desc.fFlags = kRenderTarget_GrTextureFlagBit; } else { @@ -435,63 +464,133 @@ bool GrContext::setupOffscreenAAPass1(GrDrawTarget* target, kNoStencil_GrTextureFlagBit; } - desc.fWidth = 2 * width; - desc.fHeight = 2 * height; desc.fFormat = kRGBA_8888_GrPixelConfig; - record->fEntry = this->lockKeylessTexture(desc); - if (NULL == record->fEntry) { + int scale; + // Using MSAA seems to be slower for some yet unknown reason. + if (false && fGpu->supportsFullsceneAA()) { + scale = GR_Scalar1; + desc.fAALevel = kMed_GrAALevel; + } else { + scale = 4; + desc.fAALevel = kNone_GrAALevel; + } + + desc.fWidth = scale * size; + desc.fHeight = scale * size; + + record->fEntry0 = this->lockKeylessTexture(desc); + + if (NULL == record->fEntry0) { return false; } - GrRenderTarget* offscreen = record->fEntry->texture()->asRenderTarget(); - GrAssert(NULL != offscreen); + + if (scale > 1) { + desc.fWidth /= 2; + desc.fHeight /= 2; + record->fEntry1 = this->lockKeylessTexture(desc); + if (NULL == record->fEntry1) { + this->unlockTexture(record->fEntry0); + record->fEntry0 = NULL; + return false; + } + } + + GrRenderTarget* offRT0 = record->fEntry0->texture()->asRenderTarget(); + GrAssert(NULL != offRT0); target->saveCurrentDrawState(&record->fSavedState); GrPaint tempPaint; tempPaint.reset(); SetPaint(tempPaint, target); - target->setRenderTarget(offscreen); + target->setRenderTarget(offRT0); + GrMatrix transM; + transM.setTranslate(-boundRect.fLeft, -boundRect.fTop); + target->postConcatViewMatrix(transM); GrMatrix scaleM; - scaleM.setScale(2 * GR_Scalar1, 2 * GR_Scalar1); + scaleM.setScale(scale * GR_Scalar1, scale * GR_Scalar1); target->postConcatViewMatrix(scaleM); // clip gets applied in second pass target->disableState(GrDrawTarget::kClip_StateBit); - target->clear(NULL, 0x0); + GrIRect clear(0, 0, scale * boundW, scale * boundH); + target->clear(&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); +void GrContext::offscreenAAPass2(GrDrawTarget* target, + const GrPaint& paint, + const GrIRect& boundRect, + OffscreenRecord* record) { - target->restoreDrawState(record->fSavedState); + GrAssert(NULL != record->fEntry0); - target->setTexture(kOffscreenStage, offscreen); + bool downsample = NULL != record->fEntry1; + GrMatrix sampleM; - sampleM.setScale(GR_Scalar1 / target->getRenderTarget()->width(), - GR_Scalar1 / target->getRenderTarget()->height()); - sampleM.preConcat(target->getViewMatrix()); - - // use bilinear filtering to get downsample GrSamplerState sampler(GrSamplerState::kClamp_WrapMode, - GrSamplerState::kClamp_WrapMode, - sampleM, true); + GrSamplerState::kClamp_WrapMode, true); + + GrTexture* src = record->fEntry0->texture(); + int scale; + + if (downsample) { + scale = 2; + GrRenderTarget* dst = record->fEntry1->texture()->asRenderTarget(); + + // Do 2x2 downsample from first to second + target->setTexture(kOffscreenStage, src); + target->setRenderTarget(dst); + target->setViewMatrix(GrMatrix::I()); + sampleM.setScale(scale * GR_Scalar1 / src->width(), + scale * GR_Scalar1 / src->height()); + sampler.setMatrix(sampleM); + target->setSamplerState(kOffscreenStage, sampler); + GrRect rect(0, 0, + scale * boundRect.width(), + scale * boundRect.height()); + target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage); + + src = record->fEntry1->texture(); + } else { + scale = 1; + GrIRect rect(0, 0, boundRect.width(), boundRect.height()); + src->asRenderTarget()->overrideResolveRect(rect); + } + + // setup for draw back to main RT + target->restoreDrawState(record->fSavedState); + if (NULL != paint.getTexture()) { + GrMatrix invVM; + if (target->getViewInverse(&invVM)) { + target->preConcatSamplerMatrix(0, invVM); + } + } + target->setViewMatrix(GrMatrix::I()); + + target->setTexture(kOffscreenStage, src); + sampleM.setScale(scale * GR_Scalar1 / src->width(), + scale * GR_Scalar1 / src->height()); + sampler.setMatrix(sampleM); + sampleM.setTranslate(-boundRect.fLeft, -boundRect.fTop); + sampler.preConcatMatrix(sampleM); target->setSamplerState(kOffscreenStage, sampler); -} -void GrContext::endOffscreenAA(GrDrawTarget* target, OffscreenRecord* record) { - this->unlockTexture(record->fEntry); - record->fEntry = NULL; + GrRect dstRect(boundRect); + int stages = (1 << kOffscreenStage) | (NULL == paint.getTexture() ? 0 : 1); + target->drawSimpleRect(dstRect, NULL, stages); - target->restoreDrawState(record->fSavedState); + this->unlockTexture(record->fEntry0); + record->fEntry0 = NULL; + if (downsample) { + this->unlockTexture(record->fEntry1); + record->fEntry1 = NULL; + } + target->restoreDrawState(record->fSavedState); } //////////////////////////////////////////////////////////////////////////////// @@ -838,7 +937,7 @@ void GrContext::drawRect(const GrPaint& paint, fGpu->getUnitSquareVertexBuffer()); GrDrawTarget::AutoViewMatrixRestore avmr(target); GrMatrix m; - m.setAll(rect.width(), 0, rect.fLeft, + m.setAll(rect.width(), 0, rect.fLeft, 0, rect.height(), rect.fTop, 0, 0, GrMatrix::I()[8]); @@ -944,15 +1043,9 @@ void GrContext::drawVertices(const GrPaint& paint, vertexSize += sizeof(GrColor); } - bool doOffscreenAA = false; + bool doAA = false; OffscreenRecord record; - if (paint.fAntiAlias && - !this->getRenderTarget()->isMultisampled() && - !(GrIsPrimTypeLines(primitiveType) && fGpu->supportsAALines()) && - this->setupOffscreenAAPass1(target, false, &record)) { - doOffscreenAA = true; - layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(kOffscreenStage); - } + GrIRect bounds; if (sizeof(GrPoint) != vertexSize) { if (!geo.set(target, layout, vertexCount, 0)) { @@ -978,6 +1071,17 @@ void GrContext::drawVertices(const GrPaint& paint, curVertex = (void*)((intptr_t)curVertex + vsize); } } else { + // we don't do offscreen AA when we have per-vertex tex coords or colors + if (this->doOffscreenAA(target, paint, GrIsPrimTypeLines(primitiveType))) { + GrRect b; + b.setBounds(positions, vertexCount); + target->getViewMatrix().mapRect(&b); + b.roundOut(&bounds); + + if (this->setupOffscreenAAPass1(target, false, bounds, &record)) { + doAA = true; + } + } target->setVertexSourceToArray(layout, positions, vertexCount); } @@ -985,45 +1089,14 @@ void GrContext::drawVertices(const GrPaint& paint, target->setIndexSourceToArray(indices, indexCount); } - if (doOffscreenAA) { - // draw to the offscreen - if (NULL != indices) { - target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount); - } else { - target->drawNonIndexed(primitiveType, 0, vertexCount); - } - // When there are custom texture coordinates we can't just draw - // a quad to sample the offscreen. Instead we redraw the geometry to - // specify the texture coords. This isn't quite right either, primitives - // will only be eroded at the edges, not expanded into partial pixels. - bool useRect = 0 == (layout & GrDrawTarget::StageTexCoordVertexLayoutBit(0,0)); - if (useRect) { - target->setViewMatrix(GrMatrix::I()); - } - this->setupOffscreenAAPass2(target, paint, &record); - if (useRect) { - geo.set(NULL, 0, 0, 0); - 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); - target->drawSimpleRect(dstRect, NULL, stages); - } else { - if (NULL != indices) { - target->drawIndexed (primitiveType, 0, 0, vertexCount, indexCount); - } else { - target->drawNonIndexed(primitiveType, 0, vertexCount); - } - } - this->endOffscreenAA(target, &record); + if (NULL != indices) { + target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount); } else { - if (NULL != indices) { - target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount); - } else { - target->drawNonIndexed(primitiveType, 0, vertexCount); - } + target->drawNonIndexed(primitiveType, 0, vertexCount); + } + + if (doAA) { + this->offscreenAAPass2(target, paint, bounds, &record); } } @@ -1038,28 +1111,39 @@ void GrContext::drawPath(const GrPaint& paint, 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); - - target->setViewMatrix(GrMatrix::I()); - 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; - } + if (!IsFillInverted(fill) && // will be relaxed soon + !pr->supportsAA(target, path, fill) && + this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) { + + OffscreenRecord record; + bool needsStencil = pr->requiresStencilPass(target, path, fill); + + // compute bounds as intersection of rt size, clip, and path + GrIRect bound(0, 0, + target->getRenderTarget()->width(), + target->getRenderTarget()->height()); + if (target->getClip().hasConservativeBounds()) { + GrIRect clipIBounds; + target->getClip().getConservativeBounds().roundOut(&clipIBounds); + if (!bound.intersectWith(clipIBounds)) { + return; + } + } + GrRect pathBounds; + if (path->getConservativeBounds(&pathBounds)) { + GrIRect pathIBounds; + target->getViewMatrix().mapRect(&pathBounds, pathBounds); + pathBounds.roundOut(&pathIBounds); + if (!bound.intersectWith(pathIBounds)) { + return; + } + } + + if (this->setupOffscreenAAPass1(target, needsStencil, bound, &record)) { + pr->drawPath(target, 0, path, fill, translate); + this->offscreenAAPass2(target, paint, bound, &record); + return; + } } GrDrawTarget::StageBitfield enabledStages = 0; if (NULL != paint.getTexture()) { @@ -1068,6 +1152,7 @@ void GrContext::drawPath(const GrPaint& paint, pr->drawPath(target, enabledStages, path, fill, translate); } + void GrContext::drawPath(const GrPaint& paint, const GrPath& path, GrPathFill fill, diff --git a/gpu/src/GrGLTexture.cpp b/gpu/src/GrGLTexture.cpp index 3c6504d6cb..d3ccfa6b2c 100644 --- a/gpu/src/GrGLTexture.cpp +++ b/gpu/src/GrGLTexture.cpp @@ -33,7 +33,6 @@ GrGLRenderTarget::GrGLRenderTarget(GrGpuGL* gpu, fTexFBOID = ids.fTexFBOID; fStencilRenderbufferID = ids.fStencilRenderbufferID; fMSColorRenderbufferID = ids.fMSColorRenderbufferID; - fNeedsResolve = false; fViewport = viewport; fOwnIDs = ids.fOwnIDs; fTexIDObj = texID; diff --git a/gpu/src/GrGpuGL.cpp b/gpu/src/GrGpuGL.cpp index 352ad3f39b..721d084d12 100644 --- a/gpu/src/GrGpuGL.cpp +++ b/gpu/src/GrGpuGL.cpp @@ -281,6 +281,7 @@ GrGpuGL::GrGpuGL() { GrPrintf("\tMax Samples: %d\n", maxSamples); } } + fFSAASupport = fAASamples[kHigh_GrAALevel] > 0; if (GR_GL_SUPPORT_DESKTOP) { fHasStencilWrap = (major >= 2 || (major == 1 && minor >= 4)) || @@ -1183,7 +1184,7 @@ void GrGpuGL::onClear(const GrIRect* rect, GrColor color) { return; } } - this->flushRenderTarget(); + this->flushRenderTarget(rect); this->flushScissor(rect); GR_GL(ColorMask(GR_GL_TRUE,GR_GL_TRUE,GR_GL_TRUE,GR_GL_TRUE)); fHWDrawState.fFlagBits &= ~kNoColorWrites_StateBit; @@ -1198,7 +1199,9 @@ void GrGpuGL::clearStencil(uint32_t value, uint32_t mask) { if (NULL == fCurrDrawState.fRenderTarget) { return; } - flushRenderTarget(); + + this->flushRenderTarget(&GrIRect::EmptyIRect()); + if (fHWBounds.fScissorEnabled) { GR_GL(Disable(GR_GL_SCISSOR_TEST)); fHWBounds.fScissorEnabled = false; @@ -1223,7 +1226,7 @@ void GrGpuGL::clearStencilClip(const GrIRect& rect) { // zero the client's clip bits. So we just clear the whole thing. static const GrGLint clipStencilMask = ~0; #endif - flushRenderTarget(); + this->flushRenderTarget(&GrIRect::EmptyIRect()); flushScissor(&rect); GR_GL(StencilMask(clipStencilMask)); GR_GL(ClearStencil(0)); @@ -1232,7 +1235,7 @@ void GrGpuGL::clearStencilClip(const GrIRect& rect) { } void GrGpuGL::onForceRenderTargetFlush() { - flushRenderTarget(); + this->flushRenderTarget(&GrIRect::EmptyIRect()); } bool GrGpuGL::onReadPixels(GrRenderTarget* target, @@ -1252,10 +1255,10 @@ bool GrGpuGL::onReadPixels(GrRenderTarget* target, case GrGLRenderTarget::kAutoResolves_ResolveType: autoTargetRestore.save(&fCurrDrawState.fRenderTarget); fCurrDrawState.fRenderTarget = target; - flushRenderTarget(); + this->flushRenderTarget(&GrIRect::EmptyIRect()); break; case GrGLRenderTarget::kCanResolve_ResolveType: - resolveRenderTarget(tgt); + this->resolveRenderTarget(tgt); // we don't track the state of the READ FBO ID. GR_GL(BindFramebuffer(GR_GL_READ_FRAMEBUFFER, tgt->textureFBOID())); break; @@ -1293,17 +1296,16 @@ bool GrGpuGL::onReadPixels(GrRenderTarget* target, return true; } -void GrGpuGL::flushRenderTarget() { +void GrGpuGL::flushRenderTarget(const GrIRect* bound) { GrAssert(NULL != fCurrDrawState.fRenderTarget); + GrGLRenderTarget* rt = (GrGLRenderTarget*)fCurrDrawState.fRenderTarget; if (fHWDrawState.fRenderTarget != fCurrDrawState.fRenderTarget) { - GrGLRenderTarget* rt = (GrGLRenderTarget*)fCurrDrawState.fRenderTarget; GR_GL(BindFramebuffer(GR_GL_FRAMEBUFFER, rt->renderFBOID())); #if GR_COLLECT_STATS ++fStats.fRenderTargetChngCnt; #endif - rt->flagAsNeedingResolve(); #if GR_DEBUG GrGLenum status = GR_GL(CheckFramebufferStatus(GR_GL_FRAMEBUFFER)); if (status != GR_GL_FRAMEBUFFER_COMPLETE) { @@ -1318,6 +1320,9 @@ void GrGpuGL::flushRenderTarget() { fHWBounds.fViewportRect = vp; } } + if (NULL == bound || !bound->isEmpty()) { + rt->flagAsNeedingResolve(bound); + } } GrGLenum gPrimitiveType2GLMode[] = { @@ -1427,12 +1432,16 @@ void GrGpuGL::resolveRenderTarget(GrGLRenderTarget* rt) { // the bound DRAW FBO ID. fHWDrawState.fRenderTarget = NULL; const GrGLIRect& vp = rt->getViewport(); + const GrIRect dirtyRect = rt->getResolveRect(); + GrGLIRect r; + r.setRelativeTo(vp, dirtyRect.fLeft, dirtyRect.fTop, + dirtyRect.width(), dirtyRect.height()); if (kAppleES_MSFBO == fMSFBOType) { // Apple's extension uses the scissor as the blit bounds. GR_GL(Enable(GR_GL_SCISSOR_TEST)); - GR_GL(Scissor(vp.fLeft, vp.fBottom, - vp.fWidth, vp.fHeight)); + GR_GL(Scissor(r.fLeft, r.fBottom, + r.fWidth, r.fHeight)); GR_GL(ResolveMultisampleFramebuffer()); fHWBounds.fScissorRect.invalidate(); fHWBounds.fScissorEnabled = true; @@ -1442,10 +1451,10 @@ void GrGpuGL::resolveRenderTarget(GrGLRenderTarget* rt) { GrAssert(kDesktopEXT_MSFBO == fMSFBOType); flushScissor(NULL); } - int right = vp.fLeft + vp.fWidth; - int top = vp.fBottom + vp.fHeight; - GR_GL(BlitFramebuffer(vp.fLeft, vp.fBottom, right, top, - vp.fLeft, vp.fBottom, right, top, + int right = r.fLeft + r.fWidth; + int top = r.fBottom + r.fHeight; + GR_GL(BlitFramebuffer(r.fLeft, r.fBottom, right, top, + r.fLeft, r.fBottom, right, top, GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST)); } rt->flagAsResolved(); @@ -1781,9 +1790,16 @@ bool GrGpuGL::flushGLStateCommon(GrPrimitiveType type) { } } - flushRenderTarget(); - flushAAState(type); - flushBlend(type); + GrIRect* rect = NULL; + GrIRect clipBounds; + if ((fCurrDrawState.fFlagBits & kClip_StateBit) && + fClip.hasConservativeBounds()) { + fClip.getConservativeBounds().roundOut(&clipBounds); + rect = &clipBounds; + } + this->flushRenderTarget(rect); + this->flushAAState(type); + this->flushBlend(type); if ((fCurrDrawState.fFlagBits & kDither_StateBit) != (fHWDrawState.fFlagBits & kDither_StateBit)) { diff --git a/gpu/src/GrGpuGL.h b/gpu/src/GrGpuGL.h index bfa73513e7..da955cfc56 100644 --- a/gpu/src/GrGpuGL.h +++ b/gpu/src/GrGpuGL.h @@ -155,7 +155,9 @@ private: bool useSmoothLines(); - void flushRenderTarget(); + // bound is region that may be modified and therefore has to be resolved. + // NULL means whole target. Can be an empty rect. + void flushRenderTarget(const GrIRect* bound); void flushStencil(); void flushAAState(GrPrimitiveType type); void flushBlend(GrPrimitiveType type); diff --git a/gpu/src/GrTexture.cpp b/gpu/src/GrTexture.cpp index 1ea02a77b7..e9ec4e6342 100644 --- a/gpu/src/GrTexture.cpp +++ b/gpu/src/GrTexture.cpp @@ -28,6 +28,28 @@ bool GrRenderTarget::readPixels(int left, int top, int width, int height, config, buffer); } +void GrRenderTarget::flagAsNeedingResolve(const GrIRect* rect) { + if (kCanResolve_ResolveType == getResolveType()) { + if (NULL != rect) { + fResolveRect.growToInclude(*rect); + fResolveRect.intersectWith(0, 0, this->width(), this->height()); + } else { + fResolveRect.setLTRB(0, 0, this->width(), this->height()); + } + } +} + +void GrRenderTarget::overrideResolveRect(const GrIRect rect) { + fResolveRect = rect; + if (fResolveRect.isEmpty()) { + fResolveRect.setLargestInverted(); + } else { + if (!fResolveRect.intersectWith(0, 0, this->width(), this->height())) { + fResolveRect.setLargestInverted(); + } + } +} + bool GrTexture::readPixels(int left, int top, int width, int height, GrPixelConfig config, void* buffer) { // go through context so that all necessary flushing occurs diff --git a/samplecode/SampleVertices.cpp b/samplecode/SampleVertices.cpp index f260e1af25..4557cc4e17 100644 --- a/samplecode/SampleVertices.cpp +++ b/samplecode/SampleVertices.cpp @@ -21,11 +21,20 @@ static SkShader* make_shader0(SkIPoint* size) { SkBitmap bm; - - SkImageDecoder::DecodeFile("/skimages/logo.png", &bm); - size->set(bm.width(), bm.height()); - return SkShader::CreateBitmapShader(bm, SkShader::kClamp_TileMode, - SkShader::kClamp_TileMode); + size->set(2, 2); + bm.setConfig(SkBitmap::kARGB_8888_Config, size->fX, size->fY); + SkPMColor color0 = SkPreMultiplyARGB(0x80, 0x80, 0xff, 0x80); + SkPMColor color1 = SkPreMultiplyARGB(0x40, 0xff, 0x00, 0xff); + bm.allocPixels(); + bm.eraseColor(color0); + bm.lockPixels(); + uint32_t* pixels = (uint32_t*) bm.getPixels(); + pixels[0] = pixels[2] = color0; + pixels[1] = pixels[3] = color1; + bm.unlockPixels(); + + return SkShader::CreateBitmapShader(bm, SkShader::kRepeat_TileMode, + SkShader::kRepeat_TileMode); } static SkShader* make_shader1(const SkIPoint& size) { |