diff options
Diffstat (limited to 'ui')
-rw-r--r-- | ui/gl/gpu_timing.cc | 78 | ||||
-rw-r--r-- | ui/gl/gpu_timing.h | 17 | ||||
-rw-r--r-- | ui/gl/gpu_timing_fake.cc | 44 | ||||
-rw-r--r-- | ui/gl/gpu_timing_fake.h | 1 | ||||
-rw-r--r-- | ui/gl/gpu_timing_unittest.cc | 100 |
5 files changed, 197 insertions, 43 deletions
diff --git a/ui/gl/gpu_timing.cc b/ui/gl/gpu_timing.cc index c902254..e78442e 100644 --- a/ui/gl/gpu_timing.cc +++ b/ui/gl/gpu_timing.cc @@ -11,6 +11,9 @@ namespace gfx { +class TimeElapsedTimerQuery; +class TimerQuery; + int64_t NanoToMicro(uint64_t nano_seconds) { const uint64_t up = nano_seconds + base::Time::kNanosecondsPerMicrosecond / 2; return static_cast<int64_t>(up / base::Time::kNanosecondsPerMicrosecond); @@ -313,6 +316,7 @@ GPUTimingImpl::GPUTimingImpl(GLContextReal* context) { timer_type_ = GPUTiming::kTimerTypeARB; } else if (context->HasExtension("GL_EXT_timer_query")) { timer_type_ = GPUTiming::kTimerTypeEXT; + force_time_elapsed_query_ = true; } } @@ -375,8 +379,7 @@ void GPUTimingImpl::EndElapsedTimeQuery(scoped_refptr<QueryResult> result) { } scoped_refptr<QueryResult> GPUTimingImpl::DoTimeStampQuery() { - DCHECK(timer_type_ == GPUTiming::kTimerTypeDisjoint || - timer_type_ == GPUTiming::kTimerTypeARB); + DCHECK(timer_type_ != GPUTiming::kTimerTypeInvalid); if (force_time_elapsed_query_) { // Replace with elapsed timer queries instead. @@ -467,7 +470,7 @@ GPUTimer::~GPUTimer() { void GPUTimer::Destroy(bool have_context) { if (have_context) { - if (!end_requested_) { + if (timer_state_ == kTimerState_WaitingForEnd) { DCHECK(gpu_timing_client_->gpu_timing_); DCHECK(elapsed_timer_result_.get()); gpu_timing_client_->gpu_timing_->EndElapsedTimeQuery( @@ -476,56 +479,81 @@ void GPUTimer::Destroy(bool have_context) { } } +void GPUTimer::Reset() { + // We can reset from any state other than when a Start() is waiting for End(). + DCHECK(timer_state_ != kTimerState_WaitingForEnd); + time_stamp_result_ = nullptr; + elapsed_timer_result_ = nullptr; + timer_state_ = kTimerState_Ready; +} + +void GPUTimer::QueryTimeStamp() { + DCHECK(gpu_timing_client_->gpu_timing_); + Reset(); + time_stamp_result_ = gpu_timing_client_->gpu_timing_->DoTimeStampQuery(); + timer_state_ = kTimerState_WaitingForResult; +} + void GPUTimer::Start() { DCHECK(gpu_timing_client_->gpu_timing_); + Reset(); if (!use_elapsed_timer_) time_stamp_result_ = gpu_timing_client_->gpu_timing_->DoTimeStampQuery(); elapsed_timer_result_ = gpu_timing_client_->gpu_timing_->BeginElapsedTimeQuery(); + timer_state_ = kTimerState_WaitingForEnd; } void GPUTimer::End() { + DCHECK(timer_state_ == kTimerState_WaitingForEnd); DCHECK(elapsed_timer_result_.get()); - end_requested_ = true; gpu_timing_client_->gpu_timing_->EndElapsedTimeQuery(elapsed_timer_result_); + timer_state_ = kTimerState_WaitingForResult; } bool GPUTimer::IsAvailable() { - if (!end_requested_) - return false; - if (!end_available_) { - DCHECK(elapsed_timer_result_.get()); - if (elapsed_timer_result_->IsAvailable()) { - end_available_ = true; + if (timer_state_ == kTimerState_WaitingForResult) { + // Elapsed timer are only used during start/end queries and always after + // the timestamp query. Otherwise only the timestamp is used. + scoped_refptr<QueryResult> result = + elapsed_timer_result_.get() ? + elapsed_timer_result_ : + time_stamp_result_; + + DCHECK(result.get()); + if (result->IsAvailable()) { + timer_state_ = kTimerState_ResultAvailable; } else { gpu_timing_client_->gpu_timing_->UpdateQueryResults(); - end_available_ = elapsed_timer_result_->IsAvailable(); + if (result->IsAvailable()) + timer_state_ = kTimerState_ResultAvailable; } } - return end_available_; + + return (timer_state_ == kTimerState_ResultAvailable); } void GPUTimer::GetStartEndTimestamps(int64* start, int64* end) { DCHECK(start && end); - DCHECK(elapsed_timer_result_.get()); + DCHECK(elapsed_timer_result_.get() || time_stamp_result_.get()); DCHECK(IsAvailable()); - if (time_stamp_result_.get()) { - DCHECK(time_stamp_result_->IsAvailable()); - const int64_t time_stamp = time_stamp_result_->GetStartValue(); - *start = time_stamp; - *end = time_stamp + elapsed_timer_result_->GetDelta(); - } else { - // Use estimation from elasped timer results. - *start = elapsed_timer_result_->GetStartValue(); - *end = elapsed_timer_result_->GetEndValue(); - } + const int64_t time_stamp = time_stamp_result_.get() ? + time_stamp_result_->GetStartValue() : + elapsed_timer_result_->GetStartValue(); + const int64_t elapsed_time = elapsed_timer_result_.get() ? + elapsed_timer_result_->GetDelta() : + 0; + + *start = time_stamp; + *end = time_stamp + elapsed_time; } int64 GPUTimer::GetDeltaElapsed() { - DCHECK(elapsed_timer_result_.get()); DCHECK(IsAvailable()); - return elapsed_timer_result_->GetDelta(); + if (elapsed_timer_result_.get()) + return elapsed_timer_result_->GetDelta(); + return 0; } GPUTimer::GPUTimer(scoped_refptr<GPUTimingClient> gpu_timing_client, diff --git a/ui/gl/gpu_timing.h b/ui/gl/gpu_timing.h index 08f9c03..5d72d7c 100644 --- a/ui/gl/gpu_timing.h +++ b/ui/gl/gpu_timing.h @@ -43,12 +43,9 @@ namespace gfx { class GLContextReal; -class GPUTiming; class GPUTimingClient; class GPUTimingImpl; class QueryResult; -class TimeElapsedTimerQuery; -class TimerQuery; class GPUTiming { public: @@ -86,6 +83,12 @@ class GL_EXPORT GPUTimer { // this object. void Destroy(bool have_context); + // Clears current queries. + void Reset(); + + // Start an instant timer, start and end will be equal. + void QueryTimeStamp(); + // Start a timer range. void Start(); void End(); @@ -102,8 +105,12 @@ class GL_EXPORT GPUTimer { bool use_elapsed_timer); bool use_elapsed_timer_ = false; - bool end_requested_ = false; - bool end_available_ = false; + enum TimerState { + kTimerState_Ready, + kTimerState_WaitingForEnd, + kTimerState_WaitingForResult, + kTimerState_ResultAvailable + } timer_state_ = kTimerState_Ready; scoped_refptr<GPUTimingClient> gpu_timing_client_; scoped_refptr<QueryResult> time_stamp_result_; scoped_refptr<QueryResult> elapsed_timer_result_; diff --git a/ui/gl/gpu_timing_fake.cc b/ui/gl/gpu_timing_fake.cc index e7c1df9..e329979 100644 --- a/ui/gl/gpu_timing_fake.cc +++ b/ui/gl/gpu_timing_fake.cc @@ -53,9 +53,48 @@ void GPUTimingFake::ExpectNoDisjointCalls(MockGLInterface& gl) { EXPECT_CALL(gl, GetIntegerv(GL_GPU_DISJOINT_EXT, _)).Times(Exactly(0)); } +void GPUTimingFake::ExpectGPUTimeStampQuery( + MockGLInterface& gl, bool elapsed_query) { + EXPECT_CALL(gl, GenQueries(1, NotNull())).Times(Exactly(1)) + .WillRepeatedly(Invoke(this, &GPUTimingFake::FakeGLGenQueries)); + + if (!elapsed_query) { + // Time Stamp based queries. + EXPECT_CALL(gl, GetInteger64v(GL_TIMESTAMP, _)) + .WillRepeatedly( + Invoke(this, &GPUTimingFake::FakeGLGetInteger64v)); + + EXPECT_CALL(gl, QueryCounter(_, GL_TIMESTAMP)).Times(Exactly(1)) + .WillRepeatedly( + Invoke(this, &GPUTimingFake::FakeGLQueryCounter)); + } else { + // Time Elapsed based queries. + EXPECT_CALL(gl, BeginQuery(GL_TIME_ELAPSED, _)).Times(Exactly(1)) + .WillRepeatedly( + Invoke(this, &GPUTimingFake::FakeGLBeginQuery)); + + EXPECT_CALL(gl, EndQuery(GL_TIME_ELAPSED)).Times(Exactly(1)) + .WillRepeatedly(Invoke(this, &GPUTimingFake::FakeGLEndQuery)); + } + + EXPECT_CALL(gl, GetQueryObjectuiv(_, GL_QUERY_RESULT_AVAILABLE, + NotNull())) + .WillRepeatedly( + Invoke(this, &GPUTimingFake::FakeGLGetQueryObjectuiv)); + + EXPECT_CALL(gl, GetQueryObjectui64v(_, GL_QUERY_RESULT, NotNull())) + .WillRepeatedly( + Invoke(this, &GPUTimingFake::FakeGLGetQueryObjectui64v)); + + EXPECT_CALL(gl, DeleteQueries(1, NotNull())).Times(AtLeast(1)) + .WillRepeatedly( + Invoke(this, &GPUTimingFake::FakeGLDeleteQueries)); +} + void GPUTimingFake::ExpectGPUTimerQuery( MockGLInterface& gl, bool elapsed_query) { - EXPECT_CALL(gl, GenQueries(1, NotNull())).Times(AtLeast(2)) + EXPECT_CALL(gl, GenQueries(1, NotNull())) + .Times(AtLeast(elapsed_query ? 1 : 2)) .WillRepeatedly(Invoke(this, &GPUTimingFake::FakeGLGenQueries)); if (!elapsed_query) { @@ -86,7 +125,8 @@ void GPUTimingFake::ExpectGPUTimerQuery( .WillRepeatedly( Invoke(this, &GPUTimingFake::FakeGLGetQueryObjectui64v)); - EXPECT_CALL(gl, DeleteQueries(1, NotNull())).Times(AtLeast(2)) + EXPECT_CALL(gl, DeleteQueries(1, NotNull())) + .Times(AtLeast(elapsed_query ? 1 : 2)) .WillRepeatedly( Invoke(this, &GPUTimingFake::FakeGLDeleteQueries)); } diff --git a/ui/gl/gpu_timing_fake.h b/ui/gl/gpu_timing_fake.h index 40c93f4..82deea9 100644 --- a/ui/gl/gpu_timing_fake.h +++ b/ui/gl/gpu_timing_fake.h @@ -32,6 +32,7 @@ class GPUTimingFake { void ExpectNoDisjointCalls(MockGLInterface& gl); // GPUTimer fake queries which can only be called once per setup. + void ExpectGPUTimeStampQuery(MockGLInterface& gl, bool elapsed_query); void ExpectGPUTimerQuery(MockGLInterface& gl, bool elapsed_query); void ExpectOffsetCalculationQuery(MockGLInterface& gl); void ExpectNoOffsetCalculationQuery(MockGLInterface& gl); diff --git a/ui/gl/gpu_timing_unittest.cc b/ui/gl/gpu_timing_unittest.cc index 9044394..946d231 100644 --- a/ui/gl/gpu_timing_unittest.cc +++ b/ui/gl/gpu_timing_unittest.cc @@ -11,6 +11,7 @@ #include "ui/gl/gl_surface.h" #include "ui/gl/gpu_preference.h" #include "ui/gl/gpu_timing.h" +#include "ui/gl/gpu_timing_fake.h" namespace gfx { @@ -19,24 +20,33 @@ class GPUTimingTest : public testing::Test { void SetUp() override { setup_ = false; fake_cpu_time_ = 0; - - CreateGPUTimingClient()->SetCpuTimeForTesting(base::Bind(&GetFakeCPUTime)); + cpu_time_bounded_ = false; } void TearDown() override { + if (setup_) { + MockGLInterface::SetGLInterface(NULL); + gfx::ClearGLBindings(); + } + setup_ = false; + cpu_time_bounded_ = false; context_ = nullptr; + gl_.reset(); + gpu_timing_fake_queries_.Reset(); } void SetupGLContext(const char* gl_version, const char* gl_extensions) { ASSERT_FALSE(setup_) << "Cannot setup GL context twice."; - gfx::SetGLGetProcAddressProc(gfx::MockGLInterface::GetGLProcAddress); - gfx::GLSurface::InitializeOneOffWithMockBindingsForTests(); - gl_.reset(new ::testing::StrictMock< ::gfx::MockGLInterface>()); - ::gfx::MockGLInterface::SetGLInterface(gl_.get()); + SetGLGetProcAddressProc(MockGLInterface::GetGLProcAddress); + GLSurface::InitializeOneOffWithMockBindingsForTests(); + gl_.reset(new ::testing::StrictMock<MockGLInterface>()); + MockGLInterface::SetGLInterface(gl_.get()); - context_ = new gfx::GLContextStubWithExtensions; + context_ = new GLContextStubWithExtensions; context_->AddExtensionsString(gl_extensions); context_->SetGLVersionString(gl_version); + gpu_timing_fake_queries_.Reset(); + GLSurface::InitializeDynamicMockBindingsForTests(context_.get()); setup_ = true; } @@ -45,7 +55,13 @@ class GPUTimingTest : public testing::Test { if (!setup_) { SetupGLContext("2.0", ""); } - return context_->CreateGPUTimingClient(); + + scoped_refptr<GPUTimingClient> client = context_->CreateGPUTimingClient(); + if (!cpu_time_bounded_) { + client->SetCpuTimeForTesting(base::Bind(&GetFakeCPUTime)); + cpu_time_bounded_ = true; + } + return client; } void SetFakeCPUTime(int64_t fake_cpu_time) { @@ -57,12 +73,13 @@ class GPUTimingTest : public testing::Test { return fake_cpu_time_; } - private: static int64_t fake_cpu_time_; bool setup_ = false; - scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_; - scoped_refptr<gfx::GLContextStubWithExtensions> context_; + bool cpu_time_bounded_ = false; + scoped_ptr< ::testing::StrictMock<MockGLInterface> > gl_; + scoped_refptr<GLContextStubWithExtensions> context_; + GPUTimingFake gpu_timing_fake_queries_; }; int64_t GPUTimingTest::fake_cpu_time_ = 0; @@ -95,4 +112,65 @@ TEST_F(GPUTimingTest, ForceTimeElapsedQuery) { EXPECT_TRUE(client2->IsForceTimeElapsedQuery()); } +TEST_F(GPUTimingTest, QueryTimeStampTest) { + SetupGLContext("3.2", "GL_ARB_timer_query"); + scoped_refptr<GPUTimingClient> client = CreateGPUTimingClient(); + scoped_ptr<GPUTimer> gpu_timer = client->CreateGPUTimer(false); + + SetFakeCPUTime(123); + gpu_timing_fake_queries_.SetCurrentGLTime( + 10 * base::Time::kNanosecondsPerMicrosecond); + gpu_timing_fake_queries_.ExpectGPUTimeStampQuery(*gl_, false); + + gpu_timer->QueryTimeStamp(); + + SetFakeCPUTime(122); + gpu_timing_fake_queries_.SetCurrentGLTime( + 9 * base::Time::kNanosecondsPerMicrosecond); + EXPECT_FALSE(gpu_timer->IsAvailable()); + + SetFakeCPUTime(124); + gpu_timing_fake_queries_.SetCurrentGLTime( + 11 * base::Time::kNanosecondsPerMicrosecond); + EXPECT_TRUE(gpu_timer->IsAvailable()); + EXPECT_EQ(0, gpu_timer->GetDeltaElapsed()); + + int64 start, end; + gpu_timer->GetStartEndTimestamps(&start, &end); + EXPECT_EQ(123, start); + EXPECT_EQ(123, end); +} + +TEST_F(GPUTimingTest, QueryTimeStampUsingElapsedTest) { + // Test timestamp queries using GL_EXT_timer_query which does not support + // timestamp queries. Internally we fall back to time elapsed queries. + SetupGLContext("3.2", "GL_EXT_timer_query"); + scoped_refptr<GPUTimingClient> client = CreateGPUTimingClient(); + scoped_ptr<GPUTimer> gpu_timer = client->CreateGPUTimer(false); + ASSERT_TRUE(client->IsForceTimeElapsedQuery()); + + SetFakeCPUTime(123); + gpu_timing_fake_queries_.SetCurrentGLTime( + 10 * base::Time::kNanosecondsPerMicrosecond); + gpu_timing_fake_queries_.ExpectGPUTimeStampQuery(*gl_, true); + + gpu_timer->QueryTimeStamp(); + + SetFakeCPUTime(122); + gpu_timing_fake_queries_.SetCurrentGLTime( + 9 * base::Time::kNanosecondsPerMicrosecond); + EXPECT_FALSE(gpu_timer->IsAvailable()); + + SetFakeCPUTime(124); + gpu_timing_fake_queries_.SetCurrentGLTime( + 11 * base::Time::kNanosecondsPerMicrosecond); + EXPECT_TRUE(gpu_timer->IsAvailable()); + EXPECT_EQ(0, gpu_timer->GetDeltaElapsed()); + + int64 start, end; + gpu_timer->GetStartEndTimestamps(&start, &end); + EXPECT_EQ(123, start); + EXPECT_EQ(123, end); +} + } // namespace gpu |