Commit 9c9b40ac by Jamie Madill Committed by Commit Bot

Use parameter cache to skip passing IndexRange.

For DrawElements et al., we can use a simple design to store entry point parameters and compute index ranges lazily. This allows us to compute the index range outside of the validation layer. Fixing this will let us implement a few things, such as the no error extension. It will also allow auto-generation of the entry points, since we won't have to have special cases for certain entry points. It will also help fix the syncState layering problem. Now the cached parameter helper (which is owned by the Context) can make the impl layer calls, instead of the validation layer calling the impl directly. We use a small array in Context to gather parameters in a generic way without reallocation on call. We also check type safety by storing a type info struct which can handle inheritance between type classes. Optional variables for the cache determine when to re-compute values. The intent with gatherParams is to call this in every entry point, and have in most cases be a no-op. In some cases like for IndexRange, we store some parameters for later use. The inheritance scheme enables auto-generation of the entry points by keeping signatures similar. BUG=angleproject:747 Change-Id: I871e99e1334cf6e61ef8da62fde3ced094903f8a Reviewed-on: https://chromium-review.googlesource.com/474119 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 25e297e9
...@@ -6,7 +6,7 @@ vars = { ...@@ -6,7 +6,7 @@ vars = {
deps = { deps = {
'buildtools': 'buildtools':
Var('chromium_git') + '/chromium/buildtools.git' + '@' + '39b1db2ab4aa4b2ccaa263c29bdf63e7c1ee28aa', Var('chromium_git') + '/chromium/buildtools.git' + '@' + '98f00fa10dbad2cdbb2e297a66c3d6d5bc3994f3',
'testing/gmock': 'testing/gmock':
Var('chromium_git') + '/external/googlemock.git' + '@' + '0421b6f358139f02e102c9c332ce19a33faf75be', # from svn revision 566 Var('chromium_git') + '/external/googlemock.git' + '@' + '0421b6f358139f02e102c9c332ce19a33faf75be', # from svn revision 566
......
...@@ -76,6 +76,14 @@ uint8_t *MemoryBuffer::data() ...@@ -76,6 +76,14 @@ uint8_t *MemoryBuffer::data()
return mData; return mData;
} }
void MemoryBuffer::fill(uint8_t datum)
{
if (!empty())
{
std::fill(mData, mData + mSize, datum);
}
}
// ScratchBuffer implementation. // ScratchBuffer implementation.
ScratchBuffer::ScratchBuffer(uint32_t lifetime) : mLifetime(lifetime), mResetCounter(lifetime) ScratchBuffer::ScratchBuffer(uint32_t lifetime) : mLifetime(lifetime), mResetCounter(lifetime)
......
...@@ -28,6 +28,8 @@ class MemoryBuffer final : NonCopyable ...@@ -28,6 +28,8 @@ class MemoryBuffer final : NonCopyable
const uint8_t *data() const; const uint8_t *data() const;
uint8_t *data(); uint8_t *data();
void fill(uint8_t datum);
private: private:
size_t mSize; size_t mSize;
uint8_t *mData; uint8_t *mData;
......
...@@ -1772,13 +1772,10 @@ void Context::drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsiz ...@@ -1772,13 +1772,10 @@ void Context::drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsiz
} }
} }
void Context::drawElements(GLenum mode, void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)
GLsizei count,
GLenum type,
const GLvoid *indices,
const IndexRange &indexRange)
{ {
syncRendererState(); syncRendererState();
const IndexRange &indexRange = getParams<HasIndexRange>().getIndexRange().value();
handleError(mImplementation->drawElements(mode, count, type, indices, indexRange)); handleError(mImplementation->drawElements(mode, count, type, indices, indexRange));
} }
...@@ -1786,10 +1783,10 @@ void Context::drawElementsInstanced(GLenum mode, ...@@ -1786,10 +1783,10 @@ void Context::drawElementsInstanced(GLenum mode,
GLsizei count, GLsizei count,
GLenum type, GLenum type,
const GLvoid *indices, const GLvoid *indices,
GLsizei instances, GLsizei instances)
const IndexRange &indexRange)
{ {
syncRendererState(); syncRendererState();
const IndexRange &indexRange = getParams<HasIndexRange>().getIndexRange().value();
handleError( handleError(
mImplementation->drawElementsInstanced(mode, count, type, indices, instances, indexRange)); mImplementation->drawElementsInstanced(mode, count, type, indices, instances, indexRange));
} }
...@@ -1799,10 +1796,10 @@ void Context::drawRangeElements(GLenum mode, ...@@ -1799,10 +1796,10 @@ void Context::drawRangeElements(GLenum mode,
GLuint end, GLuint end,
GLsizei count, GLsizei count,
GLenum type, GLenum type,
const GLvoid *indices, const GLvoid *indices)
const IndexRange &indexRange)
{ {
syncRendererState(); syncRendererState();
const IndexRange &indexRange = getParams<HasIndexRange>().getIndexRange().value();
handleError( handleError(
mImplementation->drawRangeElements(mode, start, end, count, type, indices, indexRange)); mImplementation->drawRangeElements(mode, start, end, count, type, indices, indexRange));
} }
......
...@@ -347,24 +347,18 @@ class Context final : public ValidationContext ...@@ -347,24 +347,18 @@ class Context final : public ValidationContext
void drawArrays(GLenum mode, GLint first, GLsizei count); void drawArrays(GLenum mode, GLint first, GLsizei count);
void drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount); void drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount);
void drawElements(GLenum mode, void drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
GLsizei count,
GLenum type,
const GLvoid *indices,
const IndexRange &indexRange);
void drawElementsInstanced(GLenum mode, void drawElementsInstanced(GLenum mode,
GLsizei count, GLsizei count,
GLenum type, GLenum type,
const GLvoid *indices, const GLvoid *indices,
GLsizei instances, GLsizei instances);
const IndexRange &indexRange);
void drawRangeElements(GLenum mode, void drawRangeElements(GLenum mode,
GLuint start, GLuint start,
GLuint end, GLuint end,
GLsizei count, GLsizei count,
GLenum type, GLenum type,
const GLvoid *indices, const GLvoid *indices);
const IndexRange &indexRange);
void drawArraysIndirect(GLenum mode, const GLvoid *indirect); void drawArraysIndirect(GLenum mode, const GLvoid *indirect);
void drawElementsIndirect(GLenum mode, GLenum type, const GLvoid *indirect); void drawElementsIndirect(GLenum mode, GLenum type, const GLvoid *indirect);
...@@ -783,6 +777,9 @@ class Context final : public ValidationContext ...@@ -783,6 +777,9 @@ class Context final : public ValidationContext
void dispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ); void dispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ);
template <EntryPoint EP, typename... ParamsT>
void gatherParams(ParamsT &&... params);
private: private:
void syncRendererState(); void syncRendererState();
void syncRendererState(const State::DirtyBits &bitMask, const State::DirtyObjects &objectMask); void syncRendererState(const State::DirtyBits &bitMask, const State::DirtyObjects &objectMask);
...@@ -880,6 +877,25 @@ class Context final : public ValidationContext ...@@ -880,6 +877,25 @@ class Context final : public ValidationContext
mutable angle::ScratchBuffer mScratchBuffer; mutable angle::ScratchBuffer mScratchBuffer;
}; };
template <EntryPoint EP, typename... ArgsT>
void Context::gatherParams(ArgsT &&... args)
{
static_assert(sizeof(EntryPointParamType<EP>) <= kParamsBufferSize,
"Params struct too large, please increase kParamsBufferSize.");
mSavedArgsType = &EntryPointParamType<EP>::TypeInfo;
// Skip doing any work for ParamsBase/Invalid type.
if (!EntryPointParamType<EP>::TypeInfo.isValid())
{
return;
}
EntryPointParamType<EP> *objBuffer =
reinterpret_cast<EntryPointParamType<EP> *>(mParamsBuffer.data());
EntryPointParamType<EP>::template Factory<EP>(objBuffer, this, std::forward<ArgsT>(args)...);
}
} // namespace gl } // namespace gl
#endif // LIBANGLE_CONTEXT_H_ #endif // LIBANGLE_CONTEXT_H_
...@@ -9,9 +9,11 @@ ...@@ -9,9 +9,11 @@
#ifndef LIBANGLE_CONTEXTSTATE_H_ #ifndef LIBANGLE_CONTEXTSTATE_H_
#define LIBANGLE_CONTEXTSTATE_H_ #define LIBANGLE_CONTEXTSTATE_H_
#include "common/MemoryBuffer.h"
#include "common/angleutils.h" #include "common/angleutils.h"
#include "libANGLE/State.h" #include "libANGLE/State.h"
#include "libANGLE/Version.h" #include "libANGLE/Version.h"
#include "libANGLE/params.h"
namespace gl namespace gl
{ {
...@@ -130,11 +132,28 @@ class ValidationContext : angle::NonCopyable ...@@ -130,11 +132,28 @@ class ValidationContext : angle::NonCopyable
bool isWebGL1() const { return mState.isWebGL1(); } bool isWebGL1() const { return mState.isWebGL1(); }
template <typename T>
const T &getParams() const;
protected: protected:
ContextState mState; ContextState mState;
bool mSkipValidation; bool mSkipValidation;
bool mDisplayTextureShareGroup; bool mDisplayTextureShareGroup;
// Caches entry point parameters and values re-used between layers.
mutable const ParamTypeInfo *mSavedArgsType;
static constexpr size_t kParamsBufferSize = 64u;
mutable std::array<uint8_t, kParamsBufferSize> mParamsBuffer;
}; };
template <typename T>
const T &ValidationContext::getParams() const
{
const T *params = reinterpret_cast<T *>(mParamsBuffer.data());
ASSERT(mSavedArgsType->hasDynamicType(T::TypeInfo));
return *params;
}
} // namespace gl } // namespace gl
#endif // LIBANGLE_CONTEXTSTATE_H_ #endif // LIBANGLE_CONTEXTSTATE_H_
//
// 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
{
#if defined(ANGLE_ENABLE_ASSERTS)
// static
constexpr ParamTypeInfo ParamsBase::TypeInfo;
constexpr ParamTypeInfo HasIndexRange::TypeInfo;
#endif // defined(ANGLE_ENABLE_ASSERTS)
ParamsBase::ParamsBase(Context *context, ...)
{
}
HasIndexRange::HasIndexRange(Context *context, GLsizei count, GLenum type, const void *indices)
: ParamsBase(context), mContext(context), mCount(count), mType(type), mIndices(indices)
{
}
const Optional<IndexRange> &HasIndexRange::getIndexRange() const
{
if (mIndexRange.valid())
{
return mIndexRange;
}
const State &state = mContext->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;
Error error =
elementArrayBuffer->getIndexRange(mType, static_cast<size_t>(offset), mCount,
state.isPrimitiveRestartEnabled(), &indexRange);
if (error.isError())
{
mContext->handleError(error);
return mIndexRange;
}
mIndexRange = indexRange;
}
else
{
mIndexRange = ComputeIndexRange(mType, mIndices, mCount, state.isPrimitiveRestartEnabled());
}
return mIndexRange;
}
} // namespace gl
//
// 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.
#ifndef LIBANGLE_PARAMS_H_
#define LIBANGLE_PARAMS_H_
#include "angle_gl.h"
#include "common/Optional.h"
#include "common/angleutils.h"
#include "common/mathutil.h"
namespace gl
{
class Context;
enum class EntryPoint
{
Invalid,
DrawArrays,
DrawElements,
DrawElementsInstanced,
DrawElementsInstancedANGLE,
DrawRangeElements,
};
template <EntryPoint EP>
struct EntryPointParam;
template <EntryPoint EP>
using EntryPointParamType = typename EntryPointParam<EP>::Type;
class ParamTypeInfo
{
public:
constexpr ParamTypeInfo(const char *selfClass, const ParamTypeInfo *parentType)
: mSelfClass(selfClass), mParentTypeInfo(parentType)
{
}
constexpr bool hasDynamicType(const ParamTypeInfo &typeInfo) const
{
return mSelfClass == typeInfo.mSelfClass ||
(mParentTypeInfo && mParentTypeInfo->hasDynamicType(typeInfo));
}
constexpr bool isValid() const { return mSelfClass != nullptr; }
private:
const char *mSelfClass;
const ParamTypeInfo *mParentTypeInfo;
};
#if defined(ANGLE_ENABLE_ASSERTS)
#define ANGLE_PARAM_TYPE_INFO(NAME, BASENAME) \
static constexpr ParamTypeInfo TypeInfo = {#NAME, &BASENAME::TypeInfo}
#else
#define ANGLE_PARAM_TYPE_INFO(NAME, BASENAME)
#endif // defined(ANGLE_ENABLE_ASSERTS)
class ParamsBase : angle::NonCopyable
{
public:
ParamsBase(Context *context, ...);
template <EntryPoint EP, typename... ArgsT>
static void Factory(EntryPointParamType<EP> *objBuffer, ArgsT... args);
#if defined(ANGLE_ENABLE_ASSERTS)
static constexpr ParamTypeInfo TypeInfo = {nullptr, nullptr};
#endif // defined(ANGLE_ENABLE_ASSERTS)
};
// static
template <EntryPoint EP, typename... ArgsT>
void ParamsBase::Factory(EntryPointParamType<EP> *objBuffer, ArgsT... args)
{
new (objBuffer) EntryPointParamType<EP>(args...);
}
class HasIndexRange : public ParamsBase
{
public:
HasIndexRange(Context *context, GLsizei count, GLenum type, const void *indices);
template <EntryPoint EP, typename... ArgsT>
static void Factory(HasIndexRange *objBuffer, ArgsT... args);
const Optional<IndexRange> &getIndexRange() const;
ANGLE_PARAM_TYPE_INFO(HasIndexRange, ParamsBase);
private:
Context *mContext;
GLsizei mCount;
GLenum mType;
const GLvoid *mIndices;
mutable Optional<IndexRange> mIndexRange;
};
// Entry point funcs essentially re-map different entry point parameter arrays into
// the format the parameter type class expects. For example, for HasIndexRange, for the
// various indexed draw calls, they drop parameters that aren't useful and re-arrange
// the rest.
#define ANGLE_ENTRY_POINT_FUNC(NAME, CLASS, ...) \
\
template<> struct EntryPointParam<EntryPoint::NAME> \
{ \
using Type = CLASS; \
}; \
\
template<> inline void CLASS::Factory<EntryPoint::NAME>(__VA_ARGS__)
ANGLE_ENTRY_POINT_FUNC(DrawElements,
HasIndexRange,
HasIndexRange *objBuffer,
Context *context,
GLenum /*mode*/,
GLsizei count,
GLenum type,
const void *indices)
{
return ParamsBase::Factory<EntryPoint::DrawElements>(objBuffer, context, count, type, indices);
}
ANGLE_ENTRY_POINT_FUNC(DrawElementsInstanced,
HasIndexRange,
HasIndexRange *objBuffer,
Context *context,
GLenum /*mode*/,
GLsizei count,
GLenum type,
const void *indices,
GLsizei /*instanceCount*/)
{
return ParamsBase::Factory<EntryPoint::DrawElementsInstanced>(objBuffer, context, count, type,
indices);
}
ANGLE_ENTRY_POINT_FUNC(DrawElementsInstancedANGLE,
HasIndexRange,
HasIndexRange *objBuffer,
Context *context,
GLenum /*mode*/,
GLsizei count,
GLenum type,
const void *indices,
GLsizei /*instanceCount*/)
{
return ParamsBase::Factory<EntryPoint::DrawElementsInstancedANGLE>(objBuffer, context, count,
type, indices);
}
ANGLE_ENTRY_POINT_FUNC(DrawRangeElements,
HasIndexRange,
HasIndexRange *objBuffer,
Context *context,
GLenum /*mode*/,
GLuint /*start*/,
GLuint /*end*/,
GLsizei count,
GLenum type,
const void *indices)
{
return ParamsBase::Factory<EntryPoint::DrawRangeElements>(objBuffer, context, count, type,
indices);
}
#undef ANGLE_ENTRY_POINT_FUNC
template <EntryPoint EP>
struct EntryPointParam
{
using Type = ParamsBase;
};
} // namespace gl
#endif // LIBANGLE_PARAMS_H_
...@@ -1820,13 +1820,12 @@ bool ValidateES2CopyTexImageParameters(ValidationContext *context, ...@@ -1820,13 +1820,12 @@ bool ValidateES2CopyTexImageParameters(ValidationContext *context,
return (width > 0 && height > 0); return (width > 0 && height > 0);
} }
bool ValidateDrawElementsInstancedBase(Context *context, bool ValidateDrawElementsInstancedBase(ValidationContext *context,
GLenum mode, GLenum mode,
GLsizei count, GLsizei count,
GLenum type, GLenum type,
const GLvoid *indices, const GLvoid *indices,
GLsizei primcount, GLsizei primcount)
IndexRange *indexRangeOut)
{ {
if (primcount < 0) if (primcount < 0)
{ {
...@@ -1834,7 +1833,7 @@ bool ValidateDrawElementsInstancedBase(Context *context, ...@@ -1834,7 +1833,7 @@ bool ValidateDrawElementsInstancedBase(Context *context,
return false; return false;
} }
if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut)) if (!ValidateDrawElementsCommon(context, mode, count, type, indices, primcount))
{ {
return false; return false;
} }
...@@ -1864,7 +1863,7 @@ bool ValidateDrawArraysInstancedBase(Context *context, ...@@ -1864,7 +1863,7 @@ bool ValidateDrawArraysInstancedBase(Context *context,
return (primcount > 0); return (primcount > 0);
} }
bool ValidateDrawInstancedANGLEAndWebGL(Context *context) bool ValidateDrawInstancedANGLEAndWebGL(ValidationContext *context)
{ {
// Verify there is at least one active attribute with a divisor of zero // Verify there is at least one active attribute with a divisor of zero
const State &state = context->getGLState(); const State &state = context->getGLState();
...@@ -3955,13 +3954,12 @@ bool ValidateDrawElementsBase(ValidationContext *context, GLenum type) ...@@ -3955,13 +3954,12 @@ bool ValidateDrawElementsBase(ValidationContext *context, GLenum type)
return true; return true;
} }
bool ValidateDrawElements(ValidationContext *context, bool ValidateDrawElementsCommon(ValidationContext *context,
GLenum mode, GLenum mode,
GLsizei count, GLsizei count,
GLenum type, GLenum type,
const GLvoid *indices, const GLvoid *indices,
GLsizei primcount, GLsizei primcount)
IndexRange *indexRangeOut)
{ {
if (!ValidateDrawElementsBase(context, type)) if (!ValidateDrawElementsBase(context, type))
return false; return false;
...@@ -4067,60 +4065,49 @@ bool ValidateDrawElements(ValidationContext *context, ...@@ -4067,60 +4065,49 @@ bool ValidateDrawElements(ValidationContext *context,
return false; return false;
} }
// Use max index to validate if our vertex buffers are large enough for the pull. // Use the parameter buffer to retrieve and cache the index range.
// TODO: offer fast path, with disabled index validation. // TODO: offer fast path, with disabled index validation.
// TODO: also disable index checking on back-ends that are robust to out-of-range accesses. // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
if (elementArrayBuffer) const auto &params = context->getParams<HasIndexRange>();
const auto &indexRangeOpt = params.getIndexRange();
if (!indexRangeOpt.valid())
{ {
uintptr_t offset = reinterpret_cast<uintptr_t>(indices); // Unexpected error.
Error error = return false;
elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
state.isPrimitiveRestartEnabled(), indexRangeOut);
if (error.isError())
{
context->handleError(error);
return false;
}
}
else
{
*indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
} }
// If we use an index greater than our maximum supported index range, return an error. // If we use an index greater than our maximum supported index range, return an error.
// The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
// return an error if possible here. // return an error if possible here.
if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex) if (static_cast<GLuint64>(indexRangeOpt.value().end) >= context->getCaps().maxElementIndex)
{ {
context->handleError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage)); context->handleError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
return false; return false;
} }
if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRangeOut->end), if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRangeOpt.value().end),
static_cast<GLint>(indexRangeOut->vertexCount()))) static_cast<GLint>(indexRangeOpt.value().vertexCount())))
{ {
return false; return false;
} }
// No op if there are no real indices in the index data (all are primitive restart). // No op if there are no real indices in the index data (all are primitive restart).
return (indexRangeOut->vertexIndexCount > 0); return (indexRangeOpt.value().vertexIndexCount > 0);
} }
bool ValidateDrawElementsInstanced(Context *context, bool ValidateDrawElementsInstancedCommon(ValidationContext *context,
GLenum mode, GLenum mode,
GLsizei count, GLsizei count,
GLenum type, GLenum type,
const GLvoid *indices, const GLvoid *indices,
GLsizei primcount, GLsizei primcount)
IndexRange *indexRangeOut)
{ {
if (context->getExtensions().webglCompatibility && !ValidateDrawInstancedANGLEAndWebGL(context)) if (context->getExtensions().webglCompatibility && !ValidateDrawInstancedANGLEAndWebGL(context))
{ {
return false; return false;
} }
return ValidateDrawElementsInstancedBase(context, mode, count, type, indices, primcount, return ValidateDrawElementsInstancedBase(context, mode, count, type, indices, primcount);
indexRangeOut);
} }
bool ValidateDrawElementsInstancedANGLE(Context *context, bool ValidateDrawElementsInstancedANGLE(Context *context,
...@@ -4128,16 +4115,14 @@ bool ValidateDrawElementsInstancedANGLE(Context *context, ...@@ -4128,16 +4115,14 @@ bool ValidateDrawElementsInstancedANGLE(Context *context,
GLsizei count, GLsizei count,
GLenum type, GLenum type,
const GLvoid *indices, const GLvoid *indices,
GLsizei primcount, GLsizei primcount)
IndexRange *indexRangeOut)
{ {
if (!ValidateDrawInstancedANGLEAndWebGL(context)) if (!ValidateDrawInstancedANGLEAndWebGL(context))
{ {
return false; return false;
} }
return ValidateDrawElementsInstancedBase(context, mode, count, type, indices, primcount, return ValidateDrawElementsInstancedBase(context, mode, count, type, indices, primcount);
indexRangeOut);
} }
bool ValidateFramebufferTextureBase(Context *context, bool ValidateFramebufferTextureBase(Context *context,
......
...@@ -273,28 +273,25 @@ bool ValidateDrawArraysInstancedANGLE(Context *context, ...@@ -273,28 +273,25 @@ bool ValidateDrawArraysInstancedANGLE(Context *context,
GLsizei primcount); GLsizei primcount);
bool ValidateDrawElementsBase(ValidationContext *context, GLenum type); bool ValidateDrawElementsBase(ValidationContext *context, GLenum type);
bool ValidateDrawElements(ValidationContext *context, bool ValidateDrawElementsCommon(ValidationContext *context,
GLenum mode, GLenum mode,
GLsizei count, GLsizei count,
GLenum type, GLenum type,
const GLvoid *indices, const GLvoid *indices,
GLsizei primcount, GLsizei primcount);
IndexRange *indexRangeOut);
bool ValidateDrawElementsInstancedCommon(ValidationContext *context,
bool ValidateDrawElementsInstanced(Context *context, GLenum mode,
GLenum mode, GLsizei count,
GLsizei count, GLenum type,
GLenum type, const GLvoid *indices,
const GLvoid *indices, GLsizei primcount);
GLsizei primcount,
IndexRange *indexRangeOut);
bool ValidateDrawElementsInstancedANGLE(Context *context, bool ValidateDrawElementsInstancedANGLE(Context *context,
GLenum mode, GLenum mode,
GLsizei count, GLsizei count,
GLenum type, GLenum type,
const GLvoid *indices, const GLvoid *indices,
GLsizei primcount, GLsizei primcount);
IndexRange *indexRangeOut);
bool ValidateFramebufferTextureBase(Context *context, bool ValidateFramebufferTextureBase(Context *context,
GLenum target, GLenum target,
......
...@@ -4894,4 +4894,13 @@ bool ValidateDrawArrays(ValidationContext *context, GLenum mode, GLint first, GL ...@@ -4894,4 +4894,13 @@ bool ValidateDrawArrays(ValidationContext *context, GLenum mode, GLint first, GL
return ValidateDrawArraysCommon(context, mode, first, count, 1); return ValidateDrawArraysCommon(context, mode, first, count, 1);
} }
bool ValidateDrawElements(ValidationContext *context,
GLenum mode,
GLsizei count,
GLenum type,
const GLvoid *indices)
{
return ValidateDrawElementsCommon(context, mode, count, type, indices, 1);
}
} // namespace gl } // namespace gl
...@@ -577,6 +577,11 @@ bool ValidateVertexAttrib4f(ValidationContext *context, ...@@ -577,6 +577,11 @@ bool ValidateVertexAttrib4f(ValidationContext *context,
GLfloat w); GLfloat w);
bool ValidateVertexAttrib4fv(ValidationContext *context, GLuint index, const GLfloat *values); bool ValidateVertexAttrib4fv(ValidationContext *context, GLuint index, const GLfloat *values);
bool ValidateViewport(ValidationContext *context, GLint x, GLint y, GLsizei width, GLsizei height); bool ValidateViewport(ValidationContext *context, GLint x, GLint y, GLsizei width, GLsizei height);
bool ValidateDrawElements(ValidationContext *context,
GLenum mode,
GLsizei count,
GLenum type,
const GLvoid *indices);
bool ValidateDrawArrays(ValidationContext *context, GLenum mode, GLint first, GLsizei count); bool ValidateDrawArrays(ValidationContext *context, GLenum mode, GLint first, GLsizei count);
......
...@@ -1080,8 +1080,7 @@ bool ValidateDrawRangeElements(Context *context, ...@@ -1080,8 +1080,7 @@ bool ValidateDrawRangeElements(Context *context,
GLuint end, GLuint end,
GLsizei count, GLsizei count,
GLenum type, GLenum type,
const GLvoid *indices, const GLvoid *indices)
IndexRange *indexRange)
{ {
if (context->getClientMajorVersion() < 3) if (context->getClientMajorVersion() < 3)
{ {
...@@ -1095,12 +1094,21 @@ bool ValidateDrawRangeElements(Context *context, ...@@ -1095,12 +1094,21 @@ bool ValidateDrawRangeElements(Context *context,
return false; return false;
} }
if (!ValidateDrawElements(context, mode, count, type, indices, 0, indexRange)) if (!ValidateDrawElementsCommon(context, mode, count, type, indices, 0))
{ {
return false; return false;
} }
if (indexRange->end > end || indexRange->start < start) // Use the parameter buffer to retrieve and cache the index range.
const auto &params = context->getParams<HasIndexRange>();
const auto &indexRangeOpt = params.getIndexRange();
if (!indexRangeOpt.valid())
{
// Unexpected error.
return false;
}
if (indexRangeOpt.value().end > end || indexRangeOpt.value().start < start)
{ {
// GL spec says that behavior in this case is undefined - generating an error is fine. // GL spec says that behavior in this case is undefined - generating an error is fine.
context->handleError( context->handleError(
...@@ -2555,4 +2563,20 @@ bool ValidateGetSynciv(Context *context, ...@@ -2555,4 +2563,20 @@ bool ValidateGetSynciv(Context *context,
return true; return true;
} }
bool ValidateDrawElementsInstanced(ValidationContext *context,
GLenum mode,
GLsizei count,
GLenum type,
const GLvoid *indices,
GLsizei instanceCount)
{
if (context->getClientMajorVersion() < 3)
{
context->handleError(Error(GL_INVALID_OPERATION, "Requires a GLES 3.0 or higher context."));
return false;
}
return ValidateDrawElementsInstancedCommon(context, mode, count, type, indices, instanceCount);
}
} // namespace gl } // namespace gl
...@@ -167,8 +167,7 @@ bool ValidateDrawRangeElements(Context *context, ...@@ -167,8 +167,7 @@ bool ValidateDrawRangeElements(Context *context,
GLuint end, GLuint end,
GLsizei count, GLsizei count,
GLenum type, GLenum type,
const GLvoid *indices, const GLvoid *indices);
IndexRange *indexRange);
bool ValidateGetUniformuiv(Context *context, GLuint program, GLint location, GLuint* params); bool ValidateGetUniformuiv(Context *context, GLuint program, GLint location, GLuint* params);
...@@ -415,6 +414,13 @@ bool ValidateGetSynciv(Context *context, ...@@ -415,6 +414,13 @@ bool ValidateGetSynciv(Context *context,
GLsizei *length, GLsizei *length,
GLint *values); GLint *values);
bool ValidateDrawElementsInstanced(ValidationContext *context,
GLenum mode,
GLsizei count,
GLenum type,
const GLvoid *indices,
GLsizei instanceCount);
} // namespace gl } // namespace gl
#endif // LIBANGLE_VALIDATION_ES3_H_ #endif // LIBANGLE_VALIDATION_ES3_H_
...@@ -111,11 +111,10 @@ TEST(ValidationESTest, DISABLED_DrawElementsWithMaxIndexGivesError) ...@@ -111,11 +111,10 @@ TEST(ValidationESTest, DISABLED_DrawElementsWithMaxIndexGivesError)
// Call once with maximum index, and once with an excessive index. // Call once with maximum index, and once with an excessive index.
GLuint indexData[] = {0, 1, static_cast<GLuint>(caps.maxElementIndex - 1), GLuint indexData[] = {0, 1, static_cast<GLuint>(caps.maxElementIndex - 1),
3, 4, static_cast<GLuint>(caps.maxElementIndex)}; 3, 4, static_cast<GLuint>(caps.maxElementIndex)};
IndexRange indexRange; EXPECT_TRUE(
EXPECT_TRUE(ValidateDrawElements(&testContext, GL_TRIANGLES, 3, GL_UNSIGNED_INT, indexData, 1, ValidateDrawElementsCommon(&testContext, GL_TRIANGLES, 3, GL_UNSIGNED_INT, indexData, 1));
&indexRange)); EXPECT_FALSE(
EXPECT_FALSE(ValidateDrawElements(&testContext, GL_TRIANGLES, 6, GL_UNSIGNED_INT, indexData, 2, ValidateDrawElementsCommon(&testContext, GL_TRIANGLES, 6, GL_UNSIGNED_INT, indexData, 2));
&indexRange));
texture->release(); texture->release();
......
...@@ -208,6 +208,8 @@ ...@@ -208,6 +208,8 @@
'libANGLE/formatutils.cpp', 'libANGLE/formatutils.cpp',
'libANGLE/formatutils.h', 'libANGLE/formatutils.h',
'libANGLE/histogram_macros.h', 'libANGLE/histogram_macros.h',
'libANGLE/params.cpp',
'libANGLE/params.h',
'libANGLE/queryconversions.cpp', 'libANGLE/queryconversions.cpp',
'libANGLE/queryconversions.h', 'libANGLE/queryconversions.h',
'libANGLE/queryutils.cpp', 'libANGLE/queryutils.cpp',
......
...@@ -716,6 +716,8 @@ void GL_APIENTRY DrawArrays(GLenum mode, GLint first, GLsizei count) ...@@ -716,6 +716,8 @@ void GL_APIENTRY DrawArrays(GLenum mode, GLint first, GLsizei count)
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
context->gatherParams<EntryPoint::DrawArrays>(mode, first, count);
if (!context->skipValidation() && !ValidateDrawArrays(context, mode, first, count)) if (!context->skipValidation() && !ValidateDrawArrays(context, mode, first, count))
{ {
return; return;
...@@ -733,14 +735,15 @@ void GL_APIENTRY DrawElements(GLenum mode, GLsizei count, GLenum type, const GLv ...@@ -733,14 +735,15 @@ void GL_APIENTRY DrawElements(GLenum mode, GLsizei count, GLenum type, const GLv
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
// TODO(jmadill): Cache index range in the context. context->gatherParams<EntryPoint::DrawElements>(mode, count, type, indices);
IndexRange indexRange;
if (!ValidateDrawElements(context, mode, count, type, indices, 1, &indexRange)) if (!context->skipValidation() &&
!ValidateDrawElements(context, mode, count, type, indices))
{ {
return; return;
} }
context->drawElements(mode, count, type, indices, indexRange); context->drawElements(mode, count, type, indices);
} }
} }
......
...@@ -294,14 +294,16 @@ void GL_APIENTRY DrawElementsInstancedANGLE(GLenum mode, ...@@ -294,14 +294,16 @@ void GL_APIENTRY DrawElementsInstancedANGLE(GLenum mode,
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
IndexRange indexRange; context->gatherParams<EntryPoint::DrawElementsInstancedANGLE>(mode, count, type, indices,
if (!ValidateDrawElementsInstancedANGLE(context, mode, count, type, indices, primcount, primcount);
&indexRange))
if (!context->skipValidation() &&
!ValidateDrawElementsInstancedANGLE(context, mode, count, type, indices, primcount))
{ {
return; return;
} }
context->drawElementsInstanced(mode, count, type, indices, primcount, indexRange); context->drawElementsInstanced(mode, count, type, indices, primcount);
} }
} }
......
...@@ -53,15 +53,16 @@ void GL_APIENTRY DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsize ...@@ -53,15 +53,16 @@ void GL_APIENTRY DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsize
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
IndexRange indexRange; context->gatherParams<EntryPoint::DrawRangeElements>(mode, start, end, count, type,
indices);
if (!context->skipValidation() && if (!context->skipValidation() &&
!ValidateDrawRangeElements(context, mode, start, end, count, type, indices, !ValidateDrawRangeElements(context, mode, start, end, count, type, indices))
&indexRange))
{ {
return; return;
} }
context->drawRangeElements(mode, start, end, count, type, indices, indexRange); context->drawRangeElements(mode, start, end, count, type, indices);
} }
} }
...@@ -1476,19 +1477,16 @@ void GL_APIENTRY DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, ...@@ -1476,19 +1477,16 @@ void GL_APIENTRY DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type,
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
if (context->getClientMajorVersion() < 3) context->gatherParams<EntryPoint::DrawElementsInstanced>(mode, count, type, indices,
{ instanceCount);
context->handleError(Error(GL_INVALID_OPERATION));
return;
}
IndexRange indexRange; if (!context->skipValidation() &&
if (!ValidateDrawElementsInstanced(context, mode, count, type, indices, instanceCount, &indexRange)) !ValidateDrawElementsInstanced(context, mode, count, type, indices, instanceCount))
{ {
return; return;
} }
context->drawElementsInstanced(mode, count, type, indices, instanceCount, indexRange); context->drawElementsInstanced(mode, count, type, indices, instanceCount);
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment