summaryrefslogtreecommitdiffstats
path: root/gfx/layers/opengl/OGLShaderProgram.h
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/layers/opengl/OGLShaderProgram.h')
-rw-r--r--gfx/layers/opengl/OGLShaderProgram.h377
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, &currentProgram); \
+ 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