| // Copyright 2014 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 <stdint.h> |
| |
| #include "base/bind.h" |
| #include "gpu/command_buffer/client/client_test_helper.h" |
| #include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h" |
| #include "gpu/command_buffer/service/gpu_service_test.h" |
| #include "gpu/command_buffer/service/gpu_tracer.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/gl/gl_context.h" |
| #include "ui/gl/gl_mock.h" |
| #include "ui/gl/gpu_timing.h" |
| #include "ui/gl/gpu_timing_fake.h" |
| |
| namespace gpu { |
| namespace gles2 { |
| namespace { |
| |
| using ::testing::_; |
| using ::testing::AtMost; |
| using ::testing::Exactly; |
| using ::testing::Invoke; |
| using ::testing::Return; |
| |
| int64_t g_fakeCPUTime = 0; |
| int64_t FakeCpuTime() { |
| return g_fakeCPUTime; |
| } |
| |
| class MockOutputter : public Outputter { |
| public: |
| MockOutputter() = default; |
| ~MockOutputter() override = default; |
| |
| MOCK_METHOD5(TraceDevice, |
| void(GpuTracerSource source, |
| const std::string& category, |
| const std::string& name, |
| int64_t start_time, |
| int64_t end_time)); |
| MOCK_METHOD3(TraceServiceBegin, |
| void(GpuTracerSource source, |
| const std::string& category, const std::string& name)); |
| MOCK_METHOD3(TraceServiceEnd, |
| void(GpuTracerSource source, |
| const std::string& category, const std::string& name)); |
| }; |
| |
| class GPUTracerTester : public GPUTracer { |
| public: |
| explicit GPUTracerTester(GLES2Decoder* decoder) |
| : GPUTracer(decoder), tracing_enabled_(0) { |
| gpu_timing_client_->SetCpuTimeForTesting(base::BindRepeating(&FakeCpuTime)); |
| |
| // Force tracing to be dependent on our mock variable here. |
| gpu_trace_srv_category = &tracing_enabled_; |
| gpu_trace_dev_category = &tracing_enabled_; |
| } |
| |
| ~GPUTracerTester() override = default; |
| |
| void SetTracingEnabled(bool enabled) { |
| tracing_enabled_ = enabled ? 1 : 0; |
| } |
| |
| private: |
| unsigned char tracing_enabled_; |
| }; |
| |
| class BaseGpuTest : public GpuServiceTest { |
| public: |
| explicit BaseGpuTest(gl::GPUTiming::TimerType test_timer_type) |
| : test_timer_type_(test_timer_type) {} |
| |
| protected: |
| void SetUp() override { |
| g_fakeCPUTime = 0; |
| const char* gl_version = "3.2"; |
| const char* extensions = ""; |
| if (GetTimerType() == gl::GPUTiming::kTimerTypeEXT) { |
| gl_version = "2.1"; |
| extensions = "GL_EXT_timer_query"; |
| } else if (GetTimerType() == gl::GPUTiming::kTimerTypeDisjoint) { |
| gl_version = "OpenGL ES 3.0"; |
| extensions = "GL_EXT_disjoint_timer_query"; |
| } else if (GetTimerType() == gl::GPUTiming::kTimerTypeARB) { |
| // TODO(sievers): The tracer should not depend on ARB_occlusion_query. |
| // Try merge Query APIs (core, ARB, EXT) into a single binding each. |
| extensions = "GL_ARB_timer_query GL_ARB_occlusion_query"; |
| } |
| GpuServiceTest::SetUpWithGLVersion(gl_version, extensions); |
| |
| // Disjoint check should only be called by kTracerTypeDisjointTimer type. |
| if (GetTimerType() == gl::GPUTiming::kTimerTypeDisjoint) |
| gl_fake_queries_.ExpectDisjointCalls(*gl_); |
| else |
| gl_fake_queries_.ExpectNoDisjointCalls(*gl_); |
| |
| gpu_timing_client_ = GetGLContext()->CreateGPUTimingClient(); |
| gpu_timing_client_->SetCpuTimeForTesting(base::BindRepeating(&FakeCpuTime)); |
| gl_fake_queries_.Reset(); |
| } |
| |
| void TearDown() override { |
| gpu_timing_client_ = nullptr; |
| gl_fake_queries_.Reset(); |
| GpuServiceTest::TearDown(); |
| } |
| |
| void ExpectTraceQueryMocks() { |
| if (gpu_timing_client_->IsAvailable()) { |
| // Delegate query APIs used by GPUTrace to a GlFakeQueries |
| const bool elapsed = (GetTimerType() == gl::GPUTiming::kTimerTypeEXT); |
| gl_fake_queries_.ExpectGPUTimerQuery(*gl_, elapsed); |
| } |
| } |
| |
| void ExpectOutputterBeginMocks(MockOutputter* outputter, |
| GpuTracerSource source, |
| const std::string& category, |
| const std::string& name) { |
| EXPECT_CALL(*outputter, |
| TraceServiceBegin(source, category, name)); |
| } |
| |
| void ExpectOutputterEndMocks(MockOutputter* outputter, |
| GpuTracerSource source, |
| const std::string& category, |
| const std::string& name, |
| int64_t expect_start_time, |
| int64_t expect_end_time, |
| bool trace_service, |
| bool trace_device) { |
| if (trace_service) { |
| EXPECT_CALL(*outputter, |
| TraceServiceEnd(source, category, name)); |
| } |
| |
| if (trace_device) { |
| EXPECT_CALL(*outputter, |
| TraceDevice(source, category, name, |
| expect_start_time, expect_end_time)) |
| .Times(Exactly(1)); |
| } else { |
| EXPECT_CALL(*outputter, TraceDevice(source, category, name, |
| expect_start_time, expect_end_time)) |
| .Times(Exactly(0)); |
| } |
| } |
| |
| void ExpectDisjointOutputMocks(MockOutputter* outputter, |
| int64_t expect_start_time, |
| int64_t expect_end_time) { |
| EXPECT_CALL(*outputter, |
| TraceDevice(kTraceDisjoint, "DisjointEvent", _, |
| expect_start_time, expect_end_time)) |
| .Times(Exactly(1)); |
| } |
| |
| void ExpectNoDisjointOutputMocks(MockOutputter* outputter) { |
| EXPECT_CALL(*outputter, |
| TraceDevice(kTraceDisjoint, "DisjointEvent", _, _, _)) |
| .Times(Exactly(0)); |
| } |
| |
| void ExpectOutputterMocks(MockOutputter* outputter, |
| bool tracing_service, |
| bool tracing_device, |
| GpuTracerSource source, |
| const std::string& category, |
| const std::string& name, |
| int64_t expect_start_time, |
| int64_t expect_end_time) { |
| if (tracing_service) |
| ExpectOutputterBeginMocks(outputter, source, category, name); |
| const bool valid_timer = tracing_device && |
| gpu_timing_client_->IsAvailable(); |
| ExpectOutputterEndMocks(outputter, source, category, name, |
| expect_start_time, expect_end_time, |
| tracing_service, valid_timer); |
| } |
| |
| void ExpectTracerOffsetQueryMocks() { |
| if (GetTimerType() != gl::GPUTiming::kTimerTypeARB) { |
| gl_fake_queries_.ExpectNoOffsetCalculationQuery(*gl_); |
| } else { |
| gl_fake_queries_.ExpectOffsetCalculationQuery(*gl_); |
| } |
| } |
| |
| gl::GPUTiming::TimerType GetTimerType() { return test_timer_type_; } |
| |
| gl::GPUTiming::TimerType test_timer_type_; |
| gl::GPUTimingFake gl_fake_queries_; |
| |
| scoped_refptr<gl::GPUTimingClient> gpu_timing_client_; |
| MockOutputter outputter_; |
| }; |
| |
| // Test GPUTrace calls all the correct gl calls. |
| class BaseGpuTraceTest : public BaseGpuTest { |
| public: |
| explicit BaseGpuTraceTest(gl::GPUTiming::TimerType test_timer_type) |
| : BaseGpuTest(test_timer_type) {} |
| |
| void DoTraceTest(bool tracing_service, bool tracing_device) { |
| // Expected results |
| const GpuTracerSource tracer_source = kTraceCHROMIUM; |
| const std::string category_name("trace_category"); |
| const std::string trace_name("trace_test"); |
| const int64_t offset_time = 3231; |
| const GLint64 start_timestamp = 7 * base::Time::kNanosecondsPerMicrosecond; |
| const GLint64 end_timestamp = 32 * base::Time::kNanosecondsPerMicrosecond; |
| const int64_t expect_start_time = |
| (start_timestamp / base::Time::kNanosecondsPerMicrosecond) + |
| offset_time; |
| const int64_t expect_end_time = |
| (end_timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_time; |
| |
| ExpectOutputterMocks(&outputter_, tracing_service, tracing_device, |
| tracer_source, category_name, trace_name, |
| expect_start_time, expect_end_time); |
| |
| if (tracing_device) |
| ExpectTraceQueryMocks(); |
| |
| scoped_refptr<GPUTrace> trace = new GPUTrace( |
| &outputter_, gpu_timing_client_.get(), tracer_source, category_name, |
| trace_name, tracing_service, tracing_device); |
| |
| gl_fake_queries_.SetCurrentGLTime(start_timestamp); |
| g_fakeCPUTime = expect_start_time; |
| trace->Start(); |
| |
| // Shouldn't be available before End() call |
| gl_fake_queries_.SetCurrentGLTime(end_timestamp); |
| g_fakeCPUTime = expect_end_time; |
| if (tracing_device) |
| EXPECT_FALSE(trace->IsAvailable()); |
| |
| trace->End(); |
| |
| // Shouldn't be available until the queries complete |
| gl_fake_queries_.SetCurrentGLTime(end_timestamp - |
| base::Time::kNanosecondsPerMicrosecond); |
| g_fakeCPUTime = expect_end_time - 1; |
| if (tracing_device) |
| EXPECT_FALSE(trace->IsAvailable()); |
| |
| // Now it should be available |
| gl_fake_queries_.SetCurrentGLTime(end_timestamp); |
| g_fakeCPUTime = expect_end_time; |
| EXPECT_TRUE(trace->IsAvailable()); |
| |
| // Process should output expected Trace results to MockOutputter |
| trace->Process(); |
| |
| // Destroy trace after we are done. |
| trace->Destroy(true); |
| } |
| }; |
| |
| class GpuARBTimerTraceTest : public BaseGpuTraceTest { |
| public: |
| GpuARBTimerTraceTest() : BaseGpuTraceTest(gl::GPUTiming::kTimerTypeARB) {} |
| }; |
| |
| class GpuDisjointTimerTraceTest : public BaseGpuTraceTest { |
| public: |
| GpuDisjointTimerTraceTest() |
| : BaseGpuTraceTest(gl::GPUTiming::kTimerTypeDisjoint) {} |
| }; |
| |
| TEST_F(GpuARBTimerTraceTest, ARBTimerTraceTestOff) { |
| DoTraceTest(false, false); |
| } |
| |
| TEST_F(GpuARBTimerTraceTest, ARBTimerTraceTestServiceOnly) { |
| DoTraceTest(true, false); |
| } |
| |
| TEST_F(GpuARBTimerTraceTest, ARBTimerTraceTestDeviceOnly) { |
| DoTraceTest(false, true); |
| } |
| |
| TEST_F(GpuARBTimerTraceTest, ARBTimerTraceTestBothOn) { |
| DoTraceTest(true, true); |
| } |
| |
| TEST_F(GpuDisjointTimerTraceTest, DisjointTimerTraceTestOff) { |
| DoTraceTest(false, false); |
| } |
| |
| TEST_F(GpuDisjointTimerTraceTest, DisjointTimerTraceTestServiceOnly) { |
| DoTraceTest(true, false); |
| } |
| |
| TEST_F(GpuDisjointTimerTraceTest, DisjointTimerTraceTestDeviceOnly) { |
| DoTraceTest(false, true); |
| } |
| |
| TEST_F(GpuDisjointTimerTraceTest, DisjointTimerTraceTestBothOn) { |
| DoTraceTest(true, true); |
| } |
| |
| // Test GPUTracer calls all the correct gl calls. |
| class BaseGpuTracerTest : public BaseGpuTest { |
| public: |
| explicit BaseGpuTracerTest(gl::GPUTiming::TimerType test_timer_type) |
| : BaseGpuTest(test_timer_type) {} |
| |
| void DoBasicTracerTest() { |
| ExpectTracerOffsetQueryMocks(); |
| |
| FakeCommandBufferServiceBase command_buffer_service; |
| MockOutputter outputter; |
| MockGLES2Decoder decoder(&command_buffer_service, &outputter); |
| EXPECT_CALL(decoder, GetGLContext()).WillOnce(Return(GetGLContext())); |
| GPUTracerTester tracer(&decoder); |
| tracer.SetTracingEnabled(true); |
| |
| ASSERT_TRUE(tracer.BeginDecoding()); |
| ASSERT_TRUE(tracer.EndDecoding()); |
| } |
| |
| void DoDisabledTracingTest() { |
| ExpectTracerOffsetQueryMocks(); |
| |
| const GpuTracerSource source = static_cast<GpuTracerSource>(0); |
| |
| FakeCommandBufferServiceBase command_buffer_service; |
| MockOutputter outputter; |
| MockGLES2Decoder decoder(&command_buffer_service, &outputter); |
| EXPECT_CALL(decoder, GetGLContext()).WillOnce(Return(GetGLContext())); |
| GPUTracerTester tracer(&decoder); |
| tracer.SetTracingEnabled(false); |
| |
| ASSERT_TRUE(tracer.BeginDecoding()); |
| ASSERT_TRUE(tracer.Begin("disabled_category", "disabled_name", source)); |
| ASSERT_TRUE(tracer.End(source)); |
| ASSERT_TRUE(tracer.EndDecoding()); |
| } |
| |
| void DoTracerMarkersTest() { |
| ExpectTracerOffsetQueryMocks(); |
| gl_fake_queries_.ExpectGetErrorCalls(*gl_); |
| |
| const std::string category_name("trace_category"); |
| const std::string trace_name("trace_test"); |
| const int64_t offset_time = 3231; |
| const GLint64 start_timestamp = 7 * base::Time::kNanosecondsPerMicrosecond; |
| const GLint64 end_timestamp = 32 * base::Time::kNanosecondsPerMicrosecond; |
| const int64_t expect_start_time = |
| (start_timestamp / base::Time::kNanosecondsPerMicrosecond) + |
| offset_time; |
| const int64_t expect_end_time = |
| (end_timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_time; |
| |
| FakeCommandBufferServiceBase command_buffer_service; |
| MockOutputter outputter; |
| MockGLES2Decoder decoder(&command_buffer_service, &outputter); |
| EXPECT_CALL(decoder, GetGLContext()).WillOnce(Return(GetGLContext())); |
| GPUTracerTester tracer(&decoder); |
| tracer.SetTracingEnabled(true); |
| |
| gl_fake_queries_.SetCurrentGLTime(start_timestamp); |
| g_fakeCPUTime = expect_start_time; |
| |
| ASSERT_TRUE(tracer.BeginDecoding()); |
| |
| ExpectTraceQueryMocks(); |
| |
| // This will test multiple marker sources which overlap one another. |
| for (int i = 0; i < NUM_TRACER_SOURCES; ++i) { |
| // Set times so each source has a different time. |
| gl_fake_queries_.SetCurrentGLTime( |
| start_timestamp + |
| (i * base::Time::kNanosecondsPerMicrosecond)); |
| g_fakeCPUTime = expect_start_time + i; |
| |
| // Each trace name should be different to differentiate. |
| const char num_char = static_cast<char>('0' + i); |
| std::string source_category = category_name + num_char; |
| std::string source_trace_name = trace_name + num_char; |
| |
| const GpuTracerSource source = static_cast<GpuTracerSource>(i); |
| ExpectOutputterBeginMocks(&outputter, source, source_category, |
| source_trace_name); |
| ASSERT_TRUE(tracer.Begin(source_category, source_trace_name, source)); |
| } |
| for (int i = 0; i < NUM_TRACER_SOURCES; ++i) { |
| // Set times so each source has a different time. |
| gl_fake_queries_.SetCurrentGLTime( |
| end_timestamp + |
| (i * base::Time::kNanosecondsPerMicrosecond)); |
| g_fakeCPUTime = expect_end_time + i; |
| |
| // Each trace name should be different to differentiate. |
| const char num_char = static_cast<char>('0' + i); |
| std::string source_category = category_name + num_char; |
| std::string source_trace_name = trace_name + num_char; |
| |
| const bool valid_timer = gpu_timing_client_->IsAvailable(); |
| const GpuTracerSource source = static_cast<GpuTracerSource>(i); |
| ExpectOutputterEndMocks(&outputter, source, source_category, |
| source_trace_name, expect_start_time + i, |
| expect_end_time + i, true, valid_timer); |
| // Check if the current category/name are correct for this source. |
| ASSERT_EQ(source_category, tracer.CurrentCategory(source)); |
| ASSERT_EQ(source_trace_name, tracer.CurrentName(source)); |
| |
| ASSERT_TRUE(tracer.End(source)); |
| } |
| ASSERT_TRUE(tracer.EndDecoding()); |
| tracer.ProcessTraces(); |
| } |
| |
| void DoOngoingTracerMarkerTest() { |
| ExpectTracerOffsetQueryMocks(); |
| gl_fake_queries_.ExpectGetErrorCalls(*gl_); |
| |
| const std::string category_name("trace_category"); |
| const std::string trace_name("trace_test"); |
| const GpuTracerSource source = static_cast<GpuTracerSource>(0); |
| const int64_t offset_time = 3231; |
| const GLint64 start_timestamp = 7 * base::Time::kNanosecondsPerMicrosecond; |
| const int64_t expect_start_time = |
| (start_timestamp / base::Time::kNanosecondsPerMicrosecond) + |
| offset_time; |
| const bool valid_timer = gpu_timing_client_->IsAvailable(); |
| |
| FakeCommandBufferServiceBase command_buffer_service; |
| MockOutputter outputter; |
| MockGLES2Decoder decoder(&command_buffer_service, &outputter); |
| EXPECT_CALL(decoder, GetGLContext()).WillOnce(Return(GetGLContext())); |
| GPUTracerTester tracer(&decoder); |
| |
| // Create trace marker while traces are disabled. |
| gl_fake_queries_.SetCurrentGLTime(start_timestamp); |
| g_fakeCPUTime = expect_start_time; |
| |
| tracer.SetTracingEnabled(false); |
| ASSERT_TRUE(tracer.BeginDecoding()); |
| ASSERT_TRUE(tracer.Begin(category_name, trace_name, source)); |
| ASSERT_TRUE(tracer.EndDecoding()); |
| |
| // Enable traces now. |
| tracer.SetTracingEnabled(true); |
| ExpectTraceQueryMocks(); |
| |
| // trace should happen when decoding begins, at time start+1. |
| gl_fake_queries_.SetCurrentGLTime( |
| start_timestamp + |
| (1 * base::Time::kNanosecondsPerMicrosecond)); |
| g_fakeCPUTime = expect_start_time + 1; |
| ASSERT_TRUE(tracer.BeginDecoding()); |
| |
| // End decoding at time start+2. |
| ExpectOutputterEndMocks(&outputter, source, category_name, trace_name, |
| expect_start_time + 1, expect_start_time + 2, true, |
| valid_timer); |
| gl_fake_queries_.SetCurrentGLTime( |
| start_timestamp + |
| (2 * base::Time::kNanosecondsPerMicrosecond)); |
| g_fakeCPUTime = expect_start_time + 2; |
| ASSERT_TRUE(tracer.EndDecoding()); |
| |
| // Begin decoding again at time start+3. |
| gl_fake_queries_.SetCurrentGLTime( |
| start_timestamp + |
| (3 * base::Time::kNanosecondsPerMicrosecond)); |
| g_fakeCPUTime = expect_start_time + 3; |
| ASSERT_TRUE(tracer.BeginDecoding()); |
| |
| // End trace at time start+4 |
| gl_fake_queries_.SetCurrentGLTime( |
| start_timestamp + |
| (4 * base::Time::kNanosecondsPerMicrosecond)); |
| g_fakeCPUTime = expect_start_time + 4; |
| ExpectOutputterEndMocks(&outputter, source, category_name, trace_name, |
| expect_start_time + 3, expect_start_time + 4, true, |
| valid_timer); |
| ASSERT_TRUE(tracer.End(source)); |
| |
| // Increment time before we end decoding to test trace does not stop here. |
| gl_fake_queries_.SetCurrentGLTime( |
| start_timestamp + |
| (5 * base::Time::kNanosecondsPerMicrosecond)); |
| g_fakeCPUTime = expect_start_time + 5; |
| ASSERT_TRUE(tracer.EndDecoding()); |
| tracer.ProcessTraces(); |
| } |
| |
| void DoDisjointTest() { |
| // Cause a disjoint in a middle of a trace and expect no output calls. |
| ExpectTracerOffsetQueryMocks(); |
| gl_fake_queries_.ExpectGetErrorCalls(*gl_); |
| |
| const std::string category_name("trace_category"); |
| const std::string trace_name("trace_test"); |
| const GpuTracerSource source = static_cast<GpuTracerSource>(0); |
| const int64_t offset_time = 3231; |
| const GLint64 start_timestamp = 7 * base::Time::kNanosecondsPerMicrosecond; |
| const GLint64 end_timestamp = 32 * base::Time::kNanosecondsPerMicrosecond; |
| const int64_t expect_start_time = |
| (start_timestamp / base::Time::kNanosecondsPerMicrosecond) + |
| offset_time; |
| const int64_t expect_end_time = |
| (end_timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_time; |
| |
| FakeCommandBufferServiceBase command_buffer_service; |
| MockOutputter outputter; |
| MockGLES2Decoder decoder(&command_buffer_service, &outputter); |
| EXPECT_CALL(decoder, GetGLContext()).WillOnce(Return(GetGLContext())); |
| GPUTracerTester tracer(&decoder); |
| tracer.SetTracingEnabled(true); |
| |
| gl_fake_queries_.SetCurrentGLTime(start_timestamp); |
| g_fakeCPUTime = expect_start_time; |
| |
| ASSERT_TRUE(tracer.BeginDecoding()); |
| |
| ExpectTraceQueryMocks(); |
| |
| ExpectOutputterBeginMocks(&outputter, source, category_name, trace_name); |
| ASSERT_TRUE(tracer.Begin(category_name, trace_name, source)); |
| |
| gl_fake_queries_.SetCurrentGLTime(end_timestamp); |
| g_fakeCPUTime = expect_end_time; |
| |
| // Create GPUTimingClient to make sure disjoint value is correct. This |
| // should not interfere with the tracer's disjoint value. |
| scoped_refptr<gl::GPUTimingClient> disjoint_client = |
| GetGLContext()->CreateGPUTimingClient(); |
| |
| // We assert here based on the disjoint_client because if disjoints are not |
| // working properly there is no point testing the tracer output. |
| ASSERT_FALSE(disjoint_client->CheckAndResetTimerErrors()); |
| gl_fake_queries_.SetDisjoint(); |
| ASSERT_TRUE(disjoint_client->CheckAndResetTimerErrors()); |
| |
| ExpectDisjointOutputMocks(&outputter, expect_start_time, expect_end_time); |
| |
| ExpectOutputterEndMocks(&outputter, source, category_name, trace_name, |
| expect_start_time, expect_end_time, true, false); |
| |
| ASSERT_TRUE(tracer.End(source)); |
| ASSERT_TRUE(tracer.EndDecoding()); |
| tracer.ProcessTraces(); |
| } |
| |
| void DoOutsideDisjointTest() { |
| ExpectTracerOffsetQueryMocks(); |
| gl_fake_queries_.ExpectGetErrorCalls(*gl_); |
| |
| const std::string category_name("trace_category"); |
| const std::string trace_name("trace_test"); |
| const GpuTracerSource source = static_cast<GpuTracerSource>(0); |
| const int64_t offset_time = 3231; |
| const GLint64 start_timestamp = 7 * base::Time::kNanosecondsPerMicrosecond; |
| const GLint64 end_timestamp = 32 * base::Time::kNanosecondsPerMicrosecond; |
| const int64_t expect_start_time = |
| (start_timestamp / base::Time::kNanosecondsPerMicrosecond) + |
| offset_time; |
| const int64_t expect_end_time = |
| (end_timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_time; |
| |
| FakeCommandBufferServiceBase command_buffer_service; |
| MockOutputter outputter; |
| MockGLES2Decoder decoder(&command_buffer_service, &outputter); |
| EXPECT_CALL(decoder, GetGLContext()).WillOnce(Return(GetGLContext())); |
| EXPECT_CALL(decoder, MakeCurrent()).WillRepeatedly(Return(true)); |
| GPUTracerTester tracer(&decoder); |
| |
| // Start a trace before tracing is enabled. |
| tracer.SetTracingEnabled(false); |
| ASSERT_TRUE(tracer.BeginDecoding()); |
| ASSERT_TRUE(tracer.Begin(category_name, trace_name, source)); |
| ASSERT_TRUE(tracer.EndDecoding()); |
| |
| // Enabling traces now, trace should be ongoing. |
| tracer.SetTracingEnabled(true); |
| gl_fake_queries_.SetCurrentGLTime(start_timestamp); |
| g_fakeCPUTime = expect_start_time; |
| |
| // Disjoints before we start tracing anything should not do anything. |
| ExpectNoDisjointOutputMocks(&outputter); |
| gl_fake_queries_.SetDisjoint(); |
| |
| ExpectTraceQueryMocks(); |
| ExpectOutputterBeginMocks(&outputter, source, category_name, trace_name); |
| ASSERT_TRUE(tracer.BeginDecoding()); |
| |
| // Set times so each source has a different time. |
| gl_fake_queries_.SetCurrentGLTime(end_timestamp); |
| g_fakeCPUTime = expect_end_time; |
| |
| ExpectOutputterEndMocks(&outputter, source, category_name, trace_name, |
| expect_start_time, expect_end_time, true, true); |
| |
| ASSERT_TRUE(tracer.End(source)); |
| ASSERT_TRUE(tracer.EndDecoding()); |
| tracer.ProcessTraces(); |
| } |
| }; |
| |
| class InvalidTimerTracerTest : public BaseGpuTracerTest { |
| public: |
| InvalidTimerTracerTest() |
| : BaseGpuTracerTest(gl::GPUTiming::kTimerTypeInvalid) {} |
| }; |
| |
| class GpuEXTTimerTracerTest : public BaseGpuTracerTest { |
| public: |
| GpuEXTTimerTracerTest() : BaseGpuTracerTest(gl::GPUTiming::kTimerTypeEXT) {} |
| }; |
| |
| class GpuARBTimerTracerTest : public BaseGpuTracerTest { |
| public: |
| GpuARBTimerTracerTest() : BaseGpuTracerTest(gl::GPUTiming::kTimerTypeARB) {} |
| }; |
| |
| class GpuDisjointTimerTracerTest : public BaseGpuTracerTest { |
| public: |
| GpuDisjointTimerTracerTest() |
| : BaseGpuTracerTest(gl::GPUTiming::kTimerTypeDisjoint) {} |
| }; |
| |
| TEST_F(InvalidTimerTracerTest, InvalidTimerBasicTracerTest) { |
| DoBasicTracerTest(); |
| } |
| |
| TEST_F(GpuEXTTimerTracerTest, EXTTimerBasicTracerTest) { |
| DoBasicTracerTest(); |
| } |
| |
| TEST_F(GpuARBTimerTracerTest, ARBTimerBasicTracerTest) { |
| DoBasicTracerTest(); |
| } |
| |
| TEST_F(GpuDisjointTimerTracerTest, DisjointTimerBasicTracerTest) { |
| DoBasicTracerTest(); |
| } |
| |
| TEST_F(InvalidTimerTracerTest, InvalidTimerDisabledTest) { |
| DoDisabledTracingTest(); |
| } |
| |
| TEST_F(GpuEXTTimerTracerTest, EXTTimerDisabledTest) { |
| DoDisabledTracingTest(); |
| } |
| |
| TEST_F(GpuARBTimerTracerTest, ARBTimerDisabledTest) { |
| DoDisabledTracingTest(); |
| } |
| |
| TEST_F(GpuDisjointTimerTracerTest, DisjointTimerDisabledTest) { |
| DoDisabledTracingTest(); |
| } |
| |
| TEST_F(InvalidTimerTracerTest, InvalidTimerTracerMarkersTest) { |
| DoTracerMarkersTest(); |
| } |
| |
| TEST_F(GpuEXTTimerTracerTest, EXTTimerTracerMarkersTest) { |
| DoTracerMarkersTest(); |
| } |
| |
| TEST_F(GpuARBTimerTracerTest, ARBTimerTracerMarkersTest) { |
| DoTracerMarkersTest(); |
| } |
| |
| TEST_F(GpuDisjointTimerTracerTest, DisjointTimerBasicTracerMarkersTest) { |
| DoTracerMarkersTest(); |
| } |
| |
| TEST_F(InvalidTimerTracerTest, InvalidTimerOngoingTracerMarkersTest) { |
| DoOngoingTracerMarkerTest(); |
| } |
| |
| TEST_F(GpuEXTTimerTracerTest, EXTTimerOngoingTracerMarkersTest) { |
| DoOngoingTracerMarkerTest(); |
| } |
| |
| TEST_F(GpuARBTimerTracerTest, ARBTimerBasicOngoingTracerMarkersTest) { |
| DoOngoingTracerMarkerTest(); |
| } |
| |
| TEST_F(GpuDisjointTimerTracerTest, DisjointTimerOngoingTracerMarkersTest) { |
| DoOngoingTracerMarkerTest(); |
| } |
| |
| TEST_F(GpuDisjointTimerTracerTest, DisjointTimerDisjointTraceTest) { |
| DoDisjointTest(); |
| } |
| |
| TEST_F(GpuDisjointTimerTracerTest, NonrelevantDisjointTraceTest) { |
| DoOutsideDisjointTest(); |
| } |
| |
| class GPUTracerTest : public GpuServiceTest { |
| protected: |
| void SetUp() override { |
| g_fakeCPUTime = 0; |
| GpuServiceTest::SetUpWithGLVersion("3.2", ""); |
| decoder_.reset(new MockGLES2Decoder(&command_buffer_service_, &outputter_)); |
| EXPECT_CALL(*decoder_, GetGLContext()) |
| .Times(AtMost(1)) |
| .WillRepeatedly(Return(GetGLContext())); |
| tracer_tester_.reset(new GPUTracerTester(decoder_.get())); |
| } |
| |
| void TearDown() override { |
| tracer_tester_ = nullptr; |
| decoder_ = nullptr; |
| GpuServiceTest::TearDown(); |
| } |
| |
| FakeCommandBufferServiceBase command_buffer_service_; |
| MockOutputter outputter_; |
| std::unique_ptr<MockGLES2Decoder> decoder_; |
| std::unique_ptr<GPUTracerTester> tracer_tester_; |
| }; |
| |
| TEST_F(GPUTracerTest, IsTracingTest) { |
| EXPECT_FALSE(tracer_tester_->IsTracing()); |
| tracer_tester_->SetTracingEnabled(true); |
| EXPECT_TRUE(tracer_tester_->IsTracing()); |
| } |
| // Test basic functionality of the GPUTracerTester. |
| TEST_F(GPUTracerTest, DecodeTest) { |
| ASSERT_TRUE(tracer_tester_->BeginDecoding()); |
| EXPECT_FALSE(tracer_tester_->BeginDecoding()); |
| ASSERT_TRUE(tracer_tester_->EndDecoding()); |
| EXPECT_FALSE(tracer_tester_->EndDecoding()); |
| } |
| |
| TEST_F(GPUTracerTest, TraceDuringDecodeTest) { |
| const std::string category_name("trace_category"); |
| const std::string trace_name("trace_test"); |
| |
| EXPECT_FALSE( |
| tracer_tester_->Begin(category_name, trace_name, kTraceCHROMIUM)); |
| |
| ASSERT_TRUE(tracer_tester_->BeginDecoding()); |
| EXPECT_TRUE( |
| tracer_tester_->Begin(category_name, trace_name, kTraceCHROMIUM)); |
| ASSERT_TRUE(tracer_tester_->EndDecoding()); |
| } |
| |
| TEST_F(GpuDisjointTimerTracerTest, MultipleClientsDisjointTest) { |
| scoped_refptr<gl::GPUTimingClient> client1 = |
| GetGLContext()->CreateGPUTimingClient(); |
| scoped_refptr<gl::GPUTimingClient> client2 = |
| GetGLContext()->CreateGPUTimingClient(); |
| |
| // Test both clients are initialized as no errors. |
| ASSERT_FALSE(client1->CheckAndResetTimerErrors()); |
| ASSERT_FALSE(client2->CheckAndResetTimerErrors()); |
| |
| // Issue a disjoint. |
| gl_fake_queries_.SetDisjoint(); |
| |
| ASSERT_TRUE(client1->CheckAndResetTimerErrors()); |
| ASSERT_TRUE(client2->CheckAndResetTimerErrors()); |
| |
| // Test both are now reset. |
| ASSERT_FALSE(client1->CheckAndResetTimerErrors()); |
| ASSERT_FALSE(client2->CheckAndResetTimerErrors()); |
| |
| // Issue a disjoint. |
| gl_fake_queries_.SetDisjoint(); |
| |
| // Test new client disjoint value is cleared. |
| scoped_refptr<gl::GPUTimingClient> client3 = |
| GetGLContext()->CreateGPUTimingClient(); |
| ASSERT_TRUE(client1->CheckAndResetTimerErrors()); |
| ASSERT_TRUE(client2->CheckAndResetTimerErrors()); |
| ASSERT_FALSE(client3->CheckAndResetTimerErrors()); |
| } |
| |
| } // namespace |
| } // namespace gles2 |
| } // namespace gpu |