summaryrefslogtreecommitdiffstats
path: root/gpu
diff options
context:
space:
mode:
authordyen <dyen@chromium.org>2015-07-24 18:18:38 -0700
committerCommit bot <commit-bot@chromium.org>2015-07-25 01:19:44 +0000
commitb245d37d309cfeb073fc8eb97c9b6c0945631ffc (patch)
treebe7796905480ca8dfd4c2ba239dfb6f8f9a9935d /gpu
parentf43a534aa12f2ceeb8c92d57021e65ab8d9e7f0d (diff)
downloadchromium_src-b245d37d309cfeb073fc8eb97c9b6c0945631ffc.zip
chromium_src-b245d37d309cfeb073fc8eb97c9b6c0945631ffc.tar.gz
chromium_src-b245d37d309cfeb073fc8eb97c9b6c0945631ffc.tar.bz2
Added support for pausing and resuming queries.
When using virtual contexts, queries need to be paused and resumed so that they do not interfere with other contexts. Because the handling of this is very dependent on the query that is being paused/resumed, this must be done at the query level. Note that this is mainly for occlusion queries. Time queries are already virtualized through gpu_timing and support multiple queries at once. BUG=509896, 345227 TEST=Added unit test which tests queries within 2 contexts. Review URL: https://codereview.chromium.org/1241443005 Cr-Commit-Position: refs/heads/master@{#340390}
Diffstat (limited to 'gpu')
-rw-r--r--gpu/command_buffer/service/async_pixel_transfer_manager_egl.cc4
-rw-r--r--gpu/command_buffer/service/context_state.h6
-rw-r--r--gpu/command_buffer/service/gl_state_restorer_impl.cc12
-rw-r--r--gpu/command_buffer/service/gl_state_restorer_impl.h2
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.cc19
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc22
-rw-r--r--gpu/command_buffer/service/query_manager.cc239
-rw-r--r--gpu/command_buffer/service/query_manager.h66
-rw-r--r--gpu/command_buffer/service/query_manager_unittest.cc229
-rw-r--r--gpu/command_buffer/tests/gl_virtual_contexts_unittest.cc61
10 files changed, 539 insertions, 121 deletions
diff --git a/gpu/command_buffer/service/async_pixel_transfer_manager_egl.cc b/gpu/command_buffer/service/async_pixel_transfer_manager_egl.cc
index 6e1c3e7..2cf8b01 100644
--- a/gpu/command_buffer/service/async_pixel_transfer_manager_egl.cc
+++ b/gpu/command_buffer/service/async_pixel_transfer_manager_egl.cc
@@ -688,6 +688,10 @@ void AsyncPixelTransferManagerEGL::BindCompletedAsyncTransfers() {
void AsyncPixelTransferManagerEGL::AsyncNotifyCompletion(
const AsyncMemoryParams& mem_params,
AsyncPixelTransferCompletionObserver* observer) {
+ if (shared_state_.pending_allocations.empty()) {
+ observer->DidComplete(mem_params);
+ return;
+ }
// Post a PerformNotifyCompletion task to the upload thread. This task
// will run after all async transfers are complete.
transfer_task_runner()->PostTask(
diff --git a/gpu/command_buffer/service/context_state.h b/gpu/command_buffer/service/context_state.h
index 88c9423..f07c83c 100644
--- a/gpu/command_buffer/service/context_state.h
+++ b/gpu/command_buffer/service/context_state.h
@@ -11,7 +11,6 @@
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "gpu/command_buffer/service/gl_utils.h"
-#include "gpu/command_buffer/service/query_manager.h"
#include "gpu/command_buffer/service/texture_manager.h"
#include "gpu/command_buffer/service/valuebuffer_manager.h"
#include "gpu/command_buffer/service/vertex_attrib_manager.h"
@@ -26,6 +25,7 @@ class ErrorState;
class ErrorStateClient;
class FeatureInfo;
class Framebuffer;
+class Logger;
class Program;
class Renderbuffer;
@@ -274,10 +274,6 @@ struct GPU_EXPORT ContextState {
// The currently bound valuebuffer
scoped_refptr<Valuebuffer> bound_valuebuffer;
- // A map of of target -> Query for current queries
- typedef std::map<GLuint, scoped_refptr<QueryManager::Query> > QueryMap;
- QueryMap current_queries;
-
bool pack_reverse_row_order;
bool ignore_cached_state;
diff --git a/gpu/command_buffer/service/gl_state_restorer_impl.cc b/gpu/command_buffer/service/gl_state_restorer_impl.cc
index 5fbd425f..c132ef8 100644
--- a/gpu/command_buffer/service/gl_state_restorer_impl.cc
+++ b/gpu/command_buffer/service/gl_state_restorer_impl.cc
@@ -5,6 +5,7 @@
#include "gpu/command_buffer/service/gl_state_restorer_impl.h"
#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "gpu/command_buffer/service/query_manager.h"
namespace gpu {
@@ -25,6 +26,7 @@ void GLStateRestorerImpl::RestoreState(const gfx::GLStateRestorer* prev_state) {
DCHECK(decoder_.get());
const GLStateRestorerImpl* restorer_impl =
static_cast<const GLStateRestorerImpl*>(prev_state);
+
decoder_->RestoreState(
restorer_impl ? restorer_impl->GetContextState() : NULL);
}
@@ -44,6 +46,16 @@ void GLStateRestorerImpl::RestoreFramebufferBindings() {
decoder_->RestoreFramebufferBindings();
}
+void GLStateRestorerImpl::PauseQueries() {
+ DCHECK(decoder_.get());
+ decoder_->GetQueryManager()->PauseQueries();
+}
+
+void GLStateRestorerImpl::ResumeQueries() {
+ DCHECK(decoder_.get());
+ decoder_->GetQueryManager()->ResumeQueries();
+}
+
const gles2::ContextState* GLStateRestorerImpl::GetContextState() const {
DCHECK(decoder_.get());
return decoder_->GetContextState();
diff --git a/gpu/command_buffer/service/gl_state_restorer_impl.h b/gpu/command_buffer/service/gl_state_restorer_impl.h
index 91d3408..d9c4181 100644
--- a/gpu/command_buffer/service/gl_state_restorer_impl.h
+++ b/gpu/command_buffer/service/gl_state_restorer_impl.h
@@ -29,6 +29,8 @@ class GPU_EXPORT GLStateRestorerImpl : public gfx::GLStateRestorer {
void RestoreAllTextureUnitBindings() override;
void RestoreActiveTextureUnitBinding(unsigned int target) override;
void RestoreFramebufferBindings() override;
+ void PauseQueries() override;
+ void ResumeQueries() override;
private:
const gles2::ContextState* GetContextState() const;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 712e9241..019879b 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -3924,7 +3924,6 @@ void GLES2DecoderImpl::Destroy(bool have_context) {
state_.bound_pixel_unpack_buffer = NULL;
state_.bound_transform_feedback_buffer = NULL;
state_.bound_uniform_buffer = NULL;
- state_.current_queries.clear();
framebuffer_state_.bound_read_framebuffer = NULL;
framebuffer_state_.bound_draw_framebuffer = NULL;
state_.bound_renderbuffer = NULL;
@@ -11530,15 +11529,6 @@ bool GLES2DecoderImpl::GenQueriesEXTHelper(
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()) {
- ContextState::QueryMap::iterator it =
- state_.current_queries.find(query->target());
- if (it != state_.current_queries.end())
- state_.current_queries.erase(it);
-
- query->Destroy(true);
- }
query_manager_->RemoveQuery(client_ids[ii]);
}
}
@@ -11661,7 +11651,7 @@ error::Error GLES2DecoderImpl::HandleBeginQueryEXT(uint32 immediate_data_size,
return error::kNoError;
}
- if (state_.current_queries.find(target) != state_.current_queries.end()) {
+ if (query_manager_->GetActiveQuery(target)) {
#if defined(OS_MACOSX)
// TODO(dyen): Remove once we know what is failing.
CHECK(target != GL_COMMANDS_COMPLETED_CHROMIUM)
@@ -11715,7 +11705,6 @@ error::Error GLES2DecoderImpl::HandleBeginQueryEXT(uint32 immediate_data_size,
return error::kOutOfBounds;
}
- state_.current_queries[target] = query;
return error::kNoError;
}
@@ -11725,22 +11714,20 @@ error::Error GLES2DecoderImpl::HandleEndQueryEXT(uint32 immediate_data_size,
*static_cast<const gles2::cmds::EndQueryEXT*>(cmd_data);
GLenum target = static_cast<GLenum>(c.target);
uint32 submit_count = static_cast<GLuint>(c.submit_count);
- ContextState::QueryMap::iterator it = state_.current_queries.find(target);
- if (it == state_.current_queries.end()) {
+ QueryManager::Query* query = query_manager_->GetActiveQuery(target);
+ if (!query) {
LOCAL_SET_GL_ERROR(
GL_INVALID_OPERATION, "glEndQueryEXT", "No active query");
return error::kNoError;
}
- QueryManager::Query* query = it->second.get();
if (!query_manager_->EndQuery(query, submit_count)) {
return error::kOutOfBounds;
}
query_manager_->ProcessPendingTransferQueries();
- state_.current_queries.erase(it);
return error::kNoError;
}
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
index 162eb6a..2dfb1090 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
@@ -538,7 +538,7 @@ TEST_P(GLES2DecoderManualInitTest, BeginEndQueryEXT) {
// After BeginQueriesEXT id name should have query object associated with it.
query = query_manager->GetQuery(kNewClientId);
ASSERT_TRUE(query != NULL);
- EXPECT_FALSE(query->pending());
+ EXPECT_FALSE(query->IsPending());
// Test trying begin again fails
EXPECT_EQ(error::kNoError, ExecuteCmd(begin_cmd));
@@ -556,7 +556,7 @@ TEST_P(GLES2DecoderManualInitTest, BeginEndQueryEXT) {
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_TRUE(query->IsPending());
EXPECT_CALL(*gl_, DeleteQueries(1, _)).Times(1).RetiresOnSaturation();
}
@@ -859,14 +859,14 @@ TEST_P(GLES2DecoderTest, BeginEndQueryEXTCommandsIssuedCHROMIUM) {
ASSERT_TRUE(query_manager != NULL);
QueryManager::Query* query = query_manager->GetQuery(kNewClientId);
ASSERT_TRUE(query != NULL);
- EXPECT_FALSE(query->pending());
+ EXPECT_FALSE(query->IsPending());
// Test end succeeds
EndQueryEXT end_cmd;
end_cmd.Init(GL_COMMANDS_ISSUED_CHROMIUM, 1);
EXPECT_EQ(error::kNoError, ExecuteCmd(end_cmd));
EXPECT_EQ(GL_NO_ERROR, GetGLError());
- EXPECT_FALSE(query->pending());
+ EXPECT_FALSE(query->IsPending());
}
TEST_P(GLES2DecoderTest, BeginEndQueryEXTGetErrorQueryCHROMIUM) {
@@ -886,7 +886,7 @@ TEST_P(GLES2DecoderTest, BeginEndQueryEXTGetErrorQueryCHROMIUM) {
ASSERT_TRUE(query_manager != NULL);
QueryManager::Query* query = query_manager->GetQuery(kNewClientId);
ASSERT_TRUE(query != NULL);
- EXPECT_FALSE(query->pending());
+ EXPECT_FALSE(query->IsPending());
// Test end succeeds
QuerySync* sync = static_cast<QuerySync*>(shared_memory_address_);
@@ -899,7 +899,7 @@ TEST_P(GLES2DecoderTest, BeginEndQueryEXTGetErrorQueryCHROMIUM) {
end_cmd.Init(GL_GET_ERROR_QUERY_CHROMIUM, 1);
EXPECT_EQ(error::kNoError, ExecuteCmd(end_cmd));
EXPECT_EQ(GL_NO_ERROR, GetGLError());
- EXPECT_FALSE(query->pending());
+ EXPECT_FALSE(query->IsPending());
EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE),
static_cast<GLenum>(sync->result));
}
@@ -927,7 +927,7 @@ TEST_P(GLES2DecoderManualInitTest, BeginEndQueryEXTCommandsCompletedCHROMIUM) {
ASSERT_TRUE(query_manager != NULL);
QueryManager::Query* query = query_manager->GetQuery(kNewClientId);
ASSERT_TRUE(query != NULL);
- EXPECT_FALSE(query->pending());
+ EXPECT_FALSE(query->IsPending());
EXPECT_CALL(*gl_, Flush()).RetiresOnSaturation();
EXPECT_CALL(*gl_, FenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0))
@@ -943,7 +943,7 @@ TEST_P(GLES2DecoderManualInitTest, BeginEndQueryEXTCommandsCompletedCHROMIUM) {
end_cmd.Init(GL_COMMANDS_COMPLETED_CHROMIUM, 1);
EXPECT_EQ(error::kNoError, ExecuteCmd(end_cmd));
EXPECT_EQ(GL_NO_ERROR, GetGLError());
- EXPECT_TRUE(query->pending());
+ EXPECT_TRUE(query->IsPending());
#if DCHECK_IS_ON()
EXPECT_CALL(*gl_, IsSync(kGlSync))
@@ -956,7 +956,7 @@ TEST_P(GLES2DecoderManualInitTest, BeginEndQueryEXTCommandsCompletedCHROMIUM) {
bool process_success = query_manager->ProcessPendingQueries(false);
EXPECT_TRUE(process_success);
- EXPECT_TRUE(query->pending());
+ EXPECT_TRUE(query->IsPending());
#if DCHECK_IS_ON()
EXPECT_CALL(*gl_, IsSync(kGlSync))
@@ -969,7 +969,7 @@ TEST_P(GLES2DecoderManualInitTest, BeginEndQueryEXTCommandsCompletedCHROMIUM) {
process_success = query_manager->ProcessPendingQueries(false);
EXPECT_TRUE(process_success);
- EXPECT_FALSE(query->pending());
+ EXPECT_FALSE(query->IsPending());
#if DCHECK_IS_ON()
EXPECT_CALL(*gl_, IsSync(kGlSync))
@@ -1061,7 +1061,7 @@ TEST_P(GLES2DecoderManualInitTest, QueryCounterEXTTimeStamp) {
ASSERT_TRUE(query_manager != NULL);
QueryManager::Query* query = query_manager->GetQuery(kNewClientId);
ASSERT_TRUE(query != NULL);
- EXPECT_TRUE(query->pending());
+ EXPECT_TRUE(query->IsPending());
}
TEST_P(GLES2DecoderManualInitTest, InvalidTargetQueryCounterFails) {
diff --git a/gpu/command_buffer/service/query_manager.cc b/gpu/command_buffer/service/query_manager.cc
index 81f7747..09bad18 100644
--- a/gpu/command_buffer/service/query_manager.cc
+++ b/gpu/command_buffer/service/query_manager.cc
@@ -67,6 +67,8 @@ class AsyncPixelTransfersCompletedQuery
bool Begin() override;
bool End(base::subtle::Atomic32 submit_count) override;
bool QueryCounter(base::subtle::Atomic32 submit_count) override;
+ void Pause() override;
+ void Resume() override;
bool Process(bool did_finish) override;
void Destroy(bool have_context) override;
@@ -82,9 +84,18 @@ AsyncPixelTransfersCompletedQuery::AsyncPixelTransfersCompletedQuery(
}
bool AsyncPixelTransfersCompletedQuery::Begin() {
+ MarkAsActive();
return true;
}
+void AsyncPixelTransfersCompletedQuery::Pause() {
+ MarkAsPaused();
+}
+
+void AsyncPixelTransfersCompletedQuery::Resume() {
+ MarkAsActive();
+}
+
bool AsyncPixelTransfersCompletedQuery::End(
base::subtle::Atomic32 submit_count) {
// Get the real shared memory since it might need to be duped to prevent
@@ -146,11 +157,12 @@ AsyncPixelTransfersCompletedQuery::~AsyncPixelTransfersCompletedQuery() {
class AllSamplesPassedQuery : public QueryManager::Query {
public:
AllSamplesPassedQuery(
- QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset,
- GLuint service_id);
+ QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
bool Begin() override;
bool End(base::subtle::Atomic32 submit_count) override;
bool QueryCounter(base::subtle::Atomic32 submit_count) override;
+ void Pause() override;
+ void Resume() override;
bool Process(bool did_finish) override;
void Destroy(bool have_context) override;
@@ -159,18 +171,26 @@ class AllSamplesPassedQuery : public QueryManager::Query {
private:
// Service side query id.
- GLuint service_id_;
+ std::vector<GLuint> service_ids_;
};
AllSamplesPassedQuery::AllSamplesPassedQuery(
- QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset,
- GLuint service_id)
- : Query(manager, target, shm_id, shm_offset),
- service_id_(service_id) {
+ QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
+ : Query(manager, target, shm_id, shm_offset) {
+ GLuint service_id = 0;
+ glGenQueries(1, &service_id);
+ DCHECK_NE(0u, service_id);
+ service_ids_.push_back(service_id);
}
bool AllSamplesPassedQuery::Begin() {
- BeginQueryHelper(target(), service_id_);
+ MarkAsActive();
+ // Delete all but the first one when beginning a new query.
+ if (service_ids_.size() > 1) {
+ glDeleteQueries(service_ids_.size() - 1, &service_ids_[1]);
+ service_ids_.resize(1);
+ }
+ BeginQueryHelper(target(), service_ids_.back());
return true;
}
@@ -184,23 +204,41 @@ bool AllSamplesPassedQuery::QueryCounter(base::subtle::Atomic32 submit_count) {
return false;
}
+void AllSamplesPassedQuery::Pause() {
+ MarkAsPaused();
+ EndQueryHelper(target());
+}
+
+void AllSamplesPassedQuery::Resume() {
+ MarkAsActive();
+
+ GLuint service_id = 0;
+ glGenQueries(1, &service_id);
+ DCHECK_NE(0u, service_id);
+ service_ids_.push_back(service_id);
+ BeginQueryHelper(target(), service_ids_.back());
+}
+
bool AllSamplesPassedQuery::Process(bool did_finish) {
GLuint available = 0;
glGetQueryObjectuiv(
- service_id_, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
+ service_ids_.back(), GL_QUERY_RESULT_AVAILABLE_EXT, &available);
if (!available) {
return true;
}
- GLuint result = 0;
- glGetQueryObjectuiv(
- service_id_, GL_QUERY_RESULT_EXT, &result);
-
- return MarkAsCompleted(result != 0);
+ for (const GLuint& service_id : service_ids_) {
+ GLuint result = 0;
+ glGetQueryObjectuiv(service_id, GL_QUERY_RESULT_EXT, &result);
+ if (result != 0)
+ return MarkAsCompleted(1);
+ }
+ return MarkAsCompleted(0);
}
void AllSamplesPassedQuery::Destroy(bool have_context) {
if (have_context && !IsDeleted()) {
- glDeleteQueries(1, &service_id_);
+ glDeleteQueries(service_ids_.size(), &service_ids_[0]);
+ service_ids_.clear();
MarkAsDeleted();
}
}
@@ -216,6 +254,8 @@ class CommandsIssuedQuery : public QueryManager::Query {
bool Begin() override;
bool End(base::subtle::Atomic32 submit_count) override;
bool QueryCounter(base::subtle::Atomic32 submit_count) override;
+ void Pause() override;
+ void Resume() override;
bool Process(bool did_finish) override;
void Destroy(bool have_context) override;
@@ -232,12 +272,21 @@ CommandsIssuedQuery::CommandsIssuedQuery(
}
bool CommandsIssuedQuery::Begin() {
+ MarkAsActive();
begin_time_ = base::TimeTicks::Now();
return true;
}
+void CommandsIssuedQuery::Pause() {
+ MarkAsPaused();
+}
+
+void CommandsIssuedQuery::Resume() {
+ MarkAsActive();
+}
+
bool CommandsIssuedQuery::End(base::subtle::Atomic32 submit_count) {
- base::TimeDelta elapsed = base::TimeTicks::Now() - begin_time_;
+ const base::TimeDelta elapsed = base::TimeTicks::Now() - begin_time_;
MarkAsPending(submit_count);
return MarkAsCompleted(elapsed.InMicroseconds());
}
@@ -269,6 +318,8 @@ class CommandLatencyQuery : public QueryManager::Query {
bool Begin() override;
bool End(base::subtle::Atomic32 submit_count) override;
bool QueryCounter(base::subtle::Atomic32 submit_count) override;
+ void Pause() override;
+ void Resume() override;
bool Process(bool did_finish) override;
void Destroy(bool have_context) override;
@@ -282,7 +333,16 @@ CommandLatencyQuery::CommandLatencyQuery(
}
bool CommandLatencyQuery::Begin() {
- return true;
+ MarkAsActive();
+ return true;
+}
+
+void CommandLatencyQuery::Pause() {
+ MarkAsPaused();
+}
+
+void CommandLatencyQuery::Resume() {
+ MarkAsActive();
}
bool CommandLatencyQuery::End(base::subtle::Atomic32 submit_count) {
@@ -321,6 +381,8 @@ class AsyncReadPixelsCompletedQuery
bool Begin() override;
bool End(base::subtle::Atomic32 submit_count) override;
bool QueryCounter(base::subtle::Atomic32 submit_count) override;
+ void Pause() override;
+ void Resume() override;
bool Process(bool did_finish) override;
void Destroy(bool have_context) override;
@@ -329,21 +391,28 @@ class AsyncReadPixelsCompletedQuery
~AsyncReadPixelsCompletedQuery() override;
private:
- bool completed_;
bool complete_result_;
};
AsyncReadPixelsCompletedQuery::AsyncReadPixelsCompletedQuery(
QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
: Query(manager, target, shm_id, shm_offset),
- completed_(false),
complete_result_(false) {
}
bool AsyncReadPixelsCompletedQuery::Begin() {
+ MarkAsActive();
return true;
}
+void AsyncReadPixelsCompletedQuery::Pause() {
+ MarkAsPaused();
+}
+
+void AsyncReadPixelsCompletedQuery::Resume() {
+ MarkAsActive();
+}
+
bool AsyncReadPixelsCompletedQuery::End(base::subtle::Atomic32 submit_count) {
if (!AddToPendingQueue(submit_count)) {
return false;
@@ -362,12 +431,11 @@ bool AsyncReadPixelsCompletedQuery::QueryCounter(
}
void AsyncReadPixelsCompletedQuery::Complete() {
- completed_ = true;
complete_result_ = MarkAsCompleted(1);
}
bool AsyncReadPixelsCompletedQuery::Process(bool did_finish) {
- return !completed_ || complete_result_;
+ return !IsFinished() || complete_result_;
}
void AsyncReadPixelsCompletedQuery::Destroy(bool /* have_context */) {
@@ -388,6 +456,8 @@ class GetErrorQuery : public QueryManager::Query {
bool Begin() override;
bool End(base::subtle::Atomic32 submit_count) override;
bool QueryCounter(base::subtle::Atomic32 submit_count) override;
+ void Pause() override;
+ void Resume() override;
bool Process(bool did_finish) override;
void Destroy(bool have_context) override;
@@ -403,9 +473,18 @@ GetErrorQuery::GetErrorQuery(
}
bool GetErrorQuery::Begin() {
+ MarkAsActive();
return true;
}
+void GetErrorQuery::Pause() {
+ MarkAsPaused();
+}
+
+void GetErrorQuery::Resume() {
+ MarkAsActive();
+}
+
bool GetErrorQuery::End(base::subtle::Atomic32 submit_count) {
MarkAsPending(submit_count);
return MarkAsCompleted(manager()->decoder()->GetErrorState()->GetGLError());
@@ -441,6 +520,8 @@ class CommandsCompletedQuery : public QueryManager::Query {
bool Begin() override;
bool End(base::subtle::Atomic32 submit_count) override;
bool QueryCounter(base::subtle::Atomic32 submit_count) override;
+ void Pause() override;
+ void Resume() override;
bool Process(bool did_finish) override;
void Destroy(bool have_context) override;
@@ -459,10 +540,19 @@ CommandsCompletedQuery::CommandsCompletedQuery(QueryManager* manager,
: Query(manager, target, shm_id, shm_offset) {}
bool CommandsCompletedQuery::Begin() {
+ MarkAsActive();
begin_time_ = base::TimeTicks::Now();
return true;
}
+void CommandsCompletedQuery::Pause() {
+ MarkAsPaused();
+}
+
+void CommandsCompletedQuery::Resume() {
+ MarkAsActive();
+}
+
bool CommandsCompletedQuery::End(base::subtle::Atomic32 submit_count) {
fence_.reset(gfx::GLFence::Create());
DCHECK(fence_);
@@ -481,7 +571,7 @@ bool CommandsCompletedQuery::Process(bool did_finish) {
if (!did_finish && fence_ && !fence_->HasCompleted())
return true;
- base::TimeDelta elapsed = base::TimeTicks::Now() - begin_time_;
+ const base::TimeDelta elapsed = base::TimeTicks::Now() - begin_time_;
return MarkAsCompleted(elapsed.InMicroseconds());
}
@@ -505,6 +595,8 @@ class TimeElapsedQuery : public QueryManager::Query {
bool Begin() override;
bool End(base::subtle::Atomic32 submit_count) override;
bool QueryCounter(base::subtle::Atomic32 submit_count) override;
+ void Pause() override;
+ void Resume() override;
bool Process(bool did_finish) override;
void Destroy(bool have_context) override;
@@ -520,9 +612,11 @@ TimeElapsedQuery::TimeElapsedQuery(QueryManager* manager,
int32 shm_id,
uint32 shm_offset)
: Query(manager, target, shm_id, shm_offset),
- gpu_timer_(manager->CreateGPUTimer(true)) {}
+ gpu_timer_(manager->CreateGPUTimer(true)) {
+}
bool TimeElapsedQuery::Begin() {
+ MarkAsActive();
gpu_timer_->Start();
return true;
}
@@ -537,20 +631,25 @@ bool TimeElapsedQuery::QueryCounter(base::subtle::Atomic32 submit_count) {
return false;
}
+void TimeElapsedQuery::Pause() {
+ MarkAsPaused();
+}
+
+void TimeElapsedQuery::Resume() {
+ MarkAsActive();
+}
+
bool TimeElapsedQuery::Process(bool did_finish) {
if (!gpu_timer_->IsAvailable())
return true;
- const uint64_t nano_seconds =
- gpu_timer_->GetDeltaElapsed() * base::Time::kNanosecondsPerMicrosecond;
+ const uint64_t nano_seconds = gpu_timer_->GetDeltaElapsed() *
+ base::Time::kNanosecondsPerMicrosecond;
return MarkAsCompleted(nano_seconds);
}
void TimeElapsedQuery::Destroy(bool have_context) {
- if (gpu_timer_.get()) {
- gpu_timer_->Destroy(have_context);
- gpu_timer_.reset();
- }
+ gpu_timer_->Destroy(have_context);
}
TimeElapsedQuery::~TimeElapsedQuery() {}
@@ -566,6 +665,8 @@ class TimeStampQuery : public QueryManager::Query {
bool Begin() override;
bool End(base::subtle::Atomic32 submit_count) override;
bool QueryCounter(base::subtle::Atomic32 submit_count) override;
+ void Pause() override;
+ void Resume() override;
bool Process(bool did_finish) override;
void Destroy(bool have_context) override;
@@ -593,7 +694,16 @@ bool TimeStampQuery::End(base::subtle::Atomic32 submit_count) {
return false;
}
+void TimeStampQuery::Pause() {
+ MarkAsPaused();
+}
+
+void TimeStampQuery::Resume() {
+ MarkAsActive();
+}
+
bool TimeStampQuery::QueryCounter(base::subtle::Atomic32 submit_count) {
+ MarkAsActive();
gpu_timer_->QueryTimeStamp();
return AddToPendingQueue(submit_count);
}
@@ -692,11 +802,7 @@ QueryManager::Query* QueryManager::CreateQuery(
query = new TimeStampQuery(this, target, shm_id, shm_offset);
break;
default: {
- GLuint service_id = 0;
- glGenQueries(1, &service_id);
- DCHECK_NE(0u, service_id);
- query = new AllSamplesPassedQuery(
- this, target, shm_id, shm_offset, service_id);
+ query = new AllSamplesPassedQuery(this, target, shm_id, shm_offset);
break;
}
}
@@ -726,16 +832,30 @@ bool QueryManager::IsValidQuery(GLuint id) {
return it != generated_query_ids_.end();
}
-QueryManager::Query* QueryManager::GetQuery(
- GLuint client_id) {
+QueryManager::Query* QueryManager::GetQuery(GLuint client_id) {
QueryMap::iterator it = queries_.find(client_id);
- return it != queries_.end() ? it->second.get() : NULL;
+ return it != queries_.end() ? it->second.get() : nullptr;
+}
+
+QueryManager::Query* QueryManager::GetActiveQuery(GLenum target) {
+ ActiveQueryMap::iterator it = active_queries_.find(target);
+ return it != active_queries_.end() ? it->second.get() : nullptr;
}
void QueryManager::RemoveQuery(GLuint client_id) {
QueryMap::iterator it = queries_.find(client_id);
if (it != queries_.end()) {
Query* query = it->second.get();
+
+ // Remove from active query map if it is active.
+ ActiveQueryMap::iterator active_it = active_queries_.find(query->target());
+ bool is_active = (active_it != active_queries_.end() &&
+ query == active_it->second.get());
+ DCHECK(is_active == query->IsActive());
+ if (is_active)
+ active_queries_.erase(active_it);
+
+ query->Destroy(true);
RemovePendingQuery(query);
query->MarkAsDeleted();
queries_.erase(it);
@@ -790,7 +910,7 @@ QueryManager::Query::Query(
shm_id_(shm_id),
shm_offset_(shm_offset),
submit_count_(0),
- pending_(false),
+ query_state_(kQueryState_Initialize),
deleted_(false) {
DCHECK(manager);
manager_->StartTracking(this);
@@ -804,7 +924,7 @@ void QueryManager::Query::RunCallbacks() {
}
void QueryManager::Query::AddCallback(base::Closure callback) {
- if (pending_) {
+ if (query_state_ == kQueryState_Pending) {
callbacks_.push_back(callback);
} else {
callback.Run();
@@ -823,14 +943,13 @@ QueryManager::Query::~Query() {
}
bool QueryManager::Query::MarkAsCompleted(uint64 result) {
- DCHECK(pending_);
+ UnmarkAsPending();
QuerySync* sync = manager_->decoder_->GetSharedMemoryAs<QuerySync*>(
shm_id_, shm_offset_, sizeof(*sync));
if (!sync) {
return false;
}
- pending_ = false;
sync->result = result;
base::subtle::Release_Store(&sync->process_count, submit_count_);
@@ -843,7 +962,7 @@ bool QueryManager::ProcessPendingQueries(bool did_finish) {
if (!query->Process(did_finish)) {
return false;
}
- if (query->pending()) {
+ if (query->IsPending()) {
break;
}
query->RunCallbacks();
@@ -865,7 +984,7 @@ bool QueryManager::ProcessPendingTransferQueries() {
if (!query->Process(false)) {
return false;
}
- if (query->pending()) {
+ if (query->IsPending()) {
break;
}
query->RunCallbacks();
@@ -906,7 +1025,7 @@ bool QueryManager::AddPendingTransferQuery(
bool QueryManager::RemovePendingQuery(Query* query) {
DCHECK(query);
- if (query->pending()) {
+ if (query->IsPending()) {
// 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.
@@ -936,7 +1055,12 @@ bool QueryManager::BeginQuery(Query* query) {
if (!RemovePendingQuery(query)) {
return false;
}
- return query->Begin();
+ if (query->Begin()) {
+ active_queries_[query->target()] = query;
+ return true;
+ }
+
+ return false;
}
bool QueryManager::EndQuery(Query* query, base::subtle::Atomic32 submit_count) {
@@ -944,6 +1068,13 @@ bool QueryManager::EndQuery(Query* query, base::subtle::Atomic32 submit_count) {
if (!RemovePendingQuery(query)) {
return false;
}
+
+ // Remove from active query map if it is active.
+ ActiveQueryMap::iterator active_it = active_queries_.find(query->target());
+ DCHECK(active_it != active_queries_.end());
+ DCHECK(query == active_it->second.get());
+ active_queries_.erase(active_it);
+
return query->End(submit_count);
}
@@ -953,5 +1084,23 @@ bool QueryManager::QueryCounter(
return query->QueryCounter(submit_count);
}
+void QueryManager::PauseQueries() {
+ for (std::pair<const GLenum, scoped_refptr<Query> >& it : active_queries_) {
+ if (it.second->IsActive()) {
+ it.second->Pause();
+ DCHECK(it.second->IsPaused());
+ }
+ }
+}
+
+void QueryManager::ResumeQueries() {
+ for (std::pair<const GLenum, scoped_refptr<Query> >& it : active_queries_) {
+ if (it.second->IsPaused()) {
+ it.second->Resume();
+ DCHECK(it.second->IsActive());
+ }
+ }
+}
+
} // namespace gles2
} // namespace gpu
diff --git a/gpu/command_buffer/service/query_manager.h b/gpu/command_buffer/service/query_manager.h
index e07d018..7e8ba49 100644
--- a/gpu/command_buffer/service/query_manager.h
+++ b/gpu/command_buffer/service/query_manager.h
@@ -50,8 +50,20 @@ class GPU_EXPORT QueryManager {
return target() && !IsDeleted();
}
- bool pending() const {
- return pending_;
+ bool IsActive() const {
+ return query_state_ == kQueryState_Active;
+ }
+
+ bool IsPaused() const {
+ return query_state_ == kQueryState_Paused;
+ }
+
+ bool IsPending() const {
+ return query_state_ == kQueryState_Pending;
+ }
+
+ bool IsFinished() const {
+ return query_state_ == kQueryState_Finished;
}
int32 shm_id() const {
@@ -74,6 +86,12 @@ class GPU_EXPORT QueryManager {
// Returns false if shared memory for sync is invalid.
virtual bool Process(bool did_finish) = 0;
+ // Pauses active query to be resumed later.
+ virtual void Pause() = 0;
+
+ // Resume from a paused active query.
+ virtual void Resume() = 0;
+
virtual void Destroy(bool have_context) = 0;
void AddCallback(base::Closure callback);
@@ -89,18 +107,30 @@ class GPU_EXPORT QueryManager {
deleted_ = true;
}
- // Returns false if shared memory for sync is invalid.
- bool MarkAsCompleted(uint64 result);
+ void MarkAsActive() {
+ DCHECK(query_state_ == kQueryState_Initialize ||
+ query_state_ == kQueryState_Paused ||
+ query_state_ == kQueryState_Finished);
+ query_state_ = kQueryState_Active;
+ }
+
+ void MarkAsPaused() {
+ DCHECK(query_state_ == kQueryState_Active);
+ query_state_ = kQueryState_Paused;
+ }
void MarkAsPending(base::subtle::Atomic32 submit_count) {
- DCHECK(!pending_);
- pending_ = true;
+ DCHECK(query_state_ == kQueryState_Active);
+ query_state_ = kQueryState_Pending;
submit_count_ = submit_count;
}
+ // Returns false if shared memory for sync is invalid.
+ bool MarkAsCompleted(uint64 result);
+
void UnmarkAsPending() {
- DCHECK(pending_);
- pending_ = false;
+ DCHECK(query_state_ == kQueryState_Pending);
+ query_state_ = kQueryState_Finished;
}
// Returns false if shared memory for sync is invalid.
@@ -143,8 +173,14 @@ class GPU_EXPORT QueryManager {
// Count to set process count do when completed.
base::subtle::Atomic32 submit_count_;
- // True if in the queue.
- bool pending_;
+ // Current state of the query.
+ enum QueryState {
+ kQueryState_Initialize, // Has not been queried yet.
+ kQueryState_Active, // Query began but has not ended.
+ kQueryState_Paused, // Query was active but is now paused.
+ kQueryState_Pending, // Query ended, waiting for result.
+ kQueryState_Finished, // Query received result.
+ } query_state_;
// True if deleted.
bool deleted_;
@@ -168,6 +204,9 @@ class GPU_EXPORT QueryManager {
// Gets the query info for the given query.
Query* GetQuery(GLuint client_id);
+ // Gets the currently active query for a target.
+ Query* GetActiveQuery(GLenum target);
+
// Removes a query info for the given query.
void RemoveQuery(GLuint client_id);
@@ -180,6 +219,9 @@ class GPU_EXPORT QueryManager {
// Returns false if any query is pointing to invalid shared memory.
bool QueryCounter(Query* query, base::subtle::Atomic32 submit_count);
+ void PauseQueries();
+ void ResumeQueries();
+
// Processes pending queries. Returns false if any queries are pointing
// to invalid shared memory. |did_finish| is true if this is called as
// a result of calling glFinish().
@@ -248,6 +290,10 @@ class GPU_EXPORT QueryManager {
typedef base::hash_set<GLuint> GeneratedQueryIds;
GeneratedQueryIds generated_query_ids_;
+ // A map of targets -> Query for current active queries.
+ typedef std::map<GLenum, scoped_refptr<Query> > ActiveQueryMap;
+ ActiveQueryMap active_queries_;
+
// Queries waiting for completion.
typedef std::deque<scoped_refptr<Query> > QueryQueue;
QueryQueue pending_queries_;
diff --git a/gpu/command_buffer/service/query_manager_unittest.cc b/gpu/command_buffer/service/query_manager_unittest.cc
index 87273f6..71b71aa 100644
--- a/gpu/command_buffer/service/query_manager_unittest.cc
+++ b/gpu/command_buffer/service/query_manager_unittest.cc
@@ -12,7 +12,10 @@
#include "gpu/command_buffer/service/gpu_service_test.h"
#include "gpu/command_buffer/service/test_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_context.h"
#include "ui/gl/gl_mock.h"
+#include "ui/gl/gpu_timing.h"
+#include "ui/gl/gpu_timing_fake.h"
using ::testing::_;
using ::testing::InSequence;
@@ -38,7 +41,7 @@ class QueryManagerTest : public GpuServiceTest {
protected:
void SetUp() override {
- GpuServiceTest::SetUpWithGLVersion("2.1",
+ GpuServiceTest::SetUpWithGLVersion("3.2",
"GL_ARB_occlusion_query, "
"GL_ARB_timer_query");
engine_.reset(new MockCommandBufferEngine());
@@ -48,7 +51,7 @@ class QueryManagerTest : public GpuServiceTest {
gl_.get(),
"GL_EXT_occlusion_query_boolean, GL_ARB_timer_query");
EXPECT_CALL(*decoder_.get(), GetGLContext())
- .WillRepeatedly(Return(GetGLContext()));
+ .WillRepeatedly(Return(GetGLContext()));
scoped_refptr<FeatureInfo> feature_info(new FeatureInfo());
feature_info->Initialize();
manager_.reset(new QueryManager(decoder_.get(), feature_info.get()));
@@ -164,6 +167,9 @@ TEST_F(QueryManagerTest, Basic) {
// Check we get nothing for a non-existent query.
EXPECT_TRUE(manager_->GetQuery(kClient2Id) == NULL);
// Check we can delete the query.
+ EXPECT_CALL(*gl_, DeleteQueries(1, ::testing::Pointee(kService1Id)))
+ .Times(1)
+ .RetiresOnSaturation();
manager_->RemoveQuery(kClient1Id);
// Check we get nothing for a non-existent query.
EXPECT_TRUE(manager_->GetQuery(kClient1Id) == NULL);
@@ -204,7 +210,7 @@ TEST_F(QueryManagerTest, QueryBasic) {
EXPECT_TRUE(query->IsValid());
EXPECT_FALSE(query->IsDeleted());
- EXPECT_FALSE(query->pending());
+ EXPECT_FALSE(query->IsPending());
EXPECT_EQ(kTarget, query->target());
EXPECT_EQ(kSharedMemoryId, query->shm_id());
EXPECT_EQ(kSharedMemoryOffset, query->shm_offset());
@@ -234,7 +240,7 @@ TEST_F(QueryManagerTest, ProcessPendingQuery) {
// Queue it
QueueQuery(query.get(), kService1Id, kSubmitCount);
- EXPECT_TRUE(query->pending());
+ EXPECT_TRUE(query->IsPending());
EXPECT_TRUE(manager_->HavePendingQueries());
// Process with return not available.
@@ -244,7 +250,7 @@ TEST_F(QueryManagerTest, ProcessPendingQuery) {
.WillOnce(SetArgumentPointee<2>(0))
.RetiresOnSaturation();
EXPECT_TRUE(manager_->ProcessPendingQueries(false));
- EXPECT_TRUE(query->pending());
+ EXPECT_TRUE(query->IsPending());
EXPECT_EQ(0, sync->process_count);
EXPECT_EQ(0u, sync->result);
@@ -259,7 +265,7 @@ TEST_F(QueryManagerTest, ProcessPendingQuery) {
.WillOnce(SetArgumentPointee<2>(kResult))
.RetiresOnSaturation();
EXPECT_TRUE(manager_->ProcessPendingQueries(false));
- EXPECT_FALSE(query->pending());
+ EXPECT_FALSE(query->IsPending());
EXPECT_EQ(kSubmitCount, sync->process_count);
EXPECT_EQ(kResult, sync->result);
EXPECT_FALSE(manager_->HavePendingQueries());
@@ -317,9 +323,9 @@ TEST_F(QueryManagerTest, ProcessPendingQueries) {
QueueQuery(query1.get(), kService1Id, kSubmitCount1);
QueueQuery(query2.get(), kService2Id, kSubmitCount2);
QueueQuery(query3.get(), kService3Id, kSubmitCount3);
- EXPECT_TRUE(query1->pending());
- EXPECT_TRUE(query2->pending());
- EXPECT_TRUE(query3->pending());
+ EXPECT_TRUE(query1->IsPending());
+ EXPECT_TRUE(query2->IsPending());
+ EXPECT_TRUE(query3->IsPending());
EXPECT_TRUE(manager_->HavePendingQueries());
// Process with return available for first 2 queries.
@@ -348,9 +354,9 @@ TEST_F(QueryManagerTest, ProcessPendingQueries) {
.RetiresOnSaturation();
EXPECT_TRUE(manager_->ProcessPendingQueries(false));
}
- EXPECT_FALSE(query1->pending());
- EXPECT_FALSE(query2->pending());
- EXPECT_TRUE(query3->pending());
+ EXPECT_FALSE(query1->IsPending());
+ EXPECT_FALSE(query2->IsPending());
+ EXPECT_TRUE(query3->IsPending());
EXPECT_EQ(kSubmitCount1, sync1->process_count);
EXPECT_EQ(kSubmitCount2, sync2->process_count);
EXPECT_EQ(kResult1, sync1->result);
@@ -366,7 +372,7 @@ TEST_F(QueryManagerTest, ProcessPendingQueries) {
.WillOnce(SetArgumentPointee<2>(0))
.RetiresOnSaturation();
EXPECT_TRUE(manager_->ProcessPendingQueries(false));
- EXPECT_TRUE(query3->pending());
+ EXPECT_TRUE(query3->IsPending());
EXPECT_EQ(0, sync3->process_count);
EXPECT_EQ(0u, sync3->result);
EXPECT_TRUE(manager_->HavePendingQueries());
@@ -382,7 +388,7 @@ TEST_F(QueryManagerTest, ProcessPendingQueries) {
.WillOnce(SetArgumentPointee<2>(kResult3))
.RetiresOnSaturation();
EXPECT_TRUE(manager_->ProcessPendingQueries(false));
- EXPECT_FALSE(query3->pending());
+ EXPECT_FALSE(query3->IsPending());
EXPECT_EQ(kSubmitCount3, sync3->process_count);
EXPECT_EQ(kResult3, sync3->result);
EXPECT_FALSE(manager_->HavePendingQueries());
@@ -479,8 +485,8 @@ TEST_F(QueryManagerTest, ARBOcclusionQuery2) {
new QueryManager(decoder_.get(), feature_info.get()));
EXPECT_CALL(*gl_, GenQueries(1, _))
- .WillOnce(SetArgumentPointee<1>(kService1Id))
- .RetiresOnSaturation();
+ .WillOnce(SetArgumentPointee<1>(kService1Id))
+ .RetiresOnSaturation();
QueryManager::Query* query = manager->CreateQuery(
kTarget, kClient1Id, kSharedMemoryId, kSharedMemoryOffset);
ASSERT_TRUE(query != NULL);
@@ -513,8 +519,8 @@ TEST_F(QueryManagerTest, ARBOcclusionQuery) {
new QueryManager(decoder_.get(), feature_info.get()));
EXPECT_CALL(*gl_, GenQueries(1, _))
- .WillOnce(SetArgumentPointee<1>(kService1Id))
- .RetiresOnSaturation();
+ .WillOnce(SetArgumentPointee<1>(kService1Id))
+ .RetiresOnSaturation();
QueryManager::Query* query = manager->CreateQuery(
kTarget, kClient1Id, kSharedMemoryId, kSharedMemoryOffset);
ASSERT_TRUE(query != NULL);
@@ -530,47 +536,204 @@ TEST_F(QueryManagerTest, ARBOcclusionQuery) {
manager->Destroy(false);
}
-TEST_F(QueryManagerTest, TimeElapsedQuery) {
+TEST_F(QueryManagerTest, ARBOcclusionPauseResume) {
const GLuint kClient1Id = 1;
const GLuint kService1Id = 11;
- const GLenum kTarget = GL_TIME_ELAPSED_EXT;
+ const GLuint kService2Id = 12;
+ const GLenum kTarget = GL_ANY_SAMPLES_PASSED_EXT;
const base::subtle::Atomic32 kSubmitCount = 123;
+ TestHelper::SetupFeatureInfoInitExpectations(
+ gl_.get(),
+ "GL_ARB_occlusion_query");
+ scoped_refptr<FeatureInfo> feature_info(new FeatureInfo());
+ feature_info->Initialize();
+ scoped_ptr<QueryManager> manager(
+ new QueryManager(decoder_.get(), feature_info.get()));
+
EXPECT_CALL(*gl_, GenQueries(1, _))
- .WillOnce(SetArgumentPointee<1>(kService1Id))
- .RetiresOnSaturation();
- QueryManager::Query* query = manager_->CreateQuery(
+ .WillOnce(SetArgumentPointee<1>(kService1Id))
+ .RetiresOnSaturation();
+ QueryManager::Query* query = manager->CreateQuery(
kTarget, kClient1Id, kSharedMemoryId, kSharedMemoryOffset);
ASSERT_TRUE(query != NULL);
- EXPECT_CALL(*gl_, BeginQuery(GL_TIME_ELAPSED_EXT, kService1Id))
+ EXPECT_CALL(*gl_, BeginQuery(GL_SAMPLES_PASSED_ARB, kService1Id))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_TRUE(manager->BeginQuery(query));
+
+ // Pause and Resume the manager.
+ EXPECT_CALL(*gl_, EndQuery(GL_SAMPLES_PASSED_ARB))
+ .Times(1)
+ .RetiresOnSaturation();
+ manager->PauseQueries();
+
+ EXPECT_CALL(*gl_, GenQueries(1, _))
+ .WillOnce(SetArgumentPointee<1>(kService2Id))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, BeginQuery(GL_SAMPLES_PASSED_ARB, kService2Id))
+ .Times(1)
+ .RetiresOnSaturation();
+ manager->ResumeQueries();
+
+ EXPECT_CALL(*gl_, EndQuery(GL_SAMPLES_PASSED_ARB))
.Times(1)
.RetiresOnSaturation();
- EXPECT_CALL(*gl_, EndQuery(GL_TIME_ELAPSED_EXT))
+ EXPECT_TRUE(manager->EndQuery(query, kSubmitCount));
+
+ EXPECT_CALL(*gl_, GetQueryObjectuiv(kService2Id,
+ GL_QUERY_RESULT_AVAILABLE_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(1u))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetQueryObjectuiv(kService1Id,
+ GL_QUERY_RESULT_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(0u))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetQueryObjectuiv(kService2Id,
+ GL_QUERY_RESULT_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(1u))
+ .RetiresOnSaturation();
+ EXPECT_TRUE(manager->ProcessPendingQueries(false));
+ EXPECT_TRUE(query->IsFinished());
+
+ QuerySync* sync = decoder_->GetSharedMemoryAs<QuerySync*>(
+ kSharedMemoryId, kSharedMemoryOffset, sizeof(*sync));
+ EXPECT_EQ(1u, sync->result);
+
+ // Make sure new query still works.
+ EXPECT_CALL(*gl_, DeleteQueries(1, ::testing::Pointee(kService2Id)))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, BeginQuery(GL_SAMPLES_PASSED_ARB, kService1Id))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, EndQuery(GL_SAMPLES_PASSED_ARB))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_TRUE(manager->BeginQuery(query));
+ EXPECT_TRUE(manager->EndQuery(query, kSubmitCount + 1));
+
+ EXPECT_CALL(*gl_, GetQueryObjectuiv(kService1Id,
+ GL_QUERY_RESULT_AVAILABLE_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(1u))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetQueryObjectuiv(kService1Id,
+ GL_QUERY_RESULT_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(0u))
+ .RetiresOnSaturation();
+ EXPECT_TRUE(manager->ProcessPendingQueries(false));
+ EXPECT_TRUE(query->IsFinished());
+
+ EXPECT_EQ(0u, sync->result);
+ EXPECT_CALL(*gl_, DeleteQueries(1, ::testing::Pointee(kService1Id)))
.Times(1)
.RetiresOnSaturation();
+ manager->Destroy(true);
+}
+
+TEST_F(QueryManagerTest, TimeElapsedQuery) {
+ const GLuint kClient1Id = 1;
+ const GLenum kTarget = GL_TIME_ELAPSED_EXT;
+ const base::subtle::Atomic32 kSubmitCount = 123;
+ gfx::GPUTimingFake fake_timing_queries;
+ decoder_->GetGLContext()->CreateGPUTimingClient()->SetCpuTimeForTesting(
+ base::Bind(&gfx::GPUTimingFake::GetFakeCPUTime));
+
+ QueryManager::Query* query = manager_->CreateQuery(
+ kTarget, kClient1Id, kSharedMemoryId, kSharedMemoryOffset);
+ ASSERT_TRUE(query != NULL);
+
+ fake_timing_queries.ExpectGPUTimerQuery(*gl_, true);
+ fake_timing_queries.SetCurrentGLTime(
+ 200 * base::Time::kNanosecondsPerMicrosecond);
+ EXPECT_TRUE(manager_->BeginQuery(query));
+ fake_timing_queries.SetCurrentGLTime(
+ 300 * base::Time::kNanosecondsPerMicrosecond);
+ EXPECT_TRUE(manager_->EndQuery(query, kSubmitCount));
+ EXPECT_TRUE(manager_->ProcessPendingQueries(false));
+
+ EXPECT_TRUE(query->IsFinished());
+
+ QuerySync* sync = decoder_->GetSharedMemoryAs<QuerySync*>(
+ kSharedMemoryId, kSharedMemoryOffset, sizeof(*sync));
+ const uint64_t expected_result =
+ 100u * base::Time::kNanosecondsPerMicrosecond;
+ EXPECT_EQ(expected_result, sync->result);
+
+ manager_->Destroy(false);
+}
+
+TEST_F(QueryManagerTest, TimeElapsedPauseResume) {
+ const GLuint kClient1Id = 1;
+ const GLenum kTarget = GL_TIME_ELAPSED_EXT;
+ const base::subtle::Atomic32 kSubmitCount = 123;
+ gfx::GPUTimingFake fake_timing_queries;
+ decoder_->GetGLContext()->CreateGPUTimingClient()->SetCpuTimeForTesting(
+ base::Bind(&gfx::GPUTimingFake::GetFakeCPUTime));
+
+ QueryManager::Query* query = manager_->CreateQuery(
+ kTarget, kClient1Id, kSharedMemoryId, kSharedMemoryOffset);
+ ASSERT_TRUE(query != NULL);
+
+ fake_timing_queries.ExpectGPUTimerQuery(*gl_, true);
+ fake_timing_queries.SetCurrentGLTime(
+ 200 * base::Time::kNanosecondsPerMicrosecond);
EXPECT_TRUE(manager_->BeginQuery(query));
+
+ // Pause and Resume here.
+ fake_timing_queries.SetCurrentGLTime(
+ 300 * base::Time::kNanosecondsPerMicrosecond);
+ manager_->PauseQueries();
+
+ fake_timing_queries.SetCurrentGLTime(
+ 400 * base::Time::kNanosecondsPerMicrosecond);
+ manager_->ResumeQueries();
+
+ fake_timing_queries.SetCurrentGLTime(
+ 500 * base::Time::kNanosecondsPerMicrosecond);
EXPECT_TRUE(manager_->EndQuery(query, kSubmitCount));
+
+ EXPECT_TRUE(manager_->ProcessPendingQueries(false));
+ EXPECT_TRUE(query->IsFinished());
+
+ QuerySync* sync = decoder_->GetSharedMemoryAs<QuerySync*>(
+ kSharedMemoryId, kSharedMemoryOffset, sizeof(*sync));
+ const uint64_t expected_result =
+ 300u * base::Time::kNanosecondsPerMicrosecond;
+ EXPECT_EQ(expected_result, sync->result);
+
+ // Make sure next query works properly.
+ fake_timing_queries.SetCurrentGLTime(
+ 600 * base::Time::kNanosecondsPerMicrosecond);
+ EXPECT_TRUE(manager_->BeginQuery(query));
+ fake_timing_queries.SetCurrentGLTime(
+ 700 * base::Time::kNanosecondsPerMicrosecond);
+ EXPECT_TRUE(manager_->EndQuery(query, kSubmitCount + 1));
+ EXPECT_TRUE(manager_->ProcessPendingQueries(false));
+
+ EXPECT_TRUE(query->IsFinished());
+
+ const uint64_t expected_result2 =
+ 100u * base::Time::kNanosecondsPerMicrosecond;
+ EXPECT_EQ(expected_result2, sync->result);
+
manager_->Destroy(false);
}
TEST_F(QueryManagerTest, TimeStampQuery) {
const GLuint kClient1Id = 1;
- const GLuint kService1Id = 11;
const GLenum kTarget = GL_TIMESTAMP_EXT;
const base::subtle::Atomic32 kSubmitCount = 123;
+ gfx::GPUTimingFake fake_timing_queries;
- EXPECT_CALL(*gl_, GenQueries(1, _))
- .WillOnce(SetArgumentPointee<1>(kService1Id))
- .RetiresOnSaturation();
QueryManager::Query* query = manager_->CreateQuery(
kTarget, kClient1Id, kSharedMemoryId, kSharedMemoryOffset);
ASSERT_TRUE(query != NULL);
- EXPECT_CALL(*gl_, QueryCounter(kService1Id, GL_TIMESTAMP_EXT))
- .Times(1)
- .RetiresOnSaturation();
+ fake_timing_queries.ExpectGPUTimeStampQuery(*gl_, false);
EXPECT_TRUE(manager_->QueryCounter(query, kSubmitCount));
+ EXPECT_TRUE(manager_->ProcessPendingQueries(false));
manager_->Destroy(false);
}
@@ -605,7 +768,7 @@ TEST_F(QueryManagerTest, GetErrorQuery) {
.RetiresOnSaturation();
EXPECT_TRUE(manager->EndQuery(query, kSubmitCount));
- EXPECT_FALSE(query->pending());
+ EXPECT_FALSE(query->IsPending());
EXPECT_EQ(static_cast<GLuint>(GL_INVALID_ENUM), sync->result);
diff --git a/gpu/command_buffer/tests/gl_virtual_contexts_unittest.cc b/gpu/command_buffer/tests/gl_virtual_contexts_unittest.cc
index 9373c38..2e599ba 100644
--- a/gpu/command_buffer/tests/gl_virtual_contexts_unittest.cc
+++ b/gpu/command_buffer/tests/gl_virtual_contexts_unittest.cc
@@ -4,13 +4,13 @@
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
+#include <GLES2/gl2extchromium.h>
#include "gpu/command_buffer/tests/gl_manager.h"
#include "gpu/command_buffer/tests/gl_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-
#define SHADER(Src) #Src
namespace gpu {
@@ -300,5 +300,64 @@ TEST_F(GLVirtualContextsTest, VertexArrayObjectRestoreDefault) {
GLTestHelper::CheckGLError("no errors", __LINE__);
}
+TEST_F(GLVirtualContextsTest, VirtualQueries) {
+ const GLenum query_targets[] = {
+ GL_ANY_SAMPLES_PASSED_EXT,
+ GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
+ GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM,
+ GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM,
+ GL_COMMANDS_COMPLETED_CHROMIUM,
+ GL_COMMANDS_ISSUED_CHROMIUM,
+ GL_GET_ERROR_QUERY_CHROMIUM,
+ GL_LATENCY_QUERY_CHROMIUM,
+ GL_TIME_ELAPSED_EXT,
+ };
+
+ for (GLenum query_target : query_targets) {
+ GLuint query1 = 0;
+ gl1_.MakeCurrent();
+ glGenQueriesEXT(1, &query1);
+ glBeginQueryEXT(query_target, query1);
+ const GLenum begin_error = glGetError();
+ if (GL_INVALID_OPERATION == begin_error) {
+ // Not supported, simply skip.
+ glDeleteQueriesEXT(1, &query1);
+ continue;
+ }
+ ASSERT_TRUE(GL_NO_ERROR == begin_error);
+
+ GLuint query2 = 0;
+ gl2_.MakeCurrent();
+ glGenQueriesEXT(1, &query2);
+ glBeginQueryEXT(query_target, query2);
+ EXPECT_TRUE(GL_NO_ERROR == glGetError())
+ << "Virtualized Query " << query_target << " failed.";
+
+ gl1_.MakeCurrent();
+ glEndQueryEXT(query_target);
+ glFinish();
+
+ GLuint query1_available = 0;
+ glGetQueryObjectuivEXT(query1, GL_QUERY_RESULT_AVAILABLE_EXT,
+ &query1_available);
+ EXPECT_TRUE(query1_available);
+
+ glDeleteQueriesEXT(1, &query1);
+ GLTestHelper::CheckGLError("no errors", __LINE__);
+
+ gl2_.MakeCurrent();
+ glEndQueryEXT(query_target);
+ glFinish();
+
+ GLuint query2_available = 0;
+ glGetQueryObjectuivEXT(query2, GL_QUERY_RESULT_AVAILABLE_EXT,
+ &query2_available);
+ EXPECT_TRUE(query2_available);
+
+ glDeleteQueriesEXT(1, &query2);
+ GLTestHelper::CheckGLError("no errors", __LINE__);
+ }
+}
+
} // namespace gpu