Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
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/. */
6 #ifndef GFX_OGLSHADERPROGRAM_H
7 #define GFX_OGLSHADERPROGRAM_H
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"
22 #include <string>
24 struct gfxRGBA;
25 struct nsIntRect;
27 namespace mozilla {
28 namespace layers {
30 class Layer;
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 };
47 class KnownUniform {
48 public:
49 enum KnownUniformName {
50 NotAKnownUniform = -1,
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,
70 KnownUniformCount
71 };
73 KnownUniform()
74 {
75 mName = NotAKnownUniform;
76 mNameString = nullptr;
77 mLocation = -1;
78 memset(&mValue, 0, sizeof(mValue));
79 }
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 }
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 }
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 }
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 }
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 }
142 NS_NOTREACHED("cnt must be 1 2 3 4 or 16");
143 return false;
144 }
146 KnownUniformName mName;
147 const char *mNameString;
148 int32_t mLocation;
150 union {
151 int i1;
152 float f1;
153 float f16v[16];
154 } mValue;
155 };
157 class ShaderConfigOGL
158 {
159 public:
160 ShaderConfigOGL() :
161 mFeatures(0) {}
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);
175 bool operator< (const ShaderConfigOGL& other) const {
176 return mFeatures < other.mFeatures;
177 }
179 public:
180 void SetFeature(int aBitmask, bool aState) {
181 if (aState)
182 mFeatures |= aBitmask;
183 else
184 mFeatures &= (~aBitmask);
185 }
187 int mFeatures;
188 };
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 }
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);
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 }
231 return -1;
232 }
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 };
243 // the source code for the program's shaders
244 std::string mVertexShaderString;
245 std::string mFragmentShaderString;
247 KnownUniform mUniforms[KnownUniform::KnownUniformCount];
248 nsTArray<Argument> mAttributes;
249 nsTArray<const char *> mDefines;
250 uint32_t mTextureCount;
252 ProgramProfileOGL() :
253 mTextureCount(0)
254 {}
255 };
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
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;
281 ShaderProgramOGL(GLContext* aGL, const ProgramProfileOGL& aProfile);
283 ~ShaderProgramOGL();
285 bool HasInitialized() {
286 NS_ASSERTION(mProgramState != STATE_OK || mProgram > 0, "Inconsistent program state");
287 return mProgramState == STATE_OK;
288 }
290 void Activate();
292 bool Initialize();
294 GLint CreateShader(GLenum aShaderType, const char *aShaderSource);
296 /**
297 * Creates a program and stores its id.
298 */
299 bool CreateProgram(const char *aVertexShaderString,
300 const char *aFragmentShaderString);
302 /**
303 * Lookup the location of an attribute
304 */
305 GLint AttribLocation(const char* aName) {
306 return mProfile.LookupAttributeLocation(aName);
307 }
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 }
318 void SetMaskLayerTransform(const gfx::Matrix4x4& aMatrix) {
319 SetMatrixUniform(KnownUniform::MaskQuadTransform, aMatrix);
320 }
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 }
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 }
340 void SetProjectionMatrix(const gfx::Matrix4x4& aMatrix) {
341 SetMatrixUniform(KnownUniform::MatrixProj, aMatrix);
342 }
344 // sets this program's texture transform, if it uses one
345 void SetTextureTransform(const gfx::Matrix4x4& aMatrix) {
346 SetMatrixUniform(KnownUniform::TextureTransform, aMatrix);
347 }
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 }
354 void SetRenderOffset(float aX, float aY) {
355 float vals[4] = { aX, aY, 0.0f, 0.0f };
356 SetUniform(KnownUniform::RenderTargetOffset, 4, vals);
357 }
359 void SetLayerOpacity(float aOpacity) {
360 SetUniform(KnownUniform::LayerOpacity, aOpacity);
361 }
363 void SetTextureUnit(GLint aUnit) {
364 SetUniform(KnownUniform::Texture, aUnit);
365 }
366 void SetYTextureUnit(GLint aUnit) {
367 SetUniform(KnownUniform::YTexture, aUnit);
368 }
370 void SetCbTextureUnit(GLint aUnit) {
371 SetUniform(KnownUniform::CbTexture, aUnit);
372 }
374 void SetCrTextureUnit(GLint aUnit) {
375 SetUniform(KnownUniform::CrTexture, aUnit);
376 }
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 }
384 void SetBlackTextureUnit(GLint aUnit) {
385 SetUniform(KnownUniform::BlackTexture, aUnit);
386 }
388 void SetWhiteTextureUnit(GLint aUnit) {
389 SetUniform(KnownUniform::WhiteTexture, aUnit);
390 }
392 void SetMaskTextureUnit(GLint aUnit) {
393 SetUniform(KnownUniform::MaskTexture, aUnit);
394 }
396 void SetRenderColor(const gfxRGBA& aColor) {
397 SetUniform(KnownUniform::RenderColor, aColor);
398 }
400 void SetRenderColor(const gfx::Color& aColor) {
401 SetUniform(KnownUniform::RenderColor, aColor);
402 }
404 void SetTexCoordMultiplier(float aWidth, float aHeight) {
405 float f[] = {aWidth, aHeight};
406 SetUniform(KnownUniform::TexCoordMultiplier, 2, f);
407 }
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 }
416 // the names of attributes
417 static const char* const VertexCoordAttrib;
418 static const char* const TexCoordAttrib;
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;
431 #ifdef CHECK_CURRENT_PROGRAM
432 static int sCurrentProgramKey;
433 #endif
435 void SetUniform(KnownUniform::KnownUniformName aKnownUniform, float aFloatValue)
436 {
437 ASSERT_THIS_PROGRAM;
438 NS_ASSERTION(aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, "Invalid known uniform");
440 KnownUniform& ku(mProfile.mUniforms[aKnownUniform]);
441 if (ku.UpdateUniform(aFloatValue)) {
442 mGL->fUniform1f(ku.mLocation, aFloatValue);
443 }
444 }
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");
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 }
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");
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 }
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");
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 }
485 void SetUniform(KnownUniform::KnownUniformName aKnownUniform, GLint aIntValue) {
486 ASSERT_THIS_PROGRAM;
487 NS_ASSERTION(aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, "Invalid known uniform");
489 KnownUniform& ku(mProfile.mUniforms[aKnownUniform]);
490 if (ku.UpdateUniform(aIntValue)) {
491 mGL->fUniform1i(ku.mLocation, aIntValue);
492 }
493 }
495 void SetMatrixUniform(KnownUniform::KnownUniformName aKnownUniform, const float *aFloatValues) {
496 ASSERT_THIS_PROGRAM;
497 NS_ASSERTION(aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, "Invalid known uniform");
499 KnownUniform& ku(mProfile.mUniforms[aKnownUniform]);
500 if (ku.UpdateUniform(16, aFloatValues)) {
501 mGL->fUniformMatrix4fv(ku.mLocation, 1, false, ku.mValue.f16v);
502 }
503 }
505 void SetMatrixUniform(KnownUniform::KnownUniformName aKnownUniform, const gfx3DMatrix& aMatrix) {
506 SetMatrixUniform(aKnownUniform, &aMatrix._11);
507 }
509 void SetMatrixUniform(KnownUniform::KnownUniformName aKnownUniform, const gfx::Matrix4x4& aMatrix) {
510 SetMatrixUniform(aKnownUniform, &aMatrix._11);
511 }
512 };
515 } /* layers */
516 } /* mozilla */
518 #endif /* GFX_OGLSHADERPROGRAM_H */