diff options
Diffstat (limited to 'gfx/layers/opengl/OGLShaderProgram.h')
-rw-r--r-- | gfx/layers/opengl/OGLShaderProgram.h | 621 |
1 files changed, 621 insertions, 0 deletions
diff --git a/gfx/layers/opengl/OGLShaderProgram.h b/gfx/layers/opengl/OGLShaderProgram.h new file mode 100644 index 000000000..ff4fb825f --- /dev/null +++ b/gfx/layers/opengl/OGLShaderProgram.h @@ -0,0 +1,621 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 "GLContext.h" // for fast inlines of glUniform* +#include "gfxTypes.h" +#include "ImageTypes.h" +#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc +#include "mozilla/Pair.h" // for Pair +#include "mozilla/RefPtr.h" // for RefPtr +#include "mozilla/gfx/Matrix.h" // for Matrix4x4 +#include "mozilla/gfx/Rect.h" // for Rect +#include "mozilla/gfx/Types.h" +#include "nsDebug.h" // for NS_ASSERTION +#include "nsPoint.h" // for nsIntPoint +#include "nsTArray.h" // for nsTArray +#include "mozilla/layers/CompositorTypes.h" + +#include <string> + +namespace mozilla { +namespace layers { + +class Layer; + +enum ShaderFeatures { + ENABLE_RENDER_COLOR=0x01, + ENABLE_TEXTURE_RECT=0x02, + ENABLE_TEXTURE_EXTERNAL=0x04, + ENABLE_TEXTURE_YCBCR=0x08, + ENABLE_TEXTURE_NV12=0x10, + ENABLE_TEXTURE_COMPONENT_ALPHA=0x20, + ENABLE_TEXTURE_NO_ALPHA=0x40, + ENABLE_TEXTURE_RB_SWAP=0x80, + ENABLE_OPACITY=0x100, + ENABLE_BLUR=0x200, + ENABLE_COLOR_MATRIX=0x400, + ENABLE_MASK=0x800, + ENABLE_NO_PREMUL_ALPHA=0x1000, + ENABLE_DEAA=0x2000, + ENABLE_DYNAMIC_GEOMETRY=0x4000 +}; + +class KnownUniform { +public: + // this needs to be kept in sync with strings in 'AddUniforms' + enum KnownUniformName { + NotAKnownUniform = -1, + + LayerTransform = 0, + LayerTransformInverse, + MaskTransform, + BackdropTransform, + LayerRects, + MatrixProj, + TextureTransform, + TextureRects, + RenderTargetOffset, + LayerOpacity, + Texture, + YTexture, + CbTexture, + CrTexture, + BlackTexture, + WhiteTexture, + MaskTexture, + BackdropTexture, + RenderColor, + TexCoordMultiplier, + CbCrTexCoordMultiplier, + TexturePass2, + ColorMatrix, + ColorMatrixVector, + BlurRadius, + BlurOffset, + BlurAlpha, + BlurGaussianKernel, + SSEdges, + ViewportSize, + VisibleCenter, + YuvColorMatrix, + + KnownUniformCount + }; + + KnownUniform() + { + mName = NotAKnownUniform; + mNameString = nullptr; + mLocation = -1; + memset(&mValue, 0, sizeof(mValue)); + } + + bool UpdateUniform(int32_t i1) { + if (mLocation == -1) return false; + if (mValue.i1 != i1) { + mValue.i1 = i1; + return true; + } + return false; + } + + bool UpdateUniform(float f1) { + if (mLocation == -1) return false; + if (mValue.f1 != f1) { + mValue.f1 = f1; + return true; + } + return false; + } + + bool UpdateUniform(float f1, float f2) { + if (mLocation == -1) return false; + if (mValue.f16v[0] != f1 || + mValue.f16v[1] != f2) + { + mValue.f16v[0] = f1; + mValue.f16v[1] = f2; + return true; + } + return false; + } + + bool UpdateUniform(float f1, float f2, float f3, float f4) { + if (mLocation == -1) return false; + if (mValue.f16v[0] != f1 || + mValue.f16v[1] != f2 || + mValue.f16v[2] != f3 || + mValue.f16v[3] != f4) + { + mValue.f16v[0] = f1; + mValue.f16v[1] = f2; + mValue.f16v[2] = f3; + mValue.f16v[3] = f4; + return true; + } + return false; + } + + bool UpdateUniform(int cnt, const float *fp) { + if (mLocation == -1) return false; + switch (cnt) { + case 1: + case 2: + case 3: + case 4: + case 9: + case 16: + if (memcmp(mValue.f16v, fp, sizeof(float) * cnt) != 0) { + memcpy(mValue.f16v, fp, sizeof(float) * cnt); + return true; + } + return false; + } + + NS_NOTREACHED("cnt must be 1 2 3 4 9 or 16"); + return false; + } + + bool UpdateArrayUniform(int cnt, const float *fp) { + if (mLocation == -1) return false; + if (cnt > 16) { + return false; + } + + if (memcmp(mValue.f16v, fp, sizeof(float) * cnt) != 0) { + memcpy(mValue.f16v, fp, sizeof(float) * cnt); + return true; + } + return false; + } + + bool UpdateArrayUniform(int cnt, const gfx::Point3D* points) { + if (mLocation == -1) return false; + if (cnt > 4) { + return false; + } + + float fp[12]; + float *d = fp; + for(int i=0; i < cnt; i++) { + // Note: Do not want to make assumptions about .x, .y, .z member packing. + // If gfx::Point3D is updated to make this guarantee, SIMD optimizations + // may be possible + *d++ = points[i].x; + *d++ = points[i].y; + *d++ = points[i].z; + } + + if (memcmp(mValue.f16v, fp, sizeof(float) * cnt * 3) != 0) { + memcpy(mValue.f16v, fp, sizeof(float) * cnt * 3); + return true; + } + return false; + } + + KnownUniformName mName; + const char *mNameString; + int32_t mLocation; + + union { + int i1; + float f1; + float f16v[16]; + } mValue; +}; + +class ShaderConfigOGL +{ +public: + ShaderConfigOGL() : + mFeatures(0), + mCompositionOp(gfx::CompositionOp::OP_OVER) + {} + + void SetRenderColor(bool aEnabled); + void SetTextureTarget(GLenum aTarget); + void SetRBSwap(bool aEnabled); + void SetNoAlpha(bool aEnabled); + void SetOpacity(bool aEnabled); + void SetYCbCr(bool aEnabled); + void SetNV12(bool aEnabled); + void SetComponentAlpha(bool aEnabled); + void SetColorMatrix(bool aEnabled); + void SetBlur(bool aEnabled); + void SetMask(bool aEnabled); + void SetDEAA(bool aEnabled); + void SetCompositionOp(gfx::CompositionOp aOp); + void SetNoPremultipliedAlpha(); + void SetDynamicGeometry(bool aEnabled); + + bool operator< (const ShaderConfigOGL& other) const { + return mFeatures < other.mFeatures || + (mFeatures == other.mFeatures && + (int)mCompositionOp < (int)other.mCompositionOp); + } + +public: + void SetFeature(int aBitmask, bool aState) { + if (aState) + mFeatures |= aBitmask; + else + mFeatures &= (~aBitmask); + } + + int mFeatures; + gfx::CompositionOp mCompositionOp; +}; + +static inline ShaderConfigOGL +ShaderConfigFromTargetAndFormat(GLenum aTarget, + gfx::SurfaceFormat aFormat) +{ + ShaderConfigOGL config; + config.SetTextureTarget(aTarget); + config.SetRBSwap(aFormat == gfx::SurfaceFormat::B8G8R8A8 || + aFormat == gfx::SurfaceFormat::B8G8R8X8); + config.SetNoAlpha(aFormat == gfx::SurfaceFormat::B8G8R8X8 || + aFormat == gfx::SurfaceFormat::R8G8B8X8 || + aFormat == gfx::SurfaceFormat::R5G6B5_UINT16); + return config; +} + +/** + * 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 + nsTArray<Pair<nsCString, GLuint>> mAttributes; + + KnownUniform mUniforms[KnownUniform::KnownUniformCount]; + nsTArray<const char *> mDefines; + size_t mTextureCount; + + ProgramProfileOGL() : + mTextureCount(0) + {} + + private: + static void BuildMixBlender(const ShaderConfigOGL& aConfig, std::ostringstream& fs); +}; + + +#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 + +/** + * 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 SetMaskLayerTransform(const gfx::Matrix4x4& aMatrix) { + SetMatrixUniform(KnownUniform::MaskTransform, aMatrix); + } + + void SetBackdropTransform(const gfx::Matrix4x4& aMatrix) { + SetMatrixUniform(KnownUniform::BackdropTransform, 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 SetBlackTextureUnit(GLint aUnit) { + SetUniform(KnownUniform::BlackTexture, aUnit); + } + + void SetWhiteTextureUnit(GLint aUnit) { + SetUniform(KnownUniform::WhiteTexture, aUnit); + } + + void SetMaskTextureUnit(GLint aUnit) { + SetUniform(KnownUniform::MaskTexture, aUnit); + } + + void SetBackdropTextureUnit(GLint aUnit) { + SetUniform(KnownUniform::BackdropTexture, aUnit); + } + + void SetRenderColor(const gfx::Color& aColor) { + SetUniform(KnownUniform::RenderColor, aColor); + } + + void SetColorMatrix(const gfx::Matrix5x4& aColorMatrix) + { + SetMatrixUniform(KnownUniform::ColorMatrix, &aColorMatrix._11); + SetUniform(KnownUniform::ColorMatrixVector, 4, &aColorMatrix._51); + } + + 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(YUVColorSpace aYUVColorSpace); + + // Set whether we want the component alpha shader to return the color + // vector (pass 1, false) or the alpha vector (pass2, true). With support + // for multiple render targets we wouldn't need two passes here. + void SetTexturePass2(bool aFlag) { + SetUniform(KnownUniform::TexturePass2, aFlag ? 1 : 0); + } + + void SetBlurRadius(float aRX, float aRY); + + void SetBlurAlpha(float aAlpha) { + SetUniform(KnownUniform::BlurAlpha, aAlpha); + } + + void SetBlurOffset(float aOffsetX, float aOffsetY) { + float f[] = {aOffsetX, aOffsetY}; + SetUniform(KnownUniform::BlurOffset, 2, f); + } + + 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::Color& 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: + NS_NOTREACHED("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 SetMatrixUniform(KnownUniform::KnownUniformName aKnownUniform, const gfx::Matrix4x4& aMatrix) { + SetMatrixUniform(aKnownUniform, &aMatrix._11); + } +}; + +} // namespace layers +} // namespace mozilla + +#endif /* GFX_OGLSHADERPROGRAM_H */ |