blob: 524a8853ca9a3d014b1e0ee34f6d0b59eb651ed7 [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
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000187 /** Add a vertex attribute to the current program that is passed in from the vertex data.
188 Returns false if the attribute was already there, true otherwise. */
189 bool addAttribute(GrSLType type, const char* name);
190
191 /** Add a varying variable to the current program to pass values between vertex and fragment
bsalomon@google.comeb715c82012-07-11 15:03:31 +0000192 shaders. If the last two parameters are non-NULL, they are filled in with the name
193 generated. */
tomhudson@google.com23cb2292012-05-30 18:26:03 +0000194 void addVarying(GrSLType type,
195 const char* name,
196 const char** vsOutName = NULL,
197 const char** fsInName = NULL);
198
bsalomon@google.com706f6682012-10-23 14:53:55 +0000199 /** Returns a variable name that represents the position of the fragment in the FS. The position
200 is in device space (e.g. 0,0 is the top left and pixel centers are at half-integers). */
201 const char* fragmentPosition();
202
bsalomon@google.com17504f52012-10-30 12:34:25 +0000203 /** Returns a vertex attribute that represents the vertex position in the VS. This is the
204 pre-matrix position and is commonly used by effects to compute texture coords via a matrix.
205 */
206 const GrGLShaderVar& positionAttribute() const { return *fPositionVar; }
207
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000208 /**
209 * Interfaces used by GrGLProgram.
210 * TODO: Hide these from the GrEffects using friend or splitting this into two related classes.
211 * Also, GrGLProgram's shader string construction should be moved to this class.
212 */
213
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000214 /** Called after building is complete to get the final shader string. */
215 void getShader(ShaderType, SkString*) const;
216
bsalomon@google.com08283af2012-10-26 13:01:20 +0000217 void setCurrentStage(int stageIdx) { fCurrentStageIdx = stageIdx; }
218 void setNonStage() { fCurrentStageIdx = kNonStageIdx; }
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000219 // TODO: move remainder of shader code generation to this class and call this privately
220 // Handles of sampler uniforms generated for the effect are appended to samplerHandles.
221 GrGLEffect* createAndEmitGLEffect(
222 const GrEffectStage& stage,
223 GrBackendEffectFactory::EffectKey key,
224 const char* fsInColor, // NULL means no incoming color
225 const char* fsOutColor,
skia.committer@gmail.com8ae714b2013-01-05 02:02:05 +0000226 const char* vsInCoord,
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000227 SkTArray<GrGLUniformManager::UniformHandle, true>* samplerHandles);
bsalomon@google.com706f6682012-10-23 14:53:55 +0000228 GrGLUniformManager::UniformHandle getRTHeightUniform() const { return fRTHeightUniform; }
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000229
230 struct AttributePair {
231 void set(int index, const SkString& name) {
232 fIndex = index; fName = name;
233 }
234 int fIndex;
235 SkString fName;
236 };
237 const SkSTArray<10, AttributePair, true>& getEffectAttributes() const {
238 return fEffectAttributes;
239 }
240 const SkString* getEffectAttributeName(int attributeIndex) const;
241
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000242 // TODO: Make this do all the compiling, linking, etc.
243 void finished(GrGLuint programID);
bsalomon@google.com706f6682012-10-23 14:53:55 +0000244
robertphillips@google.com13f181f2013-03-02 12:02:08 +0000245 const GrGLContextInfo& ctxInfo() const { return fCtxInfo; }
246
bsalomon@google.com032b2212012-07-16 13:36:18 +0000247private:
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000248 void codeAppendf(ShaderType type, const char format[], va_list args);
249 void codeAppend(ShaderType type, const char* str);
250
bsalomon@google.com032b2212012-07-16 13:36:18 +0000251 typedef GrTAllocator<GrGLShaderVar> VarArray;
252
bsalomon@google.com032b2212012-07-16 13:36:18 +0000253 void appendDecls(const VarArray&, SkString*) const;
254 void appendUniformDecls(ShaderType, SkString*) const;
255
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000256 typedef GrGLUniformManager::BuilderUniform BuilderUniform;
257 GrGLUniformManager::BuilderUniformArray fUniforms;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000258
bsalomon@google.comeb715c82012-07-11 15:03:31 +0000259 // TODO: Everything below here private.
bsalomon@google.com032b2212012-07-16 13:36:18 +0000260public:
bsalomon@google.comeb715c82012-07-11 15:03:31 +0000261
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000262 SkString fHeader; // VS+FS, GLSL version, etc
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000263 VarArray fVSAttrs;
264 VarArray fVSOutputs;
265 VarArray fGSInputs;
266 VarArray fGSOutputs;
267 VarArray fFSInputs;
268 SkString fGSHeader; // layout qualifiers specific to GS
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000269 VarArray fFSOutputs;
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000270 bool fUsesGS;
tomhudson@google.com040c41a2012-05-18 14:57:40 +0000271
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000272private:
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000273 enum {
274 kNonStageIdx = -1,
275 };
276
robertphillips@google.com6177e692013-02-28 20:16:25 +0000277 const GrGLContextInfo& fCtxInfo;
bsalomon@google.com706f6682012-10-23 14:53:55 +0000278 GrGLUniformManager& fUniformManager;
bsalomon@google.com08283af2012-10-26 13:01:20 +0000279 int fCurrentStageIdx;
bsalomon@google.com706f6682012-10-23 14:53:55 +0000280 SkString fFSFunctions;
281 SkString fFSHeader;
282
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000283 SkString fFSCode;
284 SkString fVSCode;
285 SkString fGSCode;
286
bsalomon@google.com706f6682012-10-23 14:53:55 +0000287 bool fSetupFragPosition;
288 GrGLUniformManager::UniformHandle fRTHeightUniform;
bsalomon@google.com34bcb9f2012-08-28 18:20:18 +0000289
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000290 SkSTArray<10, AttributePair, true> fEffectAttributes;
291
bsalomon@google.com17504f52012-10-30 12:34:25 +0000292 GrGLShaderVar* fPositionVar;
tomhudson@google.comf9ad8862012-05-11 20:38:48 +0000293};
294
295#endif