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
This commit is contained in:
bsalomon@google.com 2011-05-02 12:53:34 +00:00
parent 1526129380
commit 8295dc1474
13 changed files with 382 additions and 199 deletions

View File

@ -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"

View File

@ -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);
}
}

View File

@ -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.
*

View File

@ -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.

View File

@ -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

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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) {
void GrContext::offscreenAAPass2(GrDrawTarget* target,
const GrPaint& paint,
const GrIRect& boundRect,
OffscreenRecord* record) {
GrAssert(NULL != record->fEntry);
GrTexture* offscreen = record->fEntry->texture();
GrAssert(NULL != offscreen);
GrAssert(NULL != record->fEntry0);
target->restoreDrawState(record->fSavedState);
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()) {
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);
if (this->setupOffscreenAAPass1(target, needsStencil, &record)) {
pr->drawPath(target, 0, path, fill, translate);
target->setViewMatrix(GrMatrix::I());
this->setupOffscreenAAPass2(target, paint, &record);
OffscreenRecord record;
bool needsStencil = pr->requiresStencilPass(target, path, fill);
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);
// 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;
}
}
this->endOffscreenAA(target, &record);
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,

View File

@ -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;

View File

@ -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)) {

View File

@ -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);

View File

@ -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

View File

@ -21,11 +21,20 @@
static SkShader* make_shader0(SkIPoint* size) {
SkBitmap bm;
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();
SkImageDecoder::DecodeFile("/skimages/logo.png", &bm);
size->set(bm.width(), bm.height());
return SkShader::CreateBitmapShader(bm, SkShader::kClamp_TileMode,
SkShader::kClamp_TileMode);
return SkShader::CreateBitmapShader(bm, SkShader::kRepeat_TileMode,
SkShader::kRepeat_TileMode);
}
static SkShader* make_shader1(const SkIPoint& size) {