added GrMSAAPathRenderer
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1834133003 Review URL: https://codereview.chromium.org/1834133003
This commit is contained in:
parent
3bc969264d
commit
47a2dc8e22
@ -229,6 +229,8 @@
|
||||
'<(skia_src_path)/gpu/batches/GrDrawPathBatch.h',
|
||||
'<(skia_src_path)/gpu/batches/GrDrawVerticesBatch.cpp',
|
||||
'<(skia_src_path)/gpu/batches/GrDrawVerticesBatch.h',
|
||||
'<(skia_src_path)/gpu/batches/GrMSAAPathRenderer.cpp',
|
||||
'<(skia_src_path)/gpu/batches/GrMSAAPathRenderer.h',
|
||||
'<(skia_src_path)/gpu/batches/GrNonAAFillRectBatch.h',
|
||||
'<(skia_src_path)/gpu/batches/GrNonAAFillRectBatch.cpp',
|
||||
'<(skia_src_path)/gpu/batches/GrNonAAStrokeRectBatch.cpp',
|
||||
|
@ -20,9 +20,10 @@
|
||||
#include "batches/GrAALinearizingConvexPathRenderer.h"
|
||||
#include "batches/GrDashLinePathRenderer.h"
|
||||
#include "batches/GrDefaultPathRenderer.h"
|
||||
#include "batches/GrMSAAPathRenderer.h"
|
||||
#include "batches/GrPLSPathRenderer.h"
|
||||
#include "batches/GrStencilAndCoverPathRenderer.h"
|
||||
#include "batches/GrTessellatingPathRenderer.h"
|
||||
#include "batches/GrPLSPathRenderer.h"
|
||||
|
||||
GrPathRendererChain::GrPathRendererChain(GrContext* context) {
|
||||
const GrCaps& caps = *context->caps();
|
||||
@ -32,6 +33,9 @@ GrPathRendererChain::GrPathRendererChain(GrContext* context) {
|
||||
caps)) {
|
||||
this->addPathRenderer(pr)->unref();
|
||||
}
|
||||
if (caps.sampleShadingSupport()) {
|
||||
this->addPathRenderer(new GrMSAAPathRenderer)->unref();
|
||||
}
|
||||
this->addPathRenderer(new GrTessellatingPathRenderer)->unref();
|
||||
this->addPathRenderer(new GrAAHairLinePathRenderer)->unref();
|
||||
this->addPathRenderer(new GrAAConvexPathRenderer)->unref();
|
||||
|
@ -29,130 +29,6 @@ GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport,
|
||||
, fStencilWrapOps(stencilWrapOpsSupport) {
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Stencil rules for paths
|
||||
|
||||
////// Even/Odd
|
||||
|
||||
GR_STATIC_CONST_SAME_STENCIL(gEOStencilPass,
|
||||
kInvert_StencilOp,
|
||||
kKeep_StencilOp,
|
||||
kAlwaysIfInClip_StencilFunc,
|
||||
0xffff,
|
||||
0xffff,
|
||||
0xffff);
|
||||
|
||||
// ok not to check clip b/c stencil pass only wrote inside clip
|
||||
GR_STATIC_CONST_SAME_STENCIL(gEOColorPass,
|
||||
kZero_StencilOp,
|
||||
kZero_StencilOp,
|
||||
kNotEqual_StencilFunc,
|
||||
0xffff,
|
||||
0x0000,
|
||||
0xffff);
|
||||
|
||||
// have to check clip b/c outside clip will always be zero.
|
||||
GR_STATIC_CONST_SAME_STENCIL(gInvEOColorPass,
|
||||
kZero_StencilOp,
|
||||
kZero_StencilOp,
|
||||
kEqualIfInClip_StencilFunc,
|
||||
0xffff,
|
||||
0x0000,
|
||||
0xffff);
|
||||
|
||||
////// Winding
|
||||
|
||||
// when we have separate stencil we increment front faces / decrement back faces
|
||||
// when we don't have wrap incr and decr we use the stencil test to simulate
|
||||
// them.
|
||||
|
||||
GR_STATIC_CONST_STENCIL(gWindStencilSeparateWithWrap,
|
||||
kIncWrap_StencilOp, kDecWrap_StencilOp,
|
||||
kKeep_StencilOp, kKeep_StencilOp,
|
||||
kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
|
||||
0xffff, 0xffff,
|
||||
0xffff, 0xffff,
|
||||
0xffff, 0xffff);
|
||||
|
||||
// if inc'ing the max value, invert to make 0
|
||||
// if dec'ing zero invert to make all ones.
|
||||
// we can't avoid touching the stencil on both passing and
|
||||
// failing, so we can't resctrict ourselves to the clip.
|
||||
GR_STATIC_CONST_STENCIL(gWindStencilSeparateNoWrap,
|
||||
kInvert_StencilOp, kInvert_StencilOp,
|
||||
kIncClamp_StencilOp, kDecClamp_StencilOp,
|
||||
kEqual_StencilFunc, kEqual_StencilFunc,
|
||||
0xffff, 0xffff,
|
||||
0xffff, 0x0000,
|
||||
0xffff, 0xffff);
|
||||
|
||||
// When there are no separate faces we do two passes to setup the winding rule
|
||||
// stencil. First we draw the front faces and inc, then we draw the back faces
|
||||
// and dec. These are same as the above two split into the incrementing and
|
||||
// decrementing passes.
|
||||
GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapInc,
|
||||
kIncWrap_StencilOp,
|
||||
kKeep_StencilOp,
|
||||
kAlwaysIfInClip_StencilFunc,
|
||||
0xffff,
|
||||
0xffff,
|
||||
0xffff);
|
||||
|
||||
GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapDec,
|
||||
kDecWrap_StencilOp,
|
||||
kKeep_StencilOp,
|
||||
kAlwaysIfInClip_StencilFunc,
|
||||
0xffff,
|
||||
0xffff,
|
||||
0xffff);
|
||||
|
||||
GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapInc,
|
||||
kInvert_StencilOp,
|
||||
kIncClamp_StencilOp,
|
||||
kEqual_StencilFunc,
|
||||
0xffff,
|
||||
0xffff,
|
||||
0xffff);
|
||||
|
||||
GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapDec,
|
||||
kInvert_StencilOp,
|
||||
kDecClamp_StencilOp,
|
||||
kEqual_StencilFunc,
|
||||
0xffff,
|
||||
0x0000,
|
||||
0xffff);
|
||||
|
||||
// Color passes are the same whether we use the two-sided stencil or two passes
|
||||
|
||||
GR_STATIC_CONST_SAME_STENCIL(gWindColorPass,
|
||||
kZero_StencilOp,
|
||||
kZero_StencilOp,
|
||||
kNonZeroIfInClip_StencilFunc,
|
||||
0xffff,
|
||||
0x0000,
|
||||
0xffff);
|
||||
|
||||
GR_STATIC_CONST_SAME_STENCIL(gInvWindColorPass,
|
||||
kZero_StencilOp,
|
||||
kZero_StencilOp,
|
||||
kEqualIfInClip_StencilFunc,
|
||||
0xffff,
|
||||
0x0000,
|
||||
0xffff);
|
||||
|
||||
////// Normal render to stencil
|
||||
|
||||
// Sometimes the default path renderer can draw a path directly to the stencil
|
||||
// buffer without having to first resolve the interior / exterior.
|
||||
GR_STATIC_CONST_SAME_STENCIL(gDirectToStencil,
|
||||
kZero_StencilOp,
|
||||
kIncClamp_StencilOp,
|
||||
kAlwaysIfInClip_StencilFunc,
|
||||
0xffff,
|
||||
0x0000,
|
||||
0xffff);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Helpers for drawPath
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#define GrDefaultPathRenderer_DEFINED
|
||||
|
||||
#include "GrPathRenderer.h"
|
||||
#include "GrPathStencilSettings.h"
|
||||
#include "SkTypes.h"
|
||||
|
||||
/**
|
||||
|
745
src/gpu/batches/GrMSAAPathRenderer.cpp
Normal file
745
src/gpu/batches/GrMSAAPathRenderer.cpp
Normal file
@ -0,0 +1,745 @@
|
||||
/*
|
||||
* Copyright 2016 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "GrMSAAPathRenderer.h"
|
||||
|
||||
#include "GrBatchFlushState.h"
|
||||
#include "GrDefaultGeoProcFactory.h"
|
||||
#include "GrPathStencilSettings.h"
|
||||
#include "GrPathUtils.h"
|
||||
#include "GrPipelineBuilder.h"
|
||||
#include "GrMesh.h"
|
||||
#include "SkGeometry.h"
|
||||
#include "SkTraceEvent.h"
|
||||
#include "glsl/GrGLSLGeometryProcessor.h"
|
||||
#include "glsl/GrGLSLFragmentShaderBuilder.h"
|
||||
#include "glsl/GrGLSLVertexShaderBuilder.h"
|
||||
#include "glsl/GrGLSLProgramDataManager.h"
|
||||
#include "glsl/GrGLSLUtil.h"
|
||||
#include "gl/GrGLVaryingHandler.h"
|
||||
#include "batches/GrRectBatchFactory.h"
|
||||
#include "batches/GrVertexBatch.h"
|
||||
|
||||
static const float kTolerance = 0.5f;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Helpers for drawPath
|
||||
|
||||
static inline bool single_pass_path(const SkPath& path, const SkStrokeRec& stroke) {
|
||||
if (!path.isInverseFillType()) {
|
||||
return path.isConvex();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
GrPathRenderer::StencilSupport
|
||||
GrMSAAPathRenderer::onGetStencilSupport(const SkPath& path, const GrStrokeInfo& stroke) const {
|
||||
if (single_pass_path(path, stroke)) {
|
||||
return GrPathRenderer::kNoRestriction_StencilSupport;
|
||||
} else {
|
||||
return GrPathRenderer::kStencilOnly_StencilSupport;
|
||||
}
|
||||
}
|
||||
|
||||
struct MSAALineVertices {
|
||||
struct Vertex {
|
||||
SkPoint fPosition;
|
||||
SkColor fColor;
|
||||
};
|
||||
Vertex* vertices;
|
||||
Vertex* nextVertex;
|
||||
#ifdef SK_DEBUG
|
||||
Vertex* verticesEnd;
|
||||
#endif
|
||||
uint16_t* indices;
|
||||
uint16_t* nextIndex;
|
||||
};
|
||||
|
||||
struct MSAAQuadVertices {
|
||||
struct Vertex {
|
||||
SkPoint fPosition;
|
||||
SkPoint fUV;
|
||||
SkColor fColor;
|
||||
};
|
||||
Vertex* vertices;
|
||||
Vertex* nextVertex;
|
||||
#ifdef SK_DEBUG
|
||||
Vertex* verticesEnd;
|
||||
#endif
|
||||
uint16_t* indices;
|
||||
uint16_t* nextIndex;
|
||||
};
|
||||
|
||||
static inline void append_contour_edge_indices(uint16_t fanCenterIdx,
|
||||
uint16_t edgeV0Idx,
|
||||
MSAALineVertices& lines) {
|
||||
*(lines.nextIndex++) = fanCenterIdx;
|
||||
*(lines.nextIndex++) = edgeV0Idx;
|
||||
*(lines.nextIndex++) = edgeV0Idx + 1;
|
||||
}
|
||||
|
||||
static inline void add_quad(MSAALineVertices& lines, MSAAQuadVertices& quads, const SkPoint pts[],
|
||||
SkColor color, bool indexed, uint16_t subpathLineIdxStart) {
|
||||
SkASSERT(lines.nextVertex < lines.verticesEnd);
|
||||
*lines.nextVertex = { pts[2], color };
|
||||
if (indexed) {
|
||||
int prevIdx = (uint16_t) (lines.nextVertex - lines.vertices - 1);
|
||||
if (prevIdx > subpathLineIdxStart) {
|
||||
append_contour_edge_indices(subpathLineIdxStart, prevIdx, lines);
|
||||
}
|
||||
}
|
||||
lines.nextVertex++;
|
||||
|
||||
SkASSERT(quads.nextVertex + 2 < quads.verticesEnd);
|
||||
// the texture coordinates are drawn from the Loop-Blinn rendering algorithm
|
||||
*(quads.nextVertex++) = { pts[0], SkPoint::Make(0.0, 0.0), color };
|
||||
*(quads.nextVertex++) = { pts[1], SkPoint::Make(0.5, 0.0), color };
|
||||
*(quads.nextVertex++) = { pts[2], SkPoint::Make(1.0, 1.0), color };
|
||||
if (indexed) {
|
||||
uint16_t offset = (uint16_t) (quads.nextVertex - quads.vertices) - 3;
|
||||
*(quads.nextIndex++) = offset++;
|
||||
*(quads.nextIndex++) = offset++;
|
||||
*(quads.nextIndex++) = offset++;
|
||||
}
|
||||
}
|
||||
|
||||
class MSAAQuadProcessor : public GrGeometryProcessor {
|
||||
public:
|
||||
static GrGeometryProcessor* Create(const SkMatrix& viewMatrix) {
|
||||
return new MSAAQuadProcessor(viewMatrix);
|
||||
}
|
||||
|
||||
virtual ~MSAAQuadProcessor() {}
|
||||
|
||||
const char* name() const override { return "MSAAQuadProcessor"; }
|
||||
|
||||
const Attribute* inPosition() const { return fInPosition; }
|
||||
const Attribute* inUV() const { return fInUV; }
|
||||
const Attribute* inColor() const { return fInColor; }
|
||||
const SkMatrix& viewMatrix() const { return fViewMatrix; }
|
||||
const SkMatrix& localMatrix() const { return SkMatrix::I(); }
|
||||
|
||||
class GLSLProcessor : public GrGLSLGeometryProcessor {
|
||||
public:
|
||||
GLSLProcessor(const GrGeometryProcessor& qpr) {}
|
||||
|
||||
void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
|
||||
const MSAAQuadProcessor& qp = args.fGP.cast<MSAAQuadProcessor>();
|
||||
GrGLSLVertexBuilder* vsBuilder = args.fVertBuilder;
|
||||
GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
|
||||
GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
|
||||
|
||||
// emit attributes
|
||||
varyingHandler->emitAttributes(qp);
|
||||
varyingHandler->addPassThroughAttribute(qp.inColor(), args.fOutputColor);
|
||||
|
||||
GrGLSLVertToFrag uv(kVec2f_GrSLType);
|
||||
varyingHandler->addVarying("uv", &uv, kHigh_GrSLPrecision);
|
||||
vsBuilder->codeAppendf("%s = %s;", uv.vsOut(), qp.inUV()->fName);
|
||||
|
||||
// Setup position
|
||||
this->setupPosition(vsBuilder, uniformHandler, gpArgs, qp.inPosition()->fName,
|
||||
qp.viewMatrix(), &fViewMatrixUniform);
|
||||
|
||||
// emit transforms
|
||||
this->emitTransforms(vsBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar,
|
||||
qp.inPosition()->fName, SkMatrix::I(), args.fTransformsIn,
|
||||
args.fTransformsOut);
|
||||
|
||||
GrGLSLPPFragmentBuilder* fsBuilder = args.fFragBuilder;
|
||||
fsBuilder->codeAppendf("if (%s.x * %s.x >= %s.y) discard;", uv.fsIn(), uv.fsIn(),
|
||||
uv.fsIn());
|
||||
fsBuilder->codeAppendf("%s = vec4(1.0);", args.fOutputCoverage);
|
||||
}
|
||||
|
||||
static inline void GenKey(const GrGeometryProcessor& gp,
|
||||
const GrGLSLCaps&,
|
||||
GrProcessorKeyBuilder* b) {
|
||||
const MSAAQuadProcessor& qp = gp.cast<MSAAQuadProcessor>();
|
||||
uint32_t key = 0;
|
||||
key |= qp.viewMatrix().hasPerspective() ? 0x1 : 0x0;
|
||||
key |= qp.viewMatrix().isIdentity() ? 0x2: 0x0;
|
||||
b->add32(key);
|
||||
}
|
||||
|
||||
virtual void setData(const GrGLSLProgramDataManager& pdman,
|
||||
const GrPrimitiveProcessor& gp) override {
|
||||
const MSAAQuadProcessor& qp = gp.cast<MSAAQuadProcessor>();
|
||||
if (!qp.viewMatrix().isIdentity()) {
|
||||
float viewMatrix[3 * 3];
|
||||
GrGLSLGetMatrix<3>(viewMatrix, qp.viewMatrix());
|
||||
pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
|
||||
}
|
||||
}
|
||||
|
||||
void setTransformData(const GrPrimitiveProcessor& primProc,
|
||||
const GrGLSLProgramDataManager& pdman,
|
||||
int index,
|
||||
const SkTArray<const GrCoordTransform*, true>& transforms) override {
|
||||
this->setTransformDataHelper<MSAAQuadProcessor>(primProc, pdman, index, transforms);
|
||||
}
|
||||
|
||||
private:
|
||||
typedef GrGLSLGeometryProcessor INHERITED;
|
||||
|
||||
UniformHandle fViewMatrixUniform;
|
||||
};
|
||||
|
||||
virtual void getGLSLProcessorKey(const GrGLSLCaps& caps,
|
||||
GrProcessorKeyBuilder* b) const override {
|
||||
GLSLProcessor::GenKey(*this, caps, b);
|
||||
}
|
||||
|
||||
virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override {
|
||||
return new GLSLProcessor(*this);
|
||||
}
|
||||
|
||||
private:
|
||||
MSAAQuadProcessor(const SkMatrix& viewMatrix)
|
||||
: fViewMatrix(viewMatrix) {
|
||||
this->initClassID<MSAAQuadProcessor>();
|
||||
fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
|
||||
kHigh_GrSLPrecision));
|
||||
fInUV = &this->addVertexAttrib(Attribute("inUV", kVec2f_GrVertexAttribType,
|
||||
kHigh_GrSLPrecision));
|
||||
fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType));
|
||||
this->setSampleShading(1.0f);
|
||||
}
|
||||
|
||||
const Attribute* fInPosition;
|
||||
const Attribute* fInUV;
|
||||
const Attribute* fInColor;
|
||||
SkMatrix fViewMatrix;
|
||||
|
||||
GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
|
||||
|
||||
typedef GrGeometryProcessor INHERITED;
|
||||
};
|
||||
|
||||
class MSAAPathBatch : public GrVertexBatch {
|
||||
public:
|
||||
DEFINE_BATCH_CLASS_ID
|
||||
|
||||
struct Geometry {
|
||||
GrColor fColor;
|
||||
SkPath fPath;
|
||||
SkScalar fTolerance;
|
||||
};
|
||||
|
||||
static MSAAPathBatch* Create(const Geometry& geometry, const SkMatrix& viewMatrix,
|
||||
const SkRect& devBounds) {
|
||||
return new MSAAPathBatch(geometry, viewMatrix, devBounds);
|
||||
}
|
||||
|
||||
const char* name() const override { return "MSAAPathBatch"; }
|
||||
|
||||
void computePipelineOptimizations(GrInitInvariantOutput* color,
|
||||
GrInitInvariantOutput* coverage,
|
||||
GrBatchToXPOverrides* overrides) const override {
|
||||
// When this is called on a batch, there is only one geometry bundle
|
||||
color->setKnownFourComponents(fGeoData[0].fColor);
|
||||
coverage->setKnownSingleComponent(0xff);
|
||||
}
|
||||
|
||||
bool isValid() const {
|
||||
return !fIsIndexed || fMaxLineIndices <= SK_MaxU16;
|
||||
}
|
||||
|
||||
private:
|
||||
void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
|
||||
// Handle any color overrides
|
||||
if (!overrides.readsColor()) {
|
||||
fGeoData[0].fColor = GrColor_ILLEGAL;
|
||||
}
|
||||
overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
|
||||
}
|
||||
|
||||
void computeWorstCasePointCount(const SkPath& path, int* subpaths, SkScalar tol,
|
||||
int* outLinePointCount, int* outQuadPointCount) const {
|
||||
int linePointCount = 0;
|
||||
int quadPointCount = 0;
|
||||
*subpaths = 1;
|
||||
|
||||
bool first = true;
|
||||
|
||||
SkPath::Iter iter(path, false);
|
||||
SkPath::Verb verb;
|
||||
|
||||
SkPoint pts[4];
|
||||
while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
|
||||
switch (verb) {
|
||||
case SkPath::kLine_Verb:
|
||||
linePointCount += 1;
|
||||
break;
|
||||
case SkPath::kConic_Verb: {
|
||||
SkScalar weight = iter.conicWeight();
|
||||
SkAutoConicToQuads converter;
|
||||
converter.computeQuads(pts, weight, kTolerance);
|
||||
int quadPts = converter.countQuads();
|
||||
linePointCount += quadPts;
|
||||
quadPointCount += 3 * quadPts;
|
||||
}
|
||||
case SkPath::kQuad_Verb:
|
||||
linePointCount += 1;
|
||||
quadPointCount += 3;
|
||||
break;
|
||||
case SkPath::kCubic_Verb: {
|
||||
SkSTArray<15, SkPoint, true> quadPts;
|
||||
GrPathUtils::convertCubicToQuads(pts, kTolerance, &quadPts);
|
||||
int count = quadPts.count();
|
||||
linePointCount += count / 3;
|
||||
quadPointCount += count;
|
||||
break;
|
||||
}
|
||||
case SkPath::kMove_Verb:
|
||||
linePointCount += 1;
|
||||
if (!first) {
|
||||
++(*subpaths);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
*outLinePointCount = linePointCount;
|
||||
*outQuadPointCount = quadPointCount;
|
||||
}
|
||||
|
||||
void onPrepareDraws(Target* target) const override {
|
||||
SkASSERT(this->isValid());
|
||||
if (fMaxLineVertices == 0) {
|
||||
SkASSERT(fMaxQuadVertices == 0);
|
||||
return;
|
||||
}
|
||||
|
||||
GrPrimitiveType primitiveType = fIsIndexed ? kTriangles_GrPrimitiveType
|
||||
: kTriangleFan_GrPrimitiveType;
|
||||
|
||||
// allocate vertex / index buffers
|
||||
const GrBuffer* lineVertexBuffer;
|
||||
int firstLineVertex;
|
||||
MSAALineVertices lines;
|
||||
size_t lineVertexStride = sizeof(MSAALineVertices::Vertex);
|
||||
lines.vertices = (MSAALineVertices::Vertex*) target->makeVertexSpace(lineVertexStride,
|
||||
fMaxLineVertices,
|
||||
&lineVertexBuffer,
|
||||
&firstLineVertex);
|
||||
if (!lines.vertices) {
|
||||
SkDebugf("Could not allocate vertices\n");
|
||||
return;
|
||||
}
|
||||
lines.nextVertex = lines.vertices;
|
||||
SkDEBUGCODE(lines.verticesEnd = lines.vertices + fMaxLineVertices;)
|
||||
|
||||
MSAAQuadVertices quads;
|
||||
size_t quadVertexStride = sizeof(MSAAQuadVertices::Vertex);
|
||||
SkAutoFree quadVertexPtr(sk_malloc_throw(fMaxQuadVertices * quadVertexStride));
|
||||
quads.vertices = (MSAAQuadVertices::Vertex*) quadVertexPtr.get();
|
||||
quads.nextVertex = quads.vertices;
|
||||
SkDEBUGCODE(quads.verticesEnd = quads.vertices + fMaxQuadVertices;)
|
||||
|
||||
const GrBuffer* lineIndexBuffer = nullptr;
|
||||
int firstLineIndex;
|
||||
if (fIsIndexed) {
|
||||
lines.indices = target->makeIndexSpace(fMaxLineIndices, &lineIndexBuffer,
|
||||
&firstLineIndex);
|
||||
if (!lines.indices) {
|
||||
SkDebugf("Could not allocate indices\n");
|
||||
return;
|
||||
}
|
||||
lines.nextIndex = lines.indices;
|
||||
} else {
|
||||
lines.indices = nullptr;
|
||||
lines.nextIndex = nullptr;
|
||||
}
|
||||
|
||||
SkAutoFree quadIndexPtr;
|
||||
if (fIsIndexed) {
|
||||
quads.indices = (uint16_t*) sk_malloc_throw(fMaxQuadIndices * sizeof(uint16_t));
|
||||
quadIndexPtr.set(quads.indices);
|
||||
quads.nextIndex = quads.indices;
|
||||
} else {
|
||||
quads.indices = nullptr;
|
||||
quads.nextIndex = nullptr;
|
||||
}
|
||||
|
||||
// fill buffers
|
||||
for (int i = 0; i < fGeoData.count(); i++) {
|
||||
const Geometry& args = fGeoData[i];
|
||||
|
||||
if (!this->createGeom(lines,
|
||||
quads,
|
||||
args.fPath,
|
||||
args.fTolerance,
|
||||
fViewMatrix,
|
||||
args.fColor,
|
||||
fIsIndexed)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
int lineVertexOffset = (int) (lines.nextVertex - lines.vertices);
|
||||
int lineIndexOffset = (int) (lines.nextIndex - lines.indices);
|
||||
SkASSERT(lineVertexOffset <= fMaxLineVertices && lineIndexOffset <= fMaxLineIndices);
|
||||
int quadVertexOffset = (int) (quads.nextVertex - quads.vertices);
|
||||
int quadIndexOffset = (int) (quads.nextIndex - quads.indices);
|
||||
SkASSERT(quadVertexOffset <= fMaxQuadVertices && quadIndexOffset <= fMaxQuadIndices);
|
||||
|
||||
if (lineVertexOffset) {
|
||||
SkAutoTUnref<const GrGeometryProcessor> lineGP;
|
||||
{
|
||||
using namespace GrDefaultGeoProcFactory;
|
||||
lineGP.reset(GrDefaultGeoProcFactory::Create(Color(Color::kAttribute_Type),
|
||||
Coverage(255),
|
||||
LocalCoords(LocalCoords::kUnused_Type),
|
||||
fViewMatrix));
|
||||
}
|
||||
SkASSERT(lineVertexStride == lineGP->getVertexStride());
|
||||
|
||||
GrMesh lineMeshes;
|
||||
if (fIsIndexed) {
|
||||
lineMeshes.initIndexed(primitiveType, lineVertexBuffer, lineIndexBuffer,
|
||||
firstLineVertex, firstLineIndex, lineVertexOffset,
|
||||
lineIndexOffset);
|
||||
} else {
|
||||
lineMeshes.init(primitiveType, lineVertexBuffer, firstLineVertex,
|
||||
lineVertexOffset);
|
||||
}
|
||||
target->draw(lineGP, lineMeshes);
|
||||
}
|
||||
|
||||
if (quadVertexOffset) {
|
||||
SkAutoTUnref<const GrGeometryProcessor> quadGP(MSAAQuadProcessor::Create(fViewMatrix));
|
||||
SkASSERT(quadVertexStride == quadGP->getVertexStride());
|
||||
|
||||
const GrBuffer* quadVertexBuffer;
|
||||
int firstQuadVertex;
|
||||
MSAAQuadVertices::Vertex* quadVertices = (MSAAQuadVertices::Vertex*)
|
||||
target->makeVertexSpace(quadVertexStride, quadVertexOffset, &quadVertexBuffer,
|
||||
&firstQuadVertex);
|
||||
memcpy(quadVertices, quads.vertices, quadVertexStride * quadVertexOffset);
|
||||
GrMesh quadMeshes;
|
||||
if (fIsIndexed) {
|
||||
const GrBuffer* quadIndexBuffer;
|
||||
int firstQuadIndex;
|
||||
uint16_t* quadIndices = (uint16_t*) target->makeIndexSpace(quadIndexOffset,
|
||||
&quadIndexBuffer,
|
||||
&firstQuadIndex);
|
||||
memcpy(quadIndices, quads.indices, sizeof(uint16_t) * quadIndexOffset);
|
||||
quadMeshes.initIndexed(kTriangles_GrPrimitiveType, quadVertexBuffer,
|
||||
quadIndexBuffer, firstQuadVertex, firstQuadIndex,
|
||||
quadVertexOffset, quadIndexOffset);
|
||||
} else {
|
||||
quadMeshes.init(kTriangles_GrPrimitiveType, quadVertexBuffer, firstQuadVertex,
|
||||
quadVertexOffset);
|
||||
}
|
||||
target->draw(quadGP, quadMeshes);
|
||||
}
|
||||
}
|
||||
|
||||
SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
|
||||
|
||||
MSAAPathBatch(const Geometry& geometry, const SkMatrix& viewMatrix, const SkRect& devBounds)
|
||||
: INHERITED(ClassID())
|
||||
, fViewMatrix(viewMatrix) {
|
||||
fGeoData.push_back(geometry);
|
||||
this->setBounds(devBounds);
|
||||
int contourCount;
|
||||
this->computeWorstCasePointCount(geometry.fPath, &contourCount, kTolerance,
|
||||
&fMaxLineVertices, &fMaxQuadVertices);
|
||||
fMaxLineIndices = fMaxLineVertices * 3;
|
||||
fMaxQuadIndices = fMaxQuadVertices * 3;
|
||||
fIsIndexed = contourCount > 1;
|
||||
}
|
||||
|
||||
bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
|
||||
MSAAPathBatch* that = t->cast<MSAAPathBatch>();
|
||||
if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
|
||||
that->bounds(), caps)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!fViewMatrix.cheapEqualTo(that->fViewMatrix)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fMaxLineIndices + that->fMaxLineIndices > SK_MaxU16) {
|
||||
return false;
|
||||
}
|
||||
SkASSERT(fMaxQuadIndices + that->fMaxQuadIndices <= SK_MaxU16);
|
||||
|
||||
fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
|
||||
this->joinBounds(that->bounds());
|
||||
fIsIndexed = true;
|
||||
fMaxLineVertices += that->fMaxLineVertices;
|
||||
fMaxQuadVertices += that->fMaxQuadVertices;
|
||||
fMaxLineIndices += that->fMaxLineIndices;
|
||||
fMaxQuadIndices += that->fMaxQuadIndices;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool createGeom(MSAALineVertices& lines,
|
||||
MSAAQuadVertices& quads,
|
||||
const SkPath& path,
|
||||
SkScalar srcSpaceTol,
|
||||
const SkMatrix& m,
|
||||
SkColor color,
|
||||
bool isIndexed) const {
|
||||
{
|
||||
uint16_t subpathIdxStart = (uint16_t) (lines.nextVertex - lines.vertices);
|
||||
|
||||
SkPoint pts[4];
|
||||
|
||||
bool first = true;
|
||||
SkPath::Iter iter(path, false);
|
||||
|
||||
bool done = false;
|
||||
while (!done) {
|
||||
SkPath::Verb verb = iter.next(pts);
|
||||
switch (verb) {
|
||||
case SkPath::kMove_Verb:
|
||||
if (!first) {
|
||||
uint16_t currIdx = (uint16_t) (lines.nextVertex - lines.vertices);
|
||||
subpathIdxStart = currIdx;
|
||||
}
|
||||
SkASSERT(lines.nextVertex < lines.verticesEnd);
|
||||
*(lines.nextVertex++) = { pts[0], color };
|
||||
break;
|
||||
case SkPath::kLine_Verb:
|
||||
if (isIndexed) {
|
||||
uint16_t prevIdx = (uint16_t) (lines.nextVertex - lines.vertices - 1);
|
||||
if (prevIdx > subpathIdxStart) {
|
||||
append_contour_edge_indices(subpathIdxStart, prevIdx, lines);
|
||||
}
|
||||
}
|
||||
SkASSERT(lines.nextVertex < lines.verticesEnd);
|
||||
*(lines.nextVertex++) = { pts[1], color };
|
||||
break;
|
||||
case SkPath::kConic_Verb: {
|
||||
SkScalar weight = iter.conicWeight();
|
||||
SkAutoConicToQuads converter;
|
||||
const SkPoint* quadPts = converter.computeQuads(pts, weight,
|
||||
kTolerance);
|
||||
for (int i = 0; i < converter.countQuads(); ++i) {
|
||||
add_quad(lines, quads, quadPts + i * 2, color, isIndexed,
|
||||
subpathIdxStart);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SkPath::kQuad_Verb: {
|
||||
add_quad(lines, quads, pts, color, isIndexed, subpathIdxStart);
|
||||
break;
|
||||
}
|
||||
case SkPath::kCubic_Verb: {
|
||||
SkSTArray<15, SkPoint, true> quadPts;
|
||||
GrPathUtils::convertCubicToQuads(pts, kTolerance, &quadPts);
|
||||
int count = quadPts.count();
|
||||
for (int i = 0; i < count; i += 3) {
|
||||
add_quad(lines, quads, &quadPts[i], color, isIndexed, subpathIdxStart);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SkPath::kClose_Verb:
|
||||
break;
|
||||
case SkPath::kDone_Verb:
|
||||
done = true;
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
SkSTArray<1, Geometry, true> fGeoData;
|
||||
|
||||
SkMatrix fViewMatrix;
|
||||
int fMaxLineVertices;
|
||||
int fMaxQuadVertices;
|
||||
int fMaxLineIndices;
|
||||
int fMaxQuadIndices;
|
||||
bool fIsIndexed;
|
||||
|
||||
typedef GrVertexBatch INHERITED;
|
||||
};
|
||||
|
||||
bool GrMSAAPathRenderer::internalDrawPath(GrDrawTarget* target,
|
||||
GrPipelineBuilder* pipelineBuilder,
|
||||
GrColor color,
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkPath& path,
|
||||
const GrStrokeInfo& origStroke,
|
||||
bool stencilOnly) {
|
||||
SkTCopyOnFirstWrite<GrStrokeInfo> stroke(origStroke);
|
||||
|
||||
const GrXPFactory* xpFactory = pipelineBuilder->getXPFactory();
|
||||
SkAutoTUnref<const GrXPFactory> backupXPFactory(SkSafeRef(xpFactory));
|
||||
// face culling doesn't make sense here
|
||||
SkASSERT(GrPipelineBuilder::kBoth_DrawFace == pipelineBuilder->getDrawFace());
|
||||
|
||||
int passCount = 0;
|
||||
const GrStencilSettings* passes[3];
|
||||
GrPipelineBuilder::DrawFace drawFace[3];
|
||||
bool reverse = false;
|
||||
bool lastPassIsBounds;
|
||||
|
||||
if (single_pass_path(path, *stroke)) {
|
||||
passCount = 1;
|
||||
if (stencilOnly) {
|
||||
passes[0] = &gDirectToStencil;
|
||||
} else {
|
||||
passes[0] = nullptr;
|
||||
}
|
||||
drawFace[0] = GrPipelineBuilder::kBoth_DrawFace;
|
||||
lastPassIsBounds = false;
|
||||
} else {
|
||||
switch (path.getFillType()) {
|
||||
case SkPath::kInverseEvenOdd_FillType:
|
||||
reverse = true;
|
||||
// fallthrough
|
||||
case SkPath::kEvenOdd_FillType:
|
||||
passes[0] = &gEOStencilPass;
|
||||
if (stencilOnly) {
|
||||
passCount = 1;
|
||||
lastPassIsBounds = false;
|
||||
} else {
|
||||
passCount = 2;
|
||||
lastPassIsBounds = true;
|
||||
if (reverse) {
|
||||
passes[1] = &gInvEOColorPass;
|
||||
} else {
|
||||
passes[1] = &gEOColorPass;
|
||||
}
|
||||
}
|
||||
drawFace[0] = drawFace[1] = GrPipelineBuilder::kBoth_DrawFace;
|
||||
break;
|
||||
|
||||
case SkPath::kInverseWinding_FillType:
|
||||
reverse = true;
|
||||
// fallthrough
|
||||
case SkPath::kWinding_FillType:
|
||||
passes[0] = &gWindStencilSeparateWithWrap;
|
||||
passCount = 2;
|
||||
drawFace[0] = GrPipelineBuilder::kBoth_DrawFace;
|
||||
if (stencilOnly) {
|
||||
lastPassIsBounds = false;
|
||||
--passCount;
|
||||
} else {
|
||||
lastPassIsBounds = true;
|
||||
drawFace[passCount-1] = GrPipelineBuilder::kBoth_DrawFace;
|
||||
if (reverse) {
|
||||
passes[passCount-1] = &gInvWindColorPass;
|
||||
} else {
|
||||
passes[passCount-1] = &gWindColorPass;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
SkDEBUGFAIL("Unknown path fFill!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
SkRect devBounds;
|
||||
GetPathDevBounds(path, pipelineBuilder->getRenderTarget(), viewMatrix, &devBounds);
|
||||
|
||||
for (int p = 0; p < passCount; ++p) {
|
||||
pipelineBuilder->setDrawFace(drawFace[p]);
|
||||
if (passes[p]) {
|
||||
*pipelineBuilder->stencil() = *passes[p];
|
||||
}
|
||||
|
||||
if (lastPassIsBounds && (p == passCount-1)) {
|
||||
// Reset the XP Factory on pipelineBuilder
|
||||
pipelineBuilder->setXPFactory(backupXPFactory);
|
||||
SkRect bounds;
|
||||
SkMatrix localMatrix = SkMatrix::I();
|
||||
if (reverse) {
|
||||
SkASSERT(pipelineBuilder->getRenderTarget());
|
||||
// draw over the dev bounds (which will be the whole dst surface for inv fill).
|
||||
bounds = devBounds;
|
||||
SkMatrix vmi;
|
||||
// mapRect through persp matrix may not be correct
|
||||
if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) {
|
||||
vmi.mapRect(&bounds);
|
||||
} else {
|
||||
if (!viewMatrix.invert(&localMatrix)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bounds = path.getBounds();
|
||||
}
|
||||
const SkMatrix& viewM = (reverse && viewMatrix.hasPerspective()) ? SkMatrix::I() :
|
||||
viewMatrix;
|
||||
SkAutoTUnref<GrDrawBatch> batch(
|
||||
GrRectBatchFactory::CreateNonAAFill(color, viewM, bounds, nullptr,
|
||||
&localMatrix));
|
||||
target->drawBatch(*pipelineBuilder, batch);
|
||||
} else {
|
||||
if (passCount > 1) {
|
||||
pipelineBuilder->setDisableColorXPFactory();
|
||||
}
|
||||
|
||||
MSAAPathBatch::Geometry geometry;
|
||||
geometry.fColor = color;
|
||||
geometry.fPath = path;
|
||||
geometry.fTolerance = kTolerance;
|
||||
|
||||
SkAutoTUnref<MSAAPathBatch> batch(MSAAPathBatch::Create(geometry, viewMatrix,
|
||||
devBounds));
|
||||
if (batch->isValid()) {
|
||||
target->drawBatch(*pipelineBuilder, batch);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GrMSAAPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
|
||||
return !IsStrokeHairlineOrEquivalent(*args.fStroke, *args.fViewMatrix, nullptr) &&
|
||||
!args.fAntiAlias;
|
||||
}
|
||||
|
||||
bool GrMSAAPathRenderer::onDrawPath(const DrawPathArgs& args) {
|
||||
GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(), "GrMSAAPathRenderer::onDrawPath");
|
||||
SkPath path;
|
||||
GrStrokeInfo stroke(*args.fStroke);
|
||||
if (stroke.isDashed()) {
|
||||
if (!stroke.applyDashToPath(&path, &stroke, *args.fPath)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
path = *args.fPath;
|
||||
}
|
||||
if (!stroke.isFillStyle()) {
|
||||
stroke.setResScale(SkScalarAbs(args.fViewMatrix->getMaxScale()));
|
||||
if (!stroke.applyToPath(&path, path)) {
|
||||
return false;
|
||||
}
|
||||
stroke.setFillStyle();
|
||||
}
|
||||
return this->internalDrawPath(args.fTarget,
|
||||
args.fPipelineBuilder,
|
||||
args.fColor,
|
||||
*args.fViewMatrix,
|
||||
path,
|
||||
stroke,
|
||||
false);
|
||||
}
|
||||
|
||||
void GrMSAAPathRenderer::onStencilPath(const StencilPathArgs& args) {
|
||||
GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(),"GrMSAAPathRenderer::onStencilPath");
|
||||
SkASSERT(SkPath::kInverseEvenOdd_FillType != args.fPath->getFillType());
|
||||
SkASSERT(SkPath::kInverseWinding_FillType != args.fPath->getFillType());
|
||||
this->internalDrawPath(args.fTarget, args.fPipelineBuilder, GrColor_WHITE, *args.fViewMatrix,
|
||||
*args.fPath, *args.fStroke, true);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
35
src/gpu/batches/GrMSAAPathRenderer.h
Normal file
35
src/gpu/batches/GrMSAAPathRenderer.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrMSAAPathRenderer_DEFINED
|
||||
#define GrMSAAPathRenderer_DEFINED
|
||||
|
||||
#include "GrPathRenderer.h"
|
||||
#include "SkTypes.h"
|
||||
|
||||
class SK_API GrMSAAPathRenderer : public GrPathRenderer {
|
||||
private:
|
||||
StencilSupport onGetStencilSupport(const SkPath&, const GrStrokeInfo&) const override;
|
||||
|
||||
bool onCanDrawPath(const CanDrawPathArgs&) const override;
|
||||
|
||||
bool onDrawPath(const DrawPathArgs&) override;
|
||||
|
||||
void onStencilPath(const StencilPathArgs&) override;
|
||||
|
||||
bool internalDrawPath(GrDrawTarget*,
|
||||
GrPipelineBuilder*,
|
||||
GrColor,
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkPath&,
|
||||
const GrStrokeInfo&,
|
||||
bool stencilOnly);
|
||||
|
||||
typedef GrPathRenderer INHERITED;
|
||||
};
|
||||
|
||||
#endif
|
131
src/gpu/batches/GrPathStencilSettings.h
Normal file
131
src/gpu/batches/GrPathStencilSettings.h
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright 2016 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrPathStencilSettings_DEFINED
|
||||
#define GrPathStencilSettings_DEFINED
|
||||
|
||||
////// Even/Odd
|
||||
|
||||
GR_STATIC_CONST_SAME_STENCIL(gEOStencilPass,
|
||||
kInvert_StencilOp,
|
||||
kKeep_StencilOp,
|
||||
kAlwaysIfInClip_StencilFunc,
|
||||
0xffff,
|
||||
0xffff,
|
||||
0xffff);
|
||||
|
||||
// ok not to check clip b/c stencil pass only wrote inside clip
|
||||
GR_STATIC_CONST_SAME_STENCIL(gEOColorPass,
|
||||
kZero_StencilOp,
|
||||
kZero_StencilOp,
|
||||
kNotEqual_StencilFunc,
|
||||
0xffff,
|
||||
0x0000,
|
||||
0xffff);
|
||||
|
||||
// have to check clip b/c outside clip will always be zero.
|
||||
GR_STATIC_CONST_SAME_STENCIL(gInvEOColorPass,
|
||||
kZero_StencilOp,
|
||||
kZero_StencilOp,
|
||||
kEqualIfInClip_StencilFunc,
|
||||
0xffff,
|
||||
0x0000,
|
||||
0xffff);
|
||||
|
||||
////// Winding
|
||||
|
||||
// when we have separate stencil we increment front faces / decrement back faces
|
||||
// when we don't have wrap incr and decr we use the stencil test to simulate
|
||||
// them.
|
||||
|
||||
GR_STATIC_CONST_STENCIL(gWindStencilSeparateWithWrap,
|
||||
kIncWrap_StencilOp, kDecWrap_StencilOp,
|
||||
kKeep_StencilOp, kKeep_StencilOp,
|
||||
kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
|
||||
0xffff, 0xffff,
|
||||
0xffff, 0xffff,
|
||||
0xffff, 0xffff);
|
||||
|
||||
// if inc'ing the max value, invert to make 0
|
||||
// if dec'ing zero invert to make all ones.
|
||||
// we can't avoid touching the stencil on both passing and
|
||||
// failing, so we can't resctrict ourselves to the clip.
|
||||
GR_STATIC_CONST_STENCIL(gWindStencilSeparateNoWrap,
|
||||
kInvert_StencilOp, kInvert_StencilOp,
|
||||
kIncClamp_StencilOp, kDecClamp_StencilOp,
|
||||
kEqual_StencilFunc, kEqual_StencilFunc,
|
||||
0xffff, 0xffff,
|
||||
0xffff, 0x0000,
|
||||
0xffff, 0xffff);
|
||||
|
||||
// When there are no separate faces we do two passes to setup the winding rule
|
||||
// stencil. First we draw the front faces and inc, then we draw the back faces
|
||||
// and dec. These are same as the above two split into the incrementing and
|
||||
// decrementing passes.
|
||||
GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapInc,
|
||||
kIncWrap_StencilOp,
|
||||
kKeep_StencilOp,
|
||||
kAlwaysIfInClip_StencilFunc,
|
||||
0xffff,
|
||||
0xffff,
|
||||
0xffff);
|
||||
|
||||
GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapDec,
|
||||
kDecWrap_StencilOp,
|
||||
kKeep_StencilOp,
|
||||
kAlwaysIfInClip_StencilFunc,
|
||||
0xffff,
|
||||
0xffff,
|
||||
0xffff);
|
||||
|
||||
GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapInc,
|
||||
kInvert_StencilOp,
|
||||
kIncClamp_StencilOp,
|
||||
kEqual_StencilFunc,
|
||||
0xffff,
|
||||
0xffff,
|
||||
0xffff);
|
||||
|
||||
GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapDec,
|
||||
kInvert_StencilOp,
|
||||
kDecClamp_StencilOp,
|
||||
kEqual_StencilFunc,
|
||||
0xffff,
|
||||
0x0000,
|
||||
0xffff);
|
||||
|
||||
// Color passes are the same whether we use the two-sided stencil or two passes
|
||||
|
||||
GR_STATIC_CONST_SAME_STENCIL(gWindColorPass,
|
||||
kZero_StencilOp,
|
||||
kZero_StencilOp,
|
||||
kNonZeroIfInClip_StencilFunc,
|
||||
0xffff,
|
||||
0x0000,
|
||||
0xffff);
|
||||
|
||||
GR_STATIC_CONST_SAME_STENCIL(gInvWindColorPass,
|
||||
kZero_StencilOp,
|
||||
kZero_StencilOp,
|
||||
kEqualIfInClip_StencilFunc,
|
||||
0xffff,
|
||||
0x0000,
|
||||
0xffff);
|
||||
|
||||
////// Normal render to stencil
|
||||
|
||||
// Sometimes the default path renderer can draw a path directly to the stencil
|
||||
// buffer without having to first resolve the interior / exterior.
|
||||
GR_STATIC_CONST_SAME_STENCIL(gDirectToStencil,
|
||||
kZero_StencilOp,
|
||||
kIncClamp_StencilOp,
|
||||
kAlwaysIfInClip_StencilFunc,
|
||||
0xffff,
|
||||
0x0000,
|
||||
0xffff);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user