1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ui/gl/gpu_timing_fake.h"
6
7 #include "base/time/time.h"
8 #include "testing/gtest/include/gtest/gtest.h"
9 #include "ui/gl/gl_mock.h"
10
11 namespace gl {
12
13 using ::testing::_;
14 using ::testing::AtLeast;
15 using ::testing::AtMost;
16 using ::testing::Exactly;
17 using ::testing::Invoke;
18 using ::testing::NotNull;
19 using ::testing::DoAll;
20 using ::testing::Return;
21 using ::testing::SetArgPointee;
22
23 int64_t GPUTimingFake::fake_cpu_time_ = 0;
24
GPUTimingFake()25 GPUTimingFake::GPUTimingFake() {
26 Reset();
27 }
28
~GPUTimingFake()29 GPUTimingFake::~GPUTimingFake() {
30 }
31
Reset()32 void GPUTimingFake::Reset() {
33 current_gl_time_ = 0;
34 gl_cpu_time_offset_ = 0;
35 next_query_id_ = 23;
36 allocated_queries_.clear();
37 query_results_.clear();
38 current_elapsed_query_.Reset();
39
40 fake_cpu_time_ = 0;
41 }
42
GetFakeCPUTime()43 int64_t GPUTimingFake::GetFakeCPUTime() {
44 return fake_cpu_time_;
45 }
46
SetCPUGLOffset(int64_t offset)47 void GPUTimingFake::SetCPUGLOffset(int64_t offset) {
48 gl_cpu_time_offset_ = offset;
49 }
50
SetCurrentCPUTime(int64_t current_time)51 void GPUTimingFake::SetCurrentCPUTime(int64_t current_time) {
52 fake_cpu_time_ = current_time;
53 current_gl_time_ = (fake_cpu_time_ + gl_cpu_time_offset_) *
54 base::Time::kNanosecondsPerMicrosecond;
55 }
56
SetCurrentGLTime(GLint64 current_time)57 void GPUTimingFake::SetCurrentGLTime(GLint64 current_time) {
58 current_gl_time_ = current_time;
59 fake_cpu_time_ = (current_gl_time_ / base::Time::kNanosecondsPerMicrosecond) -
60 gl_cpu_time_offset_;
61 }
62
SetDisjoint()63 void GPUTimingFake::SetDisjoint() {
64 disjointed_ = true;
65 }
66
ExpectGetErrorCalls(MockGLInterface & gl)67 void GPUTimingFake::ExpectGetErrorCalls(MockGLInterface& gl) {
68 EXPECT_CALL(gl, GetError()).Times(AtLeast(0))
69 .WillRepeatedly(Invoke(this, &GPUTimingFake::FakeGLGetError));
70 }
71
ExpectDisjointCalls(MockGLInterface & gl)72 void GPUTimingFake::ExpectDisjointCalls(MockGLInterface& gl) {
73 EXPECT_CALL(gl, GetIntegerv(GL_GPU_DISJOINT_EXT, _)).Times(AtLeast(1))
74 .WillRepeatedly(Invoke(this, &GPUTimingFake::FakeGLGetIntegerv));
75 }
76
ExpectNoDisjointCalls(MockGLInterface & gl)77 void GPUTimingFake::ExpectNoDisjointCalls(MockGLInterface& gl) {
78 EXPECT_CALL(gl, GetIntegerv(GL_GPU_DISJOINT_EXT, _)).Times(Exactly(0));
79 }
80
ExpectGPUTimeStampQuery(MockGLInterface & gl,bool elapsed_query)81 void GPUTimingFake::ExpectGPUTimeStampQuery(MockGLInterface& gl,
82 bool elapsed_query) {
83 EXPECT_CALL(gl, GenQueries(1, NotNull()))
84 .WillOnce(Invoke(this, &GPUTimingFake::FakeGLGenQueries));
85
86 EXPECT_CALL(gl, GetQueryiv(GL_TIMESTAMP, GL_QUERY_COUNTER_BITS, NotNull()))
87 .WillRepeatedly(DoAll(SetArgPointee<2>(64), Return()));
88 if (!elapsed_query) {
89 // Time Stamp based queries.
90 EXPECT_CALL(gl, GetInteger64v(GL_TIMESTAMP, _))
91 .WillRepeatedly(
92 Invoke(this, &GPUTimingFake::FakeGLGetInteger64v));
93
94 EXPECT_CALL(gl, QueryCounter(_, GL_TIMESTAMP)).Times(Exactly(1))
95 .WillRepeatedly(
96 Invoke(this, &GPUTimingFake::FakeGLQueryCounter));
97 } else {
98 // Time Elapsed based queries.
99 EXPECT_CALL(gl, BeginQuery(GL_TIME_ELAPSED, _)).Times(Exactly(1))
100 .WillRepeatedly(
101 Invoke(this, &GPUTimingFake::FakeGLBeginQuery));
102
103 EXPECT_CALL(gl, EndQuery(GL_TIME_ELAPSED)).Times(Exactly(1))
104 .WillRepeatedly(Invoke(this, &GPUTimingFake::FakeGLEndQuery));
105 }
106
107 EXPECT_CALL(gl, GetQueryObjectuiv(_, GL_QUERY_RESULT_AVAILABLE,
108 NotNull()))
109 .WillRepeatedly(
110 Invoke(this, &GPUTimingFake::FakeGLGetQueryObjectuiv));
111
112 EXPECT_CALL(gl, GetQueryObjectui64v(_, GL_QUERY_RESULT, NotNull()))
113 .WillRepeatedly(
114 Invoke(this, &GPUTimingFake::FakeGLGetQueryObjectui64v));
115
116 EXPECT_CALL(gl, DeleteQueries(1, NotNull()))
117 .WillOnce(Invoke(this, &GPUTimingFake::FakeGLDeleteQueries))
118 .RetiresOnSaturation();
119 }
120
ExpectGPUTimerQuery(MockGLInterface & gl,bool elapsed_query)121 void GPUTimingFake::ExpectGPUTimerQuery(
122 MockGLInterface& gl, bool elapsed_query) {
123 EXPECT_CALL(gl, GenQueries(1, NotNull()))
124 .Times(AtLeast(elapsed_query ? 1 : 2))
125 .WillRepeatedly(Invoke(this, &GPUTimingFake::FakeGLGenQueries));
126
127 if (!elapsed_query) {
128 // Time Stamp based queries.
129 EXPECT_CALL(gl, GetQueryiv(GL_TIMESTAMP, GL_QUERY_COUNTER_BITS, NotNull()))
130 .WillRepeatedly(DoAll(SetArgPointee<2>(64), Return()));
131
132 EXPECT_CALL(gl, GetInteger64v(GL_TIMESTAMP, _))
133 .WillRepeatedly(
134 Invoke(this, &GPUTimingFake::FakeGLGetInteger64v));
135
136 EXPECT_CALL(gl, QueryCounter(_, GL_TIMESTAMP)).Times(AtLeast(1))
137 .WillRepeatedly(
138 Invoke(this, &GPUTimingFake::FakeGLQueryCounter));
139 }
140
141 // Time Elapsed based queries.
142 EXPECT_CALL(gl, BeginQuery(GL_TIME_ELAPSED, _))
143 .WillRepeatedly(
144 Invoke(this, &GPUTimingFake::FakeGLBeginQuery));
145
146 EXPECT_CALL(gl, EndQuery(GL_TIME_ELAPSED))
147 .WillRepeatedly(Invoke(this, &GPUTimingFake::FakeGLEndQuery));
148
149 EXPECT_CALL(gl, GetQueryObjectuiv(_, GL_QUERY_RESULT_AVAILABLE,
150 NotNull()))
151 .WillRepeatedly(
152 Invoke(this, &GPUTimingFake::FakeGLGetQueryObjectuiv));
153
154 EXPECT_CALL(gl, GetQueryObjectui64v(_, GL_QUERY_RESULT, NotNull()))
155 .WillRepeatedly(
156 Invoke(this, &GPUTimingFake::FakeGLGetQueryObjectui64v));
157
158 EXPECT_CALL(gl, DeleteQueries(1, NotNull()))
159 .Times(AtLeast(elapsed_query ? 1 : 2))
160 .WillRepeatedly(
161 Invoke(this, &GPUTimingFake::FakeGLDeleteQueries));
162 }
163
ExpectOffsetCalculationQuery(MockGLInterface & gl)164 void GPUTimingFake::ExpectOffsetCalculationQuery(
165 MockGLInterface& gl) {
166 EXPECT_CALL(gl, GetInteger64v(GL_TIMESTAMP, NotNull()))
167 .Times(AtMost(1))
168 .WillRepeatedly(
169 Invoke(this, &GPUTimingFake::FakeGLGetInteger64v));
170 }
171
ExpectNoOffsetCalculationQuery(MockGLInterface & gl)172 void GPUTimingFake::ExpectNoOffsetCalculationQuery(
173 MockGLInterface& gl) {
174 EXPECT_CALL(gl, GetInteger64v(GL_TIMESTAMP, NotNull())).Times(Exactly(0));
175 }
176
FakeGLGenQueries(GLsizei n,GLuint * ids)177 void GPUTimingFake::FakeGLGenQueries(GLsizei n, GLuint* ids) {
178 for (GLsizei i = 0; i < n; i++) {
179 ids[i] = next_query_id_++;
180 allocated_queries_.insert(ids[i]);
181 }
182 }
183
FakeGLDeleteQueries(GLsizei n,const GLuint * ids)184 void GPUTimingFake::FakeGLDeleteQueries(GLsizei n, const GLuint* ids) {
185 for (GLsizei i = 0; i < n; i++) {
186 allocated_queries_.erase(ids[i]);
187 query_results_.erase(ids[i]);
188 if (current_elapsed_query_.query_id_ == ids[i])
189 current_elapsed_query_.Reset();
190 }
191 }
192
FakeGLBeginQuery(GLenum target,GLuint id)193 void GPUTimingFake::FakeGLBeginQuery(GLenum target, GLuint id) {
194 switch(target) {
195 case GL_TIME_ELAPSED:
196 ASSERT_FALSE(current_elapsed_query_.active_);
197 current_elapsed_query_.Reset();
198 current_elapsed_query_.active_ = true;
199 current_elapsed_query_.query_id_ = id;
200 current_elapsed_query_.begin_time_ = current_gl_time_;
201 break;
202 default:
203 FAIL() << "Invalid target passed to BeginQuery: " << target;
204 }
205 }
206
FakeGLEndQuery(GLenum target)207 void GPUTimingFake::FakeGLEndQuery(GLenum target) {
208 switch(target) {
209 case GL_TIME_ELAPSED: {
210 ASSERT_TRUE(current_elapsed_query_.active_);
211 QueryResult& query = query_results_[current_elapsed_query_.query_id_];
212 query.type_ = QueryResult::kQueryResultType_Elapsed;
213 query.begin_time_ = current_elapsed_query_.begin_time_;
214 query.value_ = current_gl_time_;
215 current_elapsed_query_.active_ = false;
216 } break;
217 default:
218 FAIL() << "Invalid target passed to BeginQuery: " << target;
219 }
220 }
221
FakeGLGetQueryObjectuiv(GLuint id,GLenum pname,GLuint * params)222 void GPUTimingFake::FakeGLGetQueryObjectuiv(GLuint id, GLenum pname,
223 GLuint* params) {
224 switch (pname) {
225 case GL_QUERY_RESULT_AVAILABLE: {
226 auto it = query_results_.find(id);
227 if (it != query_results_.end() && it->second.value_ <= current_gl_time_)
228 *params = 1;
229 else
230 *params = 0;
231 } break;
232 default:
233 FAIL() << "Invalid variable passed to GetQueryObjectuiv: " << pname;
234 }
235 }
236
FakeGLQueryCounter(GLuint id,GLenum target)237 void GPUTimingFake::FakeGLQueryCounter(GLuint id, GLenum target) {
238 switch (target) {
239 case GL_TIMESTAMP: {
240 ASSERT_TRUE(allocated_queries_.find(id) != allocated_queries_.end());
241 QueryResult& query = query_results_[id];
242 query.type_ = QueryResult::kQueryResultType_TimeStamp;
243 query.value_ = current_gl_time_;
244 } break;
245
246 default:
247 FAIL() << "Invalid variable passed to QueryCounter: " << target;
248 }
249 }
250
FakeGLGetInteger64v(GLenum pname,GLint64 * data)251 void GPUTimingFake::FakeGLGetInteger64v(GLenum pname, GLint64 * data) {
252 switch (pname) {
253 case GL_TIMESTAMP:
254 *data = current_gl_time_;
255 break;
256 default:
257 FAIL() << "Invalid variable passed to GetInteger64v: " << pname;
258 }
259 }
260
FakeGLGetQueryObjectui64v(GLuint id,GLenum pname,GLuint64 * params)261 void GPUTimingFake::FakeGLGetQueryObjectui64v(GLuint id, GLenum pname,
262 GLuint64* params) {
263 switch (pname) {
264 case GL_QUERY_RESULT: {
265 auto it = query_results_.find(id);
266 ASSERT_TRUE(it != query_results_.end());
267 switch (it->second.type_) {
268 case QueryResult::kQueryResultType_TimeStamp:
269 *params = it->second.value_;
270 break;
271 case QueryResult::kQueryResultType_Elapsed:
272 *params = it->second.value_ - it->second.begin_time_;
273 break;
274 default:
275 FAIL() << "Invalid Query Result Type: " << it->second.type_;
276 }
277 } break;
278 default:
279 FAIL() << "Invalid variable passed to GetQueryObjectui64v: " << pname;
280 }
281 }
282
FakeGLGetIntegerv(GLenum pname,GLint * params)283 void GPUTimingFake::FakeGLGetIntegerv(GLenum pname, GLint* params) {
284 switch (pname) {
285 case GL_GPU_DISJOINT_EXT:
286 *params = static_cast<GLint>(disjointed_);
287 disjointed_ = false;
288 break;
289 default:
290 FAIL() << "Invalid variable passed to GetIntegerv: " << pname;
291 }
292 }
293
FakeGLGetError()294 GLenum GPUTimingFake::FakeGLGetError() {
295 return GL_NO_ERROR;
296 }
297
298 } // namespace gl
299