diff options
author | bajones@google.com <bajones@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-27 02:20:46 +0000 |
---|---|---|
committer | bajones@google.com <bajones@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-27 02:20:46 +0000 |
commit | 944b62f3edd69cee4fd31e21fb80ca0eafe9b217 (patch) | |
tree | 8ae5c82188ae1100fb60eb1e6ede8af2efdc73ee /gpu | |
parent | 01719f74ea916ef20b5df705a314c6b6fd659524 (diff) | |
download | chromium_src-944b62f3edd69cee4fd31e21fb80ca0eafe9b217.zip chromium_src-944b62f3edd69cee4fd31e21fb80ca0eafe9b217.tar.gz chromium_src-944b62f3edd69cee4fd31e21fb80ca0eafe9b217.tar.bz2 |
Added support for OES_vertex_array_object to the command buffer
BUG=72612
Review URL: https://chromiumcodereview.appspot.com/10915244
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@158967 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gpu')
35 files changed, 1592 insertions, 82 deletions
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py index 85cdc07..3b7596d 100755 --- a/gpu/command_buffer/build_gles2_cmd_buffer.py +++ b/gpu/command_buffer/build_gles2_cmd_buffer.py @@ -1730,6 +1730,35 @@ _FUNCTION_INFO = { 'expectation': False, 'impl_func': False, }, + + 'GenVertexArraysOES': { + 'type': 'GENn', + 'gl_test_func': 'glGenVertexArraysOES', + 'resource_type': 'VertexArray', + 'resource_types': 'VertexArrays', + 'unit_test': False, + }, + 'BindVertexArrayOES': { + 'type': 'Bind', + 'gl_test_func': 'glBindVertexArrayOES', + 'decoder_func': 'DoBindVertexArrayOES', + 'gen_func': 'GenVertexArraysOES', + 'unit_test': False, + }, + 'DeleteVertexArraysOES': { + 'type': 'DELn', + 'gl_test_func': 'glDeleteVertexArraysOES', + 'resource_type': 'VertexArray', + 'resource_types': 'VertexArrays', + 'unit_test': False, + }, + 'IsVertexArrayOES': { + 'type': 'Is', + 'gl_test_func': 'glIsVertexArrayOES', + 'decoder_func': 'DoIsVertexArrayOES', + 'expectation': False, + 'unit_test': False, + }, } @@ -2720,7 +2749,38 @@ class BindHandler(TypeHandler): def WriteServiceUnitTest(self, func, file): """Overrriden from TypeHandler.""" - valid_test = """ + + if len(func.GetOriginalArgs()) == 1: + valid_test = """ +TEST_F(%(test_name)s, %(name)sValidArgs) { + EXPECT_CALL(*gl_, %(gl_func_name)s(%(gl_args)s)); + SpecializedSetup<%(name)s, 0>(true); + %(name)s cmd; + cmd.Init(%(args)s); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +TEST_F(%(test_name)s, %(name)sValidArgsNewId) { + EXPECT_CALL(*gl_, %(gl_func_name)s(kNewServiceId)); + EXPECT_CALL(*gl_, %(gl_gen_func_name)s(1, _)) + .WillOnce(SetArgumentPointee<1>(kNewServiceId)); + SpecializedSetup<%(name)s, 0>(true); + %(name)s cmd; + cmd.Init(kNewClientId); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + EXPECT_TRUE(Get%(resource_type)sInfo(kNewClientId) != NULL); +} +""" + gen_func_names = { + } + self.WriteValidUnitTest(func, file, valid_test, { + 'resource_type': func.GetOriginalArgs()[0].resource_type, + 'gl_gen_func_name': func.GetInfo("gen_func"), + }) + else: + valid_test = """ TEST_F(%(test_name)s, %(name)sValidArgs) { EXPECT_CALL(*gl_, %(gl_func_name)s(%(gl_args)s)); SpecializedSetup<%(name)s, 0>(true); @@ -2742,14 +2802,14 @@ TEST_F(%(test_name)s, %(name)sValidArgsNewId) { EXPECT_TRUE(Get%(resource_type)sInfo(kNewClientId) != NULL); } """ - gen_func_names = { - } - self.WriteValidUnitTest(func, file, valid_test, { - 'first_arg': func.GetOriginalArgs()[0].GetValidArg(func, 0, 0), - 'first_gl_arg': func.GetOriginalArgs()[0].GetValidGLArg(func, 0, 0), - 'resource_type': func.GetOriginalArgs()[1].resource_type, - 'gl_gen_func_name': func.GetInfo("gen_func"), - }) + gen_func_names = { + } + self.WriteValidUnitTest(func, file, valid_test, { + 'first_arg': func.GetOriginalArgs()[0].GetValidArg(func, 0, 0), + 'first_gl_arg': func.GetOriginalArgs()[0].GetValidGLArg(func, 0, 0), + 'resource_type': func.GetOriginalArgs()[1].resource_type, + 'gl_gen_func_name': func.GetInfo("gen_func"), + }) invalid_test = """ TEST_F(%(test_name)s, %(name)sInvalidArgs%(arg_index)d_%(value_index)d) { @@ -2764,11 +2824,14 @@ TEST_F(%(test_name)s, %(name)sInvalidArgs%(arg_index)d_%(value_index)d) { def WriteGLES2ImplementationHeader(self, func, file): """Writes the GLES2 Implemention.""" + impl_func = func.GetInfo('impl_func') impl_decl = func.GetInfo('impl_decl') + if (func.can_auto_generate and - (impl_func == None or impl_func == True) and - (impl_decl == None or impl_decl == True)): + (impl_func == None or impl_func == True) and + (impl_decl == None or impl_decl == True)): + file.Write("%s %s(%s) {\n" % (func.return_type, func.original_name, func.MakeTypedOriginalArgString(""))) @@ -2777,6 +2840,7 @@ TEST_F(%(test_name)s, %(name)sInvalidArgs%(arg_index)d_%(value_index)d) { self.WriteClientGLCallLog(func, file) for arg in func.GetOriginalArgs(): arg.WriteClientSideValidationCode(file, func) + code = """ if (Is%(type)sReservedId(%(id)s)) { SetGLError(GL_INVALID_OPERATION, "%(name)s\", \"%(id)s reserved id"); return; @@ -2786,13 +2850,22 @@ TEST_F(%(test_name)s, %(name)sInvalidArgs%(arg_index)d_%(value_index)d) { } """ + name_arg = None + if len(func.GetOriginalArgs()) == 1: + # Bind functions that have no target (like BindVertexArrayOES) + name_arg = func.GetOriginalArgs()[0] + else: + # Bind functions that have both a target and a name (like BindTexture) + name_arg = func.GetOriginalArgs()[1] + file.Write(code % { 'name': func.name, 'arg_string': func.MakeOriginalArgString(""), - 'id': func.GetOriginalArgs()[1].name, - 'type': func.GetOriginalArgs()[1].resource_type, - 'lc_type': func.GetOriginalArgs()[1].resource_type.lower(), + 'id': name_arg.name, + 'type': name_arg.resource_type, + 'lc_type': name_arg.resource_type.lower(), }) + else: self.WriteGLES2ImplementationDeclaration(func, file) diff --git a/gpu/command_buffer/client/gles2_c_lib_autogen.h b/gpu/command_buffer/client/gles2_c_lib_autogen.h index 2f4fe35..8e5b255 100644 --- a/gpu/command_buffer/client/gles2_c_lib_autogen.h +++ b/gpu/command_buffer/client/gles2_c_lib_autogen.h @@ -553,6 +553,18 @@ void GLES2PushGroupMarkerEXT(GLsizei length, const GLchar* marker) { void GLES2PopGroupMarkerEXT() { gles2::GetGLContext()->PopGroupMarkerEXT(); } +void GLES2GenVertexArraysOES(GLsizei n, GLuint* arrays) { + gles2::GetGLContext()->GenVertexArraysOES(n, arrays); +} +void GLES2DeleteVertexArraysOES(GLsizei n, const GLuint* arrays) { + gles2::GetGLContext()->DeleteVertexArraysOES(n, arrays); +} +GLboolean GLES2IsVertexArrayOES(GLuint array) { + return gles2::GetGLContext()->IsVertexArrayOES(array); +} +void GLES2BindVertexArrayOES(GLuint array) { + gles2::GetGLContext()->BindVertexArrayOES(array); +} void GLES2SwapBuffers() { gles2::GetGLContext()->SwapBuffers(); } diff --git a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h index 77c1ac1..c311d6c 100644 --- a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h +++ b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h @@ -1596,6 +1596,58 @@ } } + void GenVertexArraysOES( + GLsizei n, uint32 arrays_shm_id, uint32 arrays_shm_offset) { + gles2::GenVertexArraysOES* c = GetCmdSpace<gles2::GenVertexArraysOES>(); + if (c) { + c->Init(n, arrays_shm_id, arrays_shm_offset); + } + } + + void GenVertexArraysOESImmediate(GLsizei n, GLuint* arrays) { + const uint32 size = gles2::GenVertexArraysOESImmediate::ComputeSize(n); + gles2::GenVertexArraysOESImmediate* c = + GetImmediateCmdSpaceTotalSize<gles2::GenVertexArraysOESImmediate>( + size); + if (c) { + c->Init(n, arrays); + } + } + + void DeleteVertexArraysOES( + GLsizei n, uint32 arrays_shm_id, uint32 arrays_shm_offset) { + gles2::DeleteVertexArraysOES* c = + GetCmdSpace<gles2::DeleteVertexArraysOES>(); + if (c) { + c->Init(n, arrays_shm_id, arrays_shm_offset); + } + } + + void DeleteVertexArraysOESImmediate(GLsizei n, const GLuint* arrays) { + const uint32 size = gles2::DeleteVertexArraysOESImmediate::ComputeSize(n); + gles2::DeleteVertexArraysOESImmediate* c = + GetImmediateCmdSpaceTotalSize<gles2::DeleteVertexArraysOESImmediate>( + size); + if (c) { + c->Init(n, arrays); + } + } + + void IsVertexArrayOES( + GLuint array, uint32 result_shm_id, uint32 result_shm_offset) { + gles2::IsVertexArrayOES* c = GetCmdSpace<gles2::IsVertexArrayOES>(); + if (c) { + c->Init(array, result_shm_id, result_shm_offset); + } + } + + void BindVertexArrayOES(GLuint array) { + gles2::BindVertexArrayOES* c = GetCmdSpace<gles2::BindVertexArrayOES>(); + if (c) { + c->Init(array); + } + } + void SwapBuffers() { gles2::SwapBuffers* c = GetCmdSpace<gles2::SwapBuffers>(); if (c) { diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc index 5b40fe3..899f192 100644 --- a/gpu/command_buffer/client/gles2_implementation.cc +++ b/gpu/command_buffer/client/gles2_implementation.cc @@ -2442,6 +2442,13 @@ void GLES2Implementation::BindTextureHelper(GLenum target, GLuint texture) { GetIdHandler(id_namespaces::kTextures)->MarkAsUsedForBind(texture); } +void GLES2Implementation::BindVertexArrayHelper(GLuint array) { + // TODO(gman): See note #1 above. + bound_vertex_array_id_ = array; + + GetIdHandler(id_namespaces::kVertexArrays)->MarkAsUsedForBind(array); +} + #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS) bool GLES2Implementation::IsBufferReservedId(GLuint id) { for (size_t ii = 0; ii < arraysize(reserved_ids_); ++ii) { @@ -2548,6 +2555,27 @@ void GLES2Implementation::DeleteTexturesHelper( } } +void GLES2Implementation::DeleteVertexArraysOESHelper( + GLsizei n, const GLuint* arrays) { + if (!GetIdHandler(id_namespaces::kVertexArrays)->FreeIds( + this, n, arrays, &GLES2Implementation::DeleteVertexArraysOESStub)) { + SetGLError( + GL_INVALID_VALUE, + "glDeleteVertexArraysOES", "id not created by this context."); + return; + } + for (GLsizei ii = 0; ii < n; ++ii) { + if (arrays[ii] == bound_vertex_array_id_) { + bound_vertex_array_id_ = 0; + } + } +} + +void GLES2Implementation::DeleteVertexArraysOESStub( + GLsizei n, const GLuint* arrays) { + helper_->DeleteVertexArraysOESImmediate(n, arrays); +} + void GLES2Implementation::DeleteTexturesStub( GLsizei n, const GLuint* textures) { helper_->DeleteTexturesImmediate(n, textures); diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h index 609e5e1..c10cc51 100644 --- a/gpu/command_buffer/client/gles2_implementation.h +++ b/gpu/command_buffer/client/gles2_implementation.h @@ -400,11 +400,13 @@ class GLES2_IMPL_EXPORT GLES2Implementation { bool IsFramebufferReservedId(GLuint id) { return false; } bool IsRenderbufferReservedId(GLuint id) { return false; } bool IsTextureReservedId(GLuint id) { return false; } + bool IsVertexArrayReservedId(GLuint id) { return false; } void BindBufferHelper(GLenum target, GLuint texture); void BindFramebufferHelper(GLenum target, GLuint texture); void BindRenderbufferHelper(GLenum target, GLuint texture); void BindTextureHelper(GLenum target, GLuint texture); + void BindVertexArrayHelper(GLuint array); void DeleteBuffersHelper(GLsizei n, const GLuint* buffers); void DeleteFramebuffersHelper(GLsizei n, const GLuint* framebuffers); @@ -413,6 +415,7 @@ class GLES2_IMPL_EXPORT GLES2Implementation { bool DeleteProgramHelper(GLuint program); bool DeleteShaderHelper(GLuint shader); void DeleteQueriesEXTHelper(GLsizei n, const GLuint* textures); + void DeleteVertexArraysOESHelper(GLsizei n, const GLuint* arrays); void DeleteBuffersStub(GLsizei n, const GLuint* buffers); void DeleteFramebuffersStub(GLsizei n, const GLuint* framebuffers); @@ -422,6 +425,7 @@ class GLES2_IMPL_EXPORT GLES2Implementation { void DeleteShaderStub(GLsizei n, const GLuint* shaders); // TODO(gman): Remove this as queries are not shared. void DeleteQueriesStub(GLsizei n, const GLuint* queries); + void DeleteVertexArraysOESStub(GLsizei n, const GLuint* arrays); void BufferDataHelper( GLenum target, GLsizeiptr size, const void* data, GLenum usage); @@ -534,6 +538,9 @@ class GLES2_IMPL_EXPORT GLES2Implementation { // buffers. scoped_ptr<ClientSideBufferHelper> client_side_buffer_helper_; + // The currently bound vertex array object (VAO) + GLuint bound_vertex_array_id_; + GLuint reserved_ids_[2]; // Current GL error bits. diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h index 52797ee..8b7901f 100644 --- a/gpu/command_buffer/client/gles2_implementation_autogen.h +++ b/gpu/command_buffer/client/gles2_implementation_autogen.h @@ -1434,6 +1434,70 @@ void PushGroupMarkerEXT(GLsizei length, const GLchar* marker); void PopGroupMarkerEXT(); +void GenVertexArraysOES(GLsizei n, GLuint* arrays) { + GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenVertexArraysOES(" << n << ", " << static_cast<const void*>(arrays) << ")"); // NOLINT + if (n < 0) { + SetGLError(GL_INVALID_VALUE, "glGenVertexArraysOES", "n < 0"); + return; + } + GPU_CLIENT_SINGLE_THREAD_CHECK(); + GetIdHandler(id_namespaces::kVertexArrays)-> + MakeIds(this, 0, n, arrays); + helper_->GenVertexArraysOESImmediate(n, arrays); + GPU_CLIENT_LOG_CODE_BLOCK({ + for (GLsizei i = 0; i < n; ++i) { + GPU_CLIENT_LOG(" " << i << ": " << arrays[i]); + } + }); +} + +void DeleteVertexArraysOES(GLsizei n, const GLuint* arrays) { + GPU_CLIENT_SINGLE_THREAD_CHECK(); + GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDeleteVertexArraysOES(" << n << ", " << static_cast<const void*>(arrays) << ")"); // NOLINT + GPU_CLIENT_LOG_CODE_BLOCK({ + for (GLsizei i = 0; i < n; ++i) { + GPU_CLIENT_LOG(" " << i << ": " << arrays[i]); + } + }); + GPU_CLIENT_DCHECK_CODE_BLOCK({ + for (GLsizei i = 0; i < n; ++i) { + GPU_DCHECK(arrays[i] != 0); + } + }); + if (n < 0) { + SetGLError(GL_INVALID_VALUE, "glDeleteVertexArraysOES", "n < 0"); + return; + } + DeleteVertexArraysOESHelper(n, arrays); +} + +GLboolean IsVertexArrayOES(GLuint array) { + GPU_CLIENT_SINGLE_THREAD_CHECK(); + GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsVertexArrayOES(" << array << ")"); // NOLINT + typedef IsVertexArrayOES::Result Result; + Result* result = GetResultAs<Result*>(); + if (!result) { + return GL_FALSE; + } + *result = 0; + helper_->IsVertexArrayOES(array, GetResultShmId(), GetResultShmOffset()); + WaitForCmd(); + GPU_CLIENT_LOG("returned " << *result); + return *result; +} + +void BindVertexArrayOES(GLuint array) { + GPU_CLIENT_SINGLE_THREAD_CHECK(); + GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindVertexArrayOES(" << array << ")"); // NOLINT + if (IsVertexArrayReservedId(array)) { + SetGLError( + GL_INVALID_OPERATION, "BindVertexArrayOES", "array reserved id"); + return; + } + BindVertexArrayHelper(array); + helper_->BindVertexArrayOES(array); +} + void SwapBuffers(); GLuint GetMaxValueInBufferCHROMIUM( diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc index e008ec7..28fdbd3 100644 --- a/gpu/command_buffer/client/gles2_implementation_unittest.cc +++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc @@ -322,6 +322,7 @@ class GLES2ImplementationTest : public testing::Test { static const GLuint kRenderbuffersStartId = 1; static const GLuint kTexturesStartId = 1; static const GLuint kQueriesStartId = 1; + static const GLuint kVertexArraysStartId = 1; typedef MockTransferBuffer::ExpectedMemoryInfo ExpectedMemoryInfo; @@ -522,6 +523,7 @@ const GLuint GLES2ImplementationTest::kProgramsAndShadersStartId; const GLuint GLES2ImplementationTest::kRenderbuffersStartId; const GLuint GLES2ImplementationTest::kTexturesStartId; const GLuint GLES2ImplementationTest::kQueriesStartId; +const GLuint GLES2ImplementationTest::kVertexArraysStartId; #endif TEST_F(GLES2ImplementationTest, Basic) { @@ -2623,6 +2625,33 @@ TEST_F(GLES2ImplementationTest, ErrorQuery) { EXPECT_EQ(static_cast<GLuint>(GL_INVALID_ENUM), result); } +#if !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS) +TEST_F(GLES2ImplementationTest, VertexArrays) { + const GLuint kAttribIndex1 = 1; + const GLint kNumComponents1 = 3; + const GLsizei kClientStride = 12; + + GLuint id = 0; + gl_->GenVertexArraysOES(1, &id); + ClearCommands(); + + gl_->BindVertexArrayOES(id); + + // Test that VertexAttribPointer cannot be called with a bound buffer of 0 + // unless the offset is NULL + gl_->BindBuffer(GL_ARRAY_BUFFER, 0); + + gl_->VertexAttribPointer( + kAttribIndex1, kNumComponents1, GL_FLOAT, GL_FALSE, kClientStride, + reinterpret_cast<const void*>(4)); + EXPECT_EQ(GL_INVALID_OPERATION, CheckError()); + + gl_->VertexAttribPointer( + kAttribIndex1, kNumComponents1, GL_FLOAT, GL_FALSE, kClientStride, NULL); + EXPECT_EQ(GL_NO_ERROR, CheckError()); +} +#endif + #include "gpu/command_buffer/client/gles2_implementation_unittest_autogen.h" } // namespace gles2 diff --git a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h index ddf5d71..a70a73e 100644 --- a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h +++ b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h @@ -1607,6 +1607,67 @@ TEST_F(GLES2ImplementationTest, PopGroupMarkerEXT) { gl_->PopGroupMarkerEXT(); EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); } + +TEST_F(GLES2ImplementationTest, GenVertexArraysOES) { + GLuint ids[2] = { 0, }; + struct Cmds { + GenVertexArraysOESImmediate gen; + GLuint data[2]; + }; + Cmds expected; + expected.gen.Init(arraysize(ids), &ids[0]); + expected.data[0] = kVertexArraysStartId; + expected.data[1] = kVertexArraysStartId + 1; + gl_->GenVertexArraysOES(arraysize(ids), &ids[0]); + EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); + EXPECT_EQ(kVertexArraysStartId, ids[0]); + EXPECT_EQ(kVertexArraysStartId + 1, ids[1]); +} + +TEST_F(GLES2ImplementationTest, DeleteVertexArraysOES) { + GLuint ids[2] = { kVertexArraysStartId, kVertexArraysStartId + 1 }; + struct Cmds { + DeleteVertexArraysOESImmediate del; + GLuint data[2]; + }; + Cmds expected; + expected.del.Init(arraysize(ids), &ids[0]); + expected.data[0] = kVertexArraysStartId; + expected.data[1] = kVertexArraysStartId + 1; + gl_->DeleteVertexArraysOES(arraysize(ids), &ids[0]); + EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); +} + +TEST_F(GLES2ImplementationTest, IsVertexArrayOES) { + struct Cmds { + IsVertexArrayOES cmd; + }; + + typedef IsVertexArrayOES::Result Result; + Cmds expected; + ExpectedMemoryInfo result1 = + GetExpectedResultMemory(sizeof(IsVertexArrayOES::Result)); + expected.cmd.Init(1, result1.id, result1.offset); + + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, uint32(1))) + .RetiresOnSaturation(); + + GLboolean result = gl_->IsVertexArrayOES(1); + EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); + EXPECT_TRUE(result); +} + +TEST_F(GLES2ImplementationTest, BindVertexArrayOES) { + struct Cmds { + BindVertexArrayOES cmd; + }; + Cmds expected; + expected.cmd.Init(1); + + gl_->BindVertexArrayOES(1); + EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); +} // TODO: Implement unit test for GenSharedIdsCHROMIUM // TODO: Implement unit test for DeleteSharedIdsCHROMIUM // TODO: Implement unit test for RegisterSharedIdsCHROMIUM diff --git a/gpu/command_buffer/cmd_buffer_functions.txt b/gpu/command_buffer/cmd_buffer_functions.txt index 7b53c10..0ad28c8 100644 --- a/gpu/command_buffer/cmd_buffer_functions.txt +++ b/gpu/command_buffer/cmd_buffer_functions.txt @@ -161,6 +161,11 @@ GL_APICALL void GL_APIENTRY glInsertEventMarkerEXT (GLsizei length, cons GL_APICALL void GL_APIENTRY glPushGroupMarkerEXT (GLsizei length, const GLchar* marker); GL_APICALL void GL_APIENTRY glPopGroupMarkerEXT (void); +GL_APICALL void GL_APIENTRY glGenVertexArraysOES (GLsizeiNotNegative n, GLuint* arrays); +GL_APICALL void GL_APIENTRY glDeleteVertexArraysOES (GLsizeiNotNegative n, const GLuint* arrays); +GL_APICALL GLboolean GL_APIENTRY glIsVertexArrayOES (GLidVertexArray array); +GL_APICALL void GL_APIENTRY glBindVertexArrayOES (GLidBindVertexArray array); + // Non-GL commands. GL_APICALL void GL_APIENTRY glSwapBuffers (void); GL_APICALL GLuint GL_APIENTRY glGetMaxValueInBufferCHROMIUM (GLidBuffer buffer_id, GLsizei count, GLenumGetMaxIndexType type, GLuint offset); diff --git a/gpu/command_buffer/common/gl_mock.h b/gpu/command_buffer/common/gl_mock.h index 6416a61..3d2e2b5 100644 --- a/gpu/command_buffer/common/gl_mock.h +++ b/gpu/command_buffer/common/gl_mock.h @@ -522,6 +522,14 @@ class MockGLInterface : public GLInterface { GLsizei primcount)); MOCK_METHOD2(VertexAttribDivisorANGLE, void(GLuint index, GLuint divisor)); + + MOCK_METHOD2(GenVertexArraysOES, void(GLsizei n, GLuint* ids)); + + MOCK_METHOD2(DeleteVertexArraysOES, void(GLsizei n, const GLuint* ids)); + + MOCK_METHOD1(IsVertexArrayOES, GLboolean(GLuint id)); + + MOCK_METHOD1(BindVertexArrayOES, void(GLuint id)); }; } // namespace gfx diff --git a/gpu/command_buffer/common/gles2_cmd_format.h b/gpu/command_buffer/common/gles2_cmd_format.h index a2b3139..2a18d4a 100644 --- a/gpu/command_buffer/common/gles2_cmd_format.h +++ b/gpu/command_buffer/common/gles2_cmd_format.h @@ -54,6 +54,7 @@ enum IdNamespaces { kRenderbuffers, kTextures, kQueries, + kVertexArrays, kNumIdNamespaces }; diff --git a/gpu/command_buffer/common/gles2_cmd_format_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_autogen.h index d6978d4..04fd1b2 100644 --- a/gpu/command_buffer/common/gles2_cmd_format_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_format_autogen.h @@ -8884,6 +8884,259 @@ COMPILE_ASSERT(sizeof(PopGroupMarkerEXT) == 4, COMPILE_ASSERT(offsetof(PopGroupMarkerEXT, header) == 0, OffsetOf_PopGroupMarkerEXT_header_not_0); +struct GenVertexArraysOES { + typedef GenVertexArraysOES ValueType; + static const CommandId kCmdId = kGenVertexArraysOES; + static const cmd::ArgFlags kArgFlags = cmd::kFixed; + + static uint32 ComputeSize() { + return static_cast<uint32>(sizeof(ValueType)); // NOLINT + } + + void SetHeader() { + header.SetCmd<ValueType>(); + } + + void Init(GLsizei _n, uint32 _arrays_shm_id, uint32 _arrays_shm_offset) { + SetHeader(); + n = _n; + arrays_shm_id = _arrays_shm_id; + arrays_shm_offset = _arrays_shm_offset; + } + + void* Set( + void* cmd, GLsizei _n, uint32 _arrays_shm_id, + uint32 _arrays_shm_offset) { + static_cast<ValueType*>(cmd)->Init(_n, _arrays_shm_id, _arrays_shm_offset); + return NextCmdAddress<ValueType>(cmd); + } + + gpu::CommandHeader header; + int32 n; + uint32 arrays_shm_id; + uint32 arrays_shm_offset; +}; + +COMPILE_ASSERT(sizeof(GenVertexArraysOES) == 16, + Sizeof_GenVertexArraysOES_is_not_16); +COMPILE_ASSERT(offsetof(GenVertexArraysOES, header) == 0, + OffsetOf_GenVertexArraysOES_header_not_0); +COMPILE_ASSERT(offsetof(GenVertexArraysOES, n) == 4, + OffsetOf_GenVertexArraysOES_n_not_4); +COMPILE_ASSERT(offsetof(GenVertexArraysOES, arrays_shm_id) == 8, + OffsetOf_GenVertexArraysOES_arrays_shm_id_not_8); +COMPILE_ASSERT(offsetof(GenVertexArraysOES, arrays_shm_offset) == 12, + OffsetOf_GenVertexArraysOES_arrays_shm_offset_not_12); + +struct GenVertexArraysOESImmediate { + typedef GenVertexArraysOESImmediate ValueType; + static const CommandId kCmdId = kGenVertexArraysOESImmediate; + static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN; + + static uint32 ComputeDataSize(GLsizei n) { + return static_cast<uint32>(sizeof(GLuint) * n); // NOLINT + } + + static uint32 ComputeSize(GLsizei n) { + return static_cast<uint32>( + sizeof(ValueType) + ComputeDataSize(n)); // NOLINT + } + + void SetHeader(GLsizei n) { + header.SetCmdByTotalSize<ValueType>(ComputeSize(n)); + } + + void Init(GLsizei _n, GLuint* _arrays) { + SetHeader(_n); + n = _n; + memcpy(ImmediateDataAddress(this), + _arrays, ComputeDataSize(_n)); + } + + void* Set(void* cmd, GLsizei _n, GLuint* _arrays) { + static_cast<ValueType*>(cmd)->Init(_n, _arrays); + const uint32 size = ComputeSize(_n); + return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size); + } + + gpu::CommandHeader header; + int32 n; +}; + +COMPILE_ASSERT(sizeof(GenVertexArraysOESImmediate) == 8, + Sizeof_GenVertexArraysOESImmediate_is_not_8); +COMPILE_ASSERT(offsetof(GenVertexArraysOESImmediate, header) == 0, + OffsetOf_GenVertexArraysOESImmediate_header_not_0); +COMPILE_ASSERT(offsetof(GenVertexArraysOESImmediate, n) == 4, + OffsetOf_GenVertexArraysOESImmediate_n_not_4); + +struct DeleteVertexArraysOES { + typedef DeleteVertexArraysOES ValueType; + static const CommandId kCmdId = kDeleteVertexArraysOES; + static const cmd::ArgFlags kArgFlags = cmd::kFixed; + + static uint32 ComputeSize() { + return static_cast<uint32>(sizeof(ValueType)); // NOLINT + } + + void SetHeader() { + header.SetCmd<ValueType>(); + } + + void Init(GLsizei _n, uint32 _arrays_shm_id, uint32 _arrays_shm_offset) { + SetHeader(); + n = _n; + arrays_shm_id = _arrays_shm_id; + arrays_shm_offset = _arrays_shm_offset; + } + + void* Set( + void* cmd, GLsizei _n, uint32 _arrays_shm_id, + uint32 _arrays_shm_offset) { + static_cast<ValueType*>(cmd)->Init(_n, _arrays_shm_id, _arrays_shm_offset); + return NextCmdAddress<ValueType>(cmd); + } + + gpu::CommandHeader header; + int32 n; + uint32 arrays_shm_id; + uint32 arrays_shm_offset; +}; + +COMPILE_ASSERT(sizeof(DeleteVertexArraysOES) == 16, + Sizeof_DeleteVertexArraysOES_is_not_16); +COMPILE_ASSERT(offsetof(DeleteVertexArraysOES, header) == 0, + OffsetOf_DeleteVertexArraysOES_header_not_0); +COMPILE_ASSERT(offsetof(DeleteVertexArraysOES, n) == 4, + OffsetOf_DeleteVertexArraysOES_n_not_4); +COMPILE_ASSERT(offsetof(DeleteVertexArraysOES, arrays_shm_id) == 8, + OffsetOf_DeleteVertexArraysOES_arrays_shm_id_not_8); +COMPILE_ASSERT(offsetof(DeleteVertexArraysOES, arrays_shm_offset) == 12, + OffsetOf_DeleteVertexArraysOES_arrays_shm_offset_not_12); + +struct DeleteVertexArraysOESImmediate { + typedef DeleteVertexArraysOESImmediate ValueType; + static const CommandId kCmdId = kDeleteVertexArraysOESImmediate; + static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN; + + static uint32 ComputeDataSize(GLsizei n) { + return static_cast<uint32>(sizeof(GLuint) * n); // NOLINT + } + + static uint32 ComputeSize(GLsizei n) { + return static_cast<uint32>( + sizeof(ValueType) + ComputeDataSize(n)); // NOLINT + } + + void SetHeader(GLsizei n) { + header.SetCmdByTotalSize<ValueType>(ComputeSize(n)); + } + + void Init(GLsizei _n, const GLuint* _arrays) { + SetHeader(_n); + n = _n; + memcpy(ImmediateDataAddress(this), + _arrays, ComputeDataSize(_n)); + } + + void* Set(void* cmd, GLsizei _n, const GLuint* _arrays) { + static_cast<ValueType*>(cmd)->Init(_n, _arrays); + const uint32 size = ComputeSize(_n); + return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size); + } + + gpu::CommandHeader header; + int32 n; +}; + +COMPILE_ASSERT(sizeof(DeleteVertexArraysOESImmediate) == 8, + Sizeof_DeleteVertexArraysOESImmediate_is_not_8); +COMPILE_ASSERT(offsetof(DeleteVertexArraysOESImmediate, header) == 0, + OffsetOf_DeleteVertexArraysOESImmediate_header_not_0); +COMPILE_ASSERT(offsetof(DeleteVertexArraysOESImmediate, n) == 4, + OffsetOf_DeleteVertexArraysOESImmediate_n_not_4); + +struct IsVertexArrayOES { + typedef IsVertexArrayOES ValueType; + static const CommandId kCmdId = kIsVertexArrayOES; + static const cmd::ArgFlags kArgFlags = cmd::kFixed; + + typedef uint32 Result; + + static uint32 ComputeSize() { + return static_cast<uint32>(sizeof(ValueType)); // NOLINT + } + + void SetHeader() { + header.SetCmd<ValueType>(); + } + + void Init(GLuint _array, uint32 _result_shm_id, uint32 _result_shm_offset) { + SetHeader(); + array = _array; + result_shm_id = _result_shm_id; + result_shm_offset = _result_shm_offset; + } + + void* Set( + void* cmd, GLuint _array, uint32 _result_shm_id, + uint32 _result_shm_offset) { + static_cast<ValueType*>( + cmd)->Init(_array, _result_shm_id, _result_shm_offset); + return NextCmdAddress<ValueType>(cmd); + } + + gpu::CommandHeader header; + uint32 array; + uint32 result_shm_id; + uint32 result_shm_offset; +}; + +COMPILE_ASSERT(sizeof(IsVertexArrayOES) == 16, + Sizeof_IsVertexArrayOES_is_not_16); +COMPILE_ASSERT(offsetof(IsVertexArrayOES, header) == 0, + OffsetOf_IsVertexArrayOES_header_not_0); +COMPILE_ASSERT(offsetof(IsVertexArrayOES, array) == 4, + OffsetOf_IsVertexArrayOES_array_not_4); +COMPILE_ASSERT(offsetof(IsVertexArrayOES, result_shm_id) == 8, + OffsetOf_IsVertexArrayOES_result_shm_id_not_8); +COMPILE_ASSERT(offsetof(IsVertexArrayOES, result_shm_offset) == 12, + OffsetOf_IsVertexArrayOES_result_shm_offset_not_12); + +struct BindVertexArrayOES { + typedef BindVertexArrayOES ValueType; + static const CommandId kCmdId = kBindVertexArrayOES; + static const cmd::ArgFlags kArgFlags = cmd::kFixed; + + static uint32 ComputeSize() { + return static_cast<uint32>(sizeof(ValueType)); // NOLINT + } + + void SetHeader() { + header.SetCmd<ValueType>(); + } + + void Init(GLuint _array) { + SetHeader(); + array = _array; + } + + void* Set(void* cmd, GLuint _array) { + static_cast<ValueType*>(cmd)->Init(_array); + return NextCmdAddress<ValueType>(cmd); + } + + gpu::CommandHeader header; + uint32 array; +}; + +COMPILE_ASSERT(sizeof(BindVertexArrayOES) == 8, + Sizeof_BindVertexArrayOES_is_not_8); +COMPILE_ASSERT(offsetof(BindVertexArrayOES, header) == 0, + OffsetOf_BindVertexArrayOES_header_not_0); +COMPILE_ASSERT(offsetof(BindVertexArrayOES, array) == 4, + OffsetOf_BindVertexArrayOES_array_not_4); + struct SwapBuffers { typedef SwapBuffers ValueType; static const CommandId kCmdId = kSwapBuffers; diff --git a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h index 9682fc2..cee8095 100644 --- a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h @@ -3457,6 +3457,106 @@ TEST_F(GLES2FormatTest, PopGroupMarkerEXT) { next_cmd, sizeof(cmd)); } +TEST_F(GLES2FormatTest, GenVertexArraysOES) { + GenVertexArraysOES& cmd = *GetBufferAs<GenVertexArraysOES>(); + void* next_cmd = cmd.Set( + &cmd, + static_cast<GLsizei>(11), + static_cast<uint32>(12), + static_cast<uint32>(13)); + EXPECT_EQ(static_cast<uint32>(GenVertexArraysOES::kCmdId), + cmd.header.command); + EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u); + EXPECT_EQ(static_cast<GLsizei>(11), cmd.n); + EXPECT_EQ(static_cast<uint32>(12), cmd.arrays_shm_id); + EXPECT_EQ(static_cast<uint32>(13), cmd.arrays_shm_offset); + CheckBytesWrittenMatchesExpectedSize( + next_cmd, sizeof(cmd)); +} + +TEST_F(GLES2FormatTest, GenVertexArraysOESImmediate) { + static GLuint ids[] = { 12, 23, 34, }; + GenVertexArraysOESImmediate& cmd = + *GetBufferAs<GenVertexArraysOESImmediate>(); + void* next_cmd = cmd.Set( + &cmd, static_cast<GLsizei>(arraysize(ids)), ids); + EXPECT_EQ(static_cast<uint32>(GenVertexArraysOESImmediate::kCmdId), + cmd.header.command); + EXPECT_EQ(sizeof(cmd) + + RoundSizeToMultipleOfEntries(cmd.n * 4u), + cmd.header.size * 4u); + EXPECT_EQ(static_cast<GLsizei>(arraysize(ids)), cmd.n); + CheckBytesWrittenMatchesExpectedSize( + next_cmd, sizeof(cmd) + + RoundSizeToMultipleOfEntries(arraysize(ids) * 4u)); + // TODO(gman): Check that ids were inserted; +} + +TEST_F(GLES2FormatTest, DeleteVertexArraysOES) { + DeleteVertexArraysOES& cmd = *GetBufferAs<DeleteVertexArraysOES>(); + void* next_cmd = cmd.Set( + &cmd, + static_cast<GLsizei>(11), + static_cast<uint32>(12), + static_cast<uint32>(13)); + EXPECT_EQ(static_cast<uint32>(DeleteVertexArraysOES::kCmdId), + cmd.header.command); + EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u); + EXPECT_EQ(static_cast<GLsizei>(11), cmd.n); + EXPECT_EQ(static_cast<uint32>(12), cmd.arrays_shm_id); + EXPECT_EQ(static_cast<uint32>(13), cmd.arrays_shm_offset); + CheckBytesWrittenMatchesExpectedSize( + next_cmd, sizeof(cmd)); +} + +TEST_F(GLES2FormatTest, DeleteVertexArraysOESImmediate) { + static GLuint ids[] = { 12, 23, 34, }; + DeleteVertexArraysOESImmediate& cmd = + *GetBufferAs<DeleteVertexArraysOESImmediate>(); + void* next_cmd = cmd.Set( + &cmd, static_cast<GLsizei>(arraysize(ids)), ids); + EXPECT_EQ(static_cast<uint32>(DeleteVertexArraysOESImmediate::kCmdId), + cmd.header.command); + EXPECT_EQ(sizeof(cmd) + + RoundSizeToMultipleOfEntries(cmd.n * 4u), + cmd.header.size * 4u); + EXPECT_EQ(static_cast<GLsizei>(arraysize(ids)), cmd.n); + CheckBytesWrittenMatchesExpectedSize( + next_cmd, sizeof(cmd) + + RoundSizeToMultipleOfEntries(arraysize(ids) * 4u)); + // TODO(gman): Check that ids were inserted; +} + +TEST_F(GLES2FormatTest, IsVertexArrayOES) { + IsVertexArrayOES& cmd = *GetBufferAs<IsVertexArrayOES>(); + void* next_cmd = cmd.Set( + &cmd, + static_cast<GLuint>(11), + static_cast<uint32>(12), + static_cast<uint32>(13)); + EXPECT_EQ(static_cast<uint32>(IsVertexArrayOES::kCmdId), + cmd.header.command); + EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u); + EXPECT_EQ(static_cast<GLuint>(11), cmd.array); + EXPECT_EQ(static_cast<uint32>(12), cmd.result_shm_id); + EXPECT_EQ(static_cast<uint32>(13), cmd.result_shm_offset); + CheckBytesWrittenMatchesExpectedSize( + next_cmd, sizeof(cmd)); +} + +TEST_F(GLES2FormatTest, BindVertexArrayOES) { + BindVertexArrayOES& cmd = *GetBufferAs<BindVertexArrayOES>(); + void* next_cmd = cmd.Set( + &cmd, + static_cast<GLuint>(11)); + EXPECT_EQ(static_cast<uint32>(BindVertexArrayOES::kCmdId), + cmd.header.command); + EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u); + EXPECT_EQ(static_cast<GLuint>(11), cmd.array); + CheckBytesWrittenMatchesExpectedSize( + next_cmd, sizeof(cmd)); +} + TEST_F(GLES2FormatTest, SwapBuffers) { SwapBuffers& cmd = *GetBufferAs<SwapBuffers>(); void* next_cmd = cmd.Set( diff --git a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h index 1bc9ac6..bed63e2 100644 --- a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h @@ -205,34 +205,40 @@ OP(InsertEventMarkerEXT) /* 448 */ \ OP(PushGroupMarkerEXT) /* 449 */ \ OP(PopGroupMarkerEXT) /* 450 */ \ - OP(SwapBuffers) /* 451 */ \ - OP(GetMaxValueInBufferCHROMIUM) /* 452 */ \ - OP(GenSharedIdsCHROMIUM) /* 453 */ \ - OP(DeleteSharedIdsCHROMIUM) /* 454 */ \ - OP(RegisterSharedIdsCHROMIUM) /* 455 */ \ - OP(EnableFeatureCHROMIUM) /* 456 */ \ - OP(ResizeCHROMIUM) /* 457 */ \ - OP(GetRequestableExtensionsCHROMIUM) /* 458 */ \ - OP(RequestExtensionCHROMIUM) /* 459 */ \ - OP(GetMultipleIntegervCHROMIUM) /* 460 */ \ - OP(GetProgramInfoCHROMIUM) /* 461 */ \ - OP(CreateStreamTextureCHROMIUM) /* 462 */ \ - OP(DestroyStreamTextureCHROMIUM) /* 463 */ \ - OP(GetTranslatedShaderSourceANGLE) /* 464 */ \ - OP(PostSubBufferCHROMIUM) /* 465 */ \ - OP(TexImageIOSurface2DCHROMIUM) /* 466 */ \ - OP(CopyTextureCHROMIUM) /* 467 */ \ - OP(DrawArraysInstancedANGLE) /* 468 */ \ - OP(DrawElementsInstancedANGLE) /* 469 */ \ - OP(VertexAttribDivisorANGLE) /* 470 */ \ - OP(GenMailboxCHROMIUM) /* 471 */ \ - OP(ProduceTextureCHROMIUM) /* 472 */ \ - OP(ProduceTextureCHROMIUMImmediate) /* 473 */ \ - OP(ConsumeTextureCHROMIUM) /* 474 */ \ - OP(ConsumeTextureCHROMIUMImmediate) /* 475 */ \ - OP(BindUniformLocationCHROMIUM) /* 476 */ \ - OP(BindUniformLocationCHROMIUMImmediate) /* 477 */ \ - OP(BindUniformLocationCHROMIUMBucket) /* 478 */ \ + OP(GenVertexArraysOES) /* 451 */ \ + OP(GenVertexArraysOESImmediate) /* 452 */ \ + OP(DeleteVertexArraysOES) /* 453 */ \ + OP(DeleteVertexArraysOESImmediate) /* 454 */ \ + OP(IsVertexArrayOES) /* 455 */ \ + OP(BindVertexArrayOES) /* 456 */ \ + OP(SwapBuffers) /* 457 */ \ + OP(GetMaxValueInBufferCHROMIUM) /* 458 */ \ + OP(GenSharedIdsCHROMIUM) /* 459 */ \ + OP(DeleteSharedIdsCHROMIUM) /* 460 */ \ + OP(RegisterSharedIdsCHROMIUM) /* 461 */ \ + OP(EnableFeatureCHROMIUM) /* 462 */ \ + OP(ResizeCHROMIUM) /* 463 */ \ + OP(GetRequestableExtensionsCHROMIUM) /* 464 */ \ + OP(RequestExtensionCHROMIUM) /* 465 */ \ + OP(GetMultipleIntegervCHROMIUM) /* 466 */ \ + OP(GetProgramInfoCHROMIUM) /* 467 */ \ + OP(CreateStreamTextureCHROMIUM) /* 468 */ \ + OP(DestroyStreamTextureCHROMIUM) /* 469 */ \ + OP(GetTranslatedShaderSourceANGLE) /* 470 */ \ + OP(PostSubBufferCHROMIUM) /* 471 */ \ + OP(TexImageIOSurface2DCHROMIUM) /* 472 */ \ + OP(CopyTextureCHROMIUM) /* 473 */ \ + OP(DrawArraysInstancedANGLE) /* 474 */ \ + OP(DrawElementsInstancedANGLE) /* 475 */ \ + OP(VertexAttribDivisorANGLE) /* 476 */ \ + OP(GenMailboxCHROMIUM) /* 477 */ \ + OP(ProduceTextureCHROMIUM) /* 478 */ \ + OP(ProduceTextureCHROMIUMImmediate) /* 479 */ \ + OP(ConsumeTextureCHROMIUM) /* 480 */ \ + OP(ConsumeTextureCHROMIUMImmediate) /* 481 */ \ + OP(BindUniformLocationCHROMIUM) /* 482 */ \ + OP(BindUniformLocationCHROMIUMImmediate) /* 483 */ \ + OP(BindUniformLocationCHROMIUMBucket) /* 484 */ \ enum CommandId { kStartPoint = cmd::kLastCommonId, // All GLES2 commands start after this. diff --git a/gpu/command_buffer/service/context_group.cc b/gpu/command_buffer/service/context_group.cc index c18bb4e..ecaf700 100644 --- a/gpu/command_buffer/service/context_group.cc +++ b/gpu/command_buffer/service/context_group.cc @@ -58,6 +58,7 @@ ContextGroup::ContextGroup( id_namespaces_[id_namespaces::kRenderbuffers].reset(new IdAllocator); id_namespaces_[id_namespaces::kTextures].reset(new IdAllocator); id_namespaces_[id_namespaces::kQueries].reset(new IdAllocator); + id_namespaces_[id_namespaces::kVertexArrays].reset(new IdAllocator); } static void GetIntegerv(GLenum pname, uint32* var) { diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc index c195084..a8c6679 100644 --- a/gpu/command_buffer/service/feature_info.cc +++ b/gpu/command_buffer/service/feature_info.cc @@ -80,6 +80,7 @@ FeatureInfo::FeatureFlags::FeatureFlags() occlusion_query_boolean(false), use_arb_occlusion_query2_for_occlusion_query_boolean(false), use_arb_occlusion_query_for_occlusion_query_boolean(false), + native_vertex_array_object_(false), disable_workarounds(false), is_intel(false), is_nvidia(false), @@ -343,6 +344,14 @@ void FeatureInfo::AddFeatures(const char* desired_features) { validators_.render_buffer_format.AddValue(GL_DEPTH24_STENCIL8); } + if (ext.Desire("GL_OES_vertex_array_object") && + (ext.Have("GL_OES_vertex_array_object") || + ext.Have("GL_ARB_vertex_array_object") || + ext.Have("GL_APPLE_vertex_array_object"))) { + feature_flags_.native_vertex_array_object_ = true; + AddExtensionString("GL_OES_vertex_array_object"); + } + bool enable_texture_format_bgra8888 = false; bool enable_read_format_bgra = false; // Check if we should allow GL_EXT_texture_format_BGRA8888 diff --git a/gpu/command_buffer/service/feature_info.h b/gpu/command_buffer/service/feature_info.h index 1721e0c..5f3fbe0 100644 --- a/gpu/command_buffer/service/feature_info.h +++ b/gpu/command_buffer/service/feature_info.h @@ -38,6 +38,7 @@ class GPU_EXPORT FeatureInfo : public base::RefCounted<FeatureInfo> { bool occlusion_query_boolean; bool use_arb_occlusion_query2_for_occlusion_query_boolean; bool use_arb_occlusion_query_for_occlusion_query_boolean; + bool native_vertex_array_object_; bool disable_workarounds; bool is_intel; bool is_nvidia; diff --git a/gpu/command_buffer/service/feature_info_unittest.cc b/gpu/command_buffer/service/feature_info_unittest.cc index 10c7f5c..a5cfa12 100644 --- a/gpu/command_buffer/service/feature_info_unittest.cc +++ b/gpu/command_buffer/service/feature_info_unittest.cc @@ -746,6 +746,39 @@ TEST_F(FeatureInfoTest, InitializeARB_occlusion_query2) { ).use_arb_occlusion_query_for_occlusion_query_boolean); } +TEST_F(FeatureInfoTest, InitializeOES_vertex_array_object) { + SetupInitExpectations("GL_OES_vertex_array_object"); + info_->Initialize(NULL); + EXPECT_THAT(info_->extensions(), + HasSubstr("GL_OES_vertex_array_object")); + EXPECT_TRUE(info_->feature_flags().native_vertex_array_object_); +} + +TEST_F(FeatureInfoTest, InitializeARB_vertex_array_object) { + SetupInitExpectations("GL_ARB_vertex_array_object"); + info_->Initialize(NULL); + EXPECT_THAT(info_->extensions(), + HasSubstr("GL_OES_vertex_array_object")); + EXPECT_TRUE(info_->feature_flags().native_vertex_array_object_); +} + +TEST_F(FeatureInfoTest, InitializeAPPLE_vertex_array_object) { + SetupInitExpectations("GL_APPLE_vertex_array_object"); + info_->Initialize(NULL); + EXPECT_THAT(info_->extensions(), + HasSubstr("GL_OES_vertex_array_object")); + EXPECT_TRUE(info_->feature_flags().native_vertex_array_object_); +} + +TEST_F(FeatureInfoTest, InitializeNo_vertex_array_object) { + SetupInitExpectations(""); + info_->Initialize(NULL); + // Even if the native extensions are not available the implementation + // may still emulate the GL_OES_vertex_array_object functionality. In this + // scenario native_vertex_array_object must be false. + EXPECT_FALSE(info_->feature_flags().native_vertex_array_object_); +} + TEST_F(FeatureInfoTest, IsIntel) { SetupInitExpectationsWithVendor("", "iNTel", ""); info_->Initialize(NULL); diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 644dfbf..4a3c6e2 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -51,6 +51,7 @@ #include "gpu/command_buffer/service/texture_definition.h" #include "gpu/command_buffer/service/texture_manager.h" #include "gpu/command_buffer/service/vertex_attrib_manager.h" +#include "gpu/command_buffer/service/vertex_array_manager.h" #include "ui/gl/gl_context.h" #include "ui/gl/gl_implementation.h" #include "ui/gl/gl_surface.h" @@ -510,6 +511,9 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, virtual gfx::GLContext* GetGLContext() { return context_.get(); } virtual ContextGroup* GetContextGroup() { return group_.get(); } virtual QueryManager* GetQueryManager() { return query_manager_.get(); } + virtual VertexArrayManager* GetVertexArrayManager() { + return vertex_array_manager_.get(); + } virtual bool ProcessPendingQueries(); virtual void SetGLError( @@ -627,6 +631,8 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, void DeleteRenderbuffersHelper(GLsizei n, const GLuint* client_ids); bool GenQueriesEXTHelper(GLsizei n, const GLuint* client_ids); void DeleteQueriesEXTHelper(GLsizei n, const GLuint* client_ids); + bool GenVertexArraysOESHelper(GLsizei n, const GLuint* client_ids); + void DeleteVertexArraysOESHelper(GLsizei n, const GLuint* client_ids); // TODO(gman): Cache these pointers? BufferManager* buffer_manager() { @@ -657,6 +663,10 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, return group_->mailbox_manager(); } + VertexArrayManager* vertex_array_manager() { + return vertex_array_manager_.get(); + } + bool IsOffscreenBufferMultisampled() const { return offscreen_target_samples_ > 1; } @@ -897,6 +907,24 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, renderbuffer_manager()->RemoveRenderbufferInfo(client_id); } + // Gets the vertex attrib manager for the given vertex array. + VertexAttribManager* GetVertexAttribManager(GLuint client_id) { + VertexAttribManager* info = + vertex_array_manager()->GetVertexAttribManager(client_id); + return info; + } + + // Removes the vertex attrib manager for the given vertex array. + void RemoveVertexAttribManager(GLuint client_id) { + vertex_array_manager()->RemoveVertexAttribManager(client_id); + } + + // Creates a vertex attrib manager for the given vertex array. + void CreateVertexAttribManager(GLuint client_id, GLuint service_id) { + return vertex_array_manager()->CreateVertexAttribManager( + client_id, service_id, group_->max_vertex_attribs()); + } + void DoBindAttribLocation(GLuint client_id, GLuint index, const char* name); void DoBindUniformLocationCHROMIUM( GLuint client_id, GLint location, const char* name); @@ -1003,6 +1031,9 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, // Wrapper for glBindTexture since we need to track the current targets. void DoBindTexture(GLenum target, GLuint texture); + // Wrapper for glBindVertexArrayOES + void DoBindVertexArrayOES(GLuint array); + // Wrapper for glBlitFramebufferEXT. void DoBlitFramebufferEXT( GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, @@ -1119,6 +1150,7 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, bool DoIsRenderbuffer(GLuint client_id); bool DoIsShader(GLuint client_id); bool DoIsTexture(GLuint client_id); + bool DoIsVertexArrayOES(GLuint client_id); // Wrapper for glLinkProgram void DoLinkProgram(GLuint program); @@ -1246,9 +1278,11 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, // Gets the buffer id for a given target. BufferManager::BufferInfo* GetBufferInfoForTarget(GLenum target) { DCHECK(target == GL_ARRAY_BUFFER || target == GL_ELEMENT_ARRAY_BUFFER); - BufferManager::BufferInfo* info = target == GL_ARRAY_BUFFER ? - bound_array_buffer_ : bound_element_array_buffer_; - return info; + if (target == GL_ARRAY_BUFFER) { + return bound_array_buffer_; + } else { + return vertex_attrib_manager_->element_array_buffer(); + } } // Gets the texture id for a given target. @@ -1432,12 +1466,11 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, // glVertexAttribPointer. BufferManager::BufferInfo::Ref bound_array_buffer_; - // The currently bound element array buffer. If this is 0 it is illegal - // to call glDrawElements. - BufferManager::BufferInfo::Ref bound_element_array_buffer_; - // Class that manages vertex attribs. - scoped_ptr<VertexAttribManager> vertex_attrib_manager_; + VertexAttribManager::Ref vertex_attrib_manager_; + + // Default vertex attribs manager, used when no VAOs are bound. + VertexAttribManager::Ref default_vertex_attrib_manager_; // The buffer we bind to attrib 0 since OpenGL requires it (ES does not). GLuint attrib_0_buffer_id_; @@ -1525,6 +1558,8 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, scoped_ptr<QueryManager> query_manager_; QueryManager::Query::Ref current_query_; + scoped_ptr<VertexArrayManager> vertex_array_manager_; + base::Callback<void(gfx::Size)> resize_callback_; MsgCallback msg_callback_; @@ -2088,10 +2123,13 @@ bool GLES2DecoderImpl::Initialize( disallowed_features_ = disallowed_features; - vertex_attrib_manager_.reset(new VertexAttribManager()); - vertex_attrib_manager_->Initialize(group_->max_vertex_attribs()); + default_vertex_attrib_manager_ = new VertexAttribManager(); + default_vertex_attrib_manager_->Initialize(group_->max_vertex_attribs()); + + vertex_attrib_manager_ = default_vertex_attrib_manager_; query_manager_.reset(new QueryManager(this, feature_info_)); + vertex_array_manager_.reset(new VertexArrayManager()); util_.set_num_compressed_texture_formats( validators_->compressed_texture_format.GetValues().size()); @@ -2352,6 +2390,10 @@ bool GLES2DecoderImpl::Initialize( DoBindFramebuffer(GL_FRAMEBUFFER, 0); DoBindRenderbuffer(GL_RENDERBUFFER, 0); + if (feature_info_->feature_flags().native_vertex_array_object_) { + DoBindVertexArrayOES(0); + } + // AMD and Intel drivers on Mac OS apparently get gl_PointCoord // backward from the spec and this setting makes them work // correctly. rdar://problem/11883495 @@ -2509,9 +2551,6 @@ void GLES2DecoderImpl::DeleteBuffersHelper( if (bound_array_buffer_ == buffer) { bound_array_buffer_ = NULL; } - if (bound_element_array_buffer_ == buffer) { - bound_element_array_buffer_ = NULL; - } RemoveBufferInfo(client_ids[ii]); } } @@ -2877,10 +2916,10 @@ void GLES2DecoderImpl::Destroy(bool have_context) { SetParent(NULL, 0); // Unbind everything. - vertex_attrib_manager_.reset(); + vertex_attrib_manager_ = NULL; + default_vertex_attrib_manager_ = NULL; texture_units_.reset(); bound_array_buffer_ = NULL; - bound_element_array_buffer_ = NULL; current_query_ = NULL; current_program_ = NULL; bound_read_framebuffer_ = NULL; @@ -2950,6 +2989,11 @@ void GLES2DecoderImpl::Destroy(bool have_context) { query_manager_.reset(); } + if (vertex_array_manager_ .get()) { + vertex_array_manager_->Destroy(have_context); + vertex_array_manager_.reset(); + } + if (group_) { group_->Destroy(have_context); group_ = NULL; @@ -3372,7 +3416,7 @@ void GLES2DecoderImpl::DoBindBuffer(GLenum target, GLuint client_id) { bound_array_buffer_ = info; break; case GL_ELEMENT_ARRAY_BUFFER: - bound_element_array_buffer_ = info; + vertex_attrib_manager_->SetElementArrayBuffer(info); break; default: NOTREACHED(); // Validation should prevent us getting here. @@ -3827,10 +3871,10 @@ bool GLES2DecoderImpl::GetHelper( case GL_ELEMENT_ARRAY_BUFFER_BINDING: *num_written = 1; if (params) { - if (bound_element_array_buffer_) { + if (vertex_attrib_manager_->element_array_buffer()) { GLuint client_id = 0; buffer_manager()->GetClientId( - bound_element_array_buffer_->service_id(), + vertex_attrib_manager_->element_array_buffer()->service_id(), &client_id); *params = client_id; } else { @@ -5718,7 +5762,7 @@ error::Error GLES2DecoderImpl::DoDrawElements( GLsizei primcount) { if (ShouldDeferDraws()) return error::kDeferCommandUntilLater; - if (!bound_element_array_buffer_) { + if (!vertex_attrib_manager_->element_array_buffer()) { SetGLError(GL_INVALID_OPERATION, function_name, "No element array buffer bound"); return error::kNoError; @@ -5754,7 +5798,7 @@ error::Error GLES2DecoderImpl::DoDrawElements( } GLuint max_vertex_accessed; - if (!bound_element_array_buffer_->GetMaxValueForRange( + if (!vertex_attrib_manager_->element_array_buffer()->GetMaxValueForRange( offset, count, type, &max_vertex_accessed)) { SetGLError(GL_INVALID_OPERATION, function_name, "range out of bounds for buffer"); @@ -6322,10 +6366,17 @@ void GLES2DecoderImpl::DoVertexAttrib4fv(GLuint index, const GLfloat* v) { error::Error GLES2DecoderImpl::HandleVertexAttribPointer( uint32 immediate_data_size, const gles2::VertexAttribPointer& c) { + if (!bound_array_buffer_ || bound_array_buffer_->IsDeleted()) { - SetGLError(GL_INVALID_VALUE, - "glVertexAttribPointer", "no array buffer bound"); - return error::kNoError; + if (vertex_attrib_manager_ == default_vertex_attrib_manager_) { + SetGLError(GL_INVALID_VALUE, + "glVertexAttribPointer", "no array buffer bound"); + return error::kNoError; + } else if (c.offset != 0) { + SetGLError(GL_INVALID_VALUE, + "glVertexAttribPointer", "client side arrays are not allowed"); + return error::kNoError; + } } GLuint indx = c.indx; @@ -8730,6 +8781,89 @@ error::Error GLES2DecoderImpl::HandleEndQueryEXT( return error::kNoError; } +bool GLES2DecoderImpl::GenVertexArraysOESHelper( + GLsizei n, const GLuint* client_ids) { + + if (!feature_info_->feature_flags().native_vertex_array_object_) { + // TODO(bajones): Emulate if not present + SetGLError(GL_INVALID_OPERATION, "glGenVertexArraysOES", "not supported."); + } + + for (GLsizei ii = 0; ii < n; ++ii) { + if (GetVertexAttribManager(client_ids[ii])) { + return false; + } + } + scoped_array<GLuint> service_ids(new GLuint[n]); + glGenVertexArraysOES(n, service_ids.get()); + for (GLsizei ii = 0; ii < n; ++ii) { + CreateVertexAttribManager(client_ids[ii], service_ids[ii]); + } + return true; +} + +void GLES2DecoderImpl::DeleteVertexArraysOESHelper( + GLsizei n, const GLuint* client_ids) { + if (!feature_info_->feature_flags().native_vertex_array_object_) { + // TODO(bajones): Emulate if not present + SetGLError(GL_INVALID_OPERATION, + "glDeleteVertexArraysOES", "not supported."); + } + + for (GLsizei ii = 0; ii < n; ++ii) { + VertexAttribManager* vao = + GetVertexAttribManager(client_ids[ii]); + if (vao && !vao->IsDeleted()) { + if (vertex_attrib_manager_ == vao) { + vertex_attrib_manager_ = default_vertex_attrib_manager_; + } + RemoveVertexAttribManager(client_ids[ii]); + } + } +} + +void GLES2DecoderImpl::DoBindVertexArrayOES(GLuint client_id) { + if (!feature_info_->feature_flags().native_vertex_array_object_) { + // TODO(bajones): Emulate if not present + SetGLError(GL_INVALID_OPERATION, "glBindVertexArrayOES", "not supported."); + } + + VertexAttribManager* vao = NULL; + GLuint service_id = 0; + if (client_id != 0) { + vao = GetVertexAttribManager(client_id); + if (!vao) { + // Unlike most Bind* methods, the spec explicitly states that VertexArray + // only allows names that have been previously generated. As such, we do + // not generate new names here. + SetGLError(GL_INVALID_OPERATION, + "glBindVertexArrayOES", "" + "bad vertex array id."); + current_decoder_error_ = error::kNoError; + return; + } else { + service_id = vao->service_id(); + } + + vertex_attrib_manager_ = vao; + } else { + vertex_attrib_manager_ = default_vertex_attrib_manager_; + } + + glBindVertexArrayOES(service_id); +} + +bool GLES2DecoderImpl::DoIsVertexArrayOES(GLuint client_id) { + if (!feature_info_->feature_flags().native_vertex_array_object_) { + // TODO(bajones): Emulate if not present + SetGLError(GL_INVALID_OPERATION, "glIsVertexArrayOES", "not supported."); + } + + const VertexAttribManager* vao = + GetVertexAttribManager(client_id); + return vao && vao->IsValid() && !vao->IsDeleted(); +} + error::Error GLES2DecoderImpl::HandleCreateStreamTextureCHROMIUM( uint32 immediate_data_size, const gles2::CreateStreamTextureCHROMIUM& c) { diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.h b/gpu/command_buffer/service/gles2_cmd_decoder.h index 541e5da..4c87189 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder.h @@ -29,6 +29,7 @@ namespace gles2 { class ContextGroup; class GLES2Util; class QueryManager; +class VertexArrayManager; struct DisallowedFeatures { DisallowedFeatures() @@ -137,6 +138,9 @@ class GPU_EXPORT GLES2Decoder : public CommonDecoder { // Gets the QueryManager for this context. virtual QueryManager* GetQueryManager() = 0; + // Gets the VertexArrayManager for this context. + virtual VertexArrayManager* GetVertexArrayManager() = 0; + // Process any pending queries. Returns false if there are no pending queries. virtual bool ProcessPendingQueries() = 0; diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h index ed5e1d0..e347ba8 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h @@ -2646,6 +2646,95 @@ error::Error GLES2DecoderImpl::HandlePopGroupMarkerEXT( return error::kNoError; } +error::Error GLES2DecoderImpl::HandleGenVertexArraysOES( + uint32 immediate_data_size, const gles2::GenVertexArraysOES& c) { + GLsizei n = static_cast<GLsizei>(c.n); + uint32 data_size; + if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) { + return error::kOutOfBounds; + } + GLuint* arrays = GetSharedMemoryAs<GLuint*>( + c.arrays_shm_id, c.arrays_shm_offset, data_size); + if (arrays == NULL) { + return error::kOutOfBounds; + } + if (!GenVertexArraysOESHelper(n, arrays)) { + return error::kInvalidArguments; + } + return error::kNoError; +} + +error::Error GLES2DecoderImpl::HandleGenVertexArraysOESImmediate( + uint32 immediate_data_size, const gles2::GenVertexArraysOESImmediate& c) { + GLsizei n = static_cast<GLsizei>(c.n); + uint32 data_size; + if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) { + return error::kOutOfBounds; + } + GLuint* arrays = GetImmediateDataAs<GLuint*>( + c, data_size, immediate_data_size); + if (arrays == NULL) { + return error::kOutOfBounds; + } + if (!GenVertexArraysOESHelper(n, arrays)) { + return error::kInvalidArguments; + } + return error::kNoError; +} + +error::Error GLES2DecoderImpl::HandleDeleteVertexArraysOES( + uint32 immediate_data_size, const gles2::DeleteVertexArraysOES& c) { + GLsizei n = static_cast<GLsizei>(c.n); + uint32 data_size; + if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) { + return error::kOutOfBounds; + } + const GLuint* arrays = GetSharedMemoryAs<const GLuint*>( + c.arrays_shm_id, c.arrays_shm_offset, data_size); + if (arrays == NULL) { + return error::kOutOfBounds; + } + DeleteVertexArraysOESHelper(n, arrays); + return error::kNoError; +} + +error::Error GLES2DecoderImpl::HandleDeleteVertexArraysOESImmediate( + uint32 immediate_data_size, + const gles2::DeleteVertexArraysOESImmediate& c) { + GLsizei n = static_cast<GLsizei>(c.n); + uint32 data_size; + if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) { + return error::kOutOfBounds; + } + const GLuint* arrays = GetImmediateDataAs<const GLuint*>( + c, data_size, immediate_data_size); + if (arrays == NULL) { + return error::kOutOfBounds; + } + DeleteVertexArraysOESHelper(n, arrays); + return error::kNoError; +} + +error::Error GLES2DecoderImpl::HandleIsVertexArrayOES( + uint32 immediate_data_size, const gles2::IsVertexArrayOES& c) { + GLuint array = c.array; + typedef IsVertexArrayOES::Result Result; + Result* result_dst = GetSharedMemoryAs<Result*>( + c.result_shm_id, c.result_shm_offset, sizeof(*result_dst)); + if (!result_dst) { + return error::kOutOfBounds; + } + *result_dst = DoIsVertexArrayOES(array); + return error::kNoError; +} + +error::Error GLES2DecoderImpl::HandleBindVertexArrayOES( + uint32 immediate_data_size, const gles2::BindVertexArrayOES& c) { + GLuint array = c.array; + DoBindVertexArrayOES(array); + return error::kNoError; +} + error::Error GLES2DecoderImpl::HandleGetMaxValueInBufferCHROMIUM( uint32 immediate_data_size, const gles2::GetMaxValueInBufferCHROMIUM& c) { GLuint buffer_id = c.buffer_id; diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h index 95d91c5..e6e2e95 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h @@ -53,6 +53,7 @@ class MockGLES2Decoder : public GLES2Decoder { MOCK_METHOD0(GetContextGroup, ContextGroup*()); MOCK_METHOD0(ProcessPendingQueries, bool()); MOCK_METHOD0(GetQueryManager, gpu::gles2::QueryManager*()); + MOCK_METHOD0(GetVertexArrayManager, gpu::gles2::VertexArrayManager*()); MOCK_METHOD1(SetResizeCallback, void(const base::Callback<void(gfx::Size)>&)); MOCK_METHOD1(SetStreamTextureManager, void(StreamTextureManager*)); MOCK_METHOD3(DoCommand, error::Error(unsigned int command, diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc index 52a61ab..af8b6b1 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc @@ -130,6 +130,47 @@ class GLES2DecoderANGLEManualInitTest : public GLES2DecoderANGLETest { } }; +class GLES2DecoderVertexArraysOESTest : public GLES2DecoderWithShaderTest { + public: + GLES2DecoderVertexArraysOESTest() { } + + bool vertex_array_deleted_manually_; + + virtual void SetUp() { + InitDecoder( + "GL_OES_vertex_array_object", // extensions + false, // has alpha + false, // has depth + false, // has stencil + false, // request alpha + false, // request depth + false, // request stencil + true); // bind generates resource + SetupDefaultProgram(); + + EXPECT_CALL(*gl_, GenVertexArraysOES(_, _)) + .WillOnce(SetArgumentPointee<1>(kServiceVertexArrayId)) + .RetiresOnSaturation(); + GenHelper<GenVertexArraysOESImmediate>(client_vertexarray_id_); + + vertex_array_deleted_manually_ = false; + } + + virtual void TearDown() { + // This should only be set if the test handled deletion of the vertex array + // itself. Necessary because vertex_array_objects are not sharable, and thus + // not managed in the ContextGroup, meaning they will be destroyed during + // test tear down + if (!vertex_array_deleted_manually_) { + EXPECT_CALL(*gl_, DeleteVertexArraysOES(1, _)) + .Times(1) + .RetiresOnSaturation(); + } + + GLES2DecoderWithShaderTest::TearDown(); + } +}; + TEST_F(GLES2DecoderWithShaderTest, DrawArraysNoAttributesSucceeds) { SetupTexture(); AddExpectationsForSimulatedAttrib0(kNumVertices, 0); @@ -7417,6 +7458,145 @@ TEST_F(GLES2DecoderWithShaderTest, BindUniformLocationCHROMIUM) { EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); } +TEST_F(GLES2DecoderVertexArraysOESTest, GenVertexArraysOESValidArgs) { + EXPECT_CALL(*gl_, GenVertexArraysOES(1, _)) + .WillOnce(SetArgumentPointee<1>(kNewServiceId)); + GetSharedMemoryAs<GLuint*>()[0] = kNewClientId; + SpecializedSetup<GenVertexArraysOES, 0>(true); + GenVertexArraysOES cmd; + cmd.Init(1, shared_memory_id_, shared_memory_offset_); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + EXPECT_TRUE(GetVertexArrayInfo(kNewClientId) != NULL); + EXPECT_CALL(*gl_, DeleteVertexArraysOES(1, _)) + .Times(1); +} + +TEST_F(GLES2DecoderVertexArraysOESTest, GenVertexArraysOESInvalidArgs) { + EXPECT_CALL(*gl_, GenVertexArraysOES(_, _)).Times(0); + GetSharedMemoryAs<GLuint*>()[0] = client_vertexarray_id_; + SpecializedSetup<GenVertexArraysOES, 0>(false); + GenVertexArraysOES cmd; + cmd.Init(1, shared_memory_id_, shared_memory_offset_); + EXPECT_EQ(error::kInvalidArguments, ExecuteCmd(cmd)); +} + +TEST_F(GLES2DecoderVertexArraysOESTest, GenVertexArraysOESImmediateValidArgs) { + EXPECT_CALL(*gl_, GenVertexArraysOES(1, _)) + .WillOnce(SetArgumentPointee<1>(kNewServiceId)); + GenVertexArraysOESImmediate* cmd = + GetImmediateAs<GenVertexArraysOESImmediate>(); + GLuint temp = kNewClientId; + SpecializedSetup<GenVertexArraysOESImmediate, 0>(true); + cmd->Init(1, &temp); + EXPECT_EQ(error::kNoError, + ExecuteImmediateCmd(*cmd, sizeof(temp))); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + EXPECT_TRUE(GetVertexArrayInfo(kNewClientId) != NULL); + EXPECT_CALL(*gl_, DeleteVertexArraysOES(1, _)) + .Times(1); +} + +TEST_F(GLES2DecoderVertexArraysOESTest, + GenVertexArraysOESImmediateInvalidArgs) { + EXPECT_CALL(*gl_, GenVertexArraysOES(_, _)).Times(0); + GenVertexArraysOESImmediate* cmd = + GetImmediateAs<GenVertexArraysOESImmediate>(); + SpecializedSetup<GenVertexArraysOESImmediate, 0>(false); + cmd->Init(1, &client_vertexarray_id_); + EXPECT_EQ(error::kInvalidArguments, + ExecuteImmediateCmd(*cmd, sizeof(&client_vertexarray_id_))); +} + +TEST_F(GLES2DecoderVertexArraysOESTest, DeleteVertexArraysOESValidArgs) { + EXPECT_CALL( + *gl_, + DeleteVertexArraysOES(1, Pointee(kServiceVertexArrayId))) + .Times(1); + GetSharedMemoryAs<GLuint*>()[0] = client_vertexarray_id_; + SpecializedSetup<DeleteVertexArraysOES, 0>(true); + DeleteVertexArraysOES cmd; + cmd.Init(1, shared_memory_id_, shared_memory_offset_); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + EXPECT_TRUE( + GetVertexArrayInfo(client_vertexarray_id_) == NULL); + vertex_array_deleted_manually_ = true; +} + +TEST_F(GLES2DecoderVertexArraysOESTest, DeleteVertexArraysOESInvalidArgs) { + GetSharedMemoryAs<GLuint*>()[0] = kInvalidClientId; + SpecializedSetup<DeleteVertexArraysOES, 0>(false); + DeleteVertexArraysOES cmd; + cmd.Init(1, shared_memory_id_, shared_memory_offset_); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); +} + +TEST_F(GLES2DecoderVertexArraysOESTest, + DeleteVertexArraysOESImmediateValidArgs) { + EXPECT_CALL( + *gl_, + DeleteVertexArraysOES(1, Pointee(kServiceVertexArrayId))) + .Times(1); + DeleteVertexArraysOESImmediate& cmd = + *GetImmediateAs<DeleteVertexArraysOESImmediate>(); + SpecializedSetup<DeleteVertexArraysOESImmediate, 0>(true); + cmd.Init(1, &client_vertexarray_id_); + EXPECT_EQ(error::kNoError, + ExecuteImmediateCmd(cmd, sizeof(client_vertexarray_id_))); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + EXPECT_TRUE( + GetVertexArrayInfo(client_vertexarray_id_) == NULL); + vertex_array_deleted_manually_ = true; +} + +TEST_F(GLES2DecoderVertexArraysOESTest, + DeleteVertexArraysOESImmediateInvalidArgs) { + DeleteVertexArraysOESImmediate& cmd = + *GetImmediateAs<DeleteVertexArraysOESImmediate>(); + SpecializedSetup<DeleteVertexArraysOESImmediate, 0>(false); + GLuint temp = kInvalidClientId; + cmd.Init(1, &temp); + EXPECT_EQ(error::kNoError, + ExecuteImmediateCmd(cmd, sizeof(temp))); +} + +TEST_F(GLES2DecoderVertexArraysOESTest, IsVertexArrayOESValidArgs) { + SpecializedSetup<IsVertexArrayOES, 0>(true); + IsVertexArrayOES cmd; + cmd.Init(client_vertexarray_id_, shared_memory_id_, shared_memory_offset_); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +TEST_F(GLES2DecoderVertexArraysOESTest, + IsVertexArrayOESInvalidArgsBadSharedMemoryId) { + SpecializedSetup<IsVertexArrayOES, 0>(false); + IsVertexArrayOES cmd; + cmd.Init( + client_vertexarray_id_, kInvalidSharedMemoryId, shared_memory_offset_); + EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd)); + cmd.Init( + client_vertexarray_id_, shared_memory_id_, kInvalidSharedMemoryOffset); + EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd)); +} + +TEST_F(GLES2DecoderVertexArraysOESTest, BindVertexArrayOESValidArgs) { + EXPECT_CALL(*gl_, BindVertexArrayOES(kServiceVertexArrayId)); + SpecializedSetup<BindVertexArrayOES, 0>(true); + BindVertexArrayOES cmd; + cmd.Init(client_vertexarray_id_); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +TEST_F(GLES2DecoderVertexArraysOESTest, BindVertexArrayOESValidArgsNewId) { + SpecializedSetup<BindVertexArrayOES, 0>(true); + BindVertexArrayOES cmd; + cmd.Init(kNewClientId); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); +} // TODO(gman): Complete this test. // TEST_F(GLES2DecoderTest, CompressedTexImage2DGLError) { diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h index e8a03a0..a62e17c 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h @@ -1737,6 +1737,6 @@ TEST_F(GLES2DecoderTest2, PopGroupMarkerEXTValidArgs) { EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); EXPECT_EQ(GL_NO_ERROR, GetGLError()); } -// TODO(gman): SwapBuffers +// TODO(gman): GenVertexArraysOES #endif // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_2_AUTOGEN_H_ diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h index f701f8b..ff37553 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h @@ -10,6 +10,12 @@ #ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_3_AUTOGEN_H_ #define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_3_AUTOGEN_H_ +// TODO(gman): GenVertexArraysOESImmediate +// TODO(gman): DeleteVertexArraysOES +// TODO(gman): DeleteVertexArraysOESImmediate +// TODO(gman): IsVertexArrayOES +// TODO(gman): BindVertexArrayOES +// TODO(gman): SwapBuffers // TODO(gman): GetMaxValueInBufferCHROMIUM // TODO(gman): GenSharedIdsCHROMIUM diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc index 8294678..0350fd7 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc @@ -47,7 +47,8 @@ GLES2DecoderTestBase::GLES2DecoderTestBase() client_element_buffer_id_(107), client_vertex_shader_id_(121), client_fragment_shader_id_(122), - client_query_id_(123) { + client_query_id_(123), + client_vertexarray_id_(124) { memset(immediate_buffer_, 0xEE, sizeof(immediate_buffer_)); } @@ -304,6 +305,12 @@ void GLES2DecoderTestBase::InitDecoder( .Times(1) .RetiresOnSaturation(); + if (group_->feature_info()->feature_flags().native_vertex_array_object_) { + EXPECT_CALL(*gl_, BindVertexArrayOES(0)) + .Times(1) + .RetiresOnSaturation(); + } + engine_.reset(new StrictMock<MockCommandBufferEngine>()); Buffer buffer = engine_->GetSharedMemoryBuffer(kSharedMemoryId); shared_memory_offset_ = kSharedMemoryOffset; @@ -367,8 +374,6 @@ void GLES2DecoderTestBase::InitDecoder( } void GLES2DecoderTestBase::TearDown() { - InSequence sequence; - // All Tests should have read all their GLErrors before getting here. EXPECT_EQ(GL_NO_ERROR, GetGLError()); @@ -1015,6 +1020,7 @@ const GLuint GLES2DecoderTestBase::kServiceProgramId; const GLuint GLES2DecoderTestBase::kServiceShaderId; const GLuint GLES2DecoderTestBase::kServiceElementBufferId; const GLuint GLES2DecoderTestBase::kServiceQueryId; +const GLuint GLES2DecoderTestBase::kServiceVertexArrayId; const int32 GLES2DecoderTestBase::kSharedMemoryId; const size_t GLES2DecoderTestBase::kSharedBufferSize; diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h index fc91ce7..a5294f1 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h @@ -19,6 +19,7 @@ #include "gpu/command_buffer/service/shader_manager.h" #include "gpu/command_buffer/service/test_helper.h" #include "gpu/command_buffer/service/texture_manager.h" +#include "gpu/command_buffer/service/vertex_array_manager.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gl/gl_context_stub.h" #include "ui/gl/gl_surface_stub.h" @@ -124,6 +125,12 @@ class GLES2DecoderTestBase : public testing::Test { return decoder_->GetQueryManager()->GetQuery(client_id); } + // This name doesn't match the underlying function, but doing it this way + // prevents the need to special-case the unit test generation + VertexAttribManager* GetVertexArrayInfo(GLuint client_id) { + return decoder_->GetVertexArrayManager()->GetVertexAttribManager(client_id); + } + ProgramManager* program_manager() { return group_->program_manager(); } @@ -368,6 +375,7 @@ class GLES2DecoderTestBase : public testing::Test { static const GLuint kServiceShaderId = 306; static const GLuint kServiceElementBufferId = 308; static const GLuint kServiceQueryId = 309; + static const GLuint kServiceVertexArrayId = 310; static const int32 kSharedMemoryId = 401; static const size_t kSharedBufferSize = 2048; @@ -460,6 +468,7 @@ class GLES2DecoderTestBase : public testing::Test { GLuint client_vertex_shader_id_; GLuint client_fragment_shader_id_; GLuint client_query_id_; + GLuint client_vertexarray_id_; uint32 shared_memory_id_; uint32 shared_memory_offset_; diff --git a/gpu/command_buffer/service/vertex_array_manager.cc b/gpu/command_buffer/service/vertex_array_manager.cc new file mode 100644 index 0000000..d200db6 --- /dev/null +++ b/gpu/command_buffer/service/vertex_array_manager.cc @@ -0,0 +1,82 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "gpu/command_buffer/service/vertex_array_manager.h" +#include "base/debug/trace_event.h" +#include "base/logging.h" +#include "gpu/command_buffer/common/gles2_cmd_utils.h" +#include "gpu/command_buffer/service/gles2_cmd_decoder.h" +#include "gpu/command_buffer/service/vertex_attrib_manager.h" + +namespace gpu { +namespace gles2 { + +VertexArrayManager::VertexArrayManager() + : vertex_attrib_manager_count_(0), + have_context_(true) { +} + +VertexArrayManager::~VertexArrayManager() { + DCHECK(vertex_attrib_managers_.empty()); + CHECK_EQ(vertex_attrib_manager_count_, 0u); +} + +void VertexArrayManager::Destroy(bool have_context) { + have_context_ = have_context; + vertex_attrib_managers_.clear(); +} + +void VertexArrayManager::CreateVertexAttribManager( + GLuint client_id, GLuint service_id, uint32 num_vertex_attribs) { + VertexAttribManager::Ref vertex_attrib_manager( + new VertexAttribManager(this, service_id, num_vertex_attribs)); + std::pair<VertexAttribManagerMap::iterator, bool> result = + vertex_attrib_managers_.insert( + std::make_pair(client_id, vertex_attrib_manager)); + DCHECK(result.second); +} + +VertexAttribManager* VertexArrayManager::GetVertexAttribManager( + GLuint client_id) { + VertexAttribManagerMap::iterator it = vertex_attrib_managers_.find(client_id); + return it != vertex_attrib_managers_.end() ? it->second : NULL; +} + +void VertexArrayManager::RemoveVertexAttribManager(GLuint client_id) { + VertexAttribManagerMap::iterator it = vertex_attrib_managers_.find(client_id); + if (it != vertex_attrib_managers_.end()) { + VertexAttribManager* vertex_attrib_manager = it->second; + vertex_attrib_manager->MarkAsDeleted(); + vertex_attrib_managers_.erase(it); + } +} + +void VertexArrayManager::StartTracking( + VertexAttribManager* /* vertex_attrib_manager */) { + ++vertex_attrib_manager_count_; +} + +void VertexArrayManager::StopTracking( + VertexAttribManager* /* vertex_attrib_manager */) { + --vertex_attrib_manager_count_; +} + +bool VertexArrayManager::GetClientId( + GLuint service_id, GLuint* client_id) const { + // This doesn't need to be fast. It's only used during slow queries. + for (VertexAttribManagerMap::const_iterator it = + vertex_attrib_managers_.begin(); + it != vertex_attrib_managers_.end(); ++it) { + if (it->second->service_id() == service_id) { + *client_id = it->first; + return true; + } + } + return false; +} + +} // namespace gles2 +} // namespace gpu + + diff --git a/gpu/command_buffer/service/vertex_array_manager.h b/gpu/command_buffer/service/vertex_array_manager.h new file mode 100644 index 0000000..1a1fc4a --- /dev/null +++ b/gpu/command_buffer/service/vertex_array_manager.h @@ -0,0 +1,67 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef GPU_COMMAND_BUFFER_SERVICE_VERTEX_ARRAY_MANAGER_H_ +#define GPU_COMMAND_BUFFER_SERVICE_VERTEX_ARRAY_MANAGER_H_ + +#include "base/basictypes.h" +#include "base/hash_tables.h" +#include "base/logging.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "gpu/command_buffer/service/gl_utils.h" +#include "gpu/gpu_export.h" + +namespace gpu { +namespace gles2 { + +class VertexAttribManager; + +// This class keeps track of the vertex arrays and their sizes so we can do +// bounds checking. +class GPU_EXPORT VertexArrayManager { + public: + VertexArrayManager(); + ~VertexArrayManager(); + + // Must call before destruction. + void Destroy(bool have_context); + + // Creates a VertexArrayInfo for the given vertex array. + void CreateVertexAttribManager(GLuint client_id, GLuint service_id, + uint32 num_vertex_attribs); + + // Gets the vertex attrib manager for the given vertex array. + VertexAttribManager* GetVertexAttribManager(GLuint client_id); + + // Removes the vertex attrib manager for the given vertex array. + void RemoveVertexAttribManager(GLuint client_id); + + // Gets a client id for a given service id. + bool GetClientId(GLuint service_id, GLuint* client_id) const; + + private: + friend class VertexAttribManager; + + void StartTracking(VertexAttribManager* vertex_attrib_manager); + void StopTracking(VertexAttribManager* vertex_attrib_manager); + + // Info for each vertex array in the system. + typedef base::hash_map<GLuint, scoped_refptr<VertexAttribManager> > + VertexAttribManagerMap; + VertexAttribManagerMap vertex_attrib_managers_; + + // Counts the number of VertexArrayInfo allocated with 'this' as its manager. + // Allows to check no VertexArrayInfo will outlive this. + unsigned int vertex_attrib_manager_count_; + + bool have_context_; + + DISALLOW_COPY_AND_ASSIGN(VertexArrayManager); +}; + +} // namespace gles2 +} // namespace gpu + +#endif // GPU_COMMAND_BUFFER_SERVICE_VERTEX_ARRAY_MANAGER_H_ diff --git a/gpu/command_buffer/service/vertex_array_manager_unittest.cc b/gpu/command_buffer/service/vertex_array_manager_unittest.cc new file mode 100644 index 0000000..e411489 --- /dev/null +++ b/gpu/command_buffer/service/vertex_array_manager_unittest.cc @@ -0,0 +1,103 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "gpu/command_buffer/service/vertex_array_manager.h" +#include "gpu/command_buffer/service/vertex_attrib_manager.h" + +#include "base/memory/scoped_ptr.h" +#include "gpu/command_buffer/common/gl_mock.h" +#include "gpu/command_buffer/service/feature_info.h" +#include "gpu/command_buffer/service/test_helper.h" +#include "testing/gtest/include/gtest/gtest.h" + +using ::testing::Pointee; +using ::testing::_; + +namespace gpu { +namespace gles2 { + +class VertexArrayManagerTest : public testing::Test { + public: + static const uint32 kNumVertexAttribs = 8; + + VertexArrayManagerTest() { + } + + ~VertexArrayManagerTest() { + } + + protected: + virtual void SetUp() { + gl_.reset(new ::testing::StrictMock< ::gfx::MockGLInterface>()); + ::gfx::GLInterface::SetGLInterface(gl_.get()); + + manager_ = new VertexArrayManager(); + } + + virtual void TearDown() { + delete manager_; + ::gfx::GLInterface::SetGLInterface(NULL); + gl_.reset(); + } + + // Use StrictMock to make 100% sure we know how GL will be called. + scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_; + VertexArrayManager* manager_; +}; + +// GCC requires these declarations, but MSVC requires they not be present +#ifndef COMPILER_MSVC +const uint32 VertexArrayManagerTest::kNumVertexAttribs; +#endif + +TEST_F(VertexArrayManagerTest, Basic) { + const GLuint kClient1Id = 1; + const GLuint kService1Id = 11; + const GLuint kClient2Id = 2; + + // Check we can create + manager_->CreateVertexAttribManager( + kClient1Id, kService1Id, kNumVertexAttribs); + // Check creation success + VertexAttribManager* info1 = manager_->GetVertexAttribManager(kClient1Id); + ASSERT_TRUE(info1 != NULL); + EXPECT_EQ(kService1Id, info1->service_id()); + GLuint client_id = 0; + EXPECT_TRUE(manager_->GetClientId(info1->service_id(), &client_id)); + EXPECT_EQ(kClient1Id, client_id); + // Check we get nothing for a non-existent name. + EXPECT_TRUE(manager_->GetVertexAttribManager(kClient2Id) == NULL); + // Check trying to a remove non-existent name does not crash. + manager_->RemoveVertexAttribManager(kClient2Id); + // Check that it gets deleted when the last reference is released. + EXPECT_CALL(*gl_, DeleteVertexArraysOES(1, ::testing::Pointee(kService1Id))) + .Times(1) + .RetiresOnSaturation(); + // Check we can't get the texture after we remove it. + manager_->RemoveVertexAttribManager(kClient1Id); + EXPECT_TRUE(manager_->GetVertexAttribManager(kClient1Id) == NULL); +} + +TEST_F(VertexArrayManagerTest, Destroy) { + const GLuint kClient1Id = 1; + const GLuint kService1Id = 11; + VertexArrayManager manager; + // Check we can create + manager.CreateVertexAttribManager(kClient1Id, kService1Id, kNumVertexAttribs); + // Check creation success + VertexAttribManager* info1 = manager.GetVertexAttribManager(kClient1Id); + ASSERT_TRUE(info1 != NULL); + EXPECT_CALL(*gl_, DeleteVertexArraysOES(1, ::testing::Pointee(kService1Id))) + .Times(1) + .RetiresOnSaturation(); + manager.Destroy(true); + // Check that resources got freed. + info1 = manager.GetVertexAttribManager(kClient1Id); + ASSERT_TRUE(info1 == NULL); +} + +} // namespace gles2 +} // namespace gpu + + diff --git a/gpu/command_buffer/service/vertex_attrib_manager.cc b/gpu/command_buffer/service/vertex_attrib_manager.cc index e1bde6d..7d15938 100644 --- a/gpu/command_buffer/service/vertex_attrib_manager.cc +++ b/gpu/command_buffer/service/vertex_attrib_manager.cc @@ -15,6 +15,7 @@ #include "gpu/command_buffer/common/gles2_cmd_utils.h" #include "gpu/command_buffer/service/gl_utils.h" #include "gpu/command_buffer/service/gpu_switches.h" +#include "gpu/command_buffer/service/vertex_array_manager.h" namespace gpu { namespace gles2 { @@ -63,13 +64,38 @@ bool VertexAttribManager::VertexAttribInfo::CanAccess(GLuint index) const { VertexAttribManager::VertexAttribManager() : max_vertex_attribs_(0), - num_fixed_attribs_(0) { + num_fixed_attribs_(0), + element_array_buffer_(NULL), + manager_(NULL), + deleted_(false), + service_id_(0) { +} + +VertexAttribManager::VertexAttribManager( + VertexArrayManager* manager, GLuint service_id, uint32 num_vertex_attribs) + : max_vertex_attribs_(0), + num_fixed_attribs_(0), + element_array_buffer_(NULL), + manager_(manager), + deleted_(false), + service_id_(service_id) { + manager_->StartTracking(this); + Initialize(num_vertex_attribs, false); } VertexAttribManager::~VertexAttribManager() { + if (manager_) { + if (manager_->have_context_) { + GLuint id = service_id(); + glDeleteVertexArraysOES(1, &id); + } + manager_->StopTracking(this); + manager_ = NULL; + } } -void VertexAttribManager::Initialize(uint32 max_vertex_attribs) { +void VertexAttribManager::Initialize( + uint32 max_vertex_attribs, bool init_attribs) { max_vertex_attribs_ = max_vertex_attribs; vertex_attrib_infos_.reset( new VertexAttribInfo[max_vertex_attribs]); @@ -79,7 +105,8 @@ void VertexAttribManager::Initialize(uint32 max_vertex_attribs) { for (uint32 vv = 0; vv < max_vertex_attribs; ++vv) { vertex_attrib_infos_[vv].set_index(vv); vertex_attrib_infos_[vv].SetList(&disabled_vertex_attribs_); - if (!disable_workarounds) { + + if (!disable_workarounds && init_attribs) { glVertexAttrib4f(vv, 0.0f, 0.0f, 0.0f, 1.0f); } } @@ -98,6 +125,9 @@ bool VertexAttribManager::Enable(GLuint index, bool enable) { } void VertexAttribManager::Unbind(BufferManager::BufferInfo* buffer) { + if (element_array_buffer_ == buffer) { + element_array_buffer_ = NULL; + } for (uint32 vv = 0; vv < max_vertex_attribs_; ++vv) { vertex_attrib_infos_[vv].Unbind(buffer); } diff --git a/gpu/command_buffer/service/vertex_attrib_manager.h b/gpu/command_buffer/service/vertex_attrib_manager.h index c42c8d6..700b545 100644 --- a/gpu/command_buffer/service/vertex_attrib_manager.h +++ b/gpu/command_buffer/service/vertex_attrib_manager.h @@ -4,7 +4,7 @@ #include <list> #include "base/logging.h" -#include "base/memory/scoped_ptr.h" +#include "base/memory/ref_counted.h" #include "build/build_config.h" #include "gpu/command_buffer/service/buffer_manager.h" #include "gpu/command_buffer/service/gl_utils.h" @@ -13,9 +13,16 @@ namespace gpu { namespace gles2 { +class VertexArrayManager; + // Manages vertex attributes. -class GPU_EXPORT VertexAttribManager { +// This class also acts as the service-side representation of a +// vertex array object and it's contained state. +class GPU_EXPORT VertexAttribManager : + public base::RefCounted<VertexAttribManager> { public: + typedef scoped_refptr<VertexAttribManager> Ref; + // Info about Vertex Attributes. This is used to track what the user currently // has bound on each Vertex Attribute so that checking can be done at // glDrawXXX time. @@ -176,9 +183,8 @@ class GPU_EXPORT VertexAttribManager { typedef std::list<VertexAttribInfo*> VertexAttribInfoList; VertexAttribManager(); - ~VertexAttribManager(); - void Initialize(uint32 num_vertex_attribs); + void Initialize(uint32 num_vertex_attribs, bool init_attribs = true); bool Enable(GLuint index, bool enable); @@ -226,9 +232,43 @@ class GPU_EXPORT VertexAttribManager { } } + void SetElementArrayBuffer(BufferManager::BufferInfo* buffer) { + element_array_buffer_ = buffer; + } + + BufferManager::BufferInfo* element_array_buffer() const { + return element_array_buffer_; + } + + GLuint service_id() const { + return service_id_; + } + void Unbind(BufferManager::BufferInfo* buffer); + bool IsDeleted() const { + return deleted_; + } + + bool IsValid() const { + return !IsDeleted(); + } + private: + friend class VertexArrayManager; + friend class VertexArrayManagerTest; + friend class base::RefCounted<VertexAttribManager>; + + // Used when creating from a VertexArrayManager + VertexAttribManager(VertexArrayManager* manager, GLuint service_id, + uint32 num_vertex_attribs); + + ~VertexAttribManager(); + + void MarkAsDeleted() { + deleted_ = true; + } + uint32 max_vertex_attribs_; // number of attribs using type GL_FIXED. @@ -238,9 +278,22 @@ class GPU_EXPORT VertexAttribManager { // if it is safe to draw. scoped_array<VertexAttribInfo> vertex_attrib_infos_; + // The currently bound element array buffer. If this is 0 it is illegal + // to call glDrawElements. + BufferManager::BufferInfo::Ref element_array_buffer_; + // Lists for which vertex attribs are enabled, disabled. VertexAttribInfoList enabled_vertex_attribs_; VertexAttribInfoList disabled_vertex_attribs_; + + // The VertexArrayManager that owns this VertexAttribManager + VertexArrayManager* manager_; + + // True if deleted. + bool deleted_; + + // Service side vertex array object id. + GLuint service_id_; }; } // namespace gles2 diff --git a/gpu/command_buffer/service/vertex_attrib_manager_unittest.cc b/gpu/command_buffer/service/vertex_attrib_manager_unittest.cc index cb34022..8217ec3 100644 --- a/gpu/command_buffer/service/vertex_attrib_manager_unittest.cc +++ b/gpu/command_buffer/service/vertex_attrib_manager_unittest.cc @@ -37,19 +37,19 @@ class VertexAttribManagerTest : public testing::Test { .RetiresOnSaturation(); } - manager_.reset(new VertexAttribManager()); + manager_ = new VertexAttribManager(); manager_->Initialize(kNumVertexAttribs); } virtual void TearDown() { - manager_.reset(); + manager_ = NULL; ::gfx::GLInterface::SetGLInterface(NULL); gl_.reset(); } // Use StrictMock to make 100% sure we know how GL will be called. scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_; - scoped_ptr<VertexAttribManager> manager_; + VertexAttribManager::Ref manager_; }; // GCC requires these declarations, but MSVC requires they not be present @@ -131,7 +131,7 @@ TEST_F(VertexAttribManagerTest, SetAttribInfo) { // The VertexAttribManager must be destroyed before the BufferManager // so it releases its buffers. - manager_.reset(); + manager_ = NULL; buffer_manager.Destroy(false); } @@ -185,7 +185,7 @@ TEST_F(VertexAttribManagerTest, CanAccess) { // The VertexAttribManager must be destroyed before the BufferManager // so it releases its buffers. - manager_.reset(); + manager_ = NULL; buffer_manager.Destroy(false); } @@ -222,7 +222,7 @@ TEST_F(VertexAttribManagerTest, Unbind) { // The VertexAttribManager must be destroyed before the BufferManager // so it releases its buffers. - manager_.reset(); + manager_ = NULL; buffer_manager.Destroy(false); } diff --git a/gpu/command_buffer_service.gypi b/gpu/command_buffer_service.gypi index 7c70c5d..0934f93 100644 --- a/gpu/command_buffer_service.gypi +++ b/gpu/command_buffer_service.gypi @@ -84,6 +84,8 @@ 'command_buffer/service/texture_manager.cc', 'command_buffer/service/transfer_buffer_manager.cc', 'command_buffer/service/transfer_buffer_manager.h', + 'command_buffer/service/vertex_array_manager.h', + 'command_buffer/service/vertex_array_manager.cc', 'command_buffer/service/vertex_attrib_manager.h', 'command_buffer/service/vertex_attrib_manager.cc', ], diff --git a/gpu/gpu.gyp b/gpu/gpu.gyp index 0b805c1..fc4c6f4 100644 --- a/gpu/gpu.gyp +++ b/gpu/gpu.gyp @@ -205,6 +205,7 @@ 'command_buffer/service/texture_manager_unittest.cc', 'command_buffer/service/transfer_buffer_manager_unittest.cc', 'command_buffer/service/vertex_attrib_manager_unittest.cc', + 'command_buffer/service/vertex_array_manager_unittest.cc', ], 'conditions': [ ['OS == "android" and gtest_target_type == "shared_library"', { |