summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xgpu/command_buffer/build_gles2_cmd_buffer.py144
-rw-r--r--gpu/command_buffer/client/gles2_c_lib_autogen.h8
-rw-r--r--gpu/command_buffer/client/gles2_cmd_helper_autogen.h54
-rw-r--r--gpu/command_buffer/client/gles2_implementation.cc188
-rw-r--r--gpu/command_buffer/client/gles2_implementation.h6
-rw-r--r--gpu/command_buffer/client/gles2_implementation_autogen.h67
-rw-r--r--gpu/command_buffer/client/gles2_implementation_unittest.cc135
-rw-r--r--gpu/command_buffer/client/gles2_implementation_unittest_autogen.h31
-rw-r--r--gpu/command_buffer/client/query_tracker.cc130
-rw-r--r--gpu/command_buffer/client/query_tracker.h167
-rw-r--r--gpu/command_buffer/client/query_tracker_unittest.cc171
-rw-r--r--gpu/command_buffer/cmd_buffer_functions.txt4
-rw-r--r--gpu/command_buffer/common/gl_mock.h15
-rw-r--r--gpu/command_buffer/common/gles2_cmd_format.h11
-rw-r--r--gpu/command_buffer/common/gles2_cmd_format_autogen.h279
-rw-r--r--gpu/command_buffer/common/gles2_cmd_format_test_autogen.h93
-rw-r--r--gpu/command_buffer/common/gles2_cmd_ids_autogen.h49
-rw-r--r--gpu/command_buffer/service/common_decoder.h28
-rw-r--r--gpu/command_buffer/service/context_group.cc1
-rw-r--r--gpu/command_buffer/service/feature_info.cc8
-rw-r--r--gpu/command_buffer/service/feature_info.h4
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.cc158
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.h4
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_autogen.h93
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_mock.h3
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc90
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc68
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h98
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h2
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc4
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h19
-rw-r--r--gpu/command_buffer/service/query_manager.cc177
-rw-r--r--gpu/command_buffer/service/query_manager.h163
-rw-r--r--gpu/command_buffer/service/query_manager_unittest.cc457
-rw-r--r--gpu/command_buffer_client.gypi2
-rw-r--r--gpu/command_buffer_service.gypi2
-rw-r--r--gpu/gpu_common.gypi2
-rw-r--r--ppapi/native_client/src/shared/ppapi_proxy/nacl.scons1
-rw-r--r--ppapi/native_client/src/shared/ppapi_proxy/ppapi_proxy_untrusted.gyp1
-rwxr-xr-xui/gfx/gl/generate_bindings.py34
-rw-r--r--ui/gfx/gl/gl_interface.h16
41 files changed, 2569 insertions, 418 deletions
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py
index 8a272e9..fbaa67d 100755
--- a/gpu/command_buffer/build_gles2_cmd_buffer.py
+++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -898,15 +898,21 @@ _FUNCTION_INFO = {
'DeleteBuffers': {
'type': 'DELn',
'gl_test_func': 'glDeleteBuffersARB',
+ 'resource_type': 'Buffer',
+ 'resource_types': 'Buffers',
},
'DeleteFramebuffers': {
'type': 'DELn',
'gl_test_func': 'glDeleteFramebuffersEXT',
+ 'resource_type': 'Framebuffer',
+ 'resource_types': 'Framebuffers',
},
'DeleteProgram': {'type': 'Delete', 'decoder_func': 'DoDeleteProgram'},
'DeleteRenderbuffers': {
'type': 'DELn',
'gl_test_func': 'glDeleteRenderbuffersEXT',
+ 'resource_type': 'Renderbuffer',
+ 'resource_types': 'Renderbuffers',
},
'DeleteShader': {'type': 'Delete', 'decoder_func': 'DoDeleteShader'},
'DeleteSharedIdsCHROMIUM': {
@@ -918,7 +924,11 @@ _FUNCTION_INFO = {
'extension': True,
'chromium': True,
},
- 'DeleteTextures': {'type': 'DELn'},
+ 'DeleteTextures': {
+ 'type': 'DELn',
+ 'resource_type': 'Texture',
+ 'resource_types': 'Textures',
+ },
'DepthRangef': {'decoder_func': 'glDepthRange'},
'DepthMask': {'decoder_func': 'DoDepthMask', 'expectation': False},
'DetachShader': {'decoder_func': 'DoDetachShader'},
@@ -949,8 +959,12 @@ _FUNCTION_INFO = {
'Finish': {
'impl_func': False,
'client_test': False,
+ 'decoder_func': 'DoFinish',
+ },
+ 'Flush': {
+ 'impl_func': False,
+ 'decoder_func': 'DoFlush',
},
- 'Flush': {'impl_func': False},
'FramebufferRenderbuffer': {
'decoder_func': 'DoFramebufferRenderbuffer',
'gl_test_func': 'glFramebufferRenderbufferEXT',
@@ -963,10 +977,29 @@ _FUNCTION_INFO = {
'decoder_func': 'DoGenerateMipmap',
'gl_test_func': 'glGenerateMipmapEXT',
},
- 'GenBuffers': {'type': 'GENn', 'gl_test_func': 'glGenBuffersARB'},
- 'GenFramebuffers': {'type': 'GENn', 'gl_test_func': 'glGenFramebuffersEXT'},
- 'GenRenderbuffers': {'type': 'GENn', 'gl_test_func': 'glGenRenderbuffersEXT'},
- 'GenTextures': {'type': 'GENn', 'gl_test_func': 'glGenTextures'},
+ 'GenBuffers': {
+ 'type': 'GENn',
+ 'gl_test_func': 'glGenBuffersARB',
+ 'resource_type': 'Buffer',
+ 'resource_types': 'Buffers',
+ },
+ 'GenFramebuffers': {
+ 'type': 'GENn',
+ 'gl_test_func': 'glGenFramebuffersEXT',
+ 'resource_type': 'Framebuffer',
+ 'resource_types': 'Framebuffers',
+ },
+ 'GenRenderbuffers': {
+ 'type': 'GENn', 'gl_test_func': 'glGenRenderbuffersEXT',
+ 'resource_type': 'Renderbuffer',
+ 'resource_types': 'Renderbuffers',
+ },
+ 'GenTextures': {
+ 'type': 'GENn',
+ 'gl_test_func': 'glGenTextures',
+ 'resource_type': 'Texture',
+ 'resource_types': 'Textures',
+ },
'GenSharedIdsCHROMIUM': {
'type': 'Custom',
'decoder_func': 'DoGenSharedIdsCHROMIUM',
@@ -1556,13 +1589,44 @@ _FUNCTION_INFO = {
'unit_test': False,
'pepper_interface': 'InstancedArrays',
},
- 'GenQueriesEXT': {'type': 'Todo'},
- 'DeleteQueriesEXT': {'type': 'Todo'},
- 'IsQueryEXT': {'type': 'Todo'},
- 'BeginQueryEXT': {'type': 'Todo'},
- 'EndQueryEXT': {'type': 'Todo'},
- 'GetQueryivEXT': {'type': 'Todo'},
- 'GetQueryObjectuivEXT': {'type': 'Todo'},
+ 'GenQueriesEXT': {
+ 'type': 'GENn',
+ 'gl_test_func': 'glGenQueriesARB',
+ 'resource_type': 'Query',
+ 'resource_types': 'Queries',
+ },
+ 'DeleteQueriesEXT': {
+ 'type': 'DELn',
+ 'gl_test_func': 'glDeleteQueriesARB',
+ 'resource_type': 'Query',
+ 'resource_types': 'Queries',
+ },
+ 'IsQueryEXT': {
+ 'gen_cmd': False,
+ 'client_test': False,
+ },
+ 'BeginQueryEXT': {
+ 'type': 'Manual',
+ 'cmd_args': 'GLenumQueryTarget target, GLidQuery id, void* sync_data',
+ 'immediate': False,
+ 'gl_test_func': 'glBeginQuery',
+ },
+ 'EndQueryEXT': {
+ 'type': 'Manual',
+ 'cmd_args': 'GLenumQueryTarget target, GLuint submit_count',
+ 'gl_test_func': 'glEndnQuery',
+ 'client_test': False,
+ },
+ 'GetQueryivEXT': {
+ 'gen_cmd': False,
+ 'client_test': False,
+ 'gl_test_func': 'glGetQueryiv',
+ },
+ 'GetQueryObjectuivEXT': {
+ 'gen_cmd': False,
+ 'client_test': False,
+ 'gl_test_func': 'glGetQueryObjectuiv',
+ },
}
@@ -1651,18 +1715,6 @@ class CWriter(object):
while not done:
splitter = string[0:end].rfind(',')
if splitter < 0 or (splitter > 0 and string[splitter - 1] == '"'):
- if last_splitter == -1:
- break
- return last_splitter
- elif splitter >= 80:
- end = splitter
- else:
- return splitter
- end = len(string)
- last_splitter = -1
- while not done:
- splitter = string[0:end].rfind(' ')
- if splitter < 0 or (splitter > 0 and string[splitter - 1] == '"'):
return last_splitter
elif splitter >= 80:
end = splitter
@@ -2688,7 +2740,7 @@ class GENnHandler(TypeHandler):
'name': func.original_name,
'typed_args': func.MakeTypedOriginalArgString(""),
'args': func.MakeOriginalArgString(""),
- 'resource_type': func.GetInfo('resource_type') or func.name[3:],
+ 'resource_types': func.GetInfo('resource_types'),
'count_name': func.GetOriginalArgs()[0].name,
}
file.Write("%(return_type)s %(name)s(%(typed_args)s) {\n" % args)
@@ -2697,7 +2749,7 @@ class GENnHandler(TypeHandler):
for arg in func.GetOriginalArgs():
arg.WriteClientSideValidationCode(file, func)
code = """ GPU_CLIENT_SINGLE_THREAD_CHECK();
- id_handlers_[id_namespaces::k%(resource_type)s]->
+ id_handlers_[id_namespaces::k%(resource_types)s]->
MakeIds(0, %(args)s);
helper_->%(name)sImmediate(%(args)s);
%(log_code)s
@@ -2717,17 +2769,17 @@ TEST_F(GLES2ImplementationTest, %(name)s) {
};
Cmds expected;
expected.gen.Init(arraysize(ids), &ids[0]);
- expected.data[0] = k%(type)ssStartId;
- expected.data[1] = k%(type)ssStartId + 1;
+ expected.data[0] = k%(types)sStartId;
+ expected.data[1] = k%(types)sStartId + 1;
gl_->%(name)s(arraysize(ids), &ids[0]);
EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
- EXPECT_EQ(k%(type)ssStartId, ids[0]);
- EXPECT_EQ(k%(type)ssStartId + 1, ids[1]);
+ EXPECT_EQ(k%(types)sStartId, ids[0]);
+ EXPECT_EQ(k%(types)sStartId + 1, ids[1]);
}
"""
file.Write(code % {
'name': func.name,
- 'type': func.name[3:-1],
+ 'types': func.GetInfo('resource_types'),
})
def WriteServiceUnitTest(self, func, file):
@@ -2746,7 +2798,7 @@ TEST_F(%(test_name)s, %(name)sValidArgs) {
}
"""
self.WriteValidUnitTest(func, file, valid_test, {
- 'resource_name': func.name[3:-1],
+ 'resource_name': func.GetInfo('resource_type'),
})
invalid_test = """
TEST_F(%(test_name)s, %(name)sInvalidArgs) {
@@ -2759,7 +2811,7 @@ TEST_F(%(test_name)s, %(name)sInvalidArgs) {
}
"""
self.WriteValidUnitTest(func, file, invalid_test, {
- 'resource_name': func.GetOriginalArgs()[1].name[0:-1]
+ 'resource_name': func.GetInfo('resource_type').lower(),
})
def WriteImmediateServiceUnitTest(self, func, file):
@@ -2779,7 +2831,7 @@ TEST_F(%(test_name)s, %(name)sValidArgs) {
}
"""
self.WriteValidUnitTest(func, file, valid_test, {
- 'resource_name': func.original_name[3:-1],
+ 'resource_name': func.GetInfo('resource_type'),
})
invalid_test = """
TEST_F(%(test_name)s, %(name)sInvalidArgs) {
@@ -2792,7 +2844,7 @@ TEST_F(%(test_name)s, %(name)sInvalidArgs) {
}
"""
self.WriteValidUnitTest(func, file, invalid_test, {
- 'resource_name': func.GetOriginalArgs()[1].name[0:-1]
+ 'resource_name': func.GetInfo('resource_type').lower(),
})
def WriteImmediateCmdComputeSize(self, func, file):
@@ -3004,22 +3056,22 @@ class DELnHandler(TypeHandler):
"""Overrriden from TypeHandler."""
code = """
TEST_F(GLES2ImplementationTest, %(name)s) {
- GLuint ids[2] = { k%(type)ssStartId, k%(type)ssStartId + 1 };
+ GLuint ids[2] = { k%(types)sStartId, k%(types)sStartId + 1 };
struct Cmds {
%(name)sImmediate del;
GLuint data[2];
};
Cmds expected;
expected.del.Init(arraysize(ids), &ids[0]);
- expected.data[0] = k%(type)ssStartId;
- expected.data[1] = k%(type)ssStartId + 1;
+ expected.data[0] = k%(types)sStartId;
+ expected.data[1] = k%(types)sStartId + 1;
gl_->%(name)s(arraysize(ids), &ids[0]);
EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
}
"""
file.Write(code % {
'name': func.name,
- 'type': func.GetOriginalArgs()[1].name[0:-1].capitalize(),
+ 'types': func.GetInfo('resource_types'),
})
def WriteServiceUnitTest(self, func, file):
@@ -3041,9 +3093,8 @@ TEST_F(%(test_name)s, %(name)sValidArgs) {
}
"""
self.WriteValidUnitTest(func, file, valid_test, {
- 'resource_name': func.GetOriginalArgs()[1].name[0:-1],
- 'upper_resource_name':
- func.GetOriginalArgs()[1].name[0:-1].capitalize(),
+ 'resource_name': func.GetInfo('resource_type').lower(),
+ 'upper_resource_name': func.GetInfo('resource_type'),
})
invalid_test = """
TEST_F(%(test_name)s, %(name)sInvalidArgs) {
@@ -3075,9 +3126,8 @@ TEST_F(%(test_name)s, %(name)sValidArgs) {
}
"""
self.WriteValidUnitTest(func, file, valid_test, {
- 'resource_name': func.GetOriginalArgs()[1].name[0:-1],
- 'upper_resource_name':
- func.GetOriginalArgs()[1].name[0:-1].capitalize(),
+ 'resource_name': func.GetInfo('resource_type').lower(),
+ 'upper_resource_name': func.GetInfo('resource_type'),
})
invalid_test = """
TEST_F(%(test_name)s, %(name)sInvalidArgs) {
@@ -3110,7 +3160,7 @@ TEST_F(%(test_name)s, %(name)sInvalidArgs) {
'name': func.original_name,
'typed_args': func.MakeTypedOriginalArgString(""),
'args': func.MakeOriginalArgString(""),
- 'resource_type': func.name[6:-1].lower(),
+ 'resource_type': func.GetInfo('resource_type').lower(),
'count_name': func.GetOriginalArgs()[0].name,
}
file.Write("%(return_type)s %(name)s(%(typed_args)s) {\n" % args)
diff --git a/gpu/command_buffer/client/gles2_c_lib_autogen.h b/gpu/command_buffer/client/gles2_c_lib_autogen.h
index 8698dce..6d86539 100644
--- a/gpu/command_buffer/client/gles2_c_lib_autogen.h
+++ b/gpu/command_buffer/client/gles2_c_lib_autogen.h
@@ -520,11 +520,11 @@ void GLES2TexStorage2DEXT(
gles2::GetGLContext()->TexStorage2DEXT(
target, levels, internalFormat, width, height);
}
-void GLES2GenQueriesEXT(GLsizei n, GLuint* ids) {
- gles2::GetGLContext()->GenQueriesEXT(n, ids);
+void GLES2GenQueriesEXT(GLsizei n, GLuint* queries) {
+ gles2::GetGLContext()->GenQueriesEXT(n, queries);
}
-void GLES2DeleteQueriesEXT(GLsizei n, const GLuint* ids) {
- gles2::GetGLContext()->DeleteQueriesEXT(n, ids);
+void GLES2DeleteQueriesEXT(GLsizei n, const GLuint* queries) {
+ gles2::GetGLContext()->DeleteQueriesEXT(n, queries);
}
GLboolean GLES2IsQueryEXT(GLuint id) {
return gles2::GetGLContext()->IsQueryEXT(id);
diff --git a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
index 524fd74..77e1ff2 100644
--- a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
+++ b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
@@ -1524,57 +1524,53 @@
}
}
- void GenQueriesEXT(GLsizei n, uint32 ids_shm_id, uint32 ids_shm_offset) {
+ void GenQueriesEXT(
+ GLsizei n, uint32 queries_shm_id, uint32 queries_shm_offset) {
gles2::GenQueriesEXT* c = GetCmdSpace<gles2::GenQueriesEXT>();
if (c) {
- c->Init(n, ids_shm_id, ids_shm_offset);
+ c->Init(n, queries_shm_id, queries_shm_offset);
}
}
- void DeleteQueriesEXT(GLsizei n, uint32 ids_shm_id, uint32 ids_shm_offset) {
- gles2::DeleteQueriesEXT* c = GetCmdSpace<gles2::DeleteQueriesEXT>();
+ void GenQueriesEXTImmediate(GLsizei n, GLuint* queries) {
+ const uint32 size = gles2::GenQueriesEXTImmediate::ComputeSize(n);
+ gles2::GenQueriesEXTImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::GenQueriesEXTImmediate>(size);
if (c) {
- c->Init(n, ids_shm_id, ids_shm_offset);
+ c->Init(n, queries);
}
}
- void IsQueryEXT(GLuint id) {
- gles2::IsQueryEXT* c = GetCmdSpace<gles2::IsQueryEXT>();
+ void DeleteQueriesEXT(
+ GLsizei n, uint32 queries_shm_id, uint32 queries_shm_offset) {
+ gles2::DeleteQueriesEXT* c = GetCmdSpace<gles2::DeleteQueriesEXT>();
if (c) {
- c->Init(id);
+ c->Init(n, queries_shm_id, queries_shm_offset);
}
}
- void BeginQueryEXT(GLenum target, GLuint id) {
- gles2::BeginQueryEXT* c = GetCmdSpace<gles2::BeginQueryEXT>();
+ void DeleteQueriesEXTImmediate(GLsizei n, const GLuint* queries) {
+ const uint32 size = gles2::DeleteQueriesEXTImmediate::ComputeSize(n);
+ gles2::DeleteQueriesEXTImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::DeleteQueriesEXTImmediate>(size);
if (c) {
- c->Init(target, id);
+ c->Init(n, queries);
}
}
- void EndQueryEXT(GLenum target) {
- gles2::EndQueryEXT* c = GetCmdSpace<gles2::EndQueryEXT>();
- if (c) {
- c->Init(target);
- }
- }
-
- void GetQueryivEXT(
- GLenum target, GLenum pname, uint32 params_shm_id,
- uint32 params_shm_offset) {
- gles2::GetQueryivEXT* c = GetCmdSpace<gles2::GetQueryivEXT>();
+ void BeginQueryEXT(
+ GLenum target, GLuint id, uint32 sync_data_shm_id,
+ uint32 sync_data_shm_offset) {
+ gles2::BeginQueryEXT* c = GetCmdSpace<gles2::BeginQueryEXT>();
if (c) {
- c->Init(target, pname, params_shm_id, params_shm_offset);
+ c->Init(target, id, sync_data_shm_id, sync_data_shm_offset);
}
}
- void GetQueryObjectuivEXT(
- GLuint id, GLenum pname, uint32 params_shm_id,
- uint32 params_shm_offset) {
- gles2::GetQueryObjectuivEXT* c =
- GetCmdSpace<gles2::GetQueryObjectuivEXT>();
+ void EndQueryEXT(GLenum target, GLuint submit_count) {
+ gles2::EndQueryEXT* c = GetCmdSpace<gles2::EndQueryEXT>();
if (c) {
- c->Init(id, pname, params_shm_id, params_shm_offset);
+ c->Init(target, submit_count);
}
}
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index 7093cd8..c3a2c24 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -6,11 +6,13 @@
#include "../client/gles2_implementation.h"
+#include <map>
#include <set>
#include <queue>
#include <GLES2/gl2ext.h>
#include "../client/mapped_memory.h"
#include "../client/program_info_manager.h"
+#include "../client/query_tracker.h"
#include "../client/transfer_buffer.h"
#include "../common/gles2_cmd_utils.h"
#include "../common/id_allocator.h"
@@ -604,7 +606,8 @@ GLES2Implementation::GLES2Implementation(
debug_(false),
sharing_resources_(share_resources),
bind_generates_resource_(bind_generates_resource),
- use_count_(0) {
+ use_count_(0),
+ current_query_(NULL) {
GPU_DCHECK(helper);
GPU_DCHECK(transfer_buffer);
GPU_CLIENT_LOG_CODE_BLOCK({
@@ -685,6 +688,7 @@ bool GLES2Implementation::Initialize(
new TextureUnit[gl_state_.max_combined_texture_image_units]);
program_info_manager_.reset(ProgramInfoManager::Create(sharing_resources_));
+ query_tracker_.reset(new QueryTracker(mapped_memory_.get()));
#if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
id_handlers_[id_namespaces::kBuffers]->MakeIds(
@@ -700,6 +704,13 @@ bool GLES2Implementation::Initialize(
}
GLES2Implementation::~GLES2Implementation() {
+ // Make sure the queries are finished otherwise we'll delete the
+ // shared memory (mapped_memory_) which will free the memory used
+ // by the queries. The GPU process when validating that memory is still
+ // shared will fail and abort (ie, it will stop running).
+ Finish();
+ query_tracker_.reset();
+
#if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
DeleteBuffers(arraysize(reserved_ids_), &reserved_ids_[0]);
#endif
@@ -2970,6 +2981,180 @@ void GLES2Implementation::PostSubBufferCHROMIUM(
}
}
+void GLES2Implementation::DeleteQueriesEXTHelper(
+ GLsizei n, const GLuint* queries) {
+ if (!id_handlers_[id_namespaces::kQueries]->FreeIds(n, queries)) {
+ SetGLError(
+ GL_INVALID_VALUE,
+ "glDeleteTextures: id not created by this context.");
+ return;
+ }
+ // When you delete a query you can't mark its memory as unused until it's
+ // completed.
+ // Note: If you don't do this you won't mess up the service but you will mess
+ // up yourself.
+
+ // TODO(gman): Consider making this faster by putting pending quereies
+ // on some queue to be removed when they are finished.
+ bool query_pending = false;
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ QueryTracker::Query* query = query_tracker_->GetQuery(queries[ii]);
+ if (query && query->Pending()) {
+ query_pending = true;
+ break;
+ }
+ }
+
+ if (query_pending) {
+ Finish();
+ }
+
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ QueryTracker::Query* query = query_tracker_->GetQuery(queries[ii]);
+ if (query && query->Pending()) {
+ GPU_CHECK(!query->CheckResultsAvailable(helper_));
+ }
+ query_tracker_->RemoveQuery(queries[ii]);
+ }
+ helper_->DeleteQueriesEXTImmediate(n, queries);
+}
+
+GLboolean GLES2Implementation::IsQueryEXT(GLuint id) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << this << "] IsQueryEXT(" << id << ")");
+
+ // TODO(gman): To be spec compliant IDs from other contexts sharing
+ // resources need to return true here even though you can't share
+ // queries across contexts?
+ return query_tracker_->GetQuery(id) != NULL;
+}
+
+void GLES2Implementation::BeginQueryEXT(GLenum target, GLuint id) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << this << "] BeginQueryEXT("
+ << GLES2Util::GetStringQueryTarget(target)
+ << ", " << id << ")");
+
+ // if any outstanding queries INV_OP
+ if (current_query_) {
+ SetGLError(
+ GL_INVALID_OPERATION, "glBeginQueryEXT: query already in progress");
+ return;
+ }
+
+ // id = 0 INV_OP
+ if (id == 0) {
+ SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT: id is 0");
+ return;
+ }
+
+ // TODO(gman) if id not GENned INV_OPERATION
+
+ // if id does not have an object
+ QueryTracker::Query* query = query_tracker_->GetQuery(id);
+ if (!query) {
+ query = query_tracker_->CreateQuery(id, target);
+ } else if (query->target() != target) {
+ SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT: target does not match");
+ return;
+ }
+
+ current_query_ = query;
+
+ // init memory, inc count
+ query->MarkAsActive();
+
+ // tell service about id, shared memory and count
+ helper_->BeginQueryEXT(target, id, query->shm_id(), query->shm_offset());
+}
+
+void GLES2Implementation::EndQueryEXT(GLenum target) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << this << "] EndQueryEXT("
+ << GLES2Util::GetStringQueryTarget(target) << ")");
+
+ if (!current_query_) {
+ SetGLError(GL_INVALID_OPERATION, "glEndQueryEXT: no active query");
+ return;
+ }
+
+ if (current_query_->target() != target) {
+ SetGLError(GL_INVALID_OPERATION,
+ "glEndQueryEXT: target does not match active query");
+ return;
+ }
+
+ helper_->EndQueryEXT(target, current_query_->submit_count());
+ current_query_->MarkAsPending(helper_->InsertToken());
+ current_query_ = NULL;
+}
+
+void GLES2Implementation::GetQueryivEXT(
+ GLenum target, GLenum pname, GLint* params) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << this << "] GetQueryivEXT("
+ << GLES2Util::GetStringQueryTarget(target) << ", "
+ << GLES2Util::GetStringQueryParameter(pname) << ", "
+ << static_cast<const void*>(params) << ")");
+
+ if (pname != GL_CURRENT_QUERY_EXT) {
+ SetGLError(GL_INVALID_ENUM, "glGetQueryivEXT: invalid pname");
+ return;
+ }
+ *params = (current_query_ && current_query_->target() == target) ?
+ current_query_->id() : 0;
+ GPU_CLIENT_LOG(" " << *params);
+}
+
+void GLES2Implementation::GetQueryObjectuivEXT(
+ GLuint id, GLenum pname, GLuint* params) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << this << "] GetQueryivEXT(" << id << ", "
+ << GLES2Util::GetStringQueryObjectParameter(pname) << ", "
+ << static_cast<const void*>(params) << ")");
+
+ QueryTracker::Query* query = query_tracker_->GetQuery(id);
+ if (!query) {
+ SetGLError(GL_INVALID_OPERATION, "glQueryObjectuivEXT: unknown query id");
+ return;
+ }
+
+ if (query == current_query_) {
+ SetGLError(
+ GL_INVALID_OPERATION,
+ "glQueryObjectuivEXT: query active. Did you to call glEndQueryEXT?");
+ return;
+ }
+
+ if (query->NeverUsed()) {
+ SetGLError(
+ GL_INVALID_OPERATION,
+ "glQueryObjectuivEXT: Never used. Did you call glBeginQueryEXT?");
+ return;
+ }
+
+ switch (pname) {
+ case GL_QUERY_RESULT_EXT:
+ if (!query->CheckResultsAvailable(helper_)) {
+ helper_->WaitForToken(query->token());
+ if (!query->CheckResultsAvailable(helper_)) {
+ // TODO(gman): Speed this up.
+ Finish();
+ GPU_CHECK(query->CheckResultsAvailable(helper_));
+ }
+ }
+ *params = query->GetResult();
+ break;
+ case GL_QUERY_RESULT_AVAILABLE_EXT:
+ *params = query->CheckResultsAvailable(helper_);
+ break;
+ default:
+ SetGLError(GL_INVALID_ENUM, "glQueryObjectuivEXT: unknown pname");
+ break;
+ }
+ GPU_CLIENT_LOG(" " << *params);
+}
+
void GLES2Implementation::DrawArraysInstancedANGLE(
GLenum mode, GLint first, GLsizei count, GLsizei primcount) {
GPU_CLIENT_SINGLE_THREAD_CHECK();
@@ -3070,6 +3255,5 @@ void GLES2Implementation::DrawElementsInstancedANGLE(
#endif
}
-
} // namespace gles2
} // namespace gpu
diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h
index dbdb271..2b5312a 100644
--- a/gpu/command_buffer/client/gles2_implementation.h
+++ b/gpu/command_buffer/client/gles2_implementation.h
@@ -16,6 +16,7 @@
#include "../common/gles2_cmd_utils.h"
#include "../common/scoped_ptr.h"
#include "../client/gles2_cmd_helper.h"
+#include "../client/query_tracker.h"
#include "../client/ring_buffer.h"
#include "gles2_impl_export.h"
@@ -216,6 +217,7 @@ class GLES2_IMPL_EXPORT GLES2Implementation {
private:
friend class ClientSideBufferHelper;
+ friend class GLES2ImplementationTest;
// Used to track whether an extension is available
enum ExtensionStatus {
@@ -393,6 +395,7 @@ class GLES2_IMPL_EXPORT GLES2Implementation {
void DeleteTexturesHelper(GLsizei n, const GLuint* textures);
bool DeleteProgramHelper(GLuint program);
bool DeleteShaderHelper(GLuint shader);
+ void DeleteQueriesEXTHelper(GLsizei n, const GLuint* textures);
void BufferDataHelper(
GLenum target, GLsizeiptr size, const void* data, GLenum usage);
@@ -516,6 +519,9 @@ class GLES2_IMPL_EXPORT GLES2Implementation {
scoped_ptr<ProgramInfoManager> program_info_manager_;
+ scoped_ptr<QueryTracker> query_tracker_;
+ QueryTracker::Query* current_query_;
+
DISALLOW_COPY_AND_ASSIGN(GLES2Implementation);
};
diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h
index 9b33d7c..6ec6e14 100644
--- a/gpu/command_buffer/client/gles2_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_autogen.h
@@ -1409,41 +1409,54 @@ void TexStorage2DEXT(
helper_->TexStorage2DEXT(target, levels, internalFormat, width, height);
}
-void GenQueriesEXT(GLsizei n, GLuint* ids) {
- // TODO: for now this is a no-op
- SetGLError(GL_INVALID_OPERATION, "glGenQueriesEXT not implemented");
+void GenQueriesEXT(GLsizei n, GLuint* queries) {
+ GPU_CLIENT_LOG("[" << this << "] glGenQueriesEXT(" << n << ", "
+ << static_cast<const void*>(queries) << ")"); // NOLINT
+ if (n < 0) {
+ SetGLError(GL_INVALID_VALUE, "glGenQueriesEXT: n < 0");
+ return;
+ }
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ id_handlers_[id_namespaces::kQueries]->
+ MakeIds(0, n, queries);
+ helper_->GenQueriesEXTImmediate(n, queries);
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < n; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << queries[i]);
+ }
+ });
}
-void DeleteQueriesEXT(GLsizei n, const GLuint* ids) {
- // TODO: for now this is a no-op
- SetGLError(GL_INVALID_OPERATION, "glDeleteQueriesEXT not implemented");
+void DeleteQueriesEXT(GLsizei n, const GLuint* queries) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << this << "] glDeleteQueriesEXT(" << n << ", "
+ << static_cast<const void*>(queries) << ")"); // NOLINT
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < n; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << queries[i]);
+ }
+ });
+ GPU_CLIENT_DCHECK_CODE_BLOCK({
+ for (GLsizei i = 0; i < n; ++i) {
+ GPU_DCHECK(queries[i] != 0);
+ }
+ });
+ if (n < 0) {
+ SetGLError(GL_INVALID_VALUE, "glDeleteQueriesEXT: n < 0");
+ return;
+ }
+ DeleteQueriesEXTHelper(n, queries);
}
-GLboolean IsQueryEXT(GLuint id) {
- // TODO: for now this is a no-op
- SetGLError(GL_INVALID_OPERATION, "glIsQueryEXT not implemented");
- return 0;
-}
+GLboolean IsQueryEXT(GLuint id);
-void BeginQueryEXT(GLenum target, GLuint id) {
- // TODO: for now this is a no-op
- SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT not implemented");
-}
+void BeginQueryEXT(GLenum target, GLuint id);
-void EndQueryEXT(GLenum target) {
- // TODO: for now this is a no-op
- SetGLError(GL_INVALID_OPERATION, "glEndQueryEXT not implemented");
-}
+void EndQueryEXT(GLenum target);
-void GetQueryivEXT(GLenum target, GLenum pname, GLint* params) {
- // TODO: for now this is a no-op
- SetGLError(GL_INVALID_OPERATION, "glGetQueryivEXT not implemented");
-}
+void GetQueryivEXT(GLenum target, GLenum pname, GLint* params);
-void GetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint* params) {
- // TODO: for now this is a no-op
- SetGLError(GL_INVALID_OPERATION, "glGetQueryObjectuivEXT not implemented");
-}
+void GetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint* params);
void SwapBuffers();
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc
index 9bfc9ce..9aa84de 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest.cc
+++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc
@@ -320,6 +320,7 @@ class GLES2ImplementationTest : public testing::Test {
static const GLuint kProgramsAndShadersStartId = 1;
static const GLuint kRenderbuffersStartId = 1;
static const GLuint kTexturesStartId = 1;
+ static const GLuint kQueriesStartId = 1;
typedef MockTransferBuffer::ExpectedMemoryInfo ExpectedMemoryInfo;
@@ -336,6 +337,10 @@ class GLES2ImplementationTest : public testing::Test {
kInitialValue;
}
+ QueryTracker::Query* GetQuery(GLuint id) {
+ return gl_->query_tracker_->GetQuery(id);
+ }
+
void Initialize(bool shared_resources, bool bind_generates_resource) {
command_buffer_.reset(new StrictMock<MockClientCommandBuffer>());
ASSERT_TRUE(command_buffer_->Initialize());
@@ -457,6 +462,15 @@ class GLES2ImplementationTest : public testing::Test {
return transfer_buffer_->GetExpectedResultMemory(size);
}
+ int CheckError() {
+ ExpectedMemoryInfo result =
+ GetExpectedResultMemory(sizeof(GetError::Result));
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result.ptr, GLuint(GL_NO_ERROR)))
+ .RetiresOnSaturation();
+ return gl_->GetError();
+ }
+
Sequence sequence_;
scoped_ptr<MockClientCommandBuffer> command_buffer_;
scoped_ptr<GLES2CmdHelper> helper_;
@@ -509,6 +523,7 @@ const GLuint GLES2ImplementationTest::kFramebuffersStartId;
const GLuint GLES2ImplementationTest::kProgramsAndShadersStartId;
const GLuint GLES2ImplementationTest::kRenderbuffersStartId;
const GLuint GLES2ImplementationTest::kTexturesStartId;
+const GLuint GLES2ImplementationTest::kQueriesStartId;
#endif
TEST_F(GLES2ImplementationTest, ShaderSource) {
@@ -2301,6 +2316,126 @@ TEST_F(GLES2ImplementationTest, BufferDataLargerThanTransferBuffer) {
EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
}
+TEST_F(GLES2ImplementationTest, BeginEndQueryEXT) {
+ // Test GetQueryivEXT returns 0 if no current query.
+ GLint param = -1;
+ gl_->GetQueryivEXT(GL_ANY_SAMPLES_PASSED_EXT, GL_CURRENT_QUERY_EXT, &param);
+ EXPECT_EQ(0, param);
+
+ GLuint expected_ids[2] = { 1, 2 }; // These must match what's actually genned.
+ struct GenCmds {
+ GenQueriesEXTImmediate gen;
+ GLuint data[2];
+ };
+ GenCmds expected_gen_cmds;
+ expected_gen_cmds.gen.Init(arraysize(expected_ids), &expected_ids[0]);
+ GLuint ids[arraysize(expected_ids)] = { 0, };
+ gl_->GenQueriesEXT(arraysize(expected_ids), &ids[0]);
+ EXPECT_EQ(0, memcmp(
+ &expected_gen_cmds, commands_, sizeof(expected_gen_cmds)));
+ GLuint id1 = ids[0];
+ GLuint id2 = ids[1];
+ ClearCommands();
+
+ // Test BeginQueryEXT fails if id = 0.
+ gl_->BeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, 0);
+ EXPECT_TRUE(NoCommandsWritten());
+ EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
+
+ // Test BeginQueryEXT fails if id not GENed.
+ // TODO(gman):
+
+ // Test BeginQueryEXT inserts command.
+ struct BeginCmds {
+ BeginQueryEXT begin_query;
+ };
+ BeginCmds expected_begin_cmds;
+ const void* commands = GetPut();
+ gl_->BeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, id1);
+ QueryTracker::Query* query = GetQuery(id1);
+ ASSERT_TRUE(query != NULL);
+ expected_begin_cmds.begin_query.Init(
+ GL_ANY_SAMPLES_PASSED_EXT, id1, query->shm_id(), query->shm_offset());
+ EXPECT_EQ(0, memcmp(
+ &expected_begin_cmds, commands, sizeof(expected_begin_cmds)));
+ ClearCommands();
+
+ // Test GetQueryivEXT returns id.
+ param = -1;
+ gl_->GetQueryivEXT(GL_ANY_SAMPLES_PASSED_EXT, GL_CURRENT_QUERY_EXT, &param);
+ EXPECT_EQ(id1, static_cast<GLuint>(param));
+ gl_->GetQueryivEXT(
+ GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, GL_CURRENT_QUERY_EXT, &param);
+ EXPECT_EQ(0, param);
+
+ // Test BeginQueryEXT fails if between Begin/End.
+ gl_->BeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, id2);
+ EXPECT_TRUE(NoCommandsWritten());
+ EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
+
+ // Test EndQueryEXT fails if target not same as current query.
+ ClearCommands();
+ gl_->EndQueryEXT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT);
+ EXPECT_TRUE(NoCommandsWritten());
+ EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
+
+ // Test EndQueryEXT sends command
+ struct EndCmds {
+ EndQueryEXT end_query;
+ };
+ EndCmds expected_end_cmds;
+ expected_end_cmds.end_query.Init(
+ GL_ANY_SAMPLES_PASSED_EXT, query->submit_count());
+ commands = GetPut();
+ gl_->EndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
+ EXPECT_EQ(0, memcmp(
+ &expected_end_cmds, commands, sizeof(expected_end_cmds)));
+
+ // Test EndQueryEXT fails if no current query.
+ ClearCommands();
+ gl_->EndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
+ EXPECT_TRUE(NoCommandsWritten());
+ EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
+
+ // Test 2nd Begin/End increments count.
+ uint32 old_submit_count = query->submit_count();
+ gl_->BeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, id1);
+ EXPECT_NE(old_submit_count, query->submit_count());
+ expected_end_cmds.end_query.Init(
+ GL_ANY_SAMPLES_PASSED_EXT, query->submit_count());
+ commands = GetPut();
+ gl_->EndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
+ EXPECT_EQ(0, memcmp(
+ &expected_end_cmds, commands, sizeof(expected_end_cmds)));
+
+ // Test BeginQueryEXT fails if target changed.
+ ClearCommands();
+ gl_->BeginQueryEXT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, id1);
+ EXPECT_TRUE(NoCommandsWritten());
+ EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
+
+ // Test GetQueryObjectuivEXT fails if unused id
+ GLuint available = 0xBDu;
+ ClearCommands();
+ gl_->GetQueryObjectuivEXT(id2, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
+ EXPECT_TRUE(NoCommandsWritten());
+ EXPECT_EQ(0xBDu, available);
+ EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
+
+ // Test GetQueryObjectuivEXT fails if bad id
+ ClearCommands();
+ gl_->GetQueryObjectuivEXT(4567, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
+ EXPECT_TRUE(NoCommandsWritten());
+ EXPECT_EQ(0xBDu, available);
+ EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
+
+ // Test GetQueryObjectuivEXT CheckResultsAvailable
+ ClearCommands();
+ gl_->GetQueryObjectuivEXT(id1, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
+ EXPECT_TRUE(NoCommandsWritten());
+ EXPECT_EQ(0u, available);
+}
+
#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 8b6bdb1..f69981f 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
@@ -1563,6 +1563,37 @@ TEST_F(GLES2ImplementationTest, TexStorage2DEXT) {
gl_->TexStorage2DEXT(GL_TEXTURE_2D, 2, GL_RGB565, 4, 5);
EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
}
+
+TEST_F(GLES2ImplementationTest, GenQueriesEXT) {
+ GLuint ids[2] = { 0, };
+ struct Cmds {
+ GenQueriesEXTImmediate gen;
+ GLuint data[2];
+ };
+ Cmds expected;
+ expected.gen.Init(arraysize(ids), &ids[0]);
+ expected.data[0] = kQueriesStartId;
+ expected.data[1] = kQueriesStartId + 1;
+ gl_->GenQueriesEXT(arraysize(ids), &ids[0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_EQ(kQueriesStartId, ids[0]);
+ EXPECT_EQ(kQueriesStartId + 1, ids[1]);
+}
+
+TEST_F(GLES2ImplementationTest, DeleteQueriesEXT) {
+ GLuint ids[2] = { kQueriesStartId, kQueriesStartId + 1 };
+ struct Cmds {
+ DeleteQueriesEXTImmediate del;
+ GLuint data[2];
+ };
+ Cmds expected;
+ expected.del.Init(arraysize(ids), &ids[0]);
+ expected.data[0] = kQueriesStartId;
+ expected.data[1] = kQueriesStartId + 1;
+ gl_->DeleteQueriesEXT(arraysize(ids), &ids[0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+// TODO: Implement unit test for BeginQueryEXT
// TODO: Implement unit test for GenSharedIdsCHROMIUM
// TODO: Implement unit test for DeleteSharedIdsCHROMIUM
// TODO: Implement unit test for RegisterSharedIdsCHROMIUM
diff --git a/gpu/command_buffer/client/query_tracker.cc b/gpu/command_buffer/client/query_tracker.cc
new file mode 100644
index 0000000..164a0f4
--- /dev/null
+++ b/gpu/command_buffer/client/query_tracker.cc
@@ -0,0 +1,130 @@
+// 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 "../client/query_tracker.h"
+
+#if !defined(__native_client__)
+ #include "base/atomicops.h"
+#endif
+#include "../client/cmd_buffer_helper.h"
+#include "../client/mapped_memory.h"
+
+#include <map>
+
+namespace gpu {
+namespace gles2 {
+
+QuerySyncManager::QuerySyncManager(MappedMemoryManager* manager)
+ : mapped_memory_(manager) {
+ GPU_DCHECK(manager);
+}
+
+QuerySyncManager::~QuerySyncManager() {
+ while (!buckets_.empty()) {
+ mapped_memory_->Free(buckets_.front());
+ buckets_.pop();
+ }
+}
+
+bool QuerySyncManager::Alloc(QuerySyncManager::QueryInfo* info) {
+ GPU_DCHECK(info);
+ if (free_queries_.empty()) {
+ int32 shm_id;
+ unsigned int shm_offset;
+ void* mem = mapped_memory_->Alloc(
+ kSyncsPerBucket * sizeof(QuerySync), &shm_id, &shm_offset);
+ if (!mem) {
+ return false;
+ }
+ QuerySync* syncs = static_cast<QuerySync*>(mem);
+ buckets_.push(syncs);
+ for (size_t ii = 0; ii < kSyncsPerBucket; ++ii) {
+ free_queries_.push(QueryInfo(shm_id, shm_offset, syncs));
+ ++syncs;
+ shm_offset += sizeof(*syncs);
+ }
+ }
+ *info = free_queries_.front();
+ info->sync->Reset();
+ free_queries_.pop();
+ return true;
+}
+
+void QuerySyncManager::Free(const QuerySyncManager::QueryInfo& info) {
+ free_queries_.push(info);
+}
+
+bool QueryTracker::Query::CheckResultsAvailable(
+ CommandBufferHelper* helper) {
+ if (Pending()) {
+ if (info_.sync->process_count == submit_count_) {
+ // Need a MemoryBarrier here so that sync->result read after
+ // sync->process_count.
+ #if defined(__native_client__)
+ __sync_synchronize();
+ #else
+ base::subtle::MemoryBarrier();
+ #endif
+ result_ = info_.sync->result;
+ state_ = kComplete;
+ } else {
+ if (!flushed_) {
+ // TODO(gman): We could reduce the number of flushes by having a
+ // flush count, recording that count at the time we insert the
+ // EndQuery command and then only flushing here if we've have not
+ // passed that count yet.
+ flushed_ = true;
+ helper->Flush();
+ }
+ }
+ }
+ return state_ == kComplete;
+}
+
+uint32 QueryTracker::Query::GetResult() const {
+ GPU_DCHECK(state_ == kComplete || state_ == kUninitialized);
+ return result_;
+}
+
+QueryTracker::QueryTracker(MappedMemoryManager* manager)
+ : query_sync_manager_(manager) {
+}
+
+QueryTracker::~QueryTracker() {
+ queries_.clear();
+}
+
+QueryTracker::Query* QueryTracker::CreateQuery(GLuint id, GLenum target) {
+ GPU_DCHECK_NE(0u, id);
+ QuerySyncManager::QueryInfo info;
+ if (!query_sync_manager_.Alloc(&info)) {
+ return NULL;
+ }
+ Query* query = new Query(id, target, info);
+ std::pair<QueryMap::iterator, bool> result =
+ queries_.insert(std::make_pair(id, query));
+ GPU_DCHECK(result.second);
+ return query;
+}
+
+QueryTracker::Query* QueryTracker::GetQuery(
+ GLuint client_id) {
+ QueryMap::iterator it = queries_.find(client_id);
+ return it != queries_.end() ? it->second : NULL;
+}
+
+void QueryTracker::RemoveQuery(GLuint client_id) {
+ QueryMap::iterator it = queries_.find(client_id);
+ if (it != queries_.end()) {
+ Query* query = it->second;
+ GPU_DCHECK(!query->Pending());
+ query_sync_manager_.Free(query->info_);
+ queries_.erase(it);
+ delete query;
+ }
+}
+
+} // namespace gles2
+} // namespace gpu
+
diff --git a/gpu/command_buffer/client/query_tracker.h b/gpu/command_buffer/client/query_tracker.h
new file mode 100644
index 0000000..c76e6c8
--- /dev/null
+++ b/gpu/command_buffer/client/query_tracker.h
@@ -0,0 +1,167 @@
+// 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_CLIENT_QUERY_TRACKER_H_
+#define GPU_COMMAND_BUFFER_CLIENT_QUERY_TRACKER_H_
+
+#include <GLES2/gl2.h>
+
+#include <queue>
+#include "../../gpu_export.h"
+#if defined(__native_client__)
+ #include <map>
+#else
+ #include "base/hash_tables.h"
+#endif
+#include "../common/gles2_cmd_format.h"
+
+namespace gpu {
+
+class CommandBufferHelper;
+class MappedMemoryManager;
+
+namespace gles2 {
+
+// Manages buckets of QuerySync instances in mapped memory.
+class GPU_EXPORT QuerySyncManager {
+ public:
+ static const size_t kSyncsPerBucket = 4096;
+
+ struct QueryInfo {
+ QueryInfo(int32 id, uint32 offset, QuerySync* sync_mem)
+ : shm_id(id),
+ shm_offset(offset),
+ sync(sync_mem) {
+ }
+ QueryInfo() {
+ }
+
+ int32 shm_id;
+ uint32 shm_offset;
+ QuerySync* sync;
+ };
+
+ explicit QuerySyncManager(MappedMemoryManager* manager);
+ ~QuerySyncManager();
+
+ bool Alloc(QueryInfo* info);
+ void Free(const QueryInfo& sync);
+
+ private:
+ MappedMemoryManager* mapped_memory_;
+ std::queue<QuerySync*> buckets_;
+ std::queue<QueryInfo> free_queries_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuerySyncManager);
+};
+
+// Tracks queries for client side of command buffer.
+class GPU_EXPORT QueryTracker {
+ public:
+ class GPU_EXPORT Query {
+ public:
+ enum State {
+ kUninitialized, // never used
+ kActive, // between begin - end
+ kPending, // not yet complete
+ kComplete // completed
+ };
+
+ Query(GLuint id, GLenum target, const QuerySyncManager::QueryInfo& info)
+ : id_(id),
+ target_(target),
+ info_(info),
+ state_(kUninitialized),
+ submit_count_(0),
+ token_(0),
+ flushed_(false),
+ result_(0) {
+ }
+
+ GLenum target() const {
+ return target_;
+ }
+
+ GLenum id() const {
+ return id_;
+ }
+
+ int32 shm_id() const {
+ return info_.shm_id;
+ }
+
+ uint32 shm_offset() const {
+ return info_.shm_offset;
+ }
+
+ void MarkAsActive() {
+ state_ = kActive;
+ ++submit_count_;
+ }
+
+ void MarkAsPending(int32 token) {
+ token_ = token;
+ state_ = kPending;
+ flushed_ = false;
+ }
+
+ uint32 submit_count() const {
+ return submit_count_;
+ }
+
+ int32 token() const {
+ return token_;
+ }
+
+ bool NeverUsed() const {
+ return state_ == kUninitialized;
+ }
+
+ bool Pending() const {
+ return state_ == kPending;
+ }
+
+ bool CheckResultsAvailable(CommandBufferHelper* helper);
+
+ uint32 GetResult() const;
+
+ private:
+ friend class QueryTracker;
+ friend class QueryTrackerTest;
+
+ GLuint id_;
+ GLenum target_;
+ QuerySyncManager::QueryInfo info_;
+ State state_;
+ uint32 submit_count_;
+ int32 token_;
+ bool flushed_;
+ uint32 result_;
+ };
+
+ QueryTracker(MappedMemoryManager* manager);
+ ~QueryTracker();
+
+ Query* CreateQuery(GLuint id, GLenum target);
+ Query* GetQuery(GLuint id);
+ void RemoveQuery(GLuint id);
+
+ private:
+ #if defined(__native_client__)
+ // TODO(gman): Figure out something for NaCl
+ typedef std::map<GLuint, Query*> QueryMap;
+ #else
+ typedef base::hash_map<GLuint, Query*> QueryMap;
+ #endif
+
+ QueryMap queries_;
+ QuerySyncManager query_sync_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(QueryTracker);
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_QUERY_TRACKER_H_
diff --git a/gpu/command_buffer/client/query_tracker_unittest.cc b/gpu/command_buffer/client/query_tracker_unittest.cc
new file mode 100644
index 0000000..16da7c8
--- /dev/null
+++ b/gpu/command_buffer/client/query_tracker_unittest.cc
@@ -0,0 +1,171 @@
+// 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.
+
+// Tests for the QueryTracker.
+
+#include "gpu/command_buffer/client/query_tracker.h"
+
+#include <GLES2/gl2ext.h>
+#include "base/memory/scoped_ptr.h"
+#include "gpu/command_buffer/client/client_test_helper.h"
+#include "gpu/command_buffer/client/gles2_cmd_helper.h"
+#include "gpu/command_buffer/client/mapped_memory.h"
+#include "gpu/command_buffer/common/command_buffer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace gpu {
+namespace gles2 {
+
+class QuerySyncManagerTest : public testing::Test {
+ protected:
+ static const int32 kNumCommandEntries = 400;
+ static const int32 kCommandBufferSizeBytes =
+ kNumCommandEntries * sizeof(CommandBufferEntry);
+
+ virtual void SetUp() {
+ command_buffer_.reset(new MockClientCommandBuffer());
+ helper_.reset(new GLES2CmdHelper(command_buffer_.get()));
+ helper_->Initialize(kCommandBufferSizeBytes);
+ mapped_memory_.reset(new MappedMemoryManager(helper_.get()));
+ sync_manager_.reset(new QuerySyncManager(mapped_memory_.get()));
+ }
+
+ virtual void TearDown() {
+ sync_manager_.reset();
+ mapped_memory_.reset();
+ helper_.reset();
+ command_buffer_.reset();
+ }
+
+ scoped_ptr<CommandBuffer> command_buffer_;
+ scoped_ptr<GLES2CmdHelper> helper_;
+ scoped_ptr<MappedMemoryManager> mapped_memory_;
+ scoped_ptr<QuerySyncManager> sync_manager_;
+};
+
+TEST_F(QuerySyncManagerTest, Basic) {
+ QuerySyncManager::QueryInfo infos[4];
+ memset(&infos, 0xBD, sizeof(infos));
+
+ for (size_t ii = 0; ii < arraysize(infos); ++ii) {
+ EXPECT_TRUE(sync_manager_->Alloc(&infos[ii]));
+ EXPECT_NE(0, infos[ii].shm_id);
+ ASSERT_TRUE(infos[ii].sync != NULL);
+ EXPECT_EQ(0u, infos[ii].sync->process_count);
+ EXPECT_EQ(0u, infos[ii].sync->result);
+ }
+
+ for (size_t ii = 0; ii < arraysize(infos); ++ii) {
+ sync_manager_->Free(infos[ii]);
+ }
+}
+
+TEST_F(QuerySyncManagerTest, DontFree) {
+ QuerySyncManager::QueryInfo infos[4];
+ memset(&infos, 0xBD, sizeof(infos));
+
+ for (size_t ii = 0; ii < arraysize(infos); ++ii) {
+ EXPECT_TRUE(sync_manager_->Alloc(&infos[ii]));
+ }
+}
+
+class QueryTrackerTest : public testing::Test {
+ protected:
+ static const int32 kNumCommandEntries = 400;
+ static const int32 kCommandBufferSizeBytes =
+ kNumCommandEntries * sizeof(CommandBufferEntry);
+
+ virtual void SetUp() {
+ command_buffer_.reset(new MockClientCommandBuffer());
+ helper_.reset(new GLES2CmdHelper(command_buffer_.get()));
+ helper_->Initialize(kCommandBufferSizeBytes);
+ mapped_memory_.reset(new MappedMemoryManager(helper_.get()));
+ query_tracker_.reset(new QueryTracker(mapped_memory_.get()));
+ }
+
+ virtual void TearDown() {
+ query_tracker_.reset();
+ mapped_memory_.reset();
+ helper_.reset();
+ command_buffer_.reset();
+ }
+
+ QuerySync* GetSync(QueryTracker::Query* query) {
+ return query->info_.sync;
+ }
+
+ scoped_ptr<CommandBuffer> command_buffer_;
+ scoped_ptr<GLES2CmdHelper> helper_;
+ scoped_ptr<MappedMemoryManager> mapped_memory_;
+ scoped_ptr<QueryTracker> query_tracker_;
+};
+
+TEST_F(QueryTrackerTest, Basic) {
+ const GLuint kId1 = 123;
+ const GLuint kId2 = 124;
+
+ // Check we can create a Query.
+ QueryTracker::Query* query = query_tracker_->CreateQuery(
+ kId1, GL_ANY_SAMPLES_PASSED_EXT);
+ ASSERT_TRUE(query != NULL);
+ // Check we can get the same Query.
+ EXPECT_EQ(query, query_tracker_->GetQuery(kId1));
+ // Check we get nothing for a non-existent query.
+ EXPECT_TRUE(query_tracker_->GetQuery(kId2) == NULL);
+ // Check we can delete the query.
+ query_tracker_->RemoveQuery(kId1);
+ // Check we get nothing for a non-existent query.
+ EXPECT_TRUE(query_tracker_->GetQuery(kId1) == NULL);
+}
+
+TEST_F(QueryTrackerTest, Query) {
+ const GLuint kId1 = 123;
+ const int32 kToken = 46;
+ const uint32 kResult = 456;
+
+ // Create a Query.
+ QueryTracker::Query* query = query_tracker_->CreateQuery(
+ kId1, GL_ANY_SAMPLES_PASSED_EXT);
+ ASSERT_TRUE(query != NULL);
+ EXPECT_TRUE(query->NeverUsed());
+ EXPECT_FALSE(query->Pending());
+ EXPECT_EQ(0, query->token());
+ EXPECT_EQ(0u, query->submit_count());
+
+ // Check MarkAsActive.
+ query->MarkAsActive();
+ EXPECT_FALSE(query->NeverUsed());
+ EXPECT_FALSE(query->Pending());
+ EXPECT_EQ(0, query->token());
+ EXPECT_EQ(1u, query->submit_count());
+
+ // Check MarkAsPending.
+ query->MarkAsPending(kToken);
+ EXPECT_FALSE(query->NeverUsed());
+ EXPECT_TRUE(query->Pending());
+ EXPECT_EQ(kToken, query->token());
+ EXPECT_EQ(1u, query->submit_count());
+
+ // Check CheckResultsAvailable.
+ EXPECT_FALSE(query->CheckResultsAvailable(helper_.get()));
+ EXPECT_FALSE(query->NeverUsed());
+ EXPECT_TRUE(query->Pending());
+
+ // Simulate GPU process marking it as available.
+ QuerySync* sync = GetSync(query);
+ sync->process_count = query->submit_count();
+ sync->result = kResult;
+
+ // Check CheckResultsAvailable.
+ EXPECT_TRUE(query->CheckResultsAvailable(helper_.get()));
+ EXPECT_EQ(kResult, query->GetResult());
+ EXPECT_FALSE(query->NeverUsed());
+ EXPECT_FALSE(query->Pending());
+}
+
+} // namespace gles2
+} // namespace gpu
+
+
diff --git a/gpu/command_buffer/cmd_buffer_functions.txt b/gpu/command_buffer/cmd_buffer_functions.txt
index 82fd73b..688a9d3 100644
--- a/gpu/command_buffer/cmd_buffer_functions.txt
+++ b/gpu/command_buffer/cmd_buffer_functions.txt
@@ -149,8 +149,8 @@ GL_APICALL void GL_APIENTRY glViewport (GLint x, GLint y, GLsizei width,
GL_APICALL void GL_APIENTRY glBlitFramebufferEXT (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenumBlitFilter filter);
GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleEXT (GLenumRenderBufferTarget target, GLsizei samples, GLenumRenderBufferFormat internalformat, GLsizei width, GLsizei height);
GL_APICALL void GL_APIENTRY glTexStorage2DEXT (GLenumTextureTarget target, GLsizei levels, GLenumTextureInternalFormatStorage internalFormat, GLsizei width, GLsizei height);
-GL_APICALL void GL_APIENTRY glGenQueriesEXT (GLsizeiNotNegative n, GLuint* ids);
-GL_APICALL void GL_APIENTRY glDeleteQueriesEXT (GLsizeiNotNegative n, const GLuint* ids);
+GL_APICALL void GL_APIENTRY glGenQueriesEXT (GLsizeiNotNegative n, GLuint* queries);
+GL_APICALL void GL_APIENTRY glDeleteQueriesEXT (GLsizeiNotNegative n, const GLuint* queries);
GL_APICALL GLboolean GL_APIENTRY glIsQueryEXT (GLidQuery id);
GL_APICALL void GL_APIENTRY glBeginQueryEXT (GLenumQueryTarget target, GLidQuery id);
GL_APICALL void GL_APIENTRY glEndQueryEXT (GLenumQueryTarget target);
diff --git a/gpu/command_buffer/common/gl_mock.h b/gpu/command_buffer/common/gl_mock.h
index feba409..8acc132 100644
--- a/gpu/command_buffer/common/gl_mock.h
+++ b/gpu/command_buffer/common/gl_mock.h
@@ -483,6 +483,21 @@ class MockGLInterface : public GLInterface {
GLsync sync, GLenum pname, GLsizei bufSize,
GLsizei* length, GLint* values));
+ MOCK_METHOD2(GenQueriesARB, void(GLsizei n, GLuint* ids));
+
+ MOCK_METHOD2(DeleteQueriesARB, void(GLsizei n, const GLuint* ids));
+
+ MOCK_METHOD1(IsQueryARB, GLboolean(GLuint id));
+
+ MOCK_METHOD2(BeginQueryARB, void(GLenum target, GLuint id));
+
+ MOCK_METHOD1(EndQueryARB, void(GLenum target));
+
+ MOCK_METHOD3(GetQueryivARB, void(GLenum target, GLenum pname, GLint* params));
+
+ MOCK_METHOD3(GetQueryObjectuivARB, void(
+ GLuint id, GLenum pname, GLuint* params));
+
MOCK_METHOD1(SetSurfaceCHROMIUM, void(GLuint));
MOCK_METHOD0(GetGraphicsResetStatusARB, GLenum());
diff --git a/gpu/command_buffer/common/gles2_cmd_format.h b/gpu/command_buffer/common/gles2_cmd_format.h
index 972771b..5120b39 100644
--- a/gpu/command_buffer/common/gles2_cmd_format.h
+++ b/gpu/command_buffer/common/gles2_cmd_format.h
@@ -137,6 +137,17 @@ struct ProgramInfoHeader {
// ProgramInput inputs[num_attribs + num_uniforms];
};
+// The format of QuerySync used by EXT_occlusion_query_boolean
+struct QuerySync {
+ void Reset() {
+ process_count = 0;
+ result = 0;
+ }
+
+ uint32 process_count;
+ uint32 result;
+};
+
COMPILE_ASSERT(sizeof(ProgramInput) == 20, ProgramInput_size_not_20);
COMPILE_ASSERT(offsetof(ProgramInput, type) == 0,
OffsetOf_ProgramInput_type_not_0);
diff --git a/gpu/command_buffer/common/gles2_cmd_format_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
index a0e05c8..f227dee 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
@@ -8536,23 +8536,25 @@ struct GenQueriesEXT {
header.SetCmd<ValueType>();
}
- void Init(GLsizei _n, uint32 _ids_shm_id, uint32 _ids_shm_offset) {
+ void Init(GLsizei _n, uint32 _queries_shm_id, uint32 _queries_shm_offset) {
SetHeader();
n = _n;
- ids_shm_id = _ids_shm_id;
- ids_shm_offset = _ids_shm_offset;
+ queries_shm_id = _queries_shm_id;
+ queries_shm_offset = _queries_shm_offset;
}
void* Set(
- void* cmd, GLsizei _n, uint32 _ids_shm_id, uint32 _ids_shm_offset) {
- static_cast<ValueType*>(cmd)->Init(_n, _ids_shm_id, _ids_shm_offset);
+ void* cmd, GLsizei _n, uint32 _queries_shm_id,
+ uint32 _queries_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_n, _queries_shm_id, _queries_shm_offset);
return NextCmdAddress<ValueType>(cmd);
}
gpu::CommandHeader header;
int32 n;
- uint32 ids_shm_id;
- uint32 ids_shm_offset;
+ uint32 queries_shm_id;
+ uint32 queries_shm_offset;
};
COMPILE_ASSERT(sizeof(GenQueriesEXT) == 16,
@@ -8561,10 +8563,52 @@ COMPILE_ASSERT(offsetof(GenQueriesEXT, header) == 0,
OffsetOf_GenQueriesEXT_header_not_0);
COMPILE_ASSERT(offsetof(GenQueriesEXT, n) == 4,
OffsetOf_GenQueriesEXT_n_not_4);
-COMPILE_ASSERT(offsetof(GenQueriesEXT, ids_shm_id) == 8,
- OffsetOf_GenQueriesEXT_ids_shm_id_not_8);
-COMPILE_ASSERT(offsetof(GenQueriesEXT, ids_shm_offset) == 12,
- OffsetOf_GenQueriesEXT_ids_shm_offset_not_12);
+COMPILE_ASSERT(offsetof(GenQueriesEXT, queries_shm_id) == 8,
+ OffsetOf_GenQueriesEXT_queries_shm_id_not_8);
+COMPILE_ASSERT(offsetof(GenQueriesEXT, queries_shm_offset) == 12,
+ OffsetOf_GenQueriesEXT_queries_shm_offset_not_12);
+
+struct GenQueriesEXTImmediate {
+ typedef GenQueriesEXTImmediate ValueType;
+ static const CommandId kCmdId = kGenQueriesEXTImmediate;
+ 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* _queries) {
+ SetHeader(_n);
+ n = _n;
+ memcpy(ImmediateDataAddress(this),
+ _queries, ComputeDataSize(_n));
+ }
+
+ void* Set(void* cmd, GLsizei _n, GLuint* _queries) {
+ static_cast<ValueType*>(cmd)->Init(_n, _queries);
+ const uint32 size = ComputeSize(_n);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ int32 n;
+};
+
+COMPILE_ASSERT(sizeof(GenQueriesEXTImmediate) == 8,
+ Sizeof_GenQueriesEXTImmediate_is_not_8);
+COMPILE_ASSERT(offsetof(GenQueriesEXTImmediate, header) == 0,
+ OffsetOf_GenQueriesEXTImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(GenQueriesEXTImmediate, n) == 4,
+ OffsetOf_GenQueriesEXTImmediate_n_not_4);
struct DeleteQueriesEXT {
typedef DeleteQueriesEXT ValueType;
@@ -8579,23 +8623,25 @@ struct DeleteQueriesEXT {
header.SetCmd<ValueType>();
}
- void Init(GLsizei _n, uint32 _ids_shm_id, uint32 _ids_shm_offset) {
+ void Init(GLsizei _n, uint32 _queries_shm_id, uint32 _queries_shm_offset) {
SetHeader();
n = _n;
- ids_shm_id = _ids_shm_id;
- ids_shm_offset = _ids_shm_offset;
+ queries_shm_id = _queries_shm_id;
+ queries_shm_offset = _queries_shm_offset;
}
void* Set(
- void* cmd, GLsizei _n, uint32 _ids_shm_id, uint32 _ids_shm_offset) {
- static_cast<ValueType*>(cmd)->Init(_n, _ids_shm_id, _ids_shm_offset);
+ void* cmd, GLsizei _n, uint32 _queries_shm_id,
+ uint32 _queries_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_n, _queries_shm_id, _queries_shm_offset);
return NextCmdAddress<ValueType>(cmd);
}
gpu::CommandHeader header;
int32 n;
- uint32 ids_shm_id;
- uint32 ids_shm_offset;
+ uint32 queries_shm_id;
+ uint32 queries_shm_offset;
};
COMPILE_ASSERT(sizeof(DeleteQueriesEXT) == 16,
@@ -8604,44 +8650,52 @@ COMPILE_ASSERT(offsetof(DeleteQueriesEXT, header) == 0,
OffsetOf_DeleteQueriesEXT_header_not_0);
COMPILE_ASSERT(offsetof(DeleteQueriesEXT, n) == 4,
OffsetOf_DeleteQueriesEXT_n_not_4);
-COMPILE_ASSERT(offsetof(DeleteQueriesEXT, ids_shm_id) == 8,
- OffsetOf_DeleteQueriesEXT_ids_shm_id_not_8);
-COMPILE_ASSERT(offsetof(DeleteQueriesEXT, ids_shm_offset) == 12,
- OffsetOf_DeleteQueriesEXT_ids_shm_offset_not_12);
+COMPILE_ASSERT(offsetof(DeleteQueriesEXT, queries_shm_id) == 8,
+ OffsetOf_DeleteQueriesEXT_queries_shm_id_not_8);
+COMPILE_ASSERT(offsetof(DeleteQueriesEXT, queries_shm_offset) == 12,
+ OffsetOf_DeleteQueriesEXT_queries_shm_offset_not_12);
+
+struct DeleteQueriesEXTImmediate {
+ typedef DeleteQueriesEXTImmediate ValueType;
+ static const CommandId kCmdId = kDeleteQueriesEXTImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
-struct IsQueryEXT {
- typedef IsQueryEXT ValueType;
- static const CommandId kCmdId = kIsQueryEXT;
- static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+ static uint32 ComputeDataSize(GLsizei n) {
+ return static_cast<uint32>(sizeof(GLuint) * n); // NOLINT
+ }
- static uint32 ComputeSize() {
- return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ static uint32 ComputeSize(GLsizei n) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + ComputeDataSize(n)); // NOLINT
}
- void SetHeader() {
- header.SetCmd<ValueType>();
+ void SetHeader(GLsizei n) {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize(n));
}
- void Init(GLuint _id) {
- SetHeader();
- id = _id;
+ void Init(GLsizei _n, const GLuint* _queries) {
+ SetHeader(_n);
+ n = _n;
+ memcpy(ImmediateDataAddress(this),
+ _queries, ComputeDataSize(_n));
}
- void* Set(void* cmd, GLuint _id) {
- static_cast<ValueType*>(cmd)->Init(_id);
- return NextCmdAddress<ValueType>(cmd);
+ void* Set(void* cmd, GLsizei _n, const GLuint* _queries) {
+ static_cast<ValueType*>(cmd)->Init(_n, _queries);
+ const uint32 size = ComputeSize(_n);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
}
gpu::CommandHeader header;
- uint32 id;
+ int32 n;
};
-COMPILE_ASSERT(sizeof(IsQueryEXT) == 8,
- Sizeof_IsQueryEXT_is_not_8);
-COMPILE_ASSERT(offsetof(IsQueryEXT, header) == 0,
- OffsetOf_IsQueryEXT_header_not_0);
-COMPILE_ASSERT(offsetof(IsQueryEXT, id) == 4,
- OffsetOf_IsQueryEXT_id_not_4);
+COMPILE_ASSERT(sizeof(DeleteQueriesEXTImmediate) == 8,
+ Sizeof_DeleteQueriesEXTImmediate_is_not_8);
+COMPILE_ASSERT(offsetof(DeleteQueriesEXTImmediate, header) == 0,
+ OffsetOf_DeleteQueriesEXTImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(DeleteQueriesEXTImmediate, n) == 4,
+ OffsetOf_DeleteQueriesEXTImmediate_n_not_4);
struct BeginQueryEXT {
typedef BeginQueryEXT ValueType;
@@ -8656,30 +8710,43 @@ struct BeginQueryEXT {
header.SetCmd<ValueType>();
}
- void Init(GLenum _target, GLuint _id) {
+ void Init(
+ GLenum _target, GLuint _id, uint32 _sync_data_shm_id,
+ uint32 _sync_data_shm_offset) {
SetHeader();
target = _target;
id = _id;
+ sync_data_shm_id = _sync_data_shm_id;
+ sync_data_shm_offset = _sync_data_shm_offset;
}
- void* Set(void* cmd, GLenum _target, GLuint _id) {
- static_cast<ValueType*>(cmd)->Init(_target, _id);
+ void* Set(
+ void* cmd, GLenum _target, GLuint _id, uint32 _sync_data_shm_id,
+ uint32 _sync_data_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_target, _id, _sync_data_shm_id, _sync_data_shm_offset);
return NextCmdAddress<ValueType>(cmd);
}
gpu::CommandHeader header;
uint32 target;
uint32 id;
+ uint32 sync_data_shm_id;
+ uint32 sync_data_shm_offset;
};
-COMPILE_ASSERT(sizeof(BeginQueryEXT) == 12,
- Sizeof_BeginQueryEXT_is_not_12);
+COMPILE_ASSERT(sizeof(BeginQueryEXT) == 20,
+ Sizeof_BeginQueryEXT_is_not_20);
COMPILE_ASSERT(offsetof(BeginQueryEXT, header) == 0,
OffsetOf_BeginQueryEXT_header_not_0);
COMPILE_ASSERT(offsetof(BeginQueryEXT, target) == 4,
OffsetOf_BeginQueryEXT_target_not_4);
COMPILE_ASSERT(offsetof(BeginQueryEXT, id) == 8,
OffsetOf_BeginQueryEXT_id_not_8);
+COMPILE_ASSERT(offsetof(BeginQueryEXT, sync_data_shm_id) == 12,
+ OffsetOf_BeginQueryEXT_sync_data_shm_id_not_12);
+COMPILE_ASSERT(offsetof(BeginQueryEXT, sync_data_shm_offset) == 16,
+ OffsetOf_BeginQueryEXT_sync_data_shm_offset_not_16);
struct EndQueryEXT {
typedef EndQueryEXT ValueType;
@@ -8694,128 +8761,30 @@ struct EndQueryEXT {
header.SetCmd<ValueType>();
}
- void Init(GLenum _target) {
+ void Init(GLenum _target, GLuint _submit_count) {
SetHeader();
target = _target;
+ submit_count = _submit_count;
}
- void* Set(void* cmd, GLenum _target) {
- static_cast<ValueType*>(cmd)->Init(_target);
+ void* Set(void* cmd, GLenum _target, GLuint _submit_count) {
+ static_cast<ValueType*>(cmd)->Init(_target, _submit_count);
return NextCmdAddress<ValueType>(cmd);
}
gpu::CommandHeader header;
uint32 target;
+ uint32 submit_count;
};
-COMPILE_ASSERT(sizeof(EndQueryEXT) == 8,
- Sizeof_EndQueryEXT_is_not_8);
+COMPILE_ASSERT(sizeof(EndQueryEXT) == 12,
+ Sizeof_EndQueryEXT_is_not_12);
COMPILE_ASSERT(offsetof(EndQueryEXT, header) == 0,
OffsetOf_EndQueryEXT_header_not_0);
COMPILE_ASSERT(offsetof(EndQueryEXT, target) == 4,
OffsetOf_EndQueryEXT_target_not_4);
-
-struct GetQueryivEXT {
- typedef GetQueryivEXT ValueType;
- static const CommandId kCmdId = kGetQueryivEXT;
- static const cmd::ArgFlags kArgFlags = cmd::kFixed;
-
- static uint32 ComputeSize() {
- return static_cast<uint32>(sizeof(ValueType)); // NOLINT
- }
-
- void SetHeader() {
- header.SetCmd<ValueType>();
- }
-
- void Init(
- GLenum _target, GLenum _pname, uint32 _params_shm_id,
- uint32 _params_shm_offset) {
- SetHeader();
- target = _target;
- pname = _pname;
- params_shm_id = _params_shm_id;
- params_shm_offset = _params_shm_offset;
- }
-
- void* Set(
- void* cmd, GLenum _target, GLenum _pname, uint32 _params_shm_id,
- uint32 _params_shm_offset) {
- static_cast<ValueType*>(
- cmd)->Init(_target, _pname, _params_shm_id, _params_shm_offset);
- return NextCmdAddress<ValueType>(cmd);
- }
-
- gpu::CommandHeader header;
- uint32 target;
- uint32 pname;
- uint32 params_shm_id;
- uint32 params_shm_offset;
-};
-
-COMPILE_ASSERT(sizeof(GetQueryivEXT) == 20,
- Sizeof_GetQueryivEXT_is_not_20);
-COMPILE_ASSERT(offsetof(GetQueryivEXT, header) == 0,
- OffsetOf_GetQueryivEXT_header_not_0);
-COMPILE_ASSERT(offsetof(GetQueryivEXT, target) == 4,
- OffsetOf_GetQueryivEXT_target_not_4);
-COMPILE_ASSERT(offsetof(GetQueryivEXT, pname) == 8,
- OffsetOf_GetQueryivEXT_pname_not_8);
-COMPILE_ASSERT(offsetof(GetQueryivEXT, params_shm_id) == 12,
- OffsetOf_GetQueryivEXT_params_shm_id_not_12);
-COMPILE_ASSERT(offsetof(GetQueryivEXT, params_shm_offset) == 16,
- OffsetOf_GetQueryivEXT_params_shm_offset_not_16);
-
-struct GetQueryObjectuivEXT {
- typedef GetQueryObjectuivEXT ValueType;
- static const CommandId kCmdId = kGetQueryObjectuivEXT;
- 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 _id, GLenum _pname, uint32 _params_shm_id,
- uint32 _params_shm_offset) {
- SetHeader();
- id = _id;
- pname = _pname;
- params_shm_id = _params_shm_id;
- params_shm_offset = _params_shm_offset;
- }
-
- void* Set(
- void* cmd, GLuint _id, GLenum _pname, uint32 _params_shm_id,
- uint32 _params_shm_offset) {
- static_cast<ValueType*>(
- cmd)->Init(_id, _pname, _params_shm_id, _params_shm_offset);
- return NextCmdAddress<ValueType>(cmd);
- }
-
- gpu::CommandHeader header;
- uint32 id;
- uint32 pname;
- uint32 params_shm_id;
- uint32 params_shm_offset;
-};
-
-COMPILE_ASSERT(sizeof(GetQueryObjectuivEXT) == 20,
- Sizeof_GetQueryObjectuivEXT_is_not_20);
-COMPILE_ASSERT(offsetof(GetQueryObjectuivEXT, header) == 0,
- OffsetOf_GetQueryObjectuivEXT_header_not_0);
-COMPILE_ASSERT(offsetof(GetQueryObjectuivEXT, id) == 4,
- OffsetOf_GetQueryObjectuivEXT_id_not_4);
-COMPILE_ASSERT(offsetof(GetQueryObjectuivEXT, pname) == 8,
- OffsetOf_GetQueryObjectuivEXT_pname_not_8);
-COMPILE_ASSERT(offsetof(GetQueryObjectuivEXT, params_shm_id) == 12,
- OffsetOf_GetQueryObjectuivEXT_params_shm_id_not_12);
-COMPILE_ASSERT(offsetof(GetQueryObjectuivEXT, params_shm_offset) == 16,
- OffsetOf_GetQueryObjectuivEXT_params_shm_offset_not_16);
+COMPILE_ASSERT(offsetof(EndQueryEXT, submit_count) == 8,
+ OffsetOf_EndQueryEXT_submit_count_not_8);
struct SwapBuffers {
typedef SwapBuffers ValueType;
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 4bc2341..fa73330 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
@@ -3329,12 +3329,29 @@ TEST_F(GLES2FormatTest, GenQueriesEXT) {
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.ids_shm_id);
- EXPECT_EQ(static_cast<uint32>(13), cmd.ids_shm_offset);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.queries_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.queries_shm_offset);
CheckBytesWrittenMatchesExpectedSize(
next_cmd, sizeof(cmd));
}
+TEST_F(GLES2FormatTest, GenQueriesEXTImmediate) {
+ static GLuint ids[] = { 12, 23, 34, };
+ GenQueriesEXTImmediate& cmd = *GetBufferAs<GenQueriesEXTImmediate>();
+ void* next_cmd = cmd.Set(
+ &cmd, static_cast<GLsizei>(arraysize(ids)), ids);
+ EXPECT_EQ(static_cast<uint32>(GenQueriesEXTImmediate::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, DeleteQueriesEXT) {
DeleteQueriesEXT& cmd = *GetBufferAs<DeleteQueriesEXT>();
void* next_cmd = cmd.Set(
@@ -3346,23 +3363,27 @@ TEST_F(GLES2FormatTest, DeleteQueriesEXT) {
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.ids_shm_id);
- EXPECT_EQ(static_cast<uint32>(13), cmd.ids_shm_offset);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.queries_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.queries_shm_offset);
CheckBytesWrittenMatchesExpectedSize(
next_cmd, sizeof(cmd));
}
-TEST_F(GLES2FormatTest, IsQueryEXT) {
- IsQueryEXT& cmd = *GetBufferAs<IsQueryEXT>();
+TEST_F(GLES2FormatTest, DeleteQueriesEXTImmediate) {
+ static GLuint ids[] = { 12, 23, 34, };
+ DeleteQueriesEXTImmediate& cmd = *GetBufferAs<DeleteQueriesEXTImmediate>();
void* next_cmd = cmd.Set(
- &cmd,
- static_cast<GLuint>(11));
- EXPECT_EQ(static_cast<uint32>(IsQueryEXT::kCmdId),
+ &cmd, static_cast<GLsizei>(arraysize(ids)), ids);
+ EXPECT_EQ(static_cast<uint32>(DeleteQueriesEXTImmediate::kCmdId),
cmd.header.command);
- EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
- EXPECT_EQ(static_cast<GLuint>(11), cmd.id);
+ 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));
+ next_cmd, sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(arraysize(ids) * 4u));
+ // TODO(gman): Check that ids were inserted;
}
TEST_F(GLES2FormatTest, BeginQueryEXT) {
@@ -3370,12 +3391,16 @@ TEST_F(GLES2FormatTest, BeginQueryEXT) {
void* next_cmd = cmd.Set(
&cmd,
static_cast<GLenum>(11),
- static_cast<GLuint>(12));
+ static_cast<GLuint>(12),
+ static_cast<uint32>(13),
+ static_cast<uint32>(14));
EXPECT_EQ(static_cast<uint32>(BeginQueryEXT::kCmdId),
cmd.header.command);
EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
EXPECT_EQ(static_cast<GLuint>(12), cmd.id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.sync_data_shm_id);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.sync_data_shm_offset);
CheckBytesWrittenMatchesExpectedSize(
next_cmd, sizeof(cmd));
}
@@ -3384,49 +3409,13 @@ TEST_F(GLES2FormatTest, EndQueryEXT) {
EndQueryEXT& cmd = *GetBufferAs<EndQueryEXT>();
void* next_cmd = cmd.Set(
&cmd,
- static_cast<GLenum>(11));
- EXPECT_EQ(static_cast<uint32>(EndQueryEXT::kCmdId),
- cmd.header.command);
- EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
- EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
- CheckBytesWrittenMatchesExpectedSize(
- next_cmd, sizeof(cmd));
-}
-
-TEST_F(GLES2FormatTest, GetQueryivEXT) {
- GetQueryivEXT& cmd = *GetBufferAs<GetQueryivEXT>();
- void* next_cmd = cmd.Set(
- &cmd,
static_cast<GLenum>(11),
- static_cast<GLenum>(12),
- static_cast<uint32>(13),
- static_cast<uint32>(14));
- EXPECT_EQ(static_cast<uint32>(GetQueryivEXT::kCmdId),
+ static_cast<GLuint>(12));
+ EXPECT_EQ(static_cast<uint32>(EndQueryEXT::kCmdId),
cmd.header.command);
EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
- EXPECT_EQ(static_cast<GLenum>(12), cmd.pname);
- EXPECT_EQ(static_cast<uint32>(13), cmd.params_shm_id);
- EXPECT_EQ(static_cast<uint32>(14), cmd.params_shm_offset);
- CheckBytesWrittenMatchesExpectedSize(
- next_cmd, sizeof(cmd));
-}
-
-TEST_F(GLES2FormatTest, GetQueryObjectuivEXT) {
- GetQueryObjectuivEXT& cmd = *GetBufferAs<GetQueryObjectuivEXT>();
- void* next_cmd = cmd.Set(
- &cmd,
- static_cast<GLuint>(11),
- static_cast<GLenum>(12),
- static_cast<uint32>(13),
- static_cast<uint32>(14));
- EXPECT_EQ(static_cast<uint32>(GetQueryObjectuivEXT::kCmdId),
- cmd.header.command);
- EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
- EXPECT_EQ(static_cast<GLuint>(11), cmd.id);
- EXPECT_EQ(static_cast<GLenum>(12), cmd.pname);
- EXPECT_EQ(static_cast<uint32>(13), cmd.params_shm_id);
- EXPECT_EQ(static_cast<uint32>(14), cmd.params_shm_offset);
+ EXPECT_EQ(static_cast<GLuint>(12), cmd.submit_count);
CheckBytesWrittenMatchesExpectedSize(
next_cmd, sizeof(cmd));
}
diff --git a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
index 9a311a8..37859a7 100644
--- a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
@@ -197,31 +197,30 @@
OP(RenderbufferStorageMultisampleEXT) /* 440 */ \
OP(TexStorage2DEXT) /* 441 */ \
OP(GenQueriesEXT) /* 442 */ \
- OP(DeleteQueriesEXT) /* 443 */ \
- OP(IsQueryEXT) /* 444 */ \
- OP(BeginQueryEXT) /* 445 */ \
- OP(EndQueryEXT) /* 446 */ \
- OP(GetQueryivEXT) /* 447 */ \
- OP(GetQueryObjectuivEXT) /* 448 */ \
- OP(SwapBuffers) /* 449 */ \
- OP(GetMaxValueInBufferCHROMIUM) /* 450 */ \
- OP(GenSharedIdsCHROMIUM) /* 451 */ \
- OP(DeleteSharedIdsCHROMIUM) /* 452 */ \
- OP(RegisterSharedIdsCHROMIUM) /* 453 */ \
- OP(EnableFeatureCHROMIUM) /* 454 */ \
- OP(ResizeCHROMIUM) /* 455 */ \
- OP(GetRequestableExtensionsCHROMIUM) /* 456 */ \
- OP(RequestExtensionCHROMIUM) /* 457 */ \
- OP(GetMultipleIntegervCHROMIUM) /* 458 */ \
- OP(GetProgramInfoCHROMIUM) /* 459 */ \
- OP(CreateStreamTextureCHROMIUM) /* 460 */ \
- OP(DestroyStreamTextureCHROMIUM) /* 461 */ \
- OP(GetTranslatedShaderSourceANGLE) /* 462 */ \
- OP(PostSubBufferCHROMIUM) /* 463 */ \
- OP(TexImageIOSurface2DCHROMIUM) /* 464 */ \
- OP(DrawArraysInstancedANGLE) /* 465 */ \
- OP(DrawElementsInstancedANGLE) /* 466 */ \
- OP(VertexAttribDivisorANGLE) /* 467 */ \
+ OP(GenQueriesEXTImmediate) /* 443 */ \
+ OP(DeleteQueriesEXT) /* 444 */ \
+ OP(DeleteQueriesEXTImmediate) /* 445 */ \
+ OP(BeginQueryEXT) /* 446 */ \
+ OP(EndQueryEXT) /* 447 */ \
+ OP(SwapBuffers) /* 448 */ \
+ OP(GetMaxValueInBufferCHROMIUM) /* 449 */ \
+ OP(GenSharedIdsCHROMIUM) /* 450 */ \
+ OP(DeleteSharedIdsCHROMIUM) /* 451 */ \
+ OP(RegisterSharedIdsCHROMIUM) /* 452 */ \
+ OP(EnableFeatureCHROMIUM) /* 453 */ \
+ OP(ResizeCHROMIUM) /* 454 */ \
+ OP(GetRequestableExtensionsCHROMIUM) /* 455 */ \
+ OP(RequestExtensionCHROMIUM) /* 456 */ \
+ OP(GetMultipleIntegervCHROMIUM) /* 457 */ \
+ OP(GetProgramInfoCHROMIUM) /* 458 */ \
+ OP(CreateStreamTextureCHROMIUM) /* 459 */ \
+ OP(DestroyStreamTextureCHROMIUM) /* 460 */ \
+ OP(GetTranslatedShaderSourceANGLE) /* 461 */ \
+ OP(PostSubBufferCHROMIUM) /* 462 */ \
+ OP(TexImageIOSurface2DCHROMIUM) /* 463 */ \
+ OP(DrawArraysInstancedANGLE) /* 464 */ \
+ OP(DrawElementsInstancedANGLE) /* 465 */ \
+ OP(VertexAttribDivisorANGLE) /* 466 */ \
enum CommandId {
kStartPoint = cmd::kLastCommonId, // All GLES2 commands start after this.
diff --git a/gpu/command_buffer/service/common_decoder.h b/gpu/command_buffer/service/common_decoder.h
index 7ac9abb..1b8cf38 100644
--- a/gpu/command_buffer/service/common_decoder.h
+++ b/gpu/command_buffer/service/common_decoder.h
@@ -105,20 +105,6 @@ class GPU_EXPORT CommonDecoder : NON_EXPORTED_BASE(public AsyncAPIInterface) {
// Gets a bucket. Returns NULL if the bucket does not exist.
Bucket* GetBucket(uint32 bucket_id) const;
- protected:
- // Executes a common command.
- // Parameters:
- // command: the command index.
- // arg_count: the number of CommandBufferEntry arguments.
- // cmd_data: the command data.
- // Returns:
- // error::kNoError if no error was found, one of
- // error::Error otherwise.
- error::Error DoCommonCommand(
- unsigned int command,
- unsigned int arg_count,
- const void* cmd_data);
-
// Gets the address of shared memory data, given a shared memory ID and an
// offset. Also checks that the size is consistent with the shared memory
// size.
@@ -140,6 +126,20 @@ class GPU_EXPORT CommonDecoder : NON_EXPORTED_BASE(public AsyncAPIInterface) {
return static_cast<T>(GetAddressAndCheckSize(shm_id, offset, size));
}
+ protected:
+ // Executes a common command.
+ // Parameters:
+ // command: the command index.
+ // arg_count: the number of CommandBufferEntry arguments.
+ // cmd_data: the command data.
+ // Returns:
+ // error::kNoError if no error was found, one of
+ // error::Error otherwise.
+ error::Error DoCommonCommand(
+ unsigned int command,
+ unsigned int arg_count,
+ const void* cmd_data);
+
// Gets an name for a common command.
const char* GetCommonCommandName(cmd::CommandId command_id) const;
diff --git a/gpu/command_buffer/service/context_group.cc b/gpu/command_buffer/service/context_group.cc
index bfe311b..f3c2de3 100644
--- a/gpu/command_buffer/service/context_group.cc
+++ b/gpu/command_buffer/service/context_group.cc
@@ -37,6 +37,7 @@ ContextGroup::ContextGroup(bool bind_generates_resource)
new NonReusedIdAllocator);
id_namespaces_[id_namespaces::kRenderbuffers].reset(new IdAllocator);
id_namespaces_[id_namespaces::kTextures].reset(new IdAllocator);
+ id_namespaces_[id_namespaces::kQueries].reset(new IdAllocator);
}
ContextGroup::~ContextGroup() {
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc
index aa819d2..b31a5e5 100644
--- a/gpu/command_buffer/service/feature_info.cc
+++ b/gpu/command_buffer/service/feature_info.cc
@@ -439,6 +439,14 @@ void FeatureInfo::AddFeatures(const char* desired_features) {
}
}
+ if (ext.Desire("GL_EXT_occlusion_query_boolean") &&
+ (ext.Have("GL_EXT_occlusion_query_boolean") ||
+ ext.Have("GL_ARB_occlusion_query2"))) {
+ // TODO(gman): Comment in the next line once this really works.
+ // AddExtensionString("GL_EXT_occlusion_query_boolean");
+ feature_flags_.occlusion_query_boolean = true;
+ }
+
if (ext.Desire("GL_ANGLE_instanced_arrays") &&
(ext.Have("GL_ANGLE_instanced_arrays") ||
(ext.Have("GL_ARB_instanced_arrays") &&
diff --git a/gpu/command_buffer/service/feature_info.h b/gpu/command_buffer/service/feature_info.h
index bdb4c0a..4bac947 100644
--- a/gpu/command_buffer/service/feature_info.h
+++ b/gpu/command_buffer/service/feature_info.h
@@ -32,7 +32,8 @@ class GPU_EXPORT FeatureInfo : public base::RefCounted<FeatureInfo> {
angle_translated_shader_source(false),
angle_pack_reverse_row_order(false),
arb_texture_rectangle(false),
- angle_instanced_arrays(false) {
+ angle_instanced_arrays(false),
+ occlusion_query_boolean(false) {
}
bool chromium_framebuffer_multisample;
@@ -47,6 +48,7 @@ class GPU_EXPORT FeatureInfo : public base::RefCounted<FeatureInfo> {
bool angle_pack_reverse_row_order;
bool arb_texture_rectangle;
bool angle_instanced_arrays;
+ bool occlusion_query_boolean;
};
FeatureInfo();
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 0ecc3d8..96440a0 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -36,6 +36,7 @@
#include "gpu/command_buffer/service/gles2_cmd_validation.h"
#include "gpu/command_buffer/service/gpu_switches.h"
#include "gpu/command_buffer/service/program_manager.h"
+#include "gpu/command_buffer/service/query_manager.h"
#include "gpu/command_buffer/service/renderbuffer_manager.h"
#include "gpu/command_buffer/service/shader_manager.h"
#include "gpu/command_buffer/service/shader_translator.h"
@@ -550,6 +551,7 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>,
virtual gfx::GLContext* GetGLContext() { return context_.get(); }
virtual gfx::GLSurface* GetGLSurface() { return surface_.get(); }
virtual ContextGroup* GetContextGroup() { return group_.get(); }
+ virtual QueryManager* GetQueryManager() { return query_manager_.get(); }
virtual void SetGLError(GLenum error, const char* msg);
virtual void SetResizeCallback(
@@ -651,6 +653,8 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>,
void DeleteFramebuffersHelper(GLsizei n, const GLuint* client_ids);
bool GenRenderbuffersHelper(GLsizei n, const GLuint* client_ids);
void DeleteRenderbuffersHelper(GLsizei n, const GLuint* client_ids);
+ bool GenQueriesEXTHelper(GLsizei n, const GLuint* client_ids);
+ void DeleteQueriesEXTHelper(GLsizei n, const GLuint* client_ids);
// TODO(gman): Cache these pointers?
BufferManager* buffer_manager() {
@@ -1068,6 +1072,12 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>,
// Wrapper for glEnableVertexAttribArray.
void DoEnableVertexAttribArray(GLuint index);
+ // Wrapper for glFinish.
+ void DoFinish();
+
+ // Wrapper for glFlush.
+ void DoFlush();
+
// Wrapper for glFramebufferRenderbufffer.
void DoFramebufferRenderbuffer(
GLenum target, GLenum attachment, GLenum renderbuffertarget,
@@ -1478,6 +1488,9 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>,
scoped_ptr<Texture> offscreen_resolved_color_texture_;
GLenum offscreen_saved_color_format_;
+ scoped_ptr<QueryManager> query_manager_;
+ QueryManager::Query::Ref current_query_;
+
base::Callback<void(gfx::Size)> resize_callback_;
MsgCallback msg_callback_;
@@ -2009,6 +2022,8 @@ bool GLES2DecoderImpl::Initialize(
vertex_attrib_manager_.reset(new VertexAttribManager());
vertex_attrib_manager_->Initialize(group_->max_vertex_attribs());
+ query_manager_.reset(new QueryManager());
+
util_.set_num_compressed_texture_formats(
validators_->compressed_texture_format.GetValues().size());
@@ -2729,6 +2744,7 @@ void GLES2DecoderImpl::Destroy() {
texture_units_.reset();
bound_array_buffer_ = NULL;
bound_element_array_buffer_ = NULL;
+ current_query_ = NULL;
current_program_ = NULL;
bound_read_framebuffer_ = NULL;
bound_draw_framebuffer_ = NULL;
@@ -2786,6 +2802,11 @@ void GLES2DecoderImpl::Destroy() {
offscreen_resolved_color_texture_->Invalidate();
}
+ if (query_manager_.get()) {
+ query_manager_->Destroy(have_context);
+ query_manager_.reset();
+ }
+
if (group_) {
group_->Destroy(have_context);
group_ = NULL;
@@ -3137,6 +3158,20 @@ bool GLES2DecoderImpl::CreateShaderHelper(GLenum type, GLuint client_id) {
return true;
}
+void GLES2DecoderImpl::DoFinish() {
+ glFinish();
+ if (!query_manager_->ProcessPendingQueries(this)) {
+ current_decoder_error_ = error::kOutOfBounds;
+ }
+}
+
+void GLES2DecoderImpl::DoFlush() {
+ glFlush();
+ if (!query_manager_->ProcessPendingQueries(this)) {
+ current_decoder_error_ = error::kOutOfBounds;
+ }
+}
+
void GLES2DecoderImpl::DoActiveTexture(GLenum texture_unit) {
GLuint texture_index = texture_unit - GL_TEXTURE0;
if (texture_index >= group_->max_texture_units()) {
@@ -5197,6 +5232,9 @@ error::Error GLES2DecoderImpl::DoDrawArrays(bool instanced,
} else {
glDrawArraysInstancedANGLE(mode, first, count, primcount);
}
+ if (!query_manager_->ProcessPendingQueries(this)) {
+ current_decoder_error_ = error::kOutOfBounds;
+ }
if (textures_set) {
RestoreStateForNonRenderableTextures();
}
@@ -5307,6 +5345,9 @@ error::Error GLES2DecoderImpl::DoDrawElements(bool instanced,
} else {
glDrawElementsInstancedANGLE(mode, count, type, indices, primcount);
}
+ if (!query_manager_->ProcessPendingQueries(this)) {
+ current_decoder_error_ = error::kOutOfBounds;
+ }
if (textures_set) {
RestoreStateForNonRenderableTextures();
}
@@ -7890,6 +7931,123 @@ bool GLES2DecoderImpl::WasContextLost() {
return false;
}
+bool GLES2DecoderImpl::GenQueriesEXTHelper(
+ GLsizei n, const GLuint* client_ids) {
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ if (query_manager_->GetQuery(client_ids[ii])) {
+ return false;
+ }
+ }
+ scoped_array<GLuint> service_ids(new GLuint[n]);
+ glGenQueriesARB(n, service_ids.get());
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ query_manager_->CreateQuery(client_ids[ii], service_ids[ii]);
+ }
+ return true;
+}
+
+void GLES2DecoderImpl::DeleteQueriesEXTHelper(
+ GLsizei n, const GLuint* client_ids) {
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ QueryManager::Query* query = query_manager_->GetQuery(client_ids[ii]);
+ if (query && !query->IsDeleted()) {
+ if (query == current_query_) {
+ current_query_ = NULL;
+ }
+ GLuint service_id = query->service_id();
+ glDeleteQueriesARB(1, &service_id);
+ query_manager_->RemoveQuery(client_ids[ii]);
+ }
+ }
+}
+
+error::Error GLES2DecoderImpl::HandleBeginQueryEXT(
+ uint32 immediate_data_size, const gles2::BeginQueryEXT& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLuint client_id = static_cast<GLuint>(c.id);
+ int32 sync_shm_id = static_cast<int32>(c.sync_data_shm_id);
+ uint32 sync_shm_offset = static_cast<uint32>(c.sync_data_shm_offset);
+
+ if (!feature_info_->feature_flags().occlusion_query_boolean) {
+ SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT: not enabled");
+ return error::kNoError;
+ }
+
+ if (current_query_) {
+ SetGLError(
+ GL_INVALID_OPERATION, "glBeginQueryEXT: query already in progress");
+ return error::kNoError;
+ }
+
+ if (client_id == 0) {
+ SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT: id is 0");
+ return error::kNoError;
+ }
+
+ QueryManager::Query* query = query_manager_->GetQuery(client_id);
+ if (!query) {
+ // Checks id was made by glGenQueries
+ IdAllocatorInterface* id_allocator =
+ group_->GetIdAllocator(id_namespaces::kQueries);
+ if (!id_allocator->InUse(client_id)) {
+ SetGLError(GL_INVALID_OPERATION,
+ "glBeginQueryEXT: id not made by glGenQueriesEXT");
+ return error::kNoError;
+ }
+ // Makes object and assoicates with memory.
+ GLuint service_id = 0;
+ glGenQueriesARB(1, &service_id);
+ DCHECK_NE(0u, service_id);
+ query = query_manager_->CreateQuery(client_id, service_id);
+ }
+
+ QuerySync* sync = GetSharedMemoryAs<QuerySync*>(
+ sync_shm_id, sync_shm_offset, sizeof(*sync));
+ if (!sync) {
+ DLOG(ERROR) << "Invalid shared memory referenced by query";
+ return error::kOutOfBounds;
+ }
+
+ if (!query->IsInitialized()) {
+ query->Initialize(target, sync_shm_id, sync_shm_offset);
+ } else if (query->target() != target) {
+ SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT: target does not match");
+ return error::kNoError;
+ } else if (query->shm_id() != sync_shm_id ||
+ query->shm_offset() != sync_shm_offset) {
+ DLOG(ERROR) << "Shared memory used by query not the same as before";
+ return error::kInvalidArguments;
+ }
+
+ query_manager_->RemovePendingQuery(query);
+
+ glBeginQueryARB(target, query->service_id());
+ current_query_ = query;
+
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleEndQueryEXT(
+ uint32 immediate_data_size, const gles2::EndQueryEXT& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ uint32 submit_count = static_cast<GLuint>(c.submit_count);
+
+ if (!current_query_) {
+ SetGLError(GL_INVALID_OPERATION, "glEndQueryEXT: No active query");
+ return error::kNoError;
+ }
+ if (current_query_->target() != target) {
+ SetGLError(GL_INVALID_OPERATION,
+ "glEndQueryEXT: target does not match active query");
+ return error::kNoError;
+ }
+ glEndQueryARB(target);
+ query_manager_->AddPendingQuery(current_query_, submit_count);
+ current_query_ = NULL;
+
+ return error::kNoError;
+}
+
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 89e1dd7..58031d6 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.h
@@ -27,6 +27,7 @@ namespace gles2 {
class ContextGroup;
class GLES2Util;
+class QueryManager;
struct DisallowedFeatures {
DisallowedFeatures()
@@ -126,6 +127,9 @@ class GPU_EXPORT GLES2Decoder : public CommonDecoder {
// Gets the associated ContextGroup
virtual ContextGroup* GetContextGroup() = 0;
+ // Gets the QueryManager for this context.
+ virtual QueryManager* GetQueryManager() = 0;
+
// Sets a callback which is called when a glResizeCHROMIUM command
// is processed.
virtual void SetResizeCallback(
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
index 79b726d..d0815dd 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
@@ -650,13 +650,13 @@ error::Error GLES2DecoderImpl::HandleEnableVertexAttribArray(
error::Error GLES2DecoderImpl::HandleFinish(
uint32 immediate_data_size, const gles2::Finish& c) {
- glFinish();
+ DoFinish();
return error::kNoError;
}
error::Error GLES2DecoderImpl::HandleFlush(
uint32 immediate_data_size, const gles2::Flush& c) {
- glFlush();
+ DoFlush();
return error::kNoError;
}
@@ -2609,50 +2609,69 @@ error::Error GLES2DecoderImpl::HandleTexStorage2DEXT(
error::Error GLES2DecoderImpl::HandleGenQueriesEXT(
uint32 immediate_data_size, const gles2::GenQueriesEXT& c) {
- // TODO: for now this is a no-op
- SetGLError(GL_INVALID_OPERATION, "glGenQueriesEXT not implemented");
- return error::kNoError;
-}
-
-error::Error GLES2DecoderImpl::HandleDeleteQueriesEXT(
- uint32 immediate_data_size, const gles2::DeleteQueriesEXT& c) {
- // TODO: for now this is a no-op
- SetGLError(GL_INVALID_OPERATION, "glDeleteQueriesEXT not implemented");
- return error::kNoError;
-}
-
-error::Error GLES2DecoderImpl::HandleIsQueryEXT(
- uint32 immediate_data_size, const gles2::IsQueryEXT& c) {
- // TODO: for now this is a no-op
- SetGLError(GL_INVALID_OPERATION, "glIsQueryEXT not implemented");
- return error::kNoError;
-}
-
-error::Error GLES2DecoderImpl::HandleBeginQueryEXT(
- uint32 immediate_data_size, const gles2::BeginQueryEXT& c) {
- // TODO: for now this is a no-op
- SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT not implemented");
+ GLsizei n = static_cast<GLsizei>(c.n);
+ uint32 data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+ GLuint* queries = GetSharedMemoryAs<GLuint*>(
+ c.queries_shm_id, c.queries_shm_offset, data_size);
+ if (queries == NULL) {
+ return error::kOutOfBounds;
+ }
+ if (!GenQueriesEXTHelper(n, queries)) {
+ return error::kInvalidArguments;
+ }
return error::kNoError;
}
-error::Error GLES2DecoderImpl::HandleEndQueryEXT(
- uint32 immediate_data_size, const gles2::EndQueryEXT& c) {
- // TODO: for now this is a no-op
- SetGLError(GL_INVALID_OPERATION, "glEndQueryEXT not implemented");
+error::Error GLES2DecoderImpl::HandleGenQueriesEXTImmediate(
+ uint32 immediate_data_size, const gles2::GenQueriesEXTImmediate& c) {
+ GLsizei n = static_cast<GLsizei>(c.n);
+ uint32 data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+ GLuint* queries = GetImmediateDataAs<GLuint*>(
+ c, data_size, immediate_data_size);
+ if (queries == NULL) {
+ return error::kOutOfBounds;
+ }
+ if (!GenQueriesEXTHelper(n, queries)) {
+ return error::kInvalidArguments;
+ }
return error::kNoError;
}
-error::Error GLES2DecoderImpl::HandleGetQueryivEXT(
- uint32 immediate_data_size, const gles2::GetQueryivEXT& c) {
- // TODO: for now this is a no-op
- SetGLError(GL_INVALID_OPERATION, "glGetQueryivEXT not implemented");
+error::Error GLES2DecoderImpl::HandleDeleteQueriesEXT(
+ uint32 immediate_data_size, const gles2::DeleteQueriesEXT& c) {
+ GLsizei n = static_cast<GLsizei>(c.n);
+ uint32 data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLuint* queries = GetSharedMemoryAs<const GLuint*>(
+ c.queries_shm_id, c.queries_shm_offset, data_size);
+ if (queries == NULL) {
+ return error::kOutOfBounds;
+ }
+ DeleteQueriesEXTHelper(n, queries);
return error::kNoError;
}
-error::Error GLES2DecoderImpl::HandleGetQueryObjectuivEXT(
- uint32 immediate_data_size, const gles2::GetQueryObjectuivEXT& c) {
- // TODO: for now this is a no-op
- SetGLError(GL_INVALID_OPERATION, "glGetQueryObjectuivEXT not implemented");
+error::Error GLES2DecoderImpl::HandleDeleteQueriesEXTImmediate(
+ uint32 immediate_data_size, const gles2::DeleteQueriesEXTImmediate& c) {
+ GLsizei n = static_cast<GLsizei>(c.n);
+ uint32 data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLuint* queries = GetImmediateDataAs<const GLuint*>(
+ c, data_size, immediate_data_size);
+ if (queries == NULL) {
+ return error::kOutOfBounds;
+ }
+ DeleteQueriesEXTHelper(n, queries);
return error::kNoError;
}
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
index 05994eb..7392280 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
@@ -25,6 +25,8 @@ class StreamTextureManager;
namespace gles2 {
class ContextGroup;
+class QueryManager;
+
class MockGLES2Decoder : public GLES2Decoder {
public:
MockGLES2Decoder();
@@ -47,6 +49,7 @@ class MockGLES2Decoder : public GLES2Decoder {
MOCK_METHOD0(GetGLSurface, gfx::GLSurface*());
MOCK_METHOD0(GetGLContext, gfx::GLContext*());
MOCK_METHOD0(GetContextGroup, ContextGroup*());
+ MOCK_METHOD0(GetQueryManager, gpu::gles2::QueryManager*());
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 d42c599..94f2e95 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
@@ -6562,6 +6562,96 @@ TEST_F(GLES2DecoderWithShaderTest,
EXPECT_EQ(GL_NO_ERROR, GetGLError());
}
+TEST_F(GLES2DecoderTest, BeingQueryEXTDisabled) {
+ // Test something fails if off.
+}
+
+TEST_F(GLES2DecoderManualInitTest, BeingEndQueryEXT) {
+ InitDecoder(
+ "GL_EXT_occlusion_query_boolean", // extensions
+ true, // has alpha
+ false, // has depth
+ false, // has stencil
+ true, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ // Test end fails if no begin.
+ EndQueryEXT end_cmd;
+ end_cmd.Init(GL_ANY_SAMPLES_PASSED_EXT, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(end_cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+
+ // Test a non-generated id fails.
+ BeginQueryEXT begin_cmd;
+ begin_cmd.Init(
+ GL_ANY_SAMPLES_PASSED_EXT, kInvalidClientId,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(begin_cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+
+ // Test id = 0 fails.
+ begin_cmd.Init(
+ GL_ANY_SAMPLES_PASSED_EXT, 0, kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(begin_cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+
+ EXPECT_CALL(*gl_, GenQueriesARB(1, _))
+ .WillOnce(SetArgumentPointee<1>(kNewServiceId))
+ .RetiresOnSaturation();
+ GenHelper<GenQueriesEXTImmediate>(kNewClientId);
+
+ // Test bad shared memory fails
+ begin_cmd.Init(
+ GL_ANY_SAMPLES_PASSED_EXT, kNewClientId,
+ kInvalidSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_NE(error::kNoError, ExecuteCmd(begin_cmd));
+ begin_cmd.Init(
+ GL_ANY_SAMPLES_PASSED_EXT, kNewClientId,
+ kSharedMemoryId, kInvalidSharedMemoryOffset);
+ EXPECT_NE(error::kNoError, ExecuteCmd(begin_cmd));
+
+ // Test valid parameters work.
+ EXPECT_CALL(*gl_, BeginQueryARB(GL_ANY_SAMPLES_PASSED_EXT, kNewServiceId))
+ .Times(1)
+ .RetiresOnSaturation();
+ begin_cmd.Init(
+ GL_ANY_SAMPLES_PASSED_EXT, kNewClientId,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(begin_cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ QueryManager* query_manager = decoder_->GetQueryManager();
+ ASSERT_TRUE(query_manager != NULL);
+ QueryManager::Query* query = query_manager->GetQuery(kNewClientId);
+ ASSERT_TRUE(query != NULL);
+ EXPECT_FALSE(query->pending());
+
+ // Test trying begin again fails
+ EXPECT_EQ(error::kNoError, ExecuteCmd(begin_cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+
+ // Test end fails with different target
+ end_cmd.Init(GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(end_cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+
+ // Test end succeeds
+ EXPECT_CALL(*gl_, EndQueryARB(GL_ANY_SAMPLES_PASSED_EXT))
+ .Times(1)
+ .RetiresOnSaturation();
+ end_cmd.Init(GL_ANY_SAMPLES_PASSED_EXT, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(end_cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(query->pending());
+
+ EXPECT_CALL(*gl_, DeleteQueriesARB(1, _))
+ .Times(1)
+ .RetiresOnSaturation();
+}
+
+
// TODO(gman): Complete this test.
// TEST_F(GLES2DecoderTest, CompressedTexImage2DGLError) {
// }
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc
index 0293bb4..f92a0f6 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc
@@ -33,6 +33,74 @@ class GLES2DecoderTest2 : public GLES2DecoderTestBase {
};
template <>
+void GLES2DecoderTestBase::SpecializedSetup<GenQueriesEXT, 0>(
+ bool valid) {
+ if (!valid) {
+ // Make the client_query_id_ so that trying to make it again
+ // will fail.
+ GetSharedMemoryAs<GLuint*>()[0] = client_query_id_;
+ EXPECT_CALL(*gl_, GenQueriesARB(1, _))
+ .WillOnce(SetArgumentPointee<1>(kNewServiceId));
+ GenQueriesEXT cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ }
+ // In the valid case this deletes the one created in the test. In the invalid
+ // case it deleted the one above.
+ EXPECT_CALL(*gl_, DeleteQueriesARB(1, _))
+ .Times(1)
+ .RetiresOnSaturation();
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<GenQueriesEXTImmediate, 0>(
+ bool valid) {
+ if (!valid) {
+ // Make the client_query_id_ so that trying to make it again
+ // will fail.
+ GetSharedMemoryAs<GLuint*>()[0] = client_query_id_;
+ EXPECT_CALL(*gl_, GenQueriesARB(1, _))
+ .WillOnce(SetArgumentPointee<1>(kNewServiceId));
+ GenQueriesEXT cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ }
+ // In the valid case this deletes the one created in the test. In the invalid
+ // case it deleted the one above.
+ EXPECT_CALL(*gl_, DeleteQueriesARB(1, _))
+ .Times(1)
+ .RetiresOnSaturation();
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<DeleteQueriesEXT, 0>(
+ bool valid) {
+ if (valid) {
+ // Make the client_query_id_ so that trying to delete it will succeed.
+ GetSharedMemoryAs<GLuint*>()[0] = client_query_id_;
+ EXPECT_CALL(*gl_, GenQueriesARB(1, _))
+ .WillOnce(SetArgumentPointee<1>(kServiceQueryId));
+ GenQueriesEXT cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ }
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<DeleteQueriesEXTImmediate, 0>(
+ bool valid) {
+ if (valid) {
+ // Make the client_query_id_ so that trying to delete it will succeed.
+ GetSharedMemoryAs<GLuint*>()[0] = client_query_id_;
+ EXPECT_CALL(*gl_, GenQueriesARB(1, _))
+ .WillOnce(SetArgumentPointee<1>(kServiceQueryId));
+ GenQueriesEXT cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ }
+};
+
+template <>
void GLES2DecoderTestBase::SpecializedSetup<LinkProgram, 0>(bool /* valid */) {
const GLuint kClientVertexShaderId = 5001;
const GLuint kServiceVertexShaderId = 6001;
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 ffe0dad..ea1be28 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
@@ -1806,23 +1806,107 @@ TEST_F(GLES2DecoderTest2, ViewportInvalidArgs3_0) {
// TODO(gman): BlitFramebufferEXT
// TODO(gman): RenderbufferStorageMultisampleEXT
// TODO(gman): TexStorage2DEXT
-// TODO(gman): GenQueriesEXT
-// TODO(gman): DeleteQueriesEXT
+TEST_F(GLES2DecoderTest2, GenQueriesEXTValidArgs) {
+ EXPECT_CALL(*gl_, GenQueriesARB(1, _))
+ .WillOnce(SetArgumentPointee<1>(kNewServiceId));
+ GetSharedMemoryAs<GLuint*>()[0] = kNewClientId;
+ SpecializedSetup<GenQueriesEXT, 0>(true);
+ GenQueriesEXT cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(GetQueryInfo(kNewClientId) != NULL);
+}
-// TODO(gman): IsQueryEXT
+TEST_F(GLES2DecoderTest2, GenQueriesEXTInvalidArgs) {
+ EXPECT_CALL(*gl_, GenQueriesARB(_, _)).Times(0);
+ GetSharedMemoryAs<GLuint*>()[0] = client_query_id_;
+ SpecializedSetup<GenQueriesEXT, 0>(false);
+ GenQueriesEXT cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kInvalidArguments, ExecuteCmd(cmd));
+}
-// TODO(gman): BeginQueryEXT
+TEST_F(GLES2DecoderTest2, GenQueriesEXTImmediateValidArgs) {
+ EXPECT_CALL(*gl_, GenQueriesARB(1, _))
+ .WillOnce(SetArgumentPointee<1>(kNewServiceId));
+ GenQueriesEXTImmediate* cmd = GetImmediateAs<GenQueriesEXTImmediate>();
+ GLuint temp = kNewClientId;
+ SpecializedSetup<GenQueriesEXTImmediate, 0>(true);
+ cmd->Init(1, &temp);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(*cmd, sizeof(temp)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(GetQueryInfo(kNewClientId) != NULL);
+}
-// TODO(gman): EndQueryEXT
+TEST_F(GLES2DecoderTest2, GenQueriesEXTImmediateInvalidArgs) {
+ EXPECT_CALL(*gl_, GenQueriesARB(_, _)).Times(0);
+ GenQueriesEXTImmediate* cmd = GetImmediateAs<GenQueriesEXTImmediate>();
+ SpecializedSetup<GenQueriesEXTImmediate, 0>(false);
+ cmd->Init(1, &client_query_id_);
+ EXPECT_EQ(error::kInvalidArguments,
+ ExecuteImmediateCmd(*cmd, sizeof(&client_query_id_)));
+}
-// TODO(gman): GetQueryivEXT
+TEST_F(GLES2DecoderTest2, DeleteQueriesEXTValidArgs) {
+ EXPECT_CALL(
+ *gl_,
+ DeleteQueriesARB(1, Pointee(kServiceQueryId)))
+ .Times(1);
+ GetSharedMemoryAs<GLuint*>()[0] = client_query_id_;
+ SpecializedSetup<DeleteQueriesEXT, 0>(true);
+ DeleteQueriesEXT cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(
+ GetQueryInfo(client_query_id_) == NULL);
+}
-// TODO(gman): GetQueryObjectuivEXT
+TEST_F(GLES2DecoderTest2, DeleteQueriesEXTInvalidArgs) {
+ GetSharedMemoryAs<GLuint*>()[0] = kInvalidClientId;
+ SpecializedSetup<DeleteQueriesEXT, 0>(false);
+ DeleteQueriesEXT cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, DeleteQueriesEXTImmediateValidArgs) {
+ EXPECT_CALL(
+ *gl_,
+ DeleteQueriesARB(1, Pointee(kServiceQueryId)))
+ .Times(1);
+ DeleteQueriesEXTImmediate& cmd =
+ *GetImmediateAs<DeleteQueriesEXTImmediate>();
+ SpecializedSetup<DeleteQueriesEXTImmediate, 0>(true);
+ cmd.Init(1, &client_query_id_);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(client_query_id_)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(
+ GetQueryInfo(client_query_id_) == NULL);
+}
+
+TEST_F(GLES2DecoderTest2, DeleteQueriesEXTImmediateInvalidArgs) {
+ DeleteQueriesEXTImmediate& cmd =
+ *GetImmediateAs<DeleteQueriesEXTImmediate>();
+ SpecializedSetup<DeleteQueriesEXTImmediate, 0>(false);
+ GLuint temp = kInvalidClientId;
+ cmd.Init(1, &temp);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+}
+// TODO(gman): BeginQueryEXT
+
+// TODO(gman): EndQueryEXT
// TODO(gman): SwapBuffers
// TODO(gman): GetMaxValueInBufferCHROMIUM
// TODO(gman): GenSharedIdsCHROMIUM
+// TODO(gman): DeleteSharedIdsCHROMIUM
+
#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 bef7a9e..56f5195 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,8 +10,6 @@
#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): DeleteSharedIdsCHROMIUM
-
// TODO(gman): RegisterSharedIdsCHROMIUM
// TODO(gman): EnableFeatureCHROMIUM
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 ec5f1dd..7e44be7 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
@@ -44,7 +44,8 @@ GLES2DecoderTestBase::GLES2DecoderTestBase()
client_texture_id_(106),
client_element_buffer_id_(107),
client_vertex_shader_id_(121),
- client_fragment_shader_id_(122) {
+ client_fragment_shader_id_(122),
+ client_query_id_(123) {
memset(immediate_buffer_, 0xEE, sizeof(immediate_buffer_));
}
@@ -798,6 +799,7 @@ const GLuint GLES2DecoderTestBase::kServiceTextureId;
const GLuint GLES2DecoderTestBase::kServiceProgramId;
const GLuint GLES2DecoderTestBase::kServiceShaderId;
const GLuint GLES2DecoderTestBase::kServiceElementBufferId;
+const GLuint GLES2DecoderTestBase::kServiceQueryId;
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 7217a58..7dcdddb 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
@@ -14,6 +14,7 @@
#include "gpu/command_buffer/service/framebuffer_manager.h"
#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
#include "gpu/command_buffer/service/program_manager.h"
+#include "gpu/command_buffer/service/query_manager.h"
#include "gpu/command_buffer/service/renderbuffer_manager.h"
#include "gpu/command_buffer/service/shader_manager.h"
#include "gpu/command_buffer/service/texture_manager.h"
@@ -50,6 +51,7 @@ class GLES2DecoderTestBase : public testing::Test {
static const GLuint kServiceProgramId = 305;
static const GLuint kServiceShaderId = 306;
static const GLuint kServiceElementBufferId = 308;
+ static const GLuint kServiceQueryId = 309;
static const int32 kSharedMemoryId = 401;
static const size_t kSharedBufferSize = 2048;
@@ -193,16 +195,20 @@ class GLES2DecoderTestBase : public testing::Test {
return group_->renderbuffer_manager()->GetRenderbufferInfo(service_id);
}
- TextureManager::TextureInfo* GetTextureInfo(GLuint service_id) {
- return group_->texture_manager()->GetTextureInfo(service_id);
+ TextureManager::TextureInfo* GetTextureInfo(GLuint client_id) {
+ return group_->texture_manager()->GetTextureInfo(client_id);
}
- ShaderManager::ShaderInfo* GetShaderInfo(GLuint service_id) {
- return group_->shader_manager()->GetShaderInfo(service_id);
+ ShaderManager::ShaderInfo* GetShaderInfo(GLuint client_id) {
+ return group_->shader_manager()->GetShaderInfo(client_id);
}
- ProgramManager::ProgramInfo* GetProgramInfo(GLuint service_id) {
- return group_->program_manager()->GetProgramInfo(service_id);
+ ProgramManager::ProgramInfo* GetProgramInfo(GLuint client_id) {
+ return group_->program_manager()->GetProgramInfo(client_id);
+ }
+
+ QueryManager::Query* GetQueryInfo(GLuint client_id) {
+ return decoder_->GetQueryManager()->GetQuery(client_id);
}
ProgramManager* program_manager() {
@@ -414,6 +420,7 @@ class GLES2DecoderTestBase : public testing::Test {
GLuint client_element_buffer_id_;
GLuint client_vertex_shader_id_;
GLuint client_fragment_shader_id_;
+ GLuint client_query_id_;
uint32 shared_memory_id_;
uint32 shared_memory_offset_;
diff --git a/gpu/command_buffer/service/query_manager.cc b/gpu/command_buffer/service/query_manager.cc
new file mode 100644
index 0000000..08cecea
--- /dev/null
+++ b/gpu/command_buffer/service/query_manager.cc
@@ -0,0 +1,177 @@
+// 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/query_manager.h"
+#include "base/atomicops.h"
+#include "base/logging.h"
+#include "gpu/command_buffer/common/gles2_cmd_format.h"
+#include "gpu/command_buffer/service/common_decoder.h"
+
+namespace gpu {
+namespace gles2 {
+
+QueryManager::QueryManager()
+ : query_count_(0) {
+}
+
+QueryManager::~QueryManager() {
+ DCHECK(queries_.empty());
+
+ // If this triggers, that means something is keeping a reference to
+ // a Query belonging to this.
+ CHECK_EQ(query_count_, 0u);
+}
+
+void QueryManager::Destroy(bool have_context) {
+ pending_queries_.clear();
+ while (!queries_.empty()) {
+ Query* query = queries_.begin()->second;
+ if (have_context) {
+ if (!query->IsDeleted()) {
+ GLuint service_id = query->service_id();
+ glDeleteQueriesARB(1, &service_id);
+ query->MarkAsDeleted();
+ }
+ }
+ queries_.erase(queries_.begin());
+ }
+}
+
+QueryManager::Query* QueryManager::CreateQuery(
+ GLuint client_id,
+ GLuint service_id) {
+ Query::Ref query(new Query(this, service_id));
+ std::pair<QueryMap::iterator, bool> result =
+ queries_.insert(std::make_pair(client_id, query));
+ DCHECK(result.second);
+ return query.get();
+}
+
+QueryManager::Query* QueryManager::GetQuery(
+ GLuint client_id) {
+ QueryMap::iterator it = queries_.find(client_id);
+ return it != queries_.end() ? it->second : NULL;
+}
+
+void QueryManager::RemoveQuery(GLuint client_id) {
+ QueryMap::iterator it = queries_.find(client_id);
+ if (it != queries_.end()) {
+ Query* query = it->second;
+ RemovePendingQuery(query);
+ query->MarkAsDeleted();
+ queries_.erase(it);
+ }
+}
+
+void QueryManager::StartTracking(QueryManager::Query* /* query */) {
+ ++query_count_;
+}
+
+void QueryManager::StopTracking(QueryManager::Query* /* query */) {
+ --query_count_;
+}
+
+QueryManager::Query::Query(
+ QueryManager* manager,
+ GLuint service_id)
+ : manager_(manager),
+ service_id_(service_id),
+ target_(0),
+ shm_id_(0),
+ shm_offset_(0),
+ pending_(false) {
+ DCHECK(manager);
+ manager_->StartTracking(this);
+}
+
+QueryManager::Query::~Query() {
+ if (manager_) {
+ manager_->StopTracking(this);
+ manager_ = NULL;
+ }
+}
+
+void QueryManager::Query::Initialize(
+ GLenum target, int32 shm_id, uint32 shm_offset) {
+ DCHECK(!IsInitialized());
+ target_ = target;
+ shm_id_ = shm_id;
+ shm_offset_ = shm_offset;
+}
+
+bool QueryManager::GetClientId(GLuint service_id, GLuint* client_id) const {
+ DCHECK(client_id);
+ // This doesn't need to be fast. It's only used during slow queries.
+ for (QueryMap::const_iterator it = queries_.begin();
+ it != queries_.end(); ++it) {
+ if (it->second->service_id() == service_id) {
+ *client_id = it->first;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool QueryManager::ProcessPendingQueries(CommonDecoder* decoder) {
+ DCHECK(decoder);
+ while (!pending_queries_.empty()) {
+ Query* query = pending_queries_.front().get();
+ GLuint available = 0;
+ glGetQueryObjectuivARB(
+ query->service_id(), GL_QUERY_RESULT_AVAILABLE_EXT, &available);
+ if (!available) {
+ return true;
+ }
+ GLuint result = 0;
+ glGetQueryObjectuivARB(
+ query->service_id(), GL_QUERY_RESULT_EXT, &result);
+ QuerySync* sync = decoder->GetSharedMemoryAs<QuerySync*>(
+ query->shm_id(), query->shm_offset(), sizeof(*sync));
+ if (!sync) {
+ return false;
+ }
+
+ sync->result = result;
+ // Need a MemoryBarrier here so that sync->result is written before
+ // sync->process_count.
+ base::subtle::MemoryBarrier();
+ sync->process_count = query->submit_count();
+
+ query->MarkAsCompleted();
+ pending_queries_.pop_front();
+ }
+
+ return true;
+}
+
+void QueryManager::AddPendingQuery(Query* query, uint32 submit_count) {
+ DCHECK(query);
+ DCHECK(query->IsInitialized());
+ DCHECK(!query->IsDeleted());
+ RemovePendingQuery(query);
+ query->MarkAsPending(submit_count);
+ pending_queries_.push_back(query);
+}
+
+void QueryManager::RemovePendingQuery(Query* query) {
+ DCHECK(query);
+ if (query->pending()) {
+ // TODO(gman): Speed this up if this is a common operation. This would only
+ // happen if you do being/end begin/end on the same query without waiting
+ // for the first one to finish.
+ for (QueryQueue::iterator it = pending_queries_.begin();
+ it != pending_queries_.end(); ++it) {
+ if (it->get() == query) {
+ pending_queries_.erase(it);
+ break;
+ }
+ }
+ query->MarkAsCompleted();
+ }
+}
+
+} // namespace gles2
+} // namespace gpu
+
+
diff --git a/gpu/command_buffer/service/query_manager.h b/gpu/command_buffer/service/query_manager.h
new file mode 100644
index 0000000..8e9e46a
--- /dev/null
+++ b/gpu/command_buffer/service/query_manager.h
@@ -0,0 +1,163 @@
+// 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_QUERY_MANAGER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_QUERY_MANAGER_H_
+
+#include <deque>
+#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 {
+
+class CommonDecoder;
+
+namespace gles2 {
+
+// This class keeps track of the queries and their state
+// As Queries are not shared there is one QueryManager per context.
+class GPU_EXPORT QueryManager {
+ public:
+ class GPU_EXPORT Query : public base::RefCounted<Query> {
+ public:
+ typedef scoped_refptr<Query> Ref;
+
+ Query(QueryManager* manager, GLuint service_id);
+
+ void Initialize(GLenum target, int32 shm_id, uint32 shm_offset);
+
+ bool IsInitialized() const {
+ return target_ != 0;
+ }
+
+ GLuint service_id() const {
+ return service_id_;
+ }
+
+ GLenum target() const {
+ return target_;
+ }
+
+ bool IsDeleted() const {
+ return service_id_ == 0;
+ }
+
+ bool IsValid() const {
+ return target() && !IsDeleted();
+ }
+
+ int32 shm_id() const {
+ return shm_id_;
+ }
+
+ uint32 shm_offset() const {
+ return shm_offset_;
+ }
+
+ bool pending() const {
+ return pending_;
+ }
+
+ private:
+ friend class QueryManager;
+ friend class QueryManagerTest;
+ friend class base::RefCounted<Query>;
+
+ ~Query();
+
+ void MarkAsPending(uint32 submit_count) {
+ DCHECK(!pending_);
+ pending_ = true;
+ submit_count_ = submit_count;
+ }
+
+ void MarkAsCompleted() {
+ DCHECK(pending_);
+ pending_ = false;
+ }
+
+ uint32 submit_count() const {
+ return submit_count_;
+ }
+
+ void MarkAsDeleted() {
+ service_id_ = 0;
+ }
+
+ // The manager that owns this Query.
+ QueryManager* manager_;
+
+ // Service side query id.
+ GLuint service_id_;
+
+ // The type of query.
+ GLenum target_;
+
+ // The shared memory used with this Query.
+ int32 shm_id_;
+ uint32 shm_offset_;
+
+ // Count to set process count do when completed.
+ uint32 submit_count_;
+
+ // True if in the Queue.
+ bool pending_;
+ };
+
+ QueryManager();
+ ~QueryManager();
+
+ // Must call before destruction.
+ void Destroy(bool have_context);
+
+ // Creates a Query for the given query.
+ Query* CreateQuery(GLuint client_id, GLuint service_id);
+
+ // Gets the query info for the given query.
+ Query* GetQuery(GLuint client_id);
+
+ // Removes a query info for the given query.
+ void RemoveQuery(GLuint client_id);
+
+ // Gets a client id for a given service id.
+ bool GetClientId(GLuint service_id, GLuint* client_id) const;
+
+ // Adds to queue of queries waiting for completion.
+ void AddPendingQuery(Query* query, uint32 submit_count);
+
+ // Removes a query from the queue of pending queries.
+ void RemovePendingQuery(Query* query);
+
+ // Processes pending queries. Returns false if any queries are pointing
+ // to invalid shared memory.
+ bool ProcessPendingQueries(CommonDecoder* decoder);
+
+ private:
+ void StartTracking(Query* query);
+ void StopTracking(Query* query);
+
+ // Counts the number of Queries allocated with 'this' as their manager.
+ // Allows checking no Query will outlive this.
+ unsigned query_count_;
+
+ // Info for each query in the system.
+ typedef base::hash_map<GLuint, Query::Ref> QueryMap;
+ QueryMap queries_;
+
+ // Queries waiting for completion.
+ typedef std::deque<Query::Ref> QueryQueue;
+ QueryQueue pending_queries_;
+
+ DISALLOW_COPY_AND_ASSIGN(QueryManager);
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_QUERY_MANAGER_H_
diff --git a/gpu/command_buffer/service/query_manager_unittest.cc b/gpu/command_buffer/service/query_manager_unittest.cc
new file mode 100644
index 0000000..e230768
--- /dev/null
+++ b/gpu/command_buffer/service/query_manager_unittest.cc
@@ -0,0 +1,457 @@
+// 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/query_manager.h"
+#include "gpu/command_buffer/common/gl_mock.h"
+#include "gpu/command_buffer/common/gles2_cmd_format.h"
+#include "gpu/command_buffer/service/cmd_buffer_engine.h"
+#include "gpu/command_buffer/service/common_decoder.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+using ::testing::InSequence;
+using ::testing::SetArgumentPointee;
+
+namespace gpu {
+namespace gles2 {
+
+class MockDecoder : public CommonDecoder {
+ public:
+ virtual ~MockDecoder() { }
+ MOCK_METHOD3(DoCommand, error::Error(
+ unsigned int command,
+ unsigned int arg_count,
+ const void* cmd_data));
+ MOCK_CONST_METHOD1(GetCommandName, const char* (unsigned int command_id));
+};
+
+class QueryManagerTest : public testing::Test {
+ public:
+ static const int32 kSharedMemoryId = 401;
+ static const size_t kSharedBufferSize = 2048;
+ static const uint32 kSharedMemoryOffset = 132;
+ static const int32 kInvalidSharedMemoryId = 402;
+ static const uint32 kInvalidSharedMemoryOffset = kSharedBufferSize + 1;
+ static const uint32 kInitialResult = 0xBDBDBDBDu;
+ static const uint8 kInitialMemoryValue = 0xBDu;
+
+ QueryManagerTest() {
+ }
+ ~QueryManagerTest() {
+ }
+
+ protected:
+ virtual void SetUp() {
+ gl_.reset(new ::testing::StrictMock< ::gfx::MockGLInterface>());
+ ::gfx::GLInterface::SetGLInterface(gl_.get());
+ engine_.reset(new MockCommandBufferEngine());
+ decoder_.reset(new MockDecoder());
+ decoder_->set_engine(engine_.get());
+ manager_.reset(new QueryManager());
+ }
+
+ virtual void TearDown() {
+ decoder_.reset();
+ manager_->Destroy(false);
+ manager_.reset();
+ engine_.reset();
+ ::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<MockDecoder> decoder_;
+ scoped_ptr<QueryManager> manager_;
+
+ private:
+ class MockCommandBufferEngine : public CommandBufferEngine {
+ public:
+ MockCommandBufferEngine() {
+ data_.reset(new int8[kSharedBufferSize]);
+ ClearSharedMemory();
+ valid_buffer_.ptr = data_.get();
+ valid_buffer_.size = kSharedBufferSize;
+ }
+
+ virtual ~MockCommandBufferEngine() {
+ }
+
+ virtual Buffer GetSharedMemoryBuffer(int32 shm_id) OVERRIDE {
+ return shm_id == kSharedMemoryId ? valid_buffer_ : invalid_buffer_;
+ }
+
+ void ClearSharedMemory() {
+ memset(data_.get(), kInitialMemoryValue, kSharedBufferSize);
+ }
+
+ virtual void set_token(int32 token) OVERRIDE {
+ DCHECK(false);
+ }
+
+ virtual bool SetGetBuffer(int32 /* transfer_buffer_id */) OVERRIDE {
+ DCHECK(false);
+ return false;
+ }
+
+ // Overridden from CommandBufferEngine.
+ virtual bool SetGetOffset(int32 offset) OVERRIDE {
+ DCHECK(false);
+ return false;
+ }
+
+ // Overridden from CommandBufferEngine.
+ virtual int32 GetGetOffset() OVERRIDE {
+ DCHECK(false);
+ return 0;
+ }
+
+ private:
+ scoped_array<int8> data_;
+ Buffer valid_buffer_;
+ Buffer invalid_buffer_;
+ };
+
+ scoped_ptr<MockCommandBufferEngine> engine_;
+};
+
+// GCC requires these declarations, but MSVC requires they not be present
+#ifndef COMPILER_MSVC
+const int32 QueryManagerTest::kSharedMemoryId;
+const size_t QueryManagerTest::kSharedBufferSize;
+const uint32 QueryManagerTest::kSharedMemoryOffset;
+const int32 QueryManagerTest::kInvalidSharedMemoryId;
+const uint32 QueryManagerTest::kInvalidSharedMemoryOffset;
+const uint32 QueryManagerTest::kInitialResult;
+const uint8 QueryManagerTest::kInitialMemoryValue;
+#endif
+
+TEST_F(QueryManagerTest, Basic) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ const GLuint kClient2Id = 2;
+
+ // Check we can create a Query.
+ QueryManager::Query::Ref query(
+ manager_->CreateQuery(kClient1Id, kService1Id));
+ ASSERT_TRUE(query.get() != NULL);
+ // Check we can get the same Query.
+ EXPECT_EQ(query.get(), manager_->GetQuery(kClient1Id));
+ // Check we can get the client id.
+ GLuint client_id = -1;
+ EXPECT_TRUE(manager_->GetClientId(kService1Id, &client_id));
+ EXPECT_EQ(kClient1Id, client_id);
+ // Check we get nothing for a non-existent query.
+ EXPECT_TRUE(manager_->GetQuery(kClient2Id) == NULL);
+ // Check we can delete the query.
+ manager_->RemoveQuery(kClient1Id);
+ // Check we get nothing for a non-existent query.
+ EXPECT_TRUE(manager_->GetQuery(kClient1Id) == NULL);
+ // Check query is deleted
+ EXPECT_TRUE(query->IsDeleted());
+}
+
+TEST_F(QueryManagerTest, Destroy) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+
+ // Create Query.
+ QueryManager::Query::Ref query(
+ manager_->CreateQuery(kClient1Id, kService1Id));
+ ASSERT_TRUE(query.get() != NULL);
+ EXPECT_CALL(*gl_, DeleteQueriesARB(1, ::testing::Pointee(kService1Id)))
+ .Times(1)
+ .RetiresOnSaturation();
+ manager_->Destroy(true);
+ // Check we get nothing for a non-existent query.
+ EXPECT_TRUE(manager_->GetQuery(kClient1Id) == NULL);
+ // Check query is deleted
+ EXPECT_TRUE(query->IsDeleted());
+}
+
+TEST_F(QueryManagerTest, QueryBasic) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+
+ // Create Query.
+ QueryManager::Query::Ref query(
+ manager_->CreateQuery(kClient1Id, kService1Id));
+ ASSERT_TRUE(query.get() != NULL);
+
+ EXPECT_FALSE(query->IsValid());
+ EXPECT_FALSE(query->IsDeleted());
+ EXPECT_FALSE(query->IsInitialized());
+ EXPECT_FALSE(query->pending());
+}
+
+TEST_F(QueryManagerTest, QueryInitialize) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ const GLenum kTarget = GL_ANY_SAMPLES_PASSED_EXT;
+
+ // Create Query.
+ QueryManager::Query::Ref query(
+ manager_->CreateQuery(kClient1Id, kService1Id));
+ ASSERT_TRUE(query.get() != NULL);
+
+ query->Initialize(kTarget, kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(kTarget, query->target());
+ EXPECT_EQ(kSharedMemoryId, query->shm_id());
+ EXPECT_EQ(kSharedMemoryOffset, query->shm_offset());
+
+ EXPECT_TRUE(query->IsValid());
+ EXPECT_FALSE(query->IsDeleted());
+ EXPECT_TRUE(query->IsInitialized());
+ EXPECT_FALSE(query->pending());
+}
+
+TEST_F(QueryManagerTest, ProcessPendingQuery) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ const GLenum kTarget = GL_ANY_SAMPLES_PASSED_EXT;
+ const uint32 kSubmitCount = 123;
+ const GLuint kResult = 456;
+
+ // Check nothing happens if there are no pending queries.
+ EXPECT_TRUE(manager_->ProcessPendingQueries(decoder_.get()));
+
+ // Create Query.
+ QueryManager::Query::Ref query(
+ manager_->CreateQuery(kClient1Id, kService1Id));
+ ASSERT_TRUE(query.get() != NULL);
+ query->Initialize(kTarget, kSharedMemoryId, kSharedMemoryOffset);
+
+ // Setup shared memory like client would.
+ QuerySync* sync = decoder_->GetSharedMemoryAs<QuerySync*>(
+ kSharedMemoryId, kSharedMemoryOffset, sizeof(*sync));
+ ASSERT_TRUE(sync != NULL);
+ sync->Reset();
+
+ // Queue it
+ manager_->AddPendingQuery(query.get(), kSubmitCount);
+ EXPECT_TRUE(query->pending());
+
+ // Process with return not available.
+ // Expect 1 GL command.
+ EXPECT_CALL(*gl_,
+ GetQueryObjectuivARB(kService1Id, GL_QUERY_RESULT_AVAILABLE_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(0))
+ .RetiresOnSaturation();
+ EXPECT_TRUE(manager_->ProcessPendingQueries(decoder_.get()));
+ EXPECT_TRUE(query->pending());
+ EXPECT_EQ(0u, sync->process_count);
+ EXPECT_EQ(0u, sync->result);
+
+ // Process with return available.
+ // Expect 2 GL commands.
+ EXPECT_CALL(*gl_,
+ GetQueryObjectuivARB(kService1Id, GL_QUERY_RESULT_AVAILABLE_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(1))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_,
+ GetQueryObjectuivARB(kService1Id, GL_QUERY_RESULT_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(kResult))
+ .RetiresOnSaturation();
+ EXPECT_TRUE(manager_->ProcessPendingQueries(decoder_.get()));
+ EXPECT_FALSE(query->pending());
+ EXPECT_EQ(kSubmitCount, sync->process_count);
+ EXPECT_EQ(kResult, sync->result);
+
+ // Process with no queries.
+ // Expect no GL commands/
+ EXPECT_TRUE(manager_->ProcessPendingQueries(decoder_.get()));
+}
+
+TEST_F(QueryManagerTest, ProcessPendingQueries) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ const GLuint kClient2Id = 2;
+ const GLuint kService2Id = 12;
+ const GLuint kClient3Id = 3;
+ const GLuint kService3Id = 13;
+ const GLenum kTarget = GL_ANY_SAMPLES_PASSED_EXT;
+ const uint32 kSubmitCount1 = 123;
+ const uint32 kSubmitCount2 = 123;
+ const uint32 kSubmitCount3 = 123;
+ const GLuint kResult1 = 456;
+ const GLuint kResult2 = 457;
+ const GLuint kResult3 = 458;
+
+ // Create Queries.
+ QueryManager::Query::Ref query1(
+ manager_->CreateQuery(kClient1Id, kService1Id));
+ QueryManager::Query::Ref query2(
+ manager_->CreateQuery(kClient2Id, kService2Id));
+ QueryManager::Query::Ref query3(
+ manager_->CreateQuery(kClient3Id, kService3Id));
+ ASSERT_TRUE(query1.get() != NULL);
+ ASSERT_TRUE(query2.get() != NULL);
+ ASSERT_TRUE(query3.get() != NULL);
+
+ // Setup shared memory like client would.
+ QuerySync* sync1 = decoder_->GetSharedMemoryAs<QuerySync*>(
+ kSharedMemoryId, kSharedMemoryOffset, sizeof(*sync1) * 3);
+ ASSERT_TRUE(sync1 != NULL);
+ QuerySync* sync2 = sync1 + 1;
+ QuerySync* sync3 = sync2 + 1;
+
+ sync1->Reset();
+ sync2->Reset();
+ sync3->Reset();
+
+ query1->Initialize(kTarget, kSharedMemoryId, kSharedMemoryOffset);
+ query2->Initialize(kTarget, kSharedMemoryId,
+ kSharedMemoryOffset + sizeof(*sync1));
+ query3->Initialize(kTarget, kSharedMemoryId,
+ kSharedMemoryOffset + sizeof(*sync1) * 2);
+
+ // Queue them
+ manager_->AddPendingQuery(query1.get(), kSubmitCount1);
+ manager_->AddPendingQuery(query2.get(), kSubmitCount2);
+ manager_->AddPendingQuery(query3.get(), kSubmitCount3);
+ EXPECT_TRUE(query1->pending());
+ EXPECT_TRUE(query2->pending());
+ EXPECT_TRUE(query3->pending());
+
+ // Process with return available for first 2 queries.
+ // Expect 4 GL commands.
+ {
+ InSequence s;
+ EXPECT_CALL(*gl_,
+ GetQueryObjectuivARB(kService1Id, GL_QUERY_RESULT_AVAILABLE_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(1))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_,
+ GetQueryObjectuivARB(kService1Id, GL_QUERY_RESULT_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(kResult1))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_,
+ GetQueryObjectuivARB(kService2Id, GL_QUERY_RESULT_AVAILABLE_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(1))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_,
+ GetQueryObjectuivARB(kService2Id, GL_QUERY_RESULT_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(kResult2))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_,
+ GetQueryObjectuivARB(kService3Id, GL_QUERY_RESULT_AVAILABLE_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(0))
+ .RetiresOnSaturation();
+ EXPECT_TRUE(manager_->ProcessPendingQueries(decoder_.get()));
+ }
+ EXPECT_FALSE(query1->pending());
+ EXPECT_FALSE(query2->pending());
+ EXPECT_TRUE(query3->pending());
+ EXPECT_EQ(kSubmitCount1, sync1->process_count);
+ EXPECT_EQ(kSubmitCount2, sync2->process_count);
+ EXPECT_EQ(kResult1, sync1->result);
+ EXPECT_EQ(kResult2, sync2->result);
+ EXPECT_EQ(0u, sync3->process_count);
+ EXPECT_EQ(0u, sync3->result);
+
+ // Process with renaming query. No result.
+ // Expect 1 GL commands.
+ EXPECT_CALL(*gl_,
+ GetQueryObjectuivARB(kService3Id, GL_QUERY_RESULT_AVAILABLE_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(0))
+ .RetiresOnSaturation();
+ EXPECT_TRUE(manager_->ProcessPendingQueries(decoder_.get()));
+ EXPECT_TRUE(query3->pending());
+ EXPECT_EQ(0u, sync3->process_count);
+ EXPECT_EQ(0u, sync3->result);
+
+ // Process with renaming query. With result.
+ // Expect 2 GL commands.
+ EXPECT_CALL(*gl_,
+ GetQueryObjectuivARB(kService3Id, GL_QUERY_RESULT_AVAILABLE_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(1))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_,
+ GetQueryObjectuivARB(kService3Id, GL_QUERY_RESULT_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(kResult3))
+ .RetiresOnSaturation();
+ EXPECT_TRUE(manager_->ProcessPendingQueries(decoder_.get()));
+ EXPECT_FALSE(query3->pending());
+ EXPECT_EQ(kSubmitCount3, sync3->process_count);
+ EXPECT_EQ(kResult3, sync3->result);
+}
+
+TEST_F(QueryManagerTest, ProcessPendingBadSharedMemoryId) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ const GLenum kTarget = GL_ANY_SAMPLES_PASSED_EXT;
+ const uint32 kSubmitCount = 123;
+ const GLuint kResult = 456;
+
+ // Create Query.
+ QueryManager::Query::Ref query(
+ manager_->CreateQuery(kClient1Id, kService1Id));
+ ASSERT_TRUE(query.get() != NULL);
+ query->Initialize(kTarget, kInvalidSharedMemoryId, kSharedMemoryOffset);
+
+ // Queue it
+ manager_->AddPendingQuery(query.get(), kSubmitCount);
+
+ // Process with return available.
+ // Expect 2 GL commands.
+ EXPECT_CALL(*gl_,
+ GetQueryObjectuivARB(kService1Id, GL_QUERY_RESULT_AVAILABLE_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(1))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_,
+ GetQueryObjectuivARB(kService1Id, GL_QUERY_RESULT_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(kResult))
+ .RetiresOnSaturation();
+ EXPECT_FALSE(manager_->ProcessPendingQueries(decoder_.get()));
+}
+
+TEST_F(QueryManagerTest, ProcessPendingBadSharedMemoryOffset) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ const GLenum kTarget = GL_ANY_SAMPLES_PASSED_EXT;
+ const uint32 kSubmitCount = 123;
+ const GLuint kResult = 456;
+
+ // Create Query.
+ QueryManager::Query::Ref query(
+ manager_->CreateQuery(kClient1Id, kService1Id));
+ ASSERT_TRUE(query.get() != NULL);
+ query->Initialize(kTarget, kSharedMemoryId, kInvalidSharedMemoryOffset);
+
+ // Queue it
+ manager_->AddPendingQuery(query.get(), kSubmitCount);
+
+ // Process with return available.
+ // Expect 2 GL commands.
+ EXPECT_CALL(*gl_,
+ GetQueryObjectuivARB(kService1Id, GL_QUERY_RESULT_AVAILABLE_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(1))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_,
+ GetQueryObjectuivARB(kService1Id, GL_QUERY_RESULT_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(kResult))
+ .RetiresOnSaturation();
+ EXPECT_FALSE(manager_->ProcessPendingQueries(decoder_.get()));
+}
+
+TEST_F(QueryManagerTest, ExitWithPendingQuery) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ const GLenum kTarget = GL_ANY_SAMPLES_PASSED_EXT;
+ const uint32 kSubmitCount = 123;
+
+ // Create Query.
+ QueryManager::Query::Ref query(
+ manager_->CreateQuery(kClient1Id, kService1Id));
+ ASSERT_TRUE(query.get() != NULL);
+ query->Initialize(kTarget, kSharedMemoryId, kSharedMemoryOffset);
+
+ // Queue it
+ manager_->AddPendingQuery(query.get(), kSubmitCount);
+}
+
+} // namespace gles2
+} // namespace gpu
+
+
diff --git a/gpu/command_buffer_client.gypi b/gpu/command_buffer_client.gypi
index c0447ef..f49d780 100644
--- a/gpu/command_buffer_client.gypi
+++ b/gpu/command_buffer_client.gypi
@@ -20,6 +20,8 @@
'command_buffer/client/fenced_allocator.h',
'command_buffer/client/mapped_memory.cc',
'command_buffer/client/mapped_memory.h',
+ 'command_buffer/client/query_tracker.cc',
+ 'command_buffer/client/query_tracker.h',
'command_buffer/client/ring_buffer.cc',
'command_buffer/client/ring_buffer.h',
'command_buffer/client/transfer_buffer.cc',
diff --git a/gpu/command_buffer_service.gypi b/gpu/command_buffer_service.gypi
index 9bb7dae..ae3d569 100644
--- a/gpu/command_buffer_service.gypi
+++ b/gpu/command_buffer_service.gypi
@@ -54,6 +54,8 @@
'command_buffer/service/mocks.h',
'command_buffer/service/program_manager.h',
'command_buffer/service/program_manager.cc',
+ 'command_buffer/service/query_manager.h',
+ 'command_buffer/service/query_manager.cc',
'command_buffer/service/renderbuffer_manager.h',
'command_buffer/service/renderbuffer_manager.cc',
'command_buffer/service/shader_manager.h',
diff --git a/gpu/gpu_common.gypi b/gpu/gpu_common.gypi
index 43209be..fb2f270 100644
--- a/gpu/gpu_common.gypi
+++ b/gpu/gpu_common.gypi
@@ -143,6 +143,7 @@
'command_buffer/client/fenced_allocator_test.cc',
'command_buffer/client/gles2_implementation_unittest.cc',
'command_buffer/client/mapped_memory_unittest.cc',
+ 'command_buffer/client/query_tracker_unittest.cc',
'command_buffer/client/program_info_manager_unittest.cc',
'command_buffer/client/ring_buffer_test.cc',
'command_buffer/client/transfer_buffer_unittest.cc',
@@ -176,6 +177,7 @@
'command_buffer/service/mocks.cc',
'command_buffer/service/mocks.h',
'command_buffer/service/program_manager_unittest.cc',
+ 'command_buffer/service/query_manager_unittest.cc',
'command_buffer/service/renderbuffer_manager_unittest.cc',
'command_buffer/service/shader_manager_unittest.cc',
'command_buffer/service/shader_translator_unittest.cc',
diff --git a/ppapi/native_client/src/shared/ppapi_proxy/nacl.scons b/ppapi/native_client/src/shared/ppapi_proxy/nacl.scons
index 9fb03c4..a58528e 100644
--- a/ppapi/native_client/src/shared/ppapi_proxy/nacl.scons
+++ b/ppapi/native_client/src/shared/ppapi_proxy/nacl.scons
@@ -34,6 +34,7 @@ command_buffer_client_srcs = [
'command_buffer/client/program_info_manager.cc',
'command_buffer/client/gles2_lib.cc',
'command_buffer/client/mapped_memory.cc',
+ 'command_buffer/client/query_tracker.cc',
'command_buffer/client/ring_buffer.cc',
'command_buffer/client/transfer_buffer.cc',
'command_buffer/common/id_allocator.cc',
diff --git a/ppapi/native_client/src/shared/ppapi_proxy/ppapi_proxy_untrusted.gyp b/ppapi/native_client/src/shared/ppapi_proxy/ppapi_proxy_untrusted.gyp
index 952fec0..f144eb2 100644
--- a/ppapi/native_client/src/shared/ppapi_proxy/ppapi_proxy_untrusted.gyp
+++ b/ppapi/native_client/src/shared/ppapi_proxy/ppapi_proxy_untrusted.gyp
@@ -37,6 +37,7 @@
'<(DEPTH)/gpu/command_buffer/client/transfer_buffer.cc',
'<(DEPTH)/gpu/command_buffer/client/gles2_lib.cc',
'<(DEPTH)/gpu/command_buffer/client/mapped_memory.cc',
+ '<(DEPTH)/gpu/command_buffer/client/query_tracker.cc',
'<(DEPTH)/gpu/command_buffer/client/ring_buffer.cc',
'<(DEPTH)/gpu/command_buffer/common/id_allocator.cc',
diff --git a/ui/gfx/gl/generate_bindings.py b/ui/gfx/gl/generate_bindings.py
index 2a255c7..ed80602 100755
--- a/ui/gfx/gl/generate_bindings.py
+++ b/ui/gfx/gl/generate_bindings.py
@@ -18,7 +18,10 @@ GL_FUNCTIONS = [
'names': ['glAttachShader'],
'arguments': 'GLuint program, GLuint shader', },
{ 'return_type': 'void',
- 'names': ['glBeginQuery', 'glBeginQueryEXT', 'glBeginQueryARB'],
+ 'names': ['glBeginQuery'],
+ 'arguments': 'GLenum target, GLuint id', },
+{ 'return_type': 'void',
+ 'names': ['glBeginQueryARB', 'glBeginQueryEXT'],
'arguments': 'GLenum target, GLuint id', },
{ 'return_type': 'void',
'names': ['glBindAttribLocation'],
@@ -134,7 +137,7 @@ GL_FUNCTIONS = [
'names': ['glCullFace'],
'arguments': 'GLenum mode', },
{ 'return_type': 'void',
- 'names': ['glDeleteBuffersARB', 'glDeleteBuffers', 'glDeleteQueriesEXT'],
+ 'names': ['glDeleteBuffersARB', 'glDeleteBuffers'],
'arguments': 'GLsizei n, const GLuint* buffers', },
{ 'return_type': 'void',
'names': ['glDeleteFramebuffersEXT', 'glDeleteFramebuffers'],
@@ -146,6 +149,9 @@ GL_FUNCTIONS = [
'names': ['glDeleteQueries'],
'arguments': 'GLsizei n, const GLuint* ids', },
{ 'return_type': 'void',
+ 'names': ['glDeleteQueriesARB', 'glDeleteQueriesEXT'],
+ 'arguments': 'GLsizei n, const GLuint* ids', },
+{ 'return_type': 'void',
'names': ['glDeleteRenderbuffersEXT', 'glDeleteRenderbuffers'],
'arguments': 'GLsizei n, const GLuint* renderbuffers', },
{ 'return_type': 'void',
@@ -201,7 +207,10 @@ GL_FUNCTIONS = [
'names': ['glEnableVertexAttribArray'],
'arguments': 'GLuint index', },
{ 'return_type': 'void',
- 'names': ['glEndQuery', 'glEndQueryARB', 'glEndQueryEXT'],
+ 'names': ['glEndQuery'],
+ 'arguments': 'GLenum target', },
+{ 'return_type': 'void',
+ 'names': ['glEndQueryARB', 'glEndQueryEXT'],
'arguments': 'GLenum target', },
{ 'return_type': 'void',
'names': ['glFinish'],
@@ -226,7 +235,10 @@ GL_FUNCTIONS = [
'names': ['glGenBuffersARB', 'glGenBuffers'],
'arguments': 'GLsizei n, GLuint* buffers', },
{ 'return_type': 'void',
- 'names': ['glGenQueries', 'glGenQueriesARB', 'glGenQueriesEXT'],
+ 'names': ['glGenQueries'],
+ 'arguments': 'GLsizei n, GLuint* ids', },
+{ 'return_type': 'void',
+ 'names': ['glGenQueriesARB', 'glGenQueriesEXT'],
'arguments': 'GLsizei n, GLuint* ids', },
{ 'return_type': 'void',
'names': ['glGenerateMipmapEXT', 'glGenerateMipmap'],
@@ -291,7 +303,10 @@ GL_FUNCTIONS = [
'arguments':
'GLuint program, GLsizei bufsize, GLsizei* length, char* infolog', },
{ 'return_type': 'void',
- 'names': ['glGetQueryiv', 'glGetQueryivARB', 'glGetQueryivEXT'],
+ 'names': ['glGetQueryiv'],
+ 'arguments': 'GLenum target, GLenum pname, GLint* params', },
+{ 'return_type': 'void',
+ 'names': ['glGetQueryivARB', 'glGetQueryivEXT'],
'arguments': 'GLenum target, GLenum pname, GLint* params', },
{ 'return_type': 'void',
'names': ['glGetQueryObjecti64v'],
@@ -303,8 +318,10 @@ GL_FUNCTIONS = [
'names': ['glGetQueryObjectui64v'],
'arguments': 'GLuint id, GLenum pname, GLuint64* params', },
{ 'return_type': 'void',
- 'names': ['glGetQueryObjectuiv', 'glGetQueryObjectuivARB',
- 'glGetQueryObjectuivEXT'],
+ 'names': ['glGetQueryObjectuiv'],
+ 'arguments': 'GLuint id, GLenum pname, GLuint* params', },
+{ 'return_type': 'void',
+ 'names': ['glGetQueryObjectuivARB', 'glGetQueryObjectuivEXT'],
'arguments': 'GLuint id, GLenum pname, GLuint* params', },
{ 'return_type': 'void',
'names': ['glGetRenderbufferParameterivEXT', 'glGetRenderbufferParameteriv'],
@@ -377,6 +394,9 @@ GL_FUNCTIONS = [
'names': ['glIsProgram'],
'arguments': 'GLuint program', },
{ 'return_type': 'GLboolean',
+ 'names': ['glIsQueryARB', 'glIsQueryEXT'],
+ 'arguments': 'GLuint query', },
+{ 'return_type': 'GLboolean',
'names': ['glIsRenderbufferEXT', 'glIsRenderbuffer'],
'arguments': 'GLuint renderbuffer', },
{ 'return_type': 'GLboolean',
diff --git a/ui/gfx/gl/gl_interface.h b/ui/gfx/gl/gl_interface.h
index 684f9b3..e5f1b46 100644
--- a/ui/gfx/gl/gl_interface.h
+++ b/ui/gfx/gl/gl_interface.h
@@ -30,6 +30,8 @@ class GL_EXPORT GLInterface {
virtual void BeginQuery(GLenum target, GLuint id) = 0;
+ virtual void BeginQueryARB(GLenum target, GLuint id) = 0;
+
virtual void BindAttribLocation(GLuint program,
GLuint index,
const char* name) = 0;
@@ -156,6 +158,8 @@ class GL_EXPORT GLInterface {
virtual void DeleteQueries(GLsizei n, const GLuint* ids) = 0;
+ virtual void DeleteQueriesARB(GLsizei n, const GLuint* ids) = 0;
+
virtual void DeleteShader(GLuint shader) = 0;
virtual void DeleteTextures(GLsizei n, const GLuint* textures) = 0;
@@ -197,6 +201,8 @@ class GL_EXPORT GLInterface {
virtual void EndQuery(GLenum target) = 0;
+ virtual void EndQueryARB(GLenum target) = 0;
+
virtual void Finish() = 0;
virtual void Flush() = 0;
@@ -222,6 +228,8 @@ class GL_EXPORT GLInterface {
virtual void GenQueries(GLsizei n, GLuint* ids) = 0;
+ virtual void GenQueriesARB(GLsizei n, GLuint* ids) = 0;
+
virtual void GenRenderbuffersEXT(GLsizei n, GLuint* renderbuffers) = 0;
virtual void GenTextures(GLsizei n, GLuint* textures) = 0;
@@ -276,6 +284,8 @@ class GL_EXPORT GLInterface {
virtual void GetQueryiv(GLenum target, GLenum pname, GLint* params) = 0;
+ virtual void GetQueryivARB(GLenum target, GLenum pname, GLint* params) = 0;
+
virtual void GetQueryObjecti64v(GLuint id, GLenum pname, GLint64* params) = 0;
virtual void GetQueryObjectiv(GLuint id, GLenum pname, GLint* params) = 0;
@@ -286,6 +296,10 @@ class GL_EXPORT GLInterface {
virtual void GetQueryObjectuiv(GLuint id, GLenum pname, GLuint* params) = 0;
+ virtual void GetQueryObjectuivARB(GLuint id,
+ GLenum pname,
+ GLuint* params) = 0;
+
virtual void GetRenderbufferParameterivEXT(GLenum target,
GLenum pname,
GLint* params) = 0;
@@ -366,6 +380,8 @@ class GL_EXPORT GLInterface {
virtual GLboolean IsProgram(GLuint program) = 0;
+ virtual GLboolean IsQueryARB(GLuint query) = 0;
+
virtual GLboolean IsRenderbufferEXT(GLuint renderbuffer) = 0;
virtual GLboolean IsShader(GLuint shader) = 0;