1// Copyright (c) 2012 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// Tests for the QueryTracker.
6
7#include "gpu/command_buffer/client/query_tracker.h"
8
9#include <GLES2/gl2ext.h>
10#include "base/memory/scoped_ptr.h"
11#include "gpu/command_buffer/client/client_test_helper.h"
12#include "gpu/command_buffer/client/gles2_cmd_helper.h"
13#include "gpu/command_buffer/client/mapped_memory.h"
14#include "gpu/command_buffer/common/command_buffer.h"
15#include "testing/gtest/include/gtest/gtest.h"
16#include "testing/gmock/include/gmock/gmock.h"
17
18namespace gpu {
19namespace gles2 {
20
21namespace {
22void EmptyPoll() {
23}
24}
25
26class QuerySyncManagerTest : public testing::Test {
27 protected:
28  static const int32 kNumCommandEntries = 400;
29  static const int32 kCommandBufferSizeBytes =
30      kNumCommandEntries * sizeof(CommandBufferEntry);
31
32  virtual void SetUp() {
33    command_buffer_.reset(new MockClientCommandBuffer());
34    helper_.reset(new GLES2CmdHelper(command_buffer_.get()));
35    helper_->Initialize(kCommandBufferSizeBytes);
36    mapped_memory_.reset(new MappedMemoryManager(
37        helper_.get(), base::Bind(&EmptyPoll), MappedMemoryManager::kNoLimit));
38    sync_manager_.reset(new QuerySyncManager(mapped_memory_.get()));
39  }
40
41  virtual void TearDown() {
42    sync_manager_.reset();
43    mapped_memory_.reset();
44    helper_.reset();
45    command_buffer_.reset();
46  }
47
48  scoped_ptr<CommandBuffer> command_buffer_;
49  scoped_ptr<GLES2CmdHelper> helper_;
50  scoped_ptr<MappedMemoryManager> mapped_memory_;
51  scoped_ptr<QuerySyncManager> sync_manager_;
52};
53
54TEST_F(QuerySyncManagerTest, Basic) {
55  QuerySyncManager::QueryInfo infos[4];
56  memset(&infos, 0xBD, sizeof(infos));
57
58  for (size_t ii = 0; ii < arraysize(infos); ++ii) {
59    EXPECT_TRUE(sync_manager_->Alloc(&infos[ii]));
60    EXPECT_NE(0, infos[ii].shm_id);
61    ASSERT_TRUE(infos[ii].sync != NULL);
62    EXPECT_EQ(0, infos[ii].sync->process_count);
63    EXPECT_EQ(0u, infos[ii].sync->result);
64  }
65
66  for (size_t ii = 0; ii < arraysize(infos); ++ii) {
67    sync_manager_->Free(infos[ii]);
68  }
69}
70
71TEST_F(QuerySyncManagerTest, DontFree) {
72  QuerySyncManager::QueryInfo infos[4];
73  memset(&infos, 0xBD, sizeof(infos));
74
75  for (size_t ii = 0; ii < arraysize(infos); ++ii) {
76    EXPECT_TRUE(sync_manager_->Alloc(&infos[ii]));
77  }
78}
79
80class QueryTrackerTest : public testing::Test {
81 protected:
82  static const int32 kNumCommandEntries = 400;
83  static const int32 kCommandBufferSizeBytes =
84      kNumCommandEntries * sizeof(CommandBufferEntry);
85
86  virtual void SetUp() {
87    command_buffer_.reset(new MockClientCommandBuffer());
88    helper_.reset(new GLES2CmdHelper(command_buffer_.get()));
89    helper_->Initialize(kCommandBufferSizeBytes);
90    mapped_memory_.reset(new MappedMemoryManager(
91        helper_.get(), base::Bind(&EmptyPoll), MappedMemoryManager::kNoLimit));
92    query_tracker_.reset(new QueryTracker(mapped_memory_.get()));
93  }
94
95  virtual void TearDown() {
96    query_tracker_.reset();
97    mapped_memory_.reset();
98    helper_.reset();
99    command_buffer_.reset();
100  }
101
102  QuerySync* GetSync(QueryTracker::Query* query) {
103    return query->info_.sync;
104  }
105
106  QuerySyncManager::Bucket* GetBucket(QueryTracker::Query* query) {
107    return query->info_.bucket;
108  }
109
110  uint32 GetFlushGeneration() { return helper_->flush_generation(); }
111
112  scoped_ptr<CommandBuffer> command_buffer_;
113  scoped_ptr<GLES2CmdHelper> helper_;
114  scoped_ptr<MappedMemoryManager> mapped_memory_;
115  scoped_ptr<QueryTracker> query_tracker_;
116};
117
118TEST_F(QueryTrackerTest, Basic) {
119  const GLuint kId1 = 123;
120  const GLuint kId2 = 124;
121
122  // Check we can create a Query.
123  QueryTracker::Query* query = query_tracker_->CreateQuery(
124      kId1, GL_ANY_SAMPLES_PASSED_EXT);
125  ASSERT_TRUE(query != NULL);
126  // Check we can get the same Query.
127  EXPECT_EQ(query, query_tracker_->GetQuery(kId1));
128  // Check we get nothing for a non-existent query.
129  EXPECT_TRUE(query_tracker_->GetQuery(kId2) == NULL);
130  // Check we can delete the query.
131  query_tracker_->RemoveQuery(kId1);
132  // Check we get nothing for a non-existent query.
133  EXPECT_TRUE(query_tracker_->GetQuery(kId1) == NULL);
134}
135
136TEST_F(QueryTrackerTest, Query) {
137  const GLuint kId1 = 123;
138  const int32 kToken = 46;
139  const uint32 kResult = 456;
140
141  // Create a Query.
142  QueryTracker::Query* query = query_tracker_->CreateQuery(
143      kId1, GL_ANY_SAMPLES_PASSED_EXT);
144  ASSERT_TRUE(query != NULL);
145  EXPECT_TRUE(query->NeverUsed());
146  EXPECT_FALSE(query->Pending());
147  EXPECT_EQ(0, query->token());
148  EXPECT_EQ(0, query->submit_count());
149
150  // Check MarkAsActive.
151  query->MarkAsActive();
152  EXPECT_FALSE(query->NeverUsed());
153  EXPECT_FALSE(query->Pending());
154  EXPECT_EQ(0, query->token());
155  EXPECT_EQ(1, query->submit_count());
156
157  // Check MarkAsPending.
158  query->MarkAsPending(kToken);
159  EXPECT_FALSE(query->NeverUsed());
160  EXPECT_TRUE(query->Pending());
161  EXPECT_EQ(kToken, query->token());
162  EXPECT_EQ(1, query->submit_count());
163
164  // Check CheckResultsAvailable.
165  EXPECT_FALSE(query->CheckResultsAvailable(helper_.get()));
166  EXPECT_FALSE(query->NeverUsed());
167  EXPECT_TRUE(query->Pending());
168
169  // Flush only once if no more flushes happened between a call to
170  // EndQuery command and CheckResultsAvailable
171  // Advance put_ so flush calls in CheckResultsAvailable go through
172  // and updates flush_generation count
173  helper_->Noop(1);
174  // Set Query in pending state_ to simulate EndQuery command is called
175  query->MarkAsPending(kToken);
176  EXPECT_TRUE(query->Pending());
177  // Store FlushGeneration count after EndQuery is called
178  uint32 gen1 = GetFlushGeneration();
179  EXPECT_FALSE(query->CheckResultsAvailable(helper_.get()));
180  uint32 gen2 = GetFlushGeneration();
181  EXPECT_NE(gen1, gen2);
182  // Repeated calls to CheckResultsAvailable should not flush unnecessarily
183  EXPECT_FALSE(query->CheckResultsAvailable(helper_.get()));
184  gen1 = GetFlushGeneration();
185  EXPECT_EQ(gen1, gen2);
186  EXPECT_FALSE(query->CheckResultsAvailable(helper_.get()));
187  gen1 = GetFlushGeneration();
188  EXPECT_EQ(gen1, gen2);
189
190  // Simulate GPU process marking it as available.
191  QuerySync* sync = GetSync(query);
192  sync->process_count = query->submit_count();
193  sync->result = kResult;
194
195  // Check CheckResultsAvailable.
196  EXPECT_TRUE(query->CheckResultsAvailable(helper_.get()));
197  EXPECT_EQ(kResult, query->GetResult());
198  EXPECT_FALSE(query->NeverUsed());
199  EXPECT_FALSE(query->Pending());
200}
201
202TEST_F(QueryTrackerTest, Remove) {
203  const GLuint kId1 = 123;
204  const int32 kToken = 46;
205  const uint32 kResult = 456;
206
207  // Create a Query.
208  QueryTracker::Query* query = query_tracker_->CreateQuery(
209      kId1, GL_ANY_SAMPLES_PASSED_EXT);
210  ASSERT_TRUE(query != NULL);
211
212  QuerySyncManager::Bucket* bucket = GetBucket(query);
213  EXPECT_EQ(1u, bucket->used_query_count);
214
215  query->MarkAsActive();
216  query->MarkAsPending(kToken);
217
218  query_tracker_->RemoveQuery(kId1);
219  // Check we get nothing for a non-existent query.
220  EXPECT_TRUE(query_tracker_->GetQuery(kId1) == NULL);
221
222  // Check that memory was not freed.
223  EXPECT_EQ(1u, bucket->used_query_count);
224
225  // Simulate GPU process marking it as available.
226  QuerySync* sync = GetSync(query);
227  sync->process_count = query->submit_count();
228  sync->result = kResult;
229
230  // Check FreeCompletedQueries.
231  query_tracker_->FreeCompletedQueries();
232  EXPECT_EQ(0u, bucket->used_query_count);
233}
234
235}  // namespace gles2
236}  // namespace gpu
237
238
239