diff options
Diffstat (limited to 'src/gpu/GrGeometryProcessor.cpp')
-rw-r--r-- | src/gpu/GrGeometryProcessor.cpp | 439 |
1 files changed, 389 insertions, 50 deletions
diff --git a/src/gpu/GrGeometryProcessor.cpp b/src/gpu/GrGeometryProcessor.cpp index 6bd6b2b54b..e8ffc7b3a7 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)); + } } + |