Replace fWillReadFragmentPosition with a bitfield

Replaces fWillReadFragmentPosition on GrProcessor with a
"RequiredFeatures" bitfield. This will allow us to add additional
built-in features. Completely removes information about reading the
fragment position from GrPipeline and GrProcOptInfo.

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1734163002

Review URL: https://codereview.chromium.org/1734163002
This commit is contained in:
cdalton 2016-02-26 12:22:02 -08:00 committed by Commit bot
parent e5824b90da
commit 87332103c6
12 changed files with 68 additions and 59 deletions

View File

@ -79,8 +79,17 @@ public:
/** Shortcut for textureAccess(index).texture(); */ /** Shortcut for textureAccess(index).texture(); */
GrTexture* texture(int index) const { return this->textureAccess(index).getTexture(); } GrTexture* texture(int index) const { return this->textureAccess(index).getTexture(); }
/** Will this processor read the fragment position? */ /**
bool willReadFragmentPosition() const { return fWillReadFragmentPosition; } * Platform specific built-in features that a processor can request for the fragment shader.
*/
enum RequiredFeatures {
kNone_RequiredFeatures = 0,
kFragmentPosition_RequiredFeature = 1
};
GR_DECL_BITFIELD_OPS_FRIENDS(RequiredFeatures);
RequiredFeatures requiredFeatures() const { return fRequiredFeatures; }
void* operator new(size_t size); void* operator new(size_t size);
void operator delete(void* target); void operator delete(void* target);
@ -100,7 +109,7 @@ public:
uint32_t classID() const { SkASSERT(kIllegalProcessorClassID != fClassID); return fClassID; } uint32_t classID() const { SkASSERT(kIllegalProcessorClassID != fClassID); return fClassID; }
protected: protected:
GrProcessor() : fClassID(kIllegalProcessorClassID), fWillReadFragmentPosition(false) {} GrProcessor() : fClassID(kIllegalProcessorClassID), fRequiredFeatures(kNone_RequiredFeatures) {}
/** /**
* Subclasses call this from their constructor to register GrTextureAccesses. The processor * Subclasses call this from their constructor to register GrTextureAccesses. The processor
@ -117,7 +126,11 @@ protected:
* position in the FS then it must call this method from its constructor. Otherwise, the * position in the FS then it must call this method from its constructor. Otherwise, the
* request to access the fragment position will be denied. * request to access the fragment position will be denied.
*/ */
void setWillReadFragmentPosition() { fWillReadFragmentPosition = true; } void setWillReadFragmentPosition() { fRequiredFeatures |= kFragmentPosition_RequiredFeature; }
void combineRequiredFeatures(const GrProcessor& other) {
fRequiredFeatures |= other.fRequiredFeatures;
}
template <typename PROC_SUBCLASS> void initClassID() { template <typename PROC_SUBCLASS> void initClassID() {
static uint32_t kClassID = GenClassID(); static uint32_t kClassID = GenClassID();
@ -145,9 +158,11 @@ private:
}; };
static int32_t gCurrProcessorClassID; static int32_t gCurrProcessorClassID;
bool fWillReadFragmentPosition; RequiredFeatures fRequiredFeatures;
typedef GrProgramElement INHERITED; typedef GrProgramElement INHERITED;
}; };
GR_MAKE_BITFIELD_OPS(GrProcessor::RequiredFeatures);
#endif #endif

View File

@ -96,9 +96,7 @@ int GrFragmentProcessor::registerChildProcessor(const GrFragmentProcessor* child
int index = fChildProcessors.count(); int index = fChildProcessors.count();
fChildProcessors.push_back(SkRef(child)); fChildProcessors.push_back(SkRef(child));
if (child->willReadFragmentPosition()) { this->combineRequiredFeatures(*child);
this->setWillReadFragmentPosition();
}
if (child->usesLocalCoords()) { if (child->usesLocalCoords()) {
fUsesLocalCoords = true; fUsesLocalCoords = true;

View File

@ -184,23 +184,14 @@ void GrPipeline::adjustProgramFromOptimizations(const GrPipelineBuilder& pipelin
int* firstColorProcessorIdx, int* firstColorProcessorIdx,
int* firstCoverageProcessorIdx) { int* firstCoverageProcessorIdx) {
fIgnoresCoverage = SkToBool(flags & GrXferProcessor::kIgnoreCoverage_OptFlag); fIgnoresCoverage = SkToBool(flags & GrXferProcessor::kIgnoreCoverage_OptFlag);
fReadsFragPosition = this->getXferProcessor().willReadFragmentPosition();
if ((flags & GrXferProcessor::kIgnoreColor_OptFlag) || if ((flags & GrXferProcessor::kIgnoreColor_OptFlag) ||
(flags & GrXferProcessor::kOverrideColor_OptFlag)) { (flags & GrXferProcessor::kOverrideColor_OptFlag)) {
*firstColorProcessorIdx = pipelineBuilder.numColorFragmentProcessors(); *firstColorProcessorIdx = pipelineBuilder.numColorFragmentProcessors();
} else {
if (colorPOI.readsFragPosition()) {
fReadsFragPosition = true;
}
} }
if (flags & GrXferProcessor::kIgnoreCoverage_OptFlag) { if (flags & GrXferProcessor::kIgnoreCoverage_OptFlag) {
*firstCoverageProcessorIdx = pipelineBuilder.numCoverageFragmentProcessors(); *firstCoverageProcessorIdx = pipelineBuilder.numCoverageFragmentProcessors();
} else {
if (coveragePOI.readsFragPosition()) {
fReadsFragPosition = true;
}
} }
} }

View File

@ -160,7 +160,6 @@ public:
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
bool readsFragPosition() const { return fReadsFragPosition; }
bool ignoresCoverage() const { return fIgnoresCoverage; } bool ignoresCoverage() const { return fIgnoresCoverage; }
private: private:
@ -200,7 +199,6 @@ private:
uint32_t fFlags; uint32_t fFlags;
ProgramXferProcessor fXferProcessor; ProgramXferProcessor fXferProcessor;
FragmentProcessorArray fFragmentProcessors; FragmentProcessorArray fFragmentProcessors;
bool fReadsFragPosition;
bool fIgnoresCoverage; bool fIgnoresCoverage;
// This value is also the index in fFragmentProcessors where coverage processors begin. // This value is also the index in fFragmentProcessors where coverage processors begin.

View File

@ -23,7 +23,7 @@ void GrProcOptInfo::calcWithInitialValues(const GrFragmentProcessor * const proc
out.fValidFlags = flags; out.fValidFlags = flags;
out.fIsLCDCoverage = isLCD; out.fIsLCDCoverage = isLCD;
fInOut.reset(out); fInOut.reset(out);
this->internalCalc(processors, cnt, false); this->internalCalc(processors, cnt);
} }
void GrProcOptInfo::initUsingInvariantOutput(GrInitInvariantOutput invOutput) { void GrProcOptInfo::initUsingInvariantOutput(GrInitInvariantOutput invOutput) {
@ -31,16 +31,13 @@ void GrProcOptInfo::initUsingInvariantOutput(GrInitInvariantOutput invOutput) {
} }
void GrProcOptInfo::completeCalculations(const GrFragmentProcessor * const processors[], int cnt) { void GrProcOptInfo::completeCalculations(const GrFragmentProcessor * const processors[], int cnt) {
this->internalCalc(processors, cnt, false); this->internalCalc(processors, cnt);
} }
void GrProcOptInfo::internalCalc(const GrFragmentProcessor* const processors[], void GrProcOptInfo::internalCalc(const GrFragmentProcessor* const processors[], int cnt) {
int cnt,
bool initWillReadFragmentPosition) {
fFirstEffectiveProcessorIndex = 0; fFirstEffectiveProcessorIndex = 0;
fInputColorIsUsed = true; fInputColorIsUsed = true;
fInputColor = fInOut.color(); fInputColor = fInOut.color();
fReadsFragPosition = initWillReadFragmentPosition;
for (int i = 0; i < cnt; ++i) { for (int i = 0; i < cnt; ++i) {
const GrFragmentProcessor* processor = processors[i]; const GrFragmentProcessor* processor = processors[i];
@ -50,11 +47,6 @@ void GrProcOptInfo::internalCalc(const GrFragmentProcessor* const processors[],
if (!fInOut.willUseInputColor()) { if (!fInOut.willUseInputColor()) {
fFirstEffectiveProcessorIndex = i; fFirstEffectiveProcessorIndex = i;
fInputColorIsUsed = false; fInputColorIsUsed = false;
// Reset these since we don't care if previous stages read these values
fReadsFragPosition = initWillReadFragmentPosition;
}
if (processor->willReadFragmentPosition()) {
fReadsFragPosition = true;
} }
if (kRGBA_GrColorComponentFlags == fInOut.validFlags()) { if (kRGBA_GrColorComponentFlags == fInOut.validFlags()) {
fFirstEffectiveProcessorIndex = i + 1; fFirstEffectiveProcessorIndex = i + 1;
@ -63,8 +55,6 @@ void GrProcOptInfo::internalCalc(const GrFragmentProcessor* const processors[],
// Since we are clearing all previous color stages we are in a state where we have found // Since we are clearing all previous color stages we are in a state where we have found
// zero stages that don't multiply the inputColor. // zero stages that don't multiply the inputColor.
fInOut.resetNonMulStageFound(); fInOut.resetNonMulStageFound();
// Reset these since we don't care if previous stages read these values
fReadsFragPosition = initWillReadFragmentPosition;
} }
} }
} }

View File

@ -14,7 +14,6 @@
class GrDrawBatch; class GrDrawBatch;
class GrFragmentProcessor; class GrFragmentProcessor;
class GrPrimitiveProcessor; class GrPrimitiveProcessor;
class GrProcessor;
/** /**
* GrProcOptInfo gathers invariant data from a set of processor stages.It is used to recognize * GrProcOptInfo gathers invariant data from a set of processor stages.It is used to recognize
@ -27,8 +26,7 @@ public:
: fInOut(0, static_cast<GrColorComponentFlags>(0), false) : fInOut(0, static_cast<GrColorComponentFlags>(0), false)
, fFirstEffectiveProcessorIndex(0) , fFirstEffectiveProcessorIndex(0)
, fInputColorIsUsed(true) , fInputColorIsUsed(true)
, fInputColor(0) , fInputColor(0) {}
, fReadsFragPosition(false) {}
void calcWithInitialValues(const GrFragmentProcessor* const *, int cnt, GrColor startColor, void calcWithInitialValues(const GrFragmentProcessor* const *, int cnt, GrColor startColor,
GrColorComponentFlags, bool areCoverageStages, bool isLCD = false); GrColorComponentFlags, bool areCoverageStages, bool isLCD = false);
@ -75,19 +73,13 @@ public:
*/ */
GrColor inputColorToFirstEffectiveProccesor() const { return fInputColor; } GrColor inputColorToFirstEffectiveProccesor() const { return fInputColor; }
/**
* Returns true if any of the processor preserved by GrProcOptInfo read the frag position.
*/
bool readsFragPosition() const { return fReadsFragPosition; }
private: private:
void internalCalc(const GrFragmentProcessor* const[], int cnt, bool initWillReadFragPosition); void internalCalc(const GrFragmentProcessor* const[], int cnt);
GrInvariantOutput fInOut; GrInvariantOutput fInOut;
int fFirstEffectiveProcessorIndex; int fFirstEffectiveProcessorIndex;
bool fInputColorIsUsed; bool fInputColorIsUsed;
GrColor fInputColor; GrColor fInputColor;
bool fReadsFragPosition;
}; };
#endif #endif

View File

@ -120,6 +120,7 @@ bool GrGLProgramDescBuilder::Build(GrProgramDesc* desc,
glDesc->key().reset(); glDesc->key().reset();
return false; return false;
} }
GrProcessor::RequiredFeatures requiredFeatures = primProc.requiredFeatures();
for (int i = 0; i < pipeline.numFragmentProcessors(); ++i) { for (int i = 0; i < pipeline.numFragmentProcessors(); ++i) {
const GrFragmentProcessor& fp = pipeline.getFragmentProcessor(i); const GrFragmentProcessor& fp = pipeline.getFragmentProcessor(i);
@ -127,6 +128,7 @@ bool GrGLProgramDescBuilder::Build(GrProgramDesc* desc,
glDesc->key().reset(); glDesc->key().reset();
return false; return false;
} }
requiredFeatures |= fp.requiredFeatures();
} }
const GrXferProcessor& xp = pipeline.getXferProcessor(); const GrXferProcessor& xp = pipeline.getXferProcessor();
@ -135,6 +137,7 @@ bool GrGLProgramDescBuilder::Build(GrProgramDesc* desc,
glDesc->key().reset(); glDesc->key().reset();
return false; return false;
} }
requiredFeatures |= xp.requiredFeatures();
// --------DO NOT MOVE HEADER ABOVE THIS LINE-------------------------------------------------- // --------DO NOT MOVE HEADER ABOVE THIS LINE--------------------------------------------------
// Because header is a pointer into the dynamic array, we can't push any new data into the key // Because header is a pointer into the dynamic array, we can't push any new data into the key
@ -144,7 +147,7 @@ bool GrGLProgramDescBuilder::Build(GrProgramDesc* desc,
// make sure any padding in the header is zeroed. // make sure any padding in the header is zeroed.
memset(header, 0, kHeaderSize); memset(header, 0, kHeaderSize);
if (pipeline.readsFragPosition()) { if (requiredFeatures & GrProcessor::kFragmentPosition_RequiredFeature) {
header->fFragPosKey = header->fFragPosKey =
GrGLSLFragmentShaderBuilder::KeyForFragmentPosition(pipeline.getRenderTarget()); GrGLSLFragmentShaderBuilder::KeyForFragmentPosition(pipeline.getRenderTarget());
} else { } else {

View File

@ -74,10 +74,16 @@ GrGLSLFragmentShaderBuilder::GrGLSLFragmentShaderBuilder(GrGLSLProgramBuilder* p
, fHasCustomColorOutput(false) , fHasCustomColorOutput(false)
, fCustomColorOutputIndex(-1) , fCustomColorOutputIndex(-1)
, fHasSecondaryOutput(false) , fHasSecondaryOutput(false)
, fHasInitializedSampleMask(false) , fHasInitializedSampleMask(false) {
, fHasReadDstColor(false)
, fHasReadFragmentPosition(false) {
fSubstageIndices.push_back(0); fSubstageIndices.push_back(0);
#ifdef SK_DEBUG
fUsedProcessorFeatures = GrProcessor::kNone_RequiredFeatures;
fHasReadDstColor = false;
#endif
}
bool GrGLSLFragmentShaderBuilder::hasFragmentPosition() const {
return 0 != fProgramBuilder->header().fFragPosKey;
} }
bool GrGLSLFragmentShaderBuilder::enableFeature(GLSLFeature feature) { bool GrGLSLFragmentShaderBuilder::enableFeature(GLSLFeature feature) {
@ -123,7 +129,8 @@ SkString GrGLSLFragmentShaderBuilder::ensureFSCoords2D(const GrGLSLTransformedCo
} }
const char* GrGLSLFragmentShaderBuilder::fragmentPosition() { const char* GrGLSLFragmentShaderBuilder::fragmentPosition() {
fHasReadFragmentPosition = true; SkASSERT(this->hasFragmentPosition());
SkDEBUGCODE(fUsedProcessorFeatures |= GrProcessor::kFragmentPosition_RequiredFeature;)
const GrGLSLCaps* glslCaps = fProgramBuilder->glslCaps(); const GrGLSLCaps* glslCaps = fProgramBuilder->glslCaps();
// We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
@ -212,7 +219,7 @@ void GrGLSLFragmentShaderBuilder::overrideSampleCoverage(const char* mask) {
} }
const char* GrGLSLFragmentShaderBuilder::dstColor() { const char* GrGLSLFragmentShaderBuilder::dstColor() {
fHasReadDstColor = true; SkDEBUGCODE(fHasReadDstColor = true;)
const char* override = fProgramBuilder->primitiveProcessor().getDestColorOverride(); const char* override = fProgramBuilder->primitiveProcessor().getDestColorOverride();
if (override != nullptr) { if (override != nullptr) {

View File

@ -10,6 +10,7 @@
#include "GrGLSLShaderBuilder.h" #include "GrGLSLShaderBuilder.h"
#include "GrProcessor.h"
#include "glsl/GrGLSLProcessorTypes.h" #include "glsl/GrGLSLProcessorTypes.h"
class GrRenderTarget; class GrRenderTarget;
@ -165,20 +166,24 @@ public:
void enableAdvancedBlendEquationIfNeeded(GrBlendEquation) override; void enableAdvancedBlendEquationIfNeeded(GrBlendEquation) override;
private: private:
bool hasFragmentPosition() const;
// Private public interface, used by GrGLProgramBuilder to build a fragment shader // Private public interface, used by GrGLProgramBuilder to build a fragment shader
void enableCustomOutput(); void enableCustomOutput();
void enableSecondaryOutput(); void enableSecondaryOutput();
const char* getPrimaryColorOutputName() const; const char* getPrimaryColorOutputName() const;
const char* getSecondaryColorOutputName() const; const char* getSecondaryColorOutputName() const;
#ifdef SK_DEBUG
// As GLSLProcessors emit code, there are some conditions we need to verify. We use the below // As GLSLProcessors emit code, there are some conditions we need to verify. We use the below
// state to track this. The reset call is called per processor emitted. // state to track this. The reset call is called per processor emitted.
GrProcessor::RequiredFeatures usedProcessorFeatures() const { return fUsedProcessorFeatures; }
bool hasReadDstColor() const { return fHasReadDstColor; } bool hasReadDstColor() const { return fHasReadDstColor; }
bool hasReadFragmentPosition() const { return fHasReadFragmentPosition; } void resetVerification() {
void reset() { fUsedProcessorFeatures = GrProcessor::kNone_RequiredFeatures;
fHasReadDstColor = false; fHasReadDstColor = false;
fHasReadFragmentPosition = false;
} }
#endif
static const char* DeclaredColorOutputName() { return "fsColorOut"; } static const char* DeclaredColorOutputName() { return "fsColorOut"; }
static const char* DeclaredSecondaryColorOutputName() { return "fsSecondaryColorOut"; } static const char* DeclaredSecondaryColorOutputName() { return "fsSecondaryColorOut"; }
@ -226,10 +231,12 @@ private:
bool fHasSecondaryOutput; bool fHasSecondaryOutput;
bool fHasInitializedSampleMask; bool fHasInitializedSampleMask;
#ifdef SK_DEBUG
// some state to verify shaders and effects are consistent, this is reset between effects by // some state to verify shaders and effects are consistent, this is reset between effects by
// the program creator // the program creator
GrProcessor::RequiredFeatures fUsedProcessorFeatures;
bool fHasReadDstColor; bool fHasReadDstColor;
bool fHasReadFragmentPosition; #endif
friend class GrGLSLProgramBuilder; friend class GrGLSLProgramBuilder;
friend class GrGLProgramBuilder; friend class GrGLProgramBuilder;

View File

@ -99,7 +99,7 @@ void GrGLSLProgramBuilder::emitAndInstallPrimProc(const GrPrimitiveProcessor& pr
// We have to check that effects and the code they emit are consistent, ie if an effect // 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 // asks for dst color, then the emit code needs to follow suit
verify(proc); SkDEBUGCODE(verify(proc);)
fFS.codeAppend("}"); fFS.codeAppend("}");
} }
@ -147,7 +147,7 @@ void GrGLSLProgramBuilder::emitAndInstallFragProc(const GrFragmentProcessor& fp,
// We have to check that effects and the code they emit are consistent, ie if an effect // 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 // asks for dst color, then the emit code needs to follow suit
verify(fp); SkDEBUGCODE(verify(fp);)
fFragmentProcessors.push_back(fragProc); fFragmentProcessors.push_back(fragProc);
fFS.codeAppend("}"); fFS.codeAppend("}");
@ -194,7 +194,7 @@ void GrGLSLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp,
// We have to check that effects and the code they emit are consistent, ie if an effect // 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 // asks for dst color, then the emit code needs to follow suit
verify(xp); SkDEBUGCODE(verify(xp);)
fFS.codeAppend("}"); fFS.codeAppend("}");
} }
@ -214,17 +214,20 @@ void GrGLSLProgramBuilder::emitFSOutputSwizzle(bool hasSecondaryOutput) {
} }
} }
#ifdef SK_DEBUG
void GrGLSLProgramBuilder::verify(const GrPrimitiveProcessor& gp) { void GrGLSLProgramBuilder::verify(const GrPrimitiveProcessor& gp) {
SkASSERT(fFS.hasReadFragmentPosition() == gp.willReadFragmentPosition()); SkASSERT(fFS.usedProcessorFeatures() == gp.requiredFeatures());
} }
void GrGLSLProgramBuilder::verify(const GrXferProcessor& xp) { void GrGLSLProgramBuilder::verify(const GrXferProcessor& xp) {
SkASSERT(fFS.usedProcessorFeatures() == xp.requiredFeatures());
SkASSERT(fFS.hasReadDstColor() == xp.willReadDstColor()); SkASSERT(fFS.hasReadDstColor() == xp.willReadDstColor());
} }
void GrGLSLProgramBuilder::verify(const GrFragmentProcessor& fp) { void GrGLSLProgramBuilder::verify(const GrFragmentProcessor& fp) {
SkASSERT(fFS.hasReadFragmentPosition() == fp.willReadFragmentPosition()); SkASSERT(fFS.usedProcessorFeatures() == fp.requiredFeatures());
} }
#endif
void GrGLSLProgramBuilder::nameVariable(SkString* out, char prefix, const char* name, bool mangle) { void GrGLSLProgramBuilder::nameVariable(SkString* out, char prefix, const char* name, bool mangle) {
if ('\0' == prefix) { if ('\0' == prefix) {

View File

@ -105,7 +105,7 @@ private:
// fragment shader are cleared. // fragment shader are cleared.
void reset() { void reset() {
this->addStage(); this->addStage();
fFS.reset(); SkDEBUGCODE(fFS.resetVerification();)
} }
void addStage() { fStageIndex++; } void addStage() { fStageIndex++; }
@ -141,9 +141,11 @@ private:
GrPixelLocalStorageState plsState); GrPixelLocalStorageState plsState);
void emitFSOutputSwizzle(bool hasSecondaryOutput); void emitFSOutputSwizzle(bool hasSecondaryOutput);
#ifdef SK_DEBUG
void verify(const GrPrimitiveProcessor&); void verify(const GrPrimitiveProcessor&);
void verify(const GrXferProcessor&); void verify(const GrXferProcessor&);
void verify(const GrFragmentProcessor&); void verify(const GrFragmentProcessor&);
#endif
virtual void emitSamplers(const GrProcessor& processor, virtual void emitSamplers(const GrProcessor& processor,
GrGLSLTextureSampler::TextureSamplerArray* outSamplers) = 0; GrGLSLTextureSampler::TextureSamplerArray* outSamplers) = 0;

View File

@ -107,6 +107,7 @@ bool GrVkProgramDescBuilder::Build(GrProgramDesc* desc,
vkDesc->key().reset(); vkDesc->key().reset();
return false; return false;
} }
GrProcessor::RequiredFeatures requiredFeatures = primProc.requiredFeatures();
for (int i = 0; i < pipeline.numFragmentProcessors(); ++i) { for (int i = 0; i < pipeline.numFragmentProcessors(); ++i) {
const GrFragmentProcessor& fp = pipeline.getFragmentProcessor(i); const GrFragmentProcessor& fp = pipeline.getFragmentProcessor(i);
@ -114,6 +115,7 @@ bool GrVkProgramDescBuilder::Build(GrProgramDesc* desc,
vkDesc->key().reset(); vkDesc->key().reset();
return false; return false;
} }
requiredFeatures |= fp.requiredFeatures();
} }
const GrXferProcessor& xp = pipeline.getXferProcessor(); const GrXferProcessor& xp = pipeline.getXferProcessor();
@ -122,6 +124,7 @@ bool GrVkProgramDescBuilder::Build(GrProgramDesc* desc,
vkDesc->key().reset(); vkDesc->key().reset();
return false; return false;
} }
requiredFeatures |= xp.requiredFeatures();
// --------DO NOT MOVE HEADER ABOVE THIS LINE-------------------------------------------------- // --------DO NOT MOVE HEADER ABOVE THIS LINE--------------------------------------------------
// Because header is a pointer into the dynamic array, we can't push any new data into the key // Because header is a pointer into the dynamic array, we can't push any new data into the key
@ -131,7 +134,7 @@ bool GrVkProgramDescBuilder::Build(GrProgramDesc* desc,
// make sure any padding in the header is zeroed. // make sure any padding in the header is zeroed.
memset(header, 0, kHeaderSize); memset(header, 0, kHeaderSize);
if (pipeline.readsFragPosition()) { if (requiredFeatures & GrProcessor::kFragmentPosition_RequiredFeature) {
header->fFragPosKey = header->fFragPosKey =
GrGLSLFragmentShaderBuilder::KeyForFragmentPosition(pipeline.getRenderTarget()); GrGLSLFragmentShaderBuilder::KeyForFragmentPosition(pipeline.getRenderTarget());
} else { } else {