blob: a9503190d29870efecf270d1952eeabe807f0d01 [file] [log] [blame]
// Copyright (c) 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "gpu/command_buffer/client/transfer_buffer_cmd_copy_helpers.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace gpu {
namespace {
// Define a fake scoped transfer buffer to test helpers
class FakeScopedTransferBufferPtr {
public:
FakeScopedTransferBufferPtr(uint32_t max_size)
: valid_(false), max_size_(max_size), buffer_() {}
void Reset(uint32_t size) {
buffer_.resize(std::min(max_size_, size));
std::fill(buffer_.begin(), buffer_.end(), 0);
valid_ = true;
}
void Release() { buffer_.clear(); }
uint32_t size() const { return static_cast<uint32_t>(buffer_.size()); }
bool valid() const { return valid_; }
void* address() { return buffer_.data(); }
private:
bool valid_;
uint32_t max_size_;
std::vector<uint8_t> buffer_;
};
constexpr uint32_t MaxCopyCount(uint32_t buffer_size) {
return ComputeMaxCopyCount<char, short, float, size_t>(buffer_size);
}
} // namespace
class TransferBufferCmdCopyHelpersTest : public testing::Test {
protected:
struct BigStruct {
std::array<char, UINT32_MAX> a;
};
struct ExpectedBuffers {
std::vector<char> a;
std::vector<short> b;
std::vector<float> c;
std::vector<size_t> d;
ExpectedBuffers(uint32_t count) : a(count), b(count), c(count), d(count) {
uint32_t j = 0;
for (uint32_t i = 0; i < count; ++i) {
a[i] = static_cast<char>(j++);
}
for (uint32_t i = 0; i < count; ++i) {
b[i] = static_cast<short>(j++);
}
for (uint32_t i = 0; i < count; ++i) {
c[i] = static_cast<float>(j++);
}
for (uint32_t i = 0; i < count; ++i) {
d[i] = static_cast<size_t>(j++);
}
}
};
template <uint32_t BufferSize>
void CheckTransferArraysAndExecute(uint32_t count) {
FakeScopedTransferBufferPtr transfer_buffer(BufferSize);
ExpectedBuffers expected(count);
EXPECT_TRUE(::internal::TransferArraysAndExecute(
count, &transfer_buffer,
[&](std::array<uint32_t, 4>& byte_offsets, uint32_t copy_offset,
uint32_t copy_count) {
// Check that each sub-copy is correct
const uint8_t* buffer =
reinterpret_cast<uint8_t*>(transfer_buffer.address());
EXPECT_EQ(memcmp(&buffer[byte_offsets[0]], &expected.a[copy_offset],
copy_count * sizeof(char)),
0);
EXPECT_EQ(memcmp(&buffer[byte_offsets[1]], &expected.b[copy_offset],
copy_count * sizeof(short)),
0);
EXPECT_EQ(memcmp(&buffer[byte_offsets[2]], &expected.c[copy_offset],
copy_count * sizeof(float)),
0);
EXPECT_EQ(memcmp(&buffer[byte_offsets[3]], &expected.d[copy_offset],
copy_count * sizeof(size_t)),
0);
},
expected.a.data(), expected.b.data(), expected.c.data(),
expected.d.data()));
}
};
// Check packed size computation
TEST_F(TransferBufferCmdCopyHelpersTest, CheckedSizeOfTypes) {
EXPECT_EQ((SizeOfPackedTypes<uint32_t, char>()), sizeof(bool));
EXPECT_EQ((SizeOfPackedTypes<uint32_t, int>()), sizeof(int));
EXPECT_EQ((SizeOfPackedTypes<uint32_t, float>()), sizeof(float));
EXPECT_EQ((SizeOfPackedTypes<uint32_t, float, int>()),
sizeof(float) + sizeof(int));
EXPECT_EQ((SizeOfPackedTypes<uint32_t, BigStruct>()), sizeof(BigStruct));
}
// Check copy size computations which do not require padding elements
TEST_F(TransferBufferCmdCopyHelpersTest, ComputeCombinedCopySizeAligned) {
EXPECT_EQ((ComputeCombinedCopySize<char, int, float>(4)),
4 * sizeof(char) + 4 * sizeof(int) + 4 * sizeof(float));
EXPECT_EQ((ComputeCombinedCopySize<float, int, char>(3)),
3 * sizeof(float) + 3 * sizeof(int) + 3 * sizeof(char));
EXPECT_EQ((ComputeCombinedCopySize<BigStruct>(1)), sizeof(BigStruct));
}
// Check copy size computations where elements do require padding
TEST_F(TransferBufferCmdCopyHelpersTest, ComputeCombinedCopySizeUnaligned) {
EXPECT_EQ((ComputeCombinedCopySize<char, int, float>(3)),
4 * sizeof(char) + 3 * sizeof(int) + 3 * sizeof(float));
EXPECT_EQ((ComputeCombinedCopySize<char, int, float>(5)),
8 * sizeof(char) + 5 * sizeof(int) + 5 * sizeof(float));
}
// Check that overflow in copy size computation returns UINT32_MAX
TEST_F(TransferBufferCmdCopyHelpersTest, ComputeCombinedCopySizeOverflow) {
EXPECT_EQ((ComputeCombinedCopySize<BigStruct, short>(1)), UINT32_MAX);
EXPECT_EQ((ComputeCombinedCopySize<short, BigStruct>(1)), UINT32_MAX);
EXPECT_EQ((ComputeCombinedCopySize<float>(UINT32_MAX / sizeof(float) + 1)),
UINT32_MAX);
EXPECT_EQ((ComputeCombinedCopySize<BigStruct, BigStruct>(2)), UINT32_MAX);
}
// Check that the computed copy count is correct when padding is not required
TEST_F(TransferBufferCmdCopyHelpersTest, ComputeMaxCopyCountAligned) {
EXPECT_EQ((ComputeMaxCopyCount<BigStruct>(UINT32_MAX)), 1u);
EXPECT_EQ((ComputeMaxCopyCount<int, float>(64)), 8u);
EXPECT_EQ((ComputeMaxCopyCount<char>(64)), 64u);
EXPECT_EQ((ComputeMaxCopyCount<short, char, char>(64)), 16u);
}
// Check that the computed copy count is correct when padding is required
TEST_F(TransferBufferCmdCopyHelpersTest, ComputeMaxCopyCountUnaligned) {
EXPECT_EQ((ComputeMaxCopyCount<char, int, float>(64)), 7u);
EXPECT_EQ((ComputeMaxCopyCount<char, short, int>(64)), 9u);
}
// Check that computing copy count for a buffer of size 0 is 0;
TEST_F(TransferBufferCmdCopyHelpersTest, ComputeMaxCopyCountZero) {
uint32_t buffer_size = 0;
EXPECT_EQ((ComputeMaxCopyCount<char>(buffer_size)), 0u);
EXPECT_EQ((ComputeMaxCopyCount<int, float>(buffer_size)), 0u);
EXPECT_EQ((ComputeMaxCopyCount<BigStruct>(buffer_size)), 0u);
}
// Check that copy count for elements whose packed size fits in the buffer
// but computed aligned size does not is 0
TEST_F(TransferBufferCmdCopyHelpersTest, ComputeMaxCopyCountOverflow) {
EXPECT_EQ((ComputeMaxCopyCount<char, float>(
SizeOfPackedTypes<uint32_t, char, float>())),
0u);
EXPECT_EQ((ComputeMaxCopyCount<short, float>(
SizeOfPackedTypes<uint32_t, short, float>())),
0u);
EXPECT_EQ((ComputeMaxCopyCount<char, size_t>(
SizeOfPackedTypes<uint32_t, char, size_t>())),
0u);
EXPECT_EQ((ComputeMaxCopyCount<short, size_t>(
SizeOfPackedTypes<uint32_t, short, size_t>())),
0u);
}
// Check that copied results are as expected and correctly aligned
TEST_F(TransferBufferCmdCopyHelpersTest, TransferArraysAndExecute) {
// Aligned: Copy 1 element from each buffer into a transfer buffer of 256
// bytes
CheckTransferArraysAndExecute<256>(1);
// Aligned: Copy as many elements as possible from each buffer into a transfer
// buffer of 256 bytes
CheckTransferArraysAndExecute<256>(MaxCopyCount(256));
// Unaligned: Copy 1 element from each buffer into a transfer buffer of 256
// bytes
CheckTransferArraysAndExecute<257>(1);
// Unaligned: Copy as many elements as possible from each buffer into a
// transfer buffer of 257 bytes
CheckTransferArraysAndExecute<257>(MaxCopyCount(257));
// Large: Copy 1 element from each buffer into a transfer buffer of UINT32_MAX
// bytes
CheckTransferArraysAndExecute<UINT32_MAX>(1);
// Large: Copy as many elements as possible from each buffer into a transfer
// buffer of 256 bytes
CheckTransferArraysAndExecute<UINT32_MAX>(MaxCopyCount(256));
}
// Check copies that overflow and require multiple transfer buffers
TEST_F(TransferBufferCmdCopyHelpersTest, TransferArraysAndExecuteOverflow) {
// Check aligned transfers
CheckTransferArraysAndExecute<256>(256);
CheckTransferArraysAndExecute<256>(512);
CheckTransferArraysAndExecute<4096>(64 * MaxCopyCount(4096));
// Check unaligned transfers
CheckTransferArraysAndExecute<257>(256);
CheckTransferArraysAndExecute<253>(513);
CheckTransferArraysAndExecute<4097>(MaxCopyCount(4097));
}
} // namespace gpu