diff --git a/src/common/PackedEnums.h b/src/common/PackedEnums.h index 301a56736..e4c3d2496 100644 --- a/src/common/PackedEnums.h +++ b/src/common/PackedEnums.h @@ -110,8 +110,18 @@ class PackedEnumMap constexpr bool empty() const noexcept { return mPrivateData.empty(); } // element access: - reference operator[](E n) { return mPrivateData[static_cast(n)]; } - const_reference operator[](E n) const { return mPrivateData[static_cast(n)]; } + reference operator[](E n) + { + ASSERT(static_cast(n) < mPrivateData.size()); + return mPrivateData[static_cast(n)]; + } + + const_reference operator[](E n) const + { + ASSERT(static_cast(n) < mPrivateData.size()); + return mPrivateData[static_cast(n)]; + } + const_reference at(E n) const { return mPrivateData.at(static_cast(n)); } reference at(E n) { return mPrivateData.at(static_cast(n)); } diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp index fad487167..315045259 100644 --- a/src/libANGLE/Context.cpp +++ b/src/libANGLE/Context.cpp @@ -361,7 +361,6 @@ Context::Context(rx::EGLImplFactory *implFactory, mWebGLContext(GetWebGLContext(attribs)), mExtensionsEnabled(GetExtensionsEnabled(attribs, mWebGLContext)), mMemoryProgramCache(memoryProgramCache), - mStateCache(this), mVertexArrayObserverBinding(this, kVertexArraySubjectIndex), mDrawFramebufferObserverBinding(this, kDrawFramebufferSubjectIndex), mReadFramebufferObserverBinding(this, kReadFramebufferSubjectIndex), @@ -3430,6 +3429,9 @@ void Context::updateCaps() } mThreadPool = angle::WorkerThreadPool::Create(mExtensions.parallelShaderCompile); + + // Reinitialize state cache after extension changes. + mStateCache.initialize(this); } void Context::initWorkarounds() @@ -7987,17 +7989,22 @@ GLenum ErrorSet::popError() } // StateCache implementation. -StateCache::StateCache(Context *context) +StateCache::StateCache() : mCachedHasAnyEnabledClientAttrib(false), mCachedNonInstancedVertexElementLimit(0), mCachedInstancedVertexElementLimit(0), mCachedBasicDrawStatesError(kInvalidPointer) { - updateValidDrawModes(context); } StateCache::~StateCache() = default; +void StateCache::initialize(Context *context) +{ + updateValidDrawModes(context); + updateValidBindTextureTypes(context); +} + void StateCache::updateActiveAttribsMask(Context *context) { bool isGLES1 = context->isGLES1(); @@ -8209,4 +8216,24 @@ void StateCache::updateValidDrawModes(Context *context) }}; } } + +void StateCache::updateValidBindTextureTypes(Context *context) +{ + const Extensions &exts = context->getExtensions(); + bool isGLES3 = context->getClientMajorVersion() >= 3; + bool isGLES31 = context->getClientVersion() >= Version(3, 1); + + mCachedValidBindTextureTypes = {{ + true, /* _2D */ + isGLES3, /* _2DArray */ + isGLES31, /* _2DMultisample */ + exts.textureStorageMultisample2DArray, /* _2DMultisampleArray */ + isGLES3, /* _3D */ + exts.eglImageExternal || exts.eglStreamConsumerExternal, /* External */ + exts.textureRectangle, /* Rectangle */ + true, /* CubeMap */ + false, /* InvalidEnum */ + + }}; +} } // namespace gl diff --git a/src/libANGLE/Context.h b/src/libANGLE/Context.h index 24523774d..29cf776cb 100644 --- a/src/libANGLE/Context.h +++ b/src/libANGLE/Context.h @@ -92,9 +92,11 @@ class ErrorSet : angle::NonCopyable class StateCache final : angle::NonCopyable { public: - StateCache(Context *context); + StateCache(); ~StateCache(); + void initialize(Context *context); + // Places that can trigger updateActiveAttribsMask: // 1. onVertexArrayBindingChange. // 2. onProgramExecutableChange. @@ -150,6 +152,12 @@ class StateCache final : angle::NonCopyable return mCachedValidDrawModes[primitiveMode]; } + // Cannot change except on Context/Extension init. + bool isValidBindTextureType(TextureType type) const + { + return mCachedValidBindTextureTypes[type]; + } + // State change notifications. void onVertexArrayBindingChange(Context *context); void onProgramExecutableChange(Context *context); @@ -174,6 +182,7 @@ class StateCache final : angle::NonCopyable void updateVertexElementLimits(Context *context); void updateBasicDrawStatesError(); void updateValidDrawModes(Context *context); + void updateValidBindTextureTypes(Context *context); intptr_t getBasicDrawStatesErrorImpl(Context *context) const; @@ -187,9 +196,11 @@ class StateCache final : angle::NonCopyable GLint64 mCachedInstancedVertexElementLimit; mutable intptr_t mCachedBasicDrawStatesError; - // Reserve an extra slot at the end of the map for invalid enum. + // Reserve an extra slot at the end of these maps for invalid enum. angle::PackedEnumMap() + 1> mCachedValidDrawModes; + angle::PackedEnumMap() + 1> + mCachedValidBindTextureTypes; }; class Context final : public egl::LabeledObject, angle::NonCopyable, public angle::ObserverInterface diff --git a/src/libANGLE/validationES2.cpp b/src/libANGLE/validationES2.cpp index 5433c43e5..15730176c 100644 --- a/src/libANGLE/validationES2.cpp +++ b/src/libANGLE/validationES2.cpp @@ -1110,6 +1110,44 @@ bool ValidDstBlendFunc(const Context *context, GLenum val) return false; } +void RecordBindTextureTypeError(Context *context, TextureType target) +{ + ASSERT(!context->getStateCache().isValidBindTextureType(target)); + + switch (target) + { + case TextureType::Rectangle: + ASSERT(!context->getExtensions().textureRectangle); + context->handleError(InvalidEnum() + << "Context does not support GL_ANGLE_texture_rectangle"); + break; + + case TextureType::_3D: + case TextureType::_2DArray: + ASSERT(context->getClientMajorVersion() < 3); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), ES3Required); + break; + + case TextureType::_2DMultisample: + ASSERT(context->getClientVersion() < Version(3, 1)); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), ES31Required); + break; + + case TextureType::_2DMultisampleArray: + ASSERT(!context->getExtensions().textureStorageMultisample2DArray); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), MultisampleArrayExtensionRequired); + break; + + case TextureType::External: + ASSERT(!context->getExtensions().eglImageExternal && + !context->getExtensions().eglStreamConsumerExternal); + context->handleError(InvalidEnum() << "External texture extension not enabled"); + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTextureTarget); + } +} } // anonymous namespace bool ValidateES2TexImageParameters(Context *context, @@ -3044,55 +3082,10 @@ bool ValidateFlushMappedBufferRangeEXT(Context *context, bool ValidateBindTexture(Context *context, TextureType target, GLuint texture) { - switch (target) + if (!context->getStateCache().isValidBindTextureType(target)) { - case TextureType::_2D: - case TextureType::CubeMap: - break; - - case TextureType::Rectangle: - if (!context->getExtensions().textureRectangle) - { - context->handleError(InvalidEnum() - << "Context does not support GL_ANGLE_texture_rectangle"); - return false; - } - break; - - case TextureType::_3D: - case TextureType::_2DArray: - if (context->getClientMajorVersion() < 3) - { - ANGLE_VALIDATION_ERR(context, InvalidEnum(), ES3Required); - return false; - } - break; - - case TextureType::_2DMultisample: - if (context->getClientVersion() < Version(3, 1)) - { - ANGLE_VALIDATION_ERR(context, InvalidEnum(), ES31Required); - return false; - } - break; - case TextureType::_2DMultisampleArray: - if (!context->getExtensions().textureStorageMultisample2DArray) - { - ANGLE_VALIDATION_ERR(context, InvalidEnum(), MultisampleArrayExtensionRequired); - return false; - } - break; - case TextureType::External: - if (!context->getExtensions().eglImageExternal && - !context->getExtensions().eglStreamConsumerExternal) - { - context->handleError(InvalidEnum() << "External texture extension not enabled"); - return false; - } - break; - default: - ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTextureTarget); - return false; + RecordBindTextureTypeError(context, target); + return false; } if (texture == 0)