summaryrefslogtreecommitdiffstats
path: root/gpu
diff options
context:
space:
mode:
authorbajones@google.com <bajones@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-27 02:20:46 +0000
committerbajones@google.com <bajones@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-27 02:20:46 +0000
commit944b62f3edd69cee4fd31e21fb80ca0eafe9b217 (patch)
tree8ae5c82188ae1100fb60eb1e6ede8af2efdc73ee /gpu
parent01719f74ea916ef20b5df705a314c6b6fd659524 (diff)
downloadchromium_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')
-rwxr-xr-xgpu/command_buffer/build_gles2_cmd_buffer.py101
-rw-r--r--gpu/command_buffer/client/gles2_c_lib_autogen.h12
-rw-r--r--gpu/command_buffer/client/gles2_cmd_helper_autogen.h52
-rw-r--r--gpu/command_buffer/client/gles2_implementation.cc28
-rw-r--r--gpu/command_buffer/client/gles2_implementation.h7
-rw-r--r--gpu/command_buffer/client/gles2_implementation_autogen.h64
-rw-r--r--gpu/command_buffer/client/gles2_implementation_unittest.cc29
-rw-r--r--gpu/command_buffer/client/gles2_implementation_unittest_autogen.h61
-rw-r--r--gpu/command_buffer/cmd_buffer_functions.txt5
-rw-r--r--gpu/command_buffer/common/gl_mock.h8
-rw-r--r--gpu/command_buffer/common/gles2_cmd_format.h1
-rw-r--r--gpu/command_buffer/common/gles2_cmd_format_autogen.h253
-rw-r--r--gpu/command_buffer/common/gles2_cmd_format_test_autogen.h100
-rw-r--r--gpu/command_buffer/common/gles2_cmd_ids_autogen.h62
-rw-r--r--gpu/command_buffer/service/context_group.cc1
-rw-r--r--gpu/command_buffer/service/feature_info.cc9
-rw-r--r--gpu/command_buffer/service/feature_info.h1
-rw-r--r--gpu/command_buffer/service/feature_info_unittest.cc33
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.cc180
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.h4
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_autogen.h89
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_mock.h1
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc180
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h2
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h6
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc12
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h9
-rw-r--r--gpu/command_buffer/service/vertex_array_manager.cc82
-rw-r--r--gpu/command_buffer/service/vertex_array_manager.h67
-rw-r--r--gpu/command_buffer/service/vertex_array_manager_unittest.cc103
-rw-r--r--gpu/command_buffer/service/vertex_attrib_manager.cc36
-rw-r--r--gpu/command_buffer/service/vertex_attrib_manager.h61
-rw-r--r--gpu/command_buffer/service/vertex_attrib_manager_unittest.cc12
-rw-r--r--gpu/command_buffer_service.gypi2
-rw-r--r--gpu/gpu.gyp1
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"', {