blob: 0f21797d48d1fafde17cf9567a35aaef42a623fb [file]
// Copyright 2016 The Fuchsia 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 <thread>
#include <gtest/gtest.h>
#include <mock/fake_address_space.h>
#include <mock/mock_bus_mapper.h>
#include "address_space.h"
#include "msd_intel_buffer.h"
using AllocatingAddressSpace = FakeAllocatingAddressSpace<GpuMapping, AddressSpace>;
using NonAllocatingAddressSpace = FakeNonAllocatingAddressSpace<GpuMapping, AddressSpace>;
class TestMsdIntelBuffer {
public:
class AddressSpaceOwner : public magma::AddressSpaceOwner {
public:
virtual ~AddressSpaceOwner() = default;
magma::PlatformBusMapper* GetBusMapper() override { return &bus_mapper_; }
private:
MockBusMapper bus_mapper_;
};
static void CreateAndDestroy() {
std::unique_ptr<MsdIntelBuffer> buffer;
uint64_t size;
buffer = MsdIntelBuffer::Create(size = 0, "test");
EXPECT_EQ(buffer, nullptr);
buffer = MsdIntelBuffer::Create(size = 100, "test");
EXPECT_NE(buffer, nullptr);
EXPECT_GE(buffer->platform_buffer()->size(), size);
buffer = MsdIntelBuffer::Create(size = 10000, "test");
EXPECT_NE(buffer, nullptr);
EXPECT_GE(buffer->platform_buffer()->size(), size);
}
static void AllocatingMapGpu() {
uint64_t base = PAGE_SIZE;
uint64_t size = PAGE_SIZE * 10;
auto address_space_owner = std::make_unique<AddressSpaceOwner>();
auto address_space =
std::make_shared<AllocatingAddressSpace>(address_space_owner.get(), base, size);
std::unique_ptr<MsdIntelBuffer> buffer(MsdIntelBuffer::Create(PAGE_SIZE, "test"));
ASSERT_NE(buffer, nullptr);
auto mapping = address_space->MapBufferGpu(address_space, std::move(buffer));
ASSERT_NE(mapping, nullptr);
gpu_addr_t gpu_addr = mapping->gpu_addr();
EXPECT_TRUE(address_space->is_allocated(gpu_addr));
EXPECT_FALSE(address_space->is_clear(gpu_addr));
mapping.reset();
EXPECT_FALSE(address_space->is_allocated(gpu_addr));
EXPECT_TRUE(address_space->is_clear(gpu_addr));
}
static void NonAllocatingMapGpuFail() {
constexpr uint64_t kAddressSpaceSize = PAGE_SIZE * 10;
auto address_space_owner = std::make_unique<AddressSpaceOwner>();
auto address_space =
std::make_shared<NonAllocatingAddressSpace>(address_space_owner.get(), kAddressSpaceSize);
constexpr uint64_t kBufferSizeInPages = 2;
auto buffer = std::shared_ptr<MsdIntelBuffer>(
MsdIntelBuffer::Create(kBufferSizeInPages * PAGE_SIZE, "test"));
ASSERT_TRUE(buffer);
std::shared_ptr<GpuMapping> mapping;
// Gpu address misaligned
EXPECT_FALSE(address_space->MapBufferGpu(address_space, buffer,
PAGE_SIZE + 1, // gpu addr
0, // page offset
kBufferSizeInPages - 1, // page count
&mapping));
// Bad page offset
EXPECT_FALSE(address_space->MapBufferGpu(address_space, buffer,
PAGE_SIZE, // gpu addr
kBufferSizeInPages, // page offset
1, // page count
&mapping));
// Bad page count
EXPECT_FALSE(address_space->MapBufferGpu(address_space, buffer,
PAGE_SIZE, // gpu addr
0, // page offset
kBufferSizeInPages + 1, // page count
&mapping));
// Bad page offset + count
EXPECT_FALSE(address_space->MapBufferGpu(address_space, buffer,
PAGE_SIZE, // gpu addr
1, // page offset
kBufferSizeInPages, // page count
&mapping));
// Won't fit
EXPECT_FALSE(address_space->MapBufferGpu(address_space, buffer,
kAddressSpaceSize - PAGE_SIZE, // gpu addr
0, // page offset
kBufferSizeInPages, // page count
&mapping));
}
static void NonAllocatingMapGpu() {
constexpr uint64_t kAddressSpaceSize = PAGE_SIZE * 10;
auto address_space_owner = std::make_unique<AddressSpaceOwner>();
auto address_space =
std::make_shared<NonAllocatingAddressSpace>(address_space_owner.get(), kAddressSpaceSize);
constexpr uint64_t kBufferSizeInPages = 2;
auto buffer = std::shared_ptr<MsdIntelBuffer>(
MsdIntelBuffer::Create(kBufferSizeInPages * PAGE_SIZE, "test"));
ASSERT_TRUE(buffer);
std::shared_ptr<GpuMapping> mapping;
// Start
EXPECT_TRUE(address_space->MapBufferGpu(address_space, buffer,
0, // gpu addr
0, // page offset
kBufferSizeInPages, // page count
&mapping));
// End
EXPECT_TRUE(
address_space->MapBufferGpu(address_space, buffer,
kAddressSpaceSize - kBufferSizeInPages * PAGE_SIZE, // gpu addr
0, // page offset
kBufferSizeInPages, // page count
&mapping));
// Middle
EXPECT_TRUE(address_space->MapBufferGpu(address_space, buffer,
PAGE_SIZE * 5, // gpu addr
0, // page offset
kBufferSizeInPages, // page count
&mapping));
// Partial from start
EXPECT_TRUE(address_space->MapBufferGpu(address_space, buffer,
PAGE_SIZE * 5, // gpu addr
1, // page offset
kBufferSizeInPages - 1, // page count
&mapping));
// Partial from end
EXPECT_TRUE(address_space->MapBufferGpu(address_space, buffer,
PAGE_SIZE * 5, // gpu addr
kBufferSizeInPages - 1, // page offset
1, // page count
&mapping));
}
static void SharedMapping(uint64_t size) {
auto address_space_owner = std::make_unique<AddressSpaceOwner>();
auto address_space = std::make_shared<AllocatingAddressSpace>(address_space_owner.get(), 0,
magma::round_up(size, PAGE_SIZE));
std::shared_ptr<MsdIntelBuffer> buffer(MsdIntelBuffer::Create(size, "test"));
ASSERT_NE(buffer, nullptr);
EXPECT_EQ(1u, buffer.use_count());
std::shared_ptr<GpuMapping> mapping = address_space->FindGpuMapping(
buffer->platform_buffer(), 0, buffer->platform_buffer()->size());
EXPECT_FALSE(mapping);
mapping = address_space->MapBufferGpu(address_space, buffer);
ASSERT_TRUE(mapping);
EXPECT_EQ(1u, mapping.use_count());
EXPECT_EQ(2u, buffer.use_count());
EXPECT_TRUE(address_space->AddMapping(mapping));
EXPECT_EQ(2u, mapping.use_count());
auto mapping2 = address_space->FindGpuMapping(buffer->platform_buffer(), 0,
buffer->platform_buffer()->size());
EXPECT_EQ(mapping, mapping2);
EXPECT_EQ(2u, buffer.use_count());
EXPECT_EQ(3u, mapping.use_count());
mapping.reset();
mapping2.reset();
// Mapping retained in the address space
EXPECT_EQ(2u, buffer.use_count());
std::vector<std::shared_ptr<GpuMapping>> mappings;
address_space->ReleaseBuffer(buffer->platform_buffer(), &mappings);
EXPECT_EQ(1u, mappings.size());
EXPECT_EQ(2u, buffer.use_count());
mappings.clear();
EXPECT_EQ(1u, buffer.use_count());
}
static void OverlappedMapping() {
auto address_space_owner = std::make_unique<AddressSpaceOwner>();
auto address_space =
std::make_shared<AllocatingAddressSpace>(address_space_owner.get(), 0, PAGE_SIZE * 10);
constexpr uint32_t kBufferSize = PAGE_SIZE * 6;
std::shared_ptr<MsdIntelBuffer> buffer(MsdIntelBuffer::Create(kBufferSize, "test"));
ASSERT_NE(buffer, nullptr);
EXPECT_EQ(1u, buffer.use_count());
std::shared_ptr<GpuMapping> mapping_low =
address_space->MapBufferGpu(address_space, buffer, 0, kBufferSize / 2);
ASSERT_TRUE(mapping_low);
EXPECT_TRUE(address_space->AddMapping(mapping_low));
EXPECT_EQ(2u, buffer.use_count());
std::shared_ptr<GpuMapping> mapping_high =
address_space->MapBufferGpu(address_space, buffer, kBufferSize / 2, kBufferSize / 2);
ASSERT_TRUE(mapping_high);
EXPECT_TRUE(address_space->AddMapping(mapping_high));
EXPECT_EQ(3u, buffer.use_count());
// not the same mapping
EXPECT_NE(mapping_low.get(), mapping_high.get());
std::shared_ptr<GpuMapping> mapping_full =
address_space->MapBufferGpu(address_space, buffer, 0, kBufferSize);
ASSERT_TRUE(mapping_full);
EXPECT_NE(mapping_full.get(), mapping_low.get());
EXPECT_NE(mapping_full.get(), mapping_high.get());
EXPECT_EQ(4u, buffer.use_count());
auto found_mapping_low =
address_space->FindGpuMapping(buffer->platform_buffer(), 0, kBufferSize / 2);
ASSERT_TRUE(found_mapping_low);
EXPECT_EQ(found_mapping_low.get(), mapping_low.get());
auto found_mapping_high = address_space->FindGpuMapping(
buffer->platform_buffer(), kBufferSize - kBufferSize / 2, kBufferSize / 2);
ASSERT_TRUE(found_mapping_high);
EXPECT_EQ(found_mapping_high.get(), mapping_high.get());
}
static void GrowMapping() {
constexpr uint32_t kSpaceSizeInPages = 10;
constexpr uint32_t kBufferSizeInPages = 8;
constexpr uint32_t kBufferPagesToGrow = 1;
auto address_space_owner = std::make_unique<AddressSpaceOwner>();
auto address_space = std::make_shared<NonAllocatingAddressSpace>(
address_space_owner.get(), magma::page_size() * kSpaceSizeInPages);
std::shared_ptr<MsdIntelBuffer> buffer(
MsdIntelBuffer::Create(kBufferSizeInPages * magma::page_size(), "test"));
ASSERT_TRUE(buffer);
std::shared_ptr<GpuMapping> mapping;
EXPECT_TRUE(address_space->MapBufferGpu(address_space, buffer,
0, // gpu addr
0, // page offset
kBufferSizeInPages - kBufferPagesToGrow, &mapping));
ASSERT_TRUE(mapping);
uint64_t orig_length = (kBufferSizeInPages - kBufferPagesToGrow) * magma::page_size();
EXPECT_EQ(mapping->length(), orig_length);
EXPECT_TRUE(address_space->GrowMapping(mapping.get(), kBufferPagesToGrow));
EXPECT_EQ(mapping->length(), kBufferSizeInPages * magma::page_size());
// Can't map on top of grown area
std::shared_ptr<GpuMapping> mapping2;
EXPECT_FALSE(address_space->MapBufferGpu(address_space, buffer,
orig_length, // gpu addr
0, // page offset
kBufferSizeInPages, &mapping2));
}
static void GrowMappingErrorOutsideBuffer() {
constexpr uint32_t kSpaceSizeInPages = 10;
constexpr uint32_t kBufferSizeInPages = 8;
constexpr uint32_t kBufferPagesToGrow = 1;
auto address_space_owner = std::make_unique<AddressSpaceOwner>();
auto address_space = std::make_shared<NonAllocatingAddressSpace>(
address_space_owner.get(), magma::page_size() * kSpaceSizeInPages);
std::shared_ptr<MsdIntelBuffer> buffer(
MsdIntelBuffer::Create(kBufferSizeInPages * magma::page_size(), "test"));
ASSERT_TRUE(buffer);
std::shared_ptr<GpuMapping> mapping;
EXPECT_TRUE(address_space->MapBufferGpu(address_space, buffer,
0, // gpu addr
0, // page offset
kBufferSizeInPages, &mapping));
ASSERT_TRUE(mapping);
EXPECT_FALSE(address_space->GrowMapping(mapping.get(), kBufferPagesToGrow));
}
static void GrowMappingErrorOutsideSpace() {
constexpr uint32_t kSpaceSizeInPages = 10;
constexpr uint32_t kBufferSizeInPages = 12;
constexpr uint32_t kBufferPagesToGrow = 1;
auto address_space_owner = std::make_unique<AddressSpaceOwner>();
auto address_space = std::make_shared<NonAllocatingAddressSpace>(
address_space_owner.get(), magma::page_size() * kSpaceSizeInPages);
std::shared_ptr<MsdIntelBuffer> buffer(
MsdIntelBuffer::Create(kBufferSizeInPages * magma::page_size(), "test"));
ASSERT_TRUE(buffer);
std::shared_ptr<GpuMapping> mapping;
EXPECT_TRUE(address_space->MapBufferGpu(address_space, buffer,
0, // gpu addr
0, // page offset
kSpaceSizeInPages, &mapping));
ASSERT_TRUE(mapping);
EXPECT_FALSE(address_space->GrowMapping(mapping.get(), kBufferPagesToGrow));
}
static void GrowMappingErrorOverlapped() {
constexpr uint32_t kSpaceSizeInPages = 10;
constexpr uint32_t kBufferSizeInPages = 4;
constexpr uint32_t kBufferPagesToGrow = 1;
auto address_space_owner = std::make_unique<AddressSpaceOwner>();
auto address_space = std::make_shared<NonAllocatingAddressSpace>(
address_space_owner.get(), magma::page_size() * kSpaceSizeInPages);
std::shared_ptr<MsdIntelBuffer> buffer(
MsdIntelBuffer::Create(kBufferSizeInPages * magma::page_size(), "test"));
ASSERT_TRUE(buffer);
std::shared_ptr<GpuMapping> mapping;
EXPECT_TRUE(address_space->MapBufferGpu(address_space, buffer,
0, // gpu addr
0, // page offset
kBufferSizeInPages, &mapping));
ASSERT_TRUE(mapping);
std::shared_ptr<GpuMapping> mapping2;
EXPECT_TRUE(address_space->MapBufferGpu(address_space, buffer,
kBufferSizeInPages * magma::page_size(), // gpu addr
0, // page offset
kBufferSizeInPages, &mapping2));
ASSERT_TRUE(mapping2);
EXPECT_FALSE(address_space->GrowMapping(mapping.get(), kBufferPagesToGrow));
}
};
TEST(MsdIntelBuffer, CreateAndDestroy) { TestMsdIntelBuffer::CreateAndDestroy(); }
TEST(MsdIntelBuffer, AllocatingMapGpu) { TestMsdIntelBuffer::AllocatingMapGpu(); }
TEST(MsdIntelBuffer, NonAllocatingMapGpuFail) { TestMsdIntelBuffer::NonAllocatingMapGpuFail(); }
TEST(MsdIntelBuffer, NonAllocatingMapGpu) { TestMsdIntelBuffer::NonAllocatingMapGpu(); }
TEST(MsdIntelBuffer, SharedMapping) {
TestMsdIntelBuffer::SharedMapping(0x400);
TestMsdIntelBuffer::SharedMapping(0x1000);
TestMsdIntelBuffer::SharedMapping(0x16000);
}
TEST(MsdIntelBuffer, OverlappedMapping) { TestMsdIntelBuffer::OverlappedMapping(); }
TEST(MsdIntelBuffer, GrowMapping) { TestMsdIntelBuffer::GrowMapping(); }
TEST(MsdIntelBuffer, GrowMappingErrorOutsideBuffer) {
TestMsdIntelBuffer::GrowMappingErrorOutsideBuffer();
}
TEST(MsdIntelBuffer, GrowMappingErrorOutsideSpace) {
TestMsdIntelBuffer::GrowMappingErrorOutsideSpace();
}
TEST(MsdIntelBuffer, GrowMappingErrorOverlapped) {
TestMsdIntelBuffer::GrowMappingErrorOverlapped();
}