Commit 18c6d628 by Geoff Lang Committed by Commit Bot

GL: Support VAOs without native VAOs.

Share the default VAO state between all frontend VAO when there is no native VAO support. Forcefully sync state every time a new frontend VAO is bound. Bug: angleproject:5577, chromium:1167179 Change-Id: Ieaedb5108ad28fc78e7e58b74495639c5246bb05 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2665266Reviewed-by: 's avatarJonah Ryan-Davis <jonahr@google.com> Reviewed-by: 's avatarPeng Huang <penghuang@chromium.org> Commit-Queue: Geoff Lang <geofflang@chromium.org>
parent fe790824
......@@ -529,6 +529,12 @@ struct FeaturesGL : FeatureSetBase
"shift_instanced_array_data_with_offset", FeatureCategory::OpenGLWorkarounds,
"glDrawArraysInstanced is buggy on certain new Mac Intel GPUs", &members,
"http://crbug.com/1144207"};
// ANGLE needs to support devices that have no native VAOs. Sync everything to the default VAO.
Feature syncVertexArraysToDefault = {
"sync_vertex_arrays_to_default", FeatureCategory::OpenGLWorkarounds,
"Only use the default VAO because of missing support or driver bugs", &members,
"http://anglebug.com/5577"};
};
inline FeaturesGL::FeaturesGL() = default;
......
......@@ -256,9 +256,10 @@ BlitGL::~BlitGL()
mScratchFBO = 0;
}
if (mVAO != 0)
if (mOwnsVAOState)
{
mStateManager->deleteVertexArray(mVAO);
SafeDelete(mVAOState);
mVAO = 0;
}
}
......@@ -365,7 +366,7 @@ angle::Result BlitGL::copySubImageToLUMAWorkaroundTexture(const gl::Context *con
ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->multiplyAlphaLocation, 0));
ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->unMultiplyAlphaLocation, 0));
mStateManager->bindVertexArray(mVAO, 0);
ANGLE_TRY(setVAOState(context));
ANGLE_GL_TRY(context, mFunctions->drawArrays(GL_TRIANGLES, 0, 3));
// Copy the swizzled texture to the destination texture
......@@ -548,7 +549,7 @@ angle::Result BlitGL::blitColorBufferWithShader(const gl::Context *context,
mStateManager->bindFramebuffer(GL_DRAW_FRAMEBUFFER, destFramebuffer);
mStateManager->bindVertexArray(mVAO, 0);
ANGLE_TRY(setVAOState(context));
ANGLE_GL_TRY(context, mFunctions->drawArrays(GL_TRIANGLES, 0, 3));
ANGLE_TRY(scopedState.exit(context));
......@@ -663,7 +664,7 @@ angle::Result BlitGL::copySubTexture(const gl::Context *context,
unpackUnmultiplyAlpha));
}
mStateManager->bindVertexArray(mVAO, 0);
ANGLE_TRY(setVAOState(context));
ANGLE_GL_TRY(context, mFunctions->drawArrays(GL_TRIANGLES, 0, 3));
*copySucceededOut = true;
......@@ -1075,7 +1076,7 @@ angle::Result BlitGL::generateSRGBMipmap(const gl::Context *context,
mStateManager->bindTexture(sourceType, source->getTextureID());
ANGLE_TRY(source->setMinFilter(context, GL_NEAREST));
mStateManager->bindVertexArray(mVAO, 0);
ANGLE_TRY(setVAOState(context));
ANGLE_GL_TRY(context, mFunctions->drawArrays(GL_TRIANGLES, 0, 3));
// Generate mipmaps on the linear texture
......@@ -1133,21 +1134,21 @@ angle::Result BlitGL::initializeResources(const gl::Context *context)
ANGLE_GL_TRY(context, mFunctions->bufferData(GL_ARRAY_BUFFER, sizeof(float) * 6, vertexData,
GL_STATIC_DRAW));
ANGLE_GL_TRY(context, mFunctions->genVertexArrays(1, &mVAO));
mStateManager->bindVertexArray(mVAO, 0);
mStateManager->bindBuffer(gl::BufferBinding::Array, mVertexBuffer);
// Enable all attributes with the same buffer so that it doesn't matter what location the
// texcoord attribute is assigned
GLint maxAttributes = 0;
ANGLE_GL_TRY(context, mFunctions->getIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxAttributes));
for (GLint i = 0; i < maxAttributes; i++)
VertexArrayStateGL *defaultVAOState = mStateManager->getDefaultVAOState();
if (!mFeatures.syncVertexArraysToDefault.enabled)
{
ANGLE_GL_TRY(context, mFunctions->enableVertexAttribArray(i));
ANGLE_GL_TRY(context,
mFunctions->vertexAttribPointer(i, 2, GL_FLOAT, GL_FALSE, 0, nullptr));
ANGLE_GL_TRY(context, mFunctions->genVertexArrays(1, &mVAO));
mVAOState = new VertexArrayStateGL(defaultVAOState->attributes.size(),
defaultVAOState->bindings.size());
mOwnsVAOState = true;
ANGLE_TRY(setVAOState(context));
ANGLE_TRY(initializeVAOState(context));
}
else
{
mVAO = mStateManager->getDefaultVAO();
mVAOState = defaultVAOState;
mOwnsVAOState = false;
}
constexpr GLenum potentialSRGBMipmapGenerationFormats[] = {
......@@ -1227,6 +1228,43 @@ angle::Result BlitGL::setScratchTextureParameter(const gl::Context *context,
return angle::Result::Continue;
}
angle::Result BlitGL::setVAOState(const gl::Context *context)
{
mStateManager->bindVertexArray(mVAO, mVAOState);
if (mFeatures.syncVertexArraysToDefault.enabled)
{
ANGLE_TRY(initializeVAOState(context));
}
return angle::Result::Continue;
}
angle::Result BlitGL::initializeVAOState(const gl::Context *context)
{
mStateManager->bindBuffer(gl::BufferBinding::Array, mVertexBuffer);
ANGLE_GL_TRY(context, mFunctions->enableVertexAttribArray(mTexcoordAttribLocation));
ANGLE_GL_TRY(context, mFunctions->vertexAttribPointer(mTexcoordAttribLocation, 2, GL_FLOAT,
GL_FALSE, 0, nullptr));
VertexAttributeGL &attribute = mVAOState->attributes[mTexcoordAttribLocation];
attribute.enabled = true;
attribute.format = &angle::Format::Get(angle::FormatID::R32G32_FLOAT);
attribute.pointer = nullptr;
VertexBindingGL &binding = mVAOState->bindings[mTexcoordAttribLocation];
binding.stride = 8;
binding.offset = 0;
binding.buffer = mVertexBuffer;
if (mFeatures.syncVertexArraysToDefault.enabled)
{
mStateManager->setDefaultVAOStateDirty();
}
return angle::Result::Continue;
}
angle::Result BlitGL::getBlitProgram(const gl::Context *context,
gl::TextureType sourceTextureType,
GLenum sourceComponentType,
......@@ -1242,6 +1280,7 @@ angle::Result BlitGL::getBlitProgram(const gl::Context *context,
// Depending on what types need to be output by the shaders, different versions need to be
// used.
constexpr const char *texcoordAttribName = "a_texcoord";
std::string version;
std::string vsInputVariableQualifier;
std::string vsOutputVariableQualifier;
......@@ -1282,15 +1321,17 @@ angle::Result BlitGL::getBlitProgram(const gl::Context *context,
// Compile the vertex shader
std::ostringstream vsSourceStream;
vsSourceStream << "#version " << version << "\n";
vsSourceStream << vsInputVariableQualifier << " vec2 a_texcoord;\n";
vsSourceStream << vsInputVariableQualifier << " vec2 " << texcoordAttribName << ";\n";
vsSourceStream << "uniform vec2 u_scale;\n";
vsSourceStream << "uniform vec2 u_offset;\n";
vsSourceStream << vsOutputVariableQualifier << " vec2 v_texcoord;\n";
vsSourceStream << "\n";
vsSourceStream << "void main()\n";
vsSourceStream << "{\n";
vsSourceStream << " gl_Position = vec4((a_texcoord * 2.0) - 1.0, 0.0, 1.0);\n";
vsSourceStream << " v_texcoord = a_texcoord * u_scale + u_offset;\n";
vsSourceStream << " gl_Position = vec4((" << texcoordAttribName
<< " * 2.0) - 1.0, 0.0, 1.0);\n";
vsSourceStream << " v_texcoord = " << texcoordAttribName
<< " * u_scale + u_offset;\n";
vsSourceStream << "}\n";
std::string vsSourceStr = vsSourceStream.str();
......@@ -1477,6 +1518,8 @@ angle::Result BlitGL::getBlitProgram(const gl::Context *context,
ANGLE_GL_TRY(context, mFunctions->deleteShader(fs));
}
ANGLE_GL_TRY(context, mFunctions->bindAttribLocation(
result.program, mTexcoordAttribLocation, texcoordAttribName));
ANGLE_GL_TRY(context, mFunctions->linkProgram(result.program));
ANGLE_TRY(CheckLinkStatus(context, mFunctions, result.program));
......
......@@ -36,6 +36,7 @@ class FunctionsGL;
class RenderbufferGL;
class StateManagerGL;
class TextureGL;
struct VertexArrayStateGL;
class BlitGL : angle::NonCopyable
{
......@@ -168,6 +169,8 @@ class BlitGL : angle::NonCopyable
angle::Result setScratchTextureParameter(const gl::Context *context,
GLenum param,
GLenum value);
angle::Result setVAOState(const gl::Context *context);
angle::Result initializeVAOState(const gl::Context *context);
const FunctionsGL *mFunctions;
const angle::FeaturesGL &mFeatures;
......@@ -195,11 +198,15 @@ class BlitGL : angle::NonCopyable
using BlitProgramType = std::tuple<gl::TextureType, GLenum, GLenum>;
std::map<BlitProgramType, BlitProgram> mBlitPrograms;
GLuint mScratchTextures[2];
GLuint mScratchFBO;
GLuint mScratchTextures[2] = {0};
GLuint mScratchFBO = 0;
GLuint mVAO;
GLuint mVertexBuffer;
GLuint mVAO = 0;
VertexArrayStateGL *mVAOState = nullptr;
bool mOwnsVAOState = false;
const GLuint mTexcoordAttribLocation = 0;
GLuint mVertexBuffer = 0;
nativegl::TexImageFormat mSRGBMipmapGenerationFormat;
};
......
......@@ -115,12 +115,23 @@ BufferImpl *ContextGL::createBuffer(const gl::BufferState &state)
VertexArrayImpl *ContextGL::createVertexArray(const gl::VertexArrayState &data)
{
const FunctionsGL *functions = getFunctions();
const angle::FeaturesGL &features = getFeaturesGL();
if (features.syncVertexArraysToDefault.enabled)
{
StateManagerGL *stateManager = getStateManager();
GLuint vao = 0;
functions->genVertexArrays(1, &vao);
return new VertexArrayGL(data, stateManager->getDefaultVAO(),
stateManager->getDefaultVAOState());
}
else
{
const FunctionsGL *functions = getFunctions();
return new VertexArrayGL(data, vao);
GLuint vao = 0;
functions->genVertexArrays(1, &vao);
return new VertexArrayGL(data, vao);
}
}
QueryImpl *ContextGL::createQuery(gl::QueryType type)
......
......@@ -56,6 +56,17 @@ static void ValidateStateHelper(const FunctionsGL *functions,
} // anonymous namespace
VertexArrayStateGL::VertexArrayStateGL(size_t maxAttribs, size_t maxBindings)
: attributes(std::min<size_t>(maxAttribs, gl::MAX_VERTEX_ATTRIBS)),
bindings(std::min<size_t>(maxBindings, gl::MAX_VERTEX_ATTRIBS))
{
// Set the cached vertex attribute array and vertex attribute binding array size
for (GLuint i = 0; i < attributes.size(); i++)
{
attributes[i].bindingIndex = i;
}
}
StateManagerGL::IndexedBufferBinding::IndexedBufferBinding() : offset(0), size(0), buffer(0) {}
StateManagerGL::StateManagerGL(const FunctionsGL *functions,
......@@ -67,6 +78,8 @@ StateManagerGL::StateManagerGL(const FunctionsGL *functions,
mProgram(0),
mVAO(0),
mVertexAttribCurrentValues(rendererCaps.maxVertexAttributes),
mDefaultVAOState(rendererCaps.maxVertexAttributes, rendererCaps.maxVertexAttribBindings),
mVAOState(&mDefaultVAOState),
mBuffers(),
mIndexedBuffers(),
mTextureUnitIndex(0),
......@@ -182,9 +195,26 @@ StateManagerGL::StateManagerGL(const FunctionsGL *functions,
mFunctions->primitiveRestartIndex(primitiveRestartIndex);
mPrimitiveRestartIndex = primitiveRestartIndex;
}
// It's possible we've enabled the emulated VAO feature for testing but we're on a core profile.
// Use a generated VAO as the default VAO so we can still test.
if (features.syncVertexArraysToDefault.enabled &&
!nativegl::CanUseDefaultVertexArrayObject(mFunctions))
{
ASSERT(nativegl::SupportsVertexArrayObjects(mFunctions));
mFunctions->genVertexArrays(1, &mDefaultVAO);
mFunctions->bindVertexArray(mDefaultVAO);
mVAO = mDefaultVAO;
}
}
StateManagerGL::~StateManagerGL() {}
StateManagerGL::~StateManagerGL()
{
if (mDefaultVAO != 0)
{
mFunctions->deleteVertexArrays(1, &mDefaultVAO);
}
}
void StateManagerGL::deleteProgram(GLuint program)
{
......@@ -205,7 +235,7 @@ void StateManagerGL::deleteVertexArray(GLuint vao)
{
if (mVAO == vao)
{
bindVertexArray(0, 0);
bindVertexArray(0, &mDefaultVAOState);
}
mFunctions->deleteVertexArrays(1, &vao);
}
......@@ -281,6 +311,22 @@ void StateManagerGL::deleteBuffer(GLuint buffer)
}
}
if (mVAOState)
{
if (mVAOState->elementArrayBuffer == buffer)
{
mVAOState->elementArrayBuffer = 0;
}
for (VertexBindingGL &binding : mVAOState->bindings)
{
if (binding.buffer == buffer)
{
binding.buffer = 0;
}
}
}
mFunctions->deleteBuffers(1, &buffer);
}
......@@ -360,12 +406,17 @@ void StateManagerGL::forceUseProgram(GLuint program)
mLocalDirtyBits.set(gl::State::DIRTY_BIT_PROGRAM_BINDING);
}
void StateManagerGL::bindVertexArray(GLuint vao, GLuint elementArrayBuffer)
void StateManagerGL::bindVertexArray(GLuint vao, VertexArrayStateGL *vaoState)
{
ASSERT(vaoState);
if (mVAO != vao)
{
ASSERT(!mFeatures.syncVertexArraysToDefault.enabled);
mVAO = vao;
mBuffers[gl::BufferBinding::ElementArray] = elementArrayBuffer;
mVAOState = vaoState;
mBuffers[gl::BufferBinding::ElementArray] = vaoState ? vaoState->elementArrayBuffer : 0;
mFunctions->bindVertexArray(vao);
mLocalDirtyBits.set(gl::State::DIRTY_BIT_VERTEX_ARRAY_BINDING);
......@@ -1957,11 +2008,37 @@ angle::Result StateManagerGL::syncState(const gl::Context *context,
break;
case gl::State::DIRTY_BIT_VERTEX_ARRAY_BINDING:
{
const VertexArrayGL *vaoGL = GetImplAs<VertexArrayGL>(state.getVertexArray());
bindVertexArray(vaoGL->getVertexArrayID(), vaoGL->getAppliedElementArrayBufferID());
VertexArrayGL *vaoGL = GetImplAs<VertexArrayGL>(state.getVertexArray());
bindVertexArray(vaoGL->getVertexArrayID(), vaoGL->getNativeState());
propagateProgramToVAO(context, state.getProgram(),
GetImplAs<VertexArrayGL>(state.getVertexArray()));
if (mFeatures.syncVertexArraysToDefault.enabled)
{
// Re-sync the vertex array because all frontend VAOs share the same backend
// state. Only sync bits that can be set in ES2.0 or 3.0
gl::VertexArray::DirtyBits dirtyBits;
gl::VertexArray::DirtyAttribBitsArray dirtyAttribBits;
gl::VertexArray::DirtyBindingBitsArray dirtBindingBits;
dirtyBits.set(gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER);
for (size_t attrib = 0; attrib < mDefaultVAOState.attributes.size(); attrib++)
{
dirtyBits.set(gl::VertexArray::DIRTY_BIT_ATTRIB_0 + attrib);
dirtyAttribBits[attrib].set(gl::VertexArray::DIRTY_ATTRIB_ENABLED);
dirtyAttribBits[attrib].set(gl::VertexArray::DIRTY_ATTRIB_POINTER);
dirtyAttribBits[attrib].set(gl::VertexArray::DIRTY_ATTRIB_POINTER_BUFFER);
}
for (size_t binding = 0; binding < mDefaultVAOState.bindings.size(); binding++)
{
dirtyBits.set(gl::VertexArray::DIRTY_BIT_BINDING_0 + binding);
dirtBindingBits[binding].set(gl::VertexArray::DIRTY_BINDING_DIVISOR);
}
ANGLE_TRY(
vaoGL->syncState(context, dirtyBits, &dirtyAttribBits, &dirtBindingBits));
}
break;
}
case gl::State::DIRTY_BIT_DRAW_INDIRECT_BUFFER_BINDING:
......@@ -2422,6 +2499,16 @@ void StateManagerGL::syncTransformFeedbackState(const gl::Context *context)
}
}
GLuint StateManagerGL::getDefaultVAO() const
{
return mDefaultVAO;
}
VertexArrayStateGL *StateManagerGL::getDefaultVAOState()
{
return &mDefaultVAOState;
}
void StateManagerGL::validateState() const
{
// Current program
......@@ -3070,4 +3157,9 @@ void StateManagerGL::restoreVertexArraysNativeContext(const gl::Extensions &exte
bindVertexArray(state->vertexArrayBinding, 0);
}
void StateManagerGL::setDefaultVAOStateDirty()
{
mLocalDirtyBits.set(gl::State::DIRTY_BIT_VERTEX_ARRAY_BINDING);
}
} // namespace rx
......@@ -115,6 +115,36 @@ struct ExternalContextState
GLenum vertexArrayBinding;
};
struct VertexAttributeGL
{
bool enabled = false;
const angle::Format *format = &angle::Format::Get(angle::FormatID::R32G32B32A32_FLOAT);
const void *pointer = nullptr;
GLuint relativeOffset = 0;
GLuint bindingIndex = 0;
};
struct VertexBindingGL
{
GLuint stride = 16;
GLuint divisor = 0;
GLintptr offset = 0;
GLuint buffer = 0;
};
struct VertexArrayStateGL
{
VertexArrayStateGL(size_t maxAttribs, size_t maxBindings);
GLuint elementArrayBuffer = 0;
angle::FixedVector<VertexAttributeGL, gl::MAX_VERTEX_ATTRIBS> attributes;
angle::FixedVector<VertexBindingGL, gl::MAX_VERTEX_ATTRIBS> bindings;
};
class StateManagerGL final : angle::NonCopyable
{
public:
......@@ -135,7 +165,7 @@ class StateManagerGL final : angle::NonCopyable
void useProgram(GLuint program);
void forceUseProgram(GLuint program);
void bindVertexArray(GLuint vao, GLuint elementArrayBuffer);
void bindVertexArray(GLuint vao, VertexArrayStateGL *vaoState);
void bindBuffer(gl::BufferBinding target, GLuint buffer);
void bindBufferBase(gl::BufferBinding target, size_t index, GLuint buffer);
void bindBufferRange(gl::BufferBinding target,
......@@ -262,6 +292,10 @@ class StateManagerGL final : angle::NonCopyable
bool getHasSeparateFramebufferBindings() const { return mHasSeparateFramebufferBindings; }
GLuint getDefaultVAO() const;
VertexArrayStateGL *getDefaultVAOState();
void setDefaultVAOStateDirty();
void validateState() const;
void syncFromNativeContext(const gl::Extensions &extensions, ExternalContextState *state);
......@@ -338,6 +372,17 @@ class StateManagerGL final : angle::NonCopyable
GLuint mVAO;
std::vector<gl::VertexAttribCurrentValueData> mVertexAttribCurrentValues;
GLuint mDefaultVAO = 0;
// The current state of the default VAO is owned by StateManagerGL. It may be shared between
// multiple VertexArrayGL objects if the native driver does not support vertex array objects.
// When this object is shared, StateManagerGL forces VertexArrayGL to resynchronize itself every
// time a new vertex array is bound.
VertexArrayStateGL mDefaultVAOState;
// The state of the currently bound vertex array object so StateManagerGL can know about the
// current element array buffer.
VertexArrayStateGL *mVAOState = nullptr;
angle::PackedEnumMap<gl::BufferBinding, GLuint> mBuffers;
struct IndexedBufferBinding
......
......@@ -28,15 +28,26 @@ namespace rx
{
namespace
{
bool SameVertexAttribFormat(const VertexAttribute &a, const VertexAttribute &b)
GLuint GetNativeBufferID(const gl::Buffer *frontendBuffer)
{
return frontendBuffer ? GetImplAs<BufferGL>(frontendBuffer)->getBufferID() : 0;
}
bool SameVertexAttribFormat(const VertexAttributeGL &a, const VertexAttribute &b)
{
return a.format == b.format && a.relativeOffset == b.relativeOffset;
}
bool SameVertexBuffer(const VertexBinding &a, const VertexBinding &b)
bool SameVertexBuffer(const VertexBindingGL &a, const VertexBinding &b)
{
return a.getStride() == b.getStride() && a.getOffset() == b.getOffset() &&
a.getBuffer().get() == b.getBuffer().get();
return a.stride == b.getStride() && a.offset == b.getOffset() &&
a.buffer == GetNativeBufferID(b.getBuffer().get());
}
bool SameIndexBuffer(const VertexArrayStateGL *a, const gl::Buffer *frontendBuffer)
{
return a->elementArrayBuffer == GetNativeBufferID(frontendBuffer);
}
bool IsVertexAttribPointerSupported(size_t attribIndex, const VertexAttribute &attrib)
......@@ -83,26 +94,23 @@ static void ValidateStateHelperGetVertexAttribiv(const FunctionsGL *functions,
// ASSERT(false);
}
}
} // anonymous namespace
VertexArrayGL::VertexArrayGL(const VertexArrayState &state, GLuint id)
: VertexArrayImpl(state),
mVertexArrayID(id),
mAppliedNumViews(1),
mAppliedElementArrayBuffer(),
mAppliedBindings(state.getMaxBindings()),
mStreamingElementArrayBufferSize(0),
mStreamingElementArrayBuffer(0),
mStreamingArrayBufferSize(0),
mStreamingArrayBuffer(0)
mOwnsNativeState(true),
mNativeState(new VertexArrayStateGL(state.getMaxAttribs(), state.getMaxBindings()))
{
// Set the cached vertex attribute array and vertex attribute binding array size
GLuint maxVertexAttribs = static_cast<GLuint>(state.getMaxAttribs());
for (GLuint i = 0; i < maxVertexAttribs; i++)
{
mAppliedAttributes.emplace_back(i);
}
mForcedStreamingAttributesFirstOffsets.fill(0);
}
VertexArrayGL::VertexArrayGL(const gl::VertexArrayState &state,
GLuint id,
VertexArrayStateGL *sharedState)
: VertexArrayImpl(state), mVertexArrayID(id), mOwnsNativeState(false), mNativeState(sharedState)
{
ASSERT(mNativeState);
mForcedStreamingAttributesFirstOffsets.fill(0);
}
......@@ -112,10 +120,19 @@ void VertexArrayGL::destroy(const gl::Context *context)
{
StateManagerGL *stateManager = GetStateManagerGL(context);
stateManager->deleteVertexArray(mVertexArrayID);
if (mOwnsNativeState)
{
stateManager->deleteVertexArray(mVertexArrayID);
}
mVertexArrayID = 0;
mAppliedNumViews = 1;
mElementArrayBuffer.set(context, nullptr);
for (gl::BindingPointer<gl::Buffer> &binding : mArrayBuffers)
{
binding.set(context, nullptr);
}
stateManager->deleteBuffer(mStreamingElementArrayBuffer);
mStreamingElementArrayBufferSize = 0;
mStreamingElementArrayBuffer = 0;
......@@ -124,11 +141,11 @@ void VertexArrayGL::destroy(const gl::Context *context)
mStreamingArrayBufferSize = 0;
mStreamingArrayBuffer = 0;
mAppliedElementArrayBuffer.set(context, nullptr);
for (auto &binding : mAppliedBindings)
if (mOwnsNativeState)
{
binding.setBuffer(context, nullptr);
delete mNativeState;
}
mNativeState = nullptr;
}
angle::Result VertexArrayGL::syncClientSideData(const gl::Context *context,
......@@ -144,12 +161,14 @@ angle::Result VertexArrayGL::syncClientSideData(const gl::Context *context,
void VertexArrayGL::updateElementArrayBufferBinding(const gl::Context *context) const
{
gl::Buffer *elementArrayBuffer = mState.getElementArrayBuffer();
if (elementArrayBuffer != nullptr && elementArrayBuffer != mAppliedElementArrayBuffer.get())
if (!SameIndexBuffer(mNativeState, elementArrayBuffer))
{
GLuint elementArrayBufferId = GetNativeBufferID(elementArrayBuffer);
StateManagerGL *stateManager = GetStateManagerGL(context);
const BufferGL *bufferGL = GetImplAs<BufferGL>(elementArrayBuffer);
stateManager->bindBuffer(gl::BufferBinding::ElementArray, bufferGL->getBufferID());
mAppliedElementArrayBuffer.set(context, elementArrayBuffer);
stateManager->bindBuffer(gl::BufferBinding::ElementArray, elementArrayBufferId);
mElementArrayBuffer.set(context, elementArrayBuffer);
mNativeState->elementArrayBuffer = elementArrayBufferId;
}
}
......@@ -242,9 +261,9 @@ angle::Result VertexArrayGL::syncIndexData(const gl::Context *context,
gl::Buffer *elementArrayBuffer = mState.getElementArrayBuffer();
// Need to check the range of indices if attributes need to be streamed
if (elementArrayBuffer != nullptr)
if (elementArrayBuffer)
{
ASSERT(elementArrayBuffer == mAppliedElementArrayBuffer.get());
ASSERT(SameIndexBuffer(mNativeState, elementArrayBuffer));
// Only compute the index range if the attributes also need to be streamed
if (attributesNeedStreaming)
{
......@@ -279,10 +298,11 @@ angle::Result VertexArrayGL::syncIndexData(const gl::Context *context,
mStreamingElementArrayBufferSize = 0;
}
stateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
stateManager->bindVertexArray(mVertexArrayID, mNativeState);
stateManager->bindBuffer(gl::BufferBinding::ElementArray, mStreamingElementArrayBuffer);
mAppliedElementArrayBuffer.set(context, nullptr);
mElementArrayBuffer.set(context, nullptr);
mNativeState->elementArrayBuffer = mStreamingElementArrayBuffer;
// Make sure the element array buffer is large enough
const GLuint indexTypeBytes = gl::GetDrawElementsTypeSize(type);
......@@ -381,7 +401,7 @@ angle::Result VertexArrayGL::streamAttributes(
mStreamingArrayBufferSize = requiredBufferSize;
}
stateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
stateManager->bindVertexArray(mVertexArrayID, mNativeState);
// Unmapping a buffer can return GL_FALSE to indicate that the system has corrupted the data
// somehow (such as by a screen change), retry writing the data a few times and return
......@@ -500,14 +520,15 @@ angle::Result VertexArrayGL::streamAttributes(
static_cast<GLintptr>(vertexStartOffset));
// Update the state to track the streamed attribute
mAppliedAttributes[idx].format = attrib.format;
mNativeState->attributes[idx].format = attrib.format;
mAppliedAttributes[idx].relativeOffset = 0;
mAppliedAttributes[idx].bindingIndex = static_cast<GLuint>(idx);
mNativeState->attributes[idx].relativeOffset = 0;
mNativeState->attributes[idx].bindingIndex = static_cast<GLuint>(idx);
mAppliedBindings[idx].setStride(static_cast<GLsizei>(destStride));
mAppliedBindings[idx].setOffset(static_cast<GLintptr>(vertexStartOffset));
mAppliedBindings[idx].setBuffer(context, nullptr);
mNativeState->bindings[idx].stride = static_cast<GLsizei>(destStride);
mNativeState->bindings[idx].offset = static_cast<GLintptr>(vertexStartOffset);
mArrayBuffers[idx].set(context, nullptr);
mNativeState->bindings[idx].buffer = mStreamingArrayBuffer;
// There's maxAttributeDataSize * indexRange.start of empty space allocated for each
// streaming attributes
......@@ -541,7 +562,7 @@ void VertexArrayGL::recoverForcedStreamingAttributesForDrawArraysInstanced(
StateManagerGL *stateManager = GetStateManagerGL(context);
stateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
stateManager->bindVertexArray(mVertexArrayID, mNativeState);
const auto &attribs = mState.getVertexAttributes();
const auto &bindings = mState.getVertexBindings();
......@@ -559,14 +580,15 @@ void VertexArrayGL::recoverForcedStreamingAttributesForDrawArraysInstanced(
static_cast<GLintptr>(binding.getOffset()));
// Restore the state to track their original buffers
mAppliedAttributes[idx].format = attrib.format;
mNativeState->attributes[idx].format = attrib.format;
mAppliedAttributes[idx].relativeOffset = 0;
mAppliedAttributes[idx].bindingIndex = static_cast<GLuint>(attrib.bindingIndex);
mNativeState->attributes[idx].relativeOffset = 0;
mNativeState->attributes[idx].bindingIndex = static_cast<GLuint>(attrib.bindingIndex);
mAppliedBindings[idx].setStride(binding.getStride());
mAppliedBindings[idx].setOffset(binding.getOffset());
mAppliedBindings[idx].setBuffer(context, binding.getBuffer().get());
mNativeState->bindings[idx].stride = binding.getStride();
mNativeState->bindings[idx].offset = binding.getOffset();
mArrayBuffers[idx].set(context, binding.getBuffer().get());
mNativeState->bindings[idx].buffer = buffer->getBufferID();
}
attributeMask->reset();
......@@ -578,21 +600,16 @@ GLuint VertexArrayGL::getVertexArrayID() const
return mVertexArrayID;
}
GLuint VertexArrayGL::getAppliedElementArrayBufferID() const
rx::VertexArrayStateGL *VertexArrayGL::getNativeState() const
{
if (mAppliedElementArrayBuffer.get() == nullptr)
{
return mStreamingElementArrayBuffer;
}
return GetImplAs<BufferGL>(mAppliedElementArrayBuffer.get())->getBufferID();
return mNativeState;
}
void VertexArrayGL::updateAttribEnabled(const gl::Context *context, size_t attribIndex)
{
const bool enabled = mState.getVertexAttribute(attribIndex).enabled &
mProgramActiveAttribLocationsMask.test(attribIndex);
if (mAppliedAttributes[attribIndex].enabled == enabled)
if (mNativeState->attributes[attribIndex].enabled == enabled)
{
return;
}
......@@ -608,7 +625,7 @@ void VertexArrayGL::updateAttribEnabled(const gl::Context *context, size_t attri
functions->disableVertexAttribArray(static_cast<GLuint>(attribIndex));
}
mAppliedAttributes[attribIndex].enabled = enabled;
mNativeState->attributes[attribIndex].enabled = enabled;
}
void VertexArrayGL::updateAttribPointer(const gl::Context *context, size_t attribIndex)
......@@ -626,21 +643,23 @@ void VertexArrayGL::updateAttribPointer(const gl::Context *context, size_t attri
// - Skip the attribute whose buffer is detached by BindVertexBuffer. Since it cannot have a
// client memory pointer either, it must be disabled and shouldn't affect the draw.
const auto &bindingBuffer = binding.getBuffer();
const Buffer *arrayBuffer = bindingBuffer.get();
gl::Buffer *arrayBuffer = bindingBuffer.get();
if (arrayBuffer == nullptr)
{
// Mark the applied binding isn't using a buffer by setting its buffer to nullptr so that if
// it starts to use a buffer later, there is no chance that the caching will skip it.
mAppliedBindings[attribIndex].setBuffer(context, nullptr);
mArrayBuffers[attribIndex].set(context, nullptr);
mNativeState->bindings[attribIndex].buffer = 0;
return;
}
// We do not need to compare attrib.pointer because when we use a different client memory
// pointer, we don't need to update mAttributesNeedStreaming by binding.buffer and we won't
// update attribPointer in this function.
if ((SameVertexAttribFormat(mAppliedAttributes[attribIndex], attrib)) &&
(mAppliedAttributes[attribIndex].bindingIndex == attrib.bindingIndex) &&
(SameVertexBuffer(mAppliedBindings[attribIndex], binding)))
if ((SameVertexAttribFormat(mNativeState->attributes[attribIndex], attrib)) &&
(mNativeState->attributes[attribIndex].bindingIndex == attrib.bindingIndex) &&
(SameVertexBuffer(mNativeState->bindings[attribIndex], binding)))
{
return;
}
......@@ -651,24 +670,25 @@ void VertexArrayGL::updateAttribPointer(const gl::Context *context, size_t attri
// zero is bound to the ARRAY_BUFFER buffer object binding point, and the pointer argument
// is not NULL.
StateManagerGL *stateManager = GetStateManagerGL(context);
const BufferGL *arrayBufferGL = GetImplAs<BufferGL>(arrayBuffer);
stateManager->bindBuffer(gl::BufferBinding::Array, arrayBufferGL->getBufferID());
StateManagerGL *stateManager = GetStateManagerGL(context);
GLuint bufferId = GetNativeBufferID(arrayBuffer);
stateManager->bindBuffer(gl::BufferBinding::Array, bufferId);
callVertexAttribPointer(context, static_cast<GLuint>(attribIndex), attrib, binding.getStride(),
binding.getOffset());
mAppliedAttributes[attribIndex].format = attrib.format;
mNativeState->attributes[attribIndex].format = attrib.format;
// After VertexAttribPointer, attrib.relativeOffset is set to 0 and attrib.bindingIndex is set
// to attribIndex in driver. If attrib.relativeOffset != 0 or attrib.bindingIndex !=
// attribIndex, they should be set in updateAttribFormat and updateAttribBinding. The cache
// should be consistent with driver so that we won't miss anything.
mAppliedAttributes[attribIndex].relativeOffset = 0;
mAppliedAttributes[attribIndex].bindingIndex = static_cast<GLuint>(attribIndex);
mNativeState->attributes[attribIndex].relativeOffset = 0;
mNativeState->attributes[attribIndex].bindingIndex = static_cast<GLuint>(attribIndex);
mAppliedBindings[attribIndex].setStride(binding.getStride());
mAppliedBindings[attribIndex].setOffset(binding.getOffset());
mAppliedBindings[attribIndex].setBuffer(context, binding.getBuffer().get());
mNativeState->bindings[attribIndex].stride = binding.getStride();
mNativeState->bindings[attribIndex].offset = binding.getOffset();
mArrayBuffers[attribIndex].set(context, arrayBuffer);
mNativeState->bindings[attribIndex].buffer = bufferId;
}
void VertexArrayGL::callVertexAttribPointer(const gl::Context *context,
......@@ -696,9 +716,13 @@ void VertexArrayGL::callVertexAttribPointer(const gl::Context *context,
bool VertexArrayGL::supportVertexAttribBinding(const gl::Context *context) const
{
const FunctionsGL *functions = GetFunctionsGL(context);
const FunctionsGL *functions = GetFunctionsGL(context);
const angle::FeaturesGL &features = GetFeaturesGL(context);
ASSERT(functions);
return (functions->vertexAttribBinding != nullptr);
// Vertex attrib bindings are not supported on the default VAO so if we're syncing to the
// default VAO due to the feature, disable bindings.
return (functions->vertexAttribBinding != nullptr) &&
!features.syncVertexArraysToDefault.enabled;
}
void VertexArrayGL::updateAttribFormat(const gl::Context *context, size_t attribIndex)
......@@ -706,7 +730,7 @@ void VertexArrayGL::updateAttribFormat(const gl::Context *context, size_t attrib
ASSERT(supportVertexAttribBinding(context));
const VertexAttribute &attrib = mState.getVertexAttribute(attribIndex);
if (SameVertexAttribFormat(mAppliedAttributes[attribIndex], attrib))
if (SameVertexAttribFormat(mNativeState->attributes[attribIndex], attrib))
{
return;
}
......@@ -728,8 +752,8 @@ void VertexArrayGL::updateAttribFormat(const gl::Context *context, size_t attrib
attrib.relativeOffset);
}
mAppliedAttributes[attribIndex].format = attrib.format;
mAppliedAttributes[attribIndex].relativeOffset = attrib.relativeOffset;
mNativeState->attributes[attribIndex].format = attrib.format;
mNativeState->attributes[attribIndex].relativeOffset = attrib.relativeOffset;
}
void VertexArrayGL::updateAttribBinding(const gl::Context *context, size_t attribIndex)
......@@ -737,7 +761,7 @@ void VertexArrayGL::updateAttribBinding(const gl::Context *context, size_t attri
ASSERT(supportVertexAttribBinding(context));
GLuint bindingIndex = mState.getVertexAttribute(attribIndex).bindingIndex;
if (mAppliedAttributes[attribIndex].bindingIndex == bindingIndex)
if (mNativeState->attributes[attribIndex].bindingIndex == bindingIndex)
{
return;
}
......@@ -745,7 +769,7 @@ void VertexArrayGL::updateAttribBinding(const gl::Context *context, size_t attri
const FunctionsGL *functions = GetFunctionsGL(context);
functions->vertexAttribBinding(static_cast<GLuint>(attribIndex), bindingIndex);
mAppliedAttributes[attribIndex].bindingIndex = bindingIndex;
mNativeState->attributes[attribIndex].bindingIndex = bindingIndex;
}
void VertexArrayGL::updateBindingBuffer(const gl::Context *context, size_t bindingIndex)
......@@ -753,32 +777,29 @@ void VertexArrayGL::updateBindingBuffer(const gl::Context *context, size_t bindi
ASSERT(supportVertexAttribBinding(context));
const VertexBinding &binding = mState.getVertexBinding(bindingIndex);
if (SameVertexBuffer(mAppliedBindings[bindingIndex], binding))
if (SameVertexBuffer(mNativeState->bindings[bindingIndex], binding))
{
return;
}
const Buffer *arrayBuffer = binding.getBuffer().get();
GLuint bufferId = 0;
if (arrayBuffer != nullptr)
{
bufferId = GetImplAs<BufferGL>(arrayBuffer)->getBufferID();
}
gl::Buffer *arrayBuffer = binding.getBuffer().get();
GLuint bufferId = GetNativeBufferID(arrayBuffer);
const FunctionsGL *functions = GetFunctionsGL(context);
functions->bindVertexBuffer(static_cast<GLuint>(bindingIndex), bufferId, binding.getOffset(),
binding.getStride());
mAppliedBindings[bindingIndex].setStride(binding.getStride());
mAppliedBindings[bindingIndex].setOffset(binding.getOffset());
mAppliedBindings[bindingIndex].setBuffer(context, binding.getBuffer().get());
mNativeState->bindings[bindingIndex].stride = binding.getStride();
mNativeState->bindings[bindingIndex].offset = binding.getOffset();
mArrayBuffers[bindingIndex].set(context, arrayBuffer);
mNativeState->bindings[bindingIndex].buffer = bufferId;
}
void VertexArrayGL::updateBindingDivisor(const gl::Context *context, size_t bindingIndex)
{
GLuint adjustedDivisor =
GetAdjustedDivisor(mAppliedNumViews, mState.getVertexBinding(bindingIndex).getDivisor());
if (mAppliedBindings[bindingIndex].getDivisor() == adjustedDivisor)
if (mNativeState->bindings[bindingIndex].divisor == adjustedDivisor)
{
return;
}
......@@ -795,8 +816,6 @@ void VertexArrayGL::updateBindingDivisor(const gl::Context *context, size_t bind
functions->vertexAttribDivisor(static_cast<GLuint>(bindingIndex), adjustedDivisor);
}
mAppliedBindings[bindingIndex].setDivisor(adjustedDivisor);
if (adjustedDivisor > 0)
{
mInstancedAttributesMask.set(bindingIndex);
......@@ -806,6 +825,8 @@ void VertexArrayGL::updateBindingDivisor(const gl::Context *context, size_t bind
// divisor is reset to 0
mInstancedAttributesMask.reset(bindingIndex);
}
mNativeState->bindings[bindingIndex].divisor = adjustedDivisor;
}
void VertexArrayGL::syncDirtyAttrib(const gl::Context *context,
......@@ -892,7 +913,7 @@ angle::Result VertexArrayGL::syncState(const gl::Context *context,
gl::VertexArray::DirtyBindingBitsArray *bindingBits)
{
StateManagerGL *stateManager = GetStateManagerGL(context);
stateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
stateManager->bindVertexArray(mVertexArrayID, mNativeState);
for (size_t dirtyBit : dirtyBits)
{
......@@ -923,9 +944,9 @@ void VertexArrayGL::applyNumViewsToDivisor(const gl::Context *context, int numVi
if (numViews != mAppliedNumViews)
{
StateManagerGL *stateManager = GetStateManagerGL(context);
stateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
stateManager->bindVertexArray(mVertexArrayID, mNativeState);
mAppliedNumViews = numViews;
for (size_t index = 0u; index < mAppliedBindings.size(); ++index)
for (size_t index = 0u; index < mNativeState->bindings.size(); ++index)
{
updateBindingDivisor(context, index);
}
......@@ -959,41 +980,31 @@ void VertexArrayGL::validateState(const gl::Context *context) const
"mVertexArrayID", "GL_VERTEX_ARRAY_BINDING");
// Element array buffer
if (mAppliedElementArrayBuffer.get() == nullptr)
{
ValidateStateHelperGetIntegerv(
functions, mStreamingElementArrayBuffer, GL_ELEMENT_ARRAY_BUFFER_BINDING,
"mAppliedElementArrayBuffer", "GL_ELEMENT_ARRAY_BUFFER_BINDING");
}
else
{
const BufferGL *bufferGL = GetImplAs<BufferGL>(mAppliedElementArrayBuffer.get());
ValidateStateHelperGetIntegerv(
functions, bufferGL->getBufferID(), GL_ELEMENT_ARRAY_BUFFER_BINDING,
"mAppliedElementArrayBuffer", "GL_ELEMENT_ARRAY_BUFFER_BINDING");
}
ValidateStateHelperGetIntegerv(
functions, mNativeState->elementArrayBuffer, GL_ELEMENT_ARRAY_BUFFER_BINDING,
"mNativeState->elementArrayBuffer", "GL_ELEMENT_ARRAY_BUFFER_BINDING");
// ValidateStateHelperGetIntegerv but with > comparison instead of !=
GLint queryValue;
functions->getIntegerv(GL_MAX_VERTEX_ATTRIBS, &queryValue);
if (mAppliedAttributes.size() > static_cast<GLuint>(queryValue))
if (mNativeState->attributes.size() > static_cast<GLuint>(queryValue))
{
WARN() << "mAppliedAttributes.size() (" << mAppliedAttributes.size()
WARN() << "mNativeState->attributes.size() (" << mNativeState->attributes.size()
<< ") > GL_MAX_VERTEX_ATTRIBS (" << queryValue << ")";
// Re-add ASSERT: http://anglebug.com/3900
// ASSERT(false);
}
// Check each applied attribute/binding
for (GLuint index = 0; index < mAppliedAttributes.size(); index++)
for (GLuint index = 0; index < mNativeState->attributes.size(); index++)
{
VertexAttribute &attribute = mAppliedAttributes[index];
ASSERT(attribute.bindingIndex < mAppliedBindings.size());
VertexBinding &binding = mAppliedBindings[attribute.bindingIndex];
VertexAttributeGL &attribute = mNativeState->attributes[index];
ASSERT(attribute.bindingIndex < mNativeState->bindings.size());
VertexBindingGL &binding = mNativeState->bindings[attribute.bindingIndex];
ValidateStateHelperGetVertexAttribiv(
functions, index, attribute.enabled, GL_VERTEX_ATTRIB_ARRAY_ENABLED,
"mAppliedAttributes.enabled", "GL_VERTEX_ATTRIB_ARRAY_ENABLED");
"mNativeState->attributes.enabled", "GL_VERTEX_ATTRIB_ARRAY_ENABLED");
if (attribute.enabled)
{
......@@ -1001,7 +1012,7 @@ void VertexArrayGL::validateState(const gl::Context *context) const
ASSERT(attribute.format);
ValidateStateHelperGetVertexAttribiv(
functions, index, ToGLenum(attribute.format->vertexAttribType),
GL_VERTEX_ATTRIB_ARRAY_TYPE, "mAppliedAttributes.format->vertexAttribType",
GL_VERTEX_ATTRIB_ARRAY_TYPE, "mNativeState->attributes.format->vertexAttribType",
"GL_VERTEX_ATTRIB_ARRAY_TYPE");
ValidateStateHelperGetVertexAttribiv(
functions, index, attribute.format->channelCount, GL_VERTEX_ATTRIB_ARRAY_SIZE,
......@@ -1023,26 +1034,17 @@ void VertexArrayGL::validateState(const gl::Context *context) const
}
// Applied bindings
if (binding.getBuffer().get() == nullptr)
{
ValidateStateHelperGetVertexAttribiv(
functions, index, mStreamingArrayBuffer, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING,
"mAppliedBindings.bufferID", "GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING");
}
else
ValidateStateHelperGetVertexAttribiv(
functions, index, binding.buffer, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING,
"binding.buffer", "GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING");
if (binding.buffer != 0)
{
const BufferGL *arrayBufferGL = GetImplAs<BufferGL>(binding.getBuffer().get());
ASSERT(arrayBufferGL);
ValidateStateHelperGetVertexAttribiv(functions, index, arrayBufferGL->getBufferID(),
GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING,
"mAppliedBindings.bufferID",
"GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING");
ValidateStateHelperGetVertexAttribiv(
functions, index, binding.getStride(), GL_VERTEX_ATTRIB_ARRAY_STRIDE,
"binding.getStride()", "GL_VERTEX_ATTRIB_ARRAY_STRIDE");
functions, index, binding.stride, GL_VERTEX_ATTRIB_ARRAY_STRIDE,
"binding.stride", "GL_VERTEX_ATTRIB_ARRAY_STRIDE");
ValidateStateHelperGetVertexAttribiv(
functions, index, binding.getDivisor(), GL_VERTEX_ATTRIB_ARRAY_DIVISOR,
"binding.getDivisor()", "GL_VERTEX_ATTRIB_ARRAY_DIVISOR");
functions, index, binding.divisor, GL_VERTEX_ATTRIB_ARRAY_DIVISOR,
"binding.divisor", "GL_VERTEX_ATTRIB_ARRAY_DIVISOR");
}
}
}
......
......@@ -20,11 +20,13 @@ namespace rx
class FunctionsGL;
class StateManagerGL;
struct VertexArrayStateGL;
class VertexArrayGL : public VertexArrayImpl
{
public:
VertexArrayGL(const gl::VertexArrayState &data, GLuint id);
VertexArrayGL(const gl::VertexArrayState &data, GLuint id, VertexArrayStateGL *sharedState);
~VertexArrayGL() override;
void destroy(const gl::Context *context) override;
......@@ -44,7 +46,7 @@ class VertexArrayGL : public VertexArrayImpl
const void **outIndices) const;
GLuint getVertexArrayID() const;
GLuint getAppliedElementArrayBufferID() const;
VertexArrayStateGL *getNativeState() const;
angle::Result syncState(const gl::Context *context,
const gl::VertexArray::DirtyBits &dirtyBits,
......@@ -123,23 +125,24 @@ class VertexArrayGL : public VertexArrayImpl
const gl::Context *context,
gl::AttributesMask *attributeMask) const;
GLuint mVertexArrayID;
int mAppliedNumViews;
GLuint mVertexArrayID = 0;
int mAppliedNumViews = 1;
// Remember the program's active attrib location mask so that attributes can be enabled/disabled
// based on whether they are active in the program
gl::AttributesMask mProgramActiveAttribLocationsMask;
mutable gl::BindingPointer<gl::Buffer> mAppliedElementArrayBuffer;
bool mOwnsNativeState = false;
VertexArrayStateGL *mNativeState = nullptr;
mutable std::vector<gl::VertexAttribute> mAppliedAttributes;
mutable std::vector<gl::VertexBinding> mAppliedBindings;
mutable gl::BindingPointer<gl::Buffer> mElementArrayBuffer;
mutable std::array<gl::BindingPointer<gl::Buffer>, gl::MAX_VERTEX_ATTRIBS> mArrayBuffers;
mutable size_t mStreamingElementArrayBufferSize;
mutable GLuint mStreamingElementArrayBuffer;
mutable size_t mStreamingElementArrayBufferSize = 0;
mutable GLuint mStreamingElementArrayBuffer = 0;
mutable size_t mStreamingArrayBufferSize;
mutable GLuint mStreamingArrayBuffer;
mutable size_t mStreamingArrayBufferSize = 0;
mutable GLuint mStreamingArrayBuffer = 0;
// Used for Mac Intel instanced draw workaround
mutable gl::AttributesMask mForcedStreamingAttributesForDrawArraysInstancedMask;
......
......@@ -1309,6 +1309,13 @@ void GenerateCaps(const FunctionsGL *functions,
LimitVersion(maxSupportedESVersion, gl::Version(3, 1));
}
if (!nativegl::SupportsVertexArrayObjects(functions) ||
features.syncVertexArraysToDefault.enabled)
{
// ES 3.1 vertex bindings are not emulated on the default vertex array
LimitVersion(maxSupportedESVersion, gl::Version(3, 0));
}
// Extension support
extensions->setTextureExtensionSupport(*textureCapsMap);
extensions->textureCompressionASTCHDRKHR =
......@@ -2080,6 +2087,8 @@ void InitializeFeatures(const FunctionsGL *functions, angle::FeaturesGL *feature
// now.
ANGLE_FEATURE_CONDITION(features, shiftInstancedArrayDataWithExtraOffset,
IsApple() && IsIntel(vendor) && !IsHaswell(device));
ANGLE_FEATURE_CONDITION(features, syncVertexArraysToDefault,
!nativegl::SupportsVertexArrayObjects(functions));
}
void InitializeFrontendFeatures(const FunctionsGL *functions, angle::FrontendFeatures *features)
......@@ -2112,6 +2121,20 @@ void ReInitializeFeaturesAtGPUSwitch(const FunctionsGL *functions, angle::Featur
namespace nativegl
{
bool SupportsVertexArrayObjects(const FunctionsGL *functions)
{
return functions->isAtLeastGLES(gl::Version(3, 0)) ||
functions->hasGLESExtension("GL_OES_vertex_array_object") ||
functions->isAtLeastGL(gl::Version(3, 0)) ||
functions->hasGLExtension("GL_ARB_vertex_array_object");
}
bool CanUseDefaultVertexArrayObject(const FunctionsGL *functions)
{
return (functions->profile & GL_CONTEXT_CORE_PROFILE_BIT) == 0;
}
bool SupportsCompute(const FunctionsGL *functions)
{
// OpenGL 4.2 is required for GL_ARB_compute_shader, some platform drivers have the extension,
......
......@@ -113,6 +113,8 @@ void ReInitializeFeaturesAtGPUSwitch(const FunctionsGL *functions, angle::Featur
namespace nativegl
{
bool SupportsVertexArrayObjects(const FunctionsGL *functions);
bool CanUseDefaultVertexArrayObject(const FunctionsGL *functions);
bool SupportsCompute(const FunctionsGL *functions);
bool SupportsFenceSync(const FunctionsGL *functions);
bool SupportsOcclusionQueries(const FunctionsGL *functions);
......
......@@ -3631,6 +3631,15 @@ void main()
}
}
// VAO emulation fails on Mac but is not used on Mac in the wild. http://anglebug.com/5577
#if !defined(__APPLE__)
# define EMULATED_VAO_CONFIGS \
WithEmulatedVAOs(ES2_OPENGL()), WithEmulatedVAOs(ES2_OPENGLES()), \
WithEmulatedVAOs(ES3_OPENGL()), WithEmulatedVAOs(ES3_OPENGLES()),
#else
# define EMULATED_VAO_CONFIGS
#endif
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against.
// D3D11 Feature Level 9_3 uses different D3D formats for vertex attribs compared to Feature Levels
......@@ -3642,7 +3651,8 @@ ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND(
/* cheapRenderPass */ true),
WithMetalMemoryBarrierAndCheapRenderPass(ES3_METAL(),
/* hasBarrier */ false,
/* cheapRenderPass */ false));
/* cheapRenderPass */ false),
EMULATED_VAO_CONFIGS);
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND(
VertexAttributeOORTest,
......
......@@ -268,6 +268,11 @@ std::ostream &operator<<(std::ostream &stream, const PlatformParameters &pp)
stream << "_NoVulkanViewportFlip";
}
if (pp.eglParameters.emulatedVAOs == EGL_TRUE)
{
stream << "_EmulatedVAOs";
}
return stream;
}
......
......@@ -289,6 +289,14 @@ inline PlatformParameters WithNoVulkanViewportFlip(const PlatformParameters &par
withoutVulkanViewportFlip.eglParameters.supportsVulkanViewportFlip = EGL_FALSE;
return withoutVulkanViewportFlip;
}
inline PlatformParameters WithEmulatedVAOs(const PlatformParameters &params)
{
PlatformParameters emualtedVAOParams = params;
emualtedVAOParams.eglParameters.emulatedVAOs = EGL_TRUE;
return emualtedVAOParams;
}
} // namespace angle
#endif // ANGLE_TEST_CONFIGS_H_
......@@ -64,7 +64,7 @@ struct EGLPlatformParameters
shaderStencilOutputFeature, genMultipleMipsPerPassFeature, platformMethods,
robustness, emulatedPrerotation, asyncCommandQueueFeatureVulkan,
hasExplicitMemBarrierFeatureMtl, hasCheapRenderPassFeatureMtl,
forceBufferGPUStorageFeatureMtl, supportsVulkanViewportFlip);
forceBufferGPUStorageFeatureMtl, supportsVulkanViewportFlip, emulatedVAOs);
}
EGLint renderer = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE;
......@@ -86,6 +86,7 @@ struct EGLPlatformParameters
EGLint hasCheapRenderPassFeatureMtl = EGL_DONT_CARE;
EGLint forceBufferGPUStorageFeatureMtl = EGL_DONT_CARE;
EGLint supportsVulkanViewportFlip = EGL_DONT_CARE;
EGLint emulatedVAOs = EGL_DONT_CARE;
angle::PlatformMethods *platformMethods = nullptr;
};
......
......@@ -263,6 +263,11 @@ bool EGLWindow::initializeDisplay(OSWindow *osWindow,
enabledFeatureOverrides.push_back("force_buffer_gpu_storage_mtl");
}
if (params.emulatedVAOs == EGL_TRUE)
{
enabledFeatureOverrides.push_back("sync_vertex_arrays_to_default");
}
const bool hasFeatureControlANGLE =
strstr(extensionString, "EGL_ANGLE_feature_control") != nullptr;
......
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