Index: src/gpu/GrGeometryProcessor.cpp |
diff --git a/src/gpu/GrGeometryProcessor.cpp b/src/gpu/GrGeometryProcessor.cpp |
index 6bd6b2b54badd963b3a5794e301476f2a1cb3d48..e8ffc7b3a7880bbc34637b7f66aa034135a69ad2 100644 |
--- a/src/gpu/GrGeometryProcessor.cpp |
+++ b/src/gpu/GrGeometryProcessor.cpp |
@@ -7,8 +7,68 @@ |
#include "GrGeometryProcessor.h" |
-#include "gl/GrGLGeometryProcessor.h" |
+#include "GrCoordTransform.h" |
#include "GrInvariantOutput.h" |
+#include "gl/GrGLGeometryProcessor.h" |
+ |
+/////////////////////////////////////////////////////////////////////////////////////////////////// |
+ |
+/** |
+ * The key for an individual coord transform is made up of a matrix type, a precision, and a bit |
+ * that indicates the source of the input coords. |
+ */ |
+enum { |
+ kMatrixTypeKeyBits = 1, |
+ kMatrixTypeKeyMask = (1 << kMatrixTypeKeyBits) - 1, |
+ |
+ kPrecisionBits = 2, |
+ kPrecisionShift = kMatrixTypeKeyBits, |
+ |
+ kPositionCoords_Flag = (1 << (kPrecisionShift + kPrecisionBits)), |
+ kDeviceCoords_Flag = kPositionCoords_Flag + kPositionCoords_Flag, |
+ |
+ kTransformKeyBits = kMatrixTypeKeyBits + kPrecisionBits + 2, |
+}; |
+ |
+GR_STATIC_ASSERT(kHigh_GrSLPrecision < (1 << kPrecisionBits)); |
+ |
+/** |
+ * We specialize the vertex code for each of these matrix types. |
+ */ |
+enum MatrixType { |
+ kNoPersp_MatrixType = 0, |
+ kGeneral_MatrixType = 1, |
+}; |
+ |
+uint32_t |
+GrPrimitiveProcessor::getTransformKey(const SkTArray<const GrCoordTransform*, true>& coords) const { |
+ uint32_t totalKey = 0; |
+ for (int t = 0; t < coords.count(); ++t) { |
+ uint32_t key = 0; |
+ const GrCoordTransform* coordTransform = coords[t]; |
+ if (coordTransform->getMatrix().hasPerspective()) { |
+ key |= kGeneral_MatrixType; |
+ } else { |
+ key |= kNoPersp_MatrixType; |
+ } |
+ |
+ if (kLocal_GrCoordSet == coordTransform->sourceCoords() && |
+ !this->hasExplicitLocalCoords()) { |
+ key |= kPositionCoords_Flag; |
+ } else if (kDevice_GrCoordSet == coordTransform->sourceCoords()) { |
+ key |= kDeviceCoords_Flag; |
+ } |
+ |
+ GR_STATIC_ASSERT(kGrSLPrecisionCount <= (1 << kPrecisionBits)); |
+ key |= (coordTransform->precision() << kPrecisionShift); |
+ |
+ key <<= kTransformKeyBits * t; |
+ |
+ SkASSERT(0 == (totalKey & key)); // keys for each transform ought not to overlap |
+ totalKey |= key; |
+ } |
+ return totalKey; |
+} |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
@@ -33,11 +93,34 @@ void GrGeometryProcessor::getInvariantOutputCoverage(GrInitInvariantOutput* out) |
#include "gl/builders/GrGLProgramBuilder.h" |
-void GrGLGeometryProcessor::setupColorPassThrough(GrGLGPBuilder* pb, |
- GrGPInput inputType, |
- const char* outputName, |
- const GrGeometryProcessor::GrAttribute* colorAttr, |
- UniformHandle* colorUniform) { |
+SkMatrix GrGLPrimitiveProcessor::GetTransformMatrix(const SkMatrix& localMatrix, |
+ const GrCoordTransform& coordTransform) { |
+ SkMatrix combined; |
+ // We only apply the localmatrix to localcoords |
+ if (kLocal_GrCoordSet == coordTransform.sourceCoords()) { |
+ combined.setConcat(coordTransform.getMatrix(), localMatrix); |
+ } else { |
+ combined = coordTransform.getMatrix(); |
+ } |
+ if (coordTransform.reverseY()) { |
+ // combined.postScale(1,-1); |
+ // combined.postTranslate(0,1); |
+ combined.set(SkMatrix::kMSkewY, |
+ combined[SkMatrix::kMPersp0] - combined[SkMatrix::kMSkewY]); |
+ combined.set(SkMatrix::kMScaleY, |
+ combined[SkMatrix::kMPersp1] - combined[SkMatrix::kMScaleY]); |
+ combined.set(SkMatrix::kMTransY, |
+ combined[SkMatrix::kMPersp2] - combined[SkMatrix::kMTransY]); |
+ } |
+ return combined; |
+} |
+ |
+void |
+GrGLPrimitiveProcessor::setupColorPassThrough(GrGLGPBuilder* pb, |
+ GrGPInput inputType, |
+ const char* outputName, |
+ const GrGeometryProcessor::GrAttribute* colorAttr, |
+ UniformHandle* colorUniform) { |
GrGLGPFragmentBuilder* fs = pb->getFragmentShaderBuilder(); |
if (kUniform_GrGPInput == inputType) { |
SkASSERT(colorUniform); |
@@ -56,15 +139,15 @@ void GrGLGeometryProcessor::setupColorPassThrough(GrGLGPBuilder* pb, |
} |
} |
-void GrGLGeometryProcessor::addUniformViewMatrix(GrGLGPBuilder* pb) { |
+void GrGLPrimitiveProcessor::addUniformViewMatrix(GrGLGPBuilder* pb) { |
fViewMatrixUniform = pb->addUniform(GrGLProgramBuilder::kVertex_Visibility, |
kMat33f_GrSLType, kDefault_GrSLPrecision, |
"uViewM", |
&fViewMatrixName); |
} |
-void GrGLGeometryProcessor::setUniformViewMatrix(const GrGLProgramDataManager& pdman, |
- const SkMatrix& viewMatrix) { |
+void GrGLPrimitiveProcessor::setUniformViewMatrix(const GrGLProgramDataManager& pdman, |
+ const SkMatrix& viewMatrix) { |
if (!fViewMatrix.cheapEqualTo(viewMatrix)) { |
SkASSERT(fViewMatrixUniform.isValid()); |
fViewMatrix = viewMatrix; |
@@ -77,6 +160,98 @@ void GrGLGeometryProcessor::setUniformViewMatrix(const GrGLProgramDataManager& p |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
+ |
+void GrGLGeometryProcessor::emitCode(EmitArgs& args) { |
+ GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder(); |
+ vsBuilder->codeAppendf("vec3 %s;", this->position()); |
+ this->onEmitCode(args); |
+ vsBuilder->transformToNormalizedDeviceSpace(this->position()); |
+} |
+ |
+void GrGLGeometryProcessor::emitTransforms(GrGLGPBuilder* pb, |
+ const char* position, |
+ const char* localCoords, |
+ const SkMatrix& localMatrix, |
+ const TransformsIn& tin, |
+ TransformsOut* tout) { |
+ GrGLVertexBuilder* vb = pb->getVertexShaderBuilder(); |
+ tout->push_back_n(tin.count()); |
+ fInstalledTransforms.push_back_n(tin.count()); |
+ for (int i = 0; i < tin.count(); i++) { |
+ const ProcCoords& coordTransforms = tin[i]; |
+ fInstalledTransforms[i].push_back_n(coordTransforms.count()); |
+ for (int t = 0; t < coordTransforms.count(); t++) { |
+ SkString strUniName("StageMatrix"); |
+ strUniName.appendf("_%i_%i", i, t); |
+ GrSLType varyingType; |
+ |
+ GrCoordSet coordType = coordTransforms[t]->sourceCoords(); |
+ uint32_t type = coordTransforms[t]->getMatrix().getType(); |
+ if (kLocal_GrCoordSet == coordType) { |
+ type |= localMatrix.getType(); |
+ } |
+ varyingType = SkToBool(SkMatrix::kPerspective_Mask & type) ? kVec3f_GrSLType : |
+ kVec2f_GrSLType; |
+ GrSLPrecision precision = coordTransforms[t]->precision(); |
+ |
+ const char* uniName; |
+ fInstalledTransforms[i][t].fHandle = |
+ pb->addUniform(GrGLProgramBuilder::kVertex_Visibility, |
+ kMat33f_GrSLType, precision, |
+ strUniName.c_str(), |
+ &uniName).toShaderBuilderIndex(); |
+ |
+ SkString strVaryingName("MatrixCoord"); |
+ strVaryingName.appendf("_%i_%i", i, t); |
+ |
+ GrGLVertToFrag v(varyingType); |
+ pb->addVarying(strVaryingName.c_str(), &v, precision); |
+ |
+ SkASSERT(kVec2f_GrSLType == varyingType || kVec3f_GrSLType == varyingType); |
+ SkNEW_APPEND_TO_TARRAY(&(*tout)[i], GrGLProcessor::TransformedCoords, |
+ (SkString(v.fsIn()), varyingType)); |
+ |
+ // varying = matrix * coords (logically) |
+ if (kDevice_GrCoordSet == coordType) { |
+ if (kVec2f_GrSLType == varyingType) { |
+ vb->codeAppendf("%s = (%s * %s).xy;", v.vsOut(), uniName, position); |
+ } else { |
+ vb->codeAppendf("%s = %s * %s;", v.vsOut(), uniName, position); |
+ } |
+ } else { |
+ if (kVec2f_GrSLType == varyingType) { |
+ vb->codeAppendf("%s = (%s * vec3(%s, 1)).xy;", v.vsOut(), uniName, localCoords); |
+ } else { |
+ vb->codeAppendf("%s = %s * vec3(%s, 1);", v.vsOut(), uniName, localCoords); |
+ } |
+ } |
+ } |
+ } |
+} |
+ |
+ |
+void |
+GrGLGeometryProcessor::setTransformData(const GrPrimitiveProcessor* primProc, |
+ const GrGLProgramDataManager& pdman, |
+ int index, |
+ const SkTArray<const GrCoordTransform*, true>& transforms) { |
+ SkSTArray<2, Transform, true>& procTransforms = fInstalledTransforms[index]; |
+ int numTransforms = transforms.count(); |
+ for (int t = 0; t < numTransforms; ++t) { |
+ SkASSERT(procTransforms[t].fHandle.isValid()); |
+ const SkMatrix& transform = GetTransformMatrix(primProc->localMatrix(), *transforms[t]); |
+ if (!procTransforms[t].fCurrentValue.cheapEqualTo(transform)) { |
+ pdman.setSkMatrix(procTransforms[t].fHandle.convertToUniformHandle(), transform); |
+ procTransforms[t].fCurrentValue = transform; |
+ } |
+ } |
+} |
+ |
+/////////////////////////////////////////////////////////////////////////////////////////////////// |
+ |
+#include "gl/GrGLGpu.h" |
+#include "gl/GrGLPathRendering.h" |
+ |
struct PathBatchTracker { |
GrGPInput fInputColorType; |
GrGPInput fInputCoverageType; |
@@ -84,58 +259,214 @@ struct PathBatchTracker { |
bool fUsesLocalCoords; |
}; |
-class GrGLPathProcessor : public GrGLGeometryProcessor { |
+GrGLPathProcessor::GrGLPathProcessor(const GrPathProcessor&, const GrBatchTracker&) |
+ : fColor(GrColor_ILLEGAL) {} |
+ |
+void GrGLPathProcessor::emitCode(EmitArgs& args) { |
+ GrGLGPBuilder* pb = args.fPB; |
+ GrGLGPFragmentBuilder* fs = args.fPB->getFragmentShaderBuilder(); |
+ const PathBatchTracker& local = args.fBT.cast<PathBatchTracker>(); |
+ |
+ // emit transforms |
+ this->emitTransforms(args.fPB, args.fTransformsIn, args.fTransformsOut); |
+ |
+ // Setup uniform color |
+ if (kUniform_GrGPInput == local.fInputColorType) { |
+ const char* stagedLocalVarName; |
+ fColorUniform = pb->addUniform(GrGLProgramBuilder::kFragment_Visibility, |
+ kVec4f_GrSLType, |
+ kDefault_GrSLPrecision, |
+ "Color", |
+ &stagedLocalVarName); |
+ fs->codeAppendf("%s = %s;", args.fOutputColor, stagedLocalVarName); |
+ } |
+ |
+ // setup constant solid coverage |
+ if (kAllOnes_GrGPInput == local.fInputCoverageType) { |
+ fs->codeAppendf("%s = vec4(1);", args.fOutputCoverage); |
+ } |
+} |
+ |
+void GrGLPathProcessor::GenKey(const GrPathProcessor&, |
+ const GrBatchTracker& bt, |
+ const GrGLCaps&, |
+ GrProcessorKeyBuilder* b) { |
+ const PathBatchTracker& local = bt.cast<PathBatchTracker>(); |
+ b->add32(local.fInputColorType | local.fInputCoverageType << 16); |
+} |
+ |
+void GrGLPathProcessor::setData(const GrGLProgramDataManager& pdman, |
+ const GrPrimitiveProcessor& primProc, |
+ const GrBatchTracker& bt) { |
+ const PathBatchTracker& local = bt.cast<PathBatchTracker>(); |
+ if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) { |
+ GrGLfloat c[4]; |
+ GrColorToRGBAFloat(local.fColor, c); |
+ pdman.set4fv(fColorUniform, 1, c); |
+ fColor = local.fColor; |
+ } |
+} |
+ |
+class GrGLLegacyPathProcessor : public GrGLPathProcessor { |
public: |
- GrGLPathProcessor(const GrPathProcessor&, const GrBatchTracker&) |
- : fColor(GrColor_ILLEGAL) {} |
- |
- void emitCode(const EmitArgs& args) SK_OVERRIDE { |
- GrGLGPBuilder* pb = args.fPB; |
- GrGLGPFragmentBuilder* fs = args.fPB->getFragmentShaderBuilder(); |
- const PathBatchTracker& local = args.fBT.cast<PathBatchTracker>(); |
- |
- // Setup uniform color |
- if (kUniform_GrGPInput == local.fInputColorType) { |
- const char* stagedLocalVarName; |
- fColorUniform = pb->addUniform(GrGLProgramBuilder::kFragment_Visibility, |
- kVec4f_GrSLType, |
- kDefault_GrSLPrecision, |
- "Color", |
- &stagedLocalVarName); |
- fs->codeAppendf("%s = %s;", args.fOutputColor, stagedLocalVarName); |
+ GrGLLegacyPathProcessor(const GrPathProcessor& pathProc, const GrBatchTracker& bt, |
+ int maxTexCoords) |
+ : INHERITED(pathProc, bt) |
+ , fMaxTexCoords(maxTexCoords) |
+ , fTexCoordSetCnt(0) {} |
+ |
+ int addTexCoordSets(int count) { |
+ int firstFreeCoordSet = fTexCoordSetCnt; |
+ fTexCoordSetCnt += count; |
+ SkASSERT(fMaxTexCoords >= fTexCoordSetCnt); |
+ return firstFreeCoordSet; |
+ } |
+ |
+ void emitTransforms(GrGLGPBuilder*, const TransformsIn& tin, TransformsOut* tout) SK_OVERRIDE { |
+ tout->push_back_n(tin.count()); |
+ fInstalledTransforms.push_back_n(tin.count()); |
+ for (int i = 0; i < tin.count(); i++) { |
+ const ProcCoords& coordTransforms = tin[i]; |
+ int texCoordIndex = this->addTexCoordSets(coordTransforms.count()); |
+ |
+ // Use the first uniform location as the texcoord index. |
+ fInstalledTransforms[i].push_back_n(1); |
+ fInstalledTransforms[i][0].fHandle = ShaderVarHandle(texCoordIndex); |
+ |
+ SkString name; |
+ for (int t = 0; t < coordTransforms.count(); ++t) { |
+ GrSLType type = coordTransforms[t]->getMatrix().hasPerspective() ? kVec3f_GrSLType : |
+ kVec2f_GrSLType; |
+ |
+ name.printf("%s(gl_TexCoord[%i])", GrGLSLTypeString(type), texCoordIndex++); |
+ SkNEW_APPEND_TO_TARRAY(&(*tout)[i], GrGLProcessor::TransformedCoords, (name, type)); |
+ } |
+ } |
+ } |
+ |
+ void setTransformData(const GrPrimitiveProcessor* primProc, |
+ int index, |
+ const SkTArray<const GrCoordTransform*, true>& transforms, |
+ GrGLPathRendering* glpr, |
+ GrGLuint) SK_OVERRIDE { |
+ // We've hidden the texcoord index in the first entry of the transforms array for each |
+ // effect |
+ int texCoordIndex = fInstalledTransforms[index][0].fHandle.handle(); |
+ for (int t = 0; t < transforms.count(); ++t) { |
+ const SkMatrix& transform = GetTransformMatrix(primProc->localMatrix(), *transforms[t]); |
+ GrGLPathRendering::PathTexGenComponents components = |
+ GrGLPathRendering::kST_PathTexGenComponents; |
+ if (transform.hasPerspective()) { |
+ components = GrGLPathRendering::kSTR_PathTexGenComponents; |
+ } |
+ glpr->enablePathTexGen(texCoordIndex++, components, transform); |
} |
+ } |
+ |
+ void didSetData(GrGLPathRendering* glpr) SK_OVERRIDE { |
+ glpr->flushPathTexGenSettings(fTexCoordSetCnt); |
+ } |
+ |
+private: |
+ int fMaxTexCoords; |
+ int fTexCoordSetCnt; |
+ |
+ typedef GrGLPathProcessor INHERITED; |
+}; |
- // setup constant solid coverage |
- if (kAllOnes_GrGPInput == local.fInputCoverageType) { |
- fs->codeAppendf("%s = vec4(1);", args.fOutputCoverage); |
+class GrGLNormalPathProcessor : public GrGLPathProcessor { |
+public: |
+ GrGLNormalPathProcessor(const GrPathProcessor& pathProc, const GrBatchTracker& bt) |
+ : INHERITED(pathProc, bt) {} |
+ |
+ void emitTransforms(GrGLGPBuilder* pb, const TransformsIn& tin, |
+ TransformsOut* tout) SK_OVERRIDE { |
+ tout->push_back_n(tin.count()); |
+ fInstalledTransforms.push_back_n(tin.count()); |
+ for (int i = 0; i < tin.count(); i++) { |
+ const ProcCoords& coordTransforms = tin[i]; |
+ fInstalledTransforms[i].push_back_n(coordTransforms.count()); |
+ for (int t = 0; t < coordTransforms.count(); t++) { |
+ GrSLType varyingType = |
+ coordTransforms[t]->getMatrix().hasPerspective() ? kVec3f_GrSLType : |
+ kVec2f_GrSLType; |
+ |
+ const char* varyingName = "MatrixCoord"; |
+ SkString suffixedVaryingName; |
+ if (0 != t) { |
+ suffixedVaryingName.append(varyingName); |
+ suffixedVaryingName.appendf("_%i", t); |
+ varyingName = suffixedVaryingName.c_str(); |
+ } |
+ GrGLVertToFrag v(varyingType); |
+ pb->addVarying(varyingName, &v); |
+ SeparableVaryingInfo& varyingInfo = fSeparableVaryingInfos.push_back(); |
+ varyingInfo.fVariable = pb->getFragmentShaderBuilder()->fInputs.back(); |
+ varyingInfo.fLocation = fSeparableVaryingInfos.count() - 1; |
+ varyingInfo.fType = varyingType; |
+ fInstalledTransforms[i][t].fHandle = ShaderVarHandle(varyingInfo.fLocation); |
+ fInstalledTransforms[i][t].fType = varyingType; |
+ |
+ SkNEW_APPEND_TO_TARRAY(&(*tout)[i], GrGLProcessor::TransformedCoords, |
+ (SkString(v.fsIn()), varyingType)); |
+ } |
} |
} |
- static inline void GenKey(const GrPathProcessor&, |
- const GrBatchTracker& bt, |
- const GrGLCaps&, |
- GrProcessorKeyBuilder* b) { |
- const PathBatchTracker& local = bt.cast<PathBatchTracker>(); |
- b->add32(local.fInputColorType | local.fInputCoverageType << 16); |
+ void resolveSeparableVaryings(GrGLGpu* gpu, GrGLuint programId) { |
+ int count = fSeparableVaryingInfos.count(); |
+ for (int i = 0; i < count; ++i) { |
+ GrGLint location; |
+ GR_GL_CALL_RET(gpu->glInterface(), |
+ location, |
+ GetProgramResourceLocation(programId, |
+ GR_GL_FRAGMENT_INPUT, |
+ fSeparableVaryingInfos[i].fVariable.c_str())); |
+ fSeparableVaryingInfos[i].fLocation = location; |
+ } |
} |
- void setData(const GrGLProgramDataManager& pdman, |
- const GrPrimitiveProcessor& primProc, |
- const GrBatchTracker& bt) SK_OVERRIDE { |
- const PathBatchTracker& local = bt.cast<PathBatchTracker>(); |
- if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) { |
- GrGLfloat c[4]; |
- GrColorToRGBAFloat(local.fColor, c); |
- pdman.set4fv(fColorUniform, 1, c); |
- fColor = local.fColor; |
+ void setTransformData(const GrPrimitiveProcessor* primProc, |
+ int index, |
+ const SkTArray<const GrCoordTransform*, true>& coordTransforms, |
+ GrGLPathRendering* glpr, |
+ GrGLuint programID) SK_OVERRIDE { |
+ SkSTArray<2, Transform, true>& transforms = fInstalledTransforms[index]; |
+ int numTransforms = transforms.count(); |
+ for (int t = 0; t < numTransforms; ++t) { |
+ SkASSERT(transforms[t].fHandle.isValid()); |
+ const SkMatrix& transform = GetTransformMatrix(primProc->localMatrix(), |
+ *coordTransforms[t]); |
+ if (transforms[t].fCurrentValue.cheapEqualTo(transform)) { |
+ continue; |
+ } |
+ transforms[t].fCurrentValue = transform; |
+ const SeparableVaryingInfo& fragmentInput = |
+ fSeparableVaryingInfos[transforms[t].fHandle.handle()]; |
+ SkASSERT(transforms[t].fType == kVec2f_GrSLType || |
+ transforms[t].fType == kVec3f_GrSLType); |
+ unsigned components = transforms[t].fType == kVec2f_GrSLType ? 2 : 3; |
+ glpr->setProgramPathFragmentInputTransform(programID, |
+ fragmentInput.fLocation, |
+ GR_GL_OBJECT_LINEAR, |
+ components, |
+ transform); |
} |
} |
private: |
- UniformHandle fColorUniform; |
- GrColor fColor; |
+ struct SeparableVaryingInfo { |
+ GrSLType fType; |
+ GrGLShaderVar fVariable; |
+ GrGLint fLocation; |
+ }; |
- typedef GrGLGeometryProcessor INHERITED; |
+ |
+ typedef SkSTArray<8, SeparableVaryingInfo, true> SeparableVaryingInfoArray; |
+ |
+ SeparableVaryingInfoArray fSeparableVaryingInfos; |
+ |
+ typedef GrGLPathProcessor INHERITED; |
}; |
GrPathProcessor::GrPathProcessor(GrColor color, |
@@ -196,6 +527,14 @@ void GrPathProcessor::getGLProcessorKey(const GrBatchTracker& bt, |
GrGLPathProcessor::GenKey(*this, bt, caps, b); |
} |
-GrGLGeometryProcessor* GrPathProcessor::createGLInstance(const GrBatchTracker& bt) const { |
- return SkNEW_ARGS(GrGLPathProcessor, (*this, bt)); |
+GrGLPrimitiveProcessor* GrPathProcessor::createGLInstance(const GrBatchTracker& bt, |
+ const GrGLCaps& caps) const { |
+ SkASSERT(caps.nvprSupport() != GrGLCaps::kNone_NvprSupport); |
+ if (caps.nvprSupport() == GrGLCaps::kLegacy_NvprSupport) { |
+ return SkNEW_ARGS(GrGLLegacyPathProcessor, (*this, bt, |
+ caps.maxFixedFunctionTextureCoords())); |
+ } else { |
+ return SkNEW_ARGS(GrGLNormalPathProcessor, (*this, bt)); |
+ } |
} |
+ |