1/* 2 * Copyright 2015 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#ifndef GrGLSLVarying_DEFINED 9#define GrGLSLVarying_DEFINED 10 11#include "GrAllocator.h" 12#include "GrGeometryProcessor.h" 13#include "GrShaderVar.h" 14#include "GrTypesPriv.h" 15#include "glsl/GrGLSLProgramDataManager.h" 16 17class GrGLSLProgramBuilder; 18 19class GrGLSLVarying { 20public: 21 enum class Scope { 22 kVertToFrag, 23 kVertToGeo, 24 kGeoToFrag 25 }; 26 27 GrGLSLVarying() = default; 28 GrGLSLVarying(GrSLType type, Scope scope = Scope::kVertToFrag) : fType(type), fScope(scope) {} 29 30 void reset(GrSLType type, Scope scope = Scope::kVertToFrag) { 31 *this = GrGLSLVarying(); 32 fType = type; 33 fScope = scope; 34 } 35 36 GrSLType type() const { return fType; } 37 Scope scope() const { return fScope; } 38 bool isInVertexShader() const { return Scope::kGeoToFrag != fScope; } 39 bool isInFragmentShader() const { return Scope::kVertToGeo != fScope; } 40 41 const char* vsOut() const { SkASSERT(this->isInVertexShader()); return fVsOut; } 42 const char* gsIn() const { return fGsIn; } 43 const char* gsOut() const { return fGsOut; } 44 const char* fsIn() const { SkASSERT(this->isInFragmentShader()); return fFsIn; } 45 46private: 47 GrSLType fType = kVoid_GrSLType; 48 Scope fScope = Scope::kVertToFrag; 49 const char* fVsOut = nullptr; 50 const char* fGsIn = nullptr; 51 const char* fGsOut = nullptr; 52 const char* fFsIn = nullptr; 53 54 friend class GrGLSLVaryingHandler; 55}; 56 57static const int kVaryingsPerBlock = 8; 58 59class GrGLSLVaryingHandler { 60public: 61 explicit GrGLSLVaryingHandler(GrGLSLProgramBuilder* program) 62 : fVaryings(kVaryingsPerBlock) 63 , fVertexInputs(kVaryingsPerBlock) 64 , fVertexOutputs(kVaryingsPerBlock) 65 , fGeomInputs(kVaryingsPerBlock) 66 , fGeomOutputs(kVaryingsPerBlock) 67 , fFragInputs(kVaryingsPerBlock) 68 , fFragOutputs(kVaryingsPerBlock) 69 , fProgramBuilder(program) 70 , fDefaultInterpolationModifier(nullptr) {} 71 72 virtual ~GrGLSLVaryingHandler() {} 73 74 /* 75 * Notifies the varying handler that this shader will never emit geometry in perspective and 76 * therefore does not require perspective-correct interpolation. When supported, this allows 77 * varyings to use the "noperspective" keyword, which means the GPU can use cheaper math for 78 * interpolation. 79 */ 80 void setNoPerspective(); 81 82 /* 83 * addVarying allows fine grained control for setting up varyings between stages. Calling this 84 * function will make sure all necessary decls are setup for the client. The client however is 85 * responsible for setting up all shader code (e.g "vOut = vIn;") If you just need to take an 86 * attribute and pass it through to an output value in a fragment shader, use 87 * addPassThroughAttribute. 88 * TODO convert most uses of addVarying to addPassThroughAttribute 89 */ 90 void addVarying(const char* name, GrGLSLVarying* varying) { 91 SkASSERT(GrSLTypeIsFloatType(varying->type())); // Integers must use addFlatVarying. 92 this->internalAddVarying(name, varying, false /*flat*/); 93 } 94 95 /* 96 * addFlatVarying sets up a varying whose value is constant across every fragment. The graphics 97 * pipeline will pull its value from the final vertex of the draw primitive (provoking vertex). 98 * Flat interpolation is not always supported and the user must check the caps before using. 99 * TODO: Some platforms can change the provoking vertex. Should we be resetting this knob? 100 */ 101 void addFlatVarying(const char* name, GrGLSLVarying* varying) { 102 this->internalAddVarying(name, varying, true /*flat*/); 103 } 104 105 /* 106 * The GP can use these calls to pass an attribute through all shaders directly to 'output' in 107 * the fragment shader. Though these calls affect both the vertex shader and fragment shader, 108 * they expect 'output' to be defined in the fragment shader before the call is made. If there 109 * is a geometry shader, we will simply take the value of the varying from the first vertex and 110 * that will be set as the output varying for all emitted vertices. 111 * TODO it might be nicer behavior to have a flag to declare output inside these calls 112 */ 113 void addPassThroughAttribute(const GrGeometryProcessor::Attribute*, const char* output); 114 void addFlatPassThroughAttribute(const GrGeometryProcessor::Attribute*, const char* output); 115 116 void emitAttributes(const GrGeometryProcessor& gp); 117 118 // This should be called once all attributes and varyings have been added to the 119 // GrGLSLVaryingHanlder and before getting/adding any of the declarations to the shaders. 120 void finalize(); 121 122 void getVertexDecls(SkString* inputDecls, SkString* outputDecls) const; 123 void getGeomDecls(SkString* inputDecls, SkString* outputDecls) const; 124 void getFragDecls(SkString* inputDecls, SkString* outputDecls) const; 125 126protected: 127 struct VaryingInfo { 128 GrSLType fType; 129 bool fIsFlat; 130 SkString fVsOut; 131 SkString fGsOut; 132 GrShaderFlags fVisibility; 133 }; 134 135 typedef GrTAllocator<VaryingInfo> VaryingList; 136 typedef GrTAllocator<GrShaderVar> VarArray; 137 typedef GrGLSLProgramDataManager::VaryingHandle VaryingHandle; 138 139 VaryingList fVaryings; 140 VarArray fVertexInputs; 141 VarArray fVertexOutputs; 142 VarArray fGeomInputs; 143 VarArray fGeomOutputs; 144 VarArray fFragInputs; 145 VarArray fFragOutputs; 146 147 // This is not owned by the class 148 GrGLSLProgramBuilder* fProgramBuilder; 149 150private: 151 void internalAddVarying(const char* name, GrGLSLVarying*, bool flat); 152 void writePassThroughAttribute(const GrGeometryProcessor::Attribute*, const char* output, 153 const GrGLSLVarying&); 154 155 void addAttribute(const GrShaderVar& var); 156 157 virtual void onFinalize() = 0; 158 159 // helper function for get*Decls 160 void appendDecls(const VarArray& vars, SkString* out) const; 161 162 const char* fDefaultInterpolationModifier; 163 164 friend class GrGLSLProgramBuilder; 165}; 166 167#endif 168