OGLShaderProgram.h (12774B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef GFX_OGLSHADERPROGRAM_H 8 #define GFX_OGLSHADERPROGRAM_H 9 10 #include <map> 11 #include <string> 12 #include <utility> 13 14 #include "GLContext.h" // for fast inlines of glUniform* 15 #include "mozilla/UniquePtr.h" 16 #include "OGLShaderConfig.h" 17 18 namespace mozilla { 19 namespace layers { 20 21 #if defined(DEBUG) 22 # define CHECK_CURRENT_PROGRAM 1 23 # define ASSERT_THIS_PROGRAM \ 24 do { \ 25 GLuint currentProgram; \ 26 mGL->GetUIntegerv(LOCAL_GL_CURRENT_PROGRAM, ¤tProgram); \ 27 MOZ_ASSERT(currentProgram == mProgram, \ 28 "SetUniform with wrong program active!"); \ 29 } while (0) 30 #else 31 # define ASSERT_THIS_PROGRAM \ 32 do { \ 33 } while (0) 34 #endif 35 36 /** 37 * This struct represents the shaders that make up a program and the uniform 38 * and attribute parmeters that those shaders take. 39 * It is used by ShaderProgramOGL. 40 * Use the factory method GetProfileFor to create instances. 41 */ 42 struct ProgramProfileOGL { 43 /** 44 * Factory method; creates an instance of this class for the given 45 * ShaderConfigOGL 46 */ 47 static ProgramProfileOGL GetProfileFor(ShaderConfigOGL aConfig); 48 49 // the source code for the program's shaders 50 std::string mVertexShaderString; 51 std::string mFragmentShaderString; 52 53 // the vertex attributes 54 CopyableTArray<std::pair<nsCString, GLuint>> mAttributes; 55 56 KnownUniform mUniforms[KnownUniform::KnownUniformCount]; 57 CopyableTArray<const char*> mDefines; 58 size_t mTextureCount; 59 60 ProgramProfileOGL() : mTextureCount(0) {} 61 62 private: 63 static void BuildMixBlender(const ShaderConfigOGL& aConfig, 64 std::ostringstream& fs); 65 }; 66 67 /** 68 * Represents an OGL shader program. The details of a program are represented 69 * by a ProgramProfileOGL 70 */ 71 class ShaderProgramOGL { 72 public: 73 typedef mozilla::gl::GLContext GLContext; 74 75 ShaderProgramOGL(GLContext* aGL, const ProgramProfileOGL& aProfile); 76 77 ~ShaderProgramOGL(); 78 79 bool HasInitialized() { 80 NS_ASSERTION(mProgramState != STATE_OK || mProgram > 0, 81 "Inconsistent program state"); 82 return mProgramState == STATE_OK; 83 } 84 85 GLuint GetProgram(); 86 87 bool Initialize(); 88 89 GLint CreateShader(GLenum aShaderType, const char* aShaderSource); 90 91 /** 92 * Creates a program and stores its id. 93 */ 94 bool CreateProgram(const char* aVertexShaderString, 95 const char* aFragmentShaderString); 96 97 /** 98 * The following set of methods set a uniform argument to the shader program. 99 * Not all uniforms may be set for all programs, and such uses will throw 100 * an assertion. 101 */ 102 void SetLayerTransform(const gfx::Matrix4x4& aMatrix) { 103 SetMatrixUniform(KnownUniform::LayerTransform, aMatrix); 104 } 105 106 void SetLayerTransformInverse(const gfx::Matrix4x4& aMatrix) { 107 SetMatrixUniform(KnownUniform::LayerTransformInverse, aMatrix); 108 } 109 110 void SetRoundedClipRect(const gfx::Rect& aRect) { 111 float vals[4] = {aRect.x, aRect.y, aRect.width, aRect.height}; 112 SetUniform(KnownUniform::RoundedClipRect, 4, vals); 113 } 114 115 void SetRoundedClipRadii(const gfx::RectCornerRadii& aRadii) { 116 float vals[4] = { 117 aRadii.radii[eCornerTopLeft].width, 118 aRadii.radii[eCornerBottomLeft].width, 119 aRadii.radii[eCornerTopRight].width, 120 aRadii.radii[eCornerBottomRight].width, 121 }; 122 SetUniform(KnownUniform::RoundedClipRadii, 4, vals); 123 } 124 125 void SetDEAAEdges(const gfx::Point3D* aEdges) { 126 SetArrayUniform(KnownUniform::SSEdges, 4, aEdges); 127 } 128 129 void SetViewportSize(const gfx::IntSize& aSize) { 130 float vals[2] = {(float)aSize.width, (float)aSize.height}; 131 SetUniform(KnownUniform::ViewportSize, 2, vals); 132 } 133 134 void SetVisibleCenter(const gfx::Point& aVisibleCenter) { 135 float vals[2] = {aVisibleCenter.x, aVisibleCenter.y}; 136 SetUniform(KnownUniform::VisibleCenter, 2, vals); 137 } 138 139 void SetLayerRects(const gfx::Rect* aRects) { 140 float vals[16] = { 141 aRects[0].X(), aRects[0].Y(), aRects[0].Width(), aRects[0].Height(), 142 aRects[1].X(), aRects[1].Y(), aRects[1].Width(), aRects[1].Height(), 143 aRects[2].X(), aRects[2].Y(), aRects[2].Width(), aRects[2].Height(), 144 aRects[3].X(), aRects[3].Y(), aRects[3].Width(), aRects[3].Height()}; 145 SetUniform(KnownUniform::LayerRects, 16, vals); 146 } 147 148 void SetProjectionMatrix(const gfx::Matrix4x4& aMatrix) { 149 SetMatrixUniform(KnownUniform::MatrixProj, aMatrix); 150 } 151 152 // sets this program's texture transform, if it uses one 153 void SetTextureTransform(const gfx::Matrix4x4& aMatrix) { 154 SetMatrixUniform(KnownUniform::TextureTransform, aMatrix); 155 } 156 157 void SetTextureRects(const gfx::Rect* aRects) { 158 float vals[16] = { 159 aRects[0].X(), aRects[0].Y(), aRects[0].Width(), aRects[0].Height(), 160 aRects[1].X(), aRects[1].Y(), aRects[1].Width(), aRects[1].Height(), 161 aRects[2].X(), aRects[2].Y(), aRects[2].Width(), aRects[2].Height(), 162 aRects[3].X(), aRects[3].Y(), aRects[3].Width(), aRects[3].Height()}; 163 SetUniform(KnownUniform::TextureRects, 16, vals); 164 } 165 166 void SetRenderOffset(const nsIntPoint& aOffset) { 167 float vals[4] = {float(aOffset.x), float(aOffset.y)}; 168 SetUniform(KnownUniform::RenderTargetOffset, 2, vals); 169 } 170 171 void SetRenderOffset(float aX, float aY) { 172 float vals[2] = {aX, aY}; 173 SetUniform(KnownUniform::RenderTargetOffset, 2, vals); 174 } 175 176 void SetLayerOpacity(float aOpacity) { 177 SetUniform(KnownUniform::LayerOpacity, aOpacity); 178 } 179 180 void SetTextureUnit(GLint aUnit) { SetUniform(KnownUniform::Texture, aUnit); } 181 void SetYTextureUnit(GLint aUnit) { 182 SetUniform(KnownUniform::YTexture, aUnit); 183 } 184 185 void SetCbTextureUnit(GLint aUnit) { 186 SetUniform(KnownUniform::CbTexture, aUnit); 187 } 188 189 void SetCrTextureUnit(GLint aUnit) { 190 SetUniform(KnownUniform::CrTexture, aUnit); 191 } 192 193 void SetYCbCrTextureUnits(GLint aYUnit, GLint aCbUnit, GLint aCrUnit) { 194 SetUniform(KnownUniform::YTexture, aYUnit); 195 SetUniform(KnownUniform::CbTexture, aCbUnit); 196 SetUniform(KnownUniform::CrTexture, aCrUnit); 197 } 198 199 void SetNV12TextureUnits(GLint aYUnit, GLint aCbCrUnit) { 200 SetUniform(KnownUniform::YTexture, aYUnit); 201 SetUniform(KnownUniform::CbTexture, aCbCrUnit); 202 } 203 204 void SetTexCoordMultiplier(float aWidth, float aHeight) { 205 float f[] = {aWidth, aHeight}; 206 SetUniform(KnownUniform::TexCoordMultiplier, 2, f); 207 } 208 209 void SetCbCrTexCoordMultiplier(float aWidth, float aHeight) { 210 float f[] = {aWidth, aHeight}; 211 SetUniform(KnownUniform::CbCrTexCoordMultiplier, 2, f); 212 } 213 214 void SetYUVColorSpace(gfx::YUVColorSpace aYUVColorSpace); 215 216 size_t GetTextureCount() const { return mProfile.mTextureCount; } 217 218 protected: 219 RefPtr<GLContext> mGL; 220 // the OpenGL id of the program 221 GLuint mProgram; 222 ProgramProfileOGL mProfile; 223 enum { STATE_NEW, STATE_OK, STATE_ERROR } mProgramState; 224 225 #ifdef CHECK_CURRENT_PROGRAM 226 static int sCurrentProgramKey; 227 #endif 228 229 void SetUniform(KnownUniform::KnownUniformName aKnownUniform, 230 float aFloatValue) { 231 ASSERT_THIS_PROGRAM; 232 NS_ASSERTION( 233 aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, 234 "Invalid known uniform"); 235 236 KnownUniform& ku(mProfile.mUniforms[aKnownUniform]); 237 if (ku.UpdateUniform(aFloatValue)) { 238 mGL->fUniform1f(ku.mLocation, aFloatValue); 239 } 240 } 241 242 void SetUniform(KnownUniform::KnownUniformName aKnownUniform, 243 const gfx::DeviceColor& aColor) { 244 ASSERT_THIS_PROGRAM; 245 NS_ASSERTION( 246 aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, 247 "Invalid known uniform"); 248 249 KnownUniform& ku(mProfile.mUniforms[aKnownUniform]); 250 if (ku.UpdateUniform(aColor.r, aColor.g, aColor.b, aColor.a)) { 251 mGL->fUniform4fv(ku.mLocation, 1, ku.mValue.f16v); 252 } 253 } 254 255 void SetUniform(KnownUniform::KnownUniformName aKnownUniform, int aLength, 256 const float* aFloatValues) { 257 ASSERT_THIS_PROGRAM; 258 NS_ASSERTION( 259 aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, 260 "Invalid known uniform"); 261 262 KnownUniform& ku(mProfile.mUniforms[aKnownUniform]); 263 if (ku.UpdateUniform(aLength, aFloatValues)) { 264 switch (aLength) { 265 case 1: 266 mGL->fUniform1fv(ku.mLocation, 1, ku.mValue.f16v); 267 break; 268 case 2: 269 mGL->fUniform2fv(ku.mLocation, 1, ku.mValue.f16v); 270 break; 271 case 3: 272 mGL->fUniform3fv(ku.mLocation, 1, ku.mValue.f16v); 273 break; 274 case 4: 275 mGL->fUniform4fv(ku.mLocation, 1, ku.mValue.f16v); 276 break; 277 case 16: 278 mGL->fUniform4fv(ku.mLocation, 4, ku.mValue.f16v); 279 break; 280 default: 281 MOZ_ASSERT_UNREACHABLE("Bogus aLength param"); 282 } 283 } 284 } 285 286 void SetArrayUniform(KnownUniform::KnownUniformName aKnownUniform, 287 int aLength, float* aFloatValues) { 288 ASSERT_THIS_PROGRAM; 289 NS_ASSERTION( 290 aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, 291 "Invalid known uniform"); 292 293 KnownUniform& ku(mProfile.mUniforms[aKnownUniform]); 294 if (ku.UpdateArrayUniform(aLength, aFloatValues)) { 295 mGL->fUniform1fv(ku.mLocation, aLength, ku.mValue.f16v); 296 } 297 } 298 299 void SetArrayUniform(KnownUniform::KnownUniformName aKnownUniform, 300 int aLength, const gfx::Point3D* aPointValues) { 301 ASSERT_THIS_PROGRAM; 302 NS_ASSERTION( 303 aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, 304 "Invalid known uniform"); 305 306 KnownUniform& ku(mProfile.mUniforms[aKnownUniform]); 307 if (ku.UpdateArrayUniform(aLength, aPointValues)) { 308 mGL->fUniform3fv(ku.mLocation, aLength, ku.mValue.f16v); 309 } 310 } 311 312 void SetUniform(KnownUniform::KnownUniformName aKnownUniform, 313 GLint aIntValue) { 314 ASSERT_THIS_PROGRAM; 315 NS_ASSERTION( 316 aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, 317 "Invalid known uniform"); 318 319 KnownUniform& ku(mProfile.mUniforms[aKnownUniform]); 320 if (ku.UpdateUniform(aIntValue)) { 321 mGL->fUniform1i(ku.mLocation, aIntValue); 322 } 323 } 324 325 void SetMatrixUniform(KnownUniform::KnownUniformName aKnownUniform, 326 const float* aFloatValues) { 327 ASSERT_THIS_PROGRAM; 328 NS_ASSERTION( 329 aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, 330 "Invalid known uniform"); 331 332 KnownUniform& ku(mProfile.mUniforms[aKnownUniform]); 333 if (ku.UpdateUniform(16, aFloatValues)) { 334 mGL->fUniformMatrix4fv(ku.mLocation, 1, false, ku.mValue.f16v); 335 } 336 } 337 338 void SetMatrix3fvUniform(KnownUniform::KnownUniformName aKnownUniform, 339 const float* aFloatValues) { 340 ASSERT_THIS_PROGRAM; 341 NS_ASSERTION( 342 aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, 343 "Invalid known uniform"); 344 345 KnownUniform& ku(mProfile.mUniforms[aKnownUniform]); 346 if (ku.UpdateUniform(9, aFloatValues)) { 347 mGL->fUniformMatrix3fv(ku.mLocation, 1, false, ku.mValue.f16v); 348 } 349 } 350 351 void SetVec3fvUniform(KnownUniform::KnownUniformName aKnownUniform, 352 const float* aFloatValues) { 353 ASSERT_THIS_PROGRAM; 354 NS_ASSERTION( 355 aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, 356 "Invalid known uniform"); 357 358 KnownUniform& ku(mProfile.mUniforms[aKnownUniform]); 359 if (ku.UpdateUniform(3, aFloatValues)) { 360 mGL->fUniform3fv(ku.mLocation, 1, ku.mValue.f16v); 361 } 362 } 363 364 void SetMatrixUniform(KnownUniform::KnownUniformName aKnownUniform, 365 const gfx::Matrix4x4& aMatrix) { 366 SetMatrixUniform(aKnownUniform, &aMatrix._11); 367 } 368 }; 369 370 class ShaderProgramOGLsHolder final { 371 public: 372 NS_INLINE_DECL_REFCOUNTING(ShaderProgramOGLsHolder) 373 374 explicit ShaderProgramOGLsHolder(gl::GLContext* aGL); 375 376 ShaderProgramOGL* GetShaderProgramFor(const ShaderConfigOGL& aConfig); 377 void Clear(); 378 ShaderProgramOGL* ActivateProgram(const ShaderConfigOGL& aConfig); 379 void ResetCurrentProgram(); 380 381 protected: 382 ~ShaderProgramOGLsHolder(); 383 384 const RefPtr<gl::GLContext> mGL; 385 std::map<ShaderConfigOGL, UniquePtr<ShaderProgramOGL>> mPrograms; 386 ShaderProgramOGL* mCurrentProgram = nullptr; 387 }; 388 389 } // namespace layers 390 } // namespace mozilla 391 392 #endif // GFX_OGLSHADERPROGRAM_H