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
13namespace gpu {
14namespace gles2 {
15
16using ::testing::InvokeWithoutArgs;
17using ::testing::Return;
18using ::testing::ReturnRef;
19using ::testing::ReturnPointee;
20using ::testing::NotNull;
21using ::testing::ElementsAreArray;
22using ::testing::ElementsAre;
23using ::testing::SetArrayArgument;
24using ::testing::AtLeast;
25using ::testing::SetArgPointee;
26using ::testing::Pointee;
27using ::testing::Unused;
28using ::testing::Invoke;
29using ::testing::_;
30
31class 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
41class 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 GenQueriesARB(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 DeleteQueriesARB(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
112class BaseGpuTracerTest : public GpuServiceTest {
113 public:
114  BaseGpuTracerTest() {}
115
116  ///////////////////////////////////////////////////////////////////////////
117
118  void DoTraceTest() {
119    MockOutputter* outputter = new MockOutputter();
120    scoped_refptr<Outputter> outputter_ref = outputter;
121
122    SetupTimerQueryMocks();
123
124    // Expected results
125    const std::string trace_name("trace_test");
126    const int64 offset_time = 3231;
127    const GLint64 start_timestamp = 7 * base::Time::kNanosecondsPerMicrosecond;
128    const GLint64 end_timestamp = 32 * base::Time::kNanosecondsPerMicrosecond;
129    const int64 expect_start_time =
130        (start_timestamp / base::Time::kNanosecondsPerMicrosecond) +
131        offset_time;
132    const int64 expect_end_time =
133        (end_timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_time;
134
135    // Expected Outputter::Trace call
136    EXPECT_CALL(*outputter,
137                Trace(trace_name, expect_start_time, expect_end_time));
138
139    scoped_refptr<GPUTrace> trace =
140        new GPUTrace(outputter_ref, trace_name, offset_time,
141                     GetTracerType());
142
143    gl_fake_queries_.SetCurrentGLTime(start_timestamp);
144    trace->Start();
145
146    // Shouldn't be available before End() call
147    gl_fake_queries_.SetCurrentGLTime(end_timestamp);
148    EXPECT_FALSE(trace->IsAvailable());
149
150    trace->End();
151
152    // Shouldn't be available until the queries complete
153    gl_fake_queries_.SetCurrentGLTime(end_timestamp -
154                                      base::Time::kNanosecondsPerMicrosecond);
155    EXPECT_FALSE(trace->IsAvailable());
156
157    // Now it should be available
158    gl_fake_queries_.SetCurrentGLTime(end_timestamp);
159    EXPECT_TRUE(trace->IsAvailable());
160
161    // Proces should output expected Trace results to MockOutputter
162    trace->Process();
163  }
164
165 protected:
166  virtual void SetUp() {
167    GpuServiceTest::SetUp();
168    gl_fake_queries_.Reset();
169  }
170
171  virtual void TearDown() {
172    gl_.reset();
173    gl_fake_queries_.Reset();
174    GpuServiceTest::TearDown();
175  }
176
177  virtual void SetupTimerQueryMocks() {
178    // Delegate query APIs used by GPUTrace to a GlFakeQueries
179    EXPECT_CALL(*gl_, GenQueriesARB(_, NotNull())).Times(AtLeast(1)).WillOnce(
180        Invoke(&gl_fake_queries_, &GlFakeQueries::GenQueriesARB));
181
182    EXPECT_CALL(*gl_, GetQueryObjectiv(_, GL_QUERY_RESULT_AVAILABLE, NotNull()))
183        .Times(AtLeast(2))
184        .WillRepeatedly(
185             Invoke(&gl_fake_queries_, &GlFakeQueries::GetQueryObjectiv));
186
187    EXPECT_CALL(*gl_, QueryCounter(_, GL_TIMESTAMP))
188        .Times(AtLeast(2))
189        .WillRepeatedly(
190             Invoke(&gl_fake_queries_, &GlFakeQueries::QueryCounter));
191
192    EXPECT_CALL(*gl_, GetQueryObjectui64v(_, GL_QUERY_RESULT, NotNull()))
193        .Times(AtLeast(2))
194        .WillRepeatedly(
195             Invoke(&gl_fake_queries_, &GlFakeQueries::GetQueryObjectui64v));
196
197    EXPECT_CALL(*gl_, DeleteQueriesARB(2, NotNull()))
198        .Times(AtLeast(1))
199        .WillRepeatedly(
200             Invoke(&gl_fake_queries_, &GlFakeQueries::DeleteQueriesARB));
201  }
202
203  virtual GpuTracerType GetTracerType() = 0;
204
205  GlFakeQueries gl_fake_queries_;
206};
207
208class GpuARBTimerTracerTest : public BaseGpuTracerTest {
209 protected:
210  virtual GpuTracerType GetTracerType() OVERRIDE {
211    return kTracerTypeARBTimer;
212  }
213};
214
215class GpuDisjointTimerTracerTest : public BaseGpuTracerTest {
216 protected:
217  virtual GpuTracerType GetTracerType() OVERRIDE {
218    return kTracerTypeDisjointTimer;
219  }
220};
221
222TEST_F(GpuARBTimerTracerTest, GPUTrace) {
223  // Test basic timer query functionality
224  {
225    DoTraceTest();
226  }
227}
228
229TEST_F(GpuDisjointTimerTracerTest, GPUTrace) {
230  // Test basic timer query functionality
231  {
232    DoTraceTest();
233  }
234}
235
236}  // namespace gles2
237}  // namespace gpu
238