| // | |
| // Copyright 2017 The ANGLE Project Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| // | |
| // params: | |
| // Parameter wrapper structs for OpenGL ES. These helpers cache re-used values | |
| // in entry point routines. | |
| #include "libANGLE/params.h" | |
| #include "common/utilities.h" | |
| #include "libANGLE/Context.h" | |
| #include "libANGLE/VertexArray.h" | |
| namespace gl | |
| { | |
| // static | |
| constexpr ParamTypeInfo ParamsBase::TypeInfo; | |
| constexpr ParamTypeInfo DrawCallParams::TypeInfo; | |
| // DrawCallParams implementation. | |
| // Called by DrawArrays. | |
| DrawCallParams::DrawCallParams(PrimitiveMode mode, | |
| GLint firstVertex, | |
| GLsizei vertexCount, | |
| GLsizei instances) | |
| : mMode(mode), | |
| mFirstVertex(firstVertex), | |
| mVertexCount(vertexCount), | |
| mIndexCount(0), | |
| mBaseVertex(0), | |
| mType(GL_NONE), | |
| mIndices(nullptr), | |
| mInstances(instances), | |
| mIndirect(nullptr) | |
| { | |
| } | |
| // Called by DrawElements. | |
| DrawCallParams::DrawCallParams(PrimitiveMode mode, | |
| GLint indexCount, | |
| GLenum type, | |
| const void *indices, | |
| GLint baseVertex, | |
| GLsizei instances) | |
| : mMode(mode), | |
| mFirstVertex(0), | |
| mVertexCount(0), | |
| mIndexCount(indexCount), | |
| mBaseVertex(baseVertex), | |
| mType(type), | |
| mIndices(indices), | |
| mInstances(instances), | |
| mIndirect(nullptr) | |
| { | |
| } | |
| // Called by DrawArraysIndirect. | |
| DrawCallParams::DrawCallParams(PrimitiveMode mode, const void *indirect) | |
| : mMode(mode), | |
| mFirstVertex(0), | |
| mVertexCount(0), | |
| mIndexCount(0), | |
| mBaseVertex(0), | |
| mType(GL_NONE), | |
| mIndices(nullptr), | |
| mInstances(0), | |
| mIndirect(indirect) | |
| { | |
| } | |
| // Called by DrawElementsIndirect. | |
| DrawCallParams::DrawCallParams(PrimitiveMode mode, GLenum type, const void *indirect) | |
| : mMode(mode), | |
| mFirstVertex(0), | |
| mVertexCount(0), | |
| mIndexCount(0), | |
| mBaseVertex(0), | |
| mType(type), | |
| mIndices(nullptr), | |
| mInstances(0), | |
| mIndirect(indirect) | |
| { | |
| } | |
| GLsizei DrawCallParams::indexCount() const | |
| { | |
| ASSERT(isDrawElements()); | |
| return mIndexCount; | |
| } | |
| GLint DrawCallParams::baseVertex() const | |
| { | |
| return mBaseVertex; | |
| } | |
| GLenum DrawCallParams::type() const | |
| { | |
| ASSERT(isDrawElements()); | |
| return mType; | |
| } | |
| const void *DrawCallParams::indices() const | |
| { | |
| return mIndices; | |
| } | |
| GLsizei DrawCallParams::instances() const | |
| { | |
| return mInstances; | |
| } | |
| const void *DrawCallParams::indirect() const | |
| { | |
| return mIndirect; | |
| } | |
| bool DrawCallParams::isDrawIndirect() const | |
| { | |
| // This is a bit of a hack - it's quite possible for a direct call to have a zero count, but we | |
| // assume these calls are filtered out before they make it to this code. | |
| return (mIndexCount == 0 && mVertexCount == 0); | |
| } | |
| Error DrawCallParams::ensureIndexRangeResolved(const Context *context) const | |
| { | |
| if (mIndexRange.valid() || !isDrawElements()) | |
| { | |
| return NoError(); | |
| } | |
| const State &state = context->getGLState(); | |
| const gl::VertexArray *vao = state.getVertexArray(); | |
| gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get(); | |
| if (elementArrayBuffer) | |
| { | |
| uintptr_t offset = reinterpret_cast<uintptr_t>(mIndices); | |
| IndexRange indexRange; | |
| ANGLE_TRY(elementArrayBuffer->getIndexRange(context, mType, static_cast<size_t>(offset), | |
| mIndexCount, state.isPrimitiveRestartEnabled(), | |
| &indexRange)); | |
| mIndexRange = indexRange; | |
| } | |
| else | |
| { | |
| mIndexRange = | |
| ComputeIndexRange(mType, mIndices, mIndexCount, state.isPrimitiveRestartEnabled()); | |
| } | |
| const IndexRange &indexRange = mIndexRange.value(); | |
| // 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()); | |
| // 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>(mBaseVertex) + 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" | |
| if (startVertexInt64 < 0) | |
| { | |
| return gl::InternalError() << "Negative index value."; | |
| } | |
| // 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. | |
| if (startVertexInt64 > std::numeric_limits<GLint>::max()) | |
| { | |
| return gl::InternalError() << "Negative value overflow."; | |
| } | |
| mFirstVertex = static_cast<GLint>(startVertexInt64); | |
| mVertexCount = indexRange.vertexCount(); | |
| return NoError(); | |
| } | |
| const IndexRange &DrawCallParams::getIndexRange() const | |
| { | |
| ASSERT(isDrawElements() && mIndexRange.valid()); | |
| return mIndexRange.value(); | |
| } | |
| } // namespace gl |