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