Implement filling a path with nv_path_rendering cover

Implement filling a path with nv_path_rendering cover functionality.

The nv_path_rendering cover can be used if the fill is non-inverted
and the draw operation does not require use of vertex shaders.

Moves code for the inverted fill from GrStencilAndCoverPathRenderer
down to GrGpuGL.

R=bsalomon@google.com, markkilgard@gmail.com, cdalton@nvidia.com

Author: kkinnunen@nvidia.com

Review URL: https://codereview.chromium.org/22686002

git-svn-id: http://skia.googlecode.com/svn/trunk@11667 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
commit-bot@chromium.org 2013-10-09 14:11:33 +00:00
parent 6ec1abf21e
commit c4dc0ad8e2
18 changed files with 328 additions and 175 deletions

View File

@ -608,6 +608,7 @@ enum GrGLBackendState {
kProgram_GrGLBackendState = 1 << 8, kProgram_GrGLBackendState = 1 << 8,
kFixedFunction_GrGLBackendState = 1 << 9, kFixedFunction_GrGLBackendState = 1 << 9,
kMisc_GrGLBackendState = 1 << 10, kMisc_GrGLBackendState = 1 << 10,
kPathRendering_GrGLBackendState = 1 << 11,
kALL_GrGLBackendState = 0xffff kALL_GrGLBackendState = 0xffff
}; };

View File

@ -1012,3 +1012,29 @@ void GrClipMaskManager::setGpu(GrGpu* gpu) {
fGpu = gpu; fGpu = gpu;
fAACache.setContext(gpu->getContext()); fAACache.setContext(gpu->getContext());
} }
void GrClipMaskManager::adjustPathStencilParams(GrStencilSettings* settings) {
const GrDrawState& drawState = fGpu->getDrawState();
GrClipMaskManager::StencilClipMode clipMode;
if (this->isClipInStencil() && drawState.isClipState()) {
clipMode = GrClipMaskManager::kRespectClip_StencilClipMode;
// We can't be modifying the clip and respecting it at the same time.
SkASSERT(!drawState.isStateFlagEnabled(
GrGpu::kModifyStencilClip_StateBit));
} else if (drawState.isStateFlagEnabled(
GrGpu::kModifyStencilClip_StateBit)) {
clipMode = GrClipMaskManager::kModifyClip_StencilClipMode;
} else {
clipMode = GrClipMaskManager::kIgnoreClip_StencilClipMode;
}
// TODO: dynamically attach a stencil buffer
int stencilBits = 0;
GrStencilBuffer* stencilBuffer =
drawState.getRenderTarget()->getStencilBuffer();
if (NULL != stencilBuffer) {
stencilBits = stencilBuffer->bits();
this->adjustStencilParams(settings, clipMode, stencilBits);
}
}

View File

@ -70,6 +70,8 @@ public:
} }
void setGpu(GrGpu* gpu); void setGpu(GrGpu* gpu);
void adjustPathStencilParams(GrStencilSettings* settings);
private: private:
/** /**
* Informs the helper function adjustStencilParams() about how the stencil * Informs the helper function adjustStencilParams() about how the stencil

View File

@ -11,6 +11,7 @@
#include "GrDrawTarget.h" #include "GrDrawTarget.h"
#include "GrContext.h" #include "GrContext.h"
#include "GrDrawTargetCaps.h" #include "GrDrawTargetCaps.h"
#include "GrPath.h"
#include "GrRenderTarget.h" #include "GrRenderTarget.h"
#include "GrTexture.h" #include "GrTexture.h"
#include "GrVertexBuffer.h" #include "GrVertexBuffer.h"
@ -413,17 +414,18 @@ bool GrDrawTarget::checkDraw(GrPrimitiveType type, int startVertex,
return true; return true;
} }
bool GrDrawTarget::setupDstReadIfNecessary(DrawInfo* info) { bool GrDrawTarget::setupDstReadIfNecessary(GrDeviceCoordTexture* dstCopy, const SkRect* drawBounds) {
if (this->caps()->dstReadInShaderSupport() || !this->getDrawState().willEffectReadDstColor()) { if (this->caps()->dstReadInShaderSupport() || !this->getDrawState().willEffectReadDstColor()) {
return true; return true;
} }
GrRenderTarget* rt = this->drawState()->getRenderTarget(); GrRenderTarget* rt = this->drawState()->getRenderTarget();
const GrClipData* clip = this->getClip();
SkIRect copyRect; SkIRect copyRect;
clip->getConservativeBounds(this->getDrawState().getRenderTarget(), &copyRect); const GrClipData* clip = this->getClip();
SkIRect drawIBounds; clip->getConservativeBounds(rt, &copyRect);
if (info->getDevIBounds(&drawIBounds)) {
if (NULL != drawBounds) {
SkIRect drawIBounds;
drawBounds->roundOut(&drawIBounds);
if (!copyRect.intersect(drawIBounds)) { if (!copyRect.intersect(drawIBounds)) {
#ifdef SK_DEBUG #ifdef SK_DEBUG
GrPrintf("Missed an early reject. Bailing on draw from setupDstReadIfNecessary.\n"); GrPrintf("Missed an early reject. Bailing on draw from setupDstReadIfNecessary.\n");
@ -451,8 +453,8 @@ bool GrDrawTarget::setupDstReadIfNecessary(DrawInfo* info) {
} }
SkIPoint dstPoint = {0, 0}; SkIPoint dstPoint = {0, 0};
if (this->copySurface(ast.texture(), rt, copyRect, dstPoint)) { if (this->copySurface(ast.texture(), rt, copyRect, dstPoint)) {
info->fDstCopy.setTexture(ast.texture()); dstCopy->setTexture(ast.texture());
info->fDstCopy.setOffset(copyRect.fLeft, copyRect.fTop); dstCopy->setOffset(copyRect.fLeft, copyRect.fTop);
return true; return true;
} else { } else {
return false; return false;
@ -518,12 +520,37 @@ void GrDrawTarget::drawNonIndexed(GrPrimitiveType type,
void GrDrawTarget::stencilPath(const GrPath* path, const SkStrokeRec& stroke, SkPath::FillType fill) { void GrDrawTarget::stencilPath(const GrPath* path, const SkStrokeRec& stroke, SkPath::FillType fill) {
// TODO: extract portions of checkDraw that are relevant to path stenciling. // TODO: extract portions of checkDraw that are relevant to path stenciling.
SkASSERT(NULL != path); SkASSERT(NULL != path);
SkASSERT(this->caps()->pathStencilingSupport()); SkASSERT(this->caps()->pathRenderingSupport());
SkASSERT(!stroke.isHairlineStyle()); SkASSERT(!stroke.isHairlineStyle());
SkASSERT(!SkPath::IsInverseFillType(fill)); SkASSERT(!SkPath::IsInverseFillType(fill));
this->onStencilPath(path, stroke, fill); this->onStencilPath(path, stroke, fill);
} }
void GrDrawTarget::fillPath(const GrPath* path, const SkStrokeRec& stroke, SkPath::FillType fill) {
// TODO: extract portions of checkDraw that are relevant to path rendering.
SkASSERT(NULL != path);
SkASSERT(this->caps()->pathRenderingSupport());
SkASSERT(!stroke.isHairlineStyle());
const GrDrawState* drawState = &getDrawState();
SkRect devBounds;
if (SkPath::IsInverseFillType(fill)) {
devBounds = SkRect::MakeWH(SkIntToScalar(drawState->getRenderTarget()->width()),
SkIntToScalar(drawState->getRenderTarget()->height()));
} else {
devBounds = path->getBounds();
}
SkMatrix viewM = drawState->getViewMatrix();
viewM.mapRect(&devBounds);
GrDeviceCoordTexture dstCopy;
if (!this->setupDstReadIfNecessary(&dstCopy, &devBounds)) {
return;
}
this->onFillPath(path, stroke, fill, dstCopy.texture() ? &dstCopy : NULL);
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool GrDrawTarget::willUseHWAALines() const { bool GrDrawTarget::willUseHWAALines() const {
@ -949,7 +976,7 @@ void GrDrawTargetCaps::reset() {
fGeometryShaderSupport = false; fGeometryShaderSupport = false;
fDualSourceBlendingSupport = false; fDualSourceBlendingSupport = false;
fBufferLockSupport = false; fBufferLockSupport = false;
fPathStencilingSupport = false; fPathRenderingSupport = false;
fDstReadInShaderSupport = false; fDstReadInShaderSupport = false;
fReuseScratchTextures = true; fReuseScratchTextures = true;
@ -968,7 +995,7 @@ GrDrawTargetCaps& GrDrawTargetCaps::operator=(const GrDrawTargetCaps& other) {
fGeometryShaderSupport = other.fGeometryShaderSupport; fGeometryShaderSupport = other.fGeometryShaderSupport;
fDualSourceBlendingSupport = other.fDualSourceBlendingSupport; fDualSourceBlendingSupport = other.fDualSourceBlendingSupport;
fBufferLockSupport = other.fBufferLockSupport; fBufferLockSupport = other.fBufferLockSupport;
fPathStencilingSupport = other.fPathStencilingSupport; fPathRenderingSupport = other.fPathRenderingSupport;
fDstReadInShaderSupport = other.fDstReadInShaderSupport; fDstReadInShaderSupport = other.fDstReadInShaderSupport;
fReuseScratchTextures = other.fReuseScratchTextures; fReuseScratchTextures = other.fReuseScratchTextures;
@ -990,7 +1017,7 @@ void GrDrawTargetCaps::print() const {
GrPrintf("Geometry Shader Support : %s\n", gNY[fGeometryShaderSupport]); GrPrintf("Geometry Shader Support : %s\n", gNY[fGeometryShaderSupport]);
GrPrintf("Dual Source Blending Support: %s\n", gNY[fDualSourceBlendingSupport]); GrPrintf("Dual Source Blending Support: %s\n", gNY[fDualSourceBlendingSupport]);
GrPrintf("Buffer Lock Support : %s\n", gNY[fBufferLockSupport]); GrPrintf("Buffer Lock Support : %s\n", gNY[fBufferLockSupport]);
GrPrintf("Path Stenciling Support : %s\n", gNY[fPathStencilingSupport]); GrPrintf("Path Rendering Support : %s\n", gNY[fPathRenderingSupport]);
GrPrintf("Dst Read In Shader Support : %s\n", gNY[fDstReadInShaderSupport]); GrPrintf("Dst Read In Shader Support : %s\n", gNY[fDstReadInShaderSupport]);
GrPrintf("Reuse Scratch Textures : %s\n", gNY[fReuseScratchTextures]); GrPrintf("Reuse Scratch Textures : %s\n", gNY[fReuseScratchTextures]);
GrPrintf("Max Texture Size : %d\n", fMaxTextureSize); GrPrintf("Max Texture Size : %d\n", fMaxTextureSize);

View File

@ -328,6 +328,12 @@ public:
*/ */
void stencilPath(const GrPath*, const SkStrokeRec& stroke, SkPath::FillType fill); void stencilPath(const GrPath*, const SkStrokeRec& stroke, SkPath::FillType fill);
/**
* Fills a path. Fill must not be a hairline. It will respect the HW
* antialias flag on the draw state (if possible in the 3D API).
*/
void fillPath(const GrPath*, const SkStrokeRec& stroke, SkPath::FillType fill);
/** /**
* Helper function for drawing rects. It performs a geometry src push and pop * Helper function for drawing rects. It performs a geometry src push and pop
* and thus will finalize any reserved geometry. * and thus will finalize any reserved geometry.
@ -448,6 +454,14 @@ public:
*/ */
void executeDraw(const DrawInfo& info) { this->onDraw(info); } void executeDraw(const DrawInfo& info) { this->onDraw(info); }
/**
* For subclass internal use to invoke a call to onFillPath().
*/
void executeFillPath(const GrPath* path, const SkStrokeRec& stroke,
SkPath::FillType fill, const GrDeviceCoordTexture* dstCopy) {
this->onFillPath(path, stroke, fill, dstCopy);
}
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
/** /**
@ -761,15 +775,6 @@ protected:
} }
const SkRect* getDevBounds() const { return fDevBounds; } const SkRect* getDevBounds() const { return fDevBounds; }
bool getDevIBounds(SkIRect* bounds) const {
if (NULL != fDevBounds) {
fDevBounds->roundOut(bounds);
return true;
} else {
return false;
}
}
// NULL if no copy of the dst is needed for the draw. // NULL if no copy of the dst is needed for the draw.
const GrDeviceCoordTexture* getDstCopy() const { const GrDeviceCoordTexture* getDstCopy() const {
if (NULL != fDstCopy.texture()) { if (NULL != fDstCopy.texture()) {
@ -834,6 +839,8 @@ private:
const SkRect* localRect, const SkRect* localRect,
const SkMatrix* localMatrix); const SkMatrix* localMatrix);
virtual void onStencilPath(const GrPath*, const SkStrokeRec& stroke, SkPath::FillType fill) = 0; virtual void onStencilPath(const GrPath*, const SkStrokeRec& stroke, SkPath::FillType fill) = 0;
virtual void onFillPath(const GrPath*, const SkStrokeRec& stroke, SkPath::FillType fill,
const GrDeviceCoordTexture* dstCopy) = 0;
// helpers for reserving vertex and index space. // helpers for reserving vertex and index space.
bool reserveVertexSpace(size_t vertexSize, bool reserveVertexSpace(size_t vertexSize,
@ -852,7 +859,10 @@ private:
// Makes a copy of the dst if it is necessary for the draw. Returns false if a copy is required // Makes a copy of the dst if it is necessary for the draw. Returns false if a copy is required
// but couldn't be made. Otherwise, returns true. // but couldn't be made. Otherwise, returns true.
bool setupDstReadIfNecessary(DrawInfo* info); bool setupDstReadIfNecessary(DrawInfo* info) {
return this->setupDstReadIfNecessary(&info->fDstCopy, info->getDevBounds());
}
bool setupDstReadIfNecessary(GrDeviceCoordTexture* dstCopy, const SkRect* drawBounds);
// Check to see if this set of draw commands has been sent out // Check to see if this set of draw commands has been sent out
virtual bool isIssued(uint32_t drawID) { return true; } virtual bool isIssued(uint32_t drawID) { return true; }

View File

@ -34,7 +34,7 @@ public:
bool geometryShaderSupport() const { return fGeometryShaderSupport; } bool geometryShaderSupport() const { return fGeometryShaderSupport; }
bool dualSourceBlendingSupport() const { return fDualSourceBlendingSupport; } bool dualSourceBlendingSupport() const { return fDualSourceBlendingSupport; }
bool bufferLockSupport() const { return fBufferLockSupport; } bool bufferLockSupport() const { return fBufferLockSupport; }
bool pathStencilingSupport() const { return fPathStencilingSupport; } bool pathRenderingSupport() const { return fPathRenderingSupport; }
bool dstReadInShaderSupport() const { return fDstReadInShaderSupport; } bool dstReadInShaderSupport() const { return fDstReadInShaderSupport; }
bool reuseScratchTextures() const { return fReuseScratchTextures; } bool reuseScratchTextures() const { return fReuseScratchTextures; }
@ -53,7 +53,7 @@ protected:
bool fGeometryShaderSupport : 1; bool fGeometryShaderSupport : 1;
bool fDualSourceBlendingSupport : 1; bool fDualSourceBlendingSupport : 1;
bool fBufferLockSupport : 1; bool fBufferLockSupport : 1;
bool fPathStencilingSupport : 1; bool fPathRenderingSupport : 1;
bool fDstReadInShaderSupport : 1; bool fDstReadInShaderSupport : 1;
bool fReuseScratchTextures : 1; bool fReuseScratchTextures : 1;

View File

@ -198,7 +198,7 @@ GrIndexBuffer* GrGpu::createIndexBuffer(uint32_t size, bool dynamic) {
} }
GrPath* GrGpu::createPath(const SkPath& path) { GrPath* GrGpu::createPath(const SkPath& path) {
SkASSERT(this->caps()->pathStencilingSupport()); SkASSERT(this->caps()->pathRenderingSupport());
this->handleDirtyContext(); this->handleDirtyContext();
return this->onCreatePath(path); return this->onCreatePath(path);
} }
@ -247,6 +247,42 @@ void GrGpu::resolveRenderTarget(GrRenderTarget* target) {
this->onResolveRenderTarget(target); this->onResolveRenderTarget(target);
} }
static const GrStencilSettings& winding_path_stencil_settings() {
GR_STATIC_CONST_SAME_STENCIL_STRUCT(gSettings,
kIncClamp_StencilOp,
kIncClamp_StencilOp,
kAlwaysIfInClip_StencilFunc,
0xFFFF, 0xFFFF, 0xFFFF);
return *GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&gSettings);
}
static const GrStencilSettings& even_odd_path_stencil_settings() {
GR_STATIC_CONST_SAME_STENCIL_STRUCT(gSettings,
kInvert_StencilOp,
kInvert_StencilOp,
kAlwaysIfInClip_StencilFunc,
0xFFFF, 0xFFFF, 0xFFFF);
return *GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&gSettings);
}
void GrGpu::getPathStencilSettingsForFillType(SkPath::FillType fill, GrStencilSettings* outStencilSettings) {
switch (fill) {
default:
GrCrash("Unexpected path fill.");
/* fallthrough */;
case SkPath::kWinding_FillType:
case SkPath::kInverseWinding_FillType:
*outStencilSettings = winding_path_stencil_settings();
break;
case SkPath::kEvenOdd_FillType:
case SkPath::kInverseEvenOdd_FillType:
*outStencilSettings = even_odd_path_stencil_settings();
break;
}
fClipMaskManager.adjustPathStencilParams(outStencilSettings);
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -349,10 +385,6 @@ void GrGpu::onDraw(const DrawInfo& info) {
void GrGpu::onStencilPath(const GrPath* path, const SkStrokeRec&, SkPath::FillType fill) { void GrGpu::onStencilPath(const GrPath* path, const SkStrokeRec&, SkPath::FillType fill) {
this->handleDirtyContext(); this->handleDirtyContext();
// TODO: make this more efficient (don't copy and copy back)
GrAutoTRestore<GrStencilSettings> asr(this->drawState()->stencil());
this->setStencilPathSettings(*path, fill, this->drawState()->stencil());
GrDrawState::AutoRestoreEffects are; GrDrawState::AutoRestoreEffects are;
if (!this->setupClipAndFlushState(kStencilPath_DrawType, NULL, &are)) { if (!this->setupClipAndFlushState(kStencilPath_DrawType, NULL, &are)) {
return; return;
@ -361,6 +393,20 @@ void GrGpu::onStencilPath(const GrPath* path, const SkStrokeRec&, SkPath::FillTy
this->onGpuStencilPath(path, fill); this->onGpuStencilPath(path, fill);
} }
void GrGpu::onFillPath(const GrPath* path, const SkStrokeRec& stroke, SkPath::FillType fill,
const GrDeviceCoordTexture* dstCopy) {
this->handleDirtyContext();
drawState()->setDefaultVertexAttribs();
GrDrawState::AutoRestoreEffects are;
if (!this->setupClipAndFlushState(kFillPath_DrawType, dstCopy, &are)) {
return;
}
this->onGpuFillPath(path, fill);
}
void GrGpu::finalizeReservedVertices() { void GrGpu::finalizeReservedVertices() {
SkASSERT(NULL != fVertexPool); SkASSERT(NULL != fVertexPool);
fVertexPool->unlock(); fVertexPool->unlock();

View File

@ -335,12 +335,15 @@ public:
// clipping. // clipping.
}; };
void getPathStencilSettingsForFillType(SkPath::FillType fill, GrStencilSettings* outStencilSettings);
protected: protected:
enum DrawType { enum DrawType {
kDrawPoints_DrawType, kDrawPoints_DrawType,
kDrawLines_DrawType, kDrawLines_DrawType,
kDrawTriangles_DrawType, kDrawTriangles_DrawType,
kStencilPath_DrawType, kStencilPath_DrawType,
kFillPath_DrawType,
}; };
DrawType PrimTypeToDrawType(GrPrimitiveType type) { DrawType PrimTypeToDrawType(GrPrimitiveType type) {
@ -440,15 +443,10 @@ private:
// overridden by backend-specific derived class to perform the draw call. // overridden by backend-specific derived class to perform the draw call.
virtual void onGpuDraw(const DrawInfo&) = 0; virtual void onGpuDraw(const DrawInfo&) = 0;
// when GrDrawTarget::stencilPath is called the draw state's current stencil
// settings are ignored. Instead the GrGpu decides the stencil rules
// necessary to stencil the path. These are still subject to filtering by
// the clip mask manager.
virtual void setStencilPathSettings(const GrPath&,
SkPath::FillType,
GrStencilSettings* settings) = 0;
// overridden by backend-specific derived class to perform the path stenciling. // overridden by backend-specific derived class to perform the path stenciling.
virtual void onGpuStencilPath(const GrPath*, SkPath::FillType) = 0; virtual void onGpuStencilPath(const GrPath*, SkPath::FillType) = 0;
virtual void onGpuFillPath(const GrPath*, SkPath::FillType) = 0;
// overridden by backend-specific derived class to perform flush // overridden by backend-specific derived class to perform flush
virtual void onForceRenderTargetFlush() = 0; virtual void onForceRenderTargetFlush() = 0;
@ -494,6 +492,9 @@ private:
virtual void onStencilPath(const GrPath* path, const SkStrokeRec& stroke, virtual void onStencilPath(const GrPath* path, const SkStrokeRec& stroke,
SkPath::FillType) SK_OVERRIDE; SkPath::FillType) SK_OVERRIDE;
virtual void onFillPath(const GrPath* path, const SkStrokeRec& stroke, SkPath::FillType,
const GrDeviceCoordTexture* dstCopy) SK_OVERRIDE;
// readies the pools to provide vertex/index data. // readies the pools to provide vertex/index data.
void prepareVertexPool(); void prepareVertexPool();
void prepareIndexPool(); void prepareIndexPool();

View File

@ -385,6 +385,7 @@ void GrInOrderDrawBuffer::onDraw(const DrawInfo& info) {
} }
GrInOrderDrawBuffer::StencilPath::StencilPath() : fStroke(SkStrokeRec::kFill_InitStyle) {} GrInOrderDrawBuffer::StencilPath::StencilPath() : fStroke(SkStrokeRec::kFill_InitStyle) {}
GrInOrderDrawBuffer::FillPath::FillPath() : fStroke(SkStrokeRec::kFill_InitStyle) {}
void GrInOrderDrawBuffer::onStencilPath(const GrPath* path, const SkStrokeRec& stroke, void GrInOrderDrawBuffer::onStencilPath(const GrPath* path, const SkStrokeRec& stroke,
SkPath::FillType fill) { SkPath::FillType fill) {
@ -402,6 +403,25 @@ void GrInOrderDrawBuffer::onStencilPath(const GrPath* path, const SkStrokeRec& s
sp->fStroke = stroke; sp->fStroke = stroke;
} }
void GrInOrderDrawBuffer::onFillPath(const GrPath* path, const SkStrokeRec& stroke,
SkPath::FillType fill, const GrDeviceCoordTexture* dstCopy) {
if (this->needsNewClip()) {
this->recordClip();
}
// TODO: Only compare the subset of GrDrawState relevant to path covering?
if (this->needsNewState()) {
this->recordState();
}
FillPath* cp = this->recordFillPath();
cp->fPath.reset(path);
path->ref();
cp->fFill = fill;
cp->fStroke = stroke;
if (NULL != dstCopy) {
cp->fDstCopy = *dstCopy;
}
}
void GrInOrderDrawBuffer::clear(const SkIRect* rect, GrColor color, GrRenderTarget* renderTarget) { void GrInOrderDrawBuffer::clear(const SkIRect* rect, GrColor color, GrRenderTarget* renderTarget) {
SkIRect r; SkIRect r;
if (NULL == renderTarget) { if (NULL == renderTarget) {
@ -436,6 +456,7 @@ void GrInOrderDrawBuffer::reset() {
fCmds.reset(); fCmds.reset();
fDraws.reset(); fDraws.reset();
fStencilPaths.reset(); fStencilPaths.reset();
fFillPaths.reset();
fStates.reset(); fStates.reset();
fClears.reset(); fClears.reset();
fVertexPool.reset(); fVertexPool.reset();
@ -480,6 +501,7 @@ void GrInOrderDrawBuffer::flush() {
int currClear = 0; int currClear = 0;
int currDraw = 0; int currDraw = 0;
int currStencilPath = 0; int currStencilPath = 0;
int currFillPath = 0;
int currCopySurface = 0; int currCopySurface = 0;
for (int c = 0; c < numCmds; ++c) { for (int c = 0; c < numCmds; ++c) {
@ -501,6 +523,13 @@ void GrInOrderDrawBuffer::flush() {
++currStencilPath; ++currStencilPath;
break; break;
} }
case kFillPath_Cmd: {
const FillPath& cp = fFillPaths[currFillPath];
fDstGpu->executeFillPath(cp.fPath.get(), cp.fStroke, cp.fFill,
NULL != cp.fDstCopy.texture() ? &cp.fDstCopy : NULL);
++currFillPath;
break;
}
case kSetState_Cmd: case kSetState_Cmd:
fStates[currState].restoreTo(&playbackState); fStates[currState].restoreTo(&playbackState);
++currState; ++currState;
@ -810,6 +839,11 @@ GrInOrderDrawBuffer::StencilPath* GrInOrderDrawBuffer::recordStencilPath() {
return &fStencilPaths.push_back(); return &fStencilPaths.push_back();
} }
GrInOrderDrawBuffer::FillPath* GrInOrderDrawBuffer::recordFillPath() {
fCmds.push_back(kFillPath_Cmd);
return &fFillPaths.push_back();
}
GrInOrderDrawBuffer::Clear* GrInOrderDrawBuffer::recordClear() { GrInOrderDrawBuffer::Clear* GrInOrderDrawBuffer::recordClear() {
fCmds.push_back(kClear_Cmd); fCmds.push_back(kClear_Cmd);
return &fClears.push_back(); return &fClears.push_back();

View File

@ -87,6 +87,7 @@ private:
kSetClip_Cmd = 4, kSetClip_Cmd = 4,
kClear_Cmd = 5, kClear_Cmd = 5,
kCopySurface_Cmd = 6, kCopySurface_Cmd = 6,
kFillPath_Cmd = 7,
}; };
class DrawRecord : public DrawInfo { class DrawRecord : public DrawInfo {
@ -104,6 +105,15 @@ private:
SkPath::FillType fFill; SkPath::FillType fFill;
}; };
struct FillPath : public ::SkNoncopyable {
FillPath();
SkAutoTUnref<const GrPath> fPath;
SkStrokeRec fStroke;
SkPath::FillType fFill;
GrDeviceCoordTexture fDstCopy;
};
struct Clear : public ::SkNoncopyable { struct Clear : public ::SkNoncopyable {
Clear() : fRenderTarget(NULL) {} Clear() : fRenderTarget(NULL) {}
~Clear() { SkSafeUnref(fRenderTarget); } ~Clear() { SkSafeUnref(fRenderTarget); }
@ -127,6 +137,8 @@ private:
const SkRect* localRect, const SkRect* localRect,
const SkMatrix* localMatrix) SK_OVERRIDE; const SkMatrix* localMatrix) SK_OVERRIDE;
virtual void onStencilPath(const GrPath*, const SkStrokeRec& stroke, SkPath::FillType) SK_OVERRIDE; virtual void onStencilPath(const GrPath*, const SkStrokeRec& stroke, SkPath::FillType) SK_OVERRIDE;
virtual void onFillPath(const GrPath*, const SkStrokeRec& stroke, SkPath::FillType,
const GrDeviceCoordTexture* dstCopy) SK_OVERRIDE;
virtual bool onReserveVertexSpace(size_t vertexSize, virtual bool onReserveVertexSpace(size_t vertexSize,
int vertexCount, int vertexCount,
void** vertices) SK_OVERRIDE; void** vertices) SK_OVERRIDE;
@ -169,6 +181,7 @@ private:
void recordClip(); void recordClip();
DrawRecord* recordDraw(const DrawInfo&); DrawRecord* recordDraw(const DrawInfo&);
StencilPath* recordStencilPath(); StencilPath* recordStencilPath();
FillPath* recordFillPath();
Clear* recordClear(); Clear* recordClear();
CopySurface* recordCopySurface(); CopySurface* recordCopySurface();
@ -177,6 +190,7 @@ private:
kCmdPreallocCnt = 32, kCmdPreallocCnt = 32,
kDrawPreallocCnt = 8, kDrawPreallocCnt = 8,
kStencilPathPreallocCnt = 8, kStencilPathPreallocCnt = 8,
kFillPathPreallocCnt = 8,
kStatePreallocCnt = 8, kStatePreallocCnt = 8,
kClipPreallocCnt = 8, kClipPreallocCnt = 8,
kClearPreallocCnt = 4, kClearPreallocCnt = 4,
@ -187,6 +201,7 @@ private:
SkSTArray<kCmdPreallocCnt, uint8_t, true> fCmds; SkSTArray<kCmdPreallocCnt, uint8_t, true> fCmds;
GrSTAllocator<kDrawPreallocCnt, DrawRecord> fDraws; GrSTAllocator<kDrawPreallocCnt, DrawRecord> fDraws;
GrSTAllocator<kStatePreallocCnt, StencilPath> fStencilPaths; GrSTAllocator<kStatePreallocCnt, StencilPath> fStencilPaths;
GrSTAllocator<kStatePreallocCnt, FillPath> fFillPaths;
GrSTAllocator<kStatePreallocCnt, GrDrawState::DeferredState> fStates; GrSTAllocator<kStatePreallocCnt, GrDrawState::DeferredState> fStates;
GrSTAllocator<kClearPreallocCnt, Clear> fClears; GrSTAllocator<kClearPreallocCnt, Clear> fClears;
GrSTAllocator<kCopySurfacePreallocCnt, CopySurface> fCopySurfaces; GrSTAllocator<kCopySurfacePreallocCnt, CopySurface> fCopySurfaces;

View File

@ -17,7 +17,7 @@
GrPathRenderer* GrStencilAndCoverPathRenderer::Create(GrContext* context) { GrPathRenderer* GrStencilAndCoverPathRenderer::Create(GrContext* context) {
SkASSERT(NULL != context); SkASSERT(NULL != context);
SkASSERT(NULL != context->getGpu()); SkASSERT(NULL != context->getGpu());
if (context->getGpu()->caps()->pathStencilingSupport()) { if (context->getGpu()->caps()->pathRenderingSupport()) {
return SkNEW_ARGS(GrStencilAndCoverPathRenderer, (context->getGpu())); return SkNEW_ARGS(GrStencilAndCoverPathRenderer, (context->getGpu()));
} else { } else {
return NULL; return NULL;
@ -25,7 +25,7 @@ GrPathRenderer* GrStencilAndCoverPathRenderer::Create(GrContext* context) {
} }
GrStencilAndCoverPathRenderer::GrStencilAndCoverPathRenderer(GrGpu* gpu) { GrStencilAndCoverPathRenderer::GrStencilAndCoverPathRenderer(GrGpu* gpu) {
SkASSERT(gpu->caps()->pathStencilingSupport()); SkASSERT(gpu->caps()->pathRenderingSupport());
fGpu = gpu; fGpu = gpu;
gpu->ref(); gpu->ref();
} }
@ -40,6 +40,7 @@ bool GrStencilAndCoverPathRenderer::canDrawPath(const SkPath& path,
bool antiAlias) const { bool antiAlias) const {
return stroke.isFillStyle() && return stroke.isFillStyle() &&
!antiAlias && // doesn't do per-path AA, relies on the target having MSAA !antiAlias && // doesn't do per-path AA, relies on the target having MSAA
NULL != target->getDrawState().getRenderTarget()->getStencilBuffer() &&
target->getDrawState().getStencil().isDisabled(); target->getDrawState().getStencil().isDisabled();
} }
@ -70,27 +71,7 @@ bool GrStencilAndCoverPathRenderer::onDrawPath(const SkPath& path,
SkAutoTUnref<GrPath> p(fGpu->createPath(path)); SkAutoTUnref<GrPath> p(fGpu->createPath(path));
SkPath::FillType nonInvertedFill = SkPath::ConvertToNonInverseFillType(path.getFillType()); if (path.isInverseFillType()) {
target->stencilPath(p, stroke, nonInvertedFill);
// TODO: Use built in cover operation rather than a rect draw. This will require making our
// fragment shaders be able to eat varyings generated by a matrix.
// fill the path, zero out the stencil
SkRect bounds = p->getBounds();
SkScalar bloat = drawState->getViewMatrix().getMaxStretch() * SK_ScalarHalf;
GrDrawState::AutoViewMatrixRestore avmr;
if (nonInvertedFill == path.getFillType()) {
GR_STATIC_CONST_SAME_STENCIL(kStencilPass,
kZero_StencilOp,
kZero_StencilOp,
kNotEqual_StencilFunc,
0xffff,
0x0000,
0xffff);
*drawState->stencil() = kStencilPass;
} else {
GR_STATIC_CONST_SAME_STENCIL(kInvertedStencilPass, GR_STATIC_CONST_SAME_STENCIL(kInvertedStencilPass,
kZero_StencilOp, kZero_StencilOp,
kZero_StencilOp, kZero_StencilOp,
@ -101,23 +82,22 @@ bool GrStencilAndCoverPathRenderer::onDrawPath(const SkPath& path,
0xffff, 0xffff,
0x0000, 0x0000,
0xffff); 0xffff);
SkMatrix vmi;
bounds.setLTRB(0, 0,
SkIntToScalar(drawState->getRenderTarget()->width()),
SkIntToScalar(drawState->getRenderTarget()->height()));
// mapRect through persp matrix may not be correct
if (!drawState->getViewMatrix().hasPerspective() && drawState->getViewInverse(&vmi)) {
vmi.mapRect(&bounds);
// theoretically could set bloat = 0, instead leave it because of matrix inversion
// precision.
} else {
avmr.setIdentity(drawState);
bloat = 0;
}
*drawState->stencil() = kInvertedStencilPass; *drawState->stencil() = kInvertedStencilPass;
} else {
GR_STATIC_CONST_SAME_STENCIL(kStencilPass,
kZero_StencilOp,
kZero_StencilOp,
kNotEqual_StencilFunc,
0xffff,
0x0000,
0xffff);
*drawState->stencil() = kStencilPass;
} }
bounds.outset(bloat, bloat);
target->drawSimpleRect(bounds, NULL); target->fillPath(p, stroke, path.getFillType());
target->drawState()->stencil()->setDisabled(); target->drawState()->stencil()->setDisabled();
return true; return true;
} }

View File

@ -302,8 +302,8 @@ void GrGLCaps::init(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli) {
// attachment, hence this min: // attachment, hence this min:
fMaxRenderTargetSize = GrMin(fMaxTextureSize, fMaxRenderTargetSize); fMaxRenderTargetSize = GrMin(fMaxTextureSize, fMaxRenderTargetSize);
fPathStencilingSupport = GR_GL_USE_NV_PATH_RENDERING && fPathRenderingSupport = GR_GL_USE_NV_PATH_RENDERING &&
ctxInfo.hasExtension("GL_NV_path_rendering"); ctxInfo.hasExtension("GL_NV_path_rendering");
fDstReadInShaderSupport = kNone_FBFetchType != fFBFetchType; fDstReadInShaderSupport = kNone_FBFetchType != fFBFetchType;

View File

@ -52,7 +52,7 @@ GrGLProgram::GrGLProgram(GrGpuGL* gpu,
if (fDesc.getHeader().fHasVertexCode || if (fDesc.getHeader().fHasVertexCode ||
!fGpu->glCaps().fixedFunctionSupport() || !fGpu->glCaps().fixedFunctionSupport() ||
!fGpu->glCaps().pathStencilingSupport()) { !fGpu->glCaps().pathRenderingSupport()) {
GrGLFullShaderBuilder fullBuilder(fGpu, fUniformManager, fDesc); GrGLFullShaderBuilder fullBuilder(fGpu, fUniformManager, fDesc);
if (this->genProgram(&fullBuilder, colorStages, coverageStages)) { if (this->genProgram(&fullBuilder, colorStages, coverageStages)) {

View File

@ -122,11 +122,13 @@ void GrGLProgramDesc::Build(const GrDrawState& drawState,
header->fExperimentalGS = false; header->fExperimentalGS = false;
#endif #endif
#endif #endif
bool defaultToUniformInputs = GR_GL_NO_CONSTANT_ATTRIBUTES || gpu->caps()->pathRenderingSupport();
if (colorIsTransBlack) { if (colorIsTransBlack) {
header->fColorInput = kTransBlack_ColorInput; header->fColorInput = kTransBlack_ColorInput;
} else if (colorIsSolidWhite) { } else if (colorIsSolidWhite) {
header->fColorInput = kSolidWhite_ColorInput; header->fColorInput = kSolidWhite_ColorInput;
} else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresColorAttrib) { } else if (defaultToUniformInputs && !requiresColorAttrib) {
header->fColorInput = kUniform_ColorInput; header->fColorInput = kUniform_ColorInput;
} else { } else {
header->fColorInput = kAttribute_ColorInput; header->fColorInput = kAttribute_ColorInput;
@ -139,7 +141,7 @@ void GrGLProgramDesc::Build(const GrDrawState& drawState,
header->fCoverageInput = kTransBlack_ColorInput; header->fCoverageInput = kTransBlack_ColorInput;
} else if (covIsSolidWhite) { } else if (covIsSolidWhite) {
header->fCoverageInput = kSolidWhite_ColorInput; header->fCoverageInput = kSolidWhite_ColorInput;
} else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresCoverageAttrib) { } else if (defaultToUniformInputs && !requiresCoverageAttrib) {
header->fCoverageInput = kUniform_ColorInput; header->fCoverageInput = kUniform_ColorInput;
} else { } else {
header->fCoverageInput = kAttribute_ColorInput; header->fCoverageInput = kAttribute_ColorInput;

View File

@ -930,7 +930,7 @@ GrGLFragmentOnlyShaderBuilder::GrGLFragmentOnlyShaderBuilder(GrGpuGL* gpu,
SkASSERT(!desc.getHeader().fHasVertexCode); SkASSERT(!desc.getHeader().fHasVertexCode);
SkASSERT(gpu->glCaps().fixedFunctionSupport()); SkASSERT(gpu->glCaps().fixedFunctionSupport());
SkASSERT(gpu->glCaps().pathStencilingSupport()); SkASSERT(gpu->glCaps().pathRenderingSupport());
SkASSERT(GrGLProgramDesc::kAttribute_ColorInput != desc.getHeader().fColorInput); SkASSERT(GrGLProgramDesc::kAttribute_ColorInput != desc.getHeader().fColorInput);
SkASSERT(GrGLProgramDesc::kAttribute_ColorInput != desc.getHeader().fCoverageInput); SkASSERT(GrGLProgramDesc::kAttribute_ColorInput != desc.getHeader().fCoverageInput);
} }

View File

@ -365,26 +365,30 @@ void GrGpuGL::onResetContext(uint32_t resetBits) {
fHWBoundRenderTarget = NULL; fHWBoundRenderTarget = NULL;
} }
if (resetBits & kFixedFunction_GrGLBackendState && this->glCaps().fixedFunctionSupport()) { if (resetBits & (kFixedFunction_GrGLBackendState | kPathRendering_GrGLBackendState)) {
if (this->glCaps().fixedFunctionSupport()) {
fHWProjectionMatrixState.invalidate();
// we don't use the model view matrix.
GL_CALL(MatrixMode(GR_GL_MODELVIEW));
GL_CALL(LoadIdentity());
fHWProjectionMatrixState.invalidate(); for (int i = 0; i < this->glCaps().maxFixedFunctionTextureCoords(); ++i) {
// we don't use the model view matrix. GL_CALL(ActiveTexture(GR_GL_TEXTURE0 + i));
GL_CALL(MatrixMode(GR_GL_MODELVIEW)); GL_CALL(Disable(GR_GL_TEXTURE_GEN_S));
GL_CALL(LoadIdentity()); GL_CALL(Disable(GR_GL_TEXTURE_GEN_T));
GL_CALL(Disable(GR_GL_TEXTURE_GEN_Q));
for (int i = 0; i < this->glCaps().maxFixedFunctionTextureCoords(); ++i) { GL_CALL(Disable(GR_GL_TEXTURE_GEN_R));
GL_CALL(ActiveTexture(GR_GL_TEXTURE0 + i)); if (this->caps()->pathRenderingSupport()) {
GL_CALL(Disable(GR_GL_TEXTURE_GEN_S)); GL_CALL(PathTexGen(GR_GL_TEXTURE0 + i, GR_GL_NONE, 0, NULL));
GL_CALL(Disable(GR_GL_TEXTURE_GEN_T)); }
GL_CALL(Disable(GR_GL_TEXTURE_GEN_Q)); fHWTexGenSettings[i].fMode = GR_GL_NONE;
GL_CALL(Disable(GR_GL_TEXTURE_GEN_R)); fHWTexGenSettings[i].fNumComponents = 0;
if (this->caps()->pathStencilingSupport()) {
GL_CALL(PathTexGen(GR_GL_TEXTURE0 + i, GR_GL_NONE, 0, NULL));
} }
fHWTexGenSettings[i].fMode = GR_GL_NONE; fHWActiveTexGenSets = 0;
fHWTexGenSettings[i].fNumComponents = 0; }
if (this->caps()->pathRenderingSupport()) {
fHWPathStencilSettings.invalidate();
} }
fHWActiveTexGenSets = 0;
} }
// we assume these values // we assume these values
@ -1273,7 +1277,7 @@ GrIndexBuffer* GrGpuGL::onCreateIndexBuffer(uint32_t size, bool dynamic) {
} }
GrPath* GrGpuGL::onCreatePath(const SkPath& inPath) { GrPath* GrGpuGL::onCreatePath(const SkPath& inPath) {
SkASSERT(this->caps()->pathStencilingSupport()); SkASSERT(this->caps()->pathRenderingSupport());
return SkNEW_ARGS(GrGLPath, (this, inPath)); return SkNEW_ARGS(GrGLPath, (this, inPath));
} }
@ -1666,81 +1670,77 @@ void GrGpuGL::onGpuDraw(const DrawInfo& info) {
#endif #endif
} }
namespace { static GrGLenum gr_stencil_op_to_gl_path_rendering_fill_mode(GrStencilOp op) {
switch (op) {
static const uint16_t kOnes16 = static_cast<uint16_t>(~0);
const GrStencilSettings& winding_nv_path_stencil_settings() {
GR_STATIC_CONST_SAME_STENCIL_STRUCT(gSettings,
kIncClamp_StencilOp,
kIncClamp_StencilOp,
kAlwaysIfInClip_StencilFunc,
kOnes16, kOnes16, kOnes16);
return *GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&gSettings);
}
const GrStencilSettings& even_odd_nv_path_stencil_settings() {
GR_STATIC_CONST_SAME_STENCIL_STRUCT(gSettings,
kInvert_StencilOp,
kInvert_StencilOp,
kAlwaysIfInClip_StencilFunc,
kOnes16, kOnes16, kOnes16);
return *GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&gSettings);
}
}
void GrGpuGL::setStencilPathSettings(const GrPath&,
SkPath::FillType fill,
GrStencilSettings* settings) {
switch (fill) {
case SkPath::kEvenOdd_FillType:
*settings = even_odd_nv_path_stencil_settings();
return;
case SkPath::kWinding_FillType:
*settings = winding_nv_path_stencil_settings();
return;
default: default:
GrCrash("Unexpected path fill."); GrCrash("Unexpected path fill.");
/* fallthrough */;
case kIncClamp_StencilOp:
return GR_GL_COUNT_UP;
case kInvert_StencilOp:
return GR_GL_INVERT;
} }
} }
void GrGpuGL::onGpuStencilPath(const GrPath* path, SkPath::FillType fill) { void GrGpuGL::onGpuStencilPath(const GrPath* path, SkPath::FillType fill) {
SkASSERT(this->caps()->pathStencilingSupport()); SkASSERT(this->caps()->pathRenderingSupport());
GrGLuint id = static_cast<const GrGLPath*>(path)->pathID(); GrGLuint id = static_cast<const GrGLPath*>(path)->pathID();
GrDrawState* drawState = this->drawState(); SkASSERT(NULL != this->drawState()->getRenderTarget());
SkASSERT(NULL != drawState->getRenderTarget()); SkASSERT(NULL != this->drawState()->getRenderTarget()->getStencilBuffer());
if (NULL == drawState->getRenderTarget()->getStencilBuffer()) {
return; flushPathStencilSettings(fill);
}
// Decide how to manipulate the stencil buffer based on the fill rule. // Decide how to manipulate the stencil buffer based on the fill rule.
// Also, assert that the stencil settings we set in setStencilPathSettings SkASSERT(!fHWPathStencilSettings.isTwoSided());
// are present.
SkASSERT(!fStencilSettings.isTwoSided()); GrGLenum fillMode =
GrGLenum fillMode; gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
switch (fill) { GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
case SkPath::kWinding_FillType:
fillMode = GR_GL_COUNT_UP;
SkASSERT(kIncClamp_StencilOp ==
fStencilSettings.passOp(GrStencilSettings::kFront_Face));
SkASSERT(kIncClamp_StencilOp ==
fStencilSettings.failOp(GrStencilSettings::kFront_Face));
break;
case SkPath::kEvenOdd_FillType:
fillMode = GR_GL_INVERT;
SkASSERT(kInvert_StencilOp ==
fStencilSettings.passOp(GrStencilSettings::kFront_Face));
SkASSERT(kInvert_StencilOp ==
fStencilSettings.failOp(GrStencilSettings::kFront_Face));
break;
default:
// Only the above two fill rules are allowed.
GrCrash("Unexpected path fill.");
return; // suppress unused var warning.
}
GrGLint writeMask = fStencilSettings.writeMask(GrStencilSettings::kFront_Face);
GL_CALL(StencilFillPath(id, fillMode, writeMask)); GL_CALL(StencilFillPath(id, fillMode, writeMask));
} }
void GrGpuGL::onGpuFillPath(const GrPath* path, SkPath::FillType fill) {
SkASSERT(this->caps()->pathRenderingSupport());
GrGLuint id = static_cast<const GrGLPath*>(path)->pathID();
SkASSERT(NULL != this->drawState()->getRenderTarget());
SkASSERT(NULL != this->drawState()->getRenderTarget()->getStencilBuffer());
SkASSERT(!fCurrentProgram->hasVertexShader());
flushPathStencilSettings(fill);
SkPath::FillType nonInvertedFill = SkPath::ConvertToNonInverseFillType(fill);
SkASSERT(!fHWPathStencilSettings.isTwoSided());
GrGLenum fillMode =
gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
GL_CALL(StencilFillPath(id, fillMode, writeMask));
if (nonInvertedFill == fill) {
GL_CALL(CoverFillPath(id, GR_GL_BOUNDING_BOX));
} else {
GrDrawState* drawState = this->drawState();
GrDrawState::AutoViewMatrixRestore avmr;
SkRect bounds = SkRect::MakeLTRB(0, 0,
SkIntToScalar(drawState->getRenderTarget()->width()),
SkIntToScalar(drawState->getRenderTarget()->height()));
SkMatrix vmi;
// mapRect through persp matrix may not be correct
if (!drawState->getViewMatrix().hasPerspective() && drawState->getViewInverse(&vmi)) {
vmi.mapRect(&bounds);
// theoretically could set bloat = 0, instead leave it because of matrix inversion
// precision.
SkScalar bloat = drawState->getViewMatrix().getMaxStretch() * SK_ScalarHalf;
bounds.outset(bloat, bloat);
} else {
avmr.setIdentity(drawState);
}
this->drawSimpleRect(bounds, NULL);
}
}
void GrGpuGL::onResolveRenderTarget(GrRenderTarget* target) { void GrGpuGL::onResolveRenderTarget(GrRenderTarget* target) {
GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(target); GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(target);
if (rt->needsResolve()) { if (rt->needsResolve()) {
@ -1862,16 +1862,7 @@ void set_gl_stencil(const GrGLInterface* gl,
} }
void GrGpuGL::flushStencil(DrawType type) { void GrGpuGL::flushStencil(DrawType type) {
if (kStencilPath_DrawType == type) { if (kStencilPath_DrawType != type && fHWStencilSettings != fStencilSettings) {
SkASSERT(!fStencilSettings.isTwoSided());
// Just the func, ref, and mask is set here. The op and write mask are params to the call
// that draws the path to the SB (glStencilFillPath)
GrGLenum func =
gr_to_gl_stencil_func(fStencilSettings.func(GrStencilSettings::kFront_Face));
GL_CALL(PathStencilFunc(func,
fStencilSettings.funcRef(GrStencilSettings::kFront_Face),
fStencilSettings.funcMask(GrStencilSettings::kFront_Face)));
} else if (fHWStencilSettings != fStencilSettings) {
if (fStencilSettings.isDisabled()) { if (fStencilSettings.isDisabled()) {
if (kNo_TriState != fHWStencilTestEnabled) { if (kNo_TriState != fHWStencilTestEnabled) {
GL_CALL(Disable(GR_GL_STENCIL_TEST)); GL_CALL(Disable(GR_GL_STENCIL_TEST));
@ -1961,6 +1952,22 @@ void GrGpuGL::flushAAState(DrawType type) {
} }
} }
void GrGpuGL::flushPathStencilSettings(SkPath::FillType fill) {
GrStencilSettings pathStencilSettings;
this->getPathStencilSettingsForFillType(fill, &pathStencilSettings);
if (fHWPathStencilSettings != pathStencilSettings) {
// Just the func, ref, and mask is set here. The op and write mask are params to the call
// that draws the path to the SB (glStencilFillPath)
GrGLenum func =
gr_to_gl_stencil_func(pathStencilSettings.func(GrStencilSettings::kFront_Face));
GL_CALL(PathStencilFunc(func,
pathStencilSettings.funcRef(GrStencilSettings::kFront_Face),
pathStencilSettings.funcMask(GrStencilSettings::kFront_Face)));
fHWPathStencilSettings = pathStencilSettings;
}
}
void GrGpuGL::flushBlend(bool isLines, void GrGpuGL::flushBlend(bool isLines,
GrBlendCoeff srcCoeff, GrBlendCoeff srcCoeff,
GrBlendCoeff dstCoeff) { GrBlendCoeff dstCoeff) {
@ -2148,7 +2155,7 @@ void GrGpuGL::enableTexGen(int unitIdx,
const GrGLfloat* coefficients) { const GrGLfloat* coefficients) {
SkASSERT(this->glCaps().fixedFunctionSupport()); SkASSERT(this->glCaps().fixedFunctionSupport());
SkASSERT(this->caps()->pathStencilingSupport()); SkASSERT(this->caps()->pathRenderingSupport());
SkASSERT(components >= kS_TexGenComponents && components <= kSTR_TexGenComponents); SkASSERT(components >= kS_TexGenComponents && components <= kSTR_TexGenComponents);
if (GR_GL_OBJECT_LINEAR == fHWTexGenSettings[unitIdx].fMode && if (GR_GL_OBJECT_LINEAR == fHWTexGenSettings[unitIdx].fMode &&

View File

@ -151,11 +151,8 @@ private:
virtual void onGpuDraw(const DrawInfo&) SK_OVERRIDE; virtual void onGpuDraw(const DrawInfo&) SK_OVERRIDE;
virtual void setStencilPathSettings(const GrPath&,
SkPath::FillType,
GrStencilSettings* settings)
SK_OVERRIDE;
virtual void onGpuStencilPath(const GrPath*, SkPath::FillType) SK_OVERRIDE; virtual void onGpuStencilPath(const GrPath*, SkPath::FillType) SK_OVERRIDE;
virtual void onGpuFillPath(const GrPath*, SkPath::FillType) SK_OVERRIDE;
virtual void clearStencil() SK_OVERRIDE; virtual void clearStencil() SK_OVERRIDE;
virtual void clearStencilClip(const SkIRect& rect, virtual void clearStencilClip(const SkIRect& rect,
@ -245,6 +242,7 @@ private:
void flushRenderTarget(const SkIRect* bound); void flushRenderTarget(const SkIRect* bound);
void flushStencil(DrawType); void flushStencil(DrawType);
void flushAAState(DrawType); void flushAAState(DrawType);
void flushPathStencilSettings(SkPath::FillType fill);
bool configToGLFormats(GrPixelConfig config, bool configToGLFormats(GrPixelConfig config,
bool getSizedInternal, bool getSizedInternal,
@ -434,6 +432,7 @@ private:
GrStencilSettings fHWStencilSettings; GrStencilSettings fHWStencilSettings;
TriState fHWStencilTestEnabled; TriState fHWStencilTestEnabled;
GrStencilSettings fHWPathStencilSettings;
GrDrawState::DrawFace fHWDrawFace; GrDrawState::DrawFace fHWDrawFace;
TriState fHWWriteToColor; TriState fHWWriteToColor;

View File

@ -252,6 +252,9 @@ bool GrGpuGL::flushGraphicsState(DrawType type, const GrDeviceCoordTexture* dstC
SkDEBUGFAIL("Failed to create program!"); SkDEBUGFAIL("Failed to create program!");
return false; return false;
} }
SkASSERT(kFillPath_DrawType != type || !fCurrentProgram->hasVertexShader());
fCurrentProgram.get()->ref(); fCurrentProgram.get()->ref();
GrGLuint programID = fCurrentProgram->programID(); GrGLuint programID = fCurrentProgram->programID();