OSDN Git Service

Reduce hwui CPU time by using glDrawRangeElements
authorArun <arun.demeure@imgtec.com>
Mon, 23 Jan 2017 11:41:06 +0000 (11:41 +0000)
committerJohn Reck <jreck@google.com>
Fri, 5 May 2017 15:11:27 +0000 (15:11 +0000)
The CPU overhead of glDrawElements in the GPU driver is significant
with client-side vertex data (unique per draw call) as the driver has
to calculate the mininimum and maximum indices from the index buffer
in order to evaluate the range of vertex data required. This can be
avoided by keeping track of the min-max in hwui and passing it with
glDrawRangeElements. This requires OpenGL ES3.0 support (which is
already checked for elsewhere in hwui).

Test: manual - visual inspection on fugu (nexus player)

Change-Id: I57bb1ddd239a1032f74f1cd2683bbe0970e84bd9

libs/hwui/Glop.h
libs/hwui/GlopBuilder.cpp
libs/hwui/renderstate/RenderState.cpp

index 6433c86..b95fd63 100644 (file)
@@ -112,6 +112,7 @@ public:
         } vertices;
 
         int elementCount;
+        int vertexCount; // only used for meshes (for glDrawRangeElements)
         TextureVertex mappedVertices[4];
     } mesh;
 
index e502725..8fcd1ea 100644 (file)
@@ -210,6 +210,7 @@ GlopBuilder& GlopBuilder::setMeshVertexBuffer(const VertexBuffer& vertexBuffer)
             alphaVertex ? kAlphaVertexStride : kVertexStride };
     mOutGlop->mesh.elementCount = indices
                 ? vertexBuffer.getIndexCount() : vertexBuffer.getVertexCount();
+    mOutGlop->mesh.vertexCount = vertexBuffer.getVertexCount(); // used for glDrawRangeElements()
     return *this;
 }
 
index 5e60064..c4e8e4f 100644 (file)
@@ -364,18 +364,28 @@ void RenderState::render(const Glop& glop, const Matrix4& orthoMatrix) {
         const GLbyte* vertexData = static_cast<const GLbyte*>(vertices.position);
         while (elementsCount > 0) {
             GLsizei drawCount = std::min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6);
+            GLsizei vertexCount = (drawCount / 6) * 4;
             meshState().bindPositionVertexPointer(vertexData, vertices.stride);
             if (vertices.attribFlags & VertexAttribFlags::TextureCoord) {
                 meshState().bindTexCoordsVertexPointer(
                         vertexData + kMeshTextureOffset, vertices.stride);
             }
 
-            glDrawElements(mesh.primitiveMode, drawCount, GL_UNSIGNED_SHORT, nullptr);
+            if (mCaches->extensions().getMajorGlVersion() >= 3) {
+                glDrawRangeElements(mesh.primitiveMode, 0, vertexCount-1, drawCount, GL_UNSIGNED_SHORT, nullptr);
+            } else {
+                glDrawElements(mesh.primitiveMode, drawCount, GL_UNSIGNED_SHORT, nullptr);
+            }
             elementsCount -= drawCount;
-            vertexData += (drawCount / 6) * 4 * vertices.stride;
+            vertexData += vertexCount * vertices.stride;
         }
     } else if (indices.bufferObject || indices.indices) {
-        glDrawElements(mesh.primitiveMode, mesh.elementCount, GL_UNSIGNED_SHORT, indices.indices);
+        if (mCaches->extensions().getMajorGlVersion() >= 3) {
+            // use glDrawRangeElements to reduce CPU overhead (otherwise the driver has to determine the min/max index values)
+            glDrawRangeElements(mesh.primitiveMode, 0, mesh.vertexCount-1, mesh.elementCount, GL_UNSIGNED_SHORT, indices.indices);
+        } else {
+            glDrawElements(mesh.primitiveMode, mesh.elementCount, GL_UNSIGNED_SHORT, indices.indices);
+        }
     } else {
         glDrawArrays(mesh.primitiveMode, 0, mesh.elementCount);
     }