diff options
-rw-r--r-- | gyp/gpu.gypi | 8 | ||||
-rw-r--r-- | include/core/SkTArray.h | 17 | ||||
-rw-r--r-- | include/gpu/GrBackendEffectFactory.h | 3 | ||||
-rw-r--r-- | include/gpu/GrEffect.h | 27 | ||||
-rw-r--r-- | include/gpu/GrEffectStage.h | 25 | ||||
-rw-r--r-- | include/gpu/GrTBackendEffectFactory.h | 7 | ||||
-rw-r--r-- | include/gpu/GrTypesPriv.h | 27 | ||||
-rw-r--r-- | src/gpu/GrContext.cpp | 19 | ||||
-rw-r--r-- | src/gpu/GrDrawState.cpp | 79 | ||||
-rw-r--r-- | src/gpu/GrDrawState.h | 29 | ||||
-rw-r--r-- | src/gpu/GrDrawTarget.cpp | 2 | ||||
-rw-r--r-- | src/gpu/GrEffect.cpp | 5 | ||||
-rw-r--r-- | src/gpu/GrSWMaskHelper.cpp | 3 | ||||
-rw-r--r-- | src/gpu/GrTextContext.cpp | 3 | ||||
-rw-r--r-- | src/gpu/effects/GrEllipseEdgeEffect.cpp | 80 | ||||
-rw-r--r-- | src/gpu/effects/GrEllipseEdgeEffect.h | 50 | ||||
-rw-r--r-- | src/gpu/gl/GrGLEffect.cpp | 15 | ||||
-rw-r--r-- | src/gpu/gl/GrGLEffect.h | 1 | ||||
-rw-r--r-- | src/gpu/gl/GrGLProgram.cpp | 35 | ||||
-rw-r--r-- | src/gpu/gl/GrGLSL.h | 17 | ||||
-rw-r--r-- | src/gpu/gl/GrGLShaderBuilder.cpp | 41 | ||||
-rw-r--r-- | src/gpu/gl/GrGLShaderBuilder.h | 21 | ||||
-rw-r--r-- | tests/GLProgramsTest.cpp | 7 |
23 files changed, 446 insertions, 75 deletions
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi index 41f0f09ee2..d9b4b22e07 100644 --- a/gyp/gpu.gypi +++ b/gyp/gpu.gypi @@ -122,19 +122,21 @@ '<(skia_src_path)/gpu/gr_unittests.cpp', '<(skia_src_path)/gpu/effects/Gr1DKernelEffect.h', - '<(skia_src_path)/gpu/effects/GrTextureStripAtlas.h', - '<(skia_src_path)/gpu/effects/GrTextureStripAtlas.cpp', '<(skia_src_path)/gpu/effects/GrConfigConversionEffect.cpp', '<(skia_src_path)/gpu/effects/GrConfigConversionEffect.h', '<(skia_src_path)/gpu/effects/GrConvolutionEffect.cpp', '<(skia_src_path)/gpu/effects/GrConvolutionEffect.h', + '<(skia_src_path)/gpu/effects/GrEllipseEdgeEffect.cpp', + '<(skia_src_path)/gpu/effects/GrEllipseEdgeEffect.h', '<(skia_src_path)/gpu/effects/GrSimpleTextureEffect.cpp', '<(skia_src_path)/gpu/effects/GrSimpleTextureEffect.h', '<(skia_src_path)/gpu/effects/GrSingleTextureEffect.cpp', '<(skia_src_path)/gpu/effects/GrSingleTextureEffect.h', '<(skia_src_path)/gpu/effects/GrTextureDomainEffect.cpp', '<(skia_src_path)/gpu/effects/GrTextureDomainEffect.h', - + '<(skia_src_path)/gpu/effects/GrTextureStripAtlas.cpp', + '<(skia_src_path)/gpu/effects/GrTextureStripAtlas.h', + '<(skia_src_path)/gpu/gl/GrGLBufferImpl.cpp', '<(skia_src_path)/gpu/gl/GrGLBufferImpl.h', '<(skia_src_path)/gpu/gl/GrGLCaps.cpp', diff --git a/include/core/SkTArray.h b/include/core/SkTArray.h index 89f4c9d304..45808d4b60 100644 --- a/include/core/SkTArray.h +++ b/include/core/SkTArray.h @@ -280,6 +280,23 @@ public: return fItemArray[fCount - i - 1]; } + bool operator==(const SkTArray<T, MEM_COPY>& right) const { + int leftCount = this->count(); + if (leftCount != right.count()) { + return false; + } + for (int index = 0; index < leftCount; ++index) { + if (fItemArray[index] != right.fItemArray[index]) { + return false; + } + } + return true; + } + + bool operator!=(const SkTArray<T, MEM_COPY>& right) const { + return !(*this == right); + } + protected: /** * Creates an empty array that will use the passed storage block until it diff --git a/include/gpu/GrBackendEffectFactory.h b/include/gpu/GrBackendEffectFactory.h index a2913870b4..f5e638fef3 100644 --- a/include/gpu/GrBackendEffectFactory.h +++ b/include/gpu/GrBackendEffectFactory.h @@ -40,7 +40,8 @@ public: * GrGLEffects' control. So there is a dedicated part of the key which is combined * automatically with the bits produced by GrGLEffect::GenKey(). */ - kTextureKeyBits = 6 + kTextureKeyBits = 6, + kAttribKeyBits = 4 }; virtual EffectKey glEffectKey(const GrEffectStage&, const GrGLCaps&) const = 0; diff --git a/include/gpu/GrEffect.h b/include/gpu/GrEffect.h index 7b7cd33b17..2792476a6d 100644 --- a/include/gpu/GrEffect.h +++ b/include/gpu/GrEffect.h @@ -14,6 +14,7 @@ #include "GrRefCnt.h" #include "GrTexture.h" #include "GrTextureAccess.h" +#include "GrTypesPriv.h" class GrBackendEffectFactory; class GrContext; @@ -136,6 +137,14 @@ public: /** Shortcut for textureAccess(index).texture(); */ GrTexture* texture(int index) const { return this->textureAccess(index).getTexture(); } + + int numVertexAttribs() const { return fVertexAttribTypes.count(); } + + GrSLType vertexAttribType(int index) const { return fVertexAttribTypes[index]; } + + static const int kMaxVertexAttribs = 2; + + /** Useful for effects that want to insert a texture matrix that is implied by the texture dimensions */ static inline SkMatrix MakeDivByTextureWHMatrix(const GrTexture* texture) { @@ -168,12 +177,19 @@ public: protected: /** - * Subclasses call this from their constructor to register GrTextureAcceses. The effect subclass - * manages the lifetime of the accesses (this function only stores a pointer). This must only be - * called from the constructor because GrEffects are supposed to be immutable. + * Subclasses call this from their constructor to register GrTextureAccesses. The effect + * subclass manages the lifetime of the accesses (this function only stores a pointer). This + * must only be called from the constructor because GrEffects are immutable. */ void addTextureAccess(const GrTextureAccess* textureAccess); + /** + * Subclasses call this from their constructor to register vertex attributes (at most + * kMaxVertexAttribs). This must only be called from the constructor because GrEffects are + * immutable. + */ + void addVertexAttrib(GrSLType type); + GrEffect() : fEffectRef(NULL) {}; /** This should be called by GrEffect subclass factories. See the comment on AutoEffectUnref for @@ -246,8 +262,9 @@ private: // from deferred state, to call isEqual on naked GrEffects, and // to inc/dec deferred ref counts. - SkSTArray<4, const GrTextureAccess*, true> fTextureAccesses; - GrEffectRef* fEffectRef; + SkSTArray<4, const GrTextureAccess*, true> fTextureAccesses; + SkSTArray<kMaxVertexAttribs, GrSLType, true> fVertexAttribTypes; + GrEffectRef* fEffectRef; typedef GrRefCnt INHERITED; }; diff --git a/include/gpu/GrEffectStage.h b/include/gpu/GrEffectStage.h index 05bc313091..05bf40c4bc 100644 --- a/include/gpu/GrEffectStage.h +++ b/include/gpu/GrEffectStage.h @@ -116,6 +116,7 @@ public: stage.fEffectRef->get()->incDeferredRefCounts(); fEffect = stage.fEffectRef->get(); fCoordChangeMatrix = stage.fCoordChangeMatrix; + fVertexAttribIndices = stage.fVertexAttribIndices; } SkDEBUGCODE(fInitialized = true;) } @@ -126,6 +127,7 @@ public: if (NULL != fEffect) { stage->fEffectRef = GrEffect::CreateEffectRef(fEffect); stage->fCoordChangeMatrix = fCoordChangeMatrix; + stage->fVertexAttribIndices = fVertexAttribIndices; } else { stage->fEffectRef = NULL; } @@ -139,16 +141,21 @@ public: return false; } - if (!(*stage.getEffect())->isEqual(*fEffect)) { + if (fVertexAttribIndices != stage.fVertexAttribIndices) { return false; } + if (!(*stage.getEffect())->isEqual(*fEffect)) { + return false; + } + return fCoordChangeMatrix == stage.fCoordChangeMatrix; } private: const GrEffect* fEffect; SkMatrix fCoordChangeMatrix; + SkSTArray<GrEffect::kMaxVertexAttribs, int, true> fVertexAttribIndices; SkDEBUGCODE(bool fInitialized;) }; @@ -162,18 +169,28 @@ public: GrSafeSetNull(fEffectRef); } - const GrEffectRef* setEffect(const GrEffectRef* EffectRef) { + const GrEffectRef* setEffect(const GrEffectRef* EffectRef, const int* attribIndices = NULL) { GrAssert(0 == fSavedCoordChangeCnt); GrSafeAssign(fEffectRef, EffectRef); fCoordChangeMatrix.reset(); + + fVertexAttribIndices.reset(); + int numVertexAttribs = (EffectRef == NULL) ? 0 : EffectRef->get()->numVertexAttribs(); + GrAssert(numVertexAttribs == 0 || attribIndices != NULL); + fVertexAttribIndices.push_back_n(numVertexAttribs, attribIndices); + return EffectRef; } const GrEffectRef* getEffect() const { return fEffectRef; } + const int* getVertexAttribIndices() const { return fVertexAttribIndices.begin(); } + int getVertexAttribIndexCount() const { return fVertexAttribIndices.count(); } + private: - SkMatrix fCoordChangeMatrix; - const GrEffectRef* fEffectRef; + SkMatrix fCoordChangeMatrix; + const GrEffectRef* fEffectRef; + SkSTArray<2, int, true> fVertexAttribIndices; GR_DEBUGCODE(mutable int fSavedCoordChangeCnt;) }; diff --git a/include/gpu/GrTBackendEffectFactory.h b/include/gpu/GrTBackendEffectFactory.h index 7ea7e39ebc..72b2aeaa27 100644 --- a/include/gpu/GrTBackendEffectFactory.h +++ b/include/gpu/GrTBackendEffectFactory.h @@ -35,14 +35,19 @@ public: GrAssert(kIllegalEffectClassID != fEffectClassID); EffectKey effectKey = GLEffect::GenKey(stage, caps); EffectKey textureKey = GLEffect::GenTextureKey(stage.getEffect(), caps); + EffectKey attribKey = GLEffect::GenAttribKey(stage); #if GR_DEBUG static const EffectKey kIllegalIDMask = (uint16_t) (~((1U << kEffectKeyBits) - 1)); GrAssert(!(kIllegalIDMask & effectKey)); static const EffectKey kIllegalTextureKeyMask = (uint16_t) (~((1U << kTextureKeyBits) - 1)); GrAssert(!(kIllegalTextureKeyMask & textureKey)); + + static const EffectKey kIllegalAttribKeyMask = (uint16_t) (~((1U << kAttribKeyBits) - 1)); + GrAssert(!(kIllegalAttribKeyMask & textureKey)); #endif - return fEffectClassID | (textureKey << kEffectKeyBits) | effectKey; + return fEffectClassID | (attribKey << (kEffectKeyBits+kTextureKeyBits)) | + (textureKey << kEffectKeyBits) | effectKey; } /** Returns a new instance of the appropriate *GL* implementation class diff --git a/include/gpu/GrTypesPriv.h b/include/gpu/GrTypesPriv.h new file mode 100644 index 0000000000..fea80f8f46 --- /dev/null +++ b/include/gpu/GrTypesPriv.h @@ -0,0 +1,27 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrTypesPriv_DEFINED +#define GrTypesPriv_DEFINED + +/** + * Types of shader-language-specific boxed variables we can create. + * (Currently only GrGLShaderVars, but should be applicable to other shader + * languages.) + */ +enum GrSLType { + kVoid_GrSLType, + kFloat_GrSLType, + kVec2f_GrSLType, + kVec3f_GrSLType, + kVec4f_GrSLType, + kMat33f_GrSLType, + kMat44f_GrSLType, + kSampler2D_GrSLType +}; + +#endif diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index 046e067cfc..7c852124e8 100644 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -12,6 +12,7 @@ #include "effects/GrConvolutionEffect.h" #include "effects/GrSingleTextureEffect.h" #include "effects/GrConfigConversionEffect.h" +#include "effects/GrEllipseEdgeEffect.h" #include "GrBufferAllocPool.h" #include "GrGpu.h" @@ -1072,12 +1073,8 @@ void GrContext::internalDrawOval(const GrPaint& paint, {kVec2f_GrVertexAttribType, 0}, {kVec4f_GrVertexAttribType, sizeof(GrPoint)} }; - static const GrAttribBindings kAttributeBindings = GrDrawState::kEdge_AttribBindingsBit; - drawState->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs)); drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0); - drawState->setAttribIndex(GrDrawState::kEdge_AttribIndex, 1); - drawState->setAttribBindings(kAttributeBindings); GrAssert(sizeof(CircleVertex) == drawState->getVertexSize()); GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0); @@ -1097,7 +1094,9 @@ void GrContext::internalDrawOval(const GrPaint& paint, SkScalar B; if (isCircle) { + drawState->setAttribBindings(GrDrawState::kEdge_AttribBindingsBit); drawState->setVertexEdgeType(GrDrawState::kCircle_EdgeType); + drawState->setAttribIndex(GrDrawState::kEdge_AttribIndex, 1); xRadius = vm.mapRadius(xRadius); @@ -1129,7 +1128,17 @@ void GrContext::internalDrawOval(const GrPaint& paint, T = -outerRadius; B = +outerRadius; } else { // is axis-aligned ellipse - drawState->setVertexEdgeType(GrDrawState::kEllipse_EdgeType); + drawState->setAttribBindings(GrDrawState::kDefault_AttribBindings); + + enum { + // the edge effects share this stage with glyph rendering + // (kGlyphMaskStage in GrTextContext) && SW path rendering + // (kPathMaskStage in GrSWMaskHelper) + kEdgeEffectStage = GrPaint::kTotalStages, + }; + GrEffectRef* effect = GrEllipseEdgeEffect::Create(); + static const int kEdgeAttrIndex = 1; + drawState->setEffect(kEdgeEffectStage, effect, &kEdgeAttrIndex)->unref(); SkRect xformedRect; vm.mapRect(&xformedRect, oval); diff --git a/src/gpu/GrDrawState.cpp b/src/gpu/GrDrawState.cpp index e797546118..fddce41099 100644 --- a/src/gpu/GrDrawState.cpp +++ b/src/gpu/GrDrawState.cpp @@ -133,6 +133,85 @@ void GrDrawState::setDefaultVertexAttribs() { //////////////////////////////////////////////////////////////////////////////// +bool GrDrawState::validateVertexAttribs() const { + // color and coverage can set indices beyond the standard count + static const int kMaxValidAttribIndex = kVertexAttribCnt+2; + int attributeTypes[kMaxValidAttribIndex]; + for (int i = 0; i < kMaxValidAttribIndex; ++i) { + attributeTypes[i] = -1; + } + + // sentinel to make sure effects don't try to use built-in attributes + static const int kBuiltInAttributeType = 10000; + + // check our built-in indices + if (fAttribIndices[kPosition_AttribIndex] >= kVertexAttribCnt) { + return false; + } + attributeTypes[fAttribIndices[kPosition_AttribIndex]] = kBuiltInAttributeType; + for (int j = kColor_AttribIndex; j <= kCoverage_AttribIndex; ++j) { + if (fCommon.fAttribBindings & kAttribIndexMasks[j]) { + int attributeIndex = fAttribIndices[j]; + if (attributeIndex >= kMaxValidAttribIndex) { + return false; + } + // they should not be shared at all + if (attributeTypes[attributeIndex] != -1) { + return false; + } + attributeTypes[attributeIndex] = kBuiltInAttributeType; + } + } + for (int j = kEdge_AttribIndex; j < kAttribIndexCount; ++j) { + if (fCommon.fAttribBindings & kAttribIndexMasks[j]) { + int attributeIndex = fAttribIndices[j]; + if (attributeIndex >= kVertexAttribCnt) { + return false; + } + // they should not be shared at all + if (attributeTypes[attributeIndex] != -1) { + return false; + } + attributeTypes[attributeIndex] = kBuiltInAttributeType; + } + } + + // now those set by effects + for (int s = 0; s < kNumStages; ++s) { + const GrEffectStage& stage = fStages[s]; + const GrEffectRef* effect = stage.getEffect(); + if (effect == NULL) { + continue; + } + + // make sure that the count in the stage and the effect matches + int numAttributes = stage.getVertexAttribIndexCount(); + if (numAttributes != effect->get()->numVertexAttribs()) { + return false; + } + + // make sure that any shared indices have the same type + const int* attributeIndices = stage.getVertexAttribIndices(); + for (int i = 0; i < numAttributes; ++i) { + int attributeIndex = attributeIndices[i]; + if (attributeIndex >= kVertexAttribCnt) { + return false; + } + + GrSLType attributeType = effect->get()->vertexAttribType(i); + if (attributeTypes[attributeIndex] != -1 && + attributeTypes[attributeIndex] != attributeType) { + return false; + } + attributeTypes[attributeIndex] = attributeType; + } + } + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// + bool GrDrawState::AttributesBindExplicitTexCoords(GrAttribBindings attribBindings) { return SkToBool(kTexCoord_AttribBindingsMask & attribBindings); } diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h index 3f372973ab..220e290a83 100644 --- a/src/gpu/GrDrawState.h +++ b/src/gpu/GrDrawState.h @@ -181,6 +181,8 @@ public: */ void setDefaultVertexAttribs(); + bool validateVertexAttribs() const; + //////////////////////////////////////////////////////////////////////////// // Helpers for picking apart vertex attributes @@ -332,7 +334,7 @@ public: bool hasSolidCoverage(GrAttribBindings) const; static void VertexAttributesUnitTest(); - + /// @} /////////////////////////////////////////////////////////////////////////// @@ -483,8 +485,9 @@ public: /// @name Effect Stages //// - const GrEffectRef* setEffect(int stageIdx, const GrEffectRef* effect) { - fStages[stageIdx].setEffect(effect); + const GrEffectRef* setEffect(int stageIdx, const GrEffectRef* effect, + const int* indices = NULL) { + fStages[stageIdx].setEffect(effect, indices); return effect; } @@ -514,7 +517,9 @@ public: return true; } - void disableStage(int stageIdx) { this->setEffect(stageIdx, NULL); } + void disableStage(int stageIdx) { + this->setEffect(stageIdx, NULL, NULL); + } /** * Release all the GrEffects referred to by this draw state. @@ -1021,9 +1026,6 @@ public: /* Circle specified as center_x, center_y, outer_radius, inner_radius all in window space (y-down). */ kCircle_EdgeType, - /* Axis-aligned ellipse specified as center_x, center_y, x_radius, x_radius/y_radius - all in window space (y-down). */ - kEllipse_EdgeType, kVertexEdgeTypeCnt }; @@ -1189,14 +1191,9 @@ public: if (fRenderTarget.get() != s.fRenderTarget.get() || fCommon != s.fCommon) { return false; } - if (fVertexAttribs.count() != s.fVertexAttribs.count()) { + if (fVertexAttribs != s.fVertexAttribs) { return false; } - for (int i = 0; i < fVertexAttribs.count(); ++i) { - if (fVertexAttribs[i] != s.fVertexAttribs[i]) { - return false; - } - } for (int i = 0; i < kAttribIndexCount; ++i) { if ((i == kPosition_AttribIndex || s.fCommon.fAttribBindings & kAttribIndexMasks[i]) && @@ -1335,13 +1332,9 @@ public: return false; } } - if (fVertexAttribs.count() != state.fVertexAttribs.count()) { + if (fVertexAttribs != state.fVertexAttribs) { return false; } - for (int i = 0; i < fVertexAttribs.count(); ++i) - if (fVertexAttribs[i] != state.fVertexAttribs[i]) { - return false; - } for (int i = 0; i < kNumStages; ++i) { if (!fStages[i].isEqual(state.fStages[i])) { return false; diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp index 954a4e7687..6fdc3a080f 100644 --- a/src/gpu/GrDrawTarget.cpp +++ b/src/gpu/GrDrawTarget.cpp @@ -392,6 +392,8 @@ bool GrDrawTarget::checkDraw(GrPrimitiveType type, int startVertex, } } } + + GrAssert(drawState.validateVertexAttribs()); #endif if (NULL == drawState.getRenderTarget()) { return false; diff --git a/src/gpu/GrEffect.cpp b/src/gpu/GrEffect.cpp index 6e743e7f95..2aad7cf00e 100644 --- a/src/gpu/GrEffect.cpp +++ b/src/gpu/GrEffect.cpp @@ -90,6 +90,11 @@ void GrEffect::addTextureAccess(const GrTextureAccess* access) { fTextureAccesses.push_back(access); } +void GrEffect::addVertexAttrib(GrSLType type) { + GrAssert(fVertexAttribTypes.count() < kMaxVertexAttribs); + fVertexAttribTypes.push_back(type); +} + void* GrEffect::operator new(size_t size) { return GrEffect_Globals::GetTLS()->allocate(size); } diff --git a/src/gpu/GrSWMaskHelper.cpp b/src/gpu/GrSWMaskHelper.cpp index 9682ec427f..fe9fd8228b 100644 --- a/src/gpu/GrSWMaskHelper.cpp +++ b/src/gpu/GrSWMaskHelper.cpp @@ -193,7 +193,8 @@ void GrSWMaskHelper::DrawToTargetWithPathMask(GrTexture* texture, } enum { // the SW path renderer shares this stage with glyph - // rendering (kGlyphMaskStage in GrBatchedTextContext) + // rendering (kGlyphMaskStage in GrTextContext) + // && edge rendering (kEdgeEffectStage in GrContext) kPathMaskStage = GrPaint::kTotalStages, }; GrAssert(!drawState->isStageEnabled(kPathMaskStage)); diff --git a/src/gpu/GrTextContext.cpp b/src/gpu/GrTextContext.cpp index db5abb40b3..a8defcb4ba 100644 --- a/src/gpu/GrTextContext.cpp +++ b/src/gpu/GrTextContext.cpp @@ -19,6 +19,9 @@ #include "SkStrokeRec.h" enum { + // glyph rendering shares this stage with edge rendering + // (kEdgeEffectStage in GrContext) && SW path rendering + // (kPathMaskStage in GrSWMaskHelper) kGlyphMaskStage = GrPaint::kTotalStages, }; diff --git a/src/gpu/effects/GrEllipseEdgeEffect.cpp b/src/gpu/effects/GrEllipseEdgeEffect.cpp new file mode 100644 index 0000000000..002753e203 --- /dev/null +++ b/src/gpu/effects/GrEllipseEdgeEffect.cpp @@ -0,0 +1,80 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrEllipseEdgeEffect.h" +#include "gl/GrGLEffect.h" +#include "gl/GrGLEffectMatrix.h" +#include "gl/GrGLSL.h" +#include "gl/GrGLTexture.h" +#include "GrTBackendEffectFactory.h" +#include "GrTexture.h" + +class GrGLEllipseEdgeEffect : public GrGLEffect { +public: + GrGLEllipseEdgeEffect(const GrBackendEffectFactory& factory, const GrEffectRef&) + : INHERITED (factory) {} + + virtual void emitCode(GrGLShaderBuilder* builder, + const GrEffectStage& stage, + EffectKey key, + const char* vertexCoords, + const char* outputColor, + const char* inputColor, + const TextureSamplerArray& samplers) SK_OVERRIDE { + const char *vsName, *fsName; + builder->addVarying(kVec4f_GrSLType, "EllipseEdge", &vsName, &fsName); + + const SkString* attrName = builder->getEffectAttributeName(stage.getVertexAttribIndices()[0]); + builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str()); + + builder->fsCodeAppend("\tfloat edgeAlpha;\n"); + // translate to origin + builder->fsCodeAppendf("\tvec2 offset = (%s.xy - %s.xy);\n", builder->fragmentPosition(), fsName); + // scale y by xRadius/yRadius + builder->fsCodeAppendf("\toffset.y *= %s.w;\n", fsName); + builder->fsCodeAppend("\tfloat d = length(offset);\n"); + // compare length against xRadius + builder->fsCodeAppendf("\tedgeAlpha = smoothstep(d - 0.5, d + 0.5, %s.z);\n", fsName); + SkString modulate; + GrGLSLModulate4f(&modulate, inputColor, "edgeAlpha"); + builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str()); + } + + static inline EffectKey GenKey(const GrEffectStage& stage, const GrGLCaps&) { + return 0; + } + + virtual void setData(const GrGLUniformManager& uman, const GrEffectStage& stage) SK_OVERRIDE { + } + +private: + typedef GrGLEffect INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +GrEllipseEdgeEffect::GrEllipseEdgeEffect() : GrEffect() { + this->addVertexAttrib(kVec4f_GrSLType); +} + +void GrEllipseEdgeEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const { + *validFlags = 0; +} + +const GrBackendEffectFactory& GrEllipseEdgeEffect::getFactory() const { + return GrTBackendEffectFactory<GrEllipseEdgeEffect>::getInstance(); +} + +/////////////////////////////////////////////////////////////////////////////// + +GR_DEFINE_EFFECT_TEST(GrEllipseEdgeEffect); + +GrEffectRef* GrEllipseEdgeEffect::TestCreate(SkMWCRandom* random, + GrContext* context, + GrTexture* textures[]) { + return GrEllipseEdgeEffect::Create(); +} diff --git a/src/gpu/effects/GrEllipseEdgeEffect.h b/src/gpu/effects/GrEllipseEdgeEffect.h new file mode 100644 index 0000000000..8f56d771df --- /dev/null +++ b/src/gpu/effects/GrEllipseEdgeEffect.h @@ -0,0 +1,50 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrEllipseEdgeEffect_DEFINED +#define GrEllipseEdgeEffect_DEFINED + +#include "GrEffect.h" + +class GrGLEllipseEdgeEffect; + +/** + * The output of this effect is a modulation of the input color and coverage for an axis-aligned + * ellipse, specified as center_x, center_y, x_radius, x_radius/y_radius in window space (y-down). + */ + +class GrEllipseEdgeEffect : public GrEffect { +public: + static GrEffectRef* Create() { + // maybe only have one static copy? + AutoEffectUnref effect(SkNEW(GrEllipseEdgeEffect)); + return CreateEffectRef(effect); + } + + virtual ~GrEllipseEdgeEffect() {} + + static const char* Name() { return "EllipseEdge"; } + + virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE; + + typedef GrGLEllipseEdgeEffect GLEffect; + + virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE; + +private: + GrEllipseEdgeEffect(); + + virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE { + return true; + } + + GR_DECLARE_EFFECT_TEST; + + typedef GrEffect INHERITED; +}; + +#endif diff --git a/src/gpu/gl/GrGLEffect.cpp b/src/gpu/gl/GrGLEffect.cpp index ccea2698e2..f2cd37c93e 100644 --- a/src/gpu/gl/GrGLEffect.cpp +++ b/src/gpu/gl/GrGLEffect.cpp @@ -31,3 +31,18 @@ GrGLEffect::EffectKey GrGLEffect::GenTextureKey(const GrEffectRef* effect, } return key; } + +GrGLEffect::EffectKey GrGLEffect::GenAttribKey(const GrEffectStage& stage) { + EffectKey key = 0; + + int numAttributes = stage.getVertexAttribIndexCount(); + GrAssert(numAttributes <= 2); + const int* attributeIndices = stage.getVertexAttribIndices(); + for (int index = 0; index < numAttributes; ++index) { + EffectKey value = attributeIndices[index] << 2*index; + GrAssert(0 == (value & key)); // keys for each attribute ought not to overlap + key |= value; + } + + return key; +} diff --git a/src/gpu/gl/GrGLEffect.h b/src/gpu/gl/GrGLEffect.h index 76f865e57c..869fbdad7f 100644 --- a/src/gpu/gl/GrGLEffect.h +++ b/src/gpu/gl/GrGLEffect.h @@ -87,6 +87,7 @@ public: const char* name() const { return fFactory.name(); } static EffectKey GenTextureKey(const GrEffectRef*, const GrGLCaps&); + static EffectKey GenAttribKey(const GrEffectStage& stage); /** * GrGLEffect subclasses get passed a GrEffectStage in their emitCode and setData functions. diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp index 2b6ccbd0b2..c1643578ad 100644 --- a/src/gpu/gl/GrGLProgram.cpp +++ b/src/gpu/gl/GrGLProgram.cpp @@ -419,9 +419,7 @@ bool GrGLProgram::genEdgeCoverage(SkString* coverageVar, if (fDesc.fAttribBindings & GrDrawState::kEdge_AttribBindingsBit) { const char *vsName, *fsName; builder->addVarying(kVec4f_GrSLType, "Edge", &vsName, &fsName); - builder->fVSAttrs.push_back().set(kVec4f_GrSLType, - GrGLShaderVar::kAttribute_TypeModifier, - EDGE_ATTR_NAME); + builder->addAttribute(kVec4f_GrSLType, EDGE_ATTR_NAME); builder->vsCodeAppendf("\t%s = " EDGE_ATTR_NAME ";\n", vsName); switch (fDesc.fVertexEdgeType) { case GrDrawState::kHairLine_EdgeType: @@ -467,13 +465,6 @@ bool GrGLProgram::genEdgeCoverage(SkString* coverageVar, builder->fsCodeAppendf("\tfloat innerAlpha = %s.w == 0.0 ? 1.0 : smoothstep(%s.w - 0.5, %s.w + 0.5, d);\n", fsName, fsName, fsName); builder->fsCodeAppend("\tedgeAlpha = outerAlpha * innerAlpha;\n"); break; - case GrDrawState::kEllipse_EdgeType: - builder->fsCodeAppend("\tfloat edgeAlpha;\n"); - builder->fsCodeAppendf("\tvec2 offset = (%s.xy - %s.xy);\n", builder->fragmentPosition(), fsName); - builder->fsCodeAppendf("\toffset.y *= %s.w;\n", fsName); - builder->fsCodeAppend("\tfloat d = length(offset);\n"); - builder->fsCodeAppendf("\tedgeAlpha = smoothstep(d - 0.5, d + 0.5, %s.z);\n", fsName); - break; default: GrCrash("Unknown Edge Type!"); break; @@ -492,9 +483,7 @@ bool GrGLProgram::genEdgeCoverage(SkString* coverageVar, void GrGLProgram::genInputColor(GrGLShaderBuilder* builder, SkString* inColor) { switch (fDesc.fColorInput) { case GrGLProgram::Desc::kAttribute_ColorInput: { - builder->fVSAttrs.push_back().set(kVec4f_GrSLType, - GrGLShaderVar::kAttribute_TypeModifier, - COL_ATTR_NAME); + builder->addAttribute(kVec4f_GrSLType, COL_ATTR_NAME); const char *vsName, *fsName; builder->addVarying(kVec4f_GrSLType, "Color", &vsName, &fsName); builder->vsCodeAppendf("\t%s = " COL_ATTR_NAME ";\n", vsName); @@ -534,9 +523,7 @@ void GrGLProgram::genUniformCoverage(GrGLShaderBuilder* builder, SkString* inOut namespace { void gen_attribute_coverage(GrGLShaderBuilder* builder, SkString* inOutCoverage) { - builder->fVSAttrs.push_back().set(kVec4f_GrSLType, - GrGLShaderVar::kAttribute_TypeModifier, - COV_ATTR_NAME); + builder->addAttribute(kVec4f_GrSLType, COV_ATTR_NAME); const char *vsName, *fsName; builder->addVarying(kVec4f_GrSLType, "Coverage", &vsName, &fsName); builder->vsCodeAppendf("\t%s = " COV_ATTR_NAME ";\n", vsName); @@ -777,9 +764,7 @@ bool GrGLProgram::genProgram(const GrEffectStage* stages[]) { // add texture coordinates that are used to the list of vertex attr decls if (GrDrawState::AttributesBindExplicitTexCoords(attribBindings)) { - builder.fVSAttrs.push_back().set(kVec2f_GrSLType, - GrGLShaderVar::kAttribute_TypeModifier, - TEX_ATTR_NAME); + builder.addAttribute(kVec2f_GrSLType, TEX_ATTR_NAME); } /////////////////////////////////////////////////////////////////////////// @@ -917,6 +902,11 @@ bool GrGLProgram::genProgram(const GrEffectStage* stages[]) { inCoverage = outCoverage; } } + + // discard if coverage is zero + if (fDesc.fDiscardIfOutsideEdge && !outCoverage.isEmpty()) { + builder.fsCodeAppendf("\tif (all(lessThanEqual(%s, vec4(0.0)))) {\n\t\tdiscard;\n\t}\n", outCoverage.c_str()); + } } if (Desc::kNone_DualSrcOutput != fDesc.fDualSrcOutput) { @@ -1022,6 +1012,13 @@ bool GrGLProgram::bindOutputsAttribsAndLinkProgram(const GrGLShaderBuilder& buil GL_CALL(BindAttribLocation(fProgramID, fDesc.fTexCoordAttributeIndex, TEX_ATTR_NAME)); } + const GrGLShaderBuilder::AttributePair* attribEnd = builder.getEffectAttributes().end(); + for (const GrGLShaderBuilder::AttributePair* attrib = builder.getEffectAttributes().begin(); + attrib != attribEnd; + ++attrib) { + GL_CALL(BindAttribLocation(fProgramID, attrib->fIndex, attrib->fName.c_str())); + } + GL_CALL(LinkProgram(fProgramID)); GrGLint linked = GR_GL_INIT_ZERO; diff --git a/src/gpu/gl/GrGLSL.h b/src/gpu/gl/GrGLSL.h index 4559fddd36..940501cd3e 100644 --- a/src/gpu/gl/GrGLSL.h +++ b/src/gpu/gl/GrGLSL.h @@ -9,6 +9,7 @@ #define GrGLSL_DEFINED #include "gl/GrGLInterface.h" +#include "GrTypesPriv.h" class GrGLShaderVar; class SkString; @@ -34,22 +35,6 @@ enum GrGLSLGeneration { k150_GrGLSLGeneration, }; -/** - * Types of shader-language-specific boxed variables we can create. - * (Currently only GrGLShaderVars, but should be applicable to other shader - * languages.) - */ -enum GrSLType { - kVoid_GrSLType, - kFloat_GrSLType, - kVec2f_GrSLType, - kVec3f_GrSLType, - kVec4f_GrSLType, - kMat33f_GrSLType, - kMat44f_GrSLType, - kSampler2D_GrSLType -}; - enum GrSLConstantVec { kZeros_GrSLConstantVec, kOnes_GrSLConstantVec, diff --git a/src/gpu/gl/GrGLShaderBuilder.cpp b/src/gpu/gl/GrGLShaderBuilder.cpp index 5c3f5b3fe8..1a238ae04b 100644 --- a/src/gpu/gl/GrGLShaderBuilder.cpp +++ b/src/gpu/gl/GrGLShaderBuilder.cpp @@ -258,6 +258,22 @@ const GrGLShaderVar& GrGLShaderBuilder::getUniformVariable(UniformHandle u) cons return fUniforms[handle_to_index(u)].fVariable; } +bool GrGLShaderBuilder::addAttribute(GrSLType type, + const char* name) { + for (int i = 0; i < fVSAttrs.count(); ++i) { + const GrGLShaderVar& attr = fVSAttrs[i]; + // if attribute already added, don't add it again + if (attr.getName().equals(name)) { + GrAssert(attr.getType() == type); + return false; + } + } + fVSAttrs.push_back().set(type, + GrGLShaderVar::kAttribute_TypeModifier, + name); + return true; +} + void GrGLShaderBuilder::addVarying(GrSLType type, const char* name, const char** vsOutName, @@ -491,6 +507,18 @@ GrGLEffect* GrGLShaderBuilder::createAndEmitGLEffect( samplerHandles->push_back(textureSamplers[i].fSamplerUniform); } + int numAttributes = stage.getVertexAttribIndexCount(); + const int* attributeIndices = stage.getVertexAttribIndices(); + SkSTArray<GrEffect::kMaxVertexAttribs, SkString> attributeNames; + for (int i = 0; i < numAttributes; ++i) { + SkString attributeName("aAttr"); + attributeName.appendS32(attributeIndices[i]); + + if (this->addAttribute(effect->vertexAttribType(i), attributeName.c_str())) { + fEffectAttributes.push_back().set(attributeIndices[i], attributeName); + } + } + GrGLEffect* glEffect = effect->getFactory().createGLInstance(effect); // Enclose custom code in a block to avoid namespace conflicts @@ -508,3 +536,16 @@ GrGLEffect* GrGLShaderBuilder::createAndEmitGLEffect( return glEffect; } + +const SkString* GrGLShaderBuilder::getEffectAttributeName(int attributeIndex) const { + const AttributePair* attribEnd = this->getEffectAttributes().end(); + for (const AttributePair* attrib = this->getEffectAttributes().begin(); + attrib != attribEnd; + ++attrib) { + if (attrib->fIndex == attributeIndex) { + return &attrib->fName; + } + } + + return NULL; +} diff --git a/src/gpu/gl/GrGLShaderBuilder.h b/src/gpu/gl/GrGLShaderBuilder.h index 08b3ef5ef5..524a8853ca 100644 --- a/src/gpu/gl/GrGLShaderBuilder.h +++ b/src/gpu/gl/GrGLShaderBuilder.h @@ -184,7 +184,11 @@ public: return this->getUniformVariable(u).c_str(); } - /** Add a varying variable to the current program to pass values between vertex and fragment + /** Add a vertex attribute to the current program that is passed in from the vertex data. + Returns false if the attribute was already there, true otherwise. */ + bool addAttribute(GrSLType type, const char* name); + + /** Add a varying variable to the current program to pass values between vertex and fragment shaders. If the last two parameters are non-NULL, they are filled in with the name generated. */ void addVarying(GrSLType type, @@ -222,6 +226,19 @@ public: const char* vsInCoord, SkTArray<GrGLUniformManager::UniformHandle, true>* samplerHandles); GrGLUniformManager::UniformHandle getRTHeightUniform() const { return fRTHeightUniform; } + + struct AttributePair { + void set(int index, const SkString& name) { + fIndex = index; fName = name; + } + int fIndex; + SkString fName; + }; + const SkSTArray<10, AttributePair, true>& getEffectAttributes() const { + return fEffectAttributes; + } + const SkString* getEffectAttributeName(int attributeIndex) const; + // TODO: Make this do all the compiling, linking, etc. void finished(GrGLuint programID); @@ -270,6 +287,8 @@ private: bool fSetupFragPosition; GrGLUniformManager::UniformHandle fRTHeightUniform; + SkSTArray<10, AttributePair, true> fEffectAttributes; + GrGLShaderVar* fPositionVar; }; diff --git a/tests/GLProgramsTest.cpp b/tests/GLProgramsTest.cpp index 45c5f2d162..b56c788513 100644 --- a/tests/GLProgramsTest.cpp +++ b/tests/GLProgramsTest.cpp @@ -121,6 +121,8 @@ bool GrGpuGL::programUnitTest(int maxStages) { GrGLProgram::Desc pdesc; GrEffectStage stages[GrDrawState::kNumStages]; + int currAttribIndex = GrDrawState::kAttribIndexCount; + int attribIndices[2]; for (int s = 0; s < maxStages; ++s) { // enable the stage? if (random.nextBool()) { @@ -129,7 +131,10 @@ bool GrGpuGL::programUnitTest(int maxStages) { &random, this->getContext(), dummyTextures)); - stages[s].setEffect(effect.get()); + for (int i = 0; i < effect.get()->get()->numVertexAttribs(); ++i) { + attribIndices[i] = currAttribIndex++; + } + stages[s].setEffect(effect.get(), attribIndices); } } pdesc.setRandom(&random, this, stages); |