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(); */
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 delete(void* target);
@ -100,7 +109,7 @@ public:
uint32_t classID() const { SkASSERT(kIllegalProcessorClassID != fClassID); return fClassID; }
protected:
GrProcessor() : fClassID(kIllegalProcessorClassID), fWillReadFragmentPosition(false) {}
GrProcessor() : fClassID(kIllegalProcessorClassID), fRequiredFeatures(kNone_RequiredFeatures) {}
/**
* 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
* 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() {
static uint32_t kClassID = GenClassID();
@ -145,9 +158,11 @@ private:
};
static int32_t gCurrProcessorClassID;
bool fWillReadFragmentPosition;
RequiredFeatures fRequiredFeatures;
typedef GrProgramElement INHERITED;
};
GR_MAKE_BITFIELD_OPS(GrProcessor::RequiredFeatures);
#endif

View File

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

View File

@ -184,23 +184,14 @@ void GrPipeline::adjustProgramFromOptimizations(const GrPipelineBuilder& pipelin
int* firstColorProcessorIdx,
int* firstCoverageProcessorIdx) {
fIgnoresCoverage = SkToBool(flags & GrXferProcessor::kIgnoreCoverage_OptFlag);
fReadsFragPosition = this->getXferProcessor().willReadFragmentPosition();
if ((flags & GrXferProcessor::kIgnoreColor_OptFlag) ||
(flags & GrXferProcessor::kOverrideColor_OptFlag)) {
*firstColorProcessorIdx = pipelineBuilder.numColorFragmentProcessors();
} else {
if (colorPOI.readsFragPosition()) {
fReadsFragPosition = true;
}
}
if (flags & GrXferProcessor::kIgnoreCoverage_OptFlag) {
*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; }
private:
@ -200,7 +199,6 @@ private:
uint32_t fFlags;
ProgramXferProcessor fXferProcessor;
FragmentProcessorArray fFragmentProcessors;
bool fReadsFragPosition;
bool fIgnoresCoverage;
// 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.fIsLCDCoverage = isLCD;
fInOut.reset(out);
this->internalCalc(processors, cnt, false);
this->internalCalc(processors, cnt);
}
void GrProcOptInfo::initUsingInvariantOutput(GrInitInvariantOutput invOutput) {
@ -31,16 +31,13 @@ void GrProcOptInfo::initUsingInvariantOutput(GrInitInvariantOutput invOutput) {
}
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[],
int cnt,
bool initWillReadFragmentPosition) {
void GrProcOptInfo::internalCalc(const GrFragmentProcessor* const processors[], int cnt) {
fFirstEffectiveProcessorIndex = 0;
fInputColorIsUsed = true;
fInputColor = fInOut.color();
fReadsFragPosition = initWillReadFragmentPosition;
for (int i = 0; i < cnt; ++i) {
const GrFragmentProcessor* processor = processors[i];
@ -50,11 +47,6 @@ void GrProcOptInfo::internalCalc(const GrFragmentProcessor* const processors[],
if (!fInOut.willUseInputColor()) {
fFirstEffectiveProcessorIndex = i;
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()) {
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
// zero stages that don't multiply the inputColor.
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 GrFragmentProcessor;
class GrPrimitiveProcessor;
class GrProcessor;
/**
* 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)
, fFirstEffectiveProcessorIndex(0)
, fInputColorIsUsed(true)
, fInputColor(0)
, fReadsFragPosition(false) {}
, fInputColor(0) {}
void calcWithInitialValues(const GrFragmentProcessor* const *, int cnt, GrColor startColor,
GrColorComponentFlags, bool areCoverageStages, bool isLCD = false);
@ -75,19 +73,13 @@ public:
*/
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:
void internalCalc(const GrFragmentProcessor* const[], int cnt, bool initWillReadFragPosition);
void internalCalc(const GrFragmentProcessor* const[], int cnt);
GrInvariantOutput fInOut;
int fFirstEffectiveProcessorIndex;
bool fInputColorIsUsed;
GrColor fInputColor;
bool fReadsFragPosition;
};
#endif

View File

@ -120,6 +120,7 @@ bool GrGLProgramDescBuilder::Build(GrProgramDesc* desc,
glDesc->key().reset();
return false;
}
GrProcessor::RequiredFeatures requiredFeatures = primProc.requiredFeatures();
for (int i = 0; i < pipeline.numFragmentProcessors(); ++i) {
const GrFragmentProcessor& fp = pipeline.getFragmentProcessor(i);
@ -127,6 +128,7 @@ bool GrGLProgramDescBuilder::Build(GrProgramDesc* desc,
glDesc->key().reset();
return false;
}
requiredFeatures |= fp.requiredFeatures();
}
const GrXferProcessor& xp = pipeline.getXferProcessor();
@ -135,6 +137,7 @@ bool GrGLProgramDescBuilder::Build(GrProgramDesc* desc,
glDesc->key().reset();
return false;
}
requiredFeatures |= xp.requiredFeatures();
// --------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
@ -144,7 +147,7 @@ bool GrGLProgramDescBuilder::Build(GrProgramDesc* desc,
// make sure any padding in the header is zeroed.
memset(header, 0, kHeaderSize);
if (pipeline.readsFragPosition()) {
if (requiredFeatures & GrProcessor::kFragmentPosition_RequiredFeature) {
header->fFragPosKey =
GrGLSLFragmentShaderBuilder::KeyForFragmentPosition(pipeline.getRenderTarget());
} else {

View File

@ -74,10 +74,16 @@ GrGLSLFragmentShaderBuilder::GrGLSLFragmentShaderBuilder(GrGLSLProgramBuilder* p
, fHasCustomColorOutput(false)
, fCustomColorOutputIndex(-1)
, fHasSecondaryOutput(false)
, fHasInitializedSampleMask(false)
, fHasReadDstColor(false)
, fHasReadFragmentPosition(false) {
, fHasInitializedSampleMask(false) {
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) {
@ -123,7 +129,8 @@ SkString GrGLSLFragmentShaderBuilder::ensureFSCoords2D(const GrGLSLTransformedCo
}
const char* GrGLSLFragmentShaderBuilder::fragmentPosition() {
fHasReadFragmentPosition = true;
SkASSERT(this->hasFragmentPosition());
SkDEBUGCODE(fUsedProcessorFeatures |= GrProcessor::kFragmentPosition_RequiredFeature;)
const GrGLSLCaps* glslCaps = fProgramBuilder->glslCaps();
// 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() {
fHasReadDstColor = true;
SkDEBUGCODE(fHasReadDstColor = true;)
const char* override = fProgramBuilder->primitiveProcessor().getDestColorOverride();
if (override != nullptr) {

View File

@ -10,6 +10,7 @@
#include "GrGLSLShaderBuilder.h"
#include "GrProcessor.h"
#include "glsl/GrGLSLProcessorTypes.h"
class GrRenderTarget;
@ -165,20 +166,24 @@ public:
void enableAdvancedBlendEquationIfNeeded(GrBlendEquation) override;
private:
bool hasFragmentPosition() const;
// Private public interface, used by GrGLProgramBuilder to build a fragment shader
void enableCustomOutput();
void enableSecondaryOutput();
const char* getPrimaryColorOutputName() const;
const char* getSecondaryColorOutputName() const;
#ifdef SK_DEBUG
// 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.
GrProcessor::RequiredFeatures usedProcessorFeatures() const { return fUsedProcessorFeatures; }
bool hasReadDstColor() const { return fHasReadDstColor; }
bool hasReadFragmentPosition() const { return fHasReadFragmentPosition; }
void reset() {
void resetVerification() {
fUsedProcessorFeatures = GrProcessor::kNone_RequiredFeatures;
fHasReadDstColor = false;
fHasReadFragmentPosition = false;
}
#endif
static const char* DeclaredColorOutputName() { return "fsColorOut"; }
static const char* DeclaredSecondaryColorOutputName() { return "fsSecondaryColorOut"; }
@ -226,10 +231,12 @@ private:
bool fHasSecondaryOutput;
bool fHasInitializedSampleMask;
#ifdef SK_DEBUG
// some state to verify shaders and effects are consistent, this is reset between effects by
// the program creator
GrProcessor::RequiredFeatures fUsedProcessorFeatures;
bool fHasReadDstColor;
bool fHasReadFragmentPosition;
#endif
friend class GrGLSLProgramBuilder;
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
// asks for dst color, then the emit code needs to follow suit
verify(proc);
SkDEBUGCODE(verify(proc);)
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
// asks for dst color, then the emit code needs to follow suit
verify(fp);
SkDEBUGCODE(verify(fp);)
fFragmentProcessors.push_back(fragProc);
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
// asks for dst color, then the emit code needs to follow suit
verify(xp);
SkDEBUGCODE(verify(xp);)
fFS.codeAppend("}");
}
@ -214,17 +214,20 @@ void GrGLSLProgramBuilder::emitFSOutputSwizzle(bool hasSecondaryOutput) {
}
}
#ifdef SK_DEBUG
void GrGLSLProgramBuilder::verify(const GrPrimitiveProcessor& gp) {
SkASSERT(fFS.hasReadFragmentPosition() == gp.willReadFragmentPosition());
SkASSERT(fFS.usedProcessorFeatures() == gp.requiredFeatures());
}
void GrGLSLProgramBuilder::verify(const GrXferProcessor& xp) {
SkASSERT(fFS.usedProcessorFeatures() == xp.requiredFeatures());
SkASSERT(fFS.hasReadDstColor() == xp.willReadDstColor());
}
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) {
if ('\0' == prefix) {

View File

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

View File

@ -107,6 +107,7 @@ bool GrVkProgramDescBuilder::Build(GrProgramDesc* desc,
vkDesc->key().reset();
return false;
}
GrProcessor::RequiredFeatures requiredFeatures = primProc.requiredFeatures();
for (int i = 0; i < pipeline.numFragmentProcessors(); ++i) {
const GrFragmentProcessor& fp = pipeline.getFragmentProcessor(i);
@ -114,6 +115,7 @@ bool GrVkProgramDescBuilder::Build(GrProgramDesc* desc,
vkDesc->key().reset();
return false;
}
requiredFeatures |= fp.requiredFeatures();
}
const GrXferProcessor& xp = pipeline.getXferProcessor();
@ -122,6 +124,7 @@ bool GrVkProgramDescBuilder::Build(GrProgramDesc* desc,
vkDesc->key().reset();
return false;
}
requiredFeatures |= xp.requiredFeatures();
// --------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
@ -131,7 +134,7 @@ bool GrVkProgramDescBuilder::Build(GrProgramDesc* desc,
// make sure any padding in the header is zeroed.
memset(header, 0, kHeaderSize);
if (pipeline.readsFragPosition()) {
if (requiredFeatures & GrProcessor::kFragmentPosition_RequiredFeature) {
header->fFragPosKey =
GrGLSLFragmentShaderBuilder::KeyForFragmentPosition(pipeline.getRenderTarget());
} else {