aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/GrGLProgram.cpp
diff options
context:
space:
mode:
authorGravatar tomhudson@google.com <tomhudson@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-10-25 19:51:09 +0000
committerGravatar tomhudson@google.com <tomhudson@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-10-25 19:51:09 +0000
commit2a2e3ef5b84de3347aedaf1f7dd93cfcdb53d7f1 (patch)
tree8aaa3d79df63356c5473120db87d53f021529e6d /src/gpu/GrGLProgram.cpp
parentc32c9994555aaf3f1ffc4c551ed3b355ce02e840 (diff)
Move helper functions out of header file, write new genProgram helpers.
Review: codereview.appspot.com/5304045/ git-svn-id: http://skia.googlecode.com/svn/trunk@2532 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/gpu/GrGLProgram.cpp')
-rw-r--r--src/gpu/GrGLProgram.cpp445
1 files changed, 237 insertions, 208 deletions
diff --git a/src/gpu/GrGLProgram.cpp b/src/gpu/GrGLProgram.cpp
index 26ada9c988..929ee502b8 100644
--- a/src/gpu/GrGLProgram.cpp
+++ b/src/gpu/GrGLProgram.cpp
@@ -16,6 +16,13 @@
namespace {
+enum {
+ /// Used to mark a StageUniLocation field that should be bound
+ /// to a uniform during getUniformLocationsAndInitCache().
+ kUseUniform = 2000
+};
+
+
const char* GrPrecision(const GrGLInterface* gl) {
if (gl->supportsES()) {
return "mediump";
@@ -541,6 +548,53 @@ bool decl_and_get_fs_color_output(GrGLProgram::GLSLVersion v,
}
}
+void genInputColor(GrGLProgram::ProgramDesc::ColorType colorType,
+ GrGLProgram::CachedData* programData,
+ ShaderCodeSegments* segments,
+ GrStringBuilder* inColor) {
+ switch (colorType) {
+ case GrGLProgram::ProgramDesc::kAttribute_ColorType: {
+ segments->fVSAttrs.push_back().set(GrGLShaderVar::kVec4f_Type,
+ COL_ATTR_NAME);
+ const char *vsName, *fsName;
+ append_varying(GrGLShaderVar::kVec4f_Type, "Color", segments, &vsName, &fsName);
+ segments->fVSCode.appendf("\t%s = " COL_ATTR_NAME ";\n", vsName);
+ *inColor = fsName;
+ } break;
+ case GrGLProgram::ProgramDesc::kUniform_ColorType:
+ segments->fFSUnis.push_back().set(GrGLShaderVar::kVec4f_Type,
+ COL_UNI_NAME);
+ programData->fUniLocations.fColorUni = kUseUniform;
+ *inColor = COL_UNI_NAME;
+ break;
+ case GrGLProgram::ProgramDesc::kTransBlack_ColorType:
+ GrAssert(!"needComputedColor should be false.");
+ break;
+ case GrGLProgram::ProgramDesc::kSolidWhite_ColorType:
+ break;
+ default:
+ GrCrash("Unknown color type.");
+ break;
+ }
+}
+
+void genPerVertexCoverage(ShaderCodeSegments* segments,
+ GrStringBuilder* inCoverage) {
+ segments->fVSAttrs.push_back().set(GrGLShaderVar::kFloat_Type,
+ COV_ATTR_NAME);
+ const char *vsName, *fsName;
+ append_varying(GrGLShaderVar::kFloat_Type, "Coverage",
+ segments, &vsName, &fsName);
+ segments->fVSCode.appendf("\t%s = " COV_ATTR_NAME ";\n", vsName);
+ if (inCoverage->size()) {
+ segments->fFSCode.appendf("\tfloat edgeAndAttrCov = %s * %s;\n",
+ fsName, inCoverage->c_str());
+ *inCoverage = "edgeAndAttrCov";
+ } else {
+ *inCoverage = fsName;
+ }
+}
+
}
void GrGLProgram::genGeometryShader(const GrGLInterface* gl,
@@ -644,30 +698,8 @@ bool GrGLProgram::genProgram(const GrGLInterface* gl,
GrStringBuilder inColor;
if (needComputedColor) {
- switch (fProgramDesc.fColorType) {
- case ProgramDesc::kAttribute_ColorType: {
- segments.fVSAttrs.push_back().set(GrGLShaderVar::kVec4f_Type,
- COL_ATTR_NAME);
- const char *vsName, *fsName;
- append_varying(GrGLShaderVar::kVec4f_Type, "Color", &segments, &vsName, &fsName);
- segments.fVSCode.appendf("\t%s = " COL_ATTR_NAME ";\n", vsName);
- inColor = fsName;
- } break;
- case ProgramDesc::kUniform_ColorType:
- segments.fFSUnis.push_back().set(GrGLShaderVar::kVec4f_Type,
- COL_UNI_NAME);
- programData->fUniLocations.fColorUni = kUseUniform;
- inColor = COL_UNI_NAME;
- break;
- case ProgramDesc::kTransBlack_ColorType:
- GrAssert(!"needComputedColor should be false.");
- break;
- case ProgramDesc::kSolidWhite_ColorType:
- break;
- default:
- GrCrash("Unknown color type.");
- break;
- }
+ genInputColor((ProgramDesc::ColorType) fProgramDesc.fColorType,
+ programData, &segments, &inColor);
}
// we output point size in the GS if present
@@ -714,14 +746,14 @@ bool GrGLProgram::genProgram(const GrGLInterface* gl,
inCoords = texCoordAttrs[tcIdx].c_str();
}
- genStageCode(gl,
- s,
- fProgramDesc.fStages[s],
- inColor.size() ? inColor.c_str() : NULL,
- outColor.c_str(),
- inCoords,
- &segments,
- &programData->fUniLocations.fStages[s]);
+ this->genStageCode(gl,
+ s,
+ fProgramDesc.fStages[s],
+ inColor.size() ? inColor.c_str() : NULL,
+ outColor.c_str(),
+ inCoords,
+ &segments,
+ &programData->fUniLocations.fStages[s]);
inColor = outColor;
}
}
@@ -785,19 +817,7 @@ bool GrGLProgram::genProgram(const GrGLInterface* gl,
// include explicit per-vertex coverage if we have it
if (GrDrawTarget::kCoverage_VertexLayoutBit & layout) {
- segments.fVSAttrs.push_back().set(GrGLShaderVar::kFloat_Type,
- COV_ATTR_NAME);
- const char *vsName, *fsName;
- append_varying(GrGLShaderVar::kFloat_Type, "Coverage",
- &segments, &vsName, &fsName);
- segments.fVSCode.appendf("\t%s = " COV_ATTR_NAME ";\n", vsName);
- if (inCoverage.size()) {
- segments.fFSCode.appendf("\tfloat edgeAndAttrCov = %s * %s;\n",
- fsName, inCoverage.c_str());
- inCoverage = "edgeAndAttrCov";
- } else {
- inCoverage = fsName;
- }
+ genPerVertexCoverage(&segments, &inCoverage);
}
GrStringBuilder outCoverage;
@@ -1287,14 +1307,59 @@ void GrGLProgram::getUniformLocationsAndInitCache(const GrGLInterface* gl,
// Stage code generation
//============================================================================
-static bool genRadial2GradientCoordMapping(int stageNum,
- ShaderCodeSegments* segments,
- const char* radial2VaryingFSName,
- const char* radial2ParamsName,
- GrStringBuilder& sampleCoords,
- GrStringBuilder& fsCoordName,
- int varyingDims,
- int coordDims) {
+namespace {
+
+bool isRadialMapping(GrGLProgram::StageDesc::CoordMapping mapping) {
+ return
+ (GrGLProgram::StageDesc::kRadial2Gradient_CoordMapping == mapping ||
+ GrGLProgram::StageDesc::kRadial2GradientDegenerate_CoordMapping == mapping);
+}
+
+const char* genRadialVS(int stageNum,
+ ShaderCodeSegments* segments,
+ GrGLProgram::StageUniLocations* locations,
+ const char** radial2VaryingVSName,
+ const char** radial2VaryingFSName,
+ const char* varyingVSName,
+ int varyingDims, int coordDims) {
+
+ GrGLShaderVar* radial2FSParams = &segments->fFSUnis.push_back();
+ radial2FSParams->setType(GrGLShaderVar::kFloat_Type);
+ radial2FSParams->setArrayCount(6);
+ radial2_param_name(stageNum, radial2FSParams->accessName());
+ segments->fVSUnis.push_back(*radial2FSParams).setEmitPrecision(true);
+
+ locations->fRadial2Uni = kUseUniform;
+
+ // for radial grads without perspective we can pass the linear
+ // part of the quadratic as a varying.
+ if (varyingDims == coordDims) {
+ GrAssert(2 == coordDims);
+ append_varying(GrGLShaderVar::kFloat_Type,
+ "Radial2BCoeff",
+ stageNum,
+ segments,
+ radial2VaryingVSName,
+ radial2VaryingFSName);
+
+ // r2Var = 2 * (r2Parm[2] * varCoord.x - r2Param[3])
+ const char* r2ParamName = radial2FSParams->getName().c_str();
+ segments->fVSCode.appendf("\t%s = 2.0 *(%s[2] * %s.x - %s[3]);\n",
+ *radial2VaryingVSName, r2ParamName,
+ varyingVSName, r2ParamName);
+ }
+
+ return radial2FSParams->getName().c_str();
+}
+
+bool genRadial2GradientCoordMapping(int stageNum,
+ ShaderCodeSegments* segments,
+ const char* radial2VaryingFSName,
+ const char* radial2ParamsName,
+ GrStringBuilder& sampleCoords,
+ GrStringBuilder& fsCoordName,
+ int varyingDims,
+ int coordDims) {
GrStringBuilder cName("c");
GrStringBuilder ac4Name("ac4");
GrStringBuilder rootName("root");
@@ -1342,14 +1407,14 @@ static bool genRadial2GradientCoordMapping(int stageNum,
return true;
}
-static bool genRadial2GradientDegenerateCoordMapping(int stageNum,
- ShaderCodeSegments* segments,
- const char* radial2VaryingFSName,
- const char* radial2ParamsName,
- GrStringBuilder& sampleCoords,
- GrStringBuilder& fsCoordName,
- int varyingDims,
- int coordDims) {
+bool genRadial2GradientDegenerateCoordMapping(int stageNum,
+ ShaderCodeSegments* segments,
+ const char* radial2VaryingFSName,
+ const char* radial2ParamsName,
+ GrStringBuilder& sampleCoords,
+ GrStringBuilder& fsCoordName,
+ int varyingDims,
+ int coordDims) {
GrStringBuilder cName("c");
cName.appendS32(stageNum);
@@ -1381,6 +1446,106 @@ static bool genRadial2GradientDegenerateCoordMapping(int stageNum,
return true;
}
+void gen2x2FS(int stageNum,
+ ShaderCodeSegments* segments,
+ GrGLProgram::StageUniLocations* locations,
+ GrStringBuilder* sampleCoords,
+ const char* samplerName,
+ const char* texelSizeName,
+ const char* smear,
+ const char* fsOutColor,
+ GrStringBuilder& texFunc,
+ GrStringBuilder& modulate,
+ bool complexCoord,
+ int coordDims) {
+ locations->fNormalizedTexelSizeUni = kUseUniform;
+ if (complexCoord) {
+ // assign the coord to a var rather than compute 4x.
+ GrStringBuilder coordVar("tCoord");
+ coordVar.appendS32(stageNum);
+ segments->fFSCode.appendf("\t%s %s = %s;\n",
+ float_vector_type_str(coordDims),
+ coordVar.c_str(), sampleCoords->c_str());
+ *sampleCoords = coordVar;
+ }
+ GrAssert(2 == coordDims);
+ GrStringBuilder accumVar("accum");
+ accumVar.appendS32(stageNum);
+ segments->fFSCode.appendf("\tvec4 %s = %s(%s, %s + vec2(-%s.x,-%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName, sampleCoords->c_str(), texelSizeName, texelSizeName, smear);
+ segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(+%s.x,-%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName, sampleCoords->c_str(), texelSizeName, texelSizeName, smear);
+ segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(-%s.x,+%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName, sampleCoords->c_str(), texelSizeName, texelSizeName, smear);
+ segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(+%s.x,+%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName, sampleCoords->c_str(), texelSizeName, texelSizeName, smear);
+ segments->fFSCode.appendf("\t%s = .25 * %s%s;\n", fsOutColor, accumVar.c_str(), modulate.c_str());
+
+}
+
+void genConvolutionVS(int stageNum,
+ const GrGLProgram::ProgramDesc::StageDesc& desc,
+ ShaderCodeSegments* segments,
+ GrGLProgram::StageUniLocations* locations,
+ const char** kernelName,
+ const char** imageIncrementName,
+ const char* varyingVSName) {
+ GrGLShaderVar* kernel = &segments->fFSUnis.push_back();
+ kernel->setType(GrGLShaderVar::kFloat_Type);
+ kernel->setArrayCount(desc.fKernelWidth);
+ GrGLShaderVar* imgInc = &segments->fFSUnis.push_back();
+ imgInc->setType(GrGLShaderVar::kVec2f_Type);
+
+ convolve_param_names(stageNum,
+ kernel->accessName(),
+ imgInc->accessName());
+ *kernelName = kernel->getName().c_str();
+ *imageIncrementName = imgInc->getName().c_str();
+
+ // need image increment in both VS and FS
+ segments->fVSUnis.push_back(*imgInc).setEmitPrecision(true);
+
+ locations->fKernelUni = kUseUniform;
+ locations->fImageIncrementUni = kUseUniform;
+ float scale = (desc.fKernelWidth - 1) * 0.5f;
+ segments->fVSCode.appendf("\t%s -= vec2(%g, %g) * %s;\n",
+ varyingVSName, scale, scale,
+ *imageIncrementName);
+}
+
+void genConvolutionFS(int stageNum,
+ const GrGLProgram::ProgramDesc::StageDesc& desc,
+ ShaderCodeSegments* segments,
+ const char* samplerName,
+ const char* kernelName,
+ const char* smear,
+ const char* imageIncrementName,
+ const char* fsOutColor,
+ GrStringBuilder& sampleCoords,
+ GrStringBuilder& texFunc,
+ GrStringBuilder& modulate) {
+ GrStringBuilder sumVar("sum");
+ sumVar.appendS32(stageNum);
+ GrStringBuilder coordVar("coord");
+ coordVar.appendS32(stageNum);
+
+ segments->fFSCode.appendf("\tvec4 %s = vec4(0, 0, 0, 0);\n",
+ sumVar.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);
+ segments->fFSCode.appendf("\t\t%s += %s(%s, %s)%s * %s[i];\n",
+ sumVar.c_str(), texFunc.c_str(),
+ samplerName, coordVar.c_str(), smear,
+ kernelName);
+ 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,
+ sumVar.c_str(), modulate.c_str());
+}
+
+}
+
void GrGLProgram::genStageCode(const GrGLInterface* gl,
int stageNum,
const GrGLProgram::StageDesc& desc,
@@ -1458,21 +1623,20 @@ void GrGLProgram::genStageCode(const GrGLInterface* gl,
const char *radial2VaryingVSName = NULL;
const char *radial2VaryingFSName = NULL;
- if (StageDesc::kRadial2Gradient_CoordMapping == desc.fCoordMapping ||
- StageDesc::kRadial2GradientDegenerate_CoordMapping == desc.fCoordMapping) {
- radial2ParamsName = this->genRadialVS(stageNum, segments,
- locations,
- &radial2VaryingVSName,
- &radial2VaryingFSName,
- varyingVSName,
- varyingDims, coordDims);
+ if (isRadialMapping((StageDesc::CoordMapping) desc.fCoordMapping)) {
+ radial2ParamsName = genRadialVS(stageNum, segments,
+ locations,
+ &radial2VaryingVSName,
+ &radial2VaryingFSName,
+ varyingVSName,
+ varyingDims, coordDims);
}
const char* kernelName = NULL;
const char* imageIncrementName = NULL;
if (ProgramDesc::StageDesc::kConvolution_FetchMode == desc.fFetchMode) {
- this->genConvolutionVS(stageNum, desc, segments, locations,
- &kernelName, &imageIncrementName, varyingVSName);
+ genConvolutionVS(stageNum, desc, segments, locations,
+ &kernelName, &imageIncrementName, varyingVSName);
}
/// Fragment Shader Stuff
@@ -1565,12 +1729,12 @@ void GrGLProgram::genStageCode(const GrGLInterface* gl,
switch (desc.fFetchMode) {
case StageDesc::k2x2_FetchMode:
- this->gen2x2FS(stageNum, segments, locations, &sampleCoords,
+ gen2x2FS(stageNum, segments, locations, &sampleCoords,
samplerName, texelSizeName, smear, fsOutColor,
texFunc, modulate, complexCoord, coordDims);
break;
case ProgramDesc::StageDesc::kConvolution_FetchMode:
- this->genConvolutionFS(stageNum, desc, segments,
+ genConvolutionFS(stageNum, desc, segments,
samplerName, kernelName, smear, imageIncrementName, fsOutColor,
sampleCoords, texFunc, modulate);
break;
@@ -1582,139 +1746,4 @@ void GrGLProgram::genStageCode(const GrGLInterface* gl,
}
}
-const char* GrGLProgram::genRadialVS(int stageNum,
- ShaderCodeSegments* segments,
- StageUniLocations* locations,
- const char** radial2VaryingVSName,
- const char** radial2VaryingFSName,
- const char* varyingVSName,
- int varyingDims, int coordDims) const {
-
- GrGLShaderVar* radial2FSParams = &segments->fFSUnis.push_back();
- radial2FSParams->setType(GrGLShaderVar::kFloat_Type);
- radial2FSParams->setArrayCount(6);
- radial2_param_name(stageNum, radial2FSParams->accessName());
- segments->fVSUnis.push_back(*radial2FSParams).setEmitPrecision(true);
-
- locations->fRadial2Uni = kUseUniform;
-
- // for radial grads without perspective we can pass the linear
- // part of the quadratic as a varying.
- if (varyingDims == coordDims) {
- GrAssert(2 == coordDims);
- append_varying(GrGLShaderVar::kFloat_Type,
- "Radial2BCoeff",
- stageNum,
- segments,
- radial2VaryingVSName,
- radial2VaryingFSName);
-
- // r2Var = 2 * (r2Parm[2] * varCoord.x - r2Param[3])
- const char* r2ParamName = radial2FSParams->getName().c_str();
- segments->fVSCode.appendf("\t%s = 2.0 *(%s[2] * %s.x - %s[3]);\n",
- *radial2VaryingVSName, r2ParamName,
- varyingVSName, r2ParamName);
- }
-
- return radial2FSParams->getName().c_str();
-}
-
-
-void GrGLProgram::gen2x2FS(int stageNum,
- ShaderCodeSegments* segments,
- StageUniLocations* locations,
- GrStringBuilder* sampleCoords,
- const char* samplerName,
- const char* texelSizeName,
- const char* smear,
- const char* fsOutColor,
- GrStringBuilder& texFunc,
- GrStringBuilder& modulate,
- bool complexCoord,
- int coordDims) const {
- locations->fNormalizedTexelSizeUni = kUseUniform;
- if (complexCoord) {
- // assign the coord to a var rather than compute 4x.
- GrStringBuilder coordVar("tCoord");
- coordVar.appendS32(stageNum);
- segments->fFSCode.appendf("\t%s %s = %s;\n",
- float_vector_type_str(coordDims),
- coordVar.c_str(), sampleCoords->c_str());
- *sampleCoords = coordVar;
- }
- GrAssert(2 == coordDims);
- GrStringBuilder accumVar("accum");
- accumVar.appendS32(stageNum);
- segments->fFSCode.appendf("\tvec4 %s = %s(%s, %s + vec2(-%s.x,-%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName, sampleCoords->c_str(), texelSizeName, texelSizeName, smear);
- segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(+%s.x,-%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName, sampleCoords->c_str(), texelSizeName, texelSizeName, smear);
- segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(-%s.x,+%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName, sampleCoords->c_str(), texelSizeName, texelSizeName, smear);
- segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(+%s.x,+%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName, sampleCoords->c_str(), texelSizeName, texelSizeName, smear);
- segments->fFSCode.appendf("\t%s = .25 * %s%s;\n", fsOutColor, accumVar.c_str(), modulate.c_str());
-
-}
-
-void GrGLProgram::genConvolutionVS(int stageNum,
- const ProgramDesc::StageDesc& desc,
- ShaderCodeSegments* segments,
- StageUniLocations* locations,
- const char** kernelName,
- const char** imageIncrementName,
- const char* varyingVSName) const {
- GrGLShaderVar* kernel = &segments->fFSUnis.push_back();
- kernel->setType(GrGLShaderVar::kFloat_Type);
- kernel->setArrayCount(desc.fKernelWidth);
- GrGLShaderVar* imgInc = &segments->fFSUnis.push_back();
- imgInc->setType(GrGLShaderVar::kVec2f_Type);
-
- convolve_param_names(stageNum,
- kernel->accessName(),
- imgInc->accessName());
- *kernelName = kernel->getName().c_str();
- *imageIncrementName = imgInc->getName().c_str();
-
- // need image increment in both VS and FS
- segments->fVSUnis.push_back(*imgInc).setEmitPrecision(true);
-
- locations->fKernelUni = kUseUniform;
- locations->fImageIncrementUni = kUseUniform;
- float scale = (desc.fKernelWidth - 1) * 0.5f;
- segments->fVSCode.appendf("\t%s -= vec2(%g, %g) * %s;\n",
- varyingVSName, scale, scale,
- *imageIncrementName);
-}
-
-void GrGLProgram::genConvolutionFS(int stageNum,
- const ProgramDesc::StageDesc& desc,
- ShaderCodeSegments* segments,
- const char* samplerName,
- const char* kernelName,
- const char* smear,
- const char* imageIncrementName,
- const char* fsOutColor,
- GrStringBuilder& sampleCoords,
- GrStringBuilder& texFunc,
- GrStringBuilder& modulate) const {
- GrStringBuilder sumVar("sum");
- sumVar.appendS32(stageNum);
- GrStringBuilder coordVar("coord");
- coordVar.appendS32(stageNum);
-
- segments->fFSCode.appendf("\tvec4 %s = vec4(0, 0, 0, 0);\n",
- sumVar.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);
- segments->fFSCode.appendf("\t\t%s += %s(%s, %s)%s * %s[i];\n",
- sumVar.c_str(), texFunc.c_str(),
- samplerName, coordVar.c_str(), smear,
- kernelName);
- 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,
- sumVar.c_str(), modulate.c_str());
-}