Commit 976489b2 by Geoff Lang

Don't allocate VertexArray or TransformFeedback objects until binding.

Follow the spec more closely and only reserve IDs of vertex arrays and transform feedback objects before binding. This saves memory and allows the glIs* calls to succeed. BUG=angleproject:1218 BUG=angleproject:1101 Change-Id: I7bf99870a7c93f5545325785cbecd891c6b77f8a Reviewed-on: https://chromium-review.googlesource.com/316402Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Tested-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent adf825b3
......@@ -144,8 +144,6 @@ Context::Context(const egl::Config *config,
// In the initial state, a default transform feedback object is bound and treated as
// a transform feedback object with a name of zero. That object is bound any time
// BindTransformFeedback is called with id of zero
mTransformFeedbackZero.set(
new TransformFeedback(mRenderer->createTransformFeedback(), 0, mCaps));
bindTransformFeedback(0);
}
......@@ -189,10 +187,12 @@ Context::~Context()
SafeDelete(vertexArray.second);
}
mTransformFeedbackZero.set(NULL);
for (auto transformFeedback : mTransformFeedbackMap)
{
transformFeedback.second->release();
if (transformFeedback.second != nullptr)
{
transformFeedback.second->release();
}
}
for (auto &zeroTexture : mZeroTextures)
......@@ -324,14 +324,9 @@ GLsync Context::createFenceSync()
GLuint Context::createVertexArray()
{
GLuint handle = mVertexArrayHandleAllocator.allocate();
// Although the spec states VAO state is not initialized until the object is bound,
// we create it immediately. The resulting behaviour is transparent to the application,
// since it's not currently possible to access the state until the object is bound.
VertexArray *vertexArray = new VertexArray(mRenderer, handle, MAX_VERTEX_ATTRIBS);
mVertexArrayMap[handle] = vertexArray;
return handle;
GLuint vertexArray = mVertexArrayHandleAllocator.allocate();
mVertexArrayMap[vertexArray] = nullptr;
return vertexArray;
}
GLuint Context::createSampler()
......@@ -341,11 +336,9 @@ GLuint Context::createSampler()
GLuint Context::createTransformFeedback()
{
GLuint handle = mTransformFeedbackAllocator.allocate();
TransformFeedback *transformFeedback = new TransformFeedback(mRenderer->createTransformFeedback(), handle, mCaps);
transformFeedback->addRef();
mTransformFeedbackMap[handle] = transformFeedback;
return handle;
GLuint transformFeedback = mTransformFeedbackAllocator.allocate();
mTransformFeedbackMap[transformFeedback] = nullptr;
return transformFeedback;
}
// Returns an unused framebuffer name
......@@ -428,15 +421,18 @@ void Context::deleteFenceSync(GLsync fenceSync)
void Context::deleteVertexArray(GLuint vertexArray)
{
auto vertexArrayObject = mVertexArrayMap.find(vertexArray);
if (vertexArrayObject != mVertexArrayMap.end())
auto iter = mVertexArrayMap.find(vertexArray);
if (iter != mVertexArrayMap.end())
{
detachVertexArray(vertexArray);
VertexArray *vertexArrayObject = iter->second;
if (vertexArrayObject != nullptr)
{
detachVertexArray(vertexArray);
delete vertexArrayObject;
}
mVertexArrayHandleAllocator.release(vertexArrayObject->first);
delete vertexArrayObject->second;
mVertexArrayMap.erase(vertexArrayObject);
mVertexArrayMap.erase(iter);
mVertexArrayHandleAllocator.release(vertexArray);
}
}
......@@ -455,10 +451,15 @@ void Context::deleteTransformFeedback(GLuint transformFeedback)
auto iter = mTransformFeedbackMap.find(transformFeedback);
if (iter != mTransformFeedbackMap.end())
{
detachTransformFeedback(transformFeedback);
mTransformFeedbackAllocator.release(transformFeedback);
iter->second->release();
TransformFeedback *transformFeedbackObject = iter->second;
if (transformFeedbackObject != nullptr)
{
detachTransformFeedback(transformFeedback);
transformFeedbackObject->release();
}
mTransformFeedbackMap.erase(iter);
mTransformFeedbackAllocator.release(transformFeedback);
}
}
......@@ -553,15 +554,8 @@ Sampler *Context::getSampler(GLuint handle) const
TransformFeedback *Context::getTransformFeedback(GLuint handle) const
{
if (handle == 0)
{
return mTransformFeedbackZero.get();
}
else
{
TransformFeedbackMap::const_iterator iter = mTransformFeedbackMap.find(handle);
return (iter != mTransformFeedbackMap.end()) ? iter->second : NULL;
}
auto iter = mTransformFeedbackMap.find(handle);
return (iter != mTransformFeedbackMap.end()) ? iter->second : nullptr;
}
bool Context::isSampler(GLuint samplerName) const
......@@ -631,11 +625,7 @@ void Context::bindRenderbuffer(GLuint renderbuffer)
void Context::bindVertexArray(GLuint vertexArray)
{
if (!getVertexArray(vertexArray))
{
VertexArray *vertexArrayObject = new VertexArray(mRenderer, vertexArray, MAX_VERTEX_ATTRIBS);
mVertexArrayMap[vertexArray] = vertexArrayObject;
}
checkVertexArrayAllocation(vertexArray);
mState.setVertexArrayBinding(getVertexArray(vertexArray));
}
......@@ -711,6 +701,8 @@ void Context::useProgram(GLuint program)
void Context::bindTransformFeedback(GLuint transformFeedback)
{
checkTransformFeedbackAllocation(transformFeedback);
mState.setTransformFeedbackBinding(getTransformFeedback(transformFeedback));
}
......@@ -1493,6 +1485,37 @@ EGLenum Context::getRenderBuffer() const
}
}
void Context::checkVertexArrayAllocation(GLuint vertexArray)
{
if (!getVertexArray(vertexArray))
{
VertexArray *vertexArrayObject =
new VertexArray(mRenderer, vertexArray, MAX_VERTEX_ATTRIBS);
mVertexArrayMap[vertexArray] = vertexArrayObject;
}
}
void Context::checkTransformFeedbackAllocation(GLuint transformFeedback)
{
if (!getTransformFeedback(transformFeedback))
{
TransformFeedback *transformFeedbackObject =
new TransformFeedback(mRenderer->createTransformFeedback(), transformFeedback, mCaps);
transformFeedbackObject->addRef();
mTransformFeedbackMap[transformFeedback] = transformFeedbackObject;
}
}
bool Context::isVertexArrayGenerated(GLuint vertexArray)
{
return mVertexArrayMap.find(vertexArray) != mVertexArrayMap.end();
}
bool Context::isTransformFeedbackGenerated(GLuint transformFeedback)
{
return mTransformFeedbackMap.find(transformFeedback) != mTransformFeedbackMap.end();
}
void Context::detachTexture(GLuint texture)
{
// Simple pass-through to State's detachTexture method, as textures do not require
......
......@@ -153,6 +153,9 @@ class Context final : public ValidationContext
bool isSampler(GLuint samplerName) const;
bool isVertexArrayGenerated(GLuint vertexArray);
bool isTransformFeedbackGenerated(GLuint vertexArray);
void getBooleanv(GLenum pname, GLboolean *params);
void getFloatv(GLenum pname, GLfloat *params);
void getIntegerv(GLenum pname, GLint *params);
......@@ -217,6 +220,9 @@ class Context final : public ValidationContext
void syncRendererState(const State::DirtyBits &bitMask);
private:
void checkVertexArrayAllocation(GLuint vertexArray);
void checkTransformFeedbackAllocation(GLuint transformFeedback);
void detachBuffer(GLuint buffer);
void detachTexture(GLuint texture);
void detachFramebuffer(GLuint framebuffer);
......@@ -265,7 +271,6 @@ class Context final : public ValidationContext
VertexArrayMap mVertexArrayMap;
HandleAllocator mVertexArrayHandleAllocator;
BindingPointer<TransformFeedback> mTransformFeedbackZero;
typedef std::map<GLuint, TransformFeedback*> TransformFeedbackMap;
TransformFeedbackMap mTransformFeedbackMap;
HandleAllocator mTransformFeedbackAllocator;
......
......@@ -1529,7 +1529,7 @@ void State::getIntegerv(const gl::Data &data, GLenum pname, GLint *params)
*params = mGenericUniformBuffer.id();
break;
case GL_TRANSFORM_FEEDBACK_BINDING:
*params = mTransformFeedback->id();
*params = mTransformFeedback.id();
break;
case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
*params = mTransformFeedback->getGenericBuffer().id();
......
......@@ -2191,9 +2191,7 @@ bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
bool ValidateBindVertexArrayBase(Context *context, GLuint array)
{
VertexArray *vao = context->getVertexArray(array);
if (!vao)
if (!context->isVertexArrayGenerated(array))
{
// The default VAO should always exist
ASSERT(array != 0);
......
......@@ -2924,9 +2924,11 @@ void GL_APIENTRY BindTransformFeedback(GLenum target, GLuint id)
}
// Cannot bind a transform feedback object that does not exist (3.0.2 pg 85 section 2.14.1)
if (context->getTransformFeedback(id) == NULL)
if (!context->isTransformFeedbackGenerated(id))
{
context->recordError(Error(GL_INVALID_OPERATION));
context->recordError(
Error(GL_INVALID_OPERATION,
"Cannot bind a transform feedback object that does not exist."));
return;
}
......@@ -2994,7 +2996,15 @@ GLboolean GL_APIENTRY IsTransformFeedback(GLuint id)
return GL_FALSE;
}
return ((context->getTransformFeedback(id) != NULL) ? GL_TRUE : GL_FALSE);
if (id == 0)
{
// The 3.0.4 spec [section 6.1.11] states that if ID is zero, IsTransformFeedback
// returns FALSE
return GL_FALSE;
}
const TransformFeedback *transformFeedback = context->getTransformFeedback(id);
return ((transformFeedback != nullptr) ? GL_TRUE : GL_FALSE);
}
return GL_FALSE;
......
......@@ -678,8 +678,6 @@
1101 WIN : dEQP-GLES3.functional.negative_api.vertex_array.draw_range_elements_incomplete_primitive = FAIL
1101 WIN : dEQP-GLES3.functional.negative_api.state.get_buffer_pointerv = FAIL
1101 WIN : dEQP-GLES3.functional.negative_api.state.get_framebuffer_attachment_parameteriv = FAIL
1101 WIN : dEQP-GLES3.functional.negative_api.state.is_transform_feedback = FAIL
1101 WIN : dEQP-GLES3.functional.negative_api.state.is_vertex_array = FAIL
1101 WIN : dEQP-GLES3.functional.state_query.integers.uniform_buffer_binding_getboolean = FAIL
1101 WIN : dEQP-GLES3.functional.state_query.integers.uniform_buffer_binding_getinteger = FAIL
1101 WIN : dEQP-GLES3.functional.state_query.integers.uniform_buffer_binding_getinteger64 = FAIL
......
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