blob: 97ca2b3251154344b307c9962a3e92ac4df9171a [file] [log] [blame]
// Copyright 2017 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 "lib/escher/vk/gpu_mem.h"
#include "gtest/gtest.h"
#include "lib/escher/impl/gpu_mem_slab.h"
#include "lib/escher/impl/vulkan_utils.h"
#include "lib/escher/test/gtest_vulkan.h"
#include "lib/escher/vk/vulkan_context.h"
#include "lib/escher/vk/vulkan_device_queues.h"
#include <iostream>
namespace {
using namespace escher;
const vk::DeviceSize kTestMemorySize = 1000;
class FakeGpuMem : public GpuMem {
public:
FakeGpuMem(vk::DeviceMemory base, vk::DeviceSize size, vk::DeviceSize offset,
uint8_t* mapped_ptr, int* obj_count = nullptr)
: GpuMem(base, size, offset, mapped_ptr), obj_count_(obj_count) {
if (obj_count_)
++(*obj_count_);
}
~FakeGpuMem() {
if (obj_count_)
--(*obj_count_);
}
private:
int* obj_count_;
};
TEST(GpuMem, ErroneousSuballocations) {
int obj_count = 0;
GpuMemPtr mem = fxl::AdoptRef(new FakeGpuMem(
vk::DeviceMemory(), kTestMemorySize, 0u, nullptr, &obj_count));
EXPECT_EQ(1, obj_count);
auto sub_alloc1 = mem->Suballocate(kTestMemorySize, 0);
auto sub_alloc2 = mem->Suballocate(kTestMemorySize + 1, 0);
auto sub_alloc3 = mem->Suballocate(kTestMemorySize, 1);
auto sub_alloc4 = mem->Suballocate(kTestMemorySize, 0);
// Creating sub-allocations does not create more "real" memory objects.
EXPECT_EQ(1, obj_count);
// Valid sub-allocation.
EXPECT_NE(nullptr, sub_alloc1.get());
// Invalid sub-allocation due to increased size.
EXPECT_EQ(nullptr, sub_alloc2.get());
// Invalid sub-allocation due to same size but increased offset.
EXPECT_EQ(nullptr, sub_alloc3.get());
// Valid sub-allocation, even though it has 100% overlap with |sub_alloc1|.
EXPECT_NE(nullptr, sub_alloc4.get());
// Can sub-allocate from a sub-allocation...
auto sub_alloc5 =
sub_alloc1->Suballocate(kTestMemorySize / 2, kTestMemorySize / 2);
EXPECT_NE(nullptr, sub_alloc5.get());
// ... and sub-allocate again from that sub-allocation. As before, the size
// and offset of the sub-allocation must fit within the parent.
auto sub_alloc6 = sub_alloc5->Suballocate(kTestMemorySize / 2, 0);
auto sub_alloc7 = sub_alloc5->Suballocate(kTestMemorySize / 2 + 1, 0);
auto sub_alloc8 = sub_alloc5->Suballocate(kTestMemorySize / 2, 1);
auto sub_alloc9 = sub_alloc5->Suballocate(kTestMemorySize / 2, 0);
// Valid sub-allocation.
EXPECT_NE(nullptr, sub_alloc6.get());
// Invalid sub-allocation due to increased size.
EXPECT_EQ(nullptr, sub_alloc7.get());
// Invalid sub-allocation due to same size but increased offset.
EXPECT_EQ(nullptr, sub_alloc8.get());
// Valid sub-allocation, even though it has 100% overlap with |sub_alloc1|.
EXPECT_NE(nullptr, sub_alloc9.get());
EXPECT_EQ(1, obj_count);
mem = nullptr;
// Suballocations keep the base allocation alive.
EXPECT_EQ(1, obj_count);
sub_alloc1 = nullptr;
sub_alloc4 = nullptr;
sub_alloc5 = nullptr;
sub_alloc6 = nullptr;
sub_alloc9 = nullptr;
// Removing all valid sub-allocations causes the base allocation to go out of
// scope.
EXPECT_EQ(0, obj_count);
}
// This test should be updated to include all hashed types used by Escher.
VK_TEST(GpuMem, AdoptVkMemory) {
VulkanInstance::Params instance_params(
{{"VK_LAYER_LUNARG_standard_validation"},
{VK_EXT_DEBUG_REPORT_EXTENSION_NAME},
false});
auto vulkan_instance = VulkanInstance::New(std::move(instance_params));
auto vulkan_queues = VulkanDeviceQueues::New(vulkan_instance, {});
auto device = vulkan_queues->GetVulkanContext().device;
auto physical_device = vulkan_queues->GetVulkanContext().physical_device;
vk::MemoryAllocateInfo info;
info.allocationSize = kTestMemorySize;
info.memoryTypeIndex = impl::GetMemoryTypeIndex(
physical_device, INT32_MAX, vk::MemoryPropertyFlagBits::eHostVisible);
vk::DeviceMemory vk_mem =
ESCHER_CHECKED_VK_RESULT(device.allocateMemory(info));
// This test only checks for valid creation and destruction. It would need
// a mock Vulkan to test for memory usage.
auto mem = GpuMem::AdoptVkMemory(device, vk_mem, kTestMemorySize,
true /* needs_mapped_ptr */);
EXPECT_EQ(vk_mem, mem->base());
EXPECT_EQ(kTestMemorySize, mem->size());
EXPECT_EQ(0u, mem->offset());
EXPECT_NE(nullptr, mem->mapped_ptr());
}
TEST(GpuMem, RecursiveAllocations) {
const vk::DeviceMemory kVkMem(reinterpret_cast<VkDeviceMemory>(10000));
const vk::DeviceSize kSize0 = 100;
const vk::DeviceSize kOffset0 = 0;
const vk::DeviceSize kSize1 = 50;
const vk::DeviceSize kOffset1 = 10;
const vk::DeviceSize kSize2 = 20;
const vk::DeviceSize kOffset2 = 20;
const vk::DeviceSize kSize3 = 5;
const vk::DeviceSize kOffset3 = 10;
GpuMemPtr mem =
fxl::MakeRefCounted<FakeGpuMem>(kVkMem, kSize0, kOffset0, nullptr);
auto sub = mem->Suballocate(kSize1, kOffset1);
auto subsub = sub->Suballocate(kSize2, kOffset2);
auto subsubsub = subsub->Suballocate(kSize3, kOffset3);
EXPECT_NE(vk::DeviceMemory(), mem->base());
EXPECT_EQ(mem->base(), sub->base());
EXPECT_EQ(sub->base(), subsub->base());
EXPECT_EQ(subsub->base(), subsubsub->base());
EXPECT_EQ(kOffset1, sub->offset());
EXPECT_EQ(kOffset1 + kOffset2, subsub->offset());
EXPECT_EQ(kOffset1 + kOffset2 + kOffset3, subsubsub->offset());
}
TEST(GpuMem, MappedPointer) {
const vk::DeviceMemory kVkMem(reinterpret_cast<VkDeviceMemory>(10000));
uint8_t* const kNullPtr = nullptr;
uint8_t* const kFakePtr = reinterpret_cast<uint8_t*>(1000);
const vk::DeviceSize kSize1 = 100;
const vk::DeviceSize kOffset1 = 0;
const vk::DeviceSize kSize2 = 50;
const vk::DeviceSize kOffset2 = 10;
const vk::DeviceSize kSize3 = 20;
const vk::DeviceSize kOffset3 = 20;
GpuMemPtr mem = fxl::MakeRefCounted<FakeGpuMem>(vk::DeviceMemory(), kSize1,
kOffset1, kNullPtr);
GpuMemPtr sub = mem->Suballocate(kSize2, kOffset2);
GpuMemPtr subsub = sub->Suballocate(kSize3, kOffset3);
EXPECT_EQ(nullptr, mem->mapped_ptr());
EXPECT_EQ(nullptr, sub->mapped_ptr());
EXPECT_EQ(nullptr, subsub->mapped_ptr());
mem = fxl::MakeRefCounted<FakeGpuMem>(vk::DeviceMemory(), kSize1, kOffset1,
kFakePtr);
sub = mem->Suballocate(kSize2, kOffset2);
subsub = sub->Suballocate(kSize3, kOffset3);
EXPECT_EQ(kFakePtr, mem->mapped_ptr());
EXPECT_EQ(static_cast<ptrdiff_t>(kOffset2),
sub->mapped_ptr() - mem->mapped_ptr());
EXPECT_EQ(static_cast<ptrdiff_t>(kOffset3 + kOffset2),
subsub->mapped_ptr() - mem->mapped_ptr());
EXPECT_EQ(static_cast<ptrdiff_t>(kOffset3),
subsub->mapped_ptr() - sub->mapped_ptr());
}
} // namespace