GrGLSLGP performs pre-order traversal to determine FP varyings.
The traversal examines sample usage during descent and tracks the last matrix sample usage encountered. Each FP that uses coords directly gets a varying inserted at the position of the last matrix sample usage encountered. Whether a starting perspective coord or perspective matrix is encountered is also tracked on the stack, removing the need for a FP flag to track this. Bug: skia:12198 Change-Id: I9f6302c1c2b6619b67a0d6ee1697d6e971560a15 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/433359 Commit-Queue: Brian Salomon <bsalomon@google.com> Reviewed-by: Michael Ludwig <michaelludwig@google.com>
This commit is contained in:
parent
e0531f50e3
commit
880bb534a0
@ -154,7 +154,7 @@ void GrFragmentProcessor::registerChild(std::unique_ptr<GrFragmentProcessor> chi
|
||||
// The child should not have been attached to another FP already and not had any sampling
|
||||
// strategy set on it.
|
||||
SkASSERT(!child->fParent && !child->sampleUsage().isSampled() &&
|
||||
!child->isSampledWithExplicitCoords() && !child->hasPerspectiveTransform());
|
||||
!child->isSampledWithExplicitCoords());
|
||||
|
||||
// Configure child's sampling state first
|
||||
child->fUsage = sampleUsage;
|
||||
@ -163,11 +163,6 @@ void GrFragmentProcessor::registerChild(std::unique_ptr<GrFragmentProcessor> chi
|
||||
child->addAndPushFlagToChildren(kSampledWithExplicitCoords_Flag);
|
||||
}
|
||||
|
||||
// Push perspective matrix type to children
|
||||
if (sampleUsage.fHasPerspective) {
|
||||
child->addAndPushFlagToChildren(kNetTransformHasPerspective_Flag);
|
||||
}
|
||||
|
||||
// Propagate the "will read dest-color" flag up to parent FPs.
|
||||
if (child->willReadDstColor()) {
|
||||
this->setWillReadDstColor();
|
||||
@ -193,8 +188,7 @@ void GrFragmentProcessor::registerChild(std::unique_ptr<GrFragmentProcessor> chi
|
||||
fChildProcessors.push_back(std::move(child));
|
||||
|
||||
// Validate: our sample strategy comes from a parent we shouldn't have yet.
|
||||
SkASSERT(!this->isSampledWithExplicitCoords() && !this->hasPerspectiveTransform() &&
|
||||
!fUsage.isSampled() && !fParent);
|
||||
SkASSERT(!this->isSampledWithExplicitCoords() && !fUsage.isSampled() && !fParent);
|
||||
}
|
||||
|
||||
void GrFragmentProcessor::cloneAndRegisterAllChildProcessors(const GrFragmentProcessor& src) {
|
||||
|
@ -206,8 +206,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
int numVaryingCoordsUsed() const { return this->usesVaryingCoordsDirectly() ? 1 : 0; }
|
||||
|
||||
int numChildProcessors() const { return fChildProcessors.count(); }
|
||||
int numNonNullChildProcessors() const;
|
||||
|
||||
@ -267,17 +265,11 @@ public:
|
||||
return SkToBool(fFlags & kUsesSampleCoordsDirectly_Flag);
|
||||
}
|
||||
|
||||
// True if this FP's parent invokes it with 'sample(float2)' or a variable 'sample(matrix)'
|
||||
// True if this FP's parent invokes it with 'sample(float2)'
|
||||
bool isSampledWithExplicitCoords() const {
|
||||
return SkToBool(fFlags & kSampledWithExplicitCoords_Flag);
|
||||
}
|
||||
|
||||
// True if the transform chain from root to this FP introduces perspective into the local
|
||||
// coordinate expression.
|
||||
bool hasPerspectiveTransform() const {
|
||||
return SkToBool(fFlags & kNetTransformHasPerspective_Flag);
|
||||
}
|
||||
|
||||
// The SampleUsage describing how this FP is invoked by its parent using 'sample(matrix)'
|
||||
// This only reflects the immediate sampling from parent to this FP
|
||||
const SkSL::SampleUsage& sampleUsage() const {
|
||||
@ -521,7 +513,6 @@ private:
|
||||
|
||||
// Propagates down the FP to all its leaves
|
||||
kSampledWithExplicitCoords_Flag = kFirstPrivateFlag << 3,
|
||||
kNetTransformHasPerspective_Flag = kFirstPrivateFlag << 4,
|
||||
|
||||
// Propagates up the FP tree to the root
|
||||
kWillReadDstColor_Flag = kFirstPrivateFlag << 5,
|
||||
|
@ -42,10 +42,10 @@ void GrGLSLFPFragmentBuilder::writeProcessorFunction(GrGLSLFragmentProcessor* fp
|
||||
params[numParams++] = GrShaderVar(args.fSampleCoord, kFloat2_GrSLType);
|
||||
|
||||
} else if (args.fFp.referencesSampleCoords()) {
|
||||
// Sampled with a uniform matrix expression and/or a legacy coord transform. The actual
|
||||
// transformation code is emitted in the vertex shader, so this only has to access it.
|
||||
// Add a float2 _coords variable that maps to the associated varying and replaces the
|
||||
// absent 2nd argument to the fp's function.
|
||||
// Sampled through a chain of passthrough/matrix samples usages. The actual transformation
|
||||
// code is emitted in the vertex shader, so this only has to access it. Add a float2 _coords
|
||||
// variable that maps to the associated varying and replaces the absent 2nd argument to the
|
||||
// fp's function.
|
||||
GrShaderVar varying = fProgramBuilder->varyingCoordsForFragmentProcessor(&args.fFp);
|
||||
switch(varying.getType()) {
|
||||
case kFloat2_GrSLType:
|
||||
|
@ -15,9 +15,11 @@
|
||||
#include "src/gpu/glsl/GrGLSLVarying.h"
|
||||
#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
|
||||
|
||||
#include <queue>
|
||||
|
||||
GrGLSLGeometryProcessor::FPToVaryingCoordsMap GrGLSLGeometryProcessor::emitCode(
|
||||
EmitArgs& args,
|
||||
GrFragmentProcessor::CIter fpIter) {
|
||||
const GrPipeline& pipeline) {
|
||||
GrGPArgs gpArgs;
|
||||
this->onEmitCode(args, &gpArgs);
|
||||
|
||||
@ -27,7 +29,7 @@ GrGLSLGeometryProcessor::FPToVaryingCoordsMap GrGLSLGeometryProcessor::emitCode(
|
||||
args.fVaryingHandler,
|
||||
args.fUniformHandler,
|
||||
gpArgs.fLocalCoordVar,
|
||||
fpIter);
|
||||
pipeline);
|
||||
}
|
||||
|
||||
if (args.fGeomProc.willUseTessellationShaders()) {
|
||||
@ -78,168 +80,169 @@ GrGLSLGeometryProcessor::FPToVaryingCoordsMap GrGLSLGeometryProcessor::collectTr
|
||||
GrGLSLVaryingHandler* varyingHandler,
|
||||
GrGLSLUniformHandler* uniformHandler,
|
||||
const GrShaderVar& localCoordsVar,
|
||||
GrFragmentProcessor::CIter fpIter) {
|
||||
const GrPipeline& pipeline) {
|
||||
SkASSERT(localCoordsVar.getType() == kFloat2_GrSLType ||
|
||||
localCoordsVar.getType() == kFloat3_GrSLType);
|
||||
// Cached varyings produced by parent FPs. If parent FPs introduce transformations, but all
|
||||
// subsequent children are not transformed, they should share the same varying.
|
||||
std::unordered_map<const GrFragmentProcessor*, GrShaderVar> localCoordsMap;
|
||||
|
||||
GrGLSLVarying baseLocalCoord;
|
||||
auto getBaseLocalCoord = [&baseLocalCoord, &localCoordsVar, vb, varyingHandler]() {
|
||||
auto baseLocalCoordVarying = [&, baseLocalCoord = GrGLSLVarying()]() mutable {
|
||||
SkASSERT(GrSLTypeIsFloatType(localCoordsVar.getType()));
|
||||
if (baseLocalCoord.type() == kVoid_GrSLType) {
|
||||
// Initialize to the GP provided coordinate
|
||||
SkString baseLocalCoordName = SkStringPrintf("LocalCoord");
|
||||
baseLocalCoord = GrGLSLVarying(localCoordsVar.getType());
|
||||
varyingHandler->addVarying(baseLocalCoordName.c_str(), &baseLocalCoord);
|
||||
vb->codeAppendf("%s = %s;\n", baseLocalCoord.vsOut(),
|
||||
localCoordsVar.getName().c_str());
|
||||
vb->codeAppendf("%s = %s;\n", baseLocalCoord.vsOut(), localCoordsVar.getName().c_str());
|
||||
}
|
||||
return baseLocalCoord.fsInVar();
|
||||
};
|
||||
|
||||
FPToVaryingCoordsMap result;
|
||||
for (int i = 0; fpIter; ++fpIter, ++i) {
|
||||
const auto& fp = *fpIter;
|
||||
|
||||
if (!fp.usesVaryingCoordsDirectly()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// FPs that use local coordinates need a varying to convey the coordinate. This may be the
|
||||
// base GP's local coord if transforms have to be computed in the FS, or it may be a unique
|
||||
// varying that computes the equivalent transformation hierarchy in the VS.
|
||||
GrShaderVar varyingVar;
|
||||
|
||||
// The FP's local coordinates are determined by the uniform transform hierarchy
|
||||
// from this FP to the root, and can be computed in the vertex shader.
|
||||
// If this hierarchy would be the identity transform, then we should use the
|
||||
// original local coordinate.
|
||||
// NOTE: The actual transform logic is handled in emitTransformCode(), this just
|
||||
// needs to determine if a unique varying should be added for the FP.
|
||||
GrShaderVar transformedLocalCoord;
|
||||
const GrFragmentProcessor* coordOwner = nullptr;
|
||||
|
||||
const GrFragmentProcessor* node = &fp;
|
||||
while(node) {
|
||||
SkASSERT(!node->isSampledWithExplicitCoords());
|
||||
|
||||
if (node->sampleUsage().isUniformMatrix()) {
|
||||
// We can stop once we hit an FP that adds transforms; this FP can reuse
|
||||
// that FPs varying (possibly vivifying it if this was the first use).
|
||||
transformedLocalCoord = localCoordsMap[node];
|
||||
coordOwner = node;
|
||||
// Performs a pre-order traversal of FP hierarchy rooted at fp and identifies FPs that are
|
||||
// sampled with a series of matrices applied to local coords. For each such FP a varying is
|
||||
// added to the varying handler and added to 'result'.
|
||||
auto liftTransforms = [&, traversalIndex = 0](auto& self,
|
||||
const GrFragmentProcessor& fp,
|
||||
bool hasPerspective,
|
||||
const GrFragmentProcessor* lastMatrixFP = nullptr,
|
||||
int lastMatrixTraversalIndex = -1) mutable {
|
||||
++traversalIndex;
|
||||
switch (fp.sampleUsage().fKind) {
|
||||
case SkSL::SampleUsage::Kind::kNone:
|
||||
// This should only happen at the root. Otherwise how did this FP get added?
|
||||
SkASSERT(!fp.parent());
|
||||
break;
|
||||
} // else intervening FP is an identity transform so skip past it
|
||||
|
||||
node = node->parent();
|
||||
case SkSL::SampleUsage::Kind::kPassThrough:
|
||||
break;
|
||||
case SkSL::SampleUsage::Kind::kUniformMatrix:
|
||||
// Update tracking of last matrix and matrix props.
|
||||
hasPerspective |= fp.sampleUsage().fHasPerspective;
|
||||
lastMatrixFP = &fp;
|
||||
lastMatrixTraversalIndex = traversalIndex;
|
||||
break;
|
||||
case SkSL::SampleUsage::Kind::kExplicit:
|
||||
// Nothing in this subtree can be lifted.
|
||||
return;
|
||||
}
|
||||
|
||||
if (coordOwner) {
|
||||
// The FP will use coordOwner's varying; add varying if this was the first use
|
||||
if (transformedLocalCoord.getType() == kVoid_GrSLType) {
|
||||
GrGLSLVarying v(kFloat2_GrSLType);
|
||||
if (GrSLTypeVecLength(localCoordsVar.getType()) == 3 ||
|
||||
coordOwner->hasPerspectiveTransform()) {
|
||||
v = GrGLSLVarying(kFloat3_GrSLType);
|
||||
if (fp.usesVaryingCoordsDirectly()) {
|
||||
// Associate the varying with the highest possible node in the FP tree that shares the
|
||||
// same coordinates so that multiple FPs in a subtree can share. If there are no matrix
|
||||
// sample nodes on the way up the tree then directly use the local coord.
|
||||
if (!lastMatrixFP) {
|
||||
result[&fp] = baseLocalCoordVarying();
|
||||
} else {
|
||||
// If there is an already a varying that incorporates all matrices from the root to
|
||||
// lastMatrixFP just use it. Otherwise, we add it.
|
||||
auto& [varying, localCoord, varyingIdx] = fTransformVaryingsMap[lastMatrixFP];
|
||||
if (varying.type() == kVoid_GrSLType) {
|
||||
varying = GrGLSLVarying(hasPerspective ? kFloat3_GrSLType : kFloat2_GrSLType);
|
||||
SkString strVaryingName = SkStringPrintf("TransformedCoords_%d",
|
||||
lastMatrixTraversalIndex);
|
||||
varyingHandler->addVarying(strVaryingName.c_str(), &varying);
|
||||
localCoord = localCoordsVar;
|
||||
varyingIdx = lastMatrixTraversalIndex;
|
||||
}
|
||||
SkString strVaryingName;
|
||||
strVaryingName.printf("TransformedCoords_%d", i);
|
||||
varyingHandler->addVarying(strVaryingName.c_str(), &v);
|
||||
|
||||
fTransformInfos.push_back({v.vsOutVar(), localCoordsVar, coordOwner});
|
||||
transformedLocalCoord = v.fsInVar();
|
||||
localCoordsMap[coordOwner] = transformedLocalCoord;
|
||||
SkASSERT(varyingIdx == lastMatrixTraversalIndex);
|
||||
// The FP will use the varying in the fragment shader as its coords.
|
||||
result[&fp] = varying.fsInVar();
|
||||
}
|
||||
|
||||
varyingVar = transformedLocalCoord;
|
||||
} else {
|
||||
// The FP transform hierarchy is the identity, so use the original local coord
|
||||
varyingVar = getBaseLocalCoord();
|
||||
} else if (!fp.usesVaryingCoords()) {
|
||||
// Early-out. No point in continuing to traversal down from here.
|
||||
return;
|
||||
}
|
||||
|
||||
SkASSERT(varyingVar.getType() != kVoid_GrSLType);
|
||||
result[&fp] = varyingVar;
|
||||
for (int c = 0; c < fp.numChildProcessors(); ++c) {
|
||||
if (auto child = fp.childProcessor(c)) {
|
||||
self(self, *child, hasPerspective, lastMatrixFP, lastMatrixTraversalIndex);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
bool hasPerspective = GrSLTypeVecLength(localCoordsVar.getType()) == 3;
|
||||
for (int i = 0; i < pipeline.numFragmentProcessors(); ++i) {
|
||||
liftTransforms(liftTransforms, pipeline.getFragmentProcessor(i), hasPerspective);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void GrGLSLGeometryProcessor::emitTransformCode(GrGLSLVertexBuilder* vb,
|
||||
GrGLSLUniformHandler* uniformHandler) {
|
||||
std::unordered_map<const GrFragmentProcessor*, GrShaderVar> localCoordsMap;
|
||||
for (const auto& tr : fTransformInfos) {
|
||||
// Because descendant varyings may be computed using the varyings of ancestor FPs we make
|
||||
// sure to visit the varyings according to FP pre-order traversal by dumping them into a
|
||||
// priority queue.
|
||||
using FPAndInfo = std::tuple<const GrFragmentProcessor*, TransformInfo>;
|
||||
auto compare = [](const FPAndInfo& a, const FPAndInfo& b) {
|
||||
return std::get<1>(a).traversalOrder > std::get<1>(b).traversalOrder;
|
||||
};
|
||||
std::priority_queue<FPAndInfo, std::vector<FPAndInfo>, decltype(compare)> pq(compare);
|
||||
std::for_each(fTransformVaryingsMap.begin(), fTransformVaryingsMap.end(), [&pq](auto entry) {
|
||||
pq.push(entry);
|
||||
});
|
||||
for (; !pq.empty(); pq.pop()) {
|
||||
const auto& [fp, info] = pq.top();
|
||||
// If we recorded a transform info, its sample matrix must be uniform
|
||||
SkASSERT(tr.fFP->sampleUsage().isUniformMatrix());
|
||||
SkASSERT(fp->sampleUsage().isUniformMatrix());
|
||||
GrShaderVar uniform = uniformHandler->liftUniformToVertexShader(
|
||||
*fp->parent(), SkString(SkSL::SampleUsage::MatrixUniformName()));
|
||||
// Start with this matrix and accumulate additional matrices as we walk up the FP tree
|
||||
// to either the base coords or an ancestor FP that has an associated varying.
|
||||
SkString transformExpression = uniform.getName();
|
||||
|
||||
SkString localCoords;
|
||||
// Build a concatenated matrix expression that we apply to the root local coord.
|
||||
// If we have an expression cached from an early FP in the hierarchy chain, we can stop
|
||||
// there instead of going all the way to the GP.
|
||||
SkString transformExpression;
|
||||
// If we hit an ancestor with a varying on our walk up then save off the varying as the
|
||||
// input to our accumulated transformExpression. Start off assuming we'll reach the root.
|
||||
GrShaderVar inputCoords = info.localCoords;
|
||||
|
||||
const auto* base = tr.fFP;
|
||||
while(base) {
|
||||
GrShaderVar cachedBaseCoord = localCoordsMap[base];
|
||||
if (cachedBaseCoord.getType() != kVoid_GrSLType) {
|
||||
for (const auto* base = fp->parent(); base; base = base->parent()) {
|
||||
if (auto iter = fTransformVaryingsMap.find(base); iter != fTransformVaryingsMap.end()) {
|
||||
// Can stop here, as this varying already holds all transforms from higher FPs
|
||||
if (cachedBaseCoord.getType() == kFloat3_GrSLType) {
|
||||
localCoords = cachedBaseCoord.getName();
|
||||
} else {
|
||||
localCoords = SkStringPrintf("%s.xy1", cachedBaseCoord.getName().c_str());
|
||||
}
|
||||
// We'll apply the residual transformExpression we've accumulated up from our
|
||||
// starting FP to this varying.
|
||||
inputCoords = iter->second.varying.vsOutVar();
|
||||
break;
|
||||
} else if (base->sampleUsage().isUniformMatrix()) {
|
||||
// The matrix expression is always the same, but the parent defined the uniform
|
||||
// Accumulate any matrices along the path to either the original local coords or
|
||||
// a parent varying. Getting here means this FP was sampled with a uniform matrix
|
||||
// but all uses of coords below here in the FP hierarchy are beneath additional
|
||||
// matrix samples and thus this node wasn't assigned a varying.
|
||||
GrShaderVar uniform = uniformHandler->liftUniformToVertexShader(
|
||||
*base->parent(), SkString(SkSL::SampleUsage::MatrixUniformName()));
|
||||
SkASSERT(uniform.getType() == kFloat3x3_GrSLType);
|
||||
|
||||
// Accumulate the base matrix expression as a preConcat
|
||||
if (!transformExpression.isEmpty()) {
|
||||
transformExpression.append(" * ");
|
||||
}
|
||||
transformExpression.appendf("(%s)", uniform.getName().c_str());
|
||||
transformExpression.appendf(" * %s", uniform.getName().c_str());
|
||||
} else {
|
||||
// This intermediate FP is just a pass through and doesn't need to be built
|
||||
// in to the expression, but must visit its parents in case they add transforms
|
||||
// in to the expression, but we must visit its parents in case they add transforms.
|
||||
SkASSERT(base->sampleUsage().isPassThrough() || !base->sampleUsage().isSampled());
|
||||
}
|
||||
|
||||
base = base->parent();
|
||||
}
|
||||
|
||||
if (localCoords.isEmpty()) {
|
||||
// Must use GP's local coords
|
||||
if (tr.fLocalCoords.getType() == kFloat3_GrSLType) {
|
||||
localCoords = tr.fLocalCoords.getName();
|
||||
} else {
|
||||
localCoords = SkStringPrintf("%s.xy1", tr.fLocalCoords.getName().c_str());
|
||||
}
|
||||
SkString inputStr;
|
||||
if (inputCoords.getType() == kFloat2_GrSLType) {
|
||||
inputStr = SkStringPrintf("%s.xy1", inputCoords.getName().c_str());
|
||||
} else {
|
||||
SkASSERT(inputCoords.getType() == kFloat3_GrSLType);
|
||||
inputStr = inputCoords.getName();
|
||||
}
|
||||
|
||||
vb->codeAppend("{\n");
|
||||
if (tr.fOutputCoords.getType() == kFloat2_GrSLType) {
|
||||
if (info.varying.type() == kFloat2_GrSLType) {
|
||||
if (vb->getProgramBuilder()->shaderCaps()->nonsquareMatrixSupport()) {
|
||||
vb->codeAppendf("%s = float3x2(%s) * %s", tr.fOutputCoords.getName().c_str(),
|
||||
vb->codeAppendf("%s = float3x2(%s) * %s", info.varying.vsOut(),
|
||||
transformExpression.c_str(),
|
||||
localCoords.c_str());
|
||||
inputStr.c_str());
|
||||
} else {
|
||||
vb->codeAppendf("%s = ((%s) * %s).xy", tr.fOutputCoords.getName().c_str(),
|
||||
transformExpression.c_str(),
|
||||
localCoords.c_str());
|
||||
vb->codeAppendf("%s = (%s * %s).xy", info.varying.vsOut(),
|
||||
transformExpression.c_str(),
|
||||
inputStr.c_str());
|
||||
}
|
||||
} else {
|
||||
SkASSERT(tr.fOutputCoords.getType() == kFloat3_GrSLType);
|
||||
vb->codeAppendf("%s = (%s) * %s", tr.fOutputCoords.getName().c_str(),
|
||||
transformExpression.c_str(),
|
||||
localCoords.c_str());
|
||||
SkASSERT(info.varying.type() == kFloat3_GrSLType);
|
||||
vb->codeAppendf("%s = %s * %s", info.varying.vsOut(),
|
||||
transformExpression.c_str(),
|
||||
inputStr.c_str());
|
||||
}
|
||||
vb->codeAppend(";\n");
|
||||
vb->codeAppend("}\n");
|
||||
|
||||
localCoordsMap.insert({ tr.fFP, tr.fOutputCoords });
|
||||
}
|
||||
// We don't need this map anymore.
|
||||
fTransformVaryingsMap.clear();
|
||||
}
|
||||
|
||||
void GrGLSLGeometryProcessor::setupUniformColor(GrGLSLFPFragmentBuilder* fragBuilder,
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "src/gpu/GrShaderCaps.h"
|
||||
#include "src/gpu/glsl/GrGLSLProgramDataManager.h"
|
||||
#include "src/gpu/glsl/GrGLSLUniformHandler.h"
|
||||
#include "src/gpu/glsl/GrGLSLVarying.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
@ -72,11 +73,11 @@ public:
|
||||
};
|
||||
|
||||
/**
|
||||
* Emits the code from this geometry processor into the shaders. For any FP that has its input
|
||||
* coords implemented by the GP as a varying, the varying will be accessible in the returned
|
||||
* map and should be used when the FP code is emitted.
|
||||
* Emits the code from this geometry processor into the shaders. For any FP in the pipeline that
|
||||
* has its input coords implemented by the GP as a varying, the varying will be accessible in
|
||||
* the returned map and should be used when the FP code is emitted.
|
||||
**/
|
||||
FPToVaryingCoordsMap emitCode(EmitArgs&, GrFragmentProcessor::CIter);
|
||||
FPToVaryingCoordsMap emitCode(EmitArgs&, const GrPipeline& pipeline);
|
||||
|
||||
/**
|
||||
* Called after all effect emitCode() functions, to give the processor a chance to write out
|
||||
@ -214,19 +215,20 @@ private:
|
||||
GrGLSLVaryingHandler* varyingHandler,
|
||||
GrGLSLUniformHandler* uniformHandler,
|
||||
const GrShaderVar& localCoordsVar,
|
||||
GrFragmentProcessor::CIter);
|
||||
|
||||
const GrPipeline& pipeline);
|
||||
struct TransformInfo {
|
||||
// The vertex-shader output variable to assign the transformed coordinates to
|
||||
GrShaderVar fOutputCoords;
|
||||
// The coordinate to be transformed
|
||||
GrShaderVar fLocalCoords;
|
||||
// The leaf FP of a transform hierarchy to be evaluated in the vertex shader;
|
||||
// this FP will be const-uniform sampled, and all of its parents will have a sample matrix
|
||||
// type of none or const-uniform.
|
||||
const GrFragmentProcessor* fFP;
|
||||
// The varying that conveys the coordinates to one or more FPs in the FS.
|
||||
GrGLSLVarying varying;
|
||||
// The coordinate to be transformed. varying is computed from this.
|
||||
GrShaderVar localCoords;
|
||||
// Used to sort so that ancestor FP varyings are initialized before descendant FP varyings.
|
||||
int traversalOrder;
|
||||
};
|
||||
SkTArray<TransformInfo> fTransformInfos;
|
||||
// Populated by collectTransforms() for use in emitTransformCode(). When we lift the computation
|
||||
// of a FP's input coord to a varying we propagate that varying up the FP tree to the highest
|
||||
// node that shares the same coordinates. This allows multiple FPs in a subtree to share a
|
||||
// varying.
|
||||
std::unordered_map<const GrFragmentProcessor*, TransformInfo> fTransformVaryingsMap;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -127,8 +127,7 @@ bool GrGLSLProgramBuilder::emitAndInstallPrimProc(SkString* outputColor, SkStrin
|
||||
outputColor->c_str(),
|
||||
outputCoverage->c_str(),
|
||||
texSamplers.get());
|
||||
GrFragmentProcessor::CIter fpIter(this->pipeline());
|
||||
fFPCoordVaryings = fGeometryProcessor->emitCode(args, std::move(fpIter));
|
||||
fFPCoordVaryings = fGeometryProcessor->emitCode(args, this->pipeline());
|
||||
|
||||
// We have to check that effects and the code they emit are consistent, ie if an effect
|
||||
// asks for dst color, then the emit code needs to follow suit
|
||||
|
Loading…
Reference in New Issue
Block a user