blob: 08b3ef5ef5e14b3286f166613e3413ea19029bf0 [file] [log] [blame]
tomhudson@google.comf9ad8862012-05-11 20:38:48 +00001/*
2 * Copyright 2012 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 GrGLShaderBuilder_DEFINED
9#define GrGLShaderBuilder_DEFINED
10
11#include "GrAllocator.h"
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +000012#include "GrBackendEffectFactory.h"
bsalomon@google.coma469c282012-10-24 18:28:34 +000013#include "GrEffect.h"
tomhudson@google.comf9ad8862012-05-11 20:38:48 +000014#include "gl/GrGLSL.h"
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000015#include "gl/GrGLUniformManager.h"
tomhudson@google.comf9ad8862012-05-11 20:38:48 +000016
bsalomon@google.comf910d3b2013-03-07 17:06:57 +000017#include <stdarg.h>
18
bsalomon@google.comad5e9372012-07-11 18:11:27 +000019class GrGLContextInfo;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000020
tomhudson@google.comf9ad8862012-05-11 20:38:48 +000021/**
bsalomon@google.comeb715c82012-07-11 15:03:31 +000022 Contains all the incremental state of a shader as it is being built,as well as helpers to
23 manipulate that state.
tomhudson@google.comf9ad8862012-05-11 20:38:48 +000024*/
tomhudson@google.comf9ad8862012-05-11 20:38:48 +000025class GrGLShaderBuilder {
tomhudson@google.comf9ad8862012-05-11 20:38:48 +000026public:
bsalomon@google.comf06df1b2012-09-06 20:22:31 +000027 /**
bsalomon@google.com34cccde2013-01-04 18:34:30 +000028 * Passed to GrGLEffects to add texture reads to their shader code.
bsalomon@google.comf06df1b2012-09-06 20:22:31 +000029 */
30 class TextureSampler {
31 public:
32 TextureSampler()
33 : fTextureAccess(NULL)
bsalomon@google.comf06df1b2012-09-06 20:22:31 +000034 , fSamplerUniform(GrGLUniformManager::kInvalidUniformHandle) {}
35
36 TextureSampler(const TextureSampler& other) { *this = other; }
37
38 TextureSampler& operator= (const TextureSampler& other) {
39 GrAssert(NULL == fTextureAccess);
40 GrAssert(GrGLUniformManager::kInvalidUniformHandle == fSamplerUniform);
41
bsalomon@google.comf06df1b2012-09-06 20:22:31 +000042 fTextureAccess = other.fTextureAccess;
43 fSamplerUniform = other.fSamplerUniform;
44 return *this;
45 }
46
47 const GrTextureAccess* textureAccess() const { return fTextureAccess; }
48
49 private:
bsalomon@google.com34cccde2013-01-04 18:34:30 +000050 // The idx param is used to ensure multiple samplers within a single effect have unique
51 // uniform names.
52 void init(GrGLShaderBuilder* builder, const GrTextureAccess* access, int idx) {
bsalomon@google.comf06df1b2012-09-06 20:22:31 +000053 GrAssert(NULL == fTextureAccess);
bsalomon@google.comf06df1b2012-09-06 20:22:31 +000054 GrAssert(GrGLUniformManager::kInvalidUniformHandle == fSamplerUniform);
55
56 GrAssert(NULL != builder);
57 GrAssert(NULL != access);
bsalomon@google.com34cccde2013-01-04 18:34:30 +000058 SkString name;
59 name.printf("Sampler%d_", idx);
bsalomon@google.comf06df1b2012-09-06 20:22:31 +000060 fSamplerUniform = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
61 kSampler2D_GrSLType,
bsalomon@google.com34cccde2013-01-04 18:34:30 +000062 name.c_str());
bsalomon@google.comf06df1b2012-09-06 20:22:31 +000063 GrAssert(GrGLUniformManager::kInvalidUniformHandle != fSamplerUniform);
64
65 fTextureAccess = access;
bsalomon@google.comf06df1b2012-09-06 20:22:31 +000066 }
67
68 const GrTextureAccess* fTextureAccess;
bsalomon@google.comf06df1b2012-09-06 20:22:31 +000069 GrGLUniformManager::UniformHandle fSamplerUniform;
70
71 friend class GrGLShaderBuilder; // to access fSamplerUniform
72 friend class GrGLProgram; // to construct these and access fSamplerUniform.
73 };
74
75 typedef SkTArray<TextureSampler> TextureSamplerArray;
76
bsalomon@google.comeb715c82012-07-11 15:03:31 +000077 enum ShaderType {
78 kVertex_ShaderType = 0x1,
79 kGeometry_ShaderType = 0x2,
80 kFragment_ShaderType = 0x4,
81 };
82
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000083 GrGLShaderBuilder(const GrGLContextInfo&, GrGLUniformManager&);
tomhudson@google.comf9ad8862012-05-11 20:38:48 +000084
bsalomon@google.comf910d3b2013-03-07 17:06:57 +000085 /**
86 * Called by GrGLEffects to add code to one of the shaders.
87 */
88 void vsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
89 va_list args;
90 va_start(args, format);
91 this->codeAppendf(kVertex_ShaderType, format, args);
92 va_end(args);
93 }
94
95 void gsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
96 va_list args;
97 va_start(args, format);
98 this->codeAppendf(kGeometry_ShaderType, format, args);
99 va_end(args);
100 }
101
102 void fsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
103 va_list args;
104 va_start(args, format);
105 this->codeAppendf(kFragment_ShaderType, format, args);
106 va_end(args);
107 }
108
109 void vsCodeAppend(const char* str) { this->codeAppend(kVertex_ShaderType, str); }
110 void gsCodeAppend(const char* str) { this->codeAppend(kGeometry_ShaderType, str); }
111 void fsCodeAppend(const char* str) { this->codeAppend(kFragment_ShaderType, str); }
112
bsalomon@google.comdbe49f72012-11-05 16:36:02 +0000113 /** Appends a 2D texture sample with projection if necessary. coordType must either be Vec2f or
114 Vec3f. The latter is interpreted as projective texture coords. The vec length and swizzle
115 order of the result depends on the GrTextureAccess associated with the TextureSampler. */
bsalomon@google.com868a8e72012-08-30 19:11:34 +0000116 void appendTextureLookup(SkString* out,
bsalomon@google.comf06df1b2012-09-06 20:22:31 +0000117 const TextureSampler&,
bsalomon@google.comdbe49f72012-11-05 16:36:02 +0000118 const char* coordName,
bsalomon@google.com868a8e72012-08-30 19:11:34 +0000119 GrSLType coordType = kVec2f_GrSLType) const;
tomhudson@google.com52598142012-05-24 17:44:30 +0000120
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000121 /** Version of above that appends the result to the shader code rather than an SkString.
122 Currently the shader type must be kFragment */
123 void appendTextureLookup(ShaderType,
124 const TextureSampler&,
125 const char* coordName,
126 GrSLType coordType = kVec2f_GrSLType);
127
128
bsalomon@google.com2d8edaf2012-09-07 14:47:31 +0000129 /** Does the work of appendTextureLookup and modulates the result by modulation. The result is
130 always a vec4. modulation and the swizzle specified by TextureSampler must both be vec4 or
131 float. If modulation is "" or NULL it this function acts as though appendTextureLookup were
132 called. */
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000133 void appendTextureLookupAndModulate(ShaderType,
bsalomon@google.com868a8e72012-08-30 19:11:34 +0000134 const char* modulation,
bsalomon@google.comf06df1b2012-09-06 20:22:31 +0000135 const TextureSampler&,
bsalomon@google.comdbe49f72012-11-05 16:36:02 +0000136 const char* coordName,
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000137 GrSLType coordType = kVec2f_GrSLType);
bsalomon@google.com34bcb9f2012-08-28 18:20:18 +0000138
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000139 /** Emits a helper function outside of main(). Currently ShaderType must be
140 kFragment_ShaderType. */
141 void emitFunction(ShaderType shader,
142 GrSLType returnType,
143 const char* name,
144 int argCnt,
145 const GrGLShaderVar* args,
146 const char* body,
147 SkString* outName);
148
bsalomon@google.com46fba0d2012-10-25 21:42:05 +0000149 /** Generates a EffectKey for the shader code based on the texture access parameters and the
twiz@google.coma5e65ec2012-08-02 15:15:16 +0000150 capabilities of the GL context. This is useful for keying the shader programs that may
151 have multiple representations, based on the type/format of textures used. */
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +0000152 static GrBackendEffectFactory::EffectKey KeyForTextureAccess(const GrTextureAccess&,
153 const GrGLCaps&);
twiz@google.coma5e65ec2012-08-02 15:15:16 +0000154
bsalomon@google.com6d003d12012-09-11 15:45:20 +0000155 /** If texture swizzling is available using tex parameters then it is preferred over mangling
156 the generated shader code. This potentially allows greater reuse of cached shaders. */
157 static const GrGLenum* GetTexParamSwizzle(GrPixelConfig config, const GrGLCaps& caps);
158
bsalomon@google.com706f6682012-10-23 14:53:55 +0000159 /** Add a uniform variable to the current program, that has visibility in one or more shaders.
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000160 visibility is a bitfield of ShaderType values indicating from which shaders the uniform
161 should be accessible. At least one bit must be set. Geometry shader uniforms are not
162 supported at this time. The actual uniform name will be mangled. If outName is not NULL then
163 it will refer to the final uniform name after return. Use the addUniformArray variant to add
164 an array of uniforms.
tomhudson@google.com242ed6f2012-05-30 17:38:57 +0000165 */
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000166 GrGLUniformManager::UniformHandle addUniform(uint32_t visibility,
167 GrSLType type,
168 const char* name,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000169 const char** outName = NULL) {
170 return this->addUniformArray(visibility, type, name, GrGLShaderVar::kNonArray, outName);
171 }
172 GrGLUniformManager::UniformHandle addUniformArray(uint32_t visibility,
173 GrSLType type,
174 const char* name,
175 int arrayCount,
176 const char** outName = NULL);
bsalomon@google.com032b2212012-07-16 13:36:18 +0000177
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000178 const GrGLShaderVar& getUniformVariable(GrGLUniformManager::UniformHandle) const;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000179
180 /**
bsalomon@google.com706f6682012-10-23 14:53:55 +0000181 * Shortcut for getUniformVariable(u).c_str()
bsalomon@google.com032b2212012-07-16 13:36:18 +0000182 */
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000183 const char* getUniformCStr(GrGLUniformManager::UniformHandle u) const {
bsalomon@google.com032b2212012-07-16 13:36:18 +0000184 return this->getUniformVariable(u).c_str();
185 }
tomhudson@google.com242ed6f2012-05-30 17:38:57 +0000186
bsalomon@google.comeb715c82012-07-11 15:03:31 +0000187 /** Add a varying variable to the current program to pass values between vertex and fragment
188 shaders. If the last two parameters are non-NULL, they are filled in with the name
189 generated. */
tomhudson@google.com23cb2292012-05-30 18:26:03 +0000190 void addVarying(GrSLType type,
191 const char* name,
192 const char** vsOutName = NULL,
193 const char** fsInName = NULL);
194
bsalomon@google.com706f6682012-10-23 14:53:55 +0000195 /** Returns a variable name that represents the position of the fragment in the FS. The position
196 is in device space (e.g. 0,0 is the top left and pixel centers are at half-integers). */
197 const char* fragmentPosition();
198
bsalomon@google.com17504f52012-10-30 12:34:25 +0000199 /** Returns a vertex attribute that represents the vertex position in the VS. This is the
200 pre-matrix position and is commonly used by effects to compute texture coords via a matrix.
201 */
202 const GrGLShaderVar& positionAttribute() const { return *fPositionVar; }
203
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000204 /**
205 * Interfaces used by GrGLProgram.
206 * TODO: Hide these from the GrEffects using friend or splitting this into two related classes.
207 * Also, GrGLProgram's shader string construction should be moved to this class.
208 */
209
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000210 /** Called after building is complete to get the final shader string. */
211 void getShader(ShaderType, SkString*) const;
212
bsalomon@google.com08283af2012-10-26 13:01:20 +0000213 void setCurrentStage(int stageIdx) { fCurrentStageIdx = stageIdx; }
214 void setNonStage() { fCurrentStageIdx = kNonStageIdx; }
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000215 // TODO: move remainder of shader code generation to this class and call this privately
216 // Handles of sampler uniforms generated for the effect are appended to samplerHandles.
217 GrGLEffect* createAndEmitGLEffect(
218 const GrEffectStage& stage,
219 GrBackendEffectFactory::EffectKey key,
220 const char* fsInColor, // NULL means no incoming color
221 const char* fsOutColor,
skia.committer@gmail.com8ae714b2013-01-05 02:02:05 +0000222 const char* vsInCoord,
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000223 SkTArray<GrGLUniformManager::UniformHandle, true>* samplerHandles);
bsalomon@google.com706f6682012-10-23 14:53:55 +0000224 GrGLUniformManager::UniformHandle getRTHeightUniform() const { return fRTHeightUniform; }
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000225 // TODO: Make this do all the compiling, linking, etc.
226 void finished(GrGLuint programID);
bsalomon@google.com706f6682012-10-23 14:53:55 +0000227
robertphillips@google.com13f181f2013-03-02 12:02:08 +0000228 const GrGLContextInfo& ctxInfo() const { return fCtxInfo; }
229
bsalomon@google.com032b2212012-07-16 13:36:18 +0000230private:
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000231 void codeAppendf(ShaderType type, const char format[], va_list args);
232 void codeAppend(ShaderType type, const char* str);
233
bsalomon@google.com032b2212012-07-16 13:36:18 +0000234 typedef GrTAllocator<GrGLShaderVar> VarArray;
235
bsalomon@google.com032b2212012-07-16 13:36:18 +0000236 void appendDecls(const VarArray&, SkString*) const;
237 void appendUniformDecls(ShaderType, SkString*) const;
238
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000239 typedef GrGLUniformManager::BuilderUniform BuilderUniform;
240 GrGLUniformManager::BuilderUniformArray fUniforms;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000241
bsalomon@google.comeb715c82012-07-11 15:03:31 +0000242 // TODO: Everything below here private.
bsalomon@google.com032b2212012-07-16 13:36:18 +0000243public:
bsalomon@google.comeb715c82012-07-11 15:03:31 +0000244
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000245 SkString fHeader; // VS+FS, GLSL version, etc
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000246 VarArray fVSAttrs;
247 VarArray fVSOutputs;
248 VarArray fGSInputs;
249 VarArray fGSOutputs;
250 VarArray fFSInputs;
251 SkString fGSHeader; // layout qualifiers specific to GS
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000252 VarArray fFSOutputs;
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000253 bool fUsesGS;
tomhudson@google.com040c41a2012-05-18 14:57:40 +0000254
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000255private:
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000256 enum {
257 kNonStageIdx = -1,
258 };
259
robertphillips@google.com6177e692013-02-28 20:16:25 +0000260 const GrGLContextInfo& fCtxInfo;
bsalomon@google.com706f6682012-10-23 14:53:55 +0000261 GrGLUniformManager& fUniformManager;
bsalomon@google.com08283af2012-10-26 13:01:20 +0000262 int fCurrentStageIdx;
bsalomon@google.com706f6682012-10-23 14:53:55 +0000263 SkString fFSFunctions;
264 SkString fFSHeader;
265
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000266 SkString fFSCode;
267 SkString fVSCode;
268 SkString fGSCode;
269
bsalomon@google.com706f6682012-10-23 14:53:55 +0000270 bool fSetupFragPosition;
271 GrGLUniformManager::UniformHandle fRTHeightUniform;
bsalomon@google.com34bcb9f2012-08-28 18:20:18 +0000272
bsalomon@google.com17504f52012-10-30 12:34:25 +0000273 GrGLShaderVar* fPositionVar;
tomhudson@google.comf9ad8862012-05-11 20:38:48 +0000274};
275
276#endif