Introduction of set of functions to manage generation of texture fetch shader code.

A new set of routines have been added to GrGLShaderBuilder to emit texture fetches, taking into consideration the format of the texture to be accessed, and the channel swizzle.  
Review URL: https://codereview.appspot.com/6446072

git-svn-id: http://skia.googlecode.com/svn/trunk@4919 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
twiz@google.com 2012-08-02 15:15:16 +00:00
parent eb7ad4a8b9
commit a5e65ec434
22 changed files with 238 additions and 55 deletions

View File

@ -14,6 +14,27 @@
class GrContext;
class GrTexture;
class SkString;
/** A class representing the swizzle access pattern for a texture.
*/
class GrTextureAccess {
public:
typedef char Swizzle[4];
GrTextureAccess(const GrTexture* texture, const SkString& swizzle);
const GrTexture* getTexture() const { return fTexture; }
const Swizzle& getSwizzle() const { return fSwizzle; }
bool referencesAlpha() const {
return fSwizzle[0] == 'a' || fSwizzle[1] == 'a' || fSwizzle[2] == 'a' || fSwizzle[3] == 'a';
}
private:
const GrTexture* fTexture;
Swizzle fSwizzle;
};
/** Provides custom vertex shader, fragment shader, uniform data for a
particular stage of the Ganesh shading pipeline.
@ -74,13 +95,17 @@ public:
*/
virtual bool isEqual(const GrCustomStage&) const;
/** Human-meaningful string to identify this effect; may be embedded
in generated shader code. */
/** Human-meaningful string to identify this effect; may be embedded
in generated shader code. */
const char* name() const { return this->getFactory().name(); }
virtual unsigned int numTextures() const;
virtual GrTexture* texture(unsigned int index) const;
/** Returns the access pattern for the texture at index. Returns NULL if index is
unused. */
virtual const GrTextureAccess* textureAccess(unsigned int index) const;
void* operator new(size_t size);
void operator delete(void* target);

View File

@ -19,15 +19,18 @@
class GrCustomStage;
class GrGLProgramStage;
class GrGLCaps;
class GrProgramStageFactory : public GrNoncopyable {
public:
typedef uint16_t StageKey;
typedef uint32_t StageKey;
enum {
kProgramStageKeyBits = 10,
kTexturingStageKeyBits = 6
};
virtual StageKey glStageKey(const GrCustomStage& stage) const = 0;
virtual StageKey glStageKey(const GrCustomStage& stage,
const GrGLCaps& caps ) const = 0;
virtual GrGLProgramStage* createGLInstance(
const GrCustomStage& stage) const = 0;
@ -68,7 +71,7 @@ template <typename StageClass>
class GrTProgramStageFactory : public GrProgramStageFactory {
public:
typedef typename StageClass::GLProgramStage GLProgramStage;
typedef typename StageClass::GLProgramStage GLProgramStage;
/** Returns a human-readable name that is accessible via GrCustomStage or
GrGLProgramStage and is consistent between the two of them.
@ -80,20 +83,26 @@ public:
id identifies the GrCustomShader subclass. The remainder is based
on the aspects of the GrCustomStage object's configuration that affect
GLSL code generation. */
virtual StageKey glStageKey(const GrCustomStage& stage) const SK_OVERRIDE {
virtual StageKey glStageKey(const GrCustomStage& stage,
const GrGLCaps& caps) const SK_OVERRIDE {
GrAssert(kIllegalStageClassID != fStageClassID);
StageKey stageID = GLProgramStage::GenKey(stage);
StageKey stageID = GLProgramStage::GenKey(stage, caps);
StageKey textureKey = GLProgramStage::GenTextureKey(stage, caps);
#if GR_DEBUG
static const StageKey kIllegalIDMask =
(uint16_t) (~((1U << kProgramStageKeyBits) - 1));
GrAssert(!(kIllegalIDMask & stageID));
static const StageKey kIllegalTextureKeyMask =
(uint16_t) (~((1U << kTexturingStageKeyBits) - 1));
GrAssert(!(kIllegalTextureKeyMask & textureKey));
#endif
return fStageClassID | stageID;
return fStageClassID | (textureKey << kProgramStageKeyBits) | stageID;
}
/** Returns a new instance of the appropriate *GL* implementation class
for the given GrCustomStage; caller is responsible for deleting
the object. */
for the given GrCustomStage; caller is responsible for deleting
the object. */
virtual GLProgramStage* createGLInstance(
const GrCustomStage& stage) const SK_OVERRIDE {
return SkNEW_ARGS(GLProgramStage, (*this, stage));
@ -113,7 +122,7 @@ public:
protected:
GrTProgramStageFactory() {
fStageClassID = GenID() << kProgramStageKeyBits;
fStageClassID = GenID() << (kProgramStageKeyBits + kTexturingStageKeyBits) ;
}
};

View File

@ -918,7 +918,7 @@ public:
virtual void emitLightFunc(const GrGLShaderBuilder*, SkString* funcs) = 0;
static inline StageKey GenKey(const GrCustomStage& s);
static inline StageKey GenKey(const GrCustomStage& s, const GrGLCaps& caps);
virtual void setData(const GrGLUniformManager&,
const GrCustomStage&,
@ -1086,8 +1086,8 @@ vec3 interiorNormal(float m[9], float surfaceScale) {\n\
code->appendf(")%s;\n", builder->fModulate.c_str());
}
GrGLProgramStage::StageKey GrGLLightingEffect::GenKey(
const GrCustomStage& s) {
GrGLProgramStage::StageKey GrGLLightingEffect::GenKey(const GrCustomStage& s,
const GrGLCaps& caps) {
return static_cast<const GrLightingEffect&>(s).light()->type();
}

View File

@ -491,7 +491,7 @@ public:
const char* outputColor,
const char* inputColor,
const char* samplerName) SK_OVERRIDE;
static StageKey GenKey(const GrCustomStage& s) { return 0; }
static StageKey GenKey(const GrCustomStage& s, const GrGLCaps& caps) { return 0; }
private:

View File

@ -487,7 +487,7 @@ public:
const char* inputColor,
const char* samplerName) SK_OVERRIDE;
static StageKey GenKey(const GrCustomStage& s) { return 0; }
static StageKey GenKey(const GrCustomStage& s, const GrGLCaps& caps) { return 0; }
private:

View File

@ -396,7 +396,7 @@ public:
const char* inputColor,
const char* samplerName) SK_OVERRIDE;
static StageKey GenKey(const GrCustomStage& s) { return 0; }
static StageKey GenKey(const GrCustomStage& s, const GrGLCaps& caps) { return 0; }
private:

View File

@ -340,7 +340,7 @@ public:
const GrRenderTarget*,
int stageNum) SK_OVERRIDE;
static StageKey GenKey(const GrCustomStage& s);
static StageKey GenKey(const GrCustomStage& s, const GrGLCaps& caps);
protected:
@ -636,7 +636,7 @@ void GrGLConical2Gradient::setData(const GrGLUniformManager& uman,
}
}
GrCustomStage::StageKey GrGLConical2Gradient::GenKey(const GrCustomStage& s) {
GrCustomStage::StageKey GrGLConical2Gradient::GenKey(const GrCustomStage& s, const GrGLCaps& caps) {
return (static_cast<const GrConical2Gradient&>(s).isDegenerate());
}
@ -669,4 +669,4 @@ GrCustomStage* SkTwoPointConicalGradient::asNewCustomStage(
return NULL;
}
#endif
#endif

View File

@ -373,7 +373,7 @@ public:
const GrRenderTarget*,
int stageNum) SK_OVERRIDE;
static StageKey GenKey(const GrCustomStage& s);
static StageKey GenKey(const GrCustomStage& s, const GrGLCaps& caps);
protected:
@ -608,7 +608,7 @@ void GrGLRadial2Gradient::setData(const GrGLUniformManager& uman,
}
}
GrCustomStage::StageKey GrGLRadial2Gradient::GenKey(const GrCustomStage& s) {
GrCustomStage::StageKey GrGLRadial2Gradient::GenKey(const GrCustomStage& s, const GrGLCaps& caps) {
return (static_cast<const GrRadial2Gradient&>(s).isDegenerate());
}

View File

@ -8,6 +8,7 @@
#include "GrContext.h"
#include "GrCustomStage.h"
#include "GrMemoryPool.h"
#include "SkString.h"
#include "SkTLS.h"
SK_DEFINE_INST_COUNT(GrCustomStage)
@ -31,6 +32,17 @@ private:
int32_t GrProgramStageFactory::fCurrStageClassID =
GrProgramStageFactory::kIllegalStageClassID;
GrTextureAccess::GrTextureAccess(const GrTexture* texture, const SkString& swizzle)
: fTexture(texture) {
GrAssert(swizzle.size() <= 4);
for (unsigned int offset = 0; offset < swizzle.size(); ++offset) {
fSwizzle[offset] = swizzle[offset];
}
if (swizzle.size() < 4) {
fSwizzle[swizzle.size()] = 0;
}
}
GrCustomStage::GrCustomStage() {
}
@ -63,6 +75,10 @@ GrTexture* GrCustomStage::texture(unsigned int index) const {
return NULL;
}
const GrTextureAccess* GrCustomStage::textureAccess(unsigned int index) const {
return NULL;
}
void * GrCustomStage::operator new(size_t size) {
return GrCustomStage_Globals::GetTLS()->allocate(size);
}
@ -70,4 +86,3 @@ void * GrCustomStage::operator new(size_t size) {
void GrCustomStage::operator delete(void* target) {
GrCustomStage_Globals::GetTLS()->release(target);
}

View File

@ -30,49 +30,72 @@ public:
const GrRenderTarget*,
int stageNum) SK_OVERRIDE {}
static inline StageKey GenKey(const GrCustomStage&);
static StageKey GenKey(const GrCustomStage&, const GrGLCaps&);
private:
const GrCustomStage& fCustomStage;
typedef GrGLProgramStage INHERITED;
};
GrGLColorTableEffect::GrGLColorTableEffect(
const GrProgramStageFactory& factory, const GrCustomStage& stage)
: INHERITED(factory) {
: INHERITED(factory)
, fCustomStage(stage) {
}
void GrGLColorTableEffect::emitFS(GrGLShaderBuilder* state,
void GrGLColorTableEffect::emitFS(GrGLShaderBuilder* builder,
const char* outputColor,
const char* inputColor,
const char* samplerName) {
static const float kColorScaleFactor = 255.0f / 256.0f;
static const float kColorOffsetFactor = 1.0f / 512.0f;
SkString* code = &state->fFSCode;
SkString* code = &builder->fFSCode;
code->appendf("\t\tvec4 coord = vec4(%s.rgb / %s.a, %s.a);\n",
inputColor, inputColor, inputColor);
code->appendf("\t\tcoord = coord * %f + vec4(%f, %f, %f, %f);\n",
kColorScaleFactor,
kColorOffsetFactor, kColorOffsetFactor, kColorOffsetFactor, kColorOffsetFactor);
code->appendf("\t\t%s.a = texture2D(%s, vec2(coord.a, 0.125)).a;\n",
outputColor, samplerName);
code->appendf("\t\t%s.r = texture2D(%s, vec2(coord.r, 0.375)).a;\n",
outputColor, samplerName);
code->appendf("\t\t%s.g = texture2D(%s, vec2(coord.g, 0.625)).a;\n",
outputColor, samplerName);
code->appendf("\t\t%s.b = texture2D(%s, vec2(coord.b, 0.875)).a;\n",
outputColor, samplerName);
const GrTextureAccess& access = *fCustomStage.textureAccess(0);
code->appendf("\t\t%s.a = ", outputColor);
builder->emitCustomTextureLookup(GrGLShaderBuilder::kDefault_SamplerMode,
access,
samplerName,
"vec2(coord.a, 0.125)");
code->appendf("\t\t%s.r = ", outputColor);
builder->emitCustomTextureLookup(GrGLShaderBuilder::kDefault_SamplerMode,
access,
samplerName,
"vec2(coord.r, 0.375)");
code->appendf("\t\t%s.g = ", outputColor);
builder->emitCustomTextureLookup(GrGLShaderBuilder::kDefault_SamplerMode,
access,
samplerName,
"vec2(coord.g, 0.625)");
code->appendf("\t\t%s.b = ", outputColor);
builder->emitCustomTextureLookup(GrGLShaderBuilder::kDefault_SamplerMode,
access,
samplerName,
"vec2(coord.b, 0.875)");
code->appendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor);
}
GrGLProgramStage::StageKey GrGLColorTableEffect::GenKey(
const GrCustomStage& s) {
GrGLProgramStage::StageKey GrGLColorTableEffect::GenKey(const GrCustomStage& s,
const GrGLCaps& caps) {
return 0;
}
///////////////////////////////////////////////////////////////////////////////
GrColorTableEffect::GrColorTableEffect(GrTexture* texture)
: INHERITED(texture) {
: INHERITED(texture)
, fTextureAccess(texture, SkString("a")) {
}
GrColorTableEffect::~GrColorTableEffect() {
@ -85,3 +108,10 @@ const GrProgramStageFactory& GrColorTableEffect::getFactory() const {
bool GrColorTableEffect::isEqual(const GrCustomStage& sBase) const {
return INHERITED::isEqual(sBase);
}
const GrTextureAccess* GrColorTableEffect::textureAccess(unsigned int index) const {
if (0 == index)
return &fTextureAccess;
return NULL;
}

View File

@ -29,10 +29,14 @@ public:
virtual const GrProgramStageFactory& getFactory() const SK_OVERRIDE;
virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
virtual const GrTextureAccess* textureAccess(unsigned int index) const SK_OVERRIDE;
typedef GrGLColorTableEffect GLProgramStage;
private:
GrTextureAccess fTextureAccess;
typedef GrSingleTextureEffect INHERITED;
};
#endif

View File

@ -33,7 +33,7 @@ public:
const GrRenderTarget*,
int stageNum) SK_OVERRIDE;
static inline StageKey GenKey(const GrCustomStage&);
static inline StageKey GenKey(const GrCustomStage&, const GrGLCaps&);
private:
int width() const { return Gr1DKernelEffect::WidthFromRadius(fRadius); }
@ -125,8 +125,8 @@ void GrGLConvolutionEffect::setData(const GrGLUniformManager& uman,
uman.set1fv(fKernelUni, 0, this->width(), conv.kernel());
}
GrGLProgramStage::StageKey GrGLConvolutionEffect::GenKey(
const GrCustomStage& s) {
GrGLProgramStage::StageKey GrGLConvolutionEffect::GenKey(const GrCustomStage& s,
const GrGLCaps& caps) {
return static_cast<const GrConvolutionEffect&>(s).radius();
}
@ -185,4 +185,3 @@ bool GrConvolutionEffect::isEqual(const GrCustomStage& sBase) const {
this->direction() == s.direction() &&
0 == memcmp(fKernel, s.fKernel, this->width() * sizeof(float)));
}

View File

@ -26,7 +26,7 @@ public:
const char* inputColor,
const char* samplerName) SK_OVERRIDE;
static inline StageKey GenKey(const GrCustomStage& s);
static inline StageKey GenKey(const GrCustomStage& s, const GrGLCaps& caps);
virtual void setData(const GrGLUniformManager&,
const GrCustomStage&,
@ -98,8 +98,8 @@ void GrGLMorphologyEffect ::emitFS(GrGLShaderBuilder* builder,
code->appendf("\t\t%s = value%s;\n", outputColor, builder->fModulate.c_str());
}
GrGLProgramStage::StageKey GrGLMorphologyEffect::GenKey(
const GrCustomStage& s) {
GrGLProgramStage::StageKey GrGLMorphologyEffect::GenKey(const GrCustomStage& s,
const GrGLCaps& caps) {
const GrMorphologyEffect& m = static_cast<const GrMorphologyEffect&>(s);
StageKey key = static_cast<StageKey>(m.radius());
key |= (m.type() << 8);

View File

@ -26,7 +26,7 @@ public:
builder->emitDefaultFetch(outputColor, samplerName);
}
static inline StageKey GenKey(const GrCustomStage&) { return 0; }
static inline StageKey GenKey(const GrCustomStage&, const GrGLCaps&) { return 0; }
private:
@ -56,5 +56,3 @@ GrTexture* GrSingleTextureEffect::texture(unsigned int index) const {
const GrProgramStageFactory& GrSingleTextureEffect::getFactory() const {
return GrTProgramStageFactory<GrSingleTextureEffect>::getInstance();
}

View File

@ -27,7 +27,7 @@ public:
const GrRenderTarget*,
int stageNum) SK_OVERRIDE;
static inline StageKey GenKey(const GrCustomStage&) { return 0; }
static inline StageKey GenKey(const GrCustomStage&, const GrGLCaps&) { return 0; }
private:
GrGLUniformManager::UniformHandle fNameUni;
@ -107,5 +107,3 @@ bool GrTextureDomainEffect::isEqual(const GrCustomStage& sBase) const {
const GrTextureDomainEffect& s = static_cast<const GrTextureDomainEffect&>(sBase);
return (INHERITED::isEqual(sBase) && this->fTextureDomain == s.fTextureDomain);
}

View File

@ -164,7 +164,7 @@ public:
/** Non-zero if user-supplied code will write the stage's
contribution to the fragment shader. */
uint16_t fCustomStageKey;
GrProgramStageFactory::StageKey fCustomStageKey;
GR_STATIC_ASSERT((InConfigFlags)(uint8_t)kInConfigBitMask ==
kInConfigBitMask);

View File

@ -27,3 +27,14 @@ void GrGLProgramStage::setData(const GrGLUniformManager&,
int stageNum) {
}
GrGLProgramStage::StageKey GrGLProgramStage::GenTextureKey(const GrCustomStage& stage,
const GrGLCaps& caps) {
StageKey key = 0;
for (unsigned int index = 0; index < stage.numTextures(); ++index) {
if (stage.textureAccess(index)) {
key = (key << index) |
GrGLShaderBuilder::KeyForTextureAccess(*stage.textureAccess(index), caps);
}
}
return key;
}

View File

@ -78,6 +78,8 @@ public:
const char* name() const { return fFactory.name(); }
static StageKey GenTextureKey(const GrCustomStage&, const GrGLCaps&);
protected:
const GrProgramStageFactory& fFactory;

View File

@ -8,6 +8,7 @@
#include "gl/GrGLShaderBuilder.h"
#include "gl/GrGLProgram.h"
#include "gl/GrGLUniformHandle.h"
#include "GrTexture.h"
// number of each input/output type in a single allocation block
static const int kVarsPerBlock = 8;
@ -21,6 +22,50 @@ static const GrGLShaderVar::Precision kDefaultFragmentPrecision = GrGLShaderVar:
typedef GrGLUniformManager::UniformHandle UniformHandle;
///////////////////////////////////////////////////////////////////////////////
static SkString build_sampler_string(GrGLShaderBuilder::SamplerMode samplerMode) {
SkString sampler("texture2D");
switch (samplerMode) {
case GrGLShaderBuilder::kDefault_SamplerMode:
break;
case GrGLShaderBuilder::kProj_SamplerMode:
sampler.append("Proj");
break;
case GrGLShaderBuilder::kExplicitDivide_SamplerMode:
GrAssert(false); // Not Implemented
break;
}
return sampler;
}
static bool texture_requires_alpha_to_red_swizzle(const GrGLCaps& caps,
const GrTextureAccess& access) {
return GrPixelConfigIsAlphaOnly(access.getTexture()->config()) && caps.textureRedSupport() &&
access.referencesAlpha();
}
static SkString build_swizzle_string(const GrTextureAccess& textureAccess,
const GrGLCaps& caps) {
const GrTextureAccess::Swizzle& swizzle = textureAccess.getSwizzle();
if (0 == swizzle[0]) {
return SkString("");
}
SkString swizzleOut(".");
bool alphaIsRed = texture_requires_alpha_to_red_swizzle(caps, textureAccess);
for (int offset = 0; offset < 4 && swizzle[offset]; ++offset) {
if (alphaIsRed && 'a' == swizzle[offset]) {
swizzleOut.appendf("r");
} else {
swizzleOut.appendf("%c", swizzle[offset]);
}
}
return swizzleOut;
}
///////////////////////////////////////////////////////////////////////////////
// Architectural assumption: always 2-d input coords.
// Likely to become non-constant and non-static, perhaps even
// varying by stage, if we use 1D textures for gradients!
@ -120,6 +165,34 @@ void GrGLShaderBuilder::emitDefaultFetch(const char* outColor,
fFSCode.appendf("%s%s;\n", fSwizzle.c_str(), fModulate.c_str());
}
void GrGLShaderBuilder::emitCustomTextureLookup(SamplerMode samplerMode,
const GrTextureAccess& textureAccess,
const char* samplerName,
const char* coordName) {
GrAssert(samplerName && coordName);
SkString sampler = build_sampler_string(samplerMode);
SkString swizzle = build_swizzle_string(textureAccess, fContext.caps());
fFSCode.appendf("%s( %s, %s)%s;\n", sampler.c_str(), samplerName,
coordName, swizzle.c_str());
}
GrCustomStage::StageKey GrGLShaderBuilder::KeyForTextureAccess(const GrTextureAccess& access,
const GrGLCaps& caps) {
GrCustomStage::StageKey key = 0;
// Assume that swizzle support implies that we never have to modify a shader to adjust
// for texture format/swizzle settings.
if (caps.textureSwizzleSupport()) {
return key;
}
if (texture_requires_alpha_to_red_swizzle(caps, access)) {
key = 1;
}
return key;
}
GrGLUniformManager::UniformHandle GrGLShaderBuilder::addUniformArray(uint32_t visibility,
GrSLType type,
const char* name,

View File

@ -9,6 +9,7 @@
#define GrGLShaderBuilder_DEFINED
#include "GrAllocator.h"
#include "GrCustomStage.h"
#include "gl/GrGLShaderVar.h"
#include "gl/GrGLSL.h"
#include "gl/GrGLUniformManager.h"
@ -55,6 +56,22 @@ public:
void emitDefaultFetch(const char* outColor,
const char* samplerName);
/** Emits a texture lookup to the shader code with the form:
texture2D{Proj}(samplerName, coordName).swizzle
The routine selects the type of texturing based on samplerMode.
The generated swizzle state is built based on the format of the texture and the requested
swizzle access pattern. */
void emitCustomTextureLookup(SamplerMode samplerMode,
const GrTextureAccess& textureAccess,
const char* samplerName,
const char* coordName);
/** Generates a StageKey for the shader code based on the texture access parameters and the
capabilities of the GL context. This is useful for keying the shader programs that may
have multiple representations, based on the type/format of textures used. */
static GrCustomStage::StageKey KeyForTextureAccess(const GrTextureAccess& access,
const GrGLCaps& caps);
/** Add a uniform variable to the current program, that has visibilty in one or more shaders.
visibility is a bitfield of ShaderType values indicating from which shaders the uniform
should be accessible. At least one bit must be set. Geometry shader uniforms are not

View File

@ -596,12 +596,13 @@ namespace {
void setup_custom_stage(GrGLProgram::Desc::StageDesc* stage,
const GrSamplerState& sampler,
const GrGLCaps& caps,
const GrCustomStage** customStages,
GrGLProgram* program, int index) {
const GrCustomStage* customStage = sampler.getCustomStage();
if (customStage) {
const GrProgramStageFactory& factory = customStage->getFactory();
stage->fCustomStageKey = factory.glStageKey(*customStage);
stage->fCustomStageKey = factory.glStageKey(*customStage, caps);
customStages[index] = customStage;
} else {
stage->fCustomStageKey = 0;
@ -746,7 +747,8 @@ void GrGpuGL::buildProgram(bool isPoints,
}
}
setup_custom_stage(&stage, sampler, customStages, fCurrentProgram.get(), s);
setup_custom_stage(&stage, sampler, this->glCaps(), customStages,
fCurrentProgram.get(), s);
} else {
stage.fOptFlags = 0;

View File

@ -413,7 +413,7 @@ bool GrGpuGL::programUnitTest() {
customStages[s].reset(create_random_effect(&stage, &random, getContext()));
if (NULL != customStages[s]) {
stage.fCustomStageKey =
customStages[s]->getFactory().glStageKey(*customStages[s]);
customStages[s]->getFactory().glStageKey(*customStages[s], this->glCaps());
}
}
}