diff options
author | 2014-09-04 08:56:46 -0700 | |
---|---|---|
committer | 2014-09-04 08:56:46 -0700 | |
commit | bd769d0f1c8cf6ccbb2738dfad1624a4c828e4eb (patch) | |
tree | 1fb4cd896c5d63bf3eb0dddbbd7259edab8703e3 | |
parent | c5ba71d2e5cd426def66fa49dcf003e5b2c98dc7 (diff) |
Initial change to create GeometryProcessor
BUG=skia:
R=bsalomon@google.com, robertphillips@google.com, egdaniel@google.com, jvanverth@google.com
Author: joshualitt@chromium.org
Review URL: https://codereview.chromium.org/509153002
25 files changed, 409 insertions, 65 deletions
diff --git a/expectations/gm/ignored-tests.txt b/expectations/gm/ignored-tests.txt index ad56781c99..2fd0339b24 100644 --- a/expectations/gm/ignored-tests.txt +++ b/expectations/gm/ignored-tests.txt @@ -36,3 +36,6 @@ # jvanverth fontcache +# joshualitt +convex_poly_clip +bezier_cubic_effects
\ No newline at end of file diff --git a/gm/beziereffects.cpp b/gm/beziereffects.cpp index e0a1d8726e..f150b7c9df 100644 --- a/gm/beziereffects.cpp +++ b/gm/beziereffects.cpp @@ -170,7 +170,7 @@ protected: GrDrawState* drawState = tt.target()->drawState(); drawState->setVertexAttribs<kAttribs>(2, sizeof(Vertex)); - drawState->addCoverageEffect(effect, 1); + drawState->setGeometryProcessor(effect, 1); drawState->setRenderTarget(rt); drawState->setColor(0xff000000); @@ -325,7 +325,7 @@ protected: GrDrawState* drawState = tt.target()->drawState(); drawState->setVertexAttribs<kAttribs>(2, sizeof(Vertex)); - drawState->addCoverageEffect(effect, 1); + drawState->setGeometryProcessor(effect, 1); drawState->setRenderTarget(rt); drawState->setColor(0xff000000); @@ -509,7 +509,7 @@ protected: GrDrawState* drawState = tt.target()->drawState(); drawState->setVertexAttribs<kAttribs>(2, sizeof(Vertex)); - drawState->addCoverageEffect(effect, 1); + drawState->setGeometryProcessor(effect, 1); drawState->setRenderTarget(rt); drawState->setColor(0xff000000); diff --git a/src/gpu/GrAAConvexPathRenderer.cpp b/src/gpu/GrAAConvexPathRenderer.cpp index c260382dbb..e4fc6ec87d 100644 --- a/src/gpu/GrAAConvexPathRenderer.cpp +++ b/src/gpu/GrAAConvexPathRenderer.cpp @@ -678,7 +678,7 @@ bool GrAAConvexPathRenderer::onDrawPath(const SkPath& origPath, static const int kEdgeAttrIndex = 1; GrEffect* quadEffect = QuadEdgeEffect::Create(); - drawState->addCoverageEffect(quadEffect, kEdgeAttrIndex)->unref(); + drawState->setGeometryProcessor(quadEffect, kEdgeAttrIndex)->unref(); GrDrawTarget::AutoReleaseGeometry arg(target, vCount, iCount); if (!arg.succeeded()) { diff --git a/src/gpu/GrAAHairLinePathRenderer.cpp b/src/gpu/GrAAHairLinePathRenderer.cpp index 2114720f34..9986ac87f0 100644 --- a/src/gpu/GrAAHairLinePathRenderer.cpp +++ b/src/gpu/GrAAHairLinePathRenderer.cpp @@ -1002,7 +1002,7 @@ bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path, SkASSERT(NULL != hairQuadEffect); GrDrawState::AutoRestoreEffects are(drawState); target->setIndexSourceToBuffer(fQuadsIndexBuffer); - drawState->addCoverageEffect(hairQuadEffect, kEdgeAttrIndex)->unref(); + drawState->setGeometryProcessor(hairQuadEffect, kEdgeAttrIndex)->unref(); int quads = 0; while (quads < quadCnt) { int n = SkTMin(quadCnt - quads, kNumQuadsInIdxBuffer); @@ -1021,7 +1021,7 @@ bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path, GrEffect* hairConicEffect = GrConicEffect::Create(kHairlineAA_GrEffectEdgeType, *target->caps()); SkASSERT(NULL != hairConicEffect); - drawState->addCoverageEffect(hairConicEffect, 1, 2)->unref(); + drawState->setGeometryProcessor(hairConicEffect, 1, 2)->unref(); int conics = 0; while (conics < conicCnt) { int n = SkTMin(conicCnt - conics, kNumQuadsInIdxBuffer); diff --git a/src/gpu/GrAARectRenderer.cpp b/src/gpu/GrAARectRenderer.cpp index a7ddfde7cc..9384457a1e 100644 --- a/src/gpu/GrAARectRenderer.cpp +++ b/src/gpu/GrAARectRenderer.cpp @@ -648,7 +648,7 @@ void GrAARectRenderer::shaderFillAARect(GrGpu* gpu, GrEffect* effect = GrRectEffect::Create(); static const int kRectAttrIndex = 1; static const int kWidthIndex = 2; - drawState->addCoverageEffect(effect, kRectAttrIndex, kWidthIndex)->unref(); + drawState->setGeometryProcessor(effect, kRectAttrIndex, kWidthIndex)->unref(); for (int i = 0; i < 4; ++i) { verts[i].fCenter = center; @@ -697,7 +697,7 @@ void GrAARectRenderer::shaderFillAlignedAARect(GrGpu* gpu, GrEffect* effect = GrAlignedRectEffect::Create(); static const int kOffsetIndex = 1; - drawState->addCoverageEffect(effect, kOffsetIndex)->unref(); + drawState->setGeometryProcessor(effect, kOffsetIndex)->unref(); SkRect devRect; combinedMatrix.mapRect(&devRect, rect); diff --git a/src/gpu/GrBitmapTextContext.cpp b/src/gpu/GrBitmapTextContext.cpp index 6599d4ea47..ac4c078275 100755 --- a/src/gpu/GrBitmapTextContext.cpp +++ b/src/gpu/GrBitmapTextContext.cpp @@ -108,7 +108,7 @@ void GrBitmapTextContext::flushGlyphs() { // This effect could be stored with one of the cache objects (atlas?) int coordsIdx = drawState->hasColorVertexAttribute() ? kGlyphCoordsWithColorAttributeIndex : kGlyphCoordsNoColorAttributeIndex; - drawState->addCoverageEffect(fCachedEffect.get(), coordsIdx); + drawState->setGeometryProcessor(fCachedEffect.get(), coordsIdx); SkASSERT(NULL != fStrike); switch (fStrike->getMaskFormat()) { // Color bitmap text diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index 322ea87dcb..85d53119b6 100755 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -1738,7 +1738,8 @@ GrDrawTarget* GrContext::prepareToDraw(const GrPaint* paint, AutoCheckFlush* acf) { // All users of this draw state should be freeing up all effects when they're done. // Otherwise effects that own resources may keep those resources alive indefinitely. - SkASSERT(0 == fDrawState->numColorStages() && 0 == fDrawState->numCoverageStages()); + SkASSERT(0 == fDrawState->numColorStages() && 0 == fDrawState->numCoverageStages() && + !fDrawState->hasGeometryProcessor()); if (NULL == fGpu) { return NULL; diff --git a/src/gpu/GrDrawState.cpp b/src/gpu/GrDrawState.cpp index 0c2b1c3684..236d48f229 100644 --- a/src/gpu/GrDrawState.cpp +++ b/src/gpu/GrDrawState.cpp @@ -54,6 +54,9 @@ GrDrawState::GrDrawState(const GrDrawState& state, const SkMatrix& preConcatMatr SkDEBUGCODE(fBlockEffectRemovalCnt = 0;) *this = state; if (!preConcatMatrix.isIdentity()) { + if (this->hasGeometryProcessor()) { + fGeometryProcessor->localCoordChange(preConcatMatrix); + } for (int i = 0; i < this->numColorStages(); ++i) { fColorStages[i].localCoordChange(preConcatMatrix); } @@ -79,6 +82,11 @@ GrDrawState& GrDrawState::operator=(const GrDrawState& that) { fStencilSettings = that.fStencilSettings; fCoverage = that.fCoverage; fDrawFace = that.fDrawFace; + if (that.hasGeometryProcessor()) { + fGeometryProcessor.reset(SkNEW_ARGS(GrEffectStage, (*that.fGeometryProcessor.get()))); + } else { + fGeometryProcessor.reset(NULL); + } fColorStages = that.fColorStages; fCoverageStages = that.fCoverageStages; fOptSrcBlend = that.fOptSrcBlend; @@ -95,6 +103,7 @@ GrDrawState& GrDrawState::operator=(const GrDrawState& that) { void GrDrawState::onReset(const SkMatrix* initialViewMatrix) { SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages()); + fGeometryProcessor.reset(NULL); fColorStages.reset(); fCoverageStages.reset(); @@ -128,6 +137,9 @@ bool GrDrawState::setIdentityViewMatrix() { // sad trombone sound return false; } + if (this->hasGeometryProcessor()) { + fGeometryProcessor->localCoordChange(invVM); + } for (int s = 0; s < this->numColorStages(); ++s) { fColorStages[s].localCoordChange(invVM); } @@ -142,6 +154,7 @@ bool GrDrawState::setIdentityViewMatrix() { void GrDrawState::setFromPaint(const GrPaint& paint, const SkMatrix& vm, GrRenderTarget* rt) { SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages()); + fGeometryProcessor.reset(NULL); fColorStages.reset(); fCoverageStages.reset(); @@ -286,6 +299,8 @@ GrDrawState::AutoVertexAttribRestore::AutoVertexAttribRestore( void GrDrawState::AutoRestoreEffects::set(GrDrawState* ds) { if (NULL != fDrawState) { + fDrawState->fGeometryProcessor.reset(fGeometryProcessor.detach()); + int m = fDrawState->numColorStages() - fColorEffectCnt; SkASSERT(m >= 0); fDrawState->fColorStages.pop_back_n(m); @@ -300,6 +315,11 @@ void GrDrawState::AutoRestoreEffects::set(GrDrawState* ds) { } fDrawState = ds; if (NULL != ds) { + if (ds->hasGeometryProcessor()) { + fGeometryProcessor.reset(SkNEW_ARGS(GrEffectStage, (*ds->getGeometryProcessor()))); + } else { + fGeometryProcessor.reset(NULL); + } fColorEffectCnt = ds->numColorStages(); fCoverageEffectCnt = ds->numCoverageStages(); SkDEBUGCODE(++ds->fBlockEffectRemovalCnt;) @@ -429,6 +449,10 @@ void GrDrawState::AutoViewMatrixRestore::restore() { SkASSERT(fDrawState->numCoverageStages() >= numCoverageStages); int i = 0; + if (fHasGeometryProcessor) { + SkASSERT(fDrawState->hasGeometryProcessor()); + fDrawState->fGeometryProcessor->restoreCoordChange(fSavedCoordChanges[i++]); + } for (int s = 0; s < fNumColorStages; ++s, ++i) { fDrawState->fColorStages[s].restoreCoordChange(fSavedCoordChanges[i]); } @@ -471,6 +495,7 @@ bool GrDrawState::AutoViewMatrixRestore::setIdentity(GrDrawState* drawState) { if (0 == drawState->numTotalStages()) { drawState->fViewMatrix.reset(); fDrawState = drawState; + fHasGeometryProcessor = false; fNumColorStages = 0; fSavedCoordChanges.reset(0); SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;) @@ -492,6 +517,13 @@ void GrDrawState::AutoViewMatrixRestore::doEffectCoordChanges(const SkMatrix& co fSavedCoordChanges.reset(fDrawState->numTotalStages()); int i = 0; + fHasGeometryProcessor = false; + if (fDrawState->hasGeometryProcessor()) { + fDrawState->fGeometryProcessor->saveCoordChange(&fSavedCoordChanges[i++]); + fDrawState->fGeometryProcessor->localCoordChange(coordChangeMatrix); + fHasGeometryProcessor = true; + } + fNumColorStages = fDrawState->numColorStages(); for (int s = 0; s < fNumColorStages; ++s, ++i) { fDrawState->getColorStage(s).saveCoordChange(&fSavedCoordChanges[i]); @@ -543,6 +575,10 @@ bool GrDrawState::srcAlphaWillBeOne() const { } // Run through the coverage stages + if (this->hasGeometryProcessor()) { + const GrEffect* effect = fGeometryProcessor->getEffect(); + effect->getConstantColorComponents(&coverage, &coverageComponentFlags); + } for (int s = 0; s < this->numCoverageStages(); ++s) { const GrEffect* effect = this->getCoverageStage(s).getEffect(); effect->getConstantColorComponents(&coverage, &coverageComponentFlags); diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h index 00bec9f7c2..a1b07de6d6 100644 --- a/src/gpu/GrDrawState.h +++ b/src/gpu/GrDrawState.h @@ -165,6 +165,20 @@ public: /// @} + /** + * The geometry processor is the sole element of the skia pipeline which can use the vertex, + * geometry, and tesselation shaders. The GP may also compute a coverage in its fragment shader + * but is never put in the color processing pipeline. + */ + + const GrEffect* setGeometryProcessor(const GrEffect* effect, int attr0 = -1, int attr1 = -1) { + SkASSERT(NULL != effect); + SkASSERT(!this->hasGeometryProcessor()); + fGeometryProcessor.reset(new GrEffectStage(effect, attr0, attr1)); + this->invalidateBlendOptFlags(); + return effect; + } + /////////////////////////////////////////////////////////////////////////// /// @name Effect Stages /// Each stage hosts a GrEffect. The effect produces an output color or coverage in the fragment @@ -242,6 +256,7 @@ public: private: GrDrawState* fDrawState; + SkAutoTDelete<GrEffectStage> fGeometryProcessor; int fColorEffectCnt; int fCoverageEffectCnt; }; @@ -364,6 +379,7 @@ public: GrDrawState* fDrawState; SkMatrix fViewMatrix; int fNumColorStages; + bool fHasGeometryProcessor; SkAutoSTArray<8, GrEffectStage::SavedCoordChange> fSavedCoordChanges; }; diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp index 9605781d34..191194eb50 100644 --- a/src/gpu/GrDrawTarget.cpp +++ b/src/gpu/GrDrawTarget.cpp @@ -389,6 +389,15 @@ bool GrDrawTarget::checkDraw(GrPrimitiveType type, int startVertex, SkASSERT(NULL != drawState.getRenderTarget()); + if (drawState.hasGeometryProcessor()) { + const GrEffect* effect = drawState.getGeometryProcessor()->getEffect(); + int numTextures = effect->numTextures(); + for (int t = 0; t < numTextures; ++t) { + GrTexture* texture = effect->texture(t); + SkASSERT(texture->asRenderTarget() != drawState.getRenderTarget()); + } + } + for (int s = 0; s < drawState.numColorStages(); ++s) { const GrEffect* effect = drawState.getColorStage(s).getEffect(); int numTextures = effect->numTextures(); diff --git a/src/gpu/GrOvalRenderer.cpp b/src/gpu/GrOvalRenderer.cpp index f368dc8d89..330d4e9289 100644 --- a/src/gpu/GrOvalRenderer.cpp +++ b/src/gpu/GrOvalRenderer.cpp @@ -553,7 +553,7 @@ void GrOvalRenderer::drawCircle(GrDrawTarget* target, GrEffect* effect = CircleEdgeEffect::Create(isStrokeOnly && innerRadius > 0); static const int kCircleEdgeAttrIndex = 1; - drawState->addCoverageEffect(effect, kCircleEdgeAttrIndex)->unref(); + drawState->setGeometryProcessor(effect, kCircleEdgeAttrIndex)->unref(); // The radii are outset for two reasons. First, it allows the shader to simply perform // clamp(distance-to-center - radius, 0, 1). Second, the outer radius is used to compute the @@ -696,7 +696,7 @@ bool GrOvalRenderer::drawEllipse(GrDrawTarget* target, static const int kEllipseCenterAttrIndex = 1; static const int kEllipseEdgeAttrIndex = 2; - drawState->addCoverageEffect(effect, kEllipseCenterAttrIndex, kEllipseEdgeAttrIndex)->unref(); + drawState->setGeometryProcessor(effect, kEllipseCenterAttrIndex, kEllipseEdgeAttrIndex)->unref(); // Compute the reciprocals of the radii here to save time in the shader SkScalar xRadRecip = SkScalarInvert(xRadius); @@ -814,8 +814,8 @@ bool GrOvalRenderer::drawDIEllipse(GrDrawTarget* target, static const int kEllipseOuterOffsetAttrIndex = 1; static const int kEllipseInnerOffsetAttrIndex = 2; - drawState->addCoverageEffect(effect, kEllipseOuterOffsetAttrIndex, - kEllipseInnerOffsetAttrIndex)->unref(); + drawState->setGeometryProcessor(effect, kEllipseOuterOffsetAttrIndex, + kEllipseInnerOffsetAttrIndex)->unref(); // This expands the outer rect so that after CTM we end up with a half-pixel border SkScalar a = vm[SkMatrix::kMScaleX]; @@ -1063,7 +1063,7 @@ bool GrOvalRenderer::drawRRect(GrDrawTarget* target, GrContext* context, bool us GrEffect* effect = CircleEdgeEffect::Create(isStrokeOnly); static const int kCircleEdgeAttrIndex = 1; - drawState->addCoverageEffect(effect, kCircleEdgeAttrIndex)->unref(); + drawState->setGeometryProcessor(effect, kCircleEdgeAttrIndex)->unref(); // The radii are outset for two reasons. First, it allows the shader to simply perform // clamp(distance-to-center - radius, 0, 1). Second, the outer radius is used to compute the @@ -1168,8 +1168,9 @@ bool GrOvalRenderer::drawRRect(GrDrawTarget* target, GrContext* context, bool us GrEffect* effect = EllipseEdgeEffect::Create(isStrokeOnly); static const int kEllipseOffsetAttrIndex = 1; static const int kEllipseRadiiAttrIndex = 2; - drawState->addCoverageEffect(effect, - kEllipseOffsetAttrIndex, kEllipseRadiiAttrIndex)->unref(); + drawState->setGeometryProcessor(effect, + kEllipseOffsetAttrIndex, + kEllipseRadiiAttrIndex)->unref(); // Compute the reciprocals of the radii here to save time in the shader SkScalar xRadRecip = SkScalarInvert(xRadius); diff --git a/src/gpu/GrRODrawState.cpp b/src/gpu/GrRODrawState.cpp index 9118d0dc8d..f6a235517a 100644 --- a/src/gpu/GrRODrawState.cpp +++ b/src/gpu/GrRODrawState.cpp @@ -38,6 +38,18 @@ bool GrRODrawState::isEqual(const GrRODrawState& that) const { } bool explicitLocalCoords = this->hasLocalCoordAttribute(); + if (this->hasGeometryProcessor()) { + if (!that.hasGeometryProcessor()) { + return kIncompatible_CombinedState; + } else if (!GrEffectStage::AreCompatible(*this->getGeometryProcessor(), + *that.getGeometryProcessor(), + explicitLocalCoords)) { + return kIncompatible_CombinedState; + } + } else if (that.hasGeometryProcessor()) { + return kIncompatible_CombinedState; + } + for (int i = 0; i < this->numColorStages(); i++) { if (!GrEffectStage::AreCompatible(this->getColorStage(i), that.getColorStage(i), explicitLocalCoords)) { @@ -66,11 +78,9 @@ bool GrRODrawState::validateVertexAttribs() const { for (int i = 0; i < kMaxVertexAttribCnt; ++i) { slTypes[i] = static_cast<GrSLType>(-1); } - int totalStages = this->numTotalStages(); - for (int s = 0; s < totalStages; ++s) { - int covIdx = s - this->numColorStages(); - const GrEffectStage& stage = covIdx < 0 ? this->getColorStage(s) : - this->getCoverageStage(covIdx); + + if (this->hasGeometryProcessor()) { + const GrEffectStage& stage = *this->getGeometryProcessor(); const GrEffect* effect = stage.getEffect(); SkASSERT(NULL != effect); // make sure that any attribute indices have the correct binding type, that the attrib @@ -118,6 +128,10 @@ bool GrRODrawState::hasSolidCoverage() const { } // Run through the coverage stages and see if the coverage will be all ones at the end. + if (this->hasGeometryProcessor()) { + const GrEffect* effect = fGeometryProcessor->getEffect(); + effect->getConstantColorComponents(&coverage, &validComponentFlags); + } for (int s = 0; s < this->numCoverageStages(); ++s) { const GrEffect* effect = this->getCoverageStage(s).getEffect(); effect->getConstantColorComponents(&coverage, &validComponentFlags); @@ -140,6 +154,11 @@ bool GrRODrawState::willEffectReadDstColor() const { return true; } } + if (this->hasGeometryProcessor()) { + if (fGeometryProcessor->getEffect()->willReadDstColor()) { + return true; + } + } return false; } diff --git a/src/gpu/GrRODrawState.h b/src/gpu/GrRODrawState.h index 54d87bdfc8..88392ba35f 100644 --- a/src/gpu/GrRODrawState.h +++ b/src/gpu/GrRODrawState.h @@ -121,8 +121,13 @@ public: int numColorStages() const { return fColorStages.count(); } int numCoverageStages() const { return fCoverageStages.count(); } - int numTotalStages() const { return this->numColorStages() + this->numCoverageStages(); } + int numTotalStages() const { + return this->numColorStages() + this->numCoverageStages() + + (this->hasGeometryProcessor() ? 1 : 0); + } + bool hasGeometryProcessor() const { return NULL != fGeometryProcessor.get(); } + const GrEffectStage* getGeometryProcessor() const { return fGeometryProcessor.get(); } const GrEffectStage& getColorStage(int stageIdx) const { return fColorStages[stageIdx]; } const GrEffectStage& getCoverageStage(int stageIdx) const { return fCoverageStages[stageIdx]; } @@ -358,6 +363,7 @@ protected: GrBlendCoeff fDstBlend; typedef SkSTArray<4, GrEffectStage> EffectStageArray; + SkAutoTDelete<GrEffectStage> fGeometryProcessor; EffectStageArray fColorStages; EffectStageArray fCoverageStages; diff --git a/src/gpu/effects/GrDashingEffect.cpp b/src/gpu/effects/GrDashingEffect.cpp index adee4aec96..f4298eb4a0 100644 --- a/src/gpu/effects/GrDashingEffect.cpp +++ b/src/gpu/effects/GrDashingEffect.cpp @@ -345,7 +345,7 @@ bool GrDashingEffect::DrawDashLine(const SkPoint pts[2], const GrPaint& paint, bool isRoundCap = SkPaint::kRound_Cap == cap; GrDashingEffect::DashCap capType = isRoundCap ? GrDashingEffect::kRound_DashCap : GrDashingEffect::kNonRound_DashCap; - drawState->addCoverageEffect( + drawState->setGeometryProcessor( GrDashingEffect::Create(edgeType, devInfo, strokeWidth, capType), 1)->unref(); } diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp index 534e3c38a1..7b5dbb4c94 100644 --- a/src/gpu/gl/GrGLProgram.cpp +++ b/src/gpu/gl/GrGLProgram.cpp @@ -23,17 +23,19 @@ GrGLProgram* GrGLProgram::Create(GrGpuGL* gpu, const GrGLProgramDesc& desc, + const GrEffectStage* geometryProcessor, const GrEffectStage* colorStages[], const GrEffectStage* coverageStages[]) { SkAutoTDelete<GrGLProgramBuilder> builder; if (!desc.getHeader().fRequiresVertexShader && gpu->glCaps().pathRenderingSupport() && gpu->glPathRendering()->texturingMode() == GrGLPathRendering::FixedFunction_TexturingMode) { + SkASSERT(NULL == geometryProcessor); builder.reset(SkNEW_ARGS(GrGLFragmentOnlyProgramBuilder, (gpu, desc))); } else { builder.reset(SkNEW_ARGS(GrGLFullProgramBuilder, (gpu, desc))); } - if (builder->genProgram(colorStages, coverageStages)) { + if (builder->genProgram(geometryProcessor, colorStages, coverageStages)) { SkASSERT(0 != builder->getProgramID()); return SkNEW_ARGS(GrGLProgram, (gpu, desc, *builder)); } @@ -47,6 +49,7 @@ GrGLProgram::GrGLProgram(GrGpuGL* gpu, , fCoverage(GrColor_ILLEGAL) , fDstCopyTexUnit(-1) , fBuiltinUniformHandles(builder.getBuiltinUniformHandles()) + , fGeometryProcessor(SkSafeRef(builder.getGeometryProcessor())) , fColorEffects(SkRef(builder.getColorEffects())) , fCoverageEffects(SkRef(builder.getCoverageEffects())) , fProgramID(builder.getProgramID()) @@ -97,6 +100,9 @@ void GrGLProgram::initSamplerUniforms() { fProgramDataManager.setSampler(fBuiltinUniformHandles.fDstCopySamplerUni, texUnitIdx); fDstCopyTexUnit = texUnitIdx++; } + if (NULL != fGeometryProcessor.get()) { + fGeometryProcessor->initSamplers(fProgramDataManager, &texUnitIdx); + } fColorEffects->initSamplers(fProgramDataManager, &texUnitIdx); fCoverageEffects->initSamplers(fProgramDataManager, &texUnitIdx); } @@ -105,6 +111,7 @@ void GrGLProgram::initSamplerUniforms() { void GrGLProgram::setData(GrGpu::DrawType drawType, GrDrawState::BlendOptFlags blendOpts, + const GrEffectStage* geometryProcessor, const GrEffectStage* colorStages[], const GrEffectStage* coverageStages[], const GrDeviceCoordTexture* dstCopy, @@ -149,6 +156,10 @@ void GrGLProgram::setData(GrGpu::DrawType drawType, SkASSERT(!fBuiltinUniformHandles.fDstCopySamplerUni.isValid()); } + if (NULL != fGeometryProcessor.get()) { + SkASSERT(NULL != geometryProcessor); + fGeometryProcessor->setData(fGpu, drawType,fProgramDataManager, geometryProcessor); + } fColorEffects->setData(fGpu, drawType,fProgramDataManager, colorStages); fCoverageEffects->setData(fGpu, drawType,fProgramDataManager, coverageStages); diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h index 5b9deb9f91..0f89e07b0d 100644 --- a/src/gpu/gl/GrGLProgram.h +++ b/src/gpu/gl/GrGLProgram.h @@ -41,6 +41,7 @@ public: static GrGLProgram* Create(GrGpuGL* gpu, const GrGLProgramDesc& desc, + const GrEffectStage* geometryProcessor, const GrEffectStage* colorStages[], const GrEffectStage* coverageStages[]); @@ -158,6 +159,7 @@ public: */ void setData(GrGpu::DrawType, GrDrawState::BlendOptFlags, + const GrEffectStage* geometryProcessor, const GrEffectStage* colorStages[], const GrEffectStage* coverageStages[], const GrDeviceCoordTexture* dstCopy, // can be NULL @@ -191,6 +193,7 @@ private: int fDstCopyTexUnit; BuiltinUniformHandles fBuiltinUniformHandles; + SkAutoTUnref<GrGLProgramEffects> fGeometryProcessor; SkAutoTUnref<GrGLProgramEffects> fColorEffects; SkAutoTUnref<GrGLProgramEffects> fCoverageEffects; GrGLuint fProgramID; diff --git a/src/gpu/gl/GrGLProgramDesc.cpp b/src/gpu/gl/GrGLProgramDesc.cpp index 545ed2114c..8d0ea3d6b3 100644 --- a/src/gpu/gl/GrGLProgramDesc.cpp +++ b/src/gpu/gl/GrGLProgramDesc.cpp @@ -53,6 +53,7 @@ bool GrGLProgramDesc::Build(const GrDrawState& drawState, GrBlendCoeff dstCoeff, const GrGpuGL* gpu, const GrDeviceCoordTexture* dstCopy, + const GrEffectStage** geometryProcessor, SkTArray<const GrEffectStage*, true>* colorStages, SkTArray<const GrEffectStage*, true>* coverageStages, GrGLProgramDesc* desc) { @@ -69,6 +70,7 @@ bool GrGLProgramDesc::Build(const GrDrawState& drawState, int firstEffectiveColorStage = 0; bool inputColorIsUsed = true; + if (!skipColor) { firstEffectiveColorStage = drawState.numColorStages(); while (firstEffectiveColorStage > 0 && inputColorIsUsed) { @@ -107,6 +109,9 @@ bool GrGLProgramDesc::Build(const GrDrawState& drawState, bool requiresVertexShader = !GrGpu::IsPathRenderingDrawType(drawType); int numStages = 0; + if (drawState.hasGeometryProcessor()) { + numStages++; + } if (!skipColor) { numStages += drawState.numColorStages() - firstEffectiveColorStage; } @@ -120,12 +125,42 @@ bool GrGLProgramDesc::Build(const GrDrawState& drawState, int offsetAndSizeIndex = 0; bool effectKeySuccess = true; + + KeyHeader* header = desc->header(); + // make sure any padding in the header is zeroed. + memset(desc->header(), 0, kHeaderSize); + + // We can only have one effect which touches the vertex shader + if (drawState.hasGeometryProcessor()) { + uint16_t* offsetAndSize = + reinterpret_cast<uint16_t*>(desc->fKey.begin() + kEffectKeyOffsetsAndLengthOffset + + offsetAndSizeIndex * 2 * sizeof(uint16_t)); + + GrEffectKeyBuilder b(&desc->fKey); + uint16_t effectKeySize; + uint32_t effectOffset = desc->fKey.count(); + effectKeySuccess |= GetEffectKeyAndUpdateStats( + *drawState.getGeometryProcessor(), gpu->glCaps(), + requiresLocalCoordAttrib, &b, + &effectKeySize, &readsDst, + &readFragPosition, &requiresVertexShader); + effectKeySuccess |= (effectOffset <= SK_MaxU16); + + offsetAndSize[0] = SkToU16(effectOffset); + offsetAndSize[1] = effectKeySize; + ++offsetAndSizeIndex; + *geometryProcessor = drawState.getGeometryProcessor(); + SkASSERT(requiresVertexShader); + header->fHasGeometryProcessor = true; + } + if (!skipColor) { for (int s = firstEffectiveColorStage; s < drawState.numColorStages(); ++s) { uint16_t* offsetAndSize = reinterpret_cast<uint16_t*>(desc->fKey.begin() + kEffectKeyOffsetsAndLengthOffset + offsetAndSizeIndex * 2 * sizeof(uint16_t)); + bool effectRequiresVertexShader = false; GrEffectKeyBuilder b(&desc->fKey); uint16_t effectKeySize; uint32_t effectOffset = desc->fKey.count(); @@ -133,12 +168,13 @@ bool GrGLProgramDesc::Build(const GrDrawState& drawState, drawState.getColorStage(s), gpu->glCaps(), requiresLocalCoordAttrib, &b, &effectKeySize, &readsDst, - &readFragPosition, &requiresVertexShader); + &readFragPosition, &effectRequiresVertexShader); effectKeySuccess |= (effectOffset <= SK_MaxU16); offsetAndSize[0] = SkToU16(effectOffset); offsetAndSize[1] = effectKeySize; ++offsetAndSizeIndex; + SkASSERT(!effectRequiresVertexShader); } } if (!skipCoverage) { @@ -147,6 +183,7 @@ bool GrGLProgramDesc::Build(const GrDrawState& drawState, reinterpret_cast<uint16_t*>(desc->fKey.begin() + kEffectKeyOffsetsAndLengthOffset + offsetAndSizeIndex * 2 * sizeof(uint16_t)); + bool effectRequiresVertexShader = false; GrEffectKeyBuilder b(&desc->fKey); uint16_t effectKeySize; uint32_t effectOffset = desc->fKey.count(); @@ -154,12 +191,13 @@ bool GrGLProgramDesc::Build(const GrDrawState& drawState, drawState.getCoverageStage(s), gpu->glCaps(), requiresLocalCoordAttrib, &b, &effectKeySize, &readsDst, - &readFragPosition, &requiresVertexShader); + &readFragPosition, &effectRequiresVertexShader); effectKeySuccess |= (effectOffset <= SK_MaxU16); offsetAndSize[0] = SkToU16(effectOffset); offsetAndSize[1] = effectKeySize; ++offsetAndSizeIndex; + SkASSERT(!effectRequiresVertexShader); } } if (!effectKeySuccess) { @@ -167,10 +205,6 @@ bool GrGLProgramDesc::Build(const GrDrawState& drawState, return false; } - KeyHeader* header = desc->header(); - // make sure any padding in the header is zeroed. - memset(desc->header(), 0, kHeaderSize); - // Because header is a pointer into the dynamic array, we can't push any new data into the key // below here. @@ -259,9 +293,11 @@ bool GrGLProgramDesc::Build(const GrDrawState& drawState, header->fCoverageOutput = kModulate_CoverageOutput; // If we do have coverage determine whether it matters. - bool separateCoverageFromColor = false; + bool separateCoverageFromColor = drawState.hasGeometryProcessor(); if (!drawState.isCoverageDrawing() && !skipCoverage && - (drawState.numCoverageStages() > 0 || requiresCoverageAttrib)) { + (drawState.numCoverageStages() > 0 || + drawState.hasGeometryProcessor() || + requiresCoverageAttrib)) { if (gpu->caps()->dualSourceBlendingSupport() && !(blendOpts & (GrDrawState::kEmitCoverage_BlendOptFlag | @@ -286,6 +322,7 @@ bool GrGLProgramDesc::Build(const GrDrawState& drawState, separateCoverageFromColor = true; } } + if (!skipColor) { for (int s = firstEffectiveColorStage; s < drawState.numColorStages(); ++s) { colorStages->push_back(&drawState.getColorStage(s)); diff --git a/src/gpu/gl/GrGLProgramDesc.h b/src/gpu/gl/GrGLProgramDesc.h index aefcb508e2..b1f54b7e29 100644 --- a/src/gpu/gl/GrGLProgramDesc.h +++ b/src/gpu/gl/GrGLProgramDesc.h @@ -48,6 +48,7 @@ public: const GrGpuGL* gpu, const GrRenderTarget* dummyDstRenderTarget, const GrTexture* dummyDstCopyTexture, + const GrEffectStage* geometryProcessor, const GrEffectStage* stages[], int numColorStages, int numCoverageStages, @@ -67,10 +68,15 @@ public: GrBlendCoeff dstCoeff, const GrGpuGL* gpu, const GrDeviceCoordTexture* dstCopy, + const GrEffectStage** outGeometryProcessor, SkTArray<const GrEffectStage*, true>* outColorStages, SkTArray<const GrEffectStage*, true>* outCoverageStages, GrGLProgramDesc* outDesc); + bool hasGeometryProcessor() const { + return SkToBool(this->getHeader().fHasGeometryProcessor); + } + int numColorEffects() const { return this->getHeader().fColorEffectCnt; } @@ -161,6 +167,7 @@ private: int8_t fColorAttributeIndex; int8_t fCoverageAttributeIndex; + SkBool8 fHasGeometryProcessor; int8_t fColorEffectCnt; int8_t fCoverageEffectCnt; }; @@ -213,13 +220,24 @@ private: class EffectKeyProvider { public: enum EffectType { + kGeometryProcessor_EffectType, kColor_EffectType, kCoverage_EffectType, }; EffectKeyProvider(const GrGLProgramDesc* desc, EffectType type) : fDesc(desc) { - // Coverage effect key offsets begin immediately after those of the color effects. - fBaseIndex = kColor_EffectType == type ? 0 : desc->numColorEffects(); + switch (type) { + case kGeometryProcessor_EffectType: + // there can be only one + fBaseIndex = 0; + break; + case kColor_EffectType: + fBaseIndex = desc->hasGeometryProcessor() ? 1 : 0; + break; + case kCoverage_EffectType: + fBaseIndex = desc->numColorEffects() + (desc->hasGeometryProcessor() ? 1 : 0); + break; + } } GrEffectKey get(int index) const { diff --git a/src/gpu/gl/GrGLProgramEffects.cpp b/src/gpu/gl/GrGLProgramEffects.cpp index 8d97b42329..45edca8106 100644 --- a/src/gpu/gl/GrGLProgramEffects.cpp +++ b/src/gpu/gl/GrGLProgramEffects.cpp @@ -387,6 +387,24 @@ void GrGLVertexProgramEffects::setData(GrGpuGL* gpu, } } +void GrGLVertexProgramEffects::setData(GrGpuGL* gpu, + GrGpu::DrawType drawType, + const GrGLProgramDataManager& programDataManager, + const GrEffectStage* effectStage) { + SkASSERT(1 == fTransforms.count()); + SkASSERT(1 == fSamplers.count()); + SkASSERT(1 == fGLEffects.count()); + GrDrawEffect drawEffect(*effectStage, fHasExplicitLocalCoords); + fGLEffects[0]->setData(programDataManager, drawEffect); + if (GrGpu::IsPathRenderingDrawType(drawType)) { + this->setPathTransformData(gpu, programDataManager, drawEffect, 0); + } else { + this->setTransformData(gpu, programDataManager, drawEffect, 0); + } + + this->bindTextures(gpu, drawEffect.effect(), 0); +} + void GrGLVertexProgramEffects::setTransformData(GrGpuGL* gpu, const GrGLProgramDataManager& pdman, const GrDrawEffect& drawEffect, diff --git a/src/gpu/gl/GrGLProgramEffects.h b/src/gpu/gl/GrGLProgramEffects.h index 0eaff53b76..daaebd6b37 100644 --- a/src/gpu/gl/GrGLProgramEffects.h +++ b/src/gpu/gl/GrGLProgramEffects.h @@ -57,6 +57,11 @@ public: const GrGLProgramDataManager&, const GrEffectStage* effectStages[]) = 0; + virtual void setData(GrGpuGL*, + GrGpu::DrawType, + const GrGLProgramDataManager&, + const GrEffectStage* effectStages) { SkFAIL("DO NOT USE"); } + void addEffect(GrGLEffect* effect) { fGLEffects.push_back(effect); } /** @@ -140,7 +145,6 @@ protected: SkTArray<SkSTArray<4, Sampler, true> > fSamplers; private: - friend class GrGLFragmentO; typedef SkRefCnt INHERITED; }; @@ -172,6 +176,11 @@ public: const GrGLProgramDataManager&, const GrEffectStage* effectStages[]) SK_OVERRIDE; + virtual void setData(GrGpuGL*, + GrGpu::DrawType, + const GrGLProgramDataManager&, + const GrEffectStage* effectStages) SK_OVERRIDE; + private: friend class GrGLFullProgramBuilder; diff --git a/src/gpu/gl/GrGpuGL.h b/src/gpu/gl/GrGpuGL.h index 1f748bb826..004ce254bf 100644 --- a/src/gpu/gl/GrGpuGL.h +++ b/src/gpu/gl/GrGpuGL.h @@ -179,6 +179,7 @@ private: void abandon(); GrGLProgram* getProgram(const GrGLProgramDesc& desc, + const GrEffectStage* geometryProcessor, const GrEffectStage* colorStages[], const GrEffectStage* coverageStages[]); diff --git a/src/gpu/gl/GrGpuGL_program.cpp b/src/gpu/gl/GrGpuGL_program.cpp index 8cdceb86af..67c0cd3a47 100644 --- a/src/gpu/gl/GrGpuGL_program.cpp +++ b/src/gpu/gl/GrGpuGL_program.cpp @@ -90,6 +90,7 @@ int GrGpuGL::ProgramCache::search(const GrGLProgramDesc& desc) const { } GrGLProgram* GrGpuGL::ProgramCache::getProgram(const GrGLProgramDesc& desc, + const GrEffectStage* geometryProcessor, const GrEffectStage* colorStages[], const GrEffectStage* coverageStages[]) { #ifdef PROGRAM_CACHE_STATS @@ -126,7 +127,8 @@ GrGLProgram* GrGpuGL::ProgramCache::getProgram(const GrGLProgramDesc& desc, #ifdef PROGRAM_CACHE_STATS ++fCacheMisses; #endif - GrGLProgram* program = GrGLProgram::Create(fGpu, desc, colorStages, coverageStages); + GrGLProgram* program = GrGLProgram::Create(fGpu, desc, geometryProcessor, + colorStages, coverageStages); if (NULL == program) { return NULL; } @@ -222,6 +224,7 @@ bool GrGpuGL::flushGraphicsState(DrawType type, const GrDeviceCoordTexture* dstC return false; } + const GrEffectStage* geometryProcessor = NULL; SkSTArray<8, const GrEffectStage*, true> colorStages; SkSTArray<8, const GrEffectStage*, true> coverageStages; GrGLProgramDesc desc; @@ -232,6 +235,7 @@ bool GrGpuGL::flushGraphicsState(DrawType type, const GrDeviceCoordTexture* dstC dstCoeff, this, dstCopy, + &geometryProcessor, &colorStages, &coverageStages, &desc)) { @@ -240,6 +244,7 @@ bool GrGpuGL::flushGraphicsState(DrawType type, const GrDeviceCoordTexture* dstC } fCurrentProgram.reset(fProgramCache->getProgram(desc, + geometryProcessor, colorStages.begin(), coverageStages.begin())); if (NULL == fCurrentProgram.get()) { @@ -260,6 +265,7 @@ bool GrGpuGL::flushGraphicsState(DrawType type, const GrDeviceCoordTexture* dstC fCurrentProgram->setData(type, blendOpts, + geometryProcessor, colorStages.begin(), coverageStages.begin(), dstCopy, diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp index 7664bab90f..ab64e28a78 100644 --- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp +++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp @@ -31,7 +31,8 @@ static const GrGLShaderVar::Precision kDefaultFragmentPrecision = GrGLShaderVar: /////////////////////////////////////////////////////////////////////////////////////////////////// -bool GrGLProgramBuilder::genProgram(const GrEffectStage* colorStages[], +bool GrGLProgramBuilder::genProgram(const GrEffectStage* geometryProcessor, + const GrEffectStage* colorStages[], const GrEffectStage* coverageStages[]) { const GrGLProgramDesc::KeyHeader& header = this->desc().getHeader(); @@ -79,6 +80,8 @@ bool GrGLProgramBuilder::genProgram(const GrEffectStage* colorStages[], colorKeyProvider, &inputColor)); + this->emitGeometryProcessor(geometryProcessor, &inputCoverage); + GrGLProgramDesc::EffectKeyProvider coverageKeyProvider( &this->desc(), GrGLProgramDesc::EffectKeyProvider::kCoverage_EffectType); fCoverageEffects.reset(this->createAndEmitEffects(coverageStages, @@ -334,10 +337,23 @@ GrGLFullProgramBuilder::GrGLFullProgramBuilder(GrGpuGL* gpu, , fVS(this) { } -void GrGLFullProgramBuilder::emitCodeBeforeEffects(GrGLSLExpr4* color, GrGLSLExpr4* coverage) { +void GrGLFullProgramBuilder::emitCodeBeforeEffects(GrGLSLExpr4* color, + GrGLSLExpr4* coverage) { fVS.emitCodeBeforeEffects(color, coverage); } +void GrGLFullProgramBuilder::emitGeometryProcessor(const GrEffectStage* geometryProcessor, + GrGLSLExpr4* coverage) { + if (NULL != geometryProcessor) { + GrGLProgramDesc::EffectKeyProvider geometryProcessorKeyProvider( + &this->desc(), GrGLProgramDesc::EffectKeyProvider::kGeometryProcessor_EffectType); + fGeometryProcessor.reset(this->createAndEmitEffect( + geometryProcessor, + geometryProcessorKeyProvider, + coverage)); + } +} + void GrGLFullProgramBuilder::emitCodeAfterEffects() { fVS.emitCodeAfterEffects(); } @@ -388,6 +404,56 @@ GrGLProgramEffects* GrGLFullProgramBuilder::createAndEmitEffects( return programEffectsBuilder.finish(); } +void GrGLFullProgramBuilder::createAndEmitEffect(GrGLProgramEffectsBuilder* programEffectsBuilder, + const GrEffectStage* effectStages, + const GrGLProgramDesc::EffectKeyProvider& keyProvider, + GrGLSLExpr4* fsInOutColor) { + GrGLSLExpr4 inColor = *fsInOutColor; + GrGLSLExpr4 outColor; + + SkASSERT(NULL != effectStages && NULL != effectStages->getEffect()); + const GrEffectStage& stage = *effectStages; + + // Using scope to force ASR destructor to be triggered + { + CodeStage::AutoStageRestore csar(&fCodeStage, &stage); + + if (inColor.isZeros()) { + SkString inColorName; + + // Effects have no way to communicate zeros, they treat an empty string as ones. + this->nameVariable(&inColorName, '\0', "input"); + fFS.codeAppendf("vec4 %s = %s;", inColorName.c_str(), inColor.c_str()); + inColor = inColorName; + } + + // create var to hold stage result + SkString outColorName; + this->nameVariable(&outColorName, '\0', "output"); + fFS.codeAppendf("vec4 %s;", outColorName.c_str()); + outColor = outColorName; + + + programEffectsBuilder->emitEffect(stage, + keyProvider.get(0), + outColor.c_str(), + inColor.isOnes() ? NULL : inColor.c_str(), + fCodeStage.stageIndex()); + } + + *fsInOutColor = outColor; +} + +GrGLProgramEffects* GrGLFullProgramBuilder::createAndEmitEffect( + const GrEffectStage* geometryProcessor, + const GrGLProgramDesc::EffectKeyProvider& keyProvider, + GrGLSLExpr4* inOutFSColor) { + + GrGLVertexProgramEffectsBuilder programEffectsBuilder(this, 1); + this->createAndEmitEffect(&programEffectsBuilder, geometryProcessor, keyProvider, inOutFSColor); + return programEffectsBuilder.finish(); +} + bool GrGLFullProgramBuilder::compileAndAttachShaders(GrGLuint programId, SkTDArray<GrGLuint>* shaderIds) const { return INHERITED::compileAndAttachShaders(programId, shaderIds) diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.h b/src/gpu/gl/builders/GrGLProgramBuilder.h index 00193efc45..deb3708bd1 100644 --- a/src/gpu/gl/builders/GrGLProgramBuilder.h +++ b/src/gpu/gl/builders/GrGLProgramBuilder.h @@ -84,11 +84,14 @@ public: * to be used. * @return true if generation was successful. */ - bool genProgram(const GrEffectStage* inColorStages[], - const GrEffectStage* inCoverageStages[]); - // Below are the results of the shader generation. + bool genProgram(const GrEffectStage* inGeometryProcessor, + const GrEffectStage* inColorStages[], + const GrEffectStage* inCoverageStages[]); + GrGLProgramEffects* getGeometryProcessor() const { + SkASSERT(fProgramID); return fGeometryProcessor.get(); + } GrGLProgramEffects* getColorEffects() const { SkASSERT(fProgramID); return fColorEffects.get(); } GrGLProgramEffects* getCoverageEffects() const { SkASSERT(fProgramID); return fCoverageEffects.get(); } const BuiltinUniformHandles& getBuiltinUniformHandles() const { @@ -165,6 +168,7 @@ protected: void appendDecls(const VarArray&, SkString*) const; void appendUniformDecls(ShaderVisibility, SkString*) const; + SkAutoTUnref<GrGLProgramEffects> fGeometryProcessor; SkAutoTUnref<GrGLProgramEffects> fColorEffects; SkAutoTUnref<GrGLProgramEffects> fCoverageEffects; BuiltinUniformHandles fUniformHandles; @@ -173,7 +177,7 @@ protected: GrGLuint fProgramID; GrGLFragmentShaderBuilder fFS; SeparableVaryingInfoArray fSeparableVaryingInfos; -private: + class CodeStage : SkNoncopyable { public: CodeStage() : fNextIndex(0), fCurrentIndex(-1), fEffectStage(NULL) {} @@ -224,6 +228,7 @@ private: int fCurrentIndex; const GrEffectStage* fEffectStage; } fCodeStage; +private: /** * The base class will emit the fragment code that precedes the per-effect code and then call @@ -232,7 +237,14 @@ private: * * The subclass can modify the initial color or coverage */ - virtual void emitCodeBeforeEffects(GrGLSLExpr4* color, GrGLSLExpr4* coverage) = 0; + virtual void emitCodeBeforeEffects(GrGLSLExpr4* color, + GrGLSLExpr4* coverage) = 0; + + /* + * Full shader builder needs to emit code after the color stages and before the coverage stages + */ + virtual void emitGeometryProcessor(const GrEffectStage* geometryProcessor, + GrGLSLExpr4* coverage) = 0; /** * Adds code for effects and returns a GrGLProgramEffects* object. The caller is responsible for @@ -297,13 +309,30 @@ public: GrGLVertexShaderBuilder* getVertexShaderBuilder() { return &fVS; } private: - virtual void emitCodeBeforeEffects(GrGLSLExpr4* color, GrGLSLExpr4* coverage) SK_OVERRIDE; + virtual void emitCodeBeforeEffects(GrGLSLExpr4* color, + GrGLSLExpr4* coverage) SK_OVERRIDE; + + virtual void emitGeometryProcessor(const GrEffectStage* geometryProcessor, + GrGLSLExpr4* coverage) SK_OVERRIDE; virtual GrGLProgramEffects* createAndEmitEffects(const GrEffectStage* effectStages[], int effectCnt, const GrGLProgramDesc::EffectKeyProvider&, GrGLSLExpr4* inOutFSColor) SK_OVERRIDE; + /* + * These functions are temporary and will eventually operate not on effects but on + * geometry processors + */ + void createAndEmitEffect(GrGLProgramEffectsBuilder*, + const GrEffectStage* effectStage, + const GrGLProgramDesc::EffectKeyProvider&, + GrGLSLExpr4* inOutFSColor); + + GrGLProgramEffects* createAndEmitEffect(const GrEffectStage* geometryProcessor, + const GrGLProgramDesc::EffectKeyProvider&, + GrGLSLExpr4* inOutFSColor); + virtual void emitCodeAfterEffects() SK_OVERRIDE; virtual bool compileAndAttachShaders(GrGLuint programId, @@ -326,7 +355,13 @@ public: int addTexCoordSets(int count); private: - virtual void emitCodeBeforeEffects(GrGLSLExpr4* color, GrGLSLExpr4* coverage) SK_OVERRIDE {} + virtual void emitCodeBeforeEffects(GrGLSLExpr4* color, + GrGLSLExpr4* coverage) SK_OVERRIDE {} + + virtual void emitGeometryProcessor(const GrEffectStage* geometryProcessor, + GrGLSLExpr4* coverage) SK_OVERRIDE { + SkASSERT(NULL == geometryProcessor); + } virtual GrGLProgramEffects* createAndEmitEffects(const GrEffectStage* effectStages[], int effectCnt, diff --git a/tests/GLProgramsTest.cpp b/tests/GLProgramsTest.cpp index af280466ae..6efd7d5b5b 100644 --- a/tests/GLProgramsTest.cpp +++ b/tests/GLProgramsTest.cpp @@ -26,6 +26,7 @@ bool GrGLProgramDesc::setRandom(SkRandom* random, const GrGpuGL* gpu, const GrRenderTarget* dstRenderTarget, const GrTexture* dstCopyTexture, + const GrEffectStage* geometryProcessor, const GrEffectStage* stages[], int numColorStages, int numCoverageStages, @@ -38,24 +39,50 @@ bool GrGLProgramDesc::setRandom(SkRandom* random, GR_STATIC_ASSERT(0 == kEffectKeyOffsetsAndLengthOffset % sizeof(uint32_t)); // Make room for everything up to and including the array of offsets to effect keys. - fKey.push_back_n(kEffectKeyOffsetsAndLengthOffset + 2 * sizeof(uint16_t) * numStages); + fKey.push_back_n(kEffectKeyOffsetsAndLengthOffset + 2 * sizeof(uint16_t) * (numStages + + (geometryProcessor ? 1 : 0))); bool dstRead = false; bool fragPos = false; - bool vertexShader = false; - for (int s = 0; s < numStages; ++s) { + bool vertexShader = (NULL != geometryProcessor); + int offset = 0; + if (NULL != geometryProcessor) { + const GrEffectStage* stage = geometryProcessor; uint16_t* offsetAndSize = reinterpret_cast<uint16_t*>(fKey.begin() + kEffectKeyOffsetsAndLengthOffset + - s * 2 * sizeof(uint16_t)); + offset * 2 * sizeof(uint16_t)); uint32_t effectKeyOffset = fKey.count(); if (effectKeyOffset > SK_MaxU16) { fKey.reset(); return false; } - GrDrawEffect drawEffect(*stages[s], useLocalCoords); + GrDrawEffect drawEffect(*stage, useLocalCoords); GrEffectKeyBuilder b(&fKey); uint16_t effectKeySize; - if (!GetEffectKeyAndUpdateStats(*stages[s], gpu->glCaps(), useLocalCoords, &b, + if (!GetEffectKeyAndUpdateStats(*stage, gpu->glCaps(), useLocalCoords, &b, + &effectKeySize, &dstRead, &fragPos, &vertexShader)) { + fKey.reset(); + return false; + } + offsetAndSize[0] = effectKeyOffset; + offsetAndSize[1] = effectKeySize; + offset++; + } + + for (int s = 0; s < numStages; ++s, ++offset) { + const GrEffectStage* stage = stages[s]; + uint16_t* offsetAndSize = reinterpret_cast<uint16_t*>(fKey.begin() + + kEffectKeyOffsetsAndLengthOffset + + offset * 2 * sizeof(uint16_t)); + uint32_t effectKeyOffset = fKey.count(); + if (effectKeyOffset > SK_MaxU16) { + fKey.reset(); + return false; + } + GrDrawEffect drawEffect(*stage, useLocalCoords); + GrEffectKeyBuilder b(&fKey); + uint16_t effectKeySize; + if (!GetEffectKeyAndUpdateStats(*stage, gpu->glCaps(), useLocalCoords, &b, &effectKeySize, &dstRead, &fragPos, &vertexShader)) { fKey.reset(); return false; @@ -118,6 +145,7 @@ bool GrGLProgramDesc::setRandom(SkRandom* random, useLocalCoords || kAttribute_ColorInput == header->fColorInput || kAttribute_ColorInput == header->fCoverageInput; + header->fHasGeometryProcessor = vertexShader; CoverageOutput coverageOutput; bool illegalCoverageOutput; @@ -179,8 +207,35 @@ bool GrGpuGL::programUnitTest(int maxStages) { SkAutoSTMalloc<8, const GrEffectStage*> stages(numStages); bool useFixedFunctionPathRendering = this->glCaps().pathRenderingSupport() && - this->glPathRendering()->texturingMode() == GrGLPathRendering::FixedFunction_TexturingMode; + this->glPathRendering()->texturingMode() == GrGLPathRendering::FixedFunction_TexturingMode && + random.nextBool(); + + SkAutoTDelete<GrEffectStage> geometryProcessor; + bool hasGeometryProcessor = useFixedFunctionPathRendering ? false : random.nextBool(); + if (hasGeometryProcessor) { + while (true) { + SkAutoTUnref<const GrEffect> effect(GrEffectTestFactory::CreateStage( + &random, + this->getContext(), + *this->caps(), + dummyTextures)); + SkASSERT(effect); + + // Only geometryProcessor can use vertex shader + if (!effect->requiresVertexShader()) { + continue; + } + int numAttribs = effect->numVertexAttribs(); + for (int i = 0; i < numAttribs; ++i) { + attribIndices[i] = currAttribIndex++; + } + GrEffectStage* stage = SkNEW_ARGS(GrEffectStage, + (effect.get(), attribIndices[0], attribIndices[1])); + geometryProcessor.reset(stage); + break; + } + } for (int s = 0; s < numStages;) { SkAutoTUnref<const GrEffect> effect(GrEffectTestFactory::CreateStage( &random, @@ -188,32 +243,24 @@ bool GrGpuGL::programUnitTest(int maxStages) { *this->caps(), dummyTextures)); SkASSERT(effect); - int numAttribs = effect->numVertexAttribs(); - // If adding this effect would exceed the max attrib count then generate a - // new random effect. - if (currAttribIndex + numAttribs > GrDrawState::kMaxVertexAttribCnt) { + // Only geometryProcessor can use vertex shader + if (effect->requiresVertexShader()) { continue; } - // If adding this effect would exceed the max texture coord set count then generate a // new random effect. - if (useFixedFunctionPathRendering && !effect->requiresVertexShader()) { + if (useFixedFunctionPathRendering) { int numTransforms = effect->numTransforms(); if (currTextureCoordSet + numTransforms > this->glCaps().maxFixedFunctionTextureCoords()) { continue; } currTextureCoordSet += numTransforms; } - - useFixedFunctionPathRendering = useFixedFunctionPathRendering && !effect->requiresVertexShader(); - - for (int i = 0; i < numAttribs; ++i) { - attribIndices[i] = currAttribIndex++; - } GrEffectStage* stage = SkNEW_ARGS(GrEffectStage, (effect.get(), attribIndices[0], attribIndices[1])); + stages[s] = stage; ++s; } @@ -222,6 +269,7 @@ bool GrGpuGL::programUnitTest(int maxStages) { this, dummyTextures[0]->asRenderTarget(), dstTexture, + geometryProcessor.get(), stages.get(), numColorStages, numCoverageStages, @@ -231,6 +279,7 @@ bool GrGpuGL::programUnitTest(int maxStages) { SkAutoTUnref<GrGLProgram> program(GrGLProgram::Create(this, pdesc, + geometryProcessor.get(), stages, stages + numColorStages)); for (int s = 0; s < numStages; ++s) { |