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, ...@@ -144,8 +144,6 @@ Context::Context(const egl::Config *config,
// In the initial state, a default transform feedback object is bound and treated as // 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 // a transform feedback object with a name of zero. That object is bound any time
// BindTransformFeedback is called with id of zero // BindTransformFeedback is called with id of zero
mTransformFeedbackZero.set(
new TransformFeedback(mRenderer->createTransformFeedback(), 0, mCaps));
bindTransformFeedback(0); bindTransformFeedback(0);
} }
...@@ -189,10 +187,12 @@ Context::~Context() ...@@ -189,10 +187,12 @@ Context::~Context()
SafeDelete(vertexArray.second); SafeDelete(vertexArray.second);
} }
mTransformFeedbackZero.set(NULL);
for (auto transformFeedback : mTransformFeedbackMap) for (auto transformFeedback : mTransformFeedbackMap)
{ {
transformFeedback.second->release(); if (transformFeedback.second != nullptr)
{
transformFeedback.second->release();
}
} }
for (auto &zeroTexture : mZeroTextures) for (auto &zeroTexture : mZeroTextures)
...@@ -324,14 +324,9 @@ GLsync Context::createFenceSync() ...@@ -324,14 +324,9 @@ GLsync Context::createFenceSync()
GLuint Context::createVertexArray() GLuint Context::createVertexArray()
{ {
GLuint handle = mVertexArrayHandleAllocator.allocate(); GLuint vertexArray = mVertexArrayHandleAllocator.allocate();
mVertexArrayMap[vertexArray] = nullptr;
// Although the spec states VAO state is not initialized until the object is bound, return vertexArray;
// 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 Context::createSampler() GLuint Context::createSampler()
...@@ -341,11 +336,9 @@ GLuint Context::createSampler() ...@@ -341,11 +336,9 @@ GLuint Context::createSampler()
GLuint Context::createTransformFeedback() GLuint Context::createTransformFeedback()
{ {
GLuint handle = mTransformFeedbackAllocator.allocate(); GLuint transformFeedback = mTransformFeedbackAllocator.allocate();
TransformFeedback *transformFeedback = new TransformFeedback(mRenderer->createTransformFeedback(), handle, mCaps); mTransformFeedbackMap[transformFeedback] = nullptr;
transformFeedback->addRef(); return transformFeedback;
mTransformFeedbackMap[handle] = transformFeedback;
return handle;
} }
// Returns an unused framebuffer name // Returns an unused framebuffer name
...@@ -428,15 +421,18 @@ void Context::deleteFenceSync(GLsync fenceSync) ...@@ -428,15 +421,18 @@ void Context::deleteFenceSync(GLsync fenceSync)
void Context::deleteVertexArray(GLuint vertexArray) void Context::deleteVertexArray(GLuint vertexArray)
{ {
auto vertexArrayObject = mVertexArrayMap.find(vertexArray); auto iter = mVertexArrayMap.find(vertexArray);
if (iter != mVertexArrayMap.end())
if (vertexArrayObject != mVertexArrayMap.end())
{ {
detachVertexArray(vertexArray); VertexArray *vertexArrayObject = iter->second;
if (vertexArrayObject != nullptr)
{
detachVertexArray(vertexArray);
delete vertexArrayObject;
}
mVertexArrayHandleAllocator.release(vertexArrayObject->first); mVertexArrayMap.erase(iter);
delete vertexArrayObject->second; mVertexArrayHandleAllocator.release(vertexArray);
mVertexArrayMap.erase(vertexArrayObject);
} }
} }
...@@ -455,10 +451,15 @@ void Context::deleteTransformFeedback(GLuint transformFeedback) ...@@ -455,10 +451,15 @@ void Context::deleteTransformFeedback(GLuint transformFeedback)
auto iter = mTransformFeedbackMap.find(transformFeedback); auto iter = mTransformFeedbackMap.find(transformFeedback);
if (iter != mTransformFeedbackMap.end()) if (iter != mTransformFeedbackMap.end())
{ {
detachTransformFeedback(transformFeedback); TransformFeedback *transformFeedbackObject = iter->second;
mTransformFeedbackAllocator.release(transformFeedback); if (transformFeedbackObject != nullptr)
iter->second->release(); {
detachTransformFeedback(transformFeedback);
transformFeedbackObject->release();
}
mTransformFeedbackMap.erase(iter); mTransformFeedbackMap.erase(iter);
mTransformFeedbackAllocator.release(transformFeedback);
} }
} }
...@@ -553,15 +554,8 @@ Sampler *Context::getSampler(GLuint handle) const ...@@ -553,15 +554,8 @@ Sampler *Context::getSampler(GLuint handle) const
TransformFeedback *Context::getTransformFeedback(GLuint handle) const TransformFeedback *Context::getTransformFeedback(GLuint handle) const
{ {
if (handle == 0) auto iter = mTransformFeedbackMap.find(handle);
{ return (iter != mTransformFeedbackMap.end()) ? iter->second : nullptr;
return mTransformFeedbackZero.get();
}
else
{
TransformFeedbackMap::const_iterator iter = mTransformFeedbackMap.find(handle);
return (iter != mTransformFeedbackMap.end()) ? iter->second : NULL;
}
} }
bool Context::isSampler(GLuint samplerName) const bool Context::isSampler(GLuint samplerName) const
...@@ -631,11 +625,7 @@ void Context::bindRenderbuffer(GLuint renderbuffer) ...@@ -631,11 +625,7 @@ void Context::bindRenderbuffer(GLuint renderbuffer)
void Context::bindVertexArray(GLuint vertexArray) void Context::bindVertexArray(GLuint vertexArray)
{ {
if (!getVertexArray(vertexArray)) checkVertexArrayAllocation(vertexArray);
{
VertexArray *vertexArrayObject = new VertexArray(mRenderer, vertexArray, MAX_VERTEX_ATTRIBS);
mVertexArrayMap[vertexArray] = vertexArrayObject;
}
mState.setVertexArrayBinding(getVertexArray(vertexArray)); mState.setVertexArrayBinding(getVertexArray(vertexArray));
} }
...@@ -711,6 +701,8 @@ void Context::useProgram(GLuint program) ...@@ -711,6 +701,8 @@ void Context::useProgram(GLuint program)
void Context::bindTransformFeedback(GLuint transformFeedback) void Context::bindTransformFeedback(GLuint transformFeedback)
{ {
checkTransformFeedbackAllocation(transformFeedback);
mState.setTransformFeedbackBinding(getTransformFeedback(transformFeedback)); mState.setTransformFeedbackBinding(getTransformFeedback(transformFeedback));
} }
...@@ -1493,6 +1485,37 @@ EGLenum Context::getRenderBuffer() const ...@@ -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) void Context::detachTexture(GLuint texture)
{ {
// Simple pass-through to State's detachTexture method, as textures do not require // Simple pass-through to State's detachTexture method, as textures do not require
......
...@@ -153,6 +153,9 @@ class Context final : public ValidationContext ...@@ -153,6 +153,9 @@ class Context final : public ValidationContext
bool isSampler(GLuint samplerName) const; bool isSampler(GLuint samplerName) const;
bool isVertexArrayGenerated(GLuint vertexArray);
bool isTransformFeedbackGenerated(GLuint vertexArray);
void getBooleanv(GLenum pname, GLboolean *params); void getBooleanv(GLenum pname, GLboolean *params);
void getFloatv(GLenum pname, GLfloat *params); void getFloatv(GLenum pname, GLfloat *params);
void getIntegerv(GLenum pname, GLint *params); void getIntegerv(GLenum pname, GLint *params);
...@@ -217,6 +220,9 @@ class Context final : public ValidationContext ...@@ -217,6 +220,9 @@ class Context final : public ValidationContext
void syncRendererState(const State::DirtyBits &bitMask); void syncRendererState(const State::DirtyBits &bitMask);
private: private:
void checkVertexArrayAllocation(GLuint vertexArray);
void checkTransformFeedbackAllocation(GLuint transformFeedback);
void detachBuffer(GLuint buffer); void detachBuffer(GLuint buffer);
void detachTexture(GLuint texture); void detachTexture(GLuint texture);
void detachFramebuffer(GLuint framebuffer); void detachFramebuffer(GLuint framebuffer);
...@@ -265,7 +271,6 @@ class Context final : public ValidationContext ...@@ -265,7 +271,6 @@ class Context final : public ValidationContext
VertexArrayMap mVertexArrayMap; VertexArrayMap mVertexArrayMap;
HandleAllocator mVertexArrayHandleAllocator; HandleAllocator mVertexArrayHandleAllocator;
BindingPointer<TransformFeedback> mTransformFeedbackZero;
typedef std::map<GLuint, TransformFeedback*> TransformFeedbackMap; typedef std::map<GLuint, TransformFeedback*> TransformFeedbackMap;
TransformFeedbackMap mTransformFeedbackMap; TransformFeedbackMap mTransformFeedbackMap;
HandleAllocator mTransformFeedbackAllocator; HandleAllocator mTransformFeedbackAllocator;
......
...@@ -1529,7 +1529,7 @@ void State::getIntegerv(const gl::Data &data, GLenum pname, GLint *params) ...@@ -1529,7 +1529,7 @@ void State::getIntegerv(const gl::Data &data, GLenum pname, GLint *params)
*params = mGenericUniformBuffer.id(); *params = mGenericUniformBuffer.id();
break; break;
case GL_TRANSFORM_FEEDBACK_BINDING: case GL_TRANSFORM_FEEDBACK_BINDING:
*params = mTransformFeedback->id(); *params = mTransformFeedback.id();
break; break;
case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
*params = mTransformFeedback->getGenericBuffer().id(); *params = mTransformFeedback->getGenericBuffer().id();
......
...@@ -2191,9 +2191,7 @@ bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context, ...@@ -2191,9 +2191,7 @@ bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
bool ValidateBindVertexArrayBase(Context *context, GLuint array) bool ValidateBindVertexArrayBase(Context *context, GLuint array)
{ {
VertexArray *vao = context->getVertexArray(array); if (!context->isVertexArrayGenerated(array))
if (!vao)
{ {
// The default VAO should always exist // The default VAO should always exist
ASSERT(array != 0); ASSERT(array != 0);
......
...@@ -2924,9 +2924,11 @@ void GL_APIENTRY BindTransformFeedback(GLenum target, GLuint id) ...@@ -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) // 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; return;
} }
...@@ -2994,7 +2996,15 @@ GLboolean GL_APIENTRY IsTransformFeedback(GLuint id) ...@@ -2994,7 +2996,15 @@ GLboolean GL_APIENTRY IsTransformFeedback(GLuint id)
return GL_FALSE; 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; return GL_FALSE;
......
...@@ -678,8 +678,6 @@ ...@@ -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.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_buffer_pointerv = FAIL
1101 WIN : dEQP-GLES3.functional.negative_api.state.get_framebuffer_attachment_parameteriv = 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_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_getinteger = FAIL
1101 WIN : dEQP-GLES3.functional.state_query.integers.uniform_buffer_binding_getinteger64 = 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