Commit 79a33df6 authored by Nicholas Cameron's avatar Nicholas Cameron
Browse files

Bug 716439; compile OGL shaders lazily. r=BenWa

parent b4264df3
Loading
Loading
Loading
Loading
+11 −14
Original line number Diff line number Diff line
@@ -182,25 +182,17 @@ LayerManagerOGL::CreateContext()
  return context.forget();
}

bool
LayerManagerOGL::InitAndAddPrograms(ShaderProgramType aType)
void
LayerManagerOGL::AddPrograms(ShaderProgramType aType)
{
  for (PRUint32 maskType = MaskNone; maskType < NumMaskTypes; ++maskType) {
    if (ProgramProfileOGL::ProgramExists(aType, static_cast<MaskType>(maskType))) {
      ShaderProgramOGL* p = new ShaderProgramOGL(this->gl(),
      mPrograms[aType].mVariations[maskType] = new ShaderProgramOGL(this->gl(),
        ProgramProfileOGL::GetProfileFor(aType, static_cast<MaskType>(maskType)));
      if (!p->Initialize()) {
        delete p;
        mPrograms[aType].mVariations[maskType] = nsnull;
        return false;
      }
      mPrograms[aType].mVariations[maskType] = p;
    } else {
      mPrograms[aType].mVariations[maskType] = nsnull;
    }
  }

  return true;
}

bool
@@ -227,13 +219,17 @@ LayerManagerOGL::Initialize(nsRefPtr<GLContext> aContext, bool force)
                                 LOCAL_GL_ONE, LOCAL_GL_ONE);
  mGLContext->fEnable(LOCAL_GL_BLEND);

  // we must initialise shaders in order
  mPrograms.AppendElements(NumProgramTypes);
  for (int type = 0; type < NumProgramTypes; ++type) {
    if (!InitAndAddPrograms(static_cast<ShaderProgramType>(type)))
    AddPrograms(static_cast<ShaderProgramType>(type));
  }

  // initialise a common shader to check that we can actually compile a shader
  if (!mPrograms[gl::RGBALayerProgramType].mVariations[MaskNone]->Initialize()) {
    return false;
  }


  mGLContext->fGenFramebuffers(1, &mBackBufferFBO);

  if (mGLContext->WorkAroundDriverBugs()) {
@@ -678,6 +674,7 @@ LayerManagerOGL::BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg,
                                                GLenum aWrapMode /* = LOCAL_GL_REPEAT */,
                                                bool aFlipped /* = false */)
{
  NS_ASSERTION(aProg->HasInitialized(), "Shader program not correctly initialized");
  GLuint vertAttribIndex =
    aProg->AttribLocation(ShaderProgramOGL::VertexCoordAttrib);
  GLuint texCoordAttribIndex =
+4 −11
Original line number Diff line number Diff line
@@ -331,6 +331,7 @@ public:
  void BindAndDrawQuad(ShaderProgramOGL *aProg,
                       bool aFlipped = false)
  {
    NS_ASSERTION(aProg->HasInitialized(), "Shader program not correctly initialized");
    BindAndDrawQuad(aProg->AttribLocation(ShaderProgramOGL::VertexCoordAttrib),
                    aProg->AttribLocation(ShaderProgramOGL::TexCoordAttrib),
                    aFlipped);
@@ -447,22 +448,14 @@ private:

  /**
   * Updates all layer programs with a new projection matrix.
   *
   * XXX we need a way to be able to delay setting this until
   * the program is actually used.  Maybe a DelayedSetUniform
   * on Program, that will delay the set until the next Activate?
   *
   * XXX this is only called once per frame, so it's not awful.
   * If we have any more similar updates, then we should delay.
   */
  void SetLayerProgramProjectionMatrix(const gfx3DMatrix& aMatrix);

  /**
   * Helper method for Initialize, creates all valid variations of a program,
   * initialises them, and adds them to mPrograms
   * returns false if any initialisation fails
   * Helper method for Initialize, creates all valid variations of a program
   * and adds them to mPrograms
   */
  bool InitAndAddPrograms(gl::ShaderProgramType aType);
  void AddPrograms(gl::ShaderProgramType aType);

  /* Thebes layer callbacks; valid at the end of a transaciton,
   * while rendering */
+5 −9
Original line number Diff line number Diff line
@@ -198,11 +198,16 @@ const char* const ShaderProgramOGL::TexCoordAttrib = "aTexCoord";
bool
ShaderProgramOGL::Initialize()
{
  NS_ASSERTION(mProgramState == STATE_NEW, "Shader program has already been initialised");

  if (!CreateProgram(mProfile.mVertexShaderString,
                     mProfile.mFragmentShaderString)) {
    mProgramState = STATE_ERROR;
    return false;
  }

  mProgramState = STATE_OK;

  for (PRUint32 i = 0; i < mProfile.mUniforms.Length(); ++i) {
    mProfile.mUniforms[i].mLocation =
      mGL->fGetUniformLocation(mProgram, mProfile.mUniforms[i].mName);
@@ -323,15 +328,6 @@ ShaderProgramOGL::CreateProgram(const char *aVertexShaderString,
  return true;
}

void
ShaderProgramOGL::CheckAndSetProjectionMatrix(const gfx3DMatrix& aMatrix)
{
  if (mProfile.mHasMatrixProj) {
    Activate();
    SetProjectionMatrix(aMatrix);
  }
}

bool
ShaderProgramOGL::LoadMask(Layer* aMaskLayer)
{
+40 −3
Original line number Diff line number Diff line
@@ -170,10 +170,15 @@ public:
  typedef mozilla::gl::GLContext GLContext;

  ShaderProgramOGL(GLContext* aGL, const ProgramProfileOGL& aProfile) :
    mGL(aGL), mProgram(-1), mProfile(aProfile) { }
    mGL(aGL), mProgram(0), mProgramState(STATE_NEW),
    mIsProjectionMatrixStale(false), mProfile(aProfile) { }


  ~ShaderProgramOGL() {
    if (mProgram <= 0) {
      return;
    }

    nsRefPtr<GLContext> ctx = mGL->GetSharedContext();
    if (!ctx) {
      ctx = mGL;
@@ -182,12 +187,27 @@ public:
    ctx->fDeleteProgram(mProgram);
  }

  bool HasInitialized() {
    NS_ASSERTION(mProgramState != STATE_OK || mProgram > 0, "Inconsistent program state");
    return mProgramState == STATE_OK;
  }

  void Activate() {
    NS_ASSERTION(mProgram != 0, "Attempting to activate a program that's not in use!");
    if (mProgramState == STATE_NEW) {
      if (!Initialize()) {
        NS_WARNING("Shader could not be initialised");
        return;
      }
    }
    NS_ASSERTION(HasInitialized(), "Attempting to activate a program that's not in use!");
    mGL->fUseProgram(mProgram);
#if CHECK_CURRENT_PROGRAM
    mGL->SetUserData(&sCurrentProgramKey, this);
#endif
    // check and set the projection matrix
    if (mIsProjectionMatrixStale) {
      SetProjectionMatrix(mProjectionMatrix);
    }
  }

  bool Initialize();
@@ -244,10 +264,17 @@ public:
  }

  // activates this program and sets its projection matrix, if the program uses one
  void CheckAndSetProjectionMatrix(const gfx3DMatrix& aMatrix);
  void CheckAndSetProjectionMatrix(const gfx3DMatrix& aMatrix)
  {
    if (mProfile.mHasMatrixProj) {
      mIsProjectionMatrixStale = true;
      mProjectionMatrix = aMatrix;
    }
  }

  void SetProjectionMatrix(const gfx3DMatrix& aMatrix) {
    SetMatrixUniform(mProfile.LookupUniformLocation("uMatrixProj"), aMatrix);
    mIsProjectionMatrixStale = false;
  }

  void SetRenderOffset(const nsIntPoint& aOffset) {
@@ -307,9 +334,19 @@ public:
  static const char* const TexCoordAttrib;

protected:
  gfx3DMatrix mProjectionMatrix;
  // true if the projection matrix needs setting
  bool mIsProjectionMatrixStale;

  nsRefPtr<GLContext> mGL;
  // the OpenGL id of the program 
  GLuint mProgram;
  ProgramProfileOGL mProfile;
  enum {
    STATE_NEW,
    STATE_OK,
    STATE_ERROR
  } mProgramState;

  GLint mTexCoordMultiplierUniformLocation;
#ifdef CHECK_CURRENT_PROGRAM