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:
parent
1526129380
commit
8295dc1474
@ -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"
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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)) {
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user