Source code
Revision control
Copy as Markdown
Other Tools
/* -*- 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
#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