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:
parent
2e71f1619d
commit
ff6ea2663f
@ -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',
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;)
|
||||
};
|
||||
|
@ -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
27
include/gpu/GrTypesPriv.h
Normal 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
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -392,6 +392,8 @@ bool GrDrawTarget::checkDraw(GrPrimitiveType type, int startVertex,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GrAssert(drawState.validateVertexAttribs());
|
||||
#endif
|
||||
if (NULL == drawState.getRenderTarget()) {
|
||||
return false;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
80
src/gpu/effects/GrEllipseEdgeEffect.cpp
Normal file
80
src/gpu/effects/GrEllipseEdgeEffect.cpp
Normal 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();
|
||||
}
|
50
src/gpu/effects/GrEllipseEdgeEffect.h
Normal file
50
src/gpu/effects/GrEllipseEdgeEffect.h
Normal 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
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user