1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/layers/opengl/OGLShaderProgram.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,518 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifndef GFX_OGLSHADERPROGRAM_H 1.10 +#define GFX_OGLSHADERPROGRAM_H 1.11 + 1.12 +#include "GLContext.h" // for fast inlines of glUniform* 1.13 +#include "gfx3DMatrix.h" // for gfx3DMatrix 1.14 +#include "gfxTypes.h" 1.15 +#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc 1.16 +#include "mozilla/RefPtr.h" // for RefPtr 1.17 +#include "mozilla/gfx/Matrix.h" // for Matrix4x4 1.18 +#include "mozilla/gfx/Rect.h" // for Rect 1.19 +#include "mozilla/gfx/Types.h" 1.20 +#include "nsDebug.h" // for NS_ASSERTION 1.21 +#include "nsPoint.h" // for nsIntPoint 1.22 +#include "nsTArray.h" // for nsTArray 1.23 +#include "mozilla/layers/CompositorTypes.h" 1.24 + 1.25 +#include <string> 1.26 + 1.27 +struct gfxRGBA; 1.28 +struct nsIntRect; 1.29 + 1.30 +namespace mozilla { 1.31 +namespace layers { 1.32 + 1.33 +class Layer; 1.34 + 1.35 +enum ShaderFeatures { 1.36 + ENABLE_RENDER_COLOR=0x01, 1.37 + ENABLE_TEXTURE_RECT=0x02, 1.38 + ENABLE_TEXTURE_EXTERNAL=0x04, 1.39 + ENABLE_TEXTURE_YCBCR=0x08, 1.40 + ENABLE_TEXTURE_COMPONENT_ALPHA=0x10, 1.41 + ENABLE_TEXTURE_NO_ALPHA=0x20, 1.42 + ENABLE_TEXTURE_RB_SWAP=0x40, 1.43 + ENABLE_OPACITY=0x80, 1.44 + ENABLE_BLUR=0x100, 1.45 + ENABLE_COLOR_MATRIX=0x200, 1.46 + ENABLE_MASK_2D=0x400, 1.47 + ENABLE_MASK_3D=0x800 1.48 +}; 1.49 + 1.50 +class KnownUniform { 1.51 +public: 1.52 + enum KnownUniformName { 1.53 + NotAKnownUniform = -1, 1.54 + 1.55 + LayerTransform = 0, 1.56 + MaskQuadTransform, 1.57 + LayerQuadTransform, 1.58 + MatrixProj, 1.59 + TextureTransform, 1.60 + RenderTargetOffset, 1.61 + LayerOpacity, 1.62 + Texture, 1.63 + YTexture, 1.64 + CbTexture, 1.65 + CrTexture, 1.66 + BlackTexture, 1.67 + WhiteTexture, 1.68 + MaskTexture, 1.69 + RenderColor, 1.70 + TexCoordMultiplier, 1.71 + TexturePass2, 1.72 + 1.73 + KnownUniformCount 1.74 + }; 1.75 + 1.76 + KnownUniform() 1.77 + { 1.78 + mName = NotAKnownUniform; 1.79 + mNameString = nullptr; 1.80 + mLocation = -1; 1.81 + memset(&mValue, 0, sizeof(mValue)); 1.82 + } 1.83 + 1.84 + bool UpdateUniform(int32_t i1) { 1.85 + if (mLocation == -1) return false; 1.86 + if (mValue.i1 != i1) { 1.87 + mValue.i1 = i1; 1.88 + return true; 1.89 + } 1.90 + return false; 1.91 + } 1.92 + 1.93 + bool UpdateUniform(float f1) { 1.94 + if (mLocation == -1) return false; 1.95 + if (mValue.f1 != f1) { 1.96 + mValue.f1 = f1; 1.97 + return true; 1.98 + } 1.99 + return false; 1.100 + } 1.101 + 1.102 + bool UpdateUniform(float f1, float f2) { 1.103 + if (mLocation == -1) return false; 1.104 + if (mValue.f16v[0] != f1 || 1.105 + mValue.f16v[1] != f2) 1.106 + { 1.107 + mValue.f16v[0] = f1; 1.108 + mValue.f16v[1] = f2; 1.109 + return true; 1.110 + } 1.111 + return false; 1.112 + } 1.113 + 1.114 + bool UpdateUniform(float f1, float f2, float f3, float f4) { 1.115 + if (mLocation == -1) return false; 1.116 + if (mValue.f16v[0] != f1 || 1.117 + mValue.f16v[1] != f2 || 1.118 + mValue.f16v[2] != f3 || 1.119 + mValue.f16v[3] != f4) 1.120 + { 1.121 + mValue.f16v[0] = f1; 1.122 + mValue.f16v[1] = f2; 1.123 + mValue.f16v[2] = f3; 1.124 + mValue.f16v[3] = f4; 1.125 + return true; 1.126 + } 1.127 + return false; 1.128 + } 1.129 + 1.130 + bool UpdateUniform(int cnt, const float *fp) { 1.131 + if (mLocation == -1) return false; 1.132 + switch (cnt) { 1.133 + case 1: 1.134 + case 2: 1.135 + case 3: 1.136 + case 4: 1.137 + case 16: 1.138 + if (memcmp(mValue.f16v, fp, sizeof(float) * cnt) != 0) { 1.139 + memcpy(mValue.f16v, fp, sizeof(float) * cnt); 1.140 + return true; 1.141 + } 1.142 + return false; 1.143 + } 1.144 + 1.145 + NS_NOTREACHED("cnt must be 1 2 3 4 or 16"); 1.146 + return false; 1.147 + } 1.148 + 1.149 + KnownUniformName mName; 1.150 + const char *mNameString; 1.151 + int32_t mLocation; 1.152 + 1.153 + union { 1.154 + int i1; 1.155 + float f1; 1.156 + float f16v[16]; 1.157 + } mValue; 1.158 +}; 1.159 + 1.160 +class ShaderConfigOGL 1.161 +{ 1.162 +public: 1.163 + ShaderConfigOGL() : 1.164 + mFeatures(0) {} 1.165 + 1.166 + void SetRenderColor(bool aEnabled); 1.167 + void SetTextureTarget(GLenum aTarget); 1.168 + void SetRBSwap(bool aEnabled); 1.169 + void SetNoAlpha(bool aEnabled); 1.170 + void SetOpacity(bool aEnabled); 1.171 + void SetYCbCr(bool aEnabled); 1.172 + void SetComponentAlpha(bool aEnabled); 1.173 + void SetColorMatrix(bool aEnabled); 1.174 + void SetBlur(bool aEnabled); 1.175 + void SetMask2D(bool aEnabled); 1.176 + void SetMask3D(bool aEnabled); 1.177 + 1.178 + bool operator< (const ShaderConfigOGL& other) const { 1.179 + return mFeatures < other.mFeatures; 1.180 + } 1.181 + 1.182 +public: 1.183 + void SetFeature(int aBitmask, bool aState) { 1.184 + if (aState) 1.185 + mFeatures |= aBitmask; 1.186 + else 1.187 + mFeatures &= (~aBitmask); 1.188 + } 1.189 + 1.190 + int mFeatures; 1.191 +}; 1.192 + 1.193 +static inline ShaderConfigOGL 1.194 +ShaderConfigFromTargetAndFormat(GLenum aTarget, 1.195 + gfx::SurfaceFormat aFormat) 1.196 +{ 1.197 + ShaderConfigOGL config; 1.198 + config.SetTextureTarget(aTarget); 1.199 + config.SetRBSwap(aFormat == gfx::SurfaceFormat::B8G8R8A8 || 1.200 + aFormat == gfx::SurfaceFormat::B8G8R8X8); 1.201 + config.SetNoAlpha(aFormat == gfx::SurfaceFormat::B8G8R8X8 || 1.202 + aFormat == gfx::SurfaceFormat::R8G8B8X8 || 1.203 + aFormat == gfx::SurfaceFormat::R5G6B5); 1.204 + return config; 1.205 +} 1.206 + 1.207 +/** 1.208 + * This struct represents the shaders that make up a program and the uniform 1.209 + * and attribute parmeters that those shaders take. 1.210 + * It is used by ShaderProgramOGL. 1.211 + * Use the factory method GetProfileFor to create instances. 1.212 + */ 1.213 +struct ProgramProfileOGL 1.214 +{ 1.215 + /** 1.216 + * Factory method; creates an instance of this class for the given 1.217 + * ShaderConfigOGL 1.218 + */ 1.219 + static ProgramProfileOGL GetProfileFor(ShaderConfigOGL aConfig); 1.220 + 1.221 + /** 1.222 + * These two methods lookup the location of a uniform and attribute, 1.223 + * respectively. Returns -1 if the named uniform/attribute does not 1.224 + * have a location for the shaders represented by this profile. 1.225 + */ 1.226 + GLint LookupAttributeLocation(const char* aName) 1.227 + { 1.228 + for (uint32_t i = 0; i < mAttributes.Length(); ++i) { 1.229 + if (strcmp(mAttributes[i].mName, aName) == 0) { 1.230 + return mAttributes[i].mLocation; 1.231 + } 1.232 + } 1.233 + 1.234 + return -1; 1.235 + } 1.236 + 1.237 + // represents the name and location of a uniform or attribute 1.238 + struct Argument 1.239 + { 1.240 + Argument(const char* aName) : 1.241 + mName(aName) {} 1.242 + const char* mName; 1.243 + GLint mLocation; 1.244 + }; 1.245 + 1.246 + // the source code for the program's shaders 1.247 + std::string mVertexShaderString; 1.248 + std::string mFragmentShaderString; 1.249 + 1.250 + KnownUniform mUniforms[KnownUniform::KnownUniformCount]; 1.251 + nsTArray<Argument> mAttributes; 1.252 + nsTArray<const char *> mDefines; 1.253 + uint32_t mTextureCount; 1.254 + 1.255 + ProgramProfileOGL() : 1.256 + mTextureCount(0) 1.257 + {} 1.258 +}; 1.259 + 1.260 + 1.261 +#if defined(DEBUG) 1.262 +#define CHECK_CURRENT_PROGRAM 1 1.263 +#define ASSERT_THIS_PROGRAM \ 1.264 + do { \ 1.265 + GLuint currentProgram; \ 1.266 + mGL->GetUIntegerv(LOCAL_GL_CURRENT_PROGRAM, ¤tProgram); \ 1.267 + NS_ASSERTION(currentProgram == mProgram, \ 1.268 + "SetUniform with wrong program active!"); \ 1.269 + } while (0) 1.270 +#else 1.271 +#define ASSERT_THIS_PROGRAM \ 1.272 + do { } while (0) 1.273 +#endif 1.274 + 1.275 +/** 1.276 + * Represents an OGL shader program. The details of a program are represented 1.277 + * by a ProgramProfileOGL 1.278 + */ 1.279 +class ShaderProgramOGL 1.280 +{ 1.281 +public: 1.282 + typedef mozilla::gl::GLContext GLContext; 1.283 + 1.284 + ShaderProgramOGL(GLContext* aGL, const ProgramProfileOGL& aProfile); 1.285 + 1.286 + ~ShaderProgramOGL(); 1.287 + 1.288 + bool HasInitialized() { 1.289 + NS_ASSERTION(mProgramState != STATE_OK || mProgram > 0, "Inconsistent program state"); 1.290 + return mProgramState == STATE_OK; 1.291 + } 1.292 + 1.293 + void Activate(); 1.294 + 1.295 + bool Initialize(); 1.296 + 1.297 + GLint CreateShader(GLenum aShaderType, const char *aShaderSource); 1.298 + 1.299 + /** 1.300 + * Creates a program and stores its id. 1.301 + */ 1.302 + bool CreateProgram(const char *aVertexShaderString, 1.303 + const char *aFragmentShaderString); 1.304 + 1.305 + /** 1.306 + * Lookup the location of an attribute 1.307 + */ 1.308 + GLint AttribLocation(const char* aName) { 1.309 + return mProfile.LookupAttributeLocation(aName); 1.310 + } 1.311 + 1.312 + /** 1.313 + * The following set of methods set a uniform argument to the shader program. 1.314 + * Not all uniforms may be set for all programs, and such uses will throw 1.315 + * an assertion. 1.316 + */ 1.317 + void SetLayerTransform(const gfx::Matrix4x4& aMatrix) { 1.318 + SetMatrixUniform(KnownUniform::LayerTransform, aMatrix); 1.319 + } 1.320 + 1.321 + void SetMaskLayerTransform(const gfx::Matrix4x4& aMatrix) { 1.322 + SetMatrixUniform(KnownUniform::MaskQuadTransform, aMatrix); 1.323 + } 1.324 + 1.325 + void SetLayerQuadRect(const nsIntRect& aRect) { 1.326 + gfx3DMatrix m; 1.327 + m._11 = float(aRect.width); 1.328 + m._22 = float(aRect.height); 1.329 + m._41 = float(aRect.x); 1.330 + m._42 = float(aRect.y); 1.331 + SetMatrixUniform(KnownUniform::LayerQuadTransform, m); 1.332 + } 1.333 + 1.334 + void SetLayerQuadRect(const gfx::Rect& aRect) { 1.335 + gfx3DMatrix m; 1.336 + m._11 = aRect.width; 1.337 + m._22 = aRect.height; 1.338 + m._41 = aRect.x; 1.339 + m._42 = aRect.y; 1.340 + SetMatrixUniform(KnownUniform::LayerQuadTransform, m); 1.341 + } 1.342 + 1.343 + void SetProjectionMatrix(const gfx::Matrix4x4& aMatrix) { 1.344 + SetMatrixUniform(KnownUniform::MatrixProj, aMatrix); 1.345 + } 1.346 + 1.347 + // sets this program's texture transform, if it uses one 1.348 + void SetTextureTransform(const gfx::Matrix4x4& aMatrix) { 1.349 + SetMatrixUniform(KnownUniform::TextureTransform, aMatrix); 1.350 + } 1.351 + 1.352 + void SetRenderOffset(const nsIntPoint& aOffset) { 1.353 + float vals[4] = { float(aOffset.x), float(aOffset.y), 0.0f, 0.0f }; 1.354 + SetUniform(KnownUniform::RenderTargetOffset, 4, vals); 1.355 + } 1.356 + 1.357 + void SetRenderOffset(float aX, float aY) { 1.358 + float vals[4] = { aX, aY, 0.0f, 0.0f }; 1.359 + SetUniform(KnownUniform::RenderTargetOffset, 4, vals); 1.360 + } 1.361 + 1.362 + void SetLayerOpacity(float aOpacity) { 1.363 + SetUniform(KnownUniform::LayerOpacity, aOpacity); 1.364 + } 1.365 + 1.366 + void SetTextureUnit(GLint aUnit) { 1.367 + SetUniform(KnownUniform::Texture, aUnit); 1.368 + } 1.369 + void SetYTextureUnit(GLint aUnit) { 1.370 + SetUniform(KnownUniform::YTexture, aUnit); 1.371 + } 1.372 + 1.373 + void SetCbTextureUnit(GLint aUnit) { 1.374 + SetUniform(KnownUniform::CbTexture, aUnit); 1.375 + } 1.376 + 1.377 + void SetCrTextureUnit(GLint aUnit) { 1.378 + SetUniform(KnownUniform::CrTexture, aUnit); 1.379 + } 1.380 + 1.381 + void SetYCbCrTextureUnits(GLint aYUnit, GLint aCbUnit, GLint aCrUnit) { 1.382 + SetUniform(KnownUniform::YTexture, aYUnit); 1.383 + SetUniform(KnownUniform::CbTexture, aCbUnit); 1.384 + SetUniform(KnownUniform::CrTexture, aCrUnit); 1.385 + } 1.386 + 1.387 + void SetBlackTextureUnit(GLint aUnit) { 1.388 + SetUniform(KnownUniform::BlackTexture, aUnit); 1.389 + } 1.390 + 1.391 + void SetWhiteTextureUnit(GLint aUnit) { 1.392 + SetUniform(KnownUniform::WhiteTexture, aUnit); 1.393 + } 1.394 + 1.395 + void SetMaskTextureUnit(GLint aUnit) { 1.396 + SetUniform(KnownUniform::MaskTexture, aUnit); 1.397 + } 1.398 + 1.399 + void SetRenderColor(const gfxRGBA& aColor) { 1.400 + SetUniform(KnownUniform::RenderColor, aColor); 1.401 + } 1.402 + 1.403 + void SetRenderColor(const gfx::Color& aColor) { 1.404 + SetUniform(KnownUniform::RenderColor, aColor); 1.405 + } 1.406 + 1.407 + void SetTexCoordMultiplier(float aWidth, float aHeight) { 1.408 + float f[] = {aWidth, aHeight}; 1.409 + SetUniform(KnownUniform::TexCoordMultiplier, 2, f); 1.410 + } 1.411 + 1.412 + // Set whether we want the component alpha shader to return the color 1.413 + // vector (pass 1, false) or the alpha vector (pass2, true). With support 1.414 + // for multiple render targets we wouldn't need two passes here. 1.415 + void SetTexturePass2(bool aFlag) { 1.416 + SetUniform(KnownUniform::TexturePass2, aFlag ? 1 : 0); 1.417 + } 1.418 + 1.419 + // the names of attributes 1.420 + static const char* const VertexCoordAttrib; 1.421 + static const char* const TexCoordAttrib; 1.422 + 1.423 +protected: 1.424 + RefPtr<GLContext> mGL; 1.425 + // the OpenGL id of the program 1.426 + GLuint mProgram; 1.427 + ProgramProfileOGL mProfile; 1.428 + enum { 1.429 + STATE_NEW, 1.430 + STATE_OK, 1.431 + STATE_ERROR 1.432 + } mProgramState; 1.433 + 1.434 +#ifdef CHECK_CURRENT_PROGRAM 1.435 + static int sCurrentProgramKey; 1.436 +#endif 1.437 + 1.438 + void SetUniform(KnownUniform::KnownUniformName aKnownUniform, float aFloatValue) 1.439 + { 1.440 + ASSERT_THIS_PROGRAM; 1.441 + NS_ASSERTION(aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, "Invalid known uniform"); 1.442 + 1.443 + KnownUniform& ku(mProfile.mUniforms[aKnownUniform]); 1.444 + if (ku.UpdateUniform(aFloatValue)) { 1.445 + mGL->fUniform1f(ku.mLocation, aFloatValue); 1.446 + } 1.447 + } 1.448 + 1.449 + void SetUniform(KnownUniform::KnownUniformName aKnownUniform, const gfxRGBA& aColor) 1.450 + { 1.451 + ASSERT_THIS_PROGRAM; 1.452 + NS_ASSERTION(aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, "Invalid known uniform"); 1.453 + 1.454 + KnownUniform& ku(mProfile.mUniforms[aKnownUniform]); 1.455 + if (ku.UpdateUniform(aColor.r, aColor.g, aColor.b, aColor.a)) { 1.456 + mGL->fUniform4fv(ku.mLocation, 1, ku.mValue.f16v); 1.457 + } 1.458 + } 1.459 + 1.460 + void SetUniform(KnownUniform::KnownUniformName aKnownUniform, const gfx::Color& aColor) { 1.461 + ASSERT_THIS_PROGRAM; 1.462 + NS_ASSERTION(aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, "Invalid known uniform"); 1.463 + 1.464 + KnownUniform& ku(mProfile.mUniforms[aKnownUniform]); 1.465 + if (ku.UpdateUniform(aColor.r, aColor.g, aColor.b, aColor.a)) { 1.466 + mGL->fUniform4fv(ku.mLocation, 1, ku.mValue.f16v); 1.467 + } 1.468 + } 1.469 + 1.470 + void SetUniform(KnownUniform::KnownUniformName aKnownUniform, int aLength, float *aFloatValues) 1.471 + { 1.472 + ASSERT_THIS_PROGRAM; 1.473 + NS_ASSERTION(aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, "Invalid known uniform"); 1.474 + 1.475 + KnownUniform& ku(mProfile.mUniforms[aKnownUniform]); 1.476 + if (ku.UpdateUniform(aLength, aFloatValues)) { 1.477 + switch (aLength) { 1.478 + case 1: mGL->fUniform1fv(ku.mLocation, 1, ku.mValue.f16v); break; 1.479 + case 2: mGL->fUniform2fv(ku.mLocation, 1, ku.mValue.f16v); break; 1.480 + case 3: mGL->fUniform3fv(ku.mLocation, 1, ku.mValue.f16v); break; 1.481 + case 4: mGL->fUniform4fv(ku.mLocation, 1, ku.mValue.f16v); break; 1.482 + default: 1.483 + NS_NOTREACHED("Bogus aLength param"); 1.484 + } 1.485 + } 1.486 + } 1.487 + 1.488 + void SetUniform(KnownUniform::KnownUniformName aKnownUniform, GLint aIntValue) { 1.489 + ASSERT_THIS_PROGRAM; 1.490 + NS_ASSERTION(aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, "Invalid known uniform"); 1.491 + 1.492 + KnownUniform& ku(mProfile.mUniforms[aKnownUniform]); 1.493 + if (ku.UpdateUniform(aIntValue)) { 1.494 + mGL->fUniform1i(ku.mLocation, aIntValue); 1.495 + } 1.496 + } 1.497 + 1.498 + void SetMatrixUniform(KnownUniform::KnownUniformName aKnownUniform, const float *aFloatValues) { 1.499 + ASSERT_THIS_PROGRAM; 1.500 + NS_ASSERTION(aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, "Invalid known uniform"); 1.501 + 1.502 + KnownUniform& ku(mProfile.mUniforms[aKnownUniform]); 1.503 + if (ku.UpdateUniform(16, aFloatValues)) { 1.504 + mGL->fUniformMatrix4fv(ku.mLocation, 1, false, ku.mValue.f16v); 1.505 + } 1.506 + } 1.507 + 1.508 + void SetMatrixUniform(KnownUniform::KnownUniformName aKnownUniform, const gfx3DMatrix& aMatrix) { 1.509 + SetMatrixUniform(aKnownUniform, &aMatrix._11); 1.510 + } 1.511 + 1.512 + void SetMatrixUniform(KnownUniform::KnownUniformName aKnownUniform, const gfx::Matrix4x4& aMatrix) { 1.513 + SetMatrixUniform(aKnownUniform, &aMatrix._11); 1.514 + } 1.515 +}; 1.516 + 1.517 + 1.518 +} /* layers */ 1.519 +} /* mozilla */ 1.520 + 1.521 +#endif /* GFX_OGLSHADERPROGRAM_H */