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. 4 5 #include <map> 6 #include <set> 7 8 #include "gpu/command_buffer/service/gpu_service_test.h" 9 #include "gpu/command_buffer/service/gpu_tracer.h" 10 #include "testing/gtest/include/gtest/gtest.h" 11 #include "ui/gl/gl_mock.h" 12 13 namespace gpu { 14 namespace gles2 { 15 16 using ::testing::InvokeWithoutArgs; 17 using ::testing::Return; 18 using ::testing::ReturnRef; 19 using ::testing::ReturnPointee; 20 using ::testing::NotNull; 21 using ::testing::ElementsAreArray; 22 using ::testing::ElementsAre; 23 using ::testing::SetArrayArgument; 24 using ::testing::AtLeast; 25 using ::testing::SetArgPointee; 26 using ::testing::Pointee; 27 using ::testing::Unused; 28 using ::testing::Invoke; 29 using ::testing::_; 30 31 class MockOutputter : public Outputter { 32 public: 33 MockOutputter() {} 34 MOCK_METHOD3(Trace, 35 void(const std::string& name, int64 start_time, int64 end_time)); 36 37 protected: 38 ~MockOutputter() {} 39 }; 40 41 class GlFakeQueries { 42 public: 43 GlFakeQueries() {} 44 45 void Reset() { 46 current_time_ = 0; 47 next_query_id_ = 23; 48 alloced_queries_.clear(); 49 query_timestamp_.clear(); 50 } 51 52 void SetCurrentGLTime(GLint64 current_time) { current_time_ = current_time; } 53 54 void GenQueries(GLsizei n, GLuint* ids) { 55 for (GLsizei i = 0; i < n; i++) { 56 ids[i] = next_query_id_++; 57 alloced_queries_.insert(ids[i]); 58 } 59 } 60 61 void DeleteQueries(GLsizei n, const GLuint* ids) { 62 for (GLsizei i = 0; i < n; i++) { 63 alloced_queries_.erase(ids[i]); 64 query_timestamp_.erase(ids[i]); 65 } 66 } 67 68 void GetQueryObjectiv(GLuint id, GLenum pname, GLint* params) { 69 switch (pname) { 70 case GL_QUERY_RESULT_AVAILABLE: { 71 std::map<GLuint, GLint64>::iterator it = query_timestamp_.find(id); 72 if (it != query_timestamp_.end() && it->second <= current_time_) 73 *params = 1; 74 else 75 *params = 0; 76 break; 77 } 78 default: 79 ASSERT_TRUE(false); 80 } 81 } 82 83 void QueryCounter(GLuint id, GLenum target) { 84 switch (target) { 85 case GL_TIMESTAMP: 86 ASSERT_TRUE(alloced_queries_.find(id) != alloced_queries_.end()); 87 query_timestamp_[id] = current_time_; 88 break; 89 default: 90 ASSERT_TRUE(false); 91 } 92 } 93 94 void GetQueryObjectui64v(GLuint id, GLenum pname, GLuint64* params) { 95 switch (pname) { 96 case GL_QUERY_RESULT: 97 ASSERT_TRUE(query_timestamp_.find(id) != query_timestamp_.end()); 98 *params = query_timestamp_.find(id)->second; 99 break; 100 default: 101 ASSERT_TRUE(false); 102 } 103 } 104 105 protected: 106 GLint64 current_time_; 107 GLuint next_query_id_; 108 std::set<GLuint> alloced_queries_; 109 std::map<GLuint, GLint64> query_timestamp_; 110 }; 111 112 class GpuTracerTest : public GpuServiceTest { 113 public: 114 GpuTracerTest() {} 115 116 /////////////////////////////////////////////////////////////////////////// 117 118 protected: 119 virtual void SetUp() { 120 GpuServiceTest::SetUp(); 121 gl_fake_queries_.Reset(); 122 } 123 124 virtual void TearDown() { 125 gl_.reset(); 126 gl_fake_queries_.Reset(); 127 GpuServiceTest::TearDown(); 128 } 129 130 void SetupTimerQueryMocks() { 131 // Delegate query APIs used by GLARBTimerTrace to a GlFakeQueries 132 EXPECT_CALL(*gl_, GenQueries(_, NotNull())).Times(AtLeast(1)).WillOnce( 133 Invoke(&gl_fake_queries_, &GlFakeQueries::GenQueries)); 134 135 EXPECT_CALL(*gl_, GetQueryObjectiv(_, GL_QUERY_RESULT_AVAILABLE, NotNull())) 136 .Times(AtLeast(2)) 137 .WillRepeatedly( 138 Invoke(&gl_fake_queries_, &GlFakeQueries::GetQueryObjectiv)); 139 140 EXPECT_CALL(*gl_, QueryCounter(_, GL_TIMESTAMP)) 141 .Times(AtLeast(2)) 142 .WillRepeatedly( 143 Invoke(&gl_fake_queries_, &GlFakeQueries::QueryCounter)); 144 145 EXPECT_CALL(*gl_, GetQueryObjectui64v(_, GL_QUERY_RESULT, NotNull())) 146 .Times(AtLeast(2)) 147 .WillRepeatedly( 148 Invoke(&gl_fake_queries_, &GlFakeQueries::GetQueryObjectui64v)); 149 150 EXPECT_CALL(*gl_, DeleteQueries(2, NotNull())) 151 .Times(AtLeast(1)) 152 .WillRepeatedly( 153 Invoke(&gl_fake_queries_, &GlFakeQueries::DeleteQueries)); 154 } 155 156 GlFakeQueries gl_fake_queries_; 157 }; 158 159 TEST_F(GpuTracerTest, GLARBTimerTrace) { 160 // Test basic timer query functionality 161 { 162 MockOutputter* outputter = new MockOutputter(); 163 scoped_refptr<Outputter> outputter_ref = outputter; 164 165 SetupTimerQueryMocks(); 166 167 // Expected results 168 const std::string trace_name("trace_test"); 169 const int64 offset_time = 3231; 170 const GLint64 start_timestamp = 7 * base::Time::kNanosecondsPerMicrosecond; 171 const GLint64 end_timestamp = 32 * base::Time::kNanosecondsPerMicrosecond; 172 const int64 expect_start_time = 173 (start_timestamp / base::Time::kNanosecondsPerMicrosecond) + 174 offset_time; 175 const int64 expect_end_time = 176 (end_timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_time; 177 178 // Expected Outputter::Trace call 179 EXPECT_CALL(*outputter, 180 Trace(trace_name, expect_start_time, expect_end_time)); 181 182 scoped_refptr<GLARBTimerTrace> trace = 183 new GLARBTimerTrace(outputter_ref, trace_name, offset_time); 184 185 gl_fake_queries_.SetCurrentGLTime(start_timestamp); 186 trace->Start(); 187 188 // Shouldn't be available before End() call 189 gl_fake_queries_.SetCurrentGLTime(end_timestamp); 190 EXPECT_FALSE(trace->IsAvailable()); 191 192 trace->End(); 193 194 // Shouldn't be available until the queries complete 195 gl_fake_queries_.SetCurrentGLTime(end_timestamp - 196 base::Time::kNanosecondsPerMicrosecond); 197 EXPECT_FALSE(trace->IsAvailable()); 198 199 // Now it should be available 200 gl_fake_queries_.SetCurrentGLTime(end_timestamp); 201 EXPECT_TRUE(trace->IsAvailable()); 202 203 // Proces should output expected Trace results to MockOutputter 204 trace->Process(); 205 } 206 } 207 208 } // namespace gles2 209 } // namespace gpu 210