123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- /*
- * Copyright 2015 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
- #ifndef GrGLSLVarying_DEFINED
- #define GrGLSLVarying_DEFINED
- #include "include/private/GrTypesPriv.h"
- #include "src/gpu/GrAllocator.h"
- #include "src/gpu/GrGeometryProcessor.h"
- #include "src/gpu/GrShaderVar.h"
- #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
- class GrGLSLProgramBuilder;
- #ifdef SK_DEBUG
- static bool is_matrix(GrSLType type) {
- switch (type) {
- case kFloat2x2_GrSLType:
- case kFloat3x3_GrSLType:
- case kFloat4x4_GrSLType:
- case kHalf2x2_GrSLType:
- case kHalf3x3_GrSLType:
- case kHalf4x4_GrSLType:
- return true;
- default:
- return false;
- }
- }
- #endif
- class GrGLSLVarying {
- public:
- enum class Scope {
- kVertToFrag,
- kVertToGeo,
- kGeoToFrag
- };
- GrGLSLVarying() = default;
- GrGLSLVarying(GrSLType type, Scope scope = Scope::kVertToFrag)
- : fType(type)
- , fScope(scope) {
- // Metal doesn't support varying matrices, so we disallow them everywhere for consistency
- SkASSERT(!is_matrix(type));
- }
- void reset(GrSLType type, Scope scope = Scope::kVertToFrag) {
- // Metal doesn't support varying matrices, so we disallow them everywhere for consistency
- SkASSERT(!is_matrix(type));
- *this = GrGLSLVarying();
- fType = type;
- fScope = scope;
- }
- GrSLType type() const { return fType; }
- Scope scope() const { return fScope; }
- bool isInVertexShader() const { return Scope::kGeoToFrag != fScope; }
- bool isInFragmentShader() const { return Scope::kVertToGeo != fScope; }
- const char* vsOut() const { SkASSERT(this->isInVertexShader()); return fVsOut; }
- const char* gsIn() const { return fGsIn; }
- const char* gsOut() const { return fGsOut; }
- const char* fsIn() const { SkASSERT(this->isInFragmentShader()); return fFsIn; }
- private:
- GrSLType fType = kVoid_GrSLType;
- Scope fScope = Scope::kVertToFrag;
- const char* fVsOut = nullptr;
- const char* fGsIn = nullptr;
- const char* fGsOut = nullptr;
- const char* fFsIn = nullptr;
- friend class GrGLSLVaryingHandler;
- };
- static const int kVaryingsPerBlock = 8;
- class GrGLSLVaryingHandler {
- public:
- explicit GrGLSLVaryingHandler(GrGLSLProgramBuilder* program)
- : fVaryings(kVaryingsPerBlock)
- , fVertexInputs(kVaryingsPerBlock)
- , fVertexOutputs(kVaryingsPerBlock)
- , fGeomInputs(kVaryingsPerBlock)
- , fGeomOutputs(kVaryingsPerBlock)
- , fFragInputs(kVaryingsPerBlock)
- , fFragOutputs(kVaryingsPerBlock)
- , fProgramBuilder(program)
- , fDefaultInterpolationModifier(nullptr) {}
- virtual ~GrGLSLVaryingHandler() {}
- /*
- * Notifies the varying handler that this shader will never emit geometry in perspective and
- * therefore does not require perspective-correct interpolation. When supported, this allows
- * varyings to use the "noperspective" keyword, which means the GPU can use cheaper math for
- * interpolation.
- */
- void setNoPerspective();
- enum class Interpolation {
- kInterpolated,
- kCanBeFlat, // Use "flat" if it will be faster.
- kMustBeFlat // Use "flat" even if it is known to be slow.
- };
- /*
- * addVarying allows fine grained control for setting up varyings between stages. Calling this
- * function will make sure all necessary decls are setup for the client. The client however is
- * responsible for setting up all shader code (e.g "vOut = vIn;") If you just need to take an
- * attribute and pass it through to an output value in a fragment shader, use
- * addPassThroughAttribute.
- * TODO convert most uses of addVarying to addPassThroughAttribute
- */
- void addVarying(const char* name, GrGLSLVarying* varying,
- Interpolation = Interpolation::kInterpolated);
- /*
- * The GP can use these calls to pass an attribute through all shaders directly to 'output' in
- * the fragment shader. Though these calls affect both the vertex shader and fragment shader,
- * they expect 'output' to be defined in the fragment shader before the call is made. If there
- * is a geometry shader, we will simply take the value of the varying from the first vertex and
- * that will be set as the output varying for all emitted vertices.
- * TODO it might be nicer behavior to have a flag to declare output inside these calls
- */
- void addPassThroughAttribute(const GrGeometryProcessor::Attribute&, const char* output,
- Interpolation = Interpolation::kInterpolated);
- void emitAttributes(const GrGeometryProcessor& gp);
- // This should be called once all attributes and varyings have been added to the
- // GrGLSLVaryingHanlder and before getting/adding any of the declarations to the shaders.
- void finalize();
- void getVertexDecls(SkString* inputDecls, SkString* outputDecls) const;
- void getGeomDecls(SkString* inputDecls, SkString* outputDecls) const;
- void getFragDecls(SkString* inputDecls, SkString* outputDecls) const;
- protected:
- struct VaryingInfo {
- GrSLType fType;
- bool fIsFlat;
- SkString fVsOut;
- SkString fGsOut;
- GrShaderFlags fVisibility;
- };
- typedef GrTAllocator<VaryingInfo> VaryingList;
- typedef GrTAllocator<GrShaderVar> VarArray;
- typedef GrGLSLProgramDataManager::VaryingHandle VaryingHandle;
- VaryingList fVaryings;
- VarArray fVertexInputs;
- VarArray fVertexOutputs;
- VarArray fGeomInputs;
- VarArray fGeomOutputs;
- VarArray fFragInputs;
- VarArray fFragOutputs;
- // This is not owned by the class
- GrGLSLProgramBuilder* fProgramBuilder;
- private:
- void addAttribute(const GrShaderVar& var);
- virtual void onFinalize() = 0;
- // helper function for get*Decls
- void appendDecls(const VarArray& vars, SkString* out) const;
- const char* fDefaultInterpolationModifier;
- friend class GrGLSLProgramBuilder;
- };
- #endif
|