blob: d947771b3e9164855f12402d23e1a4ba8b4b4886 [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.comb8eb2e82013-03-28 13:46:42 +000013#include "GrColor.h"
bsalomon@google.coma469c282012-10-24 18:28:34 +000014#include "GrEffect.h"
tomhudson@google.comf9ad8862012-05-11 20:38:48 +000015#include "gl/GrGLSL.h"
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000016#include "gl/GrGLUniformManager.h"
tomhudson@google.comf9ad8862012-05-11 20:38:48 +000017
bsalomon@google.comf910d3b2013-03-07 17:06:57 +000018#include <stdarg.h>
19
bsalomon@google.comad5e9372012-07-11 18:11:27 +000020class GrGLContextInfo;
bsalomon@google.comc7818882013-03-20 19:19:53 +000021class GrEffectStage;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000022
tomhudson@google.comf9ad8862012-05-11 20:38:48 +000023/**
bsalomon@google.comeb715c82012-07-11 15:03:31 +000024 Contains all the incremental state of a shader as it is being built,as well as helpers to
25 manipulate that state.
tomhudson@google.comf9ad8862012-05-11 20:38:48 +000026*/
tomhudson@google.comf9ad8862012-05-11 20:38:48 +000027class GrGLShaderBuilder {
tomhudson@google.comf9ad8862012-05-11 20:38:48 +000028public:
bsalomon@google.comf06df1b2012-09-06 20:22:31 +000029 /**
bsalomon@google.com34cccde2013-01-04 18:34:30 +000030 * Passed to GrGLEffects to add texture reads to their shader code.
bsalomon@google.comf06df1b2012-09-06 20:22:31 +000031 */
32 class TextureSampler {
33 public:
34 TextureSampler()
bsalomon@google.comb8eb2e82013-03-28 13:46:42 +000035 : fConfigComponentMask(0)
36 , fSamplerUniform(GrGLUniformManager::kInvalidUniformHandle) {
37 // we will memcpy the first 4 bytes from passed in swizzle. This ensures the string is
38 // terminated.
39 fSwizzle[4] = '\0';
40 }
bsalomon@google.comf06df1b2012-09-06 20:22:31 +000041
42 TextureSampler(const TextureSampler& other) { *this = other; }
43
44 TextureSampler& operator= (const TextureSampler& other) {
bsalomon@google.comb8eb2e82013-03-28 13:46:42 +000045 GrAssert(0 == fConfigComponentMask);
bsalomon@google.comf06df1b2012-09-06 20:22:31 +000046 GrAssert(GrGLUniformManager::kInvalidUniformHandle == fSamplerUniform);
47
bsalomon@google.comb8eb2e82013-03-28 13:46:42 +000048 fConfigComponentMask = other.fConfigComponentMask;
bsalomon@google.comf06df1b2012-09-06 20:22:31 +000049 fSamplerUniform = other.fSamplerUniform;
50 return *this;
51 }
52
bsalomon@google.comb8eb2e82013-03-28 13:46:42 +000053 // bitfield of GrColorComponentFlags present in the texture's config.
54 uint32_t configComponentMask() const { return fConfigComponentMask; }
55
56 const char* swizzle() const { return fSwizzle; }
bsalomon@google.comf06df1b2012-09-06 20:22:31 +000057
58 private:
bsalomon@google.com34cccde2013-01-04 18:34:30 +000059 // The idx param is used to ensure multiple samplers within a single effect have unique
bsalomon@google.comb8eb2e82013-03-28 13:46:42 +000060 // uniform names. swizzle is a four char max string made up of chars 'r', 'g', 'b', and 'a'.
61 void init(GrGLShaderBuilder* builder,
62 uint32_t configComponentMask,
63 const char* swizzle,
64 int idx) {
65 GrAssert(0 == fConfigComponentMask);
bsalomon@google.comf06df1b2012-09-06 20:22:31 +000066 GrAssert(GrGLUniformManager::kInvalidUniformHandle == fSamplerUniform);
67
68 GrAssert(NULL != builder);
bsalomon@google.com34cccde2013-01-04 18:34:30 +000069 SkString name;
70 name.printf("Sampler%d_", idx);
bsalomon@google.comf06df1b2012-09-06 20:22:31 +000071 fSamplerUniform = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
72 kSampler2D_GrSLType,
bsalomon@google.com34cccde2013-01-04 18:34:30 +000073 name.c_str());
bsalomon@google.comf06df1b2012-09-06 20:22:31 +000074 GrAssert(GrGLUniformManager::kInvalidUniformHandle != fSamplerUniform);
75
bsalomon@google.comb8eb2e82013-03-28 13:46:42 +000076 fConfigComponentMask = configComponentMask;
77 memcpy(fSwizzle, swizzle, 4);
bsalomon@google.comf06df1b2012-09-06 20:22:31 +000078 }
79
bsalomon@google.comb8eb2e82013-03-28 13:46:42 +000080 void init(GrGLShaderBuilder* builder, const GrTextureAccess* access, int idx) {
81 GrAssert(NULL != access);
82 this->init(builder,
83 GrPixelConfigComponentMask(access->getTexture()->config()),
84 access->getSwizzle(),
85 idx);
86 }
87
88 uint32_t fConfigComponentMask;
89 char fSwizzle[5];
bsalomon@google.comf06df1b2012-09-06 20:22:31 +000090 GrGLUniformManager::UniformHandle fSamplerUniform;
91
bsalomon@google.comb8eb2e82013-03-28 13:46:42 +000092 friend class GrGLShaderBuilder; // to call init().
bsalomon@google.comf06df1b2012-09-06 20:22:31 +000093 };
94
95 typedef SkTArray<TextureSampler> TextureSamplerArray;
96
bsalomon@google.comeb715c82012-07-11 15:03:31 +000097 enum ShaderType {
98 kVertex_ShaderType = 0x1,
99 kGeometry_ShaderType = 0x2,
100 kFragment_ShaderType = 0x4,
101 };
102
bsalomon@google.comc7818882013-03-20 19:19:53 +0000103 GrGLShaderBuilder(const GrGLContextInfo&, GrGLUniformManager&, bool explicitLocalCoords);
tomhudson@google.comf9ad8862012-05-11 20:38:48 +0000104
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000105 /**
106 * Called by GrGLEffects to add code to one of the shaders.
107 */
108 void vsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
109 va_list args;
110 va_start(args, format);
111 this->codeAppendf(kVertex_ShaderType, format, args);
112 va_end(args);
113 }
114
115 void gsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
116 va_list args;
117 va_start(args, format);
118 this->codeAppendf(kGeometry_ShaderType, format, args);
119 va_end(args);
120 }
121
122 void fsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
123 va_list args;
124 va_start(args, format);
125 this->codeAppendf(kFragment_ShaderType, format, args);
126 va_end(args);
127 }
128
129 void vsCodeAppend(const char* str) { this->codeAppend(kVertex_ShaderType, str); }
130 void gsCodeAppend(const char* str) { this->codeAppend(kGeometry_ShaderType, str); }
131 void fsCodeAppend(const char* str) { this->codeAppend(kFragment_ShaderType, str); }
132
bsalomon@google.comdbe49f72012-11-05 16:36:02 +0000133 /** Appends a 2D texture sample with projection if necessary. coordType must either be Vec2f or
134 Vec3f. The latter is interpreted as projective texture coords. The vec length and swizzle
135 order of the result depends on the GrTextureAccess associated with the TextureSampler. */
bsalomon@google.com868a8e72012-08-30 19:11:34 +0000136 void appendTextureLookup(SkString* out,
bsalomon@google.comf06df1b2012-09-06 20:22:31 +0000137 const TextureSampler&,
bsalomon@google.comdbe49f72012-11-05 16:36:02 +0000138 const char* coordName,
bsalomon@google.com868a8e72012-08-30 19:11:34 +0000139 GrSLType coordType = kVec2f_GrSLType) const;
tomhudson@google.com52598142012-05-24 17:44:30 +0000140
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000141 /** Version of above that appends the result to the shader code rather than an SkString.
142 Currently the shader type must be kFragment */
143 void appendTextureLookup(ShaderType,
144 const TextureSampler&,
145 const char* coordName,
146 GrSLType coordType = kVec2f_GrSLType);
147
148
bsalomon@google.com2d8edaf2012-09-07 14:47:31 +0000149 /** Does the work of appendTextureLookup and modulates the result by modulation. The result is
150 always a vec4. modulation and the swizzle specified by TextureSampler must both be vec4 or
151 float. If modulation is "" or NULL it this function acts as though appendTextureLookup were
152 called. */
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000153 void appendTextureLookupAndModulate(ShaderType,
bsalomon@google.com868a8e72012-08-30 19:11:34 +0000154 const char* modulation,
bsalomon@google.comf06df1b2012-09-06 20:22:31 +0000155 const TextureSampler&,
bsalomon@google.comdbe49f72012-11-05 16:36:02 +0000156 const char* coordName,
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000157 GrSLType coordType = kVec2f_GrSLType);
bsalomon@google.com34bcb9f2012-08-28 18:20:18 +0000158
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000159 /** Emits a helper function outside of main(). Currently ShaderType must be
160 kFragment_ShaderType. */
161 void emitFunction(ShaderType shader,
162 GrSLType returnType,
163 const char* name,
164 int argCnt,
165 const GrGLShaderVar* args,
166 const char* body,
167 SkString* outName);
168
bsalomon@google.com46fba0d2012-10-25 21:42:05 +0000169 /** Generates a EffectKey for the shader code based on the texture access parameters and the
twiz@google.coma5e65ec2012-08-02 15:15:16 +0000170 capabilities of the GL context. This is useful for keying the shader programs that may
171 have multiple representations, based on the type/format of textures used. */
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +0000172 static GrBackendEffectFactory::EffectKey KeyForTextureAccess(const GrTextureAccess&,
173 const GrGLCaps&);
twiz@google.coma5e65ec2012-08-02 15:15:16 +0000174
bsalomon@google.com6d003d12012-09-11 15:45:20 +0000175 /** If texture swizzling is available using tex parameters then it is preferred over mangling
176 the generated shader code. This potentially allows greater reuse of cached shaders. */
177 static const GrGLenum* GetTexParamSwizzle(GrPixelConfig config, const GrGLCaps& caps);
178
bsalomon@google.com706f6682012-10-23 14:53:55 +0000179 /** Add a uniform variable to the current program, that has visibility in one or more shaders.
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000180 visibility is a bitfield of ShaderType values indicating from which shaders the uniform
181 should be accessible. At least one bit must be set. Geometry shader uniforms are not
182 supported at this time. The actual uniform name will be mangled. If outName is not NULL then
183 it will refer to the final uniform name after return. Use the addUniformArray variant to add
184 an array of uniforms.
tomhudson@google.com242ed6f2012-05-30 17:38:57 +0000185 */
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000186 GrGLUniformManager::UniformHandle addUniform(uint32_t visibility,
187 GrSLType type,
188 const char* name,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000189 const char** outName = NULL) {
190 return this->addUniformArray(visibility, type, name, GrGLShaderVar::kNonArray, outName);
191 }
192 GrGLUniformManager::UniformHandle addUniformArray(uint32_t visibility,
193 GrSLType type,
194 const char* name,
195 int arrayCount,
196 const char** outName = NULL);
bsalomon@google.com032b2212012-07-16 13:36:18 +0000197
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000198 const GrGLShaderVar& getUniformVariable(GrGLUniformManager::UniformHandle) const;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000199
200 /**
bsalomon@google.com706f6682012-10-23 14:53:55 +0000201 * Shortcut for getUniformVariable(u).c_str()
bsalomon@google.com032b2212012-07-16 13:36:18 +0000202 */
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000203 const char* getUniformCStr(GrGLUniformManager::UniformHandle u) const {
bsalomon@google.com032b2212012-07-16 13:36:18 +0000204 return this->getUniformVariable(u).c_str();
205 }
tomhudson@google.com242ed6f2012-05-30 17:38:57 +0000206
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000207 /** Add a vertex attribute to the current program that is passed in from the vertex data.
208 Returns false if the attribute was already there, true otherwise. */
209 bool addAttribute(GrSLType type, const char* name);
210
211 /** Add a varying variable to the current program to pass values between vertex and fragment
bsalomon@google.comeb715c82012-07-11 15:03:31 +0000212 shaders. If the last two parameters are non-NULL, they are filled in with the name
213 generated. */
tomhudson@google.com23cb2292012-05-30 18:26:03 +0000214 void addVarying(GrSLType type,
215 const char* name,
216 const char** vsOutName = NULL,
217 const char** fsInName = NULL);
218
bsalomon@google.com706f6682012-10-23 14:53:55 +0000219 /** Returns a variable name that represents the position of the fragment in the FS. The position
220 is in device space (e.g. 0,0 is the top left and pixel centers are at half-integers). */
221 const char* fragmentPosition();
222
bsalomon@google.com17504f52012-10-30 12:34:25 +0000223 /** Returns a vertex attribute that represents the vertex position in the VS. This is the
224 pre-matrix position and is commonly used by effects to compute texture coords via a matrix.
225 */
226 const GrGLShaderVar& positionAttribute() const { return *fPositionVar; }
227
bsalomon@google.comc7818882013-03-20 19:19:53 +0000228 /** Returns a vertex attribute that represents the local coords in the VS. This may be the same
229 as positionAttribute() or it may not be. It depends upon whether the rendering code
230 specified explicit local coords or not in the GrDrawState. */
231 const GrGLShaderVar& localCoordsAttribute() const { return *fLocalCoordsVar; }
232
233 /**
234 * Are explicit local coordinates provided as input to the vertex shader.
235 */
236 bool hasExplicitLocalCoords() const { return (fLocalCoordsVar != fPositionVar); }
237
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000238 /**
239 * Interfaces used by GrGLProgram.
240 * TODO: Hide these from the GrEffects using friend or splitting this into two related classes.
241 * Also, GrGLProgram's shader string construction should be moved to this class.
242 */
243
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000244 /** Called after building is complete to get the final shader string. */
245 void getShader(ShaderType, SkString*) const;
246
bsalomon@google.com08283af2012-10-26 13:01:20 +0000247 void setCurrentStage(int stageIdx) { fCurrentStageIdx = stageIdx; }
248 void setNonStage() { fCurrentStageIdx = kNonStageIdx; }
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000249 // TODO: move remainder of shader code generation to this class and call this privately
250 // Handles of sampler uniforms generated for the effect are appended to samplerHandles.
251 GrGLEffect* createAndEmitGLEffect(
252 const GrEffectStage& stage,
253 GrBackendEffectFactory::EffectKey key,
254 const char* fsInColor, // NULL means no incoming color
255 const char* fsOutColor,
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000256 SkTArray<GrGLUniformManager::UniformHandle, true>* samplerHandles);
bsalomon@google.com706f6682012-10-23 14:53:55 +0000257 GrGLUniformManager::UniformHandle getRTHeightUniform() const { return fRTHeightUniform; }
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000258
259 struct AttributePair {
260 void set(int index, const SkString& name) {
261 fIndex = index; fName = name;
262 }
263 int fIndex;
264 SkString fName;
265 };
266 const SkSTArray<10, AttributePair, true>& getEffectAttributes() const {
267 return fEffectAttributes;
268 }
269 const SkString* getEffectAttributeName(int attributeIndex) const;
270
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000271 // TODO: Make this do all the compiling, linking, etc.
272 void finished(GrGLuint programID);
bsalomon@google.com706f6682012-10-23 14:53:55 +0000273
robertphillips@google.com13f181f2013-03-02 12:02:08 +0000274 const GrGLContextInfo& ctxInfo() const { return fCtxInfo; }
275
bsalomon@google.com032b2212012-07-16 13:36:18 +0000276private:
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000277 void codeAppendf(ShaderType type, const char format[], va_list args);
278 void codeAppend(ShaderType type, const char* str);
279
bsalomon@google.com032b2212012-07-16 13:36:18 +0000280 typedef GrTAllocator<GrGLShaderVar> VarArray;
281
bsalomon@google.com032b2212012-07-16 13:36:18 +0000282 void appendDecls(const VarArray&, SkString*) const;
283 void appendUniformDecls(ShaderType, SkString*) const;
284
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000285 typedef GrGLUniformManager::BuilderUniform BuilderUniform;
286 GrGLUniformManager::BuilderUniformArray fUniforms;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000287
bsalomon@google.comeb715c82012-07-11 15:03:31 +0000288 // TODO: Everything below here private.
bsalomon@google.com032b2212012-07-16 13:36:18 +0000289public:
bsalomon@google.comeb715c82012-07-11 15:03:31 +0000290
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000291 SkString fHeader; // VS+FS, GLSL version, etc
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000292 VarArray fVSAttrs;
293 VarArray fVSOutputs;
294 VarArray fGSInputs;
295 VarArray fGSOutputs;
296 VarArray fFSInputs;
297 SkString fGSHeader; // layout qualifiers specific to GS
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000298 VarArray fFSOutputs;
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000299 bool fUsesGS;
tomhudson@google.com040c41a2012-05-18 14:57:40 +0000300
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000301private:
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000302 enum {
303 kNonStageIdx = -1,
304 };
305
robertphillips@google.com6177e692013-02-28 20:16:25 +0000306 const GrGLContextInfo& fCtxInfo;
bsalomon@google.com706f6682012-10-23 14:53:55 +0000307 GrGLUniformManager& fUniformManager;
bsalomon@google.com08283af2012-10-26 13:01:20 +0000308 int fCurrentStageIdx;
bsalomon@google.com706f6682012-10-23 14:53:55 +0000309 SkString fFSFunctions;
310 SkString fFSHeader;
311
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000312 SkString fFSCode;
313 SkString fVSCode;
314 SkString fGSCode;
315
bsalomon@google.com706f6682012-10-23 14:53:55 +0000316 bool fSetupFragPosition;
317 GrGLUniformManager::UniformHandle fRTHeightUniform;
bsalomon@google.com34bcb9f2012-08-28 18:20:18 +0000318
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000319 SkSTArray<10, AttributePair, true> fEffectAttributes;
320
bsalomon@google.com17504f52012-10-30 12:34:25 +0000321 GrGLShaderVar* fPositionVar;
bsalomon@google.comc7818882013-03-20 19:19:53 +0000322 GrGLShaderVar* fLocalCoordsVar;
323
tomhudson@google.comf9ad8862012-05-11 20:38:48 +0000324};
325
326#endif