blob: 59a40021f34ff8ee5ca2f523d2ebdab1c60ed2c7 [file] [log] [blame]
// 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 "test_command_buffer.h"
#include "command_buffer.h"
#include "helper/command_buffer_helper.h"
#include "helper/platform_device_helper.h"
#include "mock/mock_address_space.h"
#include "mock/mock_bus_mapper.h"
#include "msd_intel_context.h"
#include "msd_intel_device.h"
#include "gtest/gtest.h"
class Test {
public:
class AddressSpaceOwner : public AddressSpace::Owner {
public:
virtual ~AddressSpaceOwner() = default;
magma::PlatformBusMapper* GetBusMapper() override { return &bus_mapper_; }
private:
MockBusMapper bus_mapper_;
};
static std::unique_ptr<Test> Create() { return std::unique_ptr<Test>(new Test()); }
MsdIntelDevice* device() { return MsdIntelDevice::cast(helper_->dev()->msd_dev()); }
std::shared_ptr<AddressSpace> exec_address_space()
{
auto context = MsdIntelAbiContext::cast(helper_->ctx())->ptr();
return context->exec_address_space();
}
void TestMapUnmapResourcesGpu()
{
auto address_space_owner = std::make_unique<AddressSpaceOwner>();
auto addr_space =
std::make_shared<MockAddressSpace>(address_space_owner.get(), 0, 1024 * PAGE_SIZE);
std::vector<std::shared_ptr<GpuMapping>> mappings;
ASSERT_TRUE(TestCommandBuffer::MapResourcesGpu(cmd_buf_.get(), addr_space, mappings));
uint32_t i = 0;
for (auto& map : mappings) {
gpu_addr_t addr = map->gpu_addr();
EXPECT_TRUE(addr_space->is_allocated(addr));
EXPECT_FALSE(addr_space->is_clear(addr));
EXPECT_GE(addr_space->allocated_size(addr), helper_->resources()[i++]->size());
}
TestCommandBuffer::UnmapResourcesGpu(cmd_buf_.get());
for (auto& map : mappings) {
gpu_addr_t addr = map->gpu_addr();
std::vector<std::shared_ptr<GpuMapping>> mappings;
addr_space->ReleaseBuffer(map->buffer()->platform_buffer(), &mappings);
EXPECT_EQ(1u, mappings.size());
EXPECT_EQ(2u, map.use_count());
mappings.clear();
EXPECT_EQ(1u, map.use_count());
EXPECT_TRUE(addr_space->is_allocated(addr));
map.reset();
EXPECT_FALSE(addr_space->is_allocated(addr));
}
}
void TestPatchRelocations()
{
auto address_space_owner = std::make_unique<AddressSpaceOwner>();
auto addr_space =
std::make_shared<MockAddressSpace>(address_space_owner.get(), 0, 1024 * PAGE_SIZE);
auto batch_buf_index = TestCommandBuffer::batch_buffer_resource_index(cmd_buf_.get());
auto batch_res = TestCommandBuffer::exec_resources(cmd_buf_.get())[batch_buf_index];
void* batch_buf_virt_addr = 0;
ASSERT_TRUE(batch_res.buffer->platform_buffer()->MapCpu(&batch_buf_virt_addr));
auto batch_buf_data = (uint32_t*)batch_buf_virt_addr;
// Clear the relocations to be sure
auto batch_buf_resource = &TestCommandBuffer::resource(cmd_buf_.get(), batch_buf_index);
for (uint32_t i = 0; i < batch_buf_resource->num_relocations(); i++) {
auto relocation = batch_buf_resource->relocation(i);
uint32_t dword_offset = relocation->offset / sizeof(uint32_t);
batch_buf_data[dword_offset] = 0xdeadbeef;
dword_offset++;
batch_buf_data[dword_offset] = 0xdeadbeef;
}
// do the relocation foo
std::vector<std::shared_ptr<GpuMapping>> mappings;
ASSERT_TRUE(TestCommandBuffer::MapResourcesGpu(cmd_buf_.get(), addr_space, mappings));
ASSERT_TRUE(TestCommandBuffer::PatchRelocations(cmd_buf_.get(), mappings));
// check that we foo'd it correctly
for (uint32_t i = 0; i < batch_buf_resource->num_relocations(); i++) {
auto relocation = batch_buf_resource->relocation(i);
gpu_addr_t target_gpu_address = mappings[relocation->target_resource_index]->gpu_addr();
auto expected_gpu_addr = target_gpu_address + relocation->target_offset;
uint32_t dword_offset = relocation->offset / sizeof(uint32_t);
EXPECT_EQ(magma::lower_32_bits(expected_gpu_addr), batch_buf_data[dword_offset]);
dword_offset++;
EXPECT_EQ(magma::upper_32_bits(expected_gpu_addr), batch_buf_data[dword_offset]);
}
}
void TestPrepareForExecution()
{
auto device = MsdIntelDevice::cast(helper_->dev()->msd_dev());
auto engine = TestCommandBuffer::render_engine(device);
uint32_t batch_start_offset = 0x10;
helper_->abi_cmd_buf()->batch_start_offset = batch_start_offset;
ASSERT_TRUE(cmd_buf_->PrepareForExecution());
auto context = cmd_buf_->GetContext().lock();
ASSERT_NE(context, nullptr);
ClientContext* ctx = static_cast<ClientContext*>(context.get());
ASSERT_NE(ctx, nullptr);
EXPECT_TRUE(TestCommandBuffer::InitContextForRender(device, context.get()));
gpu_addr_t gpu_addr;
EXPECT_TRUE(cmd_buf_->GetGpuAddress(&gpu_addr));
EXPECT_EQ(batch_start_offset, gpu_addr & (PAGE_SIZE - 1));
// Check that context is initialized correctly
EXPECT_TRUE(ctx->IsInitializedForEngine(engine->id()));
EXPECT_NE(ctx->get_ringbuffer(engine->id()), nullptr);
EXPECT_NE(ctx->get_context_buffer(engine->id()), nullptr);
// Check that context is mapped correctly
gpu_addr_t addr;
EXPECT_TRUE(ctx->GetGpuAddress(engine->id(), &addr));
EXPECT_NE(addr, kInvalidGpuAddr);
EXPECT_TRUE(ctx->GetRingbufferGpuAddress(engine->id(), &addr));
EXPECT_NE(addr, kInvalidGpuAddr);
cmd_buf_.reset();
}
void TestExecute()
{
auto context = MsdIntelAbiContext::cast(helper_->ctx())->ptr();
auto addr_space = exec_address_space();
auto target_buffer_mapping =
AddressSpace::MapBufferGpu(addr_space, MsdIntelBuffer::Create(PAGE_SIZE, "test"));
ASSERT_NE(target_buffer_mapping, nullptr);
void* target_cpu_addr;
ASSERT_TRUE(target_buffer_mapping->buffer()->platform_buffer()->MapCpu(&target_cpu_addr));
gpu_addr_t target_gpu_addr = target_buffer_mapping->gpu_addr();
DLOG("target_gpu_addr 0x%lx", target_gpu_addr);
*reinterpret_cast<uint32_t*>(target_cpu_addr) = 0;
auto batch_buf_index = TestCommandBuffer::batch_buffer_resource_index(cmd_buf_.get());
auto batch_res = TestCommandBuffer::exec_resources(cmd_buf_.get())[batch_buf_index];
void* batch_cpu_addr;
ASSERT_TRUE(batch_res.buffer->platform_buffer()->MapCpu(&batch_cpu_addr));
uint32_t expected_val = 0xdeadbeef;
uint32_t* batch_ptr = reinterpret_cast<uint32_t*>(batch_cpu_addr);
static constexpr uint32_t kDwordCount = 4;
static constexpr bool kUseGlobalGtt = false;
// store dword
*batch_ptr++ = (0x20 << 23) | (kDwordCount - 2) | (kUseGlobalGtt ? 1 << 22 : 0);
*batch_ptr++ = magma::lower_32_bits(target_gpu_addr);
*batch_ptr++ = magma::upper_32_bits(target_gpu_addr);
*batch_ptr++ = expected_val;
// batch end
*batch_ptr++ = (0xA << 23);
TestCommandBuffer::StartDeviceThread(device());
cmd_buf_.reset();
EXPECT_TRUE(helper_->ExecuteAndWait());
uint32_t target_val = *reinterpret_cast<uint32_t*>(target_cpu_addr);
EXPECT_EQ(target_val, expected_val);
}
private:
Test()
{
auto platform_device = TestPlatformPciDevice::GetInstance();
if (!platform_device)
DLOG("TestCommandBuffer: No platform device");
DLOG("creating helper");
helper_ = CommandBufferHelper::Create(platform_device);
DLOG("creating command buffer");
uint32_t handle;
helper_->buffer()->duplicate_handle(&handle);
buffer_ = MagmaSystemBuffer::Create(magma::PlatformBuffer::Import(handle));
// It's important that the CommandBuffer created here match the serialized content
// inside the command buffer provided by the helper.
cmd_buf_ =
CommandBuffer::Create(buffer_->msd_buf(), helper_->msd_resources().data(),
MsdIntelAbiContext::cast(helper_->ctx())->ptr(),
helper_->msd_wait_semaphores(), helper_->msd_signal_semaphores());
DLOG("command buffer created");
}
std::unique_ptr<MagmaSystemBuffer> buffer_;
std::unique_ptr<CommandBuffer> cmd_buf_;
std::unique_ptr<CommandBufferHelper> helper_;
};
TEST(CommandBuffer, MapUnmapResourcesGpu) { ::Test::Create()->TestMapUnmapResourcesGpu(); }
TEST(CommandBuffer, PatchRelocations) { ::Test::Create()->TestPatchRelocations(); }
TEST(CommandBuffer, PrepareForExecution) { ::Test::Create()->TestPrepareForExecution(); }
TEST(CommandBuffer, Execute) { ::Test::Create()->TestExecute(); }