Move index range calculations into VertexArray.

This is in preparation for removing the entire DrawCallParams struct.
This struct was big enough to cause a performance hit on draw call perf
tests just by virtue of initializing the fields. Also dereferencing the
struct members is slower than reading function parameters since it adds
an indirection.

Also includes some error refactoring to enable moving code to a shared
location.

In total this patch series reduces overhead by up to 5%.

Bug: angleproject:2933
Change-Id: Ib663f2538c14ac30d4c31fd10d6350be469626e2
Reviewed-on: https://chromium-review.googlesource.com/c/1298380
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/renderer/renderer_utils.cpp b/src/libANGLE/renderer/renderer_utils.cpp
index 23b6876..005ebf2 100644
--- a/src/libANGLE/renderer/renderer_utils.cpp
+++ b/src/libANGLE/renderer/renderer_utils.cpp
@@ -556,4 +556,60 @@
     angle::FormatID angleFormatID = angle::Format::InternalFormatToID(sizedInternalFormat);
     return angle::Format::Get(angleFormatID);
 }
+
+angle::Result ComputeStartVertex(ContextImpl *contextImpl,
+                                 const gl::IndexRange &indexRange,
+                                 GLint baseVertex,
+                                 GLint *firstVertexOut)
+{
+    // The entire index range should be within the limits of a 32-bit uint because the largest
+    // GL index type is GL_UNSIGNED_INT.
+    ASSERT(indexRange.start <= std::numeric_limits<uint32_t>::max() &&
+           indexRange.end <= std::numeric_limits<uint32_t>::max());
+
+    // The base vertex is only used in DrawElementsIndirect. Given the assertion above and the
+    // type of mBaseVertex (GLint), adding them both as 64-bit ints is safe.
+    int64_t startVertexInt64 =
+        static_cast<int64_t>(baseVertex) + static_cast<int64_t>(indexRange.start);
+
+    // OpenGL ES 3.2 spec section 10.5: "Behavior of DrawElementsOneInstance is undefined if the
+    // vertex ID is negative for any element"
+    ANGLE_CHECK_GL_MATH(contextImpl, startVertexInt64 >= 0);
+
+    // OpenGL ES 3.2 spec section 10.5: "If the vertex ID is larger than the maximum value
+    // representable by type, it should behave as if the calculation were upconverted to 32-bit
+    // unsigned integers(with wrapping on overflow conditions)." ANGLE does not fully handle
+    // these rules, an overflow error is returned if the start vertex cannot be stored in a
+    // 32-bit signed integer.
+    ANGLE_CHECK_GL_MATH(contextImpl, startVertexInt64 <= std::numeric_limits<GLint>::max())
+
+    *firstVertexOut = static_cast<GLint>(startVertexInt64);
+    return angle::Result::Continue();
+}
+
+angle::Result GetVertexRangeInfo(const gl::Context *context,
+                                 GLint firstVertex,
+                                 GLsizei vertexOrIndexCount,
+                                 GLenum indexTypeOrNone,
+                                 const void *indices,
+                                 GLint baseVertex,
+                                 GLint *startVertexOut,
+                                 size_t *vertexCountOut)
+{
+    if (indexTypeOrNone != GL_NONE)
+    {
+        gl::IndexRange indexRange;
+        ANGLE_TRY(context->getGLState().getVertexArray()->getIndexRange(
+            context, indexTypeOrNone, vertexOrIndexCount, indices, &indexRange));
+        ANGLE_TRY(ComputeStartVertex(context->getImplementation(), indexRange, baseVertex,
+                                     startVertexOut));
+        *vertexCountOut = indexRange.vertexCount();
+    }
+    else
+    {
+        *startVertexOut = firstVertex;
+        *vertexCountOut = vertexOrIndexCount;
+    }
+    return angle::Result::Continue();
+}
 }  // namespace rx