aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/gl
diff options
context:
space:
mode:
authorGravatar bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-06-28 18:48:06 +0000
committerGravatar bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-06-28 18:48:06 +0000
commitded4f4b163f5aa19c22c871178c55ecb34623846 (patch)
tree20c052999f9345c8cc8d0196e92760a5f4ca9273 /src/gpu/gl
parent28060e7c940b07038bdaa3c5f8d1d87cf199e228 (diff)
Initial support for GL_NV_path_renering. Experimental, there are still some issues to resolve, set gyp variable skia_nv_path_rendering=1 or build flag GR_GL_USE_NV_PATH_RENDERING to enable.
Diffstat (limited to 'src/gpu/gl')
-rw-r--r--src/gpu/gl/GrGLPath.cpp27
-rw-r--r--src/gpu/gl/GrGpuGL.cpp130
-rw-r--r--src/gpu/gl/GrGpuGL.h23
-rw-r--r--src/gpu/gl/GrGpuGL_program.cpp181
4 files changed, 263 insertions, 98 deletions
diff --git a/src/gpu/gl/GrGLPath.cpp b/src/gpu/gl/GrGLPath.cpp
index e09d073ee2..1626bb0822 100644
--- a/src/gpu/gl/GrGLPath.cpp
+++ b/src/gpu/gl/GrGLPath.cpp
@@ -54,11 +54,12 @@ inline int num_pts(const SkPath::Verb verb) {
GrGLPath::GrGLPath(GrGpuGL* gpu, const SkPath& path) : INHERITED(gpu) {
GL_CALL_RET(fPathID, GenPaths(1));
+ //GrPrintf("\tGenPaths ID: %d\n", fPathID);
SkPath::Iter iter(path, true);
SkSTArray<16, GrGLubyte, true> pathCommands;
#ifndef SK_SCALAR_IS_FLOAT
- GrCrash("Expected scalar is float.");
+ GR_STATIC_ASSERT(false);
#endif
SkSTArray<16, SkPoint, true> pathPoints;
@@ -82,8 +83,8 @@ GrGLPath::GrGLPath(GrGpuGL* gpu, const SkPath& path) : INHERITED(gpu) {
GL_CALL(PathCommands(fPathID,
verbCnt, &pathCommands[0],
2 * pointCnt, GR_GL_FLOAT, &pathPoints[0]));
- GrRect bounds = path.getBounds();
- bounds.roundOut(&fBounds);
+ //GrPrintf("\tPathCommands ID: %d\n", fPathID);
+ fBounds = path.getBounds();
}
GrGLPath::~GrGLPath() {
@@ -92,7 +93,27 @@ GrGLPath::~GrGLPath() {
void GrGLPath::onRelease() {
if (0 != fPathID) {
+ // FIXME: When we draw a clipped path we may get a call sequence that looks
+ // like this:
+ // GenPaths(1, &fPathID); // fPathID = 1, the path to draw
+ // PathCommands(1, ...);
+ // GenPaths(1, &fPathID); // fPathID = 2, the clip path
+ // PathCommands(2, ...);
+ // PathStencilFunc(...);
+ // StencilFillPath(2, ...); // draw the clip
+ // DeletePath(1, &fPathID); // fPathID == 2
+ // PathStencilFunc(...);
+ // StencilFillPath(2, ...); // draw the path
+ // DeletePath(1, &fPathID); // fPathID == 1
+ //
+ // Deleting the clip path causes the second StencilFillPath to fail with
+ // INVALID_OPERATION.
+#if 0
GL_CALL(DeletePaths(1, fPathID));
+ //GrPrintf("\tDeletePaths ID: %d\n", fPathID);
+#else
+ //GrPrintf("\tLeak Path ID: %d\n", fPathID);
+#endif
fPathID = 0;
}
}
diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp
index 2662f8e0b5..48ccd5daf7 100644
--- a/src/gpu/gl/GrGpuGL.cpp
+++ b/src/gpu/gl/GrGpuGL.cpp
@@ -268,6 +268,8 @@ void GrGpuGL::initCaps() {
fCaps.fMaxRenderTargetSize = GrMin(fCaps.fMaxTextureSize, fCaps.fMaxRenderTargetSize);
fCaps.fFSAASupport = GrGLCaps::kNone_MSFBOType != this->glCaps().msFBOType();
+ fCaps.fPathStencilingSupport = GR_GL_USE_NV_PATH_RENDERING &&
+ this->hasExtension("GL_NV_path_rendering");
// Enable supported shader-related caps
if (kDesktop_GrGLBinding == this->glBinding()) {
@@ -511,6 +513,8 @@ void GrGpuGL::onResetContext() {
fHWBoundRenderTarget = NULL;
+ fHWPathMatrixState.invalidate();
+
// we assume these values
if (this->glCaps().unpackRowLengthSupport()) {
GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0));
@@ -1322,11 +1326,8 @@ GrIndexBuffer* GrGpuGL::onCreateIndexBuffer(uint32_t size, bool dynamic) {
}
GrPath* GrGpuGL::onCreatePath(const SkPath& inPath) {
- GrPath* path = NULL;
- if (fCaps.fPathStencilingSupport) {
- path = new GrGLPath(this, inPath);
- }
- return path;
+ GrAssert(fCaps.fPathStencilingSupport);
+ return new GrGLPath(this, inPath);
}
void GrGpuGL::flushScissor() {
@@ -1735,8 +1736,78 @@ void GrGpuGL::onGpuDrawNonIndexed(GrPrimitiveType type,
#endif
}
-void GrGpuGL::onGpuStencilPath(const GrPath&, GrPathFill) {
- GrCrash("Not implemented yet. Should not get here.");
+namespace {
+const GrStencilSettings& winding_nv_path_stencil_settings() {
+ GR_STATIC_CONST_SAME_STENCIL_STRUCT(gSettings,
+ kIncClamp_StencilOp,
+ kIncClamp_StencilOp,
+ kAlwaysIfInClip_StencilFunc,
+ ~0, ~0, ~0);
+ 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,
+ ~0, ~0, ~0);
+ return *GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&gSettings);
+}
+}
+
+
+void GrGpuGL::setStencilPathSettings(const GrPath&,
+ GrPathFill fill,
+ GrStencilSettings* settings) {
+ switch (fill) {
+ case kEvenOdd_GrPathFill:
+ *settings = even_odd_nv_path_stencil_settings();
+ return;
+ case kWinding_GrPathFill:
+ *settings = winding_nv_path_stencil_settings();
+ return;
+ default:
+ GrCrash("Unexpected path fill.");
+ }
+}
+
+void GrGpuGL::onGpuStencilPath(const GrPath* path, GrPathFill fill) {
+ GrAssert(fCaps.fPathStencilingSupport);
+
+ GrGLuint id = static_cast<const GrGLPath*>(path)->pathID();
+ GrDrawState* drawState = this->drawState();
+ GrAssert(NULL != drawState->getRenderTarget());
+ if (NULL == drawState->getRenderTarget()->getStencilBuffer()) {
+ return;
+ }
+
+ // Decide how to manipulate the stencil buffer based on the fill rule.
+ // Also, assert that the stencil settings we set in setStencilPathSettings
+ // are present.
+ GrAssert(!fStencilSettings.isTwoSided());
+ GrGLenum fillMode;
+ switch (fill) {
+ case kWinding_GrPathFill:
+ fillMode = GR_GL_COUNT_UP;
+ GrAssert(kIncClamp_StencilOp ==
+ fStencilSettings.passOp(GrStencilSettings::kFront_Face));
+ GrAssert(kIncClamp_StencilOp ==
+ fStencilSettings.failOp(GrStencilSettings::kFront_Face));
+ break;
+ case kEvenOdd_GrPathFill:
+ fillMode = GR_GL_INVERT;
+ GrAssert(kInvert_StencilOp ==
+ fStencilSettings.passOp(GrStencilSettings::kFront_Face));
+ GrAssert(kInvert_StencilOp ==
+ fStencilSettings.failOp(GrStencilSettings::kFront_Face));
+ break;
+ default:
+ // Only the above two fill rules are allowed.
+ GrCrash("Unexpected path fill.");
+ }
+ GrGLint writeMask = fStencilSettings.writeMask(GrStencilSettings::kFront_Face);
+ GL_CALL(StencilFillPath(id, fillMode, writeMask));
+ //GrPrintf("\tStencilFillPath ID: %d\n", id);
}
void GrGpuGL::onResolveRenderTarget(GrRenderTarget* target) {
@@ -1863,19 +1934,28 @@ void set_gl_stencil(const GrGLInterface* gl,
}
}
-void GrGpuGL::flushStencil() {
- if (fStencilSettings.isDisabled()) {
- if (kNo_TriState != fHWStencilTestEnabled) {
- GL_CALL(Disable(GR_GL_STENCIL_TEST));
- fHWStencilTestEnabled = kNo_TriState;
- }
- } else {
- if (kYes_TriState != fHWStencilTestEnabled) {
- GL_CALL(Enable(GR_GL_STENCIL_TEST));
- fHWStencilTestEnabled = kYes_TriState;
+void GrGpuGL::flushStencil(DrawType type) {
+ if (kStencilPath_DrawType == type) {
+ GrAssert(!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 (kNo_TriState != fHWStencilTestEnabled) {
+ GL_CALL(Disable(GR_GL_STENCIL_TEST));
+ fHWStencilTestEnabled = kNo_TriState;
+ }
+ } else {
+ if (kYes_TriState != fHWStencilTestEnabled) {
+ GL_CALL(Enable(GR_GL_STENCIL_TEST));
+ fHWStencilTestEnabled = kYes_TriState;
+ }
}
- }
- if (fHWStencilSettings != fStencilSettings) {
if (!fStencilSettings.isDisabled()) {
if (this->getCaps().fTwoSidedStencilSupport) {
set_gl_stencil(this->glInterface(),
@@ -1897,7 +1977,7 @@ void GrGpuGL::flushStencil() {
}
}
-void GrGpuGL::flushAAState(bool isLines) {
+void GrGpuGL::flushAAState(DrawType type) {
const GrRenderTarget* rt = this->getDrawState().getRenderTarget();
if (kDesktop_GrGLBinding == this->glBinding()) {
// ES doesn't support toggling GL_MULTISAMPLE and doesn't have
@@ -1905,7 +1985,7 @@ void GrGpuGL::flushAAState(bool isLines) {
// we prefer smooth lines over multisampled lines
bool smoothLines = false;
- if (isLines) {
+ if (kDrawLines_DrawType == type) {
smoothLines = this->willUseHWAALines();
if (smoothLines) {
if (kYes_TriState != fHWAAState.fSmoothLineEnabled) {
@@ -1925,8 +2005,12 @@ void GrGpuGL::flushAAState(bool isLines) {
}
}
}
- if (!smoothLines && rt->isMultisampled()) {
- if (this->getDrawState().isHWAntialiasState()) {
+ if (!smoothLines && rt->isMultisampled()) {
+ // FIXME: GL_NV_pr doesn't seem to like MSAA disabled. The paths
+ // convex hulls of each segment appear to get filled.
+ bool enableMSAA = kStencilPath_DrawType == type ||
+ this->getDrawState().isHWAntialiasState();
+ if (enableMSAA) {
if (kYes_TriState != fHWAAState.fMSAAEnabled) {
GL_CALL(Enable(GR_GL_MULTISAMPLE));
fHWAAState.fMSAAEnabled = kYes_TriState;
diff --git a/src/gpu/gl/GrGpuGL.h b/src/gpu/gl/GrGpuGL.h
index 6220efafe4..2d6aa68120 100644
--- a/src/gpu/gl/GrGpuGL.h
+++ b/src/gpu/gl/GrGpuGL.h
@@ -98,7 +98,6 @@ protected:
virtual void onResolveRenderTarget(GrRenderTarget* target) SK_OVERRIDE;
-
virtual void onGpuDrawIndexed(GrPrimitiveType type,
uint32_t startVertex,
uint32_t startIndex,
@@ -107,7 +106,12 @@ protected:
virtual void onGpuDrawNonIndexed(GrPrimitiveType type,
uint32_t vertexCount,
uint32_t numVertices) SK_OVERRIDE;
- virtual void onGpuStencilPath(const GrPath&, GrPathFill) SK_OVERRIDE;
+
+ virtual void setStencilPathSettings(const GrPath&,
+ GrPathFill,
+ GrStencilSettings* settings)
+ SK_OVERRIDE;
+ virtual void onGpuStencilPath(const GrPath*, GrPathFill) SK_OVERRIDE;
virtual void clearStencil() SK_OVERRIDE;
virtual void clearStencilClip(const GrIRect& rect,
@@ -220,7 +224,7 @@ private:
void flushCoverage(GrColor color);
// sets the MVP matrix uniform for currently bound program
- void flushViewMatrix();
+ void flushViewMatrix(DrawType type);
// flushes the parameters to two point radial gradient
void flushRadial2(int stage);
@@ -268,8 +272,8 @@ private:
// bound is region that may be modified and therefore has to be resolved.
// NULL means whole target. Can be an empty rect.
void flushRenderTarget(const GrIRect* bound);
- void flushStencil();
- void flushAAState(bool isLines);
+ void flushStencil(DrawType);
+ void flushAAState(DrawType);
bool configToGLFormats(GrPixelConfig config,
bool getSizedInternal,
@@ -360,6 +364,15 @@ private:
}
} fHWAAState;
+ struct {
+ GrMatrix fViewMatrix;
+ SkISize fRTSize;
+ void invalidate() {
+ fViewMatrix = GrMatrix::InvalidMatrix();
+ fRTSize.fWidth = -1; // just make the first value compared illegal.
+ }
+ } fHWPathMatrixState;
+
GrStencilSettings fHWStencilSettings;
TriState fHWStencilTestEnabled;
diff --git a/src/gpu/gl/GrGpuGL_program.cpp b/src/gpu/gl/GrGpuGL_program.cpp
index 3ad352070a..e33f469f93 100644
--- a/src/gpu/gl/GrGpuGL_program.cpp
+++ b/src/gpu/gl/GrGpuGL_program.cpp
@@ -104,7 +104,7 @@ void GrGpuGL::abandonResources(){
#define GL_CALL(X) GR_GL_CALL(this->glInterface(), X)
-void GrGpuGL::flushViewMatrix() {
+void GrGpuGL::flushViewMatrix(DrawType type) {
const GrGLRenderTarget* rt = static_cast<const GrGLRenderTarget*>(this->getDrawState().getRenderTarget());
SkISize viewportSize;
const GrGLIRect& viewport = rt->getViewport();
@@ -112,7 +112,56 @@ void GrGpuGL::flushViewMatrix() {
const GrMatrix& vm = this->getDrawState().getViewMatrix();
- if (!fProgramData->fViewMatrix.cheapEqualTo(vm) ||
+ if (kStencilPath_DrawType == type) {
+ if (fHWPathMatrixState.fViewMatrix != vm) {
+ // We use the GL model view matrix to hold the draw state's view
+ // matrix and the GL projection matrix to convert to normalized y-up
+ // coords.
+ GrGLfloat mv[] = {
+ // col 0
+ GrScalarToFloat(vm[GrMatrix::kMScaleX]),
+ GrScalarToFloat(vm[GrMatrix::kMSkewY]),
+ 0,
+ GrScalarToFloat(vm[GrMatrix::kMPersp0]),
+
+ // col 1
+ GrScalarToFloat(vm[GrMatrix::kMSkewX]),
+ GrScalarToFloat(vm[GrMatrix::kMScaleY]),
+ 0,
+ GrScalarToFloat(vm[GrMatrix::kMPersp1]),
+
+ // col 2
+ 0, 0, 0, 0,
+
+ // col3
+ GrScalarToFloat(vm[GrMatrix::kMTransX]),
+ GrScalarToFloat(vm[GrMatrix::kMTransY]),
+ 0.5f,
+ GrScalarToFloat(vm[GrMatrix::kMPersp2])
+ };
+ GL_CALL(MatrixMode(GR_GL_MODELVIEW));
+ GL_CALL(LoadMatrixf(mv));
+ fHWPathMatrixState.fViewMatrix = vm;
+ }
+ if (fHWPathMatrixState.fRTSize != viewportSize) {
+ GrGLfloat p[] = {
+ // col 0
+ 2.f / rt->width(), 0, 0, 0,
+
+ // col 1
+ 0, -2.f / rt->height(), 0, 0,
+
+ // col 2
+ 0, 0, 1.f, 0,
+
+ // col 3
+ -1.f, 1.f, 0, 1.f,
+ };
+ GL_CALL(MatrixMode(GR_GL_PROJECTION));
+ GL_CALL(LoadMatrixf(p));
+ fHWPathMatrixState.fRTSize = viewportSize;
+ }
+ } else if (!fProgramData->fViewMatrix.cheapEqualTo(vm) ||
fProgramData->fViewportSize != viewportSize) {
GrMatrix m;
@@ -380,81 +429,79 @@ bool GrGpuGL::flushGraphicsState(DrawType type) {
// and bailed if not true.
GrAssert(NULL != drawState.getRenderTarget());
- this->flushMiscFixedFunctionState();
- this->flushStencil();
- this->flushAAState(kDrawLines_DrawType == type);
-
- GrBlendCoeff srcCoeff;
- GrBlendCoeff dstCoeff;
- BlendOptFlags blendOpts = this->getBlendOpts(false, &srcCoeff, &dstCoeff);
- if (kSkipDraw_BlendOptFlag & blendOpts) {
- return false;
- }
-
- GrCustomStage* customStages [GrDrawState::kNumStages];
- this->buildProgram(kDrawPoints_DrawType == type,
- blendOpts, dstCoeff, customStages);
- fProgramData = fProgramCache->getProgramData(fCurrentProgram,
- customStages);
- if (NULL == fProgramData) {
- GrAssert(!"Failed to create program!");
- return false;
- }
-
- if (fHWProgramID != fProgramData->fProgramID) {
- GL_CALL(UseProgram(fProgramData->fProgramID));
- fHWProgramID = fProgramData->fProgramID;
- }
- fCurrentProgram.overrideBlend(&srcCoeff, &dstCoeff);
- this->flushBlend(kDrawLines_DrawType == type, srcCoeff, dstCoeff);
-
- GrColor color;
- GrColor coverage;
- if (blendOpts & kEmitTransBlack_BlendOptFlag) {
- color = 0;
- coverage = 0;
- } else if (blendOpts & kEmitCoverage_BlendOptFlag) {
- color = 0xffffffff;
- coverage = drawState.getCoverage();
- } else {
- color = drawState.getColor();
- coverage = drawState.getCoverage();
- }
- this->flushColor(color);
- this->flushCoverage(coverage);
+ if (kStencilPath_DrawType != type) {
+ this->flushMiscFixedFunctionState();
- this->flushViewMatrix();
+ GrBlendCoeff srcCoeff;
+ GrBlendCoeff dstCoeff;
+ BlendOptFlags blendOpts = this->getBlendOpts(false, &srcCoeff, &dstCoeff);
+ if (kSkipDraw_BlendOptFlag & blendOpts) {
+ return false;
+ }
- for (int s = 0; s < GrDrawState::kNumStages; ++s) {
- if (this->isStageEnabled(s)) {
+ GrCustomStage* customStages [GrDrawState::kNumStages];
+ this->buildProgram(kDrawPoints_DrawType == type,
+ blendOpts, dstCoeff, customStages);
+ fProgramData = fProgramCache->getProgramData(fCurrentProgram,
+ customStages);
+ if (NULL == fProgramData) {
+ GrAssert(!"Failed to create program!");
+ return false;
+ }
+ if (fHWProgramID != fProgramData->fProgramID) {
+ GL_CALL(UseProgram(fProgramData->fProgramID));
+ fHWProgramID = fProgramData->fProgramID;
+ }
+ fCurrentProgram.overrideBlend(&srcCoeff, &dstCoeff);
+ this->flushBlend(kDrawLines_DrawType == type, srcCoeff, dstCoeff);
+
+ GrColor color;
+ GrColor coverage;
+ if (blendOpts & kEmitTransBlack_BlendOptFlag) {
+ color = 0;
+ coverage = 0;
+ } else if (blendOpts & kEmitCoverage_BlendOptFlag) {
+ color = 0xffffffff;
+ coverage = drawState.getCoverage();
+ } else {
+ color = drawState.getColor();
+ coverage = drawState.getCoverage();
+ }
+ this->flushColor(color);
+ this->flushCoverage(coverage);
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+ if (this->isStageEnabled(s)) {
#if GR_DEBUG
- // check for circular rendering
- GrAssert(NULL == drawState.getRenderTarget() ||
- NULL == drawState.getTexture(s) ||
- drawState.getTexture(s)->asRenderTarget() !=
- drawState.getRenderTarget());
+ // check for circular rendering
+ GrAssert(NULL == drawState.getRenderTarget() ||
+ NULL == drawState.getTexture(s) ||
+ drawState.getTexture(s)->asRenderTarget() !=
+ drawState.getRenderTarget());
#endif
-
- this->flushBoundTextureAndParams(s);
-
- this->flushTextureMatrixAndDomain(s);
-
- if (NULL != fProgramData->fCustomStage[s]) {
- const GrSamplerState& sampler =
- this->getDrawState().getSampler(s);
- const GrGLTexture* texture =
- static_cast<const GrGLTexture*>(
- this->getDrawState().getTexture(s));
- fProgramData->fCustomStage[s]->setData(
- this->glInterface(), *texture,
- *sampler.getCustomStage(), s);
+ this->flushBoundTextureAndParams(s);
+
+ this->flushTextureMatrixAndDomain(s);
+
+ if (NULL != fProgramData->fCustomStage[s]) {
+ const GrSamplerState& sampler =
+ this->getDrawState().getSampler(s);
+ const GrGLTexture* texture =
+ static_cast<const GrGLTexture*>(
+ this->getDrawState().getTexture(s));
+ fProgramData->fCustomStage[s]->setData(
+ this->glInterface(), *texture,
+ *sampler.getCustomStage(), s);
+ }
}
}
+ this->flushColorMatrix();
}
- this->flushColorMatrix();
+ this->flushStencil(type);
+ this->flushViewMatrix(type);
this->flushScissor();
+ this->flushAAState(type);
GrIRect* rect = NULL;
GrIRect clipBounds;