aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gpu/include/GrContext.h17
-rw-r--r--gpu/include/GrContext_impl.h74
-rw-r--r--gpu/include/GrDrawTarget.h2
-rw-r--r--gpu/include/GrGpu.h6
-rw-r--r--gpu/include/GrPathRenderer.h4
-rw-r--r--gpu/include/GrRect.h60
-rw-r--r--gpu/include/GrTexture.h29
-rw-r--r--gpu/src/GrContext.cpp299
-rw-r--r--gpu/src/GrGLTexture.cpp1
-rw-r--r--gpu/src/GrGpuGL.cpp52
-rw-r--r--gpu/src/GrGpuGL.h4
-rw-r--r--gpu/src/GrTexture.cpp22
-rw-r--r--samplecode/SampleVertices.cpp19
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) {