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.
*/
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);
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;
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.
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));
protected:
GrTProgramStageFactory() {
- fStageClassID = GenID() << kProgramStageKeyBits;
+ fStageClassID = GenID() << (kProgramStageKeyBits + kTexturingStageKeyBits) ;
}
};
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&,
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();
}
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:
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:
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:
const GrRenderTarget*,
int stageNum) SK_OVERRIDE;
- static StageKey GenKey(const GrCustomStage& s);
+ static StageKey GenKey(const GrCustomStage& s, const GrGLCaps& caps);
protected:
}
}
-GrCustomStage::StageKey GrGLConical2Gradient::GenKey(const GrCustomStage& s) {
+GrCustomStage::StageKey GrGLConical2Gradient::GenKey(const GrCustomStage& s, const GrGLCaps& caps) {
return (static_cast<const GrConical2Gradient&>(s).isDegenerate());
}
return NULL;
}
-#endif
\ No newline at end of file
+#endif
const GrRenderTarget*,
int stageNum) SK_OVERRIDE;
- static StageKey GenKey(const GrCustomStage& s);
+ static StageKey GenKey(const GrCustomStage& s, const GrGLCaps& caps);
protected:
}
}
-GrCustomStage::StageKey GrGLRadial2Gradient::GenKey(const GrCustomStage& s) {
+GrCustomStage::StageKey GrGLRadial2Gradient::GenKey(const GrCustomStage& s, const GrGLCaps& caps) {
return (static_cast<const GrRadial2Gradient&>(s).isDegenerate());
}
#include "GrContext.h"
#include "GrCustomStage.h"
#include "GrMemoryPool.h"
+#include "SkString.h"
#include "SkTLS.h"
SK_DEFINE_INST_COUNT(GrCustomStage)
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() {
}
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);
}
void GrCustomStage::operator delete(void* target) {
GrCustomStage_Globals::GetTLS()->release(target);
}
-
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() {
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;
+}
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
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); }
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();
}
this->direction() == s.direction() &&
0 == memcmp(fKernel, s.fKernel, this->width() * sizeof(float)));
}
-
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&,
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);
builder->emitDefaultFetch(outputColor, samplerName);
}
- static inline StageKey GenKey(const GrCustomStage&) { return 0; }
+ static inline StageKey GenKey(const GrCustomStage&, const GrGLCaps&) { return 0; }
private:
const GrProgramStageFactory& GrSingleTextureEffect::getFactory() const {
return GrTProgramStageFactory<GrSingleTextureEffect>::getInstance();
}
-
-
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;
const GrTextureDomainEffect& s = static_cast<const GrTextureDomainEffect&>(sBase);
return (INHERITED::isEqual(sBase) && this->fTextureDomain == s.fTextureDomain);
}
-
-
/** 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);
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;
+}
const char* name() const { return fFactory.name(); }
+ static StageKey GenTextureKey(const GrCustomStage&, const GrGLCaps&);
+
protected:
const GrProgramStageFactory& fFactory;
#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;
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!
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,
#define GrGLShaderBuilder_DEFINED
#include "GrAllocator.h"
+#include "GrCustomStage.h"
#include "gl/GrGLShaderVar.h"
#include "gl/GrGLSL.h"
#include "gl/GrGLUniformManager.h"
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
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;
}
}
- setup_custom_stage(&stage, sampler, customStages, fCurrentProgram.get(), s);
+ setup_custom_stage(&stage, sampler, this->glCaps(), customStages,
+ fCurrentProgram.get(), s);
} else {
stage.fOptFlags = 0;
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());
}
}
}