1 // Copyright 2014 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.
9 #include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h"
10 #include "gpu/command_buffer/service/gpu_service_test.h"
11 #include "gpu/command_buffer/service/gpu_tracer.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "ui/gl/gl_mock.h"
14 #include "ui/gl/gpu_timing.h"
21 using ::testing::AtLeast
;
22 using ::testing::AtMost
;
23 using ::testing::Exactly
;
24 using ::testing::Invoke
;
25 using ::testing::NotNull
;
26 using ::testing::Return
;
28 int64 g_fakeCPUTime
= 0;
33 class MockOutputter
: public Outputter
{
36 MOCK_METHOD4(TraceDevice
,
37 void(const std::string
& category
, const std::string
& name
,
38 int64 start_time
, int64 end_time
));
40 MOCK_METHOD2(TraceServiceBegin
,
41 void(const std::string
& category
, const std::string
& name
));
43 MOCK_METHOD2(TraceServiceEnd
,
44 void(const std::string
& category
, const std::string
& name
));
57 alloced_queries_
.clear();
58 query_timestamp_
.clear();
61 void SetCurrentGLTime(GLint64 current_time
) { current_time_
= current_time
; }
62 void SetDisjoint() { disjointed_
= true; }
64 void GenQueriesARB(GLsizei n
, GLuint
* ids
) {
65 for (GLsizei i
= 0; i
< n
; i
++) {
66 ids
[i
] = next_query_id_
++;
67 alloced_queries_
.insert(ids
[i
]);
71 void DeleteQueriesARB(GLsizei n
, const GLuint
* ids
) {
72 for (GLsizei i
= 0; i
< n
; i
++) {
73 alloced_queries_
.erase(ids
[i
]);
74 query_timestamp_
.erase(ids
[i
]);
78 void GetQueryObjectivARB(GLuint id
, GLenum pname
, GLint
* params
) {
80 case GL_QUERY_RESULT_AVAILABLE
: {
81 std::map
<GLuint
, GLint64
>::iterator it
= query_timestamp_
.find(id
);
82 if (it
!= query_timestamp_
.end() && it
->second
<= current_time_
)
89 FAIL() << "Invalid variable passed to GetQueryObjectivARB: " << pname
;
93 void QueryCounter(GLuint id
, GLenum target
) {
96 ASSERT_TRUE(alloced_queries_
.find(id
) != alloced_queries_
.end());
97 query_timestamp_
[id
] = current_time_
;
100 FAIL() << "Invalid variable passed to QueryCounter: " << target
;
104 void GetInteger64v(GLenum pname
, GLint64
* data
) {
107 *data
= current_time_
;
110 FAIL() << "Invalid variable passed to GetInteger64v: " << pname
;
114 void GetQueryObjectui64v(GLuint id
, GLenum pname
, GLuint64
* params
) {
116 case GL_QUERY_RESULT
:
117 ASSERT_TRUE(query_timestamp_
.find(id
) != query_timestamp_
.end());
118 *params
= query_timestamp_
.find(id
)->second
;
121 FAIL() << "Invalid variable passed to GetQueryObjectui64v: " << pname
;
125 void GetIntegerv(GLenum pname
, GLint
* params
) {
127 case GL_GPU_DISJOINT_EXT
:
128 *params
= static_cast<GLint
>(disjointed_
);
132 FAIL() << "Invalid variable passed to GetIntegerv: " << pname
;
144 bool disjointed_
= false;
145 GLint64 current_time_
= 0;
146 GLuint next_query_id_
= 0;
147 std::set
<GLuint
> alloced_queries_
;
148 std::map
<GLuint
, GLint64
> query_timestamp_
;
151 class GPUTracerTester
: public GPUTracer
{
153 explicit GPUTracerTester(gles2::GLES2Decoder
* decoder
)
154 : GPUTracer(decoder
), tracing_enabled_(0) {
155 gpu_timing_client_
->SetCpuTimeForTesting(base::Bind(&FakeCpuTime
));
157 // Force tracing to be dependent on our mock variable here.
158 gpu_trace_srv_category
= &tracing_enabled_
;
159 gpu_trace_dev_category
= &tracing_enabled_
;
162 ~GPUTracerTester() override
{}
164 void SetTracingEnabled(bool enabled
) {
165 tracing_enabled_
= enabled
? 1 : 0;
168 void SetOutputter(scoped_refptr
<Outputter
> outputter
) {
169 set_outputter_
= outputter
;
173 scoped_refptr
<Outputter
> CreateOutputter(const std::string
& name
) override
{
174 if (set_outputter_
.get()) {
175 return set_outputter_
;
177 return new MockOutputter();
180 void PostTask() override
{
181 // Process synchronously.
185 unsigned char tracing_enabled_
;
187 scoped_refptr
<Outputter
> set_outputter_
;
190 class BaseGpuTest
: public GpuServiceTest
{
192 explicit BaseGpuTest(gfx::GPUTiming::TimerType test_timer_type
)
193 : test_timer_type_(test_timer_type
) {
197 void SetUp() override
{
199 const char* gl_version
= "3.2";
200 const char* extensions
= "";
201 if (GetTimerType() == gfx::GPUTiming::kTimerTypeDisjoint
) {
202 gl_version
= "opengl es 3.0";
203 extensions
= "GL_EXT_disjoint_timer_query";
204 } else if (GetTimerType() == gfx::GPUTiming::kTimerTypeARB
) {
205 // TODO(sievers): The tracer should not depend on ARB_occlusion_query.
206 // Try merge Query APIs (core, ARB, EXT) into a single binding each.
207 extensions
= "GL_ARB_timer_query GL_ARB_occlusion_query";
209 GpuServiceTest::SetUpWithGLVersion(gl_version
, extensions
);
210 gpu_timing_client_
= GetGLContext()->CreateGPUTimingClient();
211 gpu_timing_client_
->SetCpuTimeForTesting(base::Bind(&FakeCpuTime
));
212 gl_fake_queries_
.Reset();
214 outputter_ref_
= new MockOutputter();
217 void TearDown() override
{
218 outputter_ref_
= NULL
;
220 gl_fake_queries_
.Reset();
221 GpuServiceTest::TearDown();
224 void ExpectTraceQueryMocks() {
225 if (GetTimerType() != gfx::GPUTiming::kTimerTypeInvalid
) {
226 // Delegate query APIs used by GPUTrace to a GlFakeQueries
227 EXPECT_CALL(*gl_
, GenQueriesARB(2, NotNull())).Times(AtLeast(1))
229 Invoke(&gl_fake_queries_
, &GlFakeQueries::GenQueriesARB
));
231 EXPECT_CALL(*gl_
, GetQueryObjectivARB(_
, GL_QUERY_RESULT_AVAILABLE
,
234 Invoke(&gl_fake_queries_
, &GlFakeQueries::GetQueryObjectivARB
));
236 EXPECT_CALL(*gl_
, GetInteger64v(GL_TIMESTAMP
, _
))
238 Invoke(&gl_fake_queries_
, &GlFakeQueries::GetInteger64v
));
240 EXPECT_CALL(*gl_
, QueryCounter(_
, GL_TIMESTAMP
)).Times(AtLeast(2))
242 Invoke(&gl_fake_queries_
, &GlFakeQueries::QueryCounter
));
244 EXPECT_CALL(*gl_
, GetQueryObjectui64v(_
, GL_QUERY_RESULT
, NotNull()))
246 Invoke(&gl_fake_queries_
,
247 &GlFakeQueries::GetQueryObjectui64v
));
249 EXPECT_CALL(*gl_
, DeleteQueriesARB(2, NotNull())).Times(AtLeast(1))
251 Invoke(&gl_fake_queries_
, &GlFakeQueries::DeleteQueriesARB
));
255 void ExpectOutputterBeginMocks(MockOutputter
* outputter
,
256 const std::string
& category
,
257 const std::string
& name
) {
258 EXPECT_CALL(*outputter
,
259 TraceServiceBegin(category
, name
));
262 void ExpectOutputterEndMocks(MockOutputter
* outputter
,
263 const std::string
& category
,
264 const std::string
& name
, int64 expect_start_time
,
265 int64 expect_end_time
,
267 EXPECT_CALL(*outputter
,
268 TraceServiceEnd(category
, name
));
271 EXPECT_CALL(*outputter
,
272 TraceDevice(category
, name
,
273 expect_start_time
, expect_end_time
))
276 EXPECT_CALL(*outputter
, TraceDevice(category
, name
,
277 expect_start_time
, expect_end_time
))
282 void ExpectOutputterMocks(MockOutputter
* outputter
,
283 const std::string
& category
,
284 const std::string
& name
, int64 expect_start_time
,
285 int64 expect_end_time
) {
286 ExpectOutputterBeginMocks(outputter
, category
, name
);
287 bool valid_timer
= GetTimerType() != gfx::GPUTiming::kTimerTypeInvalid
;
288 ExpectOutputterEndMocks(outputter
, category
, name
, expect_start_time
,
289 expect_end_time
, valid_timer
);
292 void ExpectTracerOffsetQueryMocks() {
293 // Disjoint check should only be called by kTracerTypeDisjointTimer type.
294 if (GetTimerType() == gfx::GPUTiming::kTimerTypeDisjoint
) {
295 EXPECT_CALL(*gl_
, GetIntegerv(GL_GPU_DISJOINT_EXT
, _
)).Times(AtLeast(1))
297 Invoke(&gl_fake_queries_
, &GlFakeQueries::GetIntegerv
));
299 EXPECT_CALL(*gl_
, GetIntegerv(GL_GPU_DISJOINT_EXT
, _
)).Times(Exactly(0));
302 if (GetTimerType() != gfx::GPUTiming::kTimerTypeARB
) {
303 EXPECT_CALL(*gl_
, GetInteger64v(GL_TIMESTAMP
, NotNull()))
306 EXPECT_CALL(*gl_
, GetInteger64v(GL_TIMESTAMP
, NotNull()))
309 Invoke(&gl_fake_queries_
, &GlFakeQueries::GetInteger64v
));
313 gfx::GPUTiming::TimerType
GetTimerType() { return test_timer_type_
; }
315 gfx::GPUTiming::TimerType test_timer_type_
;
316 GlFakeQueries gl_fake_queries_
;
318 scoped_refptr
<gfx::GPUTimingClient
> gpu_timing_client_
;
319 scoped_refptr
<MockOutputter
> outputter_ref_
;
322 // Test GPUTrace calls all the correct gl calls.
323 class BaseGpuTraceTest
: public BaseGpuTest
{
325 explicit BaseGpuTraceTest(gfx::GPUTiming::TimerType test_timer_type
)
326 : BaseGpuTest(test_timer_type
) {}
330 const std::string
category_name("trace_category");
331 const std::string
trace_name("trace_test");
332 const int64 offset_time
= 3231;
333 const GLint64 start_timestamp
= 7 * base::Time::kNanosecondsPerMicrosecond
;
334 const GLint64 end_timestamp
= 32 * base::Time::kNanosecondsPerMicrosecond
;
335 const int64 expect_start_time
=
336 (start_timestamp
/ base::Time::kNanosecondsPerMicrosecond
) +
338 const int64 expect_end_time
=
339 (end_timestamp
/ base::Time::kNanosecondsPerMicrosecond
) + offset_time
;
341 ExpectTraceQueryMocks();
342 ExpectOutputterMocks(outputter_ref_
.get(), category_name
, trace_name
,
343 expect_start_time
, expect_end_time
);
345 scoped_refptr
<GPUTrace
> trace
= new GPUTrace(
346 outputter_ref_
, gpu_timing_client_
.get(),
347 category_name
, trace_name
, true);
349 gl_fake_queries_
.SetCurrentGLTime(start_timestamp
);
350 g_fakeCPUTime
= expect_start_time
;
353 // Shouldn't be available before End() call
354 gl_fake_queries_
.SetCurrentGLTime(end_timestamp
);
355 g_fakeCPUTime
= expect_end_time
;
356 EXPECT_FALSE(trace
->IsAvailable());
360 // Shouldn't be available until the queries complete
361 gl_fake_queries_
.SetCurrentGLTime(end_timestamp
-
362 base::Time::kNanosecondsPerMicrosecond
);
363 EXPECT_FALSE(trace
->IsAvailable());
365 // Now it should be available
366 gl_fake_queries_
.SetCurrentGLTime(end_timestamp
);
367 EXPECT_TRUE(trace
->IsAvailable());
369 // Proces should output expected Trace results to MockOutputter
372 outputter_ref_
= NULL
;
376 class GpuARBTimerTraceTest
: public BaseGpuTraceTest
{
378 GpuARBTimerTraceTest() : BaseGpuTraceTest(gfx::GPUTiming::kTimerTypeARB
) {}
381 class GpuDisjointTimerTraceTest
: public BaseGpuTraceTest
{
383 GpuDisjointTimerTraceTest()
384 : BaseGpuTraceTest(gfx::GPUTiming::kTimerTypeDisjoint
) {}
387 TEST_F(GpuARBTimerTraceTest
, ARBTimerTraceTest
) {
391 TEST_F(GpuDisjointTimerTraceTest
, DisjointTimerTraceTest
) {
395 // Test GPUTracer calls all the correct gl calls.
396 class BaseGpuTracerTest
: public BaseGpuTest
{
398 explicit BaseGpuTracerTest(gfx::GPUTiming::TimerType test_timer_type
)
399 : BaseGpuTest(test_timer_type
) {}
401 void DoBasicTracerTest() {
402 ExpectTracerOffsetQueryMocks();
404 MockGLES2Decoder decoder
;
405 EXPECT_CALL(decoder
, GetGLContext()).WillOnce(Return(GetGLContext()));
406 GPUTracerTester
tracer(&decoder
);
407 tracer
.SetTracingEnabled(true);
409 tracer
.SetOutputter(outputter_ref_
);
411 ASSERT_TRUE(tracer
.BeginDecoding());
412 ASSERT_TRUE(tracer
.EndDecoding());
414 outputter_ref_
= NULL
;
417 void DoTracerMarkersTest() {
418 ExpectTracerOffsetQueryMocks();
420 EXPECT_CALL(*gl_
, GetError()).Times(AtLeast(0))
422 Invoke(&gl_fake_queries_
, &GlFakeQueries::GetError
));
424 const std::string
category_name("trace_category");
425 const std::string
trace_name("trace_test");
426 const int64 offset_time
= 3231;
427 const GLint64 start_timestamp
= 7 * base::Time::kNanosecondsPerMicrosecond
;
428 const GLint64 end_timestamp
= 32 * base::Time::kNanosecondsPerMicrosecond
;
429 const int64 expect_start_time
=
430 (start_timestamp
/ base::Time::kNanosecondsPerMicrosecond
) +
432 const int64 expect_end_time
=
433 (end_timestamp
/ base::Time::kNanosecondsPerMicrosecond
) + offset_time
;
435 MockGLES2Decoder decoder
;
436 EXPECT_CALL(decoder
, GetGLContext()).WillOnce(Return(GetGLContext()));
437 GPUTracerTester
tracer(&decoder
);
438 tracer
.SetTracingEnabled(true);
440 tracer
.SetOutputter(outputter_ref_
);
442 gl_fake_queries_
.SetCurrentGLTime(start_timestamp
);
443 g_fakeCPUTime
= expect_start_time
;
445 ASSERT_TRUE(tracer
.BeginDecoding());
447 ExpectTraceQueryMocks();
449 // This will test multiple marker sources which overlap one another.
450 for (int i
= 0; i
< NUM_TRACER_SOURCES
; ++i
) {
451 // Set times so each source has a different time.
452 gl_fake_queries_
.SetCurrentGLTime(
454 (i
* base::Time::kNanosecondsPerMicrosecond
));
455 g_fakeCPUTime
= expect_start_time
+ i
;
457 // Each trace name should be different to differentiate.
458 const char num_char
= static_cast<char>('0' + i
);
459 std::string source_category
= category_name
+ num_char
;
460 std::string source_trace_name
= trace_name
+ num_char
;
462 ExpectOutputterBeginMocks(outputter_ref_
.get(),
463 source_category
, source_trace_name
);
465 const GpuTracerSource source
= static_cast<GpuTracerSource
>(i
);
466 ASSERT_TRUE(tracer
.Begin(source_category
, source_trace_name
, source
));
469 for (int i
= 0; i
< NUM_TRACER_SOURCES
; ++i
) {
470 // Set times so each source has a different time.
471 gl_fake_queries_
.SetCurrentGLTime(
473 (i
* base::Time::kNanosecondsPerMicrosecond
));
474 g_fakeCPUTime
= expect_end_time
+ i
;
476 // Each trace name should be different to differentiate.
477 const char num_char
= static_cast<char>('0' + i
);
478 std::string source_category
= category_name
+ num_char
;
479 std::string source_trace_name
= trace_name
+ num_char
;
481 bool valid_timer
= GetTimerType() != gfx::GPUTiming::kTimerTypeInvalid
;
482 ExpectOutputterEndMocks(outputter_ref_
.get(), source_category
,
483 source_trace_name
, expect_start_time
+ i
,
484 expect_end_time
+ i
, valid_timer
);
486 const GpuTracerSource source
= static_cast<GpuTracerSource
>(i
);
488 // Check if the current category/name are correct for this source.
489 ASSERT_EQ(source_category
, tracer
.CurrentCategory(source
));
490 ASSERT_EQ(source_trace_name
, tracer
.CurrentName(source
));
492 ASSERT_TRUE(tracer
.End(source
));
495 ASSERT_TRUE(tracer
.EndDecoding());
497 outputter_ref_
= NULL
;
500 void DoDisjointTest() {
501 // Cause a disjoint in a middle of a trace and expect no output calls.
502 ExpectTracerOffsetQueryMocks();
504 EXPECT_CALL(*gl_
, GetError()).Times(AtLeast(0))
506 Invoke(&gl_fake_queries_
, &GlFakeQueries::GetError
));
508 const std::string
category_name("trace_category");
509 const std::string
trace_name("trace_test");
510 const GpuTracerSource source
= static_cast<GpuTracerSource
>(0);
511 const int64 offset_time
= 3231;
512 const GLint64 start_timestamp
= 7 * base::Time::kNanosecondsPerMicrosecond
;
513 const GLint64 end_timestamp
= 32 * base::Time::kNanosecondsPerMicrosecond
;
514 const int64 expect_start_time
=
515 (start_timestamp
/ base::Time::kNanosecondsPerMicrosecond
) +
517 const int64 expect_end_time
=
518 (end_timestamp
/ base::Time::kNanosecondsPerMicrosecond
) + offset_time
;
520 MockGLES2Decoder decoder
;
521 EXPECT_CALL(decoder
, GetGLContext()).WillOnce(Return(GetGLContext()));
522 GPUTracerTester
tracer(&decoder
);
523 tracer
.SetTracingEnabled(true);
525 tracer
.SetOutputter(outputter_ref_
);
527 gl_fake_queries_
.SetCurrentGLTime(start_timestamp
);
528 g_fakeCPUTime
= expect_start_time
;
530 ASSERT_TRUE(tracer
.BeginDecoding());
532 ExpectTraceQueryMocks();
534 ExpectOutputterBeginMocks(outputter_ref_
.get(),
535 category_name
, trace_name
);
536 ASSERT_TRUE(tracer
.Begin(category_name
, trace_name
, source
));
538 gl_fake_queries_
.SetCurrentGLTime(end_timestamp
);
539 g_fakeCPUTime
= expect_end_time
;
540 gl_fake_queries_
.SetDisjoint();
542 ExpectOutputterEndMocks(outputter_ref_
.get(), category_name
, trace_name
,
543 expect_start_time
, expect_end_time
, false);
545 ASSERT_TRUE(tracer
.End(source
));
546 ASSERT_TRUE(tracer
.EndDecoding());
548 outputter_ref_
= NULL
;
552 class InvalidTimerTracerTest
: public BaseGpuTracerTest
{
554 InvalidTimerTracerTest()
555 : BaseGpuTracerTest(gfx::GPUTiming::kTimerTypeInvalid
) {}
558 class GpuARBTimerTracerTest
: public BaseGpuTracerTest
{
560 GpuARBTimerTracerTest()
561 : BaseGpuTracerTest(gfx::GPUTiming::kTimerTypeARB
) {}
564 class GpuDisjointTimerTracerTest
: public BaseGpuTracerTest
{
566 GpuDisjointTimerTracerTest()
567 : BaseGpuTracerTest(gfx::GPUTiming::kTimerTypeDisjoint
) {}
570 TEST_F(InvalidTimerTracerTest
, InvalidTimerBasicTracerTest
) {
574 TEST_F(GpuARBTimerTracerTest
, ARBTimerBasicTracerTest
) {
578 TEST_F(GpuDisjointTimerTracerTest
, DisjointTimerBasicTracerTest
) {
582 TEST_F(InvalidTimerTracerTest
, InvalidTimerTracerMarkersTest
) {
583 DoTracerMarkersTest();
586 TEST_F(GpuARBTimerTracerTest
, ARBTimerBasicTracerMarkersTest
) {
587 DoTracerMarkersTest();
590 TEST_F(GpuDisjointTimerTracerTest
, DisjointTimerBasicTracerMarkersTest
) {
591 DoTracerMarkersTest();
594 TEST_F(GpuDisjointTimerTracerTest
, DisjointTimerDisjointTraceTest
) {
598 class GPUTracerTest
: public GpuServiceTest
{
600 void SetUp() override
{
602 GpuServiceTest::SetUpWithGLVersion("3.2", "");
603 decoder_
.reset(new MockGLES2Decoder());
604 EXPECT_CALL(*decoder_
, GetGLContext())
606 .WillRepeatedly(Return(GetGLContext()));
607 tracer_tester_
.reset(new GPUTracerTester(decoder_
.get()));
610 void TearDown() override
{
611 tracer_tester_
= nullptr;
613 GpuServiceTest::TearDown();
615 scoped_ptr
<MockGLES2Decoder
> decoder_
;
616 scoped_ptr
<GPUTracerTester
> tracer_tester_
;
619 TEST_F(GPUTracerTest
, IsTracingTest
) {
620 EXPECT_FALSE(tracer_tester_
->IsTracing());
621 tracer_tester_
->SetTracingEnabled(true);
622 EXPECT_TRUE(tracer_tester_
->IsTracing());
624 // Test basic functionality of the GPUTracerTester.
625 TEST_F(GPUTracerTest
, DecodeTest
) {
626 ASSERT_TRUE(tracer_tester_
->BeginDecoding());
627 EXPECT_FALSE(tracer_tester_
->BeginDecoding());
628 ASSERT_TRUE(tracer_tester_
->EndDecoding());
629 EXPECT_FALSE(tracer_tester_
->EndDecoding());
632 TEST_F(GPUTracerTest
, TraceDuringDecodeTest
) {
633 const std::string
category_name("trace_category");
634 const std::string
trace_name("trace_test");
637 tracer_tester_
->Begin(category_name
, trace_name
, kTraceGroupMarker
));
639 ASSERT_TRUE(tracer_tester_
->BeginDecoding());
641 tracer_tester_
->Begin(category_name
, trace_name
, kTraceGroupMarker
));
642 ASSERT_TRUE(tracer_tester_
->EndDecoding());