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 Command Buffer Helper.
6
7#include "gpu/command_buffer/client/transfer_buffer.h"
8
9#include "base/compiler_specific.h"
10#include "gpu/command_buffer/client/client_test_helper.h"
11#include "gpu/command_buffer/client/cmd_buffer_helper.h"
12#include "gpu/command_buffer/common/command_buffer.h"
13#include "testing/gtest/include/gtest/gtest.h"
14#include "testing/gmock/include/gmock/gmock.h"
15
16using ::testing::_;
17using ::testing::AtMost;
18using ::testing::Invoke;
19using ::testing::Return;
20using ::testing::SetArgPointee;
21using ::testing::StrictMock;
22
23namespace gpu {
24
25
26class TransferBufferTest : public testing::Test {
27 protected:
28  static const int32 kNumCommandEntries = 400;
29  static const int32 kCommandBufferSizeBytes =
30      kNumCommandEntries * sizeof(CommandBufferEntry);
31  static const unsigned int kStartingOffset = 64;
32  static const unsigned int kAlignment = 4;
33  static const size_t kTransferBufferSize = 256;
34
35  TransferBufferTest()
36      : transfer_buffer_id_(0) {
37  }
38
39  virtual void SetUp() OVERRIDE;
40  virtual void TearDown() OVERRIDE;
41
42  virtual void Initialize(unsigned int size_to_flush) {
43    ASSERT_TRUE(transfer_buffer_->Initialize(
44        kTransferBufferSize,
45        kStartingOffset,
46        kTransferBufferSize,
47        kTransferBufferSize,
48        kAlignment,
49        size_to_flush));
50  }
51
52  MockClientCommandBufferMockFlush* command_buffer() const {
53    return command_buffer_.get();
54  }
55
56  scoped_ptr<MockClientCommandBufferMockFlush> command_buffer_;
57  scoped_ptr<CommandBufferHelper> helper_;
58  scoped_ptr<TransferBuffer> transfer_buffer_;
59  int32 transfer_buffer_id_;
60};
61
62void TransferBufferTest::SetUp() {
63  command_buffer_.reset(new StrictMock<MockClientCommandBufferMockFlush>());
64  ASSERT_TRUE(command_buffer_->Initialize());
65
66  helper_.reset(new CommandBufferHelper(command_buffer()));
67  ASSERT_TRUE(helper_->Initialize(kCommandBufferSizeBytes));
68
69  transfer_buffer_id_ = command_buffer()->GetNextFreeTransferBufferId();
70
71  transfer_buffer_.reset(new TransferBuffer(helper_.get()));
72}
73
74void TransferBufferTest::TearDown() {
75  if (transfer_buffer_->HaveBuffer()) {
76    EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
77        .Times(1)
78        .RetiresOnSaturation();
79  }
80  // For command buffer.
81  EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
82      .Times(1)
83      .RetiresOnSaturation();
84  EXPECT_CALL(*command_buffer(), OnFlush()).Times(AtMost(1));
85  transfer_buffer_.reset();
86}
87
88// GCC requires these declarations, but MSVC requires they not be present
89#ifndef _MSC_VER
90const int32 TransferBufferTest::kNumCommandEntries;
91const int32 TransferBufferTest::kCommandBufferSizeBytes;
92const unsigned int TransferBufferTest::kStartingOffset;
93const unsigned int TransferBufferTest::kAlignment;
94const size_t TransferBufferTest::kTransferBufferSize;
95#endif
96
97TEST_F(TransferBufferTest, Basic) {
98  Initialize(0);
99  EXPECT_TRUE(transfer_buffer_->HaveBuffer());
100  EXPECT_EQ(transfer_buffer_id_, transfer_buffer_->GetShmId());
101  EXPECT_EQ(
102      kTransferBufferSize - kStartingOffset,
103      transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
104}
105
106TEST_F(TransferBufferTest, Free) {
107  Initialize(0);
108  EXPECT_TRUE(transfer_buffer_->HaveBuffer());
109  EXPECT_EQ(transfer_buffer_id_, transfer_buffer_->GetShmId());
110
111  // Free buffer.
112  EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
113      .Times(1)
114      .RetiresOnSaturation();
115  transfer_buffer_->Free();
116  // See it's freed.
117  EXPECT_FALSE(transfer_buffer_->HaveBuffer());
118  // See that it gets reallocated.
119  EXPECT_EQ(transfer_buffer_id_, transfer_buffer_->GetShmId());
120  EXPECT_TRUE(transfer_buffer_->HaveBuffer());
121
122  // Free buffer.
123  EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
124      .Times(1)
125      .RetiresOnSaturation();
126  transfer_buffer_->Free();
127  // See it's freed.
128  EXPECT_FALSE(transfer_buffer_->HaveBuffer());
129  // See that it gets reallocated.
130  EXPECT_TRUE(transfer_buffer_->GetResultBuffer() != NULL);
131  EXPECT_TRUE(transfer_buffer_->HaveBuffer());
132
133  // Free buffer.
134  EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
135      .Times(1)
136      .RetiresOnSaturation();
137  transfer_buffer_->Free();
138  // See it's freed.
139  EXPECT_FALSE(transfer_buffer_->HaveBuffer());
140  // See that it gets reallocated.
141  unsigned int size = 0;
142  void* data = transfer_buffer_->AllocUpTo(1, &size);
143  EXPECT_TRUE(data != NULL);
144  EXPECT_TRUE(transfer_buffer_->HaveBuffer());
145  transfer_buffer_->FreePendingToken(data, 1);
146
147  // Free buffer.
148  EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
149      .Times(1)
150      .RetiresOnSaturation();
151  transfer_buffer_->Free();
152  // See it's freed.
153  EXPECT_FALSE(transfer_buffer_->HaveBuffer());
154  // See that it gets reallocated.
155  transfer_buffer_->GetResultOffset();
156  EXPECT_TRUE(transfer_buffer_->HaveBuffer());
157
158  EXPECT_EQ(
159      kTransferBufferSize - kStartingOffset,
160      transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
161
162  // Test freeing twice.
163  EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
164      .Times(1)
165      .RetiresOnSaturation();
166  transfer_buffer_->Free();
167  transfer_buffer_->Free();
168}
169
170TEST_F(TransferBufferTest, TooLargeAllocation) {
171  Initialize(0);
172  // Check that we can't allocate large than max size.
173  void* ptr = transfer_buffer_->Alloc(kTransferBufferSize + 1);
174  EXPECT_TRUE(ptr == NULL);
175  // Check we if we try to allocate larger than max we get max.
176  unsigned int size_allocated = 0;
177  ptr = transfer_buffer_->AllocUpTo(
178      kTransferBufferSize + 1, &size_allocated);
179  ASSERT_TRUE(ptr != NULL);
180  EXPECT_EQ(kTransferBufferSize - kStartingOffset, size_allocated);
181  transfer_buffer_->FreePendingToken(ptr, 1);
182}
183
184TEST_F(TransferBufferTest, MemoryAlignmentAfterZeroAllocation) {
185  Initialize(32u);
186  void* ptr = transfer_buffer_->Alloc(0);
187  EXPECT_EQ((reinterpret_cast<uintptr_t>(ptr) & (kAlignment - 1)), 0u);
188  transfer_buffer_->FreePendingToken(ptr, static_cast<unsigned int>(-1));
189  // Check that the pointer is aligned on the following allocation.
190  ptr = transfer_buffer_->Alloc(4);
191  EXPECT_EQ((reinterpret_cast<uintptr_t>(ptr) & (kAlignment - 1)), 0u);
192  transfer_buffer_->FreePendingToken(ptr, 1);
193}
194
195TEST_F(TransferBufferTest, Flush) {
196  Initialize(16u);
197  unsigned int size_allocated = 0;
198  for (int i = 0; i < 8; ++i) {
199    void* ptr = transfer_buffer_->AllocUpTo(8u, &size_allocated);
200    ASSERT_TRUE(ptr != NULL);
201    EXPECT_EQ(8u, size_allocated);
202    if (i % 2) {
203      EXPECT_CALL(*command_buffer(), Flush(_))
204          .Times(1)
205          .RetiresOnSaturation();
206    }
207    transfer_buffer_->FreePendingToken(ptr, helper_->InsertToken());
208  }
209  for (int i = 0; i < 8; ++i) {
210    void* ptr = transfer_buffer_->Alloc(8u);
211    ASSERT_TRUE(ptr != NULL);
212    if (i % 2) {
213      EXPECT_CALL(*command_buffer(), Flush(_))
214          .Times(1)
215          .RetiresOnSaturation();
216    }
217    transfer_buffer_->FreePendingToken(ptr, helper_->InsertToken());
218  }
219}
220
221class MockClientCommandBufferCanFail : public MockClientCommandBufferMockFlush {
222 public:
223  MockClientCommandBufferCanFail() {
224  }
225  virtual ~MockClientCommandBufferCanFail() {
226  }
227
228  MOCK_METHOD2(CreateTransferBuffer,
229               scoped_refptr<Buffer>(size_t size, int32* id));
230
231  scoped_refptr<gpu::Buffer> RealCreateTransferBuffer(size_t size, int32* id) {
232    return MockCommandBufferBase::CreateTransferBuffer(size, id);
233  }
234};
235
236class TransferBufferExpandContractTest : public testing::Test {
237 protected:
238  static const int32 kNumCommandEntries = 400;
239  static const int32 kCommandBufferSizeBytes =
240      kNumCommandEntries * sizeof(CommandBufferEntry);
241  static const unsigned int kStartingOffset = 64;
242  static const unsigned int kAlignment = 4;
243  static const size_t kStartTransferBufferSize = 256;
244  static const size_t kMaxTransferBufferSize = 1024;
245  static const size_t kMinTransferBufferSize = 128;
246
247  TransferBufferExpandContractTest()
248      : transfer_buffer_id_(0) {
249  }
250
251  virtual void SetUp() OVERRIDE;
252  virtual void TearDown() OVERRIDE;
253
254  MockClientCommandBufferCanFail* command_buffer() const {
255    return command_buffer_.get();
256  }
257
258  scoped_ptr<MockClientCommandBufferCanFail> command_buffer_;
259  scoped_ptr<CommandBufferHelper> helper_;
260  scoped_ptr<TransferBuffer> transfer_buffer_;
261  int32 transfer_buffer_id_;
262};
263
264void TransferBufferExpandContractTest::SetUp() {
265  command_buffer_.reset(new StrictMock<MockClientCommandBufferCanFail>());
266  ASSERT_TRUE(command_buffer_->Initialize());
267
268  EXPECT_CALL(*command_buffer(),
269              CreateTransferBuffer(kCommandBufferSizeBytes, _))
270      .WillOnce(Invoke(
271          command_buffer(),
272          &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
273      .RetiresOnSaturation();
274
275  helper_.reset(new CommandBufferHelper(command_buffer()));
276  ASSERT_TRUE(helper_->Initialize(kCommandBufferSizeBytes));
277
278  transfer_buffer_id_ = command_buffer()->GetNextFreeTransferBufferId();
279
280  EXPECT_CALL(*command_buffer(),
281              CreateTransferBuffer(kStartTransferBufferSize, _))
282      .WillOnce(Invoke(
283          command_buffer(),
284          &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
285      .RetiresOnSaturation();
286
287  transfer_buffer_.reset(new TransferBuffer(helper_.get()));
288  ASSERT_TRUE(transfer_buffer_->Initialize(
289      kStartTransferBufferSize,
290      kStartingOffset,
291      kMinTransferBufferSize,
292      kMaxTransferBufferSize,
293      kAlignment,
294      0));
295}
296
297void TransferBufferExpandContractTest::TearDown() {
298  if (transfer_buffer_->HaveBuffer()) {
299    EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
300        .Times(1)
301        .RetiresOnSaturation();
302  }
303  // For command buffer.
304  EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
305      .Times(1)
306      .RetiresOnSaturation();
307  transfer_buffer_.reset();
308}
309
310// GCC requires these declarations, but MSVC requires they not be present
311#ifndef _MSC_VER
312const int32 TransferBufferExpandContractTest::kNumCommandEntries;
313const int32 TransferBufferExpandContractTest::kCommandBufferSizeBytes;
314const unsigned int TransferBufferExpandContractTest::kStartingOffset;
315const unsigned int TransferBufferExpandContractTest::kAlignment;
316const size_t TransferBufferExpandContractTest::kStartTransferBufferSize;
317const size_t TransferBufferExpandContractTest::kMaxTransferBufferSize;
318const size_t TransferBufferExpandContractTest::kMinTransferBufferSize;
319#endif
320
321TEST_F(TransferBufferExpandContractTest, Expand) {
322  // Check it starts at starting size.
323  EXPECT_EQ(
324      kStartTransferBufferSize - kStartingOffset,
325      transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
326
327  EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
328      .Times(1)
329      .RetiresOnSaturation();
330  EXPECT_CALL(*command_buffer(),
331              CreateTransferBuffer(kStartTransferBufferSize * 2, _))
332      .WillOnce(Invoke(
333          command_buffer(),
334          &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
335      .RetiresOnSaturation();
336
337  // Try next power of 2.
338  const size_t kSize1 = 512 - kStartingOffset;
339  unsigned int size_allocated = 0;
340  void* ptr = transfer_buffer_->AllocUpTo(kSize1, &size_allocated);
341  ASSERT_TRUE(ptr != NULL);
342  EXPECT_EQ(kSize1, size_allocated);
343  EXPECT_EQ(kSize1, transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
344  transfer_buffer_->FreePendingToken(ptr, 1);
345
346  EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
347      .Times(1)
348      .RetiresOnSaturation();
349  EXPECT_CALL(*command_buffer(),
350              CreateTransferBuffer(kMaxTransferBufferSize, _))
351      .WillOnce(Invoke(
352          command_buffer(),
353          &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
354      .RetiresOnSaturation();
355
356  // Try next power of 2.
357  const size_t kSize2 = 1024 - kStartingOffset;
358  ptr = transfer_buffer_->AllocUpTo(kSize2, &size_allocated);
359  ASSERT_TRUE(ptr != NULL);
360  EXPECT_EQ(kSize2, size_allocated);
361  EXPECT_EQ(kSize2, transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
362  transfer_buffer_->FreePendingToken(ptr, 1);
363
364  // Try next one more. Should not go past max.
365  size_allocated = 0;
366  const size_t kSize3 = kSize2 + 1;
367  ptr = transfer_buffer_->AllocUpTo(kSize3, &size_allocated);
368  EXPECT_EQ(kSize2, size_allocated);
369  EXPECT_EQ(kSize2, transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
370  transfer_buffer_->FreePendingToken(ptr, 1);
371}
372
373TEST_F(TransferBufferExpandContractTest, Contract) {
374  // Check it starts at starting size.
375  EXPECT_EQ(
376      kStartTransferBufferSize - kStartingOffset,
377      transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
378
379  // Free buffer.
380  EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
381      .Times(1)
382      .RetiresOnSaturation();
383  transfer_buffer_->Free();
384  // See it's freed.
385  EXPECT_FALSE(transfer_buffer_->HaveBuffer());
386
387  // Try to allocate again, fail first request
388  EXPECT_CALL(*command_buffer(),
389              CreateTransferBuffer(kStartTransferBufferSize, _))
390      .WillOnce(
391           DoAll(SetArgPointee<1>(-1), Return(scoped_refptr<gpu::Buffer>())))
392      .RetiresOnSaturation();
393  EXPECT_CALL(*command_buffer(),
394              CreateTransferBuffer(kMinTransferBufferSize, _))
395      .WillOnce(Invoke(
396          command_buffer(),
397          &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
398      .RetiresOnSaturation();
399
400  const size_t kSize1 = 256 - kStartingOffset;
401  const size_t kSize2 = 128 - kStartingOffset;
402  unsigned int size_allocated = 0;
403  void* ptr = transfer_buffer_->AllocUpTo(kSize1, &size_allocated);
404  ASSERT_TRUE(ptr != NULL);
405  EXPECT_EQ(kSize2, size_allocated);
406  EXPECT_EQ(kSize2, transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
407  transfer_buffer_->FreePendingToken(ptr, 1);
408
409  // Free buffer.
410  EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
411      .Times(1)
412      .RetiresOnSaturation();
413  transfer_buffer_->Free();
414  // See it's freed.
415  EXPECT_FALSE(transfer_buffer_->HaveBuffer());
416
417  // Try to allocate again,
418  EXPECT_CALL(*command_buffer(),
419              CreateTransferBuffer(kMinTransferBufferSize, _))
420      .WillOnce(Invoke(
421          command_buffer(),
422          &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
423      .RetiresOnSaturation();
424
425  ptr = transfer_buffer_->AllocUpTo(kSize1, &size_allocated);
426  ASSERT_TRUE(ptr != NULL);
427  EXPECT_EQ(kSize2, size_allocated);
428  EXPECT_EQ(kSize2, transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
429  transfer_buffer_->FreePendingToken(ptr, 1);
430}
431
432TEST_F(TransferBufferExpandContractTest, OutOfMemory) {
433  // Free buffer.
434  EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
435      .Times(1)
436      .RetiresOnSaturation();
437  transfer_buffer_->Free();
438  // See it's freed.
439  EXPECT_FALSE(transfer_buffer_->HaveBuffer());
440
441  // Try to allocate again, fail both requests.
442  EXPECT_CALL(*command_buffer(), CreateTransferBuffer(_, _))
443      .WillOnce(
444           DoAll(SetArgPointee<1>(-1), Return(scoped_refptr<gpu::Buffer>())))
445      .WillOnce(
446           DoAll(SetArgPointee<1>(-1), Return(scoped_refptr<gpu::Buffer>())))
447      .WillOnce(
448           DoAll(SetArgPointee<1>(-1), Return(scoped_refptr<gpu::Buffer>())))
449      .RetiresOnSaturation();
450
451  const size_t kSize1 = 512 - kStartingOffset;
452  unsigned int size_allocated = 0;
453  void* ptr = transfer_buffer_->AllocUpTo(kSize1, &size_allocated);
454  ASSERT_TRUE(ptr == NULL);
455  EXPECT_FALSE(transfer_buffer_->HaveBuffer());
456}
457
458TEST_F(TransferBufferExpandContractTest, ReallocsToDefault) {
459  // Free buffer.
460  EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
461      .Times(1)
462      .RetiresOnSaturation();
463  transfer_buffer_->Free();
464  // See it's freed.
465  EXPECT_FALSE(transfer_buffer_->HaveBuffer());
466
467  // See that it gets reallocated.
468  EXPECT_CALL(*command_buffer(),
469              CreateTransferBuffer(kStartTransferBufferSize, _))
470      .WillOnce(Invoke(
471          command_buffer(),
472          &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
473      .RetiresOnSaturation();
474  EXPECT_EQ(transfer_buffer_id_, transfer_buffer_->GetShmId());
475  EXPECT_TRUE(transfer_buffer_->HaveBuffer());
476
477  // Check it's the default size.
478  EXPECT_EQ(
479      kStartTransferBufferSize - kStartingOffset,
480      transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
481}
482
483}  // namespace gpu
484
485
486