|
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #ifndef GFX_OGLSHADERPROGRAM_H |
|
7 #define GFX_OGLSHADERPROGRAM_H |
|
8 |
|
9 #include "GLContext.h" // for fast inlines of glUniform* |
|
10 #include "gfx3DMatrix.h" // for gfx3DMatrix |
|
11 #include "gfxTypes.h" |
|
12 #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc |
|
13 #include "mozilla/RefPtr.h" // for RefPtr |
|
14 #include "mozilla/gfx/Matrix.h" // for Matrix4x4 |
|
15 #include "mozilla/gfx/Rect.h" // for Rect |
|
16 #include "mozilla/gfx/Types.h" |
|
17 #include "nsDebug.h" // for NS_ASSERTION |
|
18 #include "nsPoint.h" // for nsIntPoint |
|
19 #include "nsTArray.h" // for nsTArray |
|
20 #include "mozilla/layers/CompositorTypes.h" |
|
21 |
|
22 #include <string> |
|
23 |
|
24 struct gfxRGBA; |
|
25 struct nsIntRect; |
|
26 |
|
27 namespace mozilla { |
|
28 namespace layers { |
|
29 |
|
30 class Layer; |
|
31 |
|
32 enum ShaderFeatures { |
|
33 ENABLE_RENDER_COLOR=0x01, |
|
34 ENABLE_TEXTURE_RECT=0x02, |
|
35 ENABLE_TEXTURE_EXTERNAL=0x04, |
|
36 ENABLE_TEXTURE_YCBCR=0x08, |
|
37 ENABLE_TEXTURE_COMPONENT_ALPHA=0x10, |
|
38 ENABLE_TEXTURE_NO_ALPHA=0x20, |
|
39 ENABLE_TEXTURE_RB_SWAP=0x40, |
|
40 ENABLE_OPACITY=0x80, |
|
41 ENABLE_BLUR=0x100, |
|
42 ENABLE_COLOR_MATRIX=0x200, |
|
43 ENABLE_MASK_2D=0x400, |
|
44 ENABLE_MASK_3D=0x800 |
|
45 }; |
|
46 |
|
47 class KnownUniform { |
|
48 public: |
|
49 enum KnownUniformName { |
|
50 NotAKnownUniform = -1, |
|
51 |
|
52 LayerTransform = 0, |
|
53 MaskQuadTransform, |
|
54 LayerQuadTransform, |
|
55 MatrixProj, |
|
56 TextureTransform, |
|
57 RenderTargetOffset, |
|
58 LayerOpacity, |
|
59 Texture, |
|
60 YTexture, |
|
61 CbTexture, |
|
62 CrTexture, |
|
63 BlackTexture, |
|
64 WhiteTexture, |
|
65 MaskTexture, |
|
66 RenderColor, |
|
67 TexCoordMultiplier, |
|
68 TexturePass2, |
|
69 |
|
70 KnownUniformCount |
|
71 }; |
|
72 |
|
73 KnownUniform() |
|
74 { |
|
75 mName = NotAKnownUniform; |
|
76 mNameString = nullptr; |
|
77 mLocation = -1; |
|
78 memset(&mValue, 0, sizeof(mValue)); |
|
79 } |
|
80 |
|
81 bool UpdateUniform(int32_t i1) { |
|
82 if (mLocation == -1) return false; |
|
83 if (mValue.i1 != i1) { |
|
84 mValue.i1 = i1; |
|
85 return true; |
|
86 } |
|
87 return false; |
|
88 } |
|
89 |
|
90 bool UpdateUniform(float f1) { |
|
91 if (mLocation == -1) return false; |
|
92 if (mValue.f1 != f1) { |
|
93 mValue.f1 = f1; |
|
94 return true; |
|
95 } |
|
96 return false; |
|
97 } |
|
98 |
|
99 bool UpdateUniform(float f1, float f2) { |
|
100 if (mLocation == -1) return false; |
|
101 if (mValue.f16v[0] != f1 || |
|
102 mValue.f16v[1] != f2) |
|
103 { |
|
104 mValue.f16v[0] = f1; |
|
105 mValue.f16v[1] = f2; |
|
106 return true; |
|
107 } |
|
108 return false; |
|
109 } |
|
110 |
|
111 bool UpdateUniform(float f1, float f2, float f3, float f4) { |
|
112 if (mLocation == -1) return false; |
|
113 if (mValue.f16v[0] != f1 || |
|
114 mValue.f16v[1] != f2 || |
|
115 mValue.f16v[2] != f3 || |
|
116 mValue.f16v[3] != f4) |
|
117 { |
|
118 mValue.f16v[0] = f1; |
|
119 mValue.f16v[1] = f2; |
|
120 mValue.f16v[2] = f3; |
|
121 mValue.f16v[3] = f4; |
|
122 return true; |
|
123 } |
|
124 return false; |
|
125 } |
|
126 |
|
127 bool UpdateUniform(int cnt, const float *fp) { |
|
128 if (mLocation == -1) return false; |
|
129 switch (cnt) { |
|
130 case 1: |
|
131 case 2: |
|
132 case 3: |
|
133 case 4: |
|
134 case 16: |
|
135 if (memcmp(mValue.f16v, fp, sizeof(float) * cnt) != 0) { |
|
136 memcpy(mValue.f16v, fp, sizeof(float) * cnt); |
|
137 return true; |
|
138 } |
|
139 return false; |
|
140 } |
|
141 |
|
142 NS_NOTREACHED("cnt must be 1 2 3 4 or 16"); |
|
143 return false; |
|
144 } |
|
145 |
|
146 KnownUniformName mName; |
|
147 const char *mNameString; |
|
148 int32_t mLocation; |
|
149 |
|
150 union { |
|
151 int i1; |
|
152 float f1; |
|
153 float f16v[16]; |
|
154 } mValue; |
|
155 }; |
|
156 |
|
157 class ShaderConfigOGL |
|
158 { |
|
159 public: |
|
160 ShaderConfigOGL() : |
|
161 mFeatures(0) {} |
|
162 |
|
163 void SetRenderColor(bool aEnabled); |
|
164 void SetTextureTarget(GLenum aTarget); |
|
165 void SetRBSwap(bool aEnabled); |
|
166 void SetNoAlpha(bool aEnabled); |
|
167 void SetOpacity(bool aEnabled); |
|
168 void SetYCbCr(bool aEnabled); |
|
169 void SetComponentAlpha(bool aEnabled); |
|
170 void SetColorMatrix(bool aEnabled); |
|
171 void SetBlur(bool aEnabled); |
|
172 void SetMask2D(bool aEnabled); |
|
173 void SetMask3D(bool aEnabled); |
|
174 |
|
175 bool operator< (const ShaderConfigOGL& other) const { |
|
176 return mFeatures < other.mFeatures; |
|
177 } |
|
178 |
|
179 public: |
|
180 void SetFeature(int aBitmask, bool aState) { |
|
181 if (aState) |
|
182 mFeatures |= aBitmask; |
|
183 else |
|
184 mFeatures &= (~aBitmask); |
|
185 } |
|
186 |
|
187 int mFeatures; |
|
188 }; |
|
189 |
|
190 static inline ShaderConfigOGL |
|
191 ShaderConfigFromTargetAndFormat(GLenum aTarget, |
|
192 gfx::SurfaceFormat aFormat) |
|
193 { |
|
194 ShaderConfigOGL config; |
|
195 config.SetTextureTarget(aTarget); |
|
196 config.SetRBSwap(aFormat == gfx::SurfaceFormat::B8G8R8A8 || |
|
197 aFormat == gfx::SurfaceFormat::B8G8R8X8); |
|
198 config.SetNoAlpha(aFormat == gfx::SurfaceFormat::B8G8R8X8 || |
|
199 aFormat == gfx::SurfaceFormat::R8G8B8X8 || |
|
200 aFormat == gfx::SurfaceFormat::R5G6B5); |
|
201 return config; |
|
202 } |
|
203 |
|
204 /** |
|
205 * This struct represents the shaders that make up a program and the uniform |
|
206 * and attribute parmeters that those shaders take. |
|
207 * It is used by ShaderProgramOGL. |
|
208 * Use the factory method GetProfileFor to create instances. |
|
209 */ |
|
210 struct ProgramProfileOGL |
|
211 { |
|
212 /** |
|
213 * Factory method; creates an instance of this class for the given |
|
214 * ShaderConfigOGL |
|
215 */ |
|
216 static ProgramProfileOGL GetProfileFor(ShaderConfigOGL aConfig); |
|
217 |
|
218 /** |
|
219 * These two methods lookup the location of a uniform and attribute, |
|
220 * respectively. Returns -1 if the named uniform/attribute does not |
|
221 * have a location for the shaders represented by this profile. |
|
222 */ |
|
223 GLint LookupAttributeLocation(const char* aName) |
|
224 { |
|
225 for (uint32_t i = 0; i < mAttributes.Length(); ++i) { |
|
226 if (strcmp(mAttributes[i].mName, aName) == 0) { |
|
227 return mAttributes[i].mLocation; |
|
228 } |
|
229 } |
|
230 |
|
231 return -1; |
|
232 } |
|
233 |
|
234 // represents the name and location of a uniform or attribute |
|
235 struct Argument |
|
236 { |
|
237 Argument(const char* aName) : |
|
238 mName(aName) {} |
|
239 const char* mName; |
|
240 GLint mLocation; |
|
241 }; |
|
242 |
|
243 // the source code for the program's shaders |
|
244 std::string mVertexShaderString; |
|
245 std::string mFragmentShaderString; |
|
246 |
|
247 KnownUniform mUniforms[KnownUniform::KnownUniformCount]; |
|
248 nsTArray<Argument> mAttributes; |
|
249 nsTArray<const char *> mDefines; |
|
250 uint32_t mTextureCount; |
|
251 |
|
252 ProgramProfileOGL() : |
|
253 mTextureCount(0) |
|
254 {} |
|
255 }; |
|
256 |
|
257 |
|
258 #if defined(DEBUG) |
|
259 #define CHECK_CURRENT_PROGRAM 1 |
|
260 #define ASSERT_THIS_PROGRAM \ |
|
261 do { \ |
|
262 GLuint currentProgram; \ |
|
263 mGL->GetUIntegerv(LOCAL_GL_CURRENT_PROGRAM, ¤tProgram); \ |
|
264 NS_ASSERTION(currentProgram == mProgram, \ |
|
265 "SetUniform with wrong program active!"); \ |
|
266 } while (0) |
|
267 #else |
|
268 #define ASSERT_THIS_PROGRAM \ |
|
269 do { } while (0) |
|
270 #endif |
|
271 |
|
272 /** |
|
273 * Represents an OGL shader program. The details of a program are represented |
|
274 * by a ProgramProfileOGL |
|
275 */ |
|
276 class ShaderProgramOGL |
|
277 { |
|
278 public: |
|
279 typedef mozilla::gl::GLContext GLContext; |
|
280 |
|
281 ShaderProgramOGL(GLContext* aGL, const ProgramProfileOGL& aProfile); |
|
282 |
|
283 ~ShaderProgramOGL(); |
|
284 |
|
285 bool HasInitialized() { |
|
286 NS_ASSERTION(mProgramState != STATE_OK || mProgram > 0, "Inconsistent program state"); |
|
287 return mProgramState == STATE_OK; |
|
288 } |
|
289 |
|
290 void Activate(); |
|
291 |
|
292 bool Initialize(); |
|
293 |
|
294 GLint CreateShader(GLenum aShaderType, const char *aShaderSource); |
|
295 |
|
296 /** |
|
297 * Creates a program and stores its id. |
|
298 */ |
|
299 bool CreateProgram(const char *aVertexShaderString, |
|
300 const char *aFragmentShaderString); |
|
301 |
|
302 /** |
|
303 * Lookup the location of an attribute |
|
304 */ |
|
305 GLint AttribLocation(const char* aName) { |
|
306 return mProfile.LookupAttributeLocation(aName); |
|
307 } |
|
308 |
|
309 /** |
|
310 * The following set of methods set a uniform argument to the shader program. |
|
311 * Not all uniforms may be set for all programs, and such uses will throw |
|
312 * an assertion. |
|
313 */ |
|
314 void SetLayerTransform(const gfx::Matrix4x4& aMatrix) { |
|
315 SetMatrixUniform(KnownUniform::LayerTransform, aMatrix); |
|
316 } |
|
317 |
|
318 void SetMaskLayerTransform(const gfx::Matrix4x4& aMatrix) { |
|
319 SetMatrixUniform(KnownUniform::MaskQuadTransform, aMatrix); |
|
320 } |
|
321 |
|
322 void SetLayerQuadRect(const nsIntRect& aRect) { |
|
323 gfx3DMatrix m; |
|
324 m._11 = float(aRect.width); |
|
325 m._22 = float(aRect.height); |
|
326 m._41 = float(aRect.x); |
|
327 m._42 = float(aRect.y); |
|
328 SetMatrixUniform(KnownUniform::LayerQuadTransform, m); |
|
329 } |
|
330 |
|
331 void SetLayerQuadRect(const gfx::Rect& aRect) { |
|
332 gfx3DMatrix m; |
|
333 m._11 = aRect.width; |
|
334 m._22 = aRect.height; |
|
335 m._41 = aRect.x; |
|
336 m._42 = aRect.y; |
|
337 SetMatrixUniform(KnownUniform::LayerQuadTransform, m); |
|
338 } |
|
339 |
|
340 void SetProjectionMatrix(const gfx::Matrix4x4& aMatrix) { |
|
341 SetMatrixUniform(KnownUniform::MatrixProj, aMatrix); |
|
342 } |
|
343 |
|
344 // sets this program's texture transform, if it uses one |
|
345 void SetTextureTransform(const gfx::Matrix4x4& aMatrix) { |
|
346 SetMatrixUniform(KnownUniform::TextureTransform, aMatrix); |
|
347 } |
|
348 |
|
349 void SetRenderOffset(const nsIntPoint& aOffset) { |
|
350 float vals[4] = { float(aOffset.x), float(aOffset.y), 0.0f, 0.0f }; |
|
351 SetUniform(KnownUniform::RenderTargetOffset, 4, vals); |
|
352 } |
|
353 |
|
354 void SetRenderOffset(float aX, float aY) { |
|
355 float vals[4] = { aX, aY, 0.0f, 0.0f }; |
|
356 SetUniform(KnownUniform::RenderTargetOffset, 4, vals); |
|
357 } |
|
358 |
|
359 void SetLayerOpacity(float aOpacity) { |
|
360 SetUniform(KnownUniform::LayerOpacity, aOpacity); |
|
361 } |
|
362 |
|
363 void SetTextureUnit(GLint aUnit) { |
|
364 SetUniform(KnownUniform::Texture, aUnit); |
|
365 } |
|
366 void SetYTextureUnit(GLint aUnit) { |
|
367 SetUniform(KnownUniform::YTexture, aUnit); |
|
368 } |
|
369 |
|
370 void SetCbTextureUnit(GLint aUnit) { |
|
371 SetUniform(KnownUniform::CbTexture, aUnit); |
|
372 } |
|
373 |
|
374 void SetCrTextureUnit(GLint aUnit) { |
|
375 SetUniform(KnownUniform::CrTexture, aUnit); |
|
376 } |
|
377 |
|
378 void SetYCbCrTextureUnits(GLint aYUnit, GLint aCbUnit, GLint aCrUnit) { |
|
379 SetUniform(KnownUniform::YTexture, aYUnit); |
|
380 SetUniform(KnownUniform::CbTexture, aCbUnit); |
|
381 SetUniform(KnownUniform::CrTexture, aCrUnit); |
|
382 } |
|
383 |
|
384 void SetBlackTextureUnit(GLint aUnit) { |
|
385 SetUniform(KnownUniform::BlackTexture, aUnit); |
|
386 } |
|
387 |
|
388 void SetWhiteTextureUnit(GLint aUnit) { |
|
389 SetUniform(KnownUniform::WhiteTexture, aUnit); |
|
390 } |
|
391 |
|
392 void SetMaskTextureUnit(GLint aUnit) { |
|
393 SetUniform(KnownUniform::MaskTexture, aUnit); |
|
394 } |
|
395 |
|
396 void SetRenderColor(const gfxRGBA& aColor) { |
|
397 SetUniform(KnownUniform::RenderColor, aColor); |
|
398 } |
|
399 |
|
400 void SetRenderColor(const gfx::Color& aColor) { |
|
401 SetUniform(KnownUniform::RenderColor, aColor); |
|
402 } |
|
403 |
|
404 void SetTexCoordMultiplier(float aWidth, float aHeight) { |
|
405 float f[] = {aWidth, aHeight}; |
|
406 SetUniform(KnownUniform::TexCoordMultiplier, 2, f); |
|
407 } |
|
408 |
|
409 // Set whether we want the component alpha shader to return the color |
|
410 // vector (pass 1, false) or the alpha vector (pass2, true). With support |
|
411 // for multiple render targets we wouldn't need two passes here. |
|
412 void SetTexturePass2(bool aFlag) { |
|
413 SetUniform(KnownUniform::TexturePass2, aFlag ? 1 : 0); |
|
414 } |
|
415 |
|
416 // the names of attributes |
|
417 static const char* const VertexCoordAttrib; |
|
418 static const char* const TexCoordAttrib; |
|
419 |
|
420 protected: |
|
421 RefPtr<GLContext> mGL; |
|
422 // the OpenGL id of the program |
|
423 GLuint mProgram; |
|
424 ProgramProfileOGL mProfile; |
|
425 enum { |
|
426 STATE_NEW, |
|
427 STATE_OK, |
|
428 STATE_ERROR |
|
429 } mProgramState; |
|
430 |
|
431 #ifdef CHECK_CURRENT_PROGRAM |
|
432 static int sCurrentProgramKey; |
|
433 #endif |
|
434 |
|
435 void SetUniform(KnownUniform::KnownUniformName aKnownUniform, float aFloatValue) |
|
436 { |
|
437 ASSERT_THIS_PROGRAM; |
|
438 NS_ASSERTION(aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, "Invalid known uniform"); |
|
439 |
|
440 KnownUniform& ku(mProfile.mUniforms[aKnownUniform]); |
|
441 if (ku.UpdateUniform(aFloatValue)) { |
|
442 mGL->fUniform1f(ku.mLocation, aFloatValue); |
|
443 } |
|
444 } |
|
445 |
|
446 void SetUniform(KnownUniform::KnownUniformName aKnownUniform, const gfxRGBA& aColor) |
|
447 { |
|
448 ASSERT_THIS_PROGRAM; |
|
449 NS_ASSERTION(aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, "Invalid known uniform"); |
|
450 |
|
451 KnownUniform& ku(mProfile.mUniforms[aKnownUniform]); |
|
452 if (ku.UpdateUniform(aColor.r, aColor.g, aColor.b, aColor.a)) { |
|
453 mGL->fUniform4fv(ku.mLocation, 1, ku.mValue.f16v); |
|
454 } |
|
455 } |
|
456 |
|
457 void SetUniform(KnownUniform::KnownUniformName aKnownUniform, const gfx::Color& aColor) { |
|
458 ASSERT_THIS_PROGRAM; |
|
459 NS_ASSERTION(aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, "Invalid known uniform"); |
|
460 |
|
461 KnownUniform& ku(mProfile.mUniforms[aKnownUniform]); |
|
462 if (ku.UpdateUniform(aColor.r, aColor.g, aColor.b, aColor.a)) { |
|
463 mGL->fUniform4fv(ku.mLocation, 1, ku.mValue.f16v); |
|
464 } |
|
465 } |
|
466 |
|
467 void SetUniform(KnownUniform::KnownUniformName aKnownUniform, int aLength, float *aFloatValues) |
|
468 { |
|
469 ASSERT_THIS_PROGRAM; |
|
470 NS_ASSERTION(aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, "Invalid known uniform"); |
|
471 |
|
472 KnownUniform& ku(mProfile.mUniforms[aKnownUniform]); |
|
473 if (ku.UpdateUniform(aLength, aFloatValues)) { |
|
474 switch (aLength) { |
|
475 case 1: mGL->fUniform1fv(ku.mLocation, 1, ku.mValue.f16v); break; |
|
476 case 2: mGL->fUniform2fv(ku.mLocation, 1, ku.mValue.f16v); break; |
|
477 case 3: mGL->fUniform3fv(ku.mLocation, 1, ku.mValue.f16v); break; |
|
478 case 4: mGL->fUniform4fv(ku.mLocation, 1, ku.mValue.f16v); break; |
|
479 default: |
|
480 NS_NOTREACHED("Bogus aLength param"); |
|
481 } |
|
482 } |
|
483 } |
|
484 |
|
485 void SetUniform(KnownUniform::KnownUniformName aKnownUniform, GLint aIntValue) { |
|
486 ASSERT_THIS_PROGRAM; |
|
487 NS_ASSERTION(aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, "Invalid known uniform"); |
|
488 |
|
489 KnownUniform& ku(mProfile.mUniforms[aKnownUniform]); |
|
490 if (ku.UpdateUniform(aIntValue)) { |
|
491 mGL->fUniform1i(ku.mLocation, aIntValue); |
|
492 } |
|
493 } |
|
494 |
|
495 void SetMatrixUniform(KnownUniform::KnownUniformName aKnownUniform, const float *aFloatValues) { |
|
496 ASSERT_THIS_PROGRAM; |
|
497 NS_ASSERTION(aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, "Invalid known uniform"); |
|
498 |
|
499 KnownUniform& ku(mProfile.mUniforms[aKnownUniform]); |
|
500 if (ku.UpdateUniform(16, aFloatValues)) { |
|
501 mGL->fUniformMatrix4fv(ku.mLocation, 1, false, ku.mValue.f16v); |
|
502 } |
|
503 } |
|
504 |
|
505 void SetMatrixUniform(KnownUniform::KnownUniformName aKnownUniform, const gfx3DMatrix& aMatrix) { |
|
506 SetMatrixUniform(aKnownUniform, &aMatrix._11); |
|
507 } |
|
508 |
|
509 void SetMatrixUniform(KnownUniform::KnownUniformName aKnownUniform, const gfx::Matrix4x4& aMatrix) { |
|
510 SetMatrixUniform(aKnownUniform, &aMatrix._11); |
|
511 } |
|
512 }; |
|
513 |
|
514 |
|
515 } /* layers */ |
|
516 } /* mozilla */ |
|
517 |
|
518 #endif /* GFX_OGLSHADERPROGRAM_H */ |