// Copyright 2015 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 "ui/gl/gpu_timing_fake.h" #include "base/time/time.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gl/gl_mock.h" namespace gfx { using ::testing::_; using ::testing::AtLeast; using ::testing::AtMost; using ::testing::Exactly; using ::testing::Invoke; using ::testing::NotNull; using ::testing::DoAll; using ::testing::Return; using ::testing::SetArgPointee; int64_t GPUTimingFake::fake_cpu_time_ = 0; GPUTimingFake::GPUTimingFake() { Reset(); } GPUTimingFake::~GPUTimingFake() { } void GPUTimingFake::Reset() { current_gl_time_ = 0; gl_cpu_time_offset_ = 0; next_query_id_ = 23; allocated_queries_.clear(); query_results_.clear(); current_elapsed_query_.Reset(); fake_cpu_time_ = 0; } int64_t GPUTimingFake::GetFakeCPUTime() { return fake_cpu_time_; } void GPUTimingFake::SetCPUGLOffset(int64_t offset) { gl_cpu_time_offset_ = offset; } void GPUTimingFake::SetCurrentCPUTime(int64_t current_time) { fake_cpu_time_ = current_time; current_gl_time_ = (fake_cpu_time_ + gl_cpu_time_offset_) * base::Time::kNanosecondsPerMicrosecond; } void GPUTimingFake::SetCurrentGLTime(GLint64 current_time) { current_gl_time_ = current_time; fake_cpu_time_ = (current_gl_time_ / base::Time::kNanosecondsPerMicrosecond) - gl_cpu_time_offset_; } void GPUTimingFake::SetDisjoint() { disjointed_ = true; } void GPUTimingFake::ExpectGetErrorCalls(MockGLInterface& gl) { EXPECT_CALL(gl, GetError()).Times(AtLeast(0)) .WillRepeatedly(Invoke(this, &GPUTimingFake::FakeGLGetError)); } void GPUTimingFake::ExpectDisjointCalls(MockGLInterface& gl) { EXPECT_CALL(gl, GetIntegerv(GL_GPU_DISJOINT_EXT, _)).Times(AtLeast(1)) .WillRepeatedly(Invoke(this, &GPUTimingFake::FakeGLGetIntegerv)); } 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)); EXPECT_CALL(gl, GetQueryiv(GL_TIMESTAMP, GL_QUERY_COUNTER_BITS, NotNull())) .WillRepeatedly(DoAll(SetArgPointee<2>(64), Return())); 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(elapsed_query ? 1 : 2)) .WillRepeatedly(Invoke(this, &GPUTimingFake::FakeGLGenQueries)); if (!elapsed_query) { // Time Stamp based queries. EXPECT_CALL(gl, GetQueryiv(GL_TIMESTAMP, GL_QUERY_COUNTER_BITS, NotNull())) .WillRepeatedly(DoAll(SetArgPointee<2>(64), Return())); EXPECT_CALL(gl, GetInteger64v(GL_TIMESTAMP, _)) .WillRepeatedly( Invoke(this, &GPUTimingFake::FakeGLGetInteger64v)); EXPECT_CALL(gl, QueryCounter(_, GL_TIMESTAMP)).Times(AtLeast(1)) .WillRepeatedly( Invoke(this, &GPUTimingFake::FakeGLQueryCounter)); } // Time Elapsed based queries. EXPECT_CALL(gl, BeginQuery(GL_TIME_ELAPSED, _)) .WillRepeatedly( Invoke(this, &GPUTimingFake::FakeGLBeginQuery)); EXPECT_CALL(gl, EndQuery(GL_TIME_ELAPSED)) .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(elapsed_query ? 1 : 2)) .WillRepeatedly( Invoke(this, &GPUTimingFake::FakeGLDeleteQueries)); } void GPUTimingFake::ExpectOffsetCalculationQuery( MockGLInterface& gl) { EXPECT_CALL(gl, GetInteger64v(GL_TIMESTAMP, NotNull())) .Times(AtMost(1)) .WillRepeatedly( Invoke(this, &GPUTimingFake::FakeGLGetInteger64v)); } void GPUTimingFake::ExpectNoOffsetCalculationQuery( MockGLInterface& gl) { EXPECT_CALL(gl, GetInteger64v(GL_TIMESTAMP, NotNull())).Times(Exactly(0)); } void GPUTimingFake::FakeGLGenQueries(GLsizei n, GLuint* ids) { for (GLsizei i = 0; i < n; i++) { ids[i] = next_query_id_++; allocated_queries_.insert(ids[i]); } } void GPUTimingFake::FakeGLDeleteQueries(GLsizei n, const GLuint* ids) { for (GLsizei i = 0; i < n; i++) { allocated_queries_.erase(ids[i]); query_results_.erase(ids[i]); if (current_elapsed_query_.query_id_ == ids[i]) current_elapsed_query_.Reset(); } } void GPUTimingFake::FakeGLBeginQuery(GLenum target, GLuint id) { switch(target) { case GL_TIME_ELAPSED: ASSERT_FALSE(current_elapsed_query_.active_); current_elapsed_query_.Reset(); current_elapsed_query_.active_ = true; current_elapsed_query_.query_id_ = id; current_elapsed_query_.begin_time_ = current_gl_time_; break; default: FAIL() << "Invalid target passed to BeginQuery: " << target; } } void GPUTimingFake::FakeGLEndQuery(GLenum target) { switch(target) { case GL_TIME_ELAPSED: { ASSERT_TRUE(current_elapsed_query_.active_); QueryResult& query = query_results_[current_elapsed_query_.query_id_]; query.type_ = QueryResult::kQueryResultType_Elapsed; query.begin_time_ = current_elapsed_query_.begin_time_; query.value_ = current_gl_time_; current_elapsed_query_.active_ = false; } break; default: FAIL() << "Invalid target passed to BeginQuery: " << target; } } void GPUTimingFake::FakeGLGetQueryObjectuiv(GLuint id, GLenum pname, GLuint* params) { switch (pname) { case GL_QUERY_RESULT_AVAILABLE: { std::map::iterator it = query_results_.find(id); if (it != query_results_.end() && it->second.value_ <= current_gl_time_) *params = 1; else *params = 0; } break; default: FAIL() << "Invalid variable passed to GetQueryObjectuiv: " << pname; } } void GPUTimingFake::FakeGLQueryCounter(GLuint id, GLenum target) { switch (target) { case GL_TIMESTAMP: { ASSERT_TRUE(allocated_queries_.find(id) != allocated_queries_.end()); QueryResult& query = query_results_[id]; query.type_ = QueryResult::kQueryResultType_TimeStamp; query.value_ = current_gl_time_; } break; default: FAIL() << "Invalid variable passed to QueryCounter: " << target; } } void GPUTimingFake::FakeGLGetInteger64v(GLenum pname, GLint64 * data) { switch (pname) { case GL_TIMESTAMP: *data = current_gl_time_; break; default: FAIL() << "Invalid variable passed to GetInteger64v: " << pname; } } void GPUTimingFake::FakeGLGetQueryObjectui64v(GLuint id, GLenum pname, GLuint64* params) { switch (pname) { case GL_QUERY_RESULT: { std::map::iterator it = query_results_.find(id); ASSERT_TRUE(it != query_results_.end()); switch (it->second.type_) { case QueryResult::kQueryResultType_TimeStamp: *params = it->second.value_; break; case QueryResult::kQueryResultType_Elapsed: *params = it->second.value_ - it->second.begin_time_; break; default: FAIL() << "Invalid Query Result Type: " << it->second.type_; } } break; default: FAIL() << "Invalid variable passed to GetQueryObjectui64v: " << pname; } } void GPUTimingFake::FakeGLGetIntegerv(GLenum pname, GLint* params) { switch (pname) { case GL_GPU_DISJOINT_EXT: *params = static_cast(disjointed_); disjointed_ = false; break; default: FAIL() << "Invalid variable passed to GetIntegerv: " << pname; } } GLenum GPUTimingFake::FakeGLGetError() { return GL_NO_ERROR; } } // namespace gfx