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:
parent
6ec1abf21e
commit
c4dc0ad8e2
@ -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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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(), ©Rect);
|
const GrClipData* clip = this->getClip();
|
||||||
SkIRect drawIBounds;
|
clip->getConservativeBounds(rt, ©Rect);
|
||||||
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);
|
||||||
|
@ -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; }
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
@ -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();
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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)) {
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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 &&
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
|
Loading…
Reference in New Issue
Block a user