diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi index c28045d95b..e41cb8ec4f 100644 --- a/gyp/gpu.gypi +++ b/gyp/gpu.gypi @@ -168,6 +168,7 @@ '<(skia_src_path)/gpu/gl/GrGLPath.h', '<(skia_src_path)/gpu/gl/GrGLProgram.cpp', '<(skia_src_path)/gpu/gl/GrGLProgram.h', + '<(skia_src_path)/gpu/gl/GrGLProgramDesc.h', '<(skia_src_path)/gpu/gl/GrGLRenderTarget.cpp', '<(skia_src_path)/gpu/gl/GrGLRenderTarget.h', '<(skia_src_path)/gpu/gl/GrGLShaderBuilder.cpp', diff --git a/include/gpu/GrTypesPriv.h b/include/gpu/GrTypesPriv.h index fea80f8f46..ebe28dee09 100644 --- a/include/gpu/GrTypesPriv.h +++ b/include/gpu/GrTypesPriv.h @@ -8,6 +8,8 @@ #ifndef GrTypesPriv_DEFINED #define GrTypesPriv_DEFINED +#include "SkTArray.h" + /** * Types of shader-language-specific boxed variables we can create. * (Currently only GrGLShaderVars, but should be applicable to other shader @@ -24,4 +26,34 @@ enum GrSLType { kSampler2D_GrSLType }; +/** + * Types used to describe format of vertices in arrays + */ +enum GrVertexAttribType { + kFloat_GrVertexAttribType = 0, + kVec2f_GrVertexAttribType, + kVec3f_GrVertexAttribType, + kVec4f_GrVertexAttribType, + kVec4ub_GrVertexAttribType, // vector of 4 unsigned bytes, e.g. colors + + kLast_GrVertexAttribType = kVec4ub_GrVertexAttribType +}; +static const int kGrVertexAttribTypeCount = kLast_GrVertexAttribType + 1; + +struct GrVertexAttrib { + inline void set(GrVertexAttribType type, size_t offset) { + fType = type; fOffset = offset; + } + bool operator==(const GrVertexAttrib& other) const { + return fType == other.fType && fOffset == other.fOffset; + }; + bool operator!=(const GrVertexAttrib& other) const { return !(*this == other); } + + GrVertexAttribType fType; + size_t fOffset; +}; + +template +class GrVertexAttribArray : public SkSTArray {}; + #endif diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h index fed89dbefc..8b7a36e466 100644 --- a/src/gpu/GrDrawState.h +++ b/src/gpu/GrDrawState.h @@ -16,6 +16,7 @@ #include "GrStencil.h" #include "GrTemplates.h" #include "GrTexture.h" +#include "GrTypesPriv.h" #include "effects/GrSimpleTextureEffect.h" #include "SkMatrix.h" @@ -23,36 +24,6 @@ class GrPaint; -/** - * Types used to describe format of vertices in arrays - */ -enum GrVertexAttribType { - kFloat_GrVertexAttribType = 0, - kVec2f_GrVertexAttribType, - kVec3f_GrVertexAttribType, - kVec4f_GrVertexAttribType, - kVec4ub_GrVertexAttribType, // vector of 4 unsigned bytes, e.g. colors - - kLast_GrVertexAttribType = kVec4ub_GrVertexAttribType -}; -static const int kGrVertexAttribTypeCount = kLast_GrVertexAttribType + 1; - -struct GrVertexAttrib { - inline void set(GrVertexAttribType type, size_t offset) { - fType = type; fOffset = offset; - } - bool operator==(const GrVertexAttrib& other) const { - return fType == other.fType && fOffset == other.fOffset; - }; - bool operator!=(const GrVertexAttrib& other) const { return !(*this == other); } - - GrVertexAttribType fType; - size_t fOffset; -}; - -template -class GrVertexAttribArray : public SkSTArray {}; - /** * Type used to describe how attributes bind to program usage */ diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp index 5f567912f6..5c5dabfd70 100644 --- a/src/gpu/gl/GrGLProgram.cpp +++ b/src/gpu/gl/GrGLProgram.cpp @@ -36,21 +36,13 @@ inline const char* declared_color_output_name() { return "fsColorOut"; } inline const char* dual_source_output_name() { return "dualSourceOut"; } } -const GrGLProgram::AttribLayout GrGLProgram::kAttribLayouts[kGrVertexAttribTypeCount] = { - {1, GR_GL_FLOAT, false}, // kFloat_GrVertexAttribType - {2, GR_GL_FLOAT, false}, // kVec2f_GrVertexAttribType - {3, GR_GL_FLOAT, false}, // kVec3f_GrVertexAttribType - {4, GR_GL_FLOAT, false}, // kVec4f_GrVertexAttribType - {4, GR_GL_UNSIGNED_BYTE, true}, // kVec4ub_GrVertexAttribType -}; - -void GrGLProgram::BuildDesc(const GrDrawState& drawState, +void GrGLProgramDesc::Build(const GrDrawState& drawState, bool isPoints, GrDrawState::BlendOptFlags blendOpts, GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff, const GrGpuGL* gpu, - Desc* desc) { + GrGLProgramDesc* desc) { // This should already have been caught GrAssert(!(GrDrawState::kSkipDraw_BlendOptFlag & blendOpts)); @@ -94,25 +86,25 @@ void GrGLProgram::BuildDesc(const GrDrawState& drawState, bool colorIsSolidWhite = (blendOpts & GrDrawState::kEmitCoverage_BlendOptFlag) || (!requiresAttributeColors && 0xffffffff == drawState.getColor()); if (colorIsTransBlack) { - desc->fColorInput = Desc::kTransBlack_ColorInput; + desc->fColorInput = kTransBlack_ColorInput; } else if (colorIsSolidWhite) { - desc->fColorInput = Desc::kSolidWhite_ColorInput; + desc->fColorInput = kSolidWhite_ColorInput; } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresAttributeColors) { - desc->fColorInput = Desc::kUniform_ColorInput; + desc->fColorInput = kUniform_ColorInput; } else { - desc->fColorInput = Desc::kAttribute_ColorInput; + desc->fColorInput = kAttribute_ColorInput; } bool covIsSolidWhite = !requiresAttributeCoverage && 0xffffffff == drawState.getCoverage(); if (skipCoverage) { - desc->fCoverageInput = Desc::kTransBlack_ColorInput; + desc->fCoverageInput = kTransBlack_ColorInput; } else if (covIsSolidWhite) { - desc->fCoverageInput = Desc::kSolidWhite_ColorInput; + desc->fCoverageInput = kSolidWhite_ColorInput; } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresAttributeCoverage) { - desc->fCoverageInput = Desc::kUniform_ColorInput; + desc->fCoverageInput = kUniform_ColorInput; } else { - desc->fCoverageInput = Desc::kAttribute_ColorInput; + desc->fCoverageInput = kAttribute_ColorInput; } int lastEnabledStage = -1; @@ -133,7 +125,7 @@ void GrGLProgram::BuildDesc(const GrDrawState& drawState, } } - desc->fDualSrcOutput = Desc::kNone_DualSrcOutput; + desc->fDualSrcOutput = kNone_DualSrcOutput; // Currently the experimental GS will only work with triangle prims (and it doesn't do anything // other than pass through values from the VS to the FS anyway). @@ -181,15 +173,15 @@ void GrGLProgram::BuildDesc(const GrDrawState& drawState, GrDrawState::kCoverageAsAlpha_BlendOptFlag))) { if (kZero_GrBlendCoeff == dstCoeff) { // write the coverage value to second color - desc->fDualSrcOutput = Desc::kCoverage_DualSrcOutput; + desc->fDualSrcOutput = kCoverage_DualSrcOutput; desc->fFirstCoverageStage = firstCoverageStage; } else if (kSA_GrBlendCoeff == dstCoeff) { // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered. - desc->fDualSrcOutput = Desc::kCoverageISA_DualSrcOutput; + desc->fDualSrcOutput = kCoverageISA_DualSrcOutput; desc->fFirstCoverageStage = firstCoverageStage; } else if (kSC_GrBlendCoeff == dstCoeff) { // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered. - desc->fDualSrcOutput = Desc::kCoverageISC_DualSrcOutput; + desc->fDualSrcOutput = kCoverageISC_DualSrcOutput; desc->fFirstCoverageStage = firstCoverageStage; } } @@ -211,27 +203,28 @@ void GrGLProgram::BuildDesc(const GrDrawState& drawState, } #if GR_DEBUG - // verify valid vertex attribute state + // Verify valid vertex attribute state. These assertions should probably be done somewhere + // higher up the callstack const GrVertexAttrib* vertexAttribs = drawState.getVertexAttribs(); GrAssert(desc->fPositionAttributeIndex < GrDrawState::kVertexAttribCnt); - GrAssert(kAttribLayouts[vertexAttribs[desc->fPositionAttributeIndex].fType].fCount == 2); + GrAssert(GrGLAttribTypeToLayout(vertexAttribs[desc->fPositionAttributeIndex].fType).fCount == 2); if (requiresAttributeColors) { GrAssert(desc->fColorAttributeIndex < GrDrawState::kVertexAttribCnt); - GrAssert(kAttribLayouts[vertexAttribs[desc->fColorAttributeIndex].fType].fCount == 4); + GrAssert(GrGLAttribTypeToLayout(vertexAttribs[desc->fColorAttributeIndex].fType).fCount == 4); } if (requiresAttributeCoverage) { GrAssert(desc->fCoverageAttributeIndex < GrDrawState::kVertexAttribCnt); - GrAssert(kAttribLayouts[vertexAttribs[desc->fCoverageAttributeIndex].fType].fCount == 4); + GrAssert(GrGLAttribTypeToLayout(vertexAttribs[desc->fCoverageAttributeIndex].fType).fCount == 4); } if (desc->fAttribBindings & GrDrawState::kLocalCoords_AttribBindingsBit) { GrAssert(desc->fLocalCoordsAttributeIndex < GrDrawState::kVertexAttribCnt); - GrAssert(kAttribLayouts[vertexAttribs[desc->fLocalCoordsAttributeIndex].fType].fCount == 2); + GrAssert(GrGLAttribTypeToLayout(vertexAttribs[desc->fLocalCoordsAttributeIndex].fType).fCount == 2); } #endif } GrGLProgram* GrGLProgram::Create(const GrGLContext& gl, - const Desc& desc, + const GrGLProgramDesc& desc, const GrEffectStage* stages[]) { GrGLProgram* program = SkNEW_ARGS(GrGLProgram, (gl, desc, stages)); if (!program->succeeded()) { @@ -242,7 +235,7 @@ GrGLProgram* GrGLProgram::Create(const GrGLContext& gl, } GrGLProgram::GrGLProgram(const GrGLContext& gl, - const Desc& desc, + const GrGLProgramDesc& desc, const GrEffectStage* stages[]) : fContext(gl) , fUniformManager(gl) { @@ -291,13 +284,13 @@ void GrGLProgram::abandon() { void GrGLProgram::overrideBlend(GrBlendCoeff* srcCoeff, GrBlendCoeff* dstCoeff) const { switch (fDesc.fDualSrcOutput) { - case Desc::kNone_DualSrcOutput: + case GrGLProgramDesc::kNone_DualSrcOutput: break; // the prog will write a coverage value to the secondary // output and the dst is blended by one minus that value. - case Desc::kCoverage_DualSrcOutput: - case Desc::kCoverageISA_DualSrcOutput: - case Desc::kCoverageISC_DualSrcOutput: + case GrGLProgramDesc::kCoverage_DualSrcOutput: + case GrGLProgramDesc::kCoverageISA_DualSrcOutput: + case GrGLProgramDesc::kCoverageISC_DualSrcOutput: *dstCoeff = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff; break; default: @@ -413,24 +406,24 @@ void add_color_filter(GrGLShaderBuilder* builder, void GrGLProgram::genInputColor(GrGLShaderBuilder* builder, SkString* inColor) { switch (fDesc.fColorInput) { - case GrGLProgram::Desc::kAttribute_ColorInput: { + case GrGLProgramDesc::kAttribute_ColorInput: { builder->addAttribute(kVec4f_GrSLType, COL_ATTR_NAME); const char *vsName, *fsName; builder->addVarying(kVec4f_GrSLType, "Color", &vsName, &fsName); builder->vsCodeAppendf("\t%s = " COL_ATTR_NAME ";\n", vsName); *inColor = fsName; } break; - case GrGLProgram::Desc::kUniform_ColorInput: { + case GrGLProgramDesc::kUniform_ColorInput: { const char* name; fUniformHandles.fColorUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, kVec4f_GrSLType, "Color", &name); *inColor = name; break; } - case GrGLProgram::Desc::kTransBlack_ColorInput: + case GrGLProgramDesc::kTransBlack_ColorInput: GrAssert(!"needComputedColor should be false."); break; - case GrGLProgram::Desc::kSolidWhite_ColorInput: + case GrGLProgramDesc::kSolidWhite_ColorInput: break; default: GrCrash("Unknown color type."); @@ -497,7 +490,7 @@ const char* GrGLProgram::adjustInColor(const SkString& inColor) const { if (inColor.size()) { return inColor.c_str(); } else { - if (Desc::kSolidWhite_ColorInput == fDesc.fColorInput) { + if (GrGLProgramDesc::kSolidWhite_ColorInput == fDesc.fColorInput) { return GrGLSLOnesVecf(4); } else { return GrGLSLZerosVecf(4); @@ -636,7 +629,7 @@ bool GrGLProgram::genProgram(const GrEffectStage* stages[]) { // no need to do the color filter if coverage is 0. The output color is scaled by the coverage. // All the dual source outputs are scaled by the coverage as well. - if (Desc::kTransBlack_ColorInput == fDesc.fCoverageInput) { + if (GrGLProgramDesc::kTransBlack_ColorInput == fDesc.fCoverageInput) { colorCoeff = SkXfermode::kZero_Coeff; uniformCoeff = SkXfermode::kZero_Coeff; } @@ -644,7 +637,7 @@ bool GrGLProgram::genProgram(const GrEffectStage* stages[]) { // If we know the final color is going to be all zeros then we can // simplify the color filter coefficients. needComputedColor will then // come out false below. - if (Desc::kTransBlack_ColorInput == fDesc.fColorInput) { + if (GrGLProgramDesc::kTransBlack_ColorInput == fDesc.fColorInput) { colorCoeff = SkXfermode::kZero_Coeff; if (SkXfermode::kDC_Coeff == uniformCoeff || SkXfermode::kDA_Coeff == uniformCoeff) { @@ -724,7 +717,7 @@ bool GrGLProgram::genProgram(const GrEffectStage* stages[]) { // if have all ones or zeros for the "dst" input to the color filter then we // may be able to make additional optimizations. if (needColorFilterUniform && needComputedColor && !inColor.size()) { - GrAssert(Desc::kSolidWhite_ColorInput == fDesc.fColorInput); + GrAssert(GrGLProgramDesc::kSolidWhite_ColorInput == fDesc.fColorInput); bool uniformCoeffIsZero = SkXfermode::kIDC_Coeff == uniformCoeff || SkXfermode::kIDA_Coeff == uniformCoeff; if (uniformCoeffIsZero) { @@ -758,20 +751,20 @@ bool GrGLProgram::genProgram(const GrEffectStage* stages[]) { // compute the partial coverage (coverage stages and edge aa) SkString inCoverage; - bool coverageIsZero = Desc::kTransBlack_ColorInput == fDesc.fCoverageInput; + bool coverageIsZero = GrGLProgramDesc::kTransBlack_ColorInput == fDesc.fCoverageInput; // we don't need to compute coverage at all if we know the final shader // output will be zero and we don't have a dual src blend output. - if (!wroteFragColorZero || Desc::kNone_DualSrcOutput != fDesc.fDualSrcOutput) { + if (!wroteFragColorZero || GrGLProgramDesc::kNone_DualSrcOutput != fDesc.fDualSrcOutput) { if (!coverageIsZero) { switch (fDesc.fCoverageInput) { - case Desc::kSolidWhite_ColorInput: + case GrGLProgramDesc::kSolidWhite_ColorInput: // empty string implies solid white break; - case Desc::kAttribute_ColorInput: + case GrGLProgramDesc::kAttribute_ColorInput: gen_attribute_coverage(&builder, &inCoverage); break; - case Desc::kUniform_ColorInput: + case GrGLProgramDesc::kUniform_ColorInput: this->genUniformCoverage(&builder, &inCoverage); break; default: @@ -807,18 +800,18 @@ bool GrGLProgram::genProgram(const GrEffectStage* stages[]) { } } - if (Desc::kNone_DualSrcOutput != fDesc.fDualSrcOutput) { + if (GrGLProgramDesc::kNone_DualSrcOutput != fDesc.fDualSrcOutput) { builder.fFSOutputs.push_back().set(kVec4f_GrSLType, GrGLShaderVar::kOut_TypeModifier, dual_source_output_name()); bool outputIsZero = coverageIsZero; SkString coeff; if (!outputIsZero && - Desc::kCoverage_DualSrcOutput != fDesc.fDualSrcOutput && !wroteFragColorZero) { + GrGLProgramDesc::kCoverage_DualSrcOutput != fDesc.fDualSrcOutput && !wroteFragColorZero) { if (!inColor.size()) { outputIsZero = true; } else { - if (Desc::kCoverageISA_DualSrcOutput == fDesc.fDualSrcOutput) { + if (GrGLProgramDesc::kCoverageISA_DualSrcOutput == fDesc.fDualSrcOutput) { coeff.printf("(1 - %s.a)", inColor.c_str()); } else { coeff.printf("(vec4(1,1,1,1) - %s)", inColor.c_str()); @@ -1009,7 +1002,7 @@ void GrGLProgram::setColor(const GrDrawState& drawState, SharedGLState* sharedState) { if (!(drawState.getAttribBindings() & GrDrawState::kColor_AttribBindingsBit)) { switch (fDesc.fColorInput) { - case GrGLProgram::Desc::kAttribute_ColorInput: + case GrGLProgramDesc::kAttribute_ColorInput: if (sharedState->fConstAttribColor != color) { // OpenGL ES only supports the float varieties of glVertexAttrib GrGLfloat c[4]; @@ -1018,7 +1011,7 @@ void GrGLProgram::setColor(const GrDrawState& drawState, sharedState->fConstAttribColor = color; } break; - case GrGLProgram::Desc::kUniform_ColorInput: + case GrGLProgramDesc::kUniform_ColorInput: if (fColor != color) { // OpenGL ES doesn't support unsigned byte varieties of glUniform GrGLfloat c[4]; @@ -1029,8 +1022,8 @@ void GrGLProgram::setColor(const GrDrawState& drawState, fColor = color; } break; - case GrGLProgram::Desc::kSolidWhite_ColorInput: - case GrGLProgram::Desc::kTransBlack_ColorInput: + case GrGLProgramDesc::kSolidWhite_ColorInput: + case GrGLProgramDesc::kTransBlack_ColorInput: break; default: GrCrash("Unknown color type."); @@ -1043,7 +1036,7 @@ void GrGLProgram::setCoverage(const GrDrawState& drawState, SharedGLState* sharedState) { if (!(drawState.getAttribBindings() & GrDrawState::kCoverage_AttribBindingsBit)) { switch (fDesc.fCoverageInput) { - case Desc::kAttribute_ColorInput: + case GrGLProgramDesc::kAttribute_ColorInput: if (sharedState->fConstAttribCoverage != coverage) { // OpenGL ES only supports the float varieties of glVertexAttrib GrGLfloat c[4]; @@ -1052,7 +1045,7 @@ void GrGLProgram::setCoverage(const GrDrawState& drawState, sharedState->fConstAttribCoverage = coverage; } break; - case Desc::kUniform_ColorInput: + case GrGLProgramDesc::kUniform_ColorInput: if (fCoverage != coverage) { // OpenGL ES doesn't support unsigned byte varieties of glUniform GrGLfloat c[4]; @@ -1063,8 +1056,8 @@ void GrGLProgram::setCoverage(const GrDrawState& drawState, fCoverage = coverage; } break; - case Desc::kSolidWhite_ColorInput: - case Desc::kTransBlack_ColorInput: + case GrGLProgramDesc::kSolidWhite_ColorInput: + case GrGLProgramDesc::kTransBlack_ColorInput: break; default: GrCrash("Unknown coverage type."); diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h index 2dea59efd8..df46e9b58d 100644 --- a/src/gpu/gl/GrGLProgram.h +++ b/src/gpu/gl/GrGLProgram.h @@ -10,8 +10,8 @@ #define GrGLProgram_DEFINED #include "GrDrawState.h" -#include "GrGLEffect.h" #include "GrGLContext.h" +#include "GrGLProgramDesc.h" #include "GrGLSL.h" #include "GrGLTexture.h" #include "GrGLUniformManager.h" @@ -24,10 +24,6 @@ class GrGLEffect; class GrGLShaderBuilder; class SkMWCRandom; -// optionally compile the experimental GS code. Set to GR_DEBUG -// so that debug build bots will execute the code. -#define GR_GL_EXPERIMENTAL_GS GR_DEBUG - /** * This class manages a GPU program and records per-program information. * We can specify the attribute locations so that they are constant @@ -41,22 +37,8 @@ class GrGLProgram : public GrRefCnt { public: SK_DECLARE_INST_COUNT(GrGLProgram) - class Desc; - - /** - * Builds a program descriptor from a GrDrawState. Whether the primitive type is points, the - * output of GrDrawState::getBlendOpts, and the caps of the GrGpuGL are also inputs. - */ - static void BuildDesc(const GrDrawState&, - bool isPoints, - GrDrawState::BlendOptFlags, - GrBlendCoeff srcCoeff, - GrBlendCoeff dstCoeff, - const GrGpuGL* gpu, - Desc* outDesc); - static GrGLProgram* Create(const GrGLContext& gl, - const Desc& desc, + const GrGLProgramDesc& desc, const GrEffectStage* stages[]); virtual ~GrGLProgram(); @@ -71,7 +53,7 @@ public: */ void overrideBlend(GrBlendCoeff* srcCoeff, GrBlendCoeff* dstCoeff) const; - const Desc& getDesc() { return fDesc; } + const GrGLProgramDesc& getDesc() { return fDesc; } /** * Gets the GL program ID for this program. @@ -123,88 +105,9 @@ public: */ void setData(GrGpuGL*, GrColor color, GrColor coverage, SharedGLState*); - // Parameters that affect code generation - // This structs should be kept compact; it is input to an expensive hash key generator. - class Desc { - public: - Desc() { - // since we use this as part of a key we can't have any uninitialized - // padding - memset(this, 0, sizeof(Desc)); - } - - // returns this as a uint32_t array to be used as a key in the program cache - const uint32_t* asKey() const { - return reinterpret_cast(this); - } - - // For unit testing. - void setRandom(SkMWCRandom*, - const GrGpuGL* gpu, - const GrEffectStage stages[GrDrawState::kNumStages]); - - private: - // Specifies where the initial color comes from before the stages are applied. - enum ColorInput { - kSolidWhite_ColorInput, - kTransBlack_ColorInput, - kAttribute_ColorInput, - kUniform_ColorInput, - - kColorInputCnt - }; - // Dual-src blending makes use of a secondary output color that can be - // used as a per-pixel blend coefficient. This controls whether a - // secondary source is output and what value it holds. - enum DualSrcOutput { - kNone_DualSrcOutput, - kCoverage_DualSrcOutput, - kCoverageISA_DualSrcOutput, - kCoverageISC_DualSrcOutput, - - kDualSrcOutputCnt - }; - - // should the FS discard if the coverage is zero (to avoid stencil manipulation) - bool fDiscardIfZeroCoverage; - - // stripped of bits that don't affect program generation - GrAttribBindings fAttribBindings; - - /** Non-zero if this stage has an effect */ - GrGLEffect::EffectKey fEffectKeys[GrDrawState::kNumStages]; - - // To enable experimental geometry shader code (not for use in - // production) -#if GR_GL_EXPERIMENTAL_GS - bool fExperimentalGS; -#endif - uint8_t fColorInput; // casts to enum ColorInput - uint8_t fCoverageInput; // casts to enum ColorInput - uint8_t fDualSrcOutput; // casts to enum DualSrcOutput - int8_t fFirstCoverageStage; - SkBool8 fEmitsPointSize; - uint8_t fColorFilterXfermode; // casts to enum SkXfermode::Mode - - int8_t fPositionAttributeIndex; - int8_t fColorAttributeIndex; - int8_t fCoverageAttributeIndex; - int8_t fLocalCoordsAttributeIndex; - - friend class GrGLProgram; - }; - - // Layout information for OpenGL vertex attributes - struct AttribLayout { - GrGLint fCount; - GrGLenum fType; - GrGLboolean fNormalized; - }; - static const AttribLayout kAttribLayouts[kGrVertexAttribTypeCount]; - private: GrGLProgram(const GrGLContext& gl, - const Desc& desc, + const GrGLProgramDesc& desc, const GrEffectStage* stages[]); bool succeeded() const { return 0 != fProgramID; } @@ -281,7 +184,7 @@ private: GrGLEffect* fEffects[GrDrawState::kNumStages]; - Desc fDesc; + GrGLProgramDesc fDesc; const GrGLContext& fContext; GrGLUniformManager fUniformManager; diff --git a/src/gpu/gl/GrGLProgramDesc.h b/src/gpu/gl/GrGLProgramDesc.h new file mode 100644 index 0000000000..2835259868 --- /dev/null +++ b/src/gpu/gl/GrGLProgramDesc.h @@ -0,0 +1,104 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrGLProgramDesc_DEFINED +#define GrGLProgramDesc_DEFINED + +#include "GrGLEffect.h" + +class GrGpuGL; + +// optionally compile the experimental GS code. Set to GR_DEBUG so that debug build bots will +// execute the code. +#define GR_GL_EXPERIMENTAL_GS GR_DEBUG + + +/** This class describes a program to generate. It also serves as a program cache key. The only + thing GL-specific about this is the generation of GrGLEffect::EffectKeys. With some refactoring + it could be made backend-neutral. */ +class GrGLProgramDesc { +public: + GrGLProgramDesc() { + // since we use this as part of a key we can't have any uninitialized padding + memset(this, 0, sizeof(GrGLProgramDesc)); + } + + // Returns this as a uint32_t array to be used as a key in the program cache + const uint32_t* asKey() const { + return reinterpret_cast(this); + } + + // For unit testing. + void setRandom(SkMWCRandom*, + const GrGpuGL* gpu, + const GrEffectStage stages[GrDrawState::kNumStages]); + + /** + * Builds a program descriptor from a GrDrawState. Whether the primitive type is points, the + * output of GrDrawState::getBlendOpts, and the caps of the GrGpuGL are also inputs. + */ + static void Build(const GrDrawState&, + bool isPoints, + GrDrawState::BlendOptFlags, + GrBlendCoeff srcCoeff, + GrBlendCoeff dstCoeff, + const GrGpuGL* gpu, + GrGLProgramDesc* outDesc); + +private: + // Specifies where the initial color comes from before the stages are applied. + enum ColorInput { + kSolidWhite_ColorInput, + kTransBlack_ColorInput, + kAttribute_ColorInput, + kUniform_ColorInput, + + kColorInputCnt + }; + // Dual-src blending makes use of a secondary output color that can be + // used as a per-pixel blend coefficient. This controls whether a + // secondary source is output and what value it holds. + enum DualSrcOutput { + kNone_DualSrcOutput, + kCoverage_DualSrcOutput, + kCoverageISA_DualSrcOutput, + kCoverageISC_DualSrcOutput, + + kDualSrcOutputCnt + }; + + // should the FS discard if the coverage is zero (to avoid stencil manipulation) + bool fDiscardIfZeroCoverage; + + // stripped of bits that don't affect program generation + GrAttribBindings fAttribBindings; + + /** Non-zero if this stage has an effect */ + GrGLEffect::EffectKey fEffectKeys[GrDrawState::kNumStages]; + + // To enable experimental geometry shader code (not for use in + // production) +#if GR_GL_EXPERIMENTAL_GS + bool fExperimentalGS; +#endif + uint8_t fColorInput; // casts to enum ColorInput + uint8_t fCoverageInput; // casts to enum ColorInput + uint8_t fDualSrcOutput; // casts to enum DualSrcOutput + int8_t fFirstCoverageStage; + SkBool8 fEmitsPointSize; + uint8_t fColorFilterXfermode; // casts to enum SkXfermode::Mode + + int8_t fPositionAttributeIndex; + int8_t fColorAttributeIndex; + int8_t fCoverageAttributeIndex; + int8_t fLocalCoordsAttributeIndex; + + // GrGLProgram reads the private fields to generate code. + friend class GrGLProgram; +}; + +#endif diff --git a/src/gpu/gl/GrGLVertexArray.h b/src/gpu/gl/GrGLVertexArray.h index 5693f4a5e0..2d1ff2950d 100644 --- a/src/gpu/gl/GrGLVertexArray.h +++ b/src/gpu/gl/GrGLVertexArray.h @@ -9,6 +9,8 @@ #define GrGLVertexArray_DEFINED #include "GrResource.h" +#include "GrTypesPriv.h" +#include "gl/GrGLDefines.h" #include "gl/GrGLFunctions.h" #include "SkTArray.h" @@ -17,6 +19,30 @@ class GrGLVertexBuffer; class GrGLIndexBuffer; class GrGpuGL; +struct GrGLAttribLayout { + GrGLint fCount; + GrGLenum fType; + GrGLboolean fNormalized; +}; + +static inline const GrGLAttribLayout& GrGLAttribTypeToLayout(GrVertexAttribType type) { + GrAssert(type >= 0 && type < kGrVertexAttribTypeCount); + static const GrGLAttribLayout kLayouts[kGrVertexAttribTypeCount] = { + {1, GR_GL_FLOAT, false}, // kFloat_GrVertexAttribType + {2, GR_GL_FLOAT, false}, // kVec2f_GrVertexAttribType + {3, GR_GL_FLOAT, false}, // kVec3f_GrVertexAttribType + {4, GR_GL_FLOAT, false}, // kVec4f_GrVertexAttribType + {4, GR_GL_UNSIGNED_BYTE, true}, // kVec4ub_GrVertexAttribType + }; + GR_STATIC_ASSERT(0 == kFloat_GrVertexAttribType); + GR_STATIC_ASSERT(1 == kVec2f_GrVertexAttribType); + GR_STATIC_ASSERT(2 == kVec3f_GrVertexAttribType); + GR_STATIC_ASSERT(3 == kVec4f_GrVertexAttribType); + GR_STATIC_ASSERT(4 == kVec4ub_GrVertexAttribType); + GR_STATIC_ASSERT(SK_ARRAY_COUNT(kLayouts) == kGrVertexAttribTypeCount); + return kLayouts[type]; +} + /** * This sets and tracks the vertex attribute array state. It is used internally by GrGLVertexArray * (below) but is separate because it is also used to track the state of vertex array object 0. diff --git a/src/gpu/gl/GrGpuGL.h b/src/gpu/gl/GrGpuGL.h index 423d87fe16..c95b40ad46 100644 --- a/src/gpu/gl/GrGpuGL.h +++ b/src/gpu/gl/GrGpuGL.h @@ -163,10 +163,10 @@ private: ~ProgramCache(); void abandon(); - GrGLProgram* getProgram(const GrGLProgram::Desc& desc, const GrEffectStage* stages[]); + GrGLProgram* getProgram(const GrGLProgramDesc& desc, const GrEffectStage* stages[]); private: enum { - kKeySize = sizeof(GrGLProgram::Desc), + kKeySize = sizeof(GrGLProgramDesc), // We may actually have kMaxEntries+1 shaders in the GL context because we create a new // shader before evicting from the cache. kMaxEntries = 32 diff --git a/src/gpu/gl/GrGpuGL_program.cpp b/src/gpu/gl/GrGpuGL_program.cpp index a07ad02501..8f527f878d 100644 --- a/src/gpu/gl/GrGpuGL_program.cpp +++ b/src/gpu/gl/GrGpuGL_program.cpp @@ -48,7 +48,7 @@ void GrGpuGL::ProgramCache::abandon() { fCount = 0; } -GrGLProgram* GrGpuGL::ProgramCache::getProgram(const GrGLProgram::Desc& desc, +GrGLProgram* GrGpuGL::ProgramCache::getProgram(const GrGLProgramDesc& desc, const GrEffectStage* stages[]) { Entry newEntry; newEntry.fKey.setKeyData(desc.asKey()); @@ -180,8 +180,8 @@ bool GrGpuGL::flushGraphicsState(DrawType type) { for (int i = 0; i < GrDrawState::kNumStages; ++i) { stages[i] = drawState.isStageEnabled(i) ? &drawState.getStage(i) : NULL; } - GrGLProgram::Desc desc; - GrGLProgram::BuildDesc(this->getDrawState(), + GrGLProgramDesc desc; + GrGLProgramDesc::Build(this->getDrawState(), kDrawPoints_DrawType == type, blendOpts, srcCoeff, @@ -302,9 +302,9 @@ void GrGpuGL::setupGeometry(const DrawInfo& info, size_t* indexOffsetInBytes) { attribState->set(this, vertexAttribIndex, vbuf, - GrGLProgram::kAttribLayouts[attribType].fCount, - GrGLProgram::kAttribLayouts[attribType].fType, - GrGLProgram::kAttribLayouts[attribType].fNormalized, + GrGLAttribTypeToLayout(attribType).fCount, + GrGLAttribTypeToLayout(attribType).fType, + GrGLAttribTypeToLayout(attribType).fNormalized, stride, reinterpret_cast( vertexOffsetInBytes + vertexAttrib->fOffset)); diff --git a/tests/GLProgramsTest.cpp b/tests/GLProgramsTest.cpp index afbc1221ad..13cf85c81d 100644 --- a/tests/GLProgramsTest.cpp +++ b/tests/GLProgramsTest.cpp @@ -21,9 +21,9 @@ #include "SkRandom.h" #include "Test.h" -void GrGLProgram::Desc::setRandom(SkMWCRandom* random, - const GrGpuGL* gpu, - const GrEffectStage stages[GrDrawState::kNumStages]) { +void GrGLProgramDesc::setRandom(SkMWCRandom* random, + const GrGpuGL* gpu, + const GrEffectStage stages[GrDrawState::kNumStages]) { fAttribBindings = 0; fEmitsPointSize = random->nextBool(); fColorInput = random->nextULessThan(kColorInputCnt); @@ -106,7 +106,7 @@ bool GrGpuGL::programUnitTest(int maxStages) { } #endif - GrGLProgram::Desc pdesc; + GrGLProgramDesc pdesc; GrEffectStage stages[GrDrawState::kNumStages]; int currAttribIndex = GrDrawState::kAttribIndexCount;