GPU-based Gaussian blur.
This is a first stab at implementing a GPU-based
Gaussian blur in Ganesh. The convolution shader is implemented as a new
filtering mode. There are several known issues:
- no support for blur types other than "normal"
- FBO truncation problem at high zoom values
- uses bilinear for upsampling instead of Mitchell
Review URL: http://codereview.appspot.com/4645082/
git-svn-id: http://skia.googlecode.com/svn/trunk@1830 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/src/GrGLProgram.cpp b/gpu/src/GrGLProgram.cpp
index d6a832c..4290c96 100644
--- a/gpu/src/GrGLProgram.cpp
+++ b/gpu/src/GrGLProgram.cpp
@@ -136,6 +136,13 @@
s->appendS32(stage);
}
+static void convolve_param_names(int stage, GrStringBuilder* k, GrStringBuilder* i) {
+ *k = "uKernel";
+ k->appendS32(stage);
+ *i = "uImageIncrement";
+ i->appendS32(stage);
+}
+
static void tex_domain_name(int stage, GrStringBuilder* s) {
*s = "uTexDom";
s->appendS32(stage);
@@ -941,6 +948,22 @@
texDomName.c_str()));
GrAssert(kUnusedUniform != locations.fTexDomUni);
}
+
+ GrStringBuilder kernelName, imageIncrementName;
+ convolve_param_names(s, &kernelName, &imageIncrementName);
+ if (kUseUniform == locations.fKernelUni) {
+ locations.fKernelUni = GR_GL(GetUniformLocation(
+ progID,
+ kernelName.c_str()));
+ GrAssert(kUnusedUniform != locations.fKernelUni);
+ }
+
+ if (kUseUniform == locations.fImageIncrementUni) {
+ locations.fImageIncrementUni = GR_GL(GetUniformLocation(
+ progID,
+ imageIncrementName.c_str()));
+ GrAssert(kUnusedUniform != locations.fImageIncrementUni);
+ }
}
}
GR_GL(UseProgram(progID));
@@ -1058,6 +1081,24 @@
}
}
+ GrStringBuilder kernelName, kernelWidthName, imageIncrementName;
+ convolve_param_names(stageNum, &kernelName, &imageIncrementName);
+
+ if (ProgramDesc::StageDesc::kConvolution_FetchMode == desc.fFetchMode) {
+ segments->fFSUnis.appendf("uniform float %s[%d];\n",
+ kernelName.c_str(), desc.fKernelWidth);
+ segments->fFSUnis.appendf("uniform vec2 %s;\n",
+ imageIncrementName.c_str());
+ segments->fVSUnis.appendf("uniform vec2 %s;\n",
+ imageIncrementName.c_str());
+ locations->fKernelUni = kUseUniform;
+ locations->fImageIncrementUni = kUseUniform;
+ float scale = (desc.fKernelWidth - 1) * 0.5f;
+ segments->fVSCode.appendf("\t%s -= vec2(%g, %g) * %s;\n",
+ varyingName.c_str(), scale, scale,
+ imageIncrementName.c_str());
+}
+
/// Fragment Shader Stuff
GrStringBuilder fsCoordName;
// function used to access the shader, may be made projective
@@ -1229,6 +1270,17 @@
segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(-%s.x,+%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), texelSizeName.c_str(), texelSizeName.c_str(), smear);
segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(+%s.x,+%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), texelSizeName.c_str(), texelSizeName.c_str(), smear);
segments->fFSCode.appendf("\t%s = .25 * %s%s;\n", fsOutColor, accumVar.c_str(), modulate.c_str());
+ } else if (ProgramDesc::StageDesc::kConvolution_FetchMode == desc.fFetchMode) {
+ segments->fFSCode.append("\tvec4 sum = vec4(0, 0, 0, 0);\n");
+ segments->fFSCode.appendf("\tvec2 coord = %s;\n", sampleCoords.c_str());
+ segments->fFSCode.appendf("\tfor (int i = 0; i < %d; i++) {\n", desc.fKernelWidth);
+ segments->fFSCode.appendf("\t\tsum += %s(%s, coord)%s * %s[i];\n",
+ texFunc.c_str(), samplerName.c_str(),
+ smear, kernelName.c_str());
+ segments->fFSCode.appendf("\t\tcoord += %s;\n",
+ imageIncrementName.c_str());
+ segments->fFSCode.appendf("\t}\n");
+ segments->fFSCode.appendf("\t%s = sum%s;\n", fsOutColor, modulate.c_str());
} else {
segments->fFSCode.appendf("\t%s = %s(%s, %s)%s%s;\n", fsOutColor, texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), smear, modulate.c_str());
}