diff options
Diffstat (limited to '')
-rw-r--r-- | gfx/layers/opengl/OGLShaderProgram.h | 377 |
1 files changed, 377 insertions, 0 deletions
diff --git a/gfx/layers/opengl/OGLShaderProgram.h b/gfx/layers/opengl/OGLShaderProgram.h new file mode 100644 index 0000000000..cfeb7dd23e --- /dev/null +++ b/gfx/layers/opengl/OGLShaderProgram.h @@ -0,0 +1,377 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef GFX_OGLSHADERPROGRAM_H +#define GFX_OGLSHADERPROGRAM_H + +#include <map> +#include <string> +#include <utility> + +#include "GLContext.h" // for fast inlines of glUniform* +#include "mozilla/UniquePtr.h" +#include "OGLShaderConfig.h" + +namespace mozilla { +namespace layers { + +#if defined(DEBUG) +# define CHECK_CURRENT_PROGRAM 1 +# define ASSERT_THIS_PROGRAM \ + do { \ + GLuint currentProgram; \ + mGL->GetUIntegerv(LOCAL_GL_CURRENT_PROGRAM, ¤tProgram); \ + MOZ_ASSERT(currentProgram == mProgram, \ + "SetUniform with wrong program active!"); \ + } while (0) +#else +# define ASSERT_THIS_PROGRAM \ + do { \ + } while (0) +#endif + +/** + * This struct represents the shaders that make up a program and the uniform + * and attribute parmeters that those shaders take. + * It is used by ShaderProgramOGL. + * Use the factory method GetProfileFor to create instances. + */ +struct ProgramProfileOGL { + /** + * Factory method; creates an instance of this class for the given + * ShaderConfigOGL + */ + static ProgramProfileOGL GetProfileFor(ShaderConfigOGL aConfig); + + // the source code for the program's shaders + std::string mVertexShaderString; + std::string mFragmentShaderString; + + // the vertex attributes + CopyableTArray<std::pair<nsCString, GLuint>> mAttributes; + + KnownUniform mUniforms[KnownUniform::KnownUniformCount]; + CopyableTArray<const char*> mDefines; + size_t mTextureCount; + + ProgramProfileOGL() : mTextureCount(0) {} + + private: + static void BuildMixBlender(const ShaderConfigOGL& aConfig, + std::ostringstream& fs); +}; + +/** + * Represents an OGL shader program. The details of a program are represented + * by a ProgramProfileOGL + */ +class ShaderProgramOGL { + public: + typedef mozilla::gl::GLContext GLContext; + + ShaderProgramOGL(GLContext* aGL, const ProgramProfileOGL& aProfile); + + ~ShaderProgramOGL(); + + bool HasInitialized() { + NS_ASSERTION(mProgramState != STATE_OK || mProgram > 0, + "Inconsistent program state"); + return mProgramState == STATE_OK; + } + + GLuint GetProgram(); + + bool Initialize(); + + GLint CreateShader(GLenum aShaderType, const char* aShaderSource); + + /** + * Creates a program and stores its id. + */ + bool CreateProgram(const char* aVertexShaderString, + const char* aFragmentShaderString); + + /** + * The following set of methods set a uniform argument to the shader program. + * Not all uniforms may be set for all programs, and such uses will throw + * an assertion. + */ + void SetLayerTransform(const gfx::Matrix4x4& aMatrix) { + SetMatrixUniform(KnownUniform::LayerTransform, aMatrix); + } + + void SetLayerTransformInverse(const gfx::Matrix4x4& aMatrix) { + SetMatrixUniform(KnownUniform::LayerTransformInverse, aMatrix); + } + + void SetDEAAEdges(const gfx::Point3D* aEdges) { + SetArrayUniform(KnownUniform::SSEdges, 4, aEdges); + } + + void SetViewportSize(const gfx::IntSize& aSize) { + float vals[2] = {(float)aSize.width, (float)aSize.height}; + SetUniform(KnownUniform::ViewportSize, 2, vals); + } + + void SetVisibleCenter(const gfx::Point& aVisibleCenter) { + float vals[2] = {aVisibleCenter.x, aVisibleCenter.y}; + SetUniform(KnownUniform::VisibleCenter, 2, vals); + } + + void SetLayerRects(const gfx::Rect* aRects) { + float vals[16] = { + aRects[0].X(), aRects[0].Y(), aRects[0].Width(), aRects[0].Height(), + aRects[1].X(), aRects[1].Y(), aRects[1].Width(), aRects[1].Height(), + aRects[2].X(), aRects[2].Y(), aRects[2].Width(), aRects[2].Height(), + aRects[3].X(), aRects[3].Y(), aRects[3].Width(), aRects[3].Height()}; + SetUniform(KnownUniform::LayerRects, 16, vals); + } + + void SetProjectionMatrix(const gfx::Matrix4x4& aMatrix) { + SetMatrixUniform(KnownUniform::MatrixProj, aMatrix); + } + + // sets this program's texture transform, if it uses one + void SetTextureTransform(const gfx::Matrix4x4& aMatrix) { + SetMatrixUniform(KnownUniform::TextureTransform, aMatrix); + } + + void SetTextureRects(const gfx::Rect* aRects) { + float vals[16] = { + aRects[0].X(), aRects[0].Y(), aRects[0].Width(), aRects[0].Height(), + aRects[1].X(), aRects[1].Y(), aRects[1].Width(), aRects[1].Height(), + aRects[2].X(), aRects[2].Y(), aRects[2].Width(), aRects[2].Height(), + aRects[3].X(), aRects[3].Y(), aRects[3].Width(), aRects[3].Height()}; + SetUniform(KnownUniform::TextureRects, 16, vals); + } + + void SetRenderOffset(const nsIntPoint& aOffset) { + float vals[4] = {float(aOffset.x), float(aOffset.y)}; + SetUniform(KnownUniform::RenderTargetOffset, 2, vals); + } + + void SetRenderOffset(float aX, float aY) { + float vals[2] = {aX, aY}; + SetUniform(KnownUniform::RenderTargetOffset, 2, vals); + } + + void SetLayerOpacity(float aOpacity) { + SetUniform(KnownUniform::LayerOpacity, aOpacity); + } + + void SetTextureUnit(GLint aUnit) { SetUniform(KnownUniform::Texture, aUnit); } + void SetYTextureUnit(GLint aUnit) { + SetUniform(KnownUniform::YTexture, aUnit); + } + + void SetCbTextureUnit(GLint aUnit) { + SetUniform(KnownUniform::CbTexture, aUnit); + } + + void SetCrTextureUnit(GLint aUnit) { + SetUniform(KnownUniform::CrTexture, aUnit); + } + + void SetYCbCrTextureUnits(GLint aYUnit, GLint aCbUnit, GLint aCrUnit) { + SetUniform(KnownUniform::YTexture, aYUnit); + SetUniform(KnownUniform::CbTexture, aCbUnit); + SetUniform(KnownUniform::CrTexture, aCrUnit); + } + + void SetNV12TextureUnits(GLint aYUnit, GLint aCbCrUnit) { + SetUniform(KnownUniform::YTexture, aYUnit); + SetUniform(KnownUniform::CbTexture, aCbCrUnit); + } + + void SetTexCoordMultiplier(float aWidth, float aHeight) { + float f[] = {aWidth, aHeight}; + SetUniform(KnownUniform::TexCoordMultiplier, 2, f); + } + + void SetCbCrTexCoordMultiplier(float aWidth, float aHeight) { + float f[] = {aWidth, aHeight}; + SetUniform(KnownUniform::CbCrTexCoordMultiplier, 2, f); + } + + void SetYUVColorSpace(gfx::YUVColorSpace aYUVColorSpace); + + size_t GetTextureCount() const { return mProfile.mTextureCount; } + + protected: + RefPtr<GLContext> mGL; + // the OpenGL id of the program + GLuint mProgram; + ProgramProfileOGL mProfile; + enum { STATE_NEW, STATE_OK, STATE_ERROR } mProgramState; + +#ifdef CHECK_CURRENT_PROGRAM + static int sCurrentProgramKey; +#endif + + void SetUniform(KnownUniform::KnownUniformName aKnownUniform, + float aFloatValue) { + ASSERT_THIS_PROGRAM; + NS_ASSERTION( + aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, + "Invalid known uniform"); + + KnownUniform& ku(mProfile.mUniforms[aKnownUniform]); + if (ku.UpdateUniform(aFloatValue)) { + mGL->fUniform1f(ku.mLocation, aFloatValue); + } + } + + void SetUniform(KnownUniform::KnownUniformName aKnownUniform, + const gfx::DeviceColor& aColor) { + ASSERT_THIS_PROGRAM; + NS_ASSERTION( + aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, + "Invalid known uniform"); + + KnownUniform& ku(mProfile.mUniforms[aKnownUniform]); + if (ku.UpdateUniform(aColor.r, aColor.g, aColor.b, aColor.a)) { + mGL->fUniform4fv(ku.mLocation, 1, ku.mValue.f16v); + } + } + + void SetUniform(KnownUniform::KnownUniformName aKnownUniform, int aLength, + const float* aFloatValues) { + ASSERT_THIS_PROGRAM; + NS_ASSERTION( + aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, + "Invalid known uniform"); + + KnownUniform& ku(mProfile.mUniforms[aKnownUniform]); + if (ku.UpdateUniform(aLength, aFloatValues)) { + switch (aLength) { + case 1: + mGL->fUniform1fv(ku.mLocation, 1, ku.mValue.f16v); + break; + case 2: + mGL->fUniform2fv(ku.mLocation, 1, ku.mValue.f16v); + break; + case 3: + mGL->fUniform3fv(ku.mLocation, 1, ku.mValue.f16v); + break; + case 4: + mGL->fUniform4fv(ku.mLocation, 1, ku.mValue.f16v); + break; + case 16: + mGL->fUniform4fv(ku.mLocation, 4, ku.mValue.f16v); + break; + default: + MOZ_ASSERT_UNREACHABLE("Bogus aLength param"); + } + } + } + + void SetArrayUniform(KnownUniform::KnownUniformName aKnownUniform, + int aLength, float* aFloatValues) { + ASSERT_THIS_PROGRAM; + NS_ASSERTION( + aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, + "Invalid known uniform"); + + KnownUniform& ku(mProfile.mUniforms[aKnownUniform]); + if (ku.UpdateArrayUniform(aLength, aFloatValues)) { + mGL->fUniform1fv(ku.mLocation, aLength, ku.mValue.f16v); + } + } + + void SetArrayUniform(KnownUniform::KnownUniformName aKnownUniform, + int aLength, const gfx::Point3D* aPointValues) { + ASSERT_THIS_PROGRAM; + NS_ASSERTION( + aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, + "Invalid known uniform"); + + KnownUniform& ku(mProfile.mUniforms[aKnownUniform]); + if (ku.UpdateArrayUniform(aLength, aPointValues)) { + mGL->fUniform3fv(ku.mLocation, aLength, ku.mValue.f16v); + } + } + + void SetUniform(KnownUniform::KnownUniformName aKnownUniform, + GLint aIntValue) { + ASSERT_THIS_PROGRAM; + NS_ASSERTION( + aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, + "Invalid known uniform"); + + KnownUniform& ku(mProfile.mUniforms[aKnownUniform]); + if (ku.UpdateUniform(aIntValue)) { + mGL->fUniform1i(ku.mLocation, aIntValue); + } + } + + void SetMatrixUniform(KnownUniform::KnownUniformName aKnownUniform, + const float* aFloatValues) { + ASSERT_THIS_PROGRAM; + NS_ASSERTION( + aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, + "Invalid known uniform"); + + KnownUniform& ku(mProfile.mUniforms[aKnownUniform]); + if (ku.UpdateUniform(16, aFloatValues)) { + mGL->fUniformMatrix4fv(ku.mLocation, 1, false, ku.mValue.f16v); + } + } + + void SetMatrix3fvUniform(KnownUniform::KnownUniformName aKnownUniform, + const float* aFloatValues) { + ASSERT_THIS_PROGRAM; + NS_ASSERTION( + aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, + "Invalid known uniform"); + + KnownUniform& ku(mProfile.mUniforms[aKnownUniform]); + if (ku.UpdateUniform(9, aFloatValues)) { + mGL->fUniformMatrix3fv(ku.mLocation, 1, false, ku.mValue.f16v); + } + } + + void SetVec3fvUniform(KnownUniform::KnownUniformName aKnownUniform, + const float* aFloatValues) { + ASSERT_THIS_PROGRAM; + NS_ASSERTION( + aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, + "Invalid known uniform"); + + KnownUniform& ku(mProfile.mUniforms[aKnownUniform]); + if (ku.UpdateUniform(3, aFloatValues)) { + mGL->fUniform3fv(ku.mLocation, 1, ku.mValue.f16v); + } + } + + void SetMatrixUniform(KnownUniform::KnownUniformName aKnownUniform, + const gfx::Matrix4x4& aMatrix) { + SetMatrixUniform(aKnownUniform, &aMatrix._11); + } +}; + +class ShaderProgramOGLsHolder final { + public: + NS_INLINE_DECL_REFCOUNTING(ShaderProgramOGLsHolder) + + explicit ShaderProgramOGLsHolder(gl::GLContext* aGL); + + ShaderProgramOGL* GetShaderProgramFor(const ShaderConfigOGL& aConfig); + void Clear(); + ShaderProgramOGL* ActivateProgram(const ShaderConfigOGL& aConfig); + void ResetCurrentProgram(); + + protected: + ~ShaderProgramOGLsHolder(); + + const RefPtr<gl::GLContext> mGL; + std::map<ShaderConfigOGL, UniquePtr<ShaderProgramOGL>> mPrograms; + ShaderProgramOGL* mCurrentProgram = nullptr; +}; + +} // namespace layers +} // namespace mozilla + +#endif // GFX_OGLSHADERPROGRAM_H |