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, Flush) {
185  Initialize(16u);
186  unsigned int size_allocated = 0;
187  for (int i = 0; i < 8; ++i) {
188    void* ptr = transfer_buffer_->AllocUpTo(8u, &size_allocated);
189    ASSERT_TRUE(ptr != NULL);
190    EXPECT_EQ(8u, size_allocated);
191    if (i % 2) {
192      EXPECT_CALL(*command_buffer(), Flush(_))
193          .Times(1)
194          .RetiresOnSaturation();
195    }
196    transfer_buffer_->FreePendingToken(ptr, helper_->InsertToken());
197  }
198  for (int i = 0; i < 8; ++i) {
199    void* ptr = transfer_buffer_->Alloc(8u);
200    ASSERT_TRUE(ptr != NULL);
201    if (i % 2) {
202      EXPECT_CALL(*command_buffer(), Flush(_))
203          .Times(1)
204          .RetiresOnSaturation();
205    }
206    transfer_buffer_->FreePendingToken(ptr, helper_->InsertToken());
207  }
208}
209
210class MockClientCommandBufferCanFail : public MockClientCommandBufferMockFlush {
211 public:
212  MockClientCommandBufferCanFail() {
213  }
214  virtual ~MockClientCommandBufferCanFail() {
215  }
216
217  MOCK_METHOD2(CreateTransferBuffer, Buffer(size_t size, int32* id));
218
219  Buffer RealCreateTransferBuffer(size_t size, int32* id) {
220    return MockCommandBufferBase::CreateTransferBuffer(size, id);
221  }
222};
223
224class TransferBufferExpandContractTest : public testing::Test {
225 protected:
226  static const int32 kNumCommandEntries = 400;
227  static const int32 kCommandBufferSizeBytes =
228      kNumCommandEntries * sizeof(CommandBufferEntry);
229  static const unsigned int kStartingOffset = 64;
230  static const unsigned int kAlignment = 4;
231  static const size_t kStartTransferBufferSize = 256;
232  static const size_t kMaxTransferBufferSize = 1024;
233  static const size_t kMinTransferBufferSize = 128;
234
235  TransferBufferExpandContractTest()
236      : transfer_buffer_id_(0) {
237  }
238
239  virtual void SetUp() OVERRIDE;
240  virtual void TearDown() OVERRIDE;
241
242  MockClientCommandBufferCanFail* command_buffer() const {
243    return command_buffer_.get();
244  }
245
246  scoped_ptr<MockClientCommandBufferCanFail> command_buffer_;
247  scoped_ptr<CommandBufferHelper> helper_;
248  scoped_ptr<TransferBuffer> transfer_buffer_;
249  int32 transfer_buffer_id_;
250};
251
252void TransferBufferExpandContractTest::SetUp() {
253  command_buffer_.reset(new StrictMock<MockClientCommandBufferCanFail>());
254  ASSERT_TRUE(command_buffer_->Initialize());
255
256  EXPECT_CALL(*command_buffer(),
257              CreateTransferBuffer(kCommandBufferSizeBytes, _))
258      .WillOnce(Invoke(
259          command_buffer(),
260          &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
261      .RetiresOnSaturation();
262
263  helper_.reset(new CommandBufferHelper(command_buffer()));
264  ASSERT_TRUE(helper_->Initialize(kCommandBufferSizeBytes));
265
266  transfer_buffer_id_ = command_buffer()->GetNextFreeTransferBufferId();
267
268  EXPECT_CALL(*command_buffer(),
269              CreateTransferBuffer(kStartTransferBufferSize, _))
270      .WillOnce(Invoke(
271          command_buffer(),
272          &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
273      .RetiresOnSaturation();
274
275  transfer_buffer_.reset(new TransferBuffer(helper_.get()));
276  ASSERT_TRUE(transfer_buffer_->Initialize(
277      kStartTransferBufferSize,
278      kStartingOffset,
279      kMinTransferBufferSize,
280      kMaxTransferBufferSize,
281      kAlignment,
282      0));
283}
284
285void TransferBufferExpandContractTest::TearDown() {
286  if (transfer_buffer_->HaveBuffer()) {
287    EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
288        .Times(1)
289        .RetiresOnSaturation();
290  }
291  // For command buffer.
292  EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
293      .Times(1)
294      .RetiresOnSaturation();
295  transfer_buffer_.reset();
296}
297
298// GCC requires these declarations, but MSVC requires they not be present
299#ifndef _MSC_VER
300const int32 TransferBufferExpandContractTest::kNumCommandEntries;
301const int32 TransferBufferExpandContractTest::kCommandBufferSizeBytes;
302const unsigned int TransferBufferExpandContractTest::kStartingOffset;
303const unsigned int TransferBufferExpandContractTest::kAlignment;
304const size_t TransferBufferExpandContractTest::kStartTransferBufferSize;
305const size_t TransferBufferExpandContractTest::kMaxTransferBufferSize;
306const size_t TransferBufferExpandContractTest::kMinTransferBufferSize;
307#endif
308
309TEST_F(TransferBufferExpandContractTest, Expand) {
310  // Check it starts at starting size.
311  EXPECT_EQ(
312      kStartTransferBufferSize - kStartingOffset,
313      transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
314
315  EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
316      .Times(1)
317      .RetiresOnSaturation();
318  EXPECT_CALL(*command_buffer(),
319              CreateTransferBuffer(kStartTransferBufferSize * 2, _))
320      .WillOnce(Invoke(
321          command_buffer(),
322          &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
323      .RetiresOnSaturation();
324
325  // Try next power of 2.
326  const size_t kSize1 = 512 - kStartingOffset;
327  unsigned int size_allocated = 0;
328  void* ptr = transfer_buffer_->AllocUpTo(kSize1, &size_allocated);
329  ASSERT_TRUE(ptr != NULL);
330  EXPECT_EQ(kSize1, size_allocated);
331  EXPECT_EQ(kSize1, transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
332  transfer_buffer_->FreePendingToken(ptr, 1);
333
334  EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
335      .Times(1)
336      .RetiresOnSaturation();
337  EXPECT_CALL(*command_buffer(),
338              CreateTransferBuffer(kMaxTransferBufferSize, _))
339      .WillOnce(Invoke(
340          command_buffer(),
341          &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
342      .RetiresOnSaturation();
343
344  // Try next power of 2.
345  const size_t kSize2 = 1024 - kStartingOffset;
346  ptr = transfer_buffer_->AllocUpTo(kSize2, &size_allocated);
347  ASSERT_TRUE(ptr != NULL);
348  EXPECT_EQ(kSize2, size_allocated);
349  EXPECT_EQ(kSize2, transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
350  transfer_buffer_->FreePendingToken(ptr, 1);
351
352  // Try next one more. Should not go past max.
353  size_allocated = 0;
354  const size_t kSize3 = kSize2 + 1;
355  ptr = transfer_buffer_->AllocUpTo(kSize3, &size_allocated);
356  EXPECT_EQ(kSize2, size_allocated);
357  EXPECT_EQ(kSize2, transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
358  transfer_buffer_->FreePendingToken(ptr, 1);
359}
360
361TEST_F(TransferBufferExpandContractTest, Contract) {
362  // Check it starts at starting size.
363  EXPECT_EQ(
364      kStartTransferBufferSize - kStartingOffset,
365      transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
366
367  // Free buffer.
368  EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
369      .Times(1)
370      .RetiresOnSaturation();
371  transfer_buffer_->Free();
372  // See it's freed.
373  EXPECT_FALSE(transfer_buffer_->HaveBuffer());
374
375  // Try to allocate again, fail first request
376  EXPECT_CALL(*command_buffer(),
377              CreateTransferBuffer(kStartTransferBufferSize, _))
378      .WillOnce(DoAll(SetArgPointee<1>(-1), Return(Buffer())))
379      .RetiresOnSaturation();
380  EXPECT_CALL(*command_buffer(),
381              CreateTransferBuffer(kMinTransferBufferSize, _))
382      .WillOnce(Invoke(
383          command_buffer(),
384          &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
385      .RetiresOnSaturation();
386
387  const size_t kSize1 = 256 - kStartingOffset;
388  const size_t kSize2 = 128 - kStartingOffset;
389  unsigned int size_allocated = 0;
390  void* ptr = transfer_buffer_->AllocUpTo(kSize1, &size_allocated);
391  ASSERT_TRUE(ptr != NULL);
392  EXPECT_EQ(kSize2, size_allocated);
393  EXPECT_EQ(kSize2, transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
394  transfer_buffer_->FreePendingToken(ptr, 1);
395
396  // Free buffer.
397  EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
398      .Times(1)
399      .RetiresOnSaturation();
400  transfer_buffer_->Free();
401  // See it's freed.
402  EXPECT_FALSE(transfer_buffer_->HaveBuffer());
403
404  // Try to allocate again,
405  EXPECT_CALL(*command_buffer(),
406              CreateTransferBuffer(kMinTransferBufferSize, _))
407      .WillOnce(Invoke(
408          command_buffer(),
409          &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
410      .RetiresOnSaturation();
411
412  ptr = transfer_buffer_->AllocUpTo(kSize1, &size_allocated);
413  ASSERT_TRUE(ptr != NULL);
414  EXPECT_EQ(kSize2, size_allocated);
415  EXPECT_EQ(kSize2, transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
416  transfer_buffer_->FreePendingToken(ptr, 1);
417}
418
419TEST_F(TransferBufferExpandContractTest, OutOfMemory) {
420  // Free buffer.
421  EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
422      .Times(1)
423      .RetiresOnSaturation();
424  transfer_buffer_->Free();
425  // See it's freed.
426  EXPECT_FALSE(transfer_buffer_->HaveBuffer());
427
428  // Try to allocate again, fail both requests.
429  EXPECT_CALL(*command_buffer(), CreateTransferBuffer(_, _))
430      .WillOnce(DoAll(SetArgPointee<1>(-1), Return(Buffer())))
431      .WillOnce(DoAll(SetArgPointee<1>(-1), Return(Buffer())))
432      .WillOnce(DoAll(SetArgPointee<1>(-1), Return(Buffer())))
433      .RetiresOnSaturation();
434
435  const size_t kSize1 = 512 - kStartingOffset;
436  unsigned int size_allocated = 0;
437  void* ptr = transfer_buffer_->AllocUpTo(kSize1, &size_allocated);
438  ASSERT_TRUE(ptr == NULL);
439  EXPECT_FALSE(transfer_buffer_->HaveBuffer());
440}
441
442TEST_F(TransferBufferExpandContractTest, ReallocsToDefault) {
443  // Free buffer.
444  EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
445      .Times(1)
446      .RetiresOnSaturation();
447  transfer_buffer_->Free();
448  // See it's freed.
449  EXPECT_FALSE(transfer_buffer_->HaveBuffer());
450
451  // See that it gets reallocated.
452  EXPECT_CALL(*command_buffer(),
453              CreateTransferBuffer(kStartTransferBufferSize, _))
454      .WillOnce(Invoke(
455          command_buffer(),
456          &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
457      .RetiresOnSaturation();
458  EXPECT_EQ(transfer_buffer_id_, transfer_buffer_->GetShmId());
459  EXPECT_TRUE(transfer_buffer_->HaveBuffer());
460
461  // Check it's the default size.
462  EXPECT_EQ(
463      kStartTransferBufferSize - kStartingOffset,
464      transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
465}
466
467}  // namespace gpu
468
469
470