Implement morphology as a custom effect
Review URL: http://codereview.appspot.com/6250073/
git-svn-id: http://skia.googlecode.com/svn/trunk@4102 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index 9a78a6e..a49aa61 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -95,18 +95,6 @@
s->appendS32(stage);
}
-inline void convolve_param_names(int stage, GrStringBuilder* k, GrStringBuilder* i) {
- *k = "uKernel";
- k->appendS32(stage);
- *i = "uImageIncrement";
- i->appendS32(stage);
-}
-
-inline void image_increment_param_name(int stage, GrStringBuilder* i) {
- *i = "uImageIncrement";
- i->appendS32(stage);
-}
-
inline void tex_domain_name(int stage, GrStringBuilder* s) {
*s = "uTexDom";
s->appendS32(stage);
@@ -629,7 +617,7 @@
const GrProgramStageFactory& factory =
customStages[s]->getFactory();
programData->fCustomStage[s] =
- factory.createGLInstance(customStages[s]);
+ factory.createGLInstance(*customStages[s]);
}
this->genStageCode(gl,
s,
@@ -752,7 +740,7 @@
const GrProgramStageFactory& factory =
customStages[s]->getFactory();
programData->fCustomStage[s] =
- factory.createGLInstance(customStages[s]);
+ factory.createGLInstance(*customStages[s]);
}
this->genStageCode(gl, s,
fProgramDesc.fStages[s],
@@ -1186,21 +1174,6 @@
GrAssert(kUnusedUniform != locations.fTexDomUni);
}
- GrStringBuilder kernelName, imageIncrementName;
- convolve_param_names(s, &kernelName, &imageIncrementName);
- if (kUseUniform == locations.fKernelUni) {
- GL_CALL_RET(locations.fKernelUni,
- GetUniformLocation(progID, kernelName.c_str()));
- GrAssert(kUnusedUniform != locations.fKernelUni);
- }
-
- if (kUseUniform == locations.fImageIncrementUni) {
- GL_CALL_RET(locations.fImageIncrementUni,
- GetUniformLocation(progID,
- imageIncrementName.c_str()));
- GrAssert(kUnusedUniform != locations.fImageIncrementUni);
- }
-
if (NULL != programData->fCustomStage[s]) {
programData->fCustomStage[s]->
initUniforms(gl.interface(), progID);
@@ -1411,65 +1384,6 @@
}
-void genMorphologyVS(int stageNum,
- const StageDesc& desc,
- GrGLShaderBuilder* segments,
- GrGLProgram::StageUniLocations* locations,
- const char** imageIncrementName,
- const char* varyingVSName) {
-
- GrStringBuilder iiName;
- image_increment_param_name(stageNum, &iiName);
- const GrGLShaderVar* imgInc =
- &segments->addUniform(
- GrGLShaderBuilder::kBoth_VariableLifetime, kVec2f_GrSLType,
- iiName.c_str());
- *imageIncrementName = imgInc->getName().c_str();
-
- locations->fImageIncrementUni = kUseUniform;
- segments->fVSCode.appendf("\t%s -= vec2(%d, %d) * %s;\n",
- varyingVSName, desc.fKernelWidth,
- desc.fKernelWidth, *imageIncrementName);
-}
-
-void genMorphologyFS(int stageNum,
- const StageDesc& desc,
- GrGLShaderBuilder* segments,
- const char* samplerName,
- const char* imageIncrementName,
- const char* fsOutColor,
- GrStringBuilder& texFunc) {
- GrStringBuilder valueVar("value");
- valueVar.appendS32(stageNum);
- GrStringBuilder coordVar("coord");
- coordVar.appendS32(stageNum);
- bool isDilate = StageDesc::kDilate_FetchMode == desc.fFetchMode;
-
- if (isDilate) {
- segments->fFSCode.appendf("\tvec4 %s = vec4(0, 0, 0, 0);\n",
- valueVar.c_str());
- } else {
- segments->fFSCode.appendf("\tvec4 %s = vec4(1, 1, 1, 1);\n",
- valueVar.c_str());
- }
- segments->fFSCode.appendf("\tvec2 %s = %s;\n",
- coordVar.c_str(),
- segments->fSampleCoords.c_str());
- segments->fFSCode.appendf("\tfor (int i = 0; i < %d; i++) {\n",
- desc.fKernelWidth * 2 + 1);
- segments->fFSCode.appendf("\t\t%s = %s(%s, %s(%s, %s)%s);\n",
- valueVar.c_str(), isDilate ? "max" : "min",
- valueVar.c_str(), texFunc.c_str(),
- samplerName, coordVar.c_str(),
- segments->fSwizzle.c_str());
- segments->fFSCode.appendf("\t\t%s += %s;\n",
- coordVar.c_str(),
- imageIncrementName);
- segments->fFSCode.appendf("\t}\n");
- segments->fFSCode.appendf("\t%s = %s%s;\n", fsOutColor,
- valueVar.c_str(), segments->fModulate.c_str());
-}
-
}
void GrGLProgram::genStageCode(const GrGLContextInfo& gl,
@@ -1562,12 +1476,6 @@
GrGLShaderVar* kernel = NULL;
const char* imageIncrementName = NULL;
- if (StageDesc::kDilate_FetchMode == desc.fFetchMode ||
- StageDesc::kErode_FetchMode == desc.fFetchMode) {
- genMorphologyVS(stageNum, desc, segments, locations,
- &imageIncrementName, varyingVSName);
- }
-
if (NULL != customStage) {
segments->fVSCode.appendf("\t{ // stage %d %s\n",
stageNum, customStage->name());
@@ -1677,15 +1585,6 @@
gen2x2FS(stageNum, segments, locations,
samplerName.c_str(), texelSizeName, fsOutColor, texFunc);
break;
- case StageDesc::kConvolution_FetchMode:
- GrAssert(!(desc.fInConfigFlags & kMulByAlphaMask));
- break;
- case StageDesc::kDilate_FetchMode:
- case StageDesc::kErode_FetchMode:
- GrAssert(!(desc.fInConfigFlags & kMulByAlphaMask));
- genMorphologyFS(stageNum, desc, segments,
- samplerName.c_str(), imageIncrementName, fsOutColor, texFunc);
- break;
default:
if (desc.fInConfigFlags & kMulByAlphaMask) {
// only one of the mul by alpha flags should be set
diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h
index 189e876..bfb1f1c 100644
--- a/src/gpu/gl/GrGLProgram.h
+++ b/src/gpu/gl/GrGLProgram.h
@@ -106,13 +106,10 @@
kCustomTextureDomain_OptFlagBit = 1 << 2,
kIsEnabled_OptFlagBit = 1 << 7
};
- // Convolution is obsolete; left in for testing only
+
enum FetchMode {
kSingle_FetchMode,
k2x2_FetchMode,
- kConvolution_FetchMode,
- kErode_FetchMode,
- kDilate_FetchMode,
kFetchModeCnt,
};
@@ -179,7 +176,6 @@
uint8_t fInConfigFlags; // bitfield of InConfigFlags values
uint8_t fFetchMode; // casts to enum FetchMode
uint8_t fCoordMapping; // casts to enum CoordMapping
- uint8_t fKernelWidth;
/** Non-zero if user-supplied code will write the stage's
contribution to the fragment shader. */
@@ -268,16 +264,12 @@
GrGLint fSamplerUni;
GrGLint fRadial2Uni;
GrGLint fTexDomUni;
- GrGLint fKernelUni;
- GrGLint fImageIncrementUni;
void reset() {
fTextureMatrixUni = kUnusedUniform;
fNormalizedTexelSizeUni = kUnusedUniform;
fSamplerUni = kUnusedUniform;
fRadial2Uni = kUnusedUniform;
fTexDomUni = kUnusedUniform;
- fKernelUni = kUnusedUniform;
- fImageIncrementUni = kUnusedUniform;
}
};
diff --git a/src/gpu/gl/GrGLProgramStage.cpp b/src/gpu/gl/GrGLProgramStage.cpp
index 70d1186..487b468 100644
--- a/src/gpu/gl/GrGLProgramStage.cpp
+++ b/src/gpu/gl/GrGLProgramStage.cpp
@@ -25,11 +25,9 @@
}
-void GrGLProgramStage::setData(const GrGLInterface*,
- const GrGLTexture&,
- GrCustomStage*,
+void GrGLProgramStage::setData(const GrGLInterface*,
+ const GrGLTexture&,
+ const GrCustomStage&,
int stageNum) {
-
-
}
diff --git a/src/gpu/gl/GrGLProgramStage.h b/src/gpu/gl/GrGLProgramStage.h
index 52d7200..e10d13b 100644
--- a/src/gpu/gl/GrGLProgramStage.h
+++ b/src/gpu/gl/GrGLProgramStage.h
@@ -32,7 +32,12 @@
class GrGLProgramStage {
public:
- typedef GrCustomStage::StageKey StageKey ;
+ typedef GrCustomStage::StageKey StageKey;
+ enum {
+ // the number of bits in StageKey available to GenKey
+ kProgramStageKeyBits = GrProgramStageFactory::kProgramStageKeyBits,
+ };
+
// TODO: redundant with GrGLProgram.cpp
enum {
kUnusedUniform = -1,
@@ -79,7 +84,7 @@
created in emit*(). */
virtual void setData(const GrGLInterface* gl,
const GrGLTexture& texture,
- GrCustomStage* stage,
+ const GrCustomStage& stage,
int stageNum);
const char* name() const { return fFactory.name(); }
diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp
index 8b28c9f..29c7900 100644
--- a/src/gpu/gl/GrGpuGL.cpp
+++ b/src/gpu/gl/GrGpuGL.cpp
@@ -2102,9 +2102,6 @@
case GrSamplerState::k4x4Downsample_Filter:
return GR_GL_LINEAR;
case GrSamplerState::kNearest_Filter:
- case GrSamplerState::kConvolution_Filter:
- case GrSamplerState::kErode_Filter:
- case GrSamplerState::kDilate_Filter:
return GR_GL_NEAREST;
default:
GrAssert(!"Unknown filter type");
diff --git a/src/gpu/gl/GrGpuGL_program.cpp b/src/gpu/gl/GrGpuGL_program.cpp
index 2ac26d5..2448fa4 100644
--- a/src/gpu/gl/GrGpuGL_program.cpp
+++ b/src/gpu/gl/GrGpuGL_program.cpp
@@ -7,8 +7,10 @@
#include "GrGpuGL.h"
-#include "GrBinHashKey.h"
#include "effects/GrConvolutionEffect.h"
+#include "effects/GrMorphologyEffect.h"
+
+#include "GrBinHashKey.h"
#include "GrCustomStage.h"
#include "GrGLProgramStage.h"
#include "GrGLSL.h"
@@ -176,6 +178,75 @@
return r->nextF() > .5f;
}
+typedef GrGLProgram::StageDesc StageDesc;
+// TODO: Effects should be able to register themselves for inclusion in the
+// randomly generated shaders. They should be able to configure themselves
+// randomly.
+GrCustomStage* create_random_effect(StageDesc* stageDesc,
+ GrRandom* random) {
+ enum EffectType {
+ kConvolution_EffectType,
+ kErode_EffectType,
+ kDilate_EffectType,
+
+ kEffectCount
+ };
+
+ // TODO: Remove this when generator doesn't apply this non-custom-stage
+ // notion to custom stages automatically.
+ static const uint32_t kMulByAlphaMask =
+ StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag |
+ StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag;
+
+ static const Gr1DKernelEffect::Direction gKernelDirections[] = {
+ Gr1DKernelEffect::kX_Direction,
+ Gr1DKernelEffect::kY_Direction
+ };
+
+ // TODO: When matrices are property of the custom-stage then remove the
+ // no-persp flag code below.
+ int effect = random_int(random, kEffectCount);
+ switch (effect) {
+ case kConvolution_EffectType: {
+ int direction = random_int(random, 2);
+ int kernelRadius = random_int(random, 1, 4);
+ float kernel[GrConvolutionEffect::kMaxKernelWidth];
+ for (int i = 0; i < GrConvolutionEffect::kMaxKernelWidth; i++) {
+ kernel[i] = random->nextF();
+ }
+ // does not work with perspective or mul-by-alpha-mask
+ stageDesc->fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
+ stageDesc->fInConfigFlags &= ~kMulByAlphaMask;
+ return new GrConvolutionEffect(gKernelDirections[direction],
+ kernelRadius,
+ kernel);
+ }
+ case kErode_EffectType: {
+ int direction = random_int(random, 2);
+ int kernelRadius = random_int(random, 1, 4);
+ // does not work with perspective or mul-by-alpha-mask
+ stageDesc->fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
+ stageDesc->fInConfigFlags &= ~kMulByAlphaMask;
+ return new GrMorphologyEffect(gKernelDirections[direction],
+ kernelRadius,
+ GrContext::kErode_MorphologyType);
+ }
+ case kDilate_EffectType: {
+ int direction = random_int(random, 2);
+ int kernelRadius = random_int(random, 1, 4);
+ // does not work with perspective or mul-by-alpha-mask
+ stageDesc->fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
+ stageDesc->fInConfigFlags &= ~kMulByAlphaMask;
+ return new GrMorphologyEffect(gKernelDirections[direction],
+ kernelRadius,
+ GrContext::kDilate_MorphologyType);
+ }
+ default:
+ GrCrash("Unexpected custom effect type");
+ }
+ return NULL;
+}
+
}
bool GrGpuGL::programUnitTest() {
@@ -250,7 +321,7 @@
pdesc.fDualSrcOutput = ProgramDesc::kNone_DualSrcOutput;
}
- GrCustomStage* customStages[GrDrawState::kNumStages];
+ SkAutoTUnref<GrCustomStage> customStages[GrDrawState::kNumStages];
for (int s = 0; s < GrDrawState::kNumStages; ++s) {
// enable the stage?
@@ -270,56 +341,34 @@
StageDesc& stage = pdesc.fStages[s];
stage.fCustomStageKey = 0;
- customStages[s] = NULL;
stage.fOptFlags = STAGE_OPTS[random_int(&random, GR_ARRAY_COUNT(STAGE_OPTS))];
stage.fInConfigFlags = IN_CONFIG_FLAGS[random_int(&random, GR_ARRAY_COUNT(IN_CONFIG_FLAGS))];
stage.fCoordMapping = random_int(&random, StageDesc::kCoordMappingCnt);
stage.fFetchMode = random_int(&random, StageDesc::kFetchModeCnt);
- // convolution shaders don't work with persp tex matrix
- if (stage.fFetchMode == StageDesc::kConvolution_FetchMode ||
- stage.fFetchMode == StageDesc::kDilate_FetchMode ||
- stage.fFetchMode == StageDesc::kErode_FetchMode) {
- stage.fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
- }
stage.setEnabled(VertexUsesStage(s, pdesc.fVertexLayout));
static const uint32_t kMulByAlphaMask =
StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag |
StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag;
- switch (stage.fFetchMode) {
- case StageDesc::kSingle_FetchMode:
- stage.fKernelWidth = 0;
- break;
- case StageDesc::kConvolution_FetchMode:
- case StageDesc::kDilate_FetchMode:
- case StageDesc::kErode_FetchMode:
- stage.fKernelWidth = random_int(&random, 2, 8);
- stage.fInConfigFlags &= ~kMulByAlphaMask;
- break;
- case StageDesc::k2x2_FetchMode:
- stage.fKernelWidth = 0;
- stage.fInConfigFlags &= ~kMulByAlphaMask;
- break;
+ if (StageDesc::k2x2_FetchMode == stage.fFetchMode) {
+ stage.fInConfigFlags &= ~kMulByAlphaMask;
}
- // TODO: is there a more elegant way to express this?
- if (stage.fFetchMode == StageDesc::kConvolution_FetchMode) {
- int direction = random_int(&random, 2);
- float kernel[MAX_KERNEL_WIDTH];
- for (int i = 0; i < stage.fKernelWidth; i++) {
- kernel[i] = random.nextF();
+ bool useCustomEffect = random_bool(&random);
+ if (useCustomEffect) {
+ customStages[s].reset(create_random_effect(&stage, &random));
+ if (NULL != customStages[s]) {
+ stage.fCustomStageKey =
+ customStages[s]->getFactory().glStageKey(*customStages[s]);
}
- customStages[s] = new GrConvolutionEffect(
- (GrSamplerState::FilterDirection)direction,
- stage.fKernelWidth, kernel);
- stage.fCustomStageKey =
- customStages[s]->getFactory().glStageKey(customStages[s]);
}
}
CachedData cachedData;
- if (!program.genProgram(this->glContextInfo(), customStages,
- &cachedData)) {
+ GR_STATIC_ASSERT(sizeof(customStages) ==
+ GrDrawState::kNumStages * sizeof(GrCustomStage*));
+ GrCustomStage** stages = reinterpret_cast<GrCustomStage**>(&customStages);
+ if (!program.genProgram(this->glContextInfo(), stages, &cachedData)) {
return false;
}
DeleteProgram(this->glInterface(), &cachedData);
@@ -469,32 +518,6 @@
}
}
-void GrGpuGL::flushConvolution(int s) {
- const GrSamplerState& sampler = this->getDrawState().getSampler(s);
- int kernelUni = fProgramData->fUniLocations.fStages[s].fKernelUni;
- if (GrGLProgram::kUnusedUniform != kernelUni) {
- GL_CALL(Uniform1fv(kernelUni, sampler.getKernelWidth(),
- sampler.getKernel()));
- }
- int imageIncrementUni = fProgramData->fUniLocations.fStages[s].fImageIncrementUni;
- if (GrGLProgram::kUnusedUniform != imageIncrementUni) {
- const GrGLTexture* texture =
- static_cast<const GrGLTexture*>(this->getDrawState().getTexture(s));
- float imageIncrement[2] = { 0 };
- switch (sampler.getFilterDirection()) {
- case GrSamplerState::kX_FilterDirection:
- imageIncrement[0] = 1.0f / texture->width();
- break;
- case GrSamplerState::kY_FilterDirection:
- imageIncrement[1] = 1.0f / texture->height();
- break;
- default:
- GrCrash("Unknown filter direction.");
- }
- GL_CALL(Uniform2fv(imageIncrementUni, 1, imageIncrement));
- }
-}
-
void GrGpuGL::flushTexelSize(int s) {
const int& uni = fProgramData->fUniLocations.fStages[s].fNormalizedTexelSizeUni;
if (GrGLProgram::kUnusedUniform != uni) {
@@ -692,8 +715,6 @@
this->flushRadial2(s);
- this->flushConvolution(s);
-
this->flushTexelSize(s);
this->flushTextureDomain(s);
@@ -706,7 +727,7 @@
this->getDrawState().getTexture(s));
fProgramData->fCustomStage[s]->setData(
this->glInterface(), *texture,
- sampler.getCustomStage(), s);
+ *sampler.getCustomStage(), s);
}
}
}
@@ -875,7 +896,7 @@
GrCustomStage* customStage = sampler.getCustomStage();
if (customStage) {
const GrProgramStageFactory& factory = customStage->getFactory();
- stage->fCustomStageKey = factory.glStageKey(customStage);
+ stage->fCustomStageKey = factory.glStageKey(*customStage);
customStages[index] = customStage;
} else {
stage->fCustomStageKey = 0;
@@ -1027,16 +1048,6 @@
case GrSamplerState::k4x4Downsample_Filter:
stage.fFetchMode = StageDesc::k2x2_FetchMode;
break;
- // performs fKernelWidth texture2D()s
- case GrSamplerState::kConvolution_Filter:
- stage.fFetchMode = StageDesc::kConvolution_FetchMode;
- break;
- case GrSamplerState::kDilate_Filter:
- stage.fFetchMode = StageDesc::kDilate_FetchMode;
- break;
- case GrSamplerState::kErode_Filter:
- stage.fFetchMode = StageDesc::kErode_FetchMode;
- break;
default:
GrCrash("Unexpected filter!");
break;
@@ -1083,13 +1094,6 @@
}
}
- if (sampler.getFilter() == GrSamplerState::kDilate_Filter ||
- sampler.getFilter() == GrSamplerState::kErode_Filter) {
- stage.fKernelWidth = sampler.getKernelWidth();
- } else {
- stage.fKernelWidth = 0;
- }
-
setup_custom_stage(&stage, sampler, customStages,
&fCurrentProgram, s);
@@ -1098,7 +1102,6 @@
stage.fCoordMapping = (StageDesc::CoordMapping) 0;
stage.fInConfigFlags = 0;
stage.fFetchMode = (StageDesc::FetchMode) 0;
- stage.fKernelWidth = 0;
stage.fCustomStageKey = 0;
customStages[s] = NULL;
}