Add GrEllipseEdgeEffect.

Adds the effect that replaces the old oval rendering code. Also hooks in code to set attribute names and indices for effects.

Author: jvanverth@google.com

Review URL: https://chromiumcodereview.appspot.com/12462008

git-svn-id: http://skia.googlecode.com/svn/trunk@8092 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
commit-bot@chromium.org 2013-03-12 12:26:08 +00:00
parent 2e71f1619d
commit ff6ea2663f
23 changed files with 446 additions and 75 deletions

View File

@ -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',

View File

@ -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

View File

@ -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;

View File

@ -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;
};

View File

@ -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;)
};

View File

@ -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

27
include/gpu/GrTypesPriv.h Normal file
View File

@ -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

View File

@ -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);

View File

@ -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);
}

View File

@ -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;

View File

@ -392,6 +392,8 @@ bool GrDrawTarget::checkDraw(GrPrimitiveType type, int startVertex,
}
}
}
GrAssert(drawState.validateVertexAttribs());
#endif
if (NULL == drawState.getRenderTarget()) {
return false;

View File

@ -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);
}

View File

@ -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));

View File

@ -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,
};

View File

@ -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();
}

View File

@ -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

View File

@ -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;
}

View File

@ -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.

View File

@ -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;

View File

@ -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,

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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);