Erode and dilate image filter effects, CPU and GPU implementations.
Review URL: http://codereview.appspot.com/5656067/
git-svn-id: http://skia.googlecode.com/svn/trunk@3310 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index 7eecf91..2925213 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -166,6 +166,11 @@
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);
@@ -1655,6 +1660,68 @@
segments->fFSCode.appendf("\t%s = %s%s;\n", fsOutColor,
sumVar.c_str(), modulate.c_str());
}
+
+void genMorphologyVS(int stageNum,
+ const StageDesc& desc,
+ ShaderCodeSegments* segments,
+ GrGLProgram::StageUniLocations* locations,
+ const char** imageIncrementName,
+ const char* varyingVSName) {
+ GrGLShaderVar* imgInc = &segments->fFSUnis.push_back();
+ imgInc->setType(GrGLShaderVar::kVec2f_Type);
+ imgInc->setTypeModifier(GrGLShaderVar::kUniform_TypeModifier);
+
+ image_increment_param_name(stageNum, imgInc->accessName());
+ *imageIncrementName = imgInc->getName().c_str();
+
+ // need image increment in both VS and FS
+ segments->fVSUnis.push_back(*imgInc).setEmitPrecision(true);
+
+ 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,
+ ShaderCodeSegments* segments,
+ const char* samplerName,
+ const char* swizzle,
+ const char* imageIncrementName,
+ const char* fsOutColor,
+ GrStringBuilder& sampleCoords,
+ GrStringBuilder& texFunc,
+ GrStringBuilder& modulate) {
+ 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(),
+ sampleCoords.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(), swizzle);
+ 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(), modulate.c_str());
+}
}
@@ -1755,6 +1822,10 @@
if (StageDesc::kConvolution_FetchMode == desc.fFetchMode) {
genConvolutionVS(stageNum, desc, segments, locations,
&kernel, &imageIncrementName, varyingVSName);
+ } else if (StageDesc::kDilate_FetchMode == desc.fFetchMode ||
+ StageDesc::kErode_FetchMode == desc.fFetchMode) {
+ genMorphologyVS(stageNum, desc, segments, locations,
+ &imageIncrementName, varyingVSName);
}
/// Fragment Shader Stuff
@@ -1866,6 +1937,13 @@
samplerName, kernel, swizzle, imageIncrementName, fsOutColor,
sampleCoords, texFunc, modulate);
break;
+ case StageDesc::kDilate_FetchMode:
+ case StageDesc::kErode_FetchMode:
+ GrAssert(!(desc.fInConfigFlags & kMulByAlphaMask));
+ genMorphologyFS(stageNum, desc, segments,
+ samplerName, swizzle, imageIncrementName, fsOutColor,
+ sampleCoords, texFunc, modulate);
+ 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 e9030bc..76f9c90 100644
--- a/src/gpu/gl/GrGLProgram.h
+++ b/src/gpu/gl/GrGLProgram.h
@@ -110,6 +110,8 @@
kSingle_FetchMode,
k2x2_FetchMode,
kConvolution_FetchMode,
+ kErode_FetchMode,
+ kDilate_FetchMode,
kFetchModeCnt,
};
diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp
index bee2017..69880e5 100644
--- a/src/gpu/gl/GrGpuGL.cpp
+++ b/src/gpu/gl/GrGpuGL.cpp
@@ -445,7 +445,7 @@
-GR_ScalarMax,
true);
*fHWDrawState.sampler(s)->matrix() = GrMatrix::InvalidMatrix();
- fHWDrawState.sampler(s)->setConvolutionParams(0, NULL, NULL);
+ fHWDrawState.sampler(s)->setConvolutionParams(0, NULL);
}
fHWBounds.fScissorRect.invalidate();
@@ -1935,6 +1935,8 @@
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/GrGpuGLShaders.cpp b/src/gpu/gl/GrGpuGLShaders.cpp
index a0a2df5..db7e3a7 100644
--- a/src/gpu/gl/GrGpuGLShaders.cpp
+++ b/src/gpu/gl/GrGpuGLShaders.cpp
@@ -261,7 +261,9 @@
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) {
+ 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));
@@ -273,6 +275,8 @@
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;
@@ -560,7 +564,20 @@
}
int imageIncrementUni = fProgramData->fUniLocations.fStages[s].fImageIncrementUni;
if (GrGLProgram::kUnusedUniform != imageIncrementUni) {
- GL_CALL(Uniform2fv(imageIncrementUni, 1, sampler.getImageIncrement()));
+ 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));
}
}
@@ -1081,6 +1098,12 @@
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;
@@ -1119,7 +1142,9 @@
}
}
- if (sampler.getFilter() == GrSamplerState::kConvolution_Filter) {
+ if (sampler.getFilter() == GrSamplerState::kConvolution_Filter ||
+ sampler.getFilter() == GrSamplerState::kDilate_Filter ||
+ sampler.getFilter() == GrSamplerState::kErode_Filter) {
stage.fKernelWidth = sampler.getKernelWidth();
} else {
stage.fKernelWidth = 0;