Bug 923409 - Draw FPS counter with a single GL call and eliminate last use of Copy2D program (r=BenWa).
authorAndreas Gal <gal@mozilla.com>
Sun, 13 Oct 2013 09:10:13 -0700
changeset 150605 33563ee5a85975f7f8590d832110f66a4ee81245
parent 150603 e628236f3424d717d1fb846358a3368518552798
child 150606 20ffeada8ecab8a70699718cbc5c7d370cd7f5bf
push id25452
push usercbook@mozilla.com
push dateMon, 14 Oct 2013 12:04:08 +0000
treeherdermozilla-central@e8bb002bc13a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersBenWa
bugs923409
milestone27.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 923409 - Draw FPS counter with a single GL call and eliminate last use of Copy2D program (r=BenWa).
gfx/layers/opengl/CompositorOGL.cpp
gfx/layers/opengl/FPSCounter.h
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -54,74 +54,126 @@ using namespace gfx;
 namespace layers {
 
 using namespace mozilla::gl;
 
 static inline IntSize ns2gfxSize(const nsIntSize& s) {
   return IntSize(s.width, s.height);
 }
 
-// Draw the supplied geometry with the already selected shader. Both aArray1
-// and aArray2 are expected to have a stride of 2 * sizeof(GLfloat).
+// Draw the given quads with the already selected shader. Texture coordinates
+// are supplied if the shader requires them.
 static void
-DrawWithVertexBuffer2(GLContext *aGLContext, VBOArena &aVBOs,
-                      GLenum aMode, GLsizei aElements,
-                      GLint aAttr1, GLfloat *aArray1,
-                      GLint aAttr2, GLfloat *aArray2)
+DrawQuads(GLContext *aGLContext,
+          VBOArena &aVBOs,
+          ShaderProgramOGL *aProg,
+          GLContext::RectTriangles &aRects)
 {
-  GLsizei bytes = aElements * 2 * sizeof(GLfloat);
+  NS_ASSERTION(aProg->HasInitialized(), "Shader program not correctly initialized");
+  GLuint vertAttribIndex =
+    aProg->AttribLocation(ShaderProgramOGL::VertexCoordAttrib);
+  GLuint texCoordAttribIndex =
+    aProg->AttribLocation(ShaderProgramOGL::TexCoordAttrib);
+  bool texCoords = (texCoordAttribIndex != GLuint(-1));
+
+  GLsizei elements = aRects.elements();
+  GLsizei bytes = elements * 2 * sizeof(GLfloat);
+
+  GLsizei total = bytes;
+  if (texCoords) {
+    total *= 2;
+  }
 
   aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER,
                           aVBOs.Allocate(aGLContext));
   aGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER,
-                          2 * bytes,
+                          total,
                           nullptr,
                           LOCAL_GL_STREAM_DRAW);
 
   aGLContext->fBufferSubData(LOCAL_GL_ARRAY_BUFFER,
                              0,
                              bytes,
-                             aArray1);
-  aGLContext->fBufferSubData(LOCAL_GL_ARRAY_BUFFER,
-                             bytes,
-                             bytes,
-                             aArray2);
-
-  aGLContext->fEnableVertexAttribArray(aAttr1);
-  aGLContext->fEnableVertexAttribArray(aAttr2);
-
-  aGLContext->fVertexAttribPointer(aAttr1,
+                             aRects.vertexPointer());
+  aGLContext->fEnableVertexAttribArray(vertAttribIndex);
+  aGLContext->fVertexAttribPointer(vertAttribIndex,
                                    2, LOCAL_GL_FLOAT,
                                    LOCAL_GL_FALSE,
                                    0, BUFFER_OFFSET(0));
-  aGLContext->fVertexAttribPointer(aAttr2,
-                                   2, LOCAL_GL_FLOAT,
-                                   LOCAL_GL_FALSE,
-                                   0, BUFFER_OFFSET(bytes));
 
-  aGLContext->fDrawArrays(aMode, 0, aElements);
+  if (texCoords) {
+    aGLContext->fBufferSubData(LOCAL_GL_ARRAY_BUFFER,
+                               bytes,
+                               bytes,
+                               aRects.texCoordPointer());
+    aGLContext->fEnableVertexAttribArray(texCoordAttribIndex);
+    aGLContext->fVertexAttribPointer(texCoordAttribIndex,
+                                     2, LOCAL_GL_FLOAT,
+                                     LOCAL_GL_FALSE,
+                                     0, BUFFER_OFFSET(bytes));
+  }
 
-  aGLContext->fDisableVertexAttribArray(aAttr1);
-  aGLContext->fDisableVertexAttribArray(aAttr2);
+  aGLContext->fDrawArrays(LOCAL_GL_TRIANGLES, 0, elements);
+
+  aGLContext->fDisableVertexAttribArray(vertAttribIndex);
+  if (texCoords) {
+    aGLContext->fDisableVertexAttribArray(texCoordAttribIndex);
+  }
 
   aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
 }
 
+// Size of the builtin font.
+static const float FontHeight = 7.f;
+static const float FontWidth = 5.f;
+static const float FontStride = 4.f;
+
+// Scale the font when drawing it to the viewport for better readability.
+static const float FontScaleX = 2.f;
+static const float FontScaleY = 3.f;
+
+// Size of the font texture (POT).
+static const size_t FontTextureWidth = 64;
+static const size_t FontTextureHeight = 8;
+
+static void
+AddDigits(GLContext::RectTriangles &aRects,
+          const gfx::IntSize aViewportSize,
+          unsigned int aOffset,
+          unsigned int aValue)
+{
+  unsigned int divisor = 100;
+  for (size_t n = 0; n < 3; ++n) {
+    gfxRect d(aOffset * FontWidth, 0.f, FontWidth, FontHeight);
+    d.Scale(FontScaleX / aViewportSize.width, FontScaleY / aViewportSize.height);
+
+    unsigned int digit = aValue % (divisor * 10) / divisor;
+    gfxRect t(digit * FontStride, 0.f, FontWidth, FontHeight);
+    t.Scale(1.f / FontTextureWidth, 1.f / FontTextureHeight);
+
+    aRects.addRect(d.x, d.y, d.x + d.width, d.y + d.height,
+                   t.x, t.y, t.x + t.width, t.y + t.height,
+                   false);
+    divisor /= 10;
+    ++aOffset;
+  }
+}
+
 void
-FPSState::DrawCounter(float offset,
-                      unsigned value,
-                      GLContext* context,
-                      ShaderProgramOGL* copyprog)
+FPSState::DrawFPS(TimeStamp aNow,
+                  unsigned int aFillRatio,
+                  GLContext* aContext,
+                  ShaderProgramOGL* aProgram)
 {
   if (!mTexture) {
     // Bind the number of textures we need, in this case one.
-    context->fGenTextures(1, &mTexture);
-    context->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
-    context->fTexParameteri(LOCAL_GL_TEXTURE_2D,LOCAL_GL_TEXTURE_MIN_FILTER,LOCAL_GL_NEAREST);
-    context->fTexParameteri(LOCAL_GL_TEXTURE_2D,LOCAL_GL_TEXTURE_MAG_FILTER,LOCAL_GL_NEAREST);
+    aContext->fGenTextures(1, &mTexture);
+    aContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
+    aContext->fTexParameteri(LOCAL_GL_TEXTURE_2D,LOCAL_GL_TEXTURE_MIN_FILTER,LOCAL_GL_NEAREST);
+    aContext->fTexParameteri(LOCAL_GL_TEXTURE_2D,LOCAL_GL_TEXTURE_MAG_FILTER,LOCAL_GL_NEAREST);
 
     const char *text =
       "                                         "
       " XXX XX  XXX XXX X X XXX XXX XXX XXX XXX "
       " X X  X    X   X X X X   X     X X X X X "
       " X X  X  XXX XXX XXX XXX XXX   X XXX XXX "
       " X X  X  X     X   X   X X X   X X X   X "
       " XXX XXX XXX XXX   X XXX XXX   X XXX   X "
@@ -131,102 +183,53 @@ FPSState::DrawCounter(float offset,
     uint32_t* buf = (uint32_t *) malloc(64 * 8 * sizeof(uint32_t));
     for (int i = 0; i < 7; i++) {
       for (int j = 0; j < 41; j++) {
         uint32_t purple = 0xfff000ff;
         uint32_t white  = 0xffffffff;
         buf[i * 64 + j] = (text[i * 41 + j] == ' ') ? purple : white;
       }
     }
-    context->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA, 64, 8, 0, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, buf);
+    aContext->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA, 64, 8, 0, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, buf);
     free(buf);
   }
 
-  GLint viewport[4];
-  context->fGetIntegerv(LOCAL_GL_VIEWPORT, viewport);
+  mVBOs.Reset();
 
-  struct Vertex2D {
-    float x,y;
-  };
-  float oneOverVP2 = 1.0 / viewport[2];
-  float oneOverVP3 = 1.0 / viewport[3];
-  const Vertex2D vertices[] = {
-    { -1.0f + (offset +  0.f) * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
-    { -1.0f + (offset +  0.f) * oneOverVP2, 1.0f},
-    { -1.0f + (offset + 22.f) * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
-    { -1.0f + (offset + 22.f) * oneOverVP2, 1.0f },
-
-    { -1.0f + (offset + 22.f) * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
-    { -1.0f + (offset + 22.f) * oneOverVP2, 1.0f },
-    { -1.0f + (offset + 44.f) * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
-    { -1.0f + (offset + 44.f) * oneOverVP2, 1.0f },
+  GLint viewport[4];
+  aContext->fGetIntegerv(LOCAL_GL_VIEWPORT, viewport);
+  gfx::IntSize viewportSize(viewport[2], viewport[3]);
 
-    { -1.0f + (offset + 44.f) * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
-    { -1.0f + (offset + 44.f) * oneOverVP2, 1.0f },
-    { -1.0f + (offset + 66.f) * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
-    { -1.0f + (offset + 66.f) * oneOverVP2, 1.0f }
-  };
-
-  unsigned v1   = value % 10;
-  unsigned v10  = (value % 100) / 10;
-  unsigned v100 = (value % 1000) / 100;
+  unsigned int fps = unsigned(mCompositionFps.AddFrameAndGetFps(aNow));
+  unsigned int txnFps = unsigned(mTransactionFps.GetFpsAt(aNow));
 
-  const GLfloat texCoords[] = {
-    (v100 * 4.f) / 64, 7.f / 8,
-    (v100 * 4.f) / 64, 0.0f,
-    (v100 * 4.f + 4) / 64, 7.f / 8,
-    (v100 * 4.f + 4) / 64, 0.0f,
-
-    (v10 * 4.f) / 64, 7.f / 8,
-    (v10 * 4.f) / 64, 0.0f,
-    (v10 * 4.f + 4) / 64, 7.f / 8,
-    (v10 * 4.f + 4) / 64, 0.0f,
-
-    (v1 * 4.f) / 64, 7.f / 8,
-    (v1 * 4.f) / 64, 0.0f,
-    (v1 * 4.f + 4) / 64, 7.f / 8,
-    (v1 * 4.f + 4) / 64, 0.0f,
-  };
+  GLContext::RectTriangles rects;
+  AddDigits(rects, viewportSize, 0, fps);
+  AddDigits(rects, viewportSize, 4, txnFps);
+  AddDigits(rects, viewportSize, 8, aFillRatio);
 
   // Turn necessary features on
-  context->fEnable(LOCAL_GL_BLEND);
-  context->fBlendFunc(LOCAL_GL_ONE, LOCAL_GL_SRC_COLOR);
-
-  context->fActiveTexture(LOCAL_GL_TEXTURE0);
-  context->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
+  aContext->fEnable(LOCAL_GL_BLEND);
+  aContext->fBlendFunc(LOCAL_GL_ONE, LOCAL_GL_SRC_COLOR);
 
-  copyprog->Activate();
-  copyprog->SetTextureUnit(0);
-
-  // "COPY"
-  context->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ZERO,
-                              LOCAL_GL_ONE, LOCAL_GL_ZERO);
-
-  GLint vcattr = copyprog->AttribLocation(ShaderProgramOGL::VertexCoordAttrib);
-  GLint tcattr = copyprog->AttribLocation(ShaderProgramOGL::TexCoordAttrib);
+  aContext->fActiveTexture(LOCAL_GL_TEXTURE0);
+  aContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
 
-  DrawWithVertexBuffer2(context, mVBOs,
-                        LOCAL_GL_TRIANGLE_STRIP, 12,
-                        vcattr, (GLfloat *) vertices,
-                        tcattr, (GLfloat *) texCoords);
-}
+  aProgram->Activate();
+  aProgram->SetTextureUnit(0);
+  aProgram->SetLayerQuadRect(gfx::Rect(0.f, 0.f, viewport[2], viewport[3]));
+  aProgram->SetLayerOpacity(1.f);
+  aProgram->SetTextureTransform(gfx3DMatrix());
+  aProgram->SetLayerTransform(gfx3DMatrix());
+  aProgram->SetRenderOffset(0, 0);
 
-void
-FPSState::DrawFPS(TimeStamp aNow,
-                  unsigned aFillRatio,
-                  GLContext* context, ShaderProgramOGL* copyprog)
-{
-  mVBOs.Reset();
+  aContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ZERO,
+                               LOCAL_GL_ONE, LOCAL_GL_ZERO);
 
-  unsigned fps = unsigned(mCompositionFps.AddFrameAndGetFps(aNow));
-  unsigned txnFps = unsigned(mTransactionFps.GetFpsAt(aNow));
-
-  DrawCounter(0, fps, context, copyprog);
-  DrawCounter(80, txnFps, context, copyprog);
-  DrawCounter(160, aFillRatio, context, copyprog);
+  DrawQuads(aContext, mVBOs, aProgram, rects);
 }
 
 #ifdef CHECK_CURRENT_PROGRAM
 int ShaderProgramOGL::sCurrentProgramKey = 0;
 #endif
 
 CompositorOGL::CompositorOGL(nsIWidget *aWidget, int aSurfaceWidth,
                              int aSurfaceHeight, bool aUseExternalSurfaceSize)
@@ -285,17 +288,17 @@ CompositorOGL::AddPrograms(ShaderProgram
 GLuint
 CompositorOGL::GetTemporaryTexture(GLenum aTextureUnit)
 {
   size_t index = aTextureUnit - LOCAL_GL_TEXTURE0;
   // lazily grow the array of temporary textures
   if (mTextures.Length() <= index) {
     size_t prevLength = mTextures.Length();
     mTextures.SetLength(index + 1);
-    for(unsigned i = prevLength; i <= index; ++i) {
+    for(unsigned int i = prevLength; i <= index; ++i) {
       mTextures[i] = 0;
     }
   }
   // lazily initialize the temporary textures
   if (!mTextures[index]) {
     gl()->MakeCurrent();
     gl()->fGenTextures(1, &mTextures[index]);
   }
@@ -539,30 +542,23 @@ CompositorOGL::Initialize()
   return true;
 }
 
 // |aTexCoordRect| is the rectangle from the texture that we want to
 // draw using the given program.  The program already has a necessary
 // offset and scale, so the geometry that needs to be drawn is a unit
 // square from 0,0 to 1,1.
 //
-// |aTexSize| is the actual size of the texture, as it can be larger
-// than the rectangle given by |aTexCoordRect|.
+// |aTexture| is the texture we are drawing. Its actual size can be
+// larger than the rectangle given by |aTexCoordRect|.
 void
 CompositorOGL::BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg,
                                               const Rect& aTexCoordRect,
                                               TextureSource *aTexture)
 {
-  NS_ASSERTION(aProg->HasInitialized(), "Shader program not correctly initialized");
-  GLuint vertAttribIndex =
-    aProg->AttribLocation(ShaderProgramOGL::VertexCoordAttrib);
-  GLuint texCoordAttribIndex =
-    aProg->AttribLocation(ShaderProgramOGL::TexCoordAttrib);
-  NS_ASSERTION(texCoordAttribIndex != GLuint(-1), "no texture coords?");
-
   // Given what we know about these textures and coordinates, we can
   // compute fmod(t, 1.0f) to get the same texture coordinate out.  If
   // the texCoordRect dimension is < 0 or > width/height, then we have
   // wraparound that we need to deal with by drawing multiple quads,
   // because we can't rely on full non-power-of-two texture support
   // (which is required for the REPEAT wrap mode).
 
   GLContext::RectTriangles rects;
@@ -606,20 +602,17 @@ CompositorOGL::BindAndDrawQuadWithTextur
   } else {
     nsIntRect tcRect(texCoordRect.x, texCoordRect.y,
                      texCoordRect.width, texCoordRect.height);
     GLContext::DecomposeIntoNoRepeatTriangles(tcRect,
                                               nsIntSize(realTexSize.width, realTexSize.height),
                                               rects, flipped);
   }
 
-  DrawWithVertexBuffer2(mGLContext, mVBOs,
-                        LOCAL_GL_TRIANGLES, rects.elements(),
-                        vertAttribIndex, rects.vertexPointer(),
-                        texCoordAttribIndex, rects.texCoordPointer());
+  DrawQuads(mGLContext, mVBOs, aProg, rects);
 }
 
 void
 CompositorOGL::PrepareViewport(const gfx::IntSize& aSize,
                                const gfxMatrix& aWorldTransform)
 {
   // Set the viewport correctly.
   mGLContext->fViewport(0, 0, aSize.width, aSize.height);
@@ -1305,17 +1298,17 @@ CompositorOGL::EndFrame()
 
   if (mFPS) {
     float fillRatio = 0;
     if (mPixelsFilled > 0 && mPixelsPerFrame > 0) {
       fillRatio = 100.0f * float(mPixelsFilled) / float(mPixelsPerFrame);
       if (fillRatio > 999.0f)
         fillRatio = 999.0f;
     }
-    mFPS->DrawFPS(TimeStamp::Now(), unsigned(fillRatio), mGLContext, GetProgram(Copy2DProgramType));
+    mFPS->DrawFPS(TimeStamp::Now(), unsigned(fillRatio), mGLContext, GetProgram(RGBXLayerProgramType));
   }
 
   mGLContext->SwapBuffers();
   mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
 }
 
 void
 CompositorOGL::EndFrameForExternalComposition(const gfxMatrix& aTransform)
--- a/gfx/layers/opengl/FPSCounter.h
+++ b/gfx/layers/opengl/FPSCounter.h
@@ -70,17 +70,16 @@ private:
 struct FPSState {
   GLuint mTexture;
   FPSCounter mCompositionFps;
   FPSCounter mTransactionFps;
   gl::VBOArena mVBOs;
 
   FPSState() : mTexture(0) { }
 
-  void DrawCounter(float, unsigned, gl::GLContext*, ShaderProgramOGL*);
   void DrawFPS(TimeStamp, unsigned, gl::GLContext*, ShaderProgramOGL*);
 
   void NotifyShadowTreeTransaction() {
     mTransactionFps.AddFrame(TimeStamp::Now());
   }
 };
 
 }