summaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
Diffstat (limited to 'ui')
-rw-r--r--ui/gl/gpu_timing.cc78
-rw-r--r--ui/gl/gpu_timing.h17
-rw-r--r--ui/gl/gpu_timing_fake.cc44
-rw-r--r--ui/gl/gpu_timing_fake.h1
-rw-r--r--ui/gl/gpu_timing_unittest.cc100
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