blob: 256cd8da8c8695db27bc12eb11bf77b2feacc380 [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 "global_context.h"
#include "mock/mock_address_space.h"
#include "mock/mock_bus_mapper.h"
#include "msd_intel_connection.h"
#include "msd_intel_context.h"
#include "ringbuffer.h"
#include "test_command_buffer.h"
#include "gtest/gtest.h"
class TestContext {
public:
class AddressSpaceOwner : public AddressSpace::Owner {
public:
virtual ~AddressSpaceOwner() = default;
magma::PlatformBusMapper* GetBusMapper() override { return &bus_mapper_; }
private:
MockBusMapper bus_mapper_;
};
void Init()
{
auto address_space_owner = std::make_unique<AddressSpaceOwner>();
auto address_space =
std::make_shared<MockAddressSpace>(address_space_owner.get(), 0, PAGE_SIZE);
std::weak_ptr<MsdIntelConnection> connection;
std::unique_ptr<MsdIntelContext> context(new ClientContext(connection, address_space));
EXPECT_EQ(nullptr, get_buffer(context.get(), RENDER_COMMAND_STREAMER));
EXPECT_EQ(nullptr, get_ringbuffer(context.get(), RENDER_COMMAND_STREAMER));
std::unique_ptr<MsdIntelBuffer> buffer(MsdIntelBuffer::Create(10, "test"));
ASSERT_NE(buffer, nullptr);
auto expected_buffer = buffer.get();
std::unique_ptr<Ringbuffer> ringbuffer(
new Ringbuffer(MsdIntelBuffer::Create(PAGE_SIZE, "test")));
ASSERT_NE(ringbuffer, nullptr);
auto expected_ringbuffer = ringbuffer.get();
context->SetEngineState(RENDER_COMMAND_STREAMER, std::move(buffer), std::move(ringbuffer));
EXPECT_EQ(expected_buffer, get_buffer(context.get(), RENDER_COMMAND_STREAMER));
EXPECT_EQ(expected_ringbuffer, get_ringbuffer(context.get(), RENDER_COMMAND_STREAMER));
}
void Map(bool global)
{
// Arbitrary
constexpr uint32_t base = 0x10000;
std::weak_ptr<MsdIntelConnection> connection;
std::unique_ptr<MsdIntelContext> context;
std::unique_ptr<MsdIntelBuffer> buffer(MsdIntelBuffer::Create(PAGE_SIZE, "test"));
std::unique_ptr<Ringbuffer> ringbuffer(new Ringbuffer(
std::unique_ptr<MsdIntelBuffer>(MsdIntelBuffer::Create(PAGE_SIZE, "test"))));
auto address_space_owner = std::make_unique<AddressSpaceOwner>();
auto address_space = std::make_shared<MockAddressSpace>(address_space_owner.get(), base,
buffer->platform_buffer()->size() +
ringbuffer->size());
if (global)
context = std::unique_ptr<MsdIntelContext>(new GlobalContext(address_space));
else
context =
std::unique_ptr<MsdIntelContext>(new ClientContext(connection, address_space));
context->SetEngineState(RENDER_COMMAND_STREAMER, std::move(buffer), std::move(ringbuffer));
// Not mapped
EXPECT_FALSE(context->Unmap(RENDER_COMMAND_STREAMER));
gpu_addr_t gpu_addr;
EXPECT_FALSE(context->GetRingbufferGpuAddress(RENDER_COMMAND_STREAMER, &gpu_addr));
EXPECT_TRUE(context->Map(address_space, RENDER_COMMAND_STREAMER));
EXPECT_TRUE(context->GetRingbufferGpuAddress(RENDER_COMMAND_STREAMER, &gpu_addr));
EXPECT_GE(gpu_addr, base);
// Already mapped
EXPECT_TRUE(context->Map(address_space, RENDER_COMMAND_STREAMER));
// Unmap
EXPECT_TRUE(context->Unmap(RENDER_COMMAND_STREAMER));
// Already unmapped
EXPECT_FALSE(context->Unmap(RENDER_COMMAND_STREAMER));
}
void CachedMapping()
{
// Arbitrary
constexpr uint32_t base = 0x10000;
std::unique_ptr<MsdIntelBuffer> buffer(MsdIntelBuffer::Create(PAGE_SIZE, "test"));
auto ringbuffer = std::make_unique<Ringbuffer>(
std::unique_ptr<MsdIntelBuffer>(MsdIntelBuffer::Create(PAGE_SIZE, "test")));
auto address_space_owner = std::make_unique<AddressSpaceOwner>();
auto address_space = std::make_shared<MockAddressSpace>(address_space_owner.get(), base,
buffer->platform_buffer()->size() +
ringbuffer->size());
auto context =
std::make_unique<ClientContext>(std::weak_ptr<MsdIntelConnection>(), address_space);
void* cpu_addr = context->GetCachedContextBufferCpuAddr(RENDER_COMMAND_STREAMER);
EXPECT_EQ(nullptr, cpu_addr);
context->SetEngineState(RENDER_COMMAND_STREAMER, std::move(buffer), std::move(ringbuffer));
cpu_addr = context->GetCachedContextBufferCpuAddr(RENDER_COMMAND_STREAMER);
EXPECT_NE(nullptr, cpu_addr);
// Returned address shouldn't change.
EXPECT_EQ(cpu_addr, context->GetCachedContextBufferCpuAddr(RENDER_COMMAND_STREAMER));
}
static void SubmitCommandBuffer(uint32_t command_buffer_count, uint32_t semaphore_count)
{
DLOG("SubmitCommandBuffer command_buffer_count %u semaphore_count %u", command_buffer_count,
semaphore_count);
class ConnectionOwner : public MsdIntelConnection::Owner {
public:
ConnectionOwner(
std::function<void(std::unique_ptr<CommandBuffer> command_buffer)> callback)
: callback_(callback)
{
address_space_owner_ = std::make_unique<AddressSpaceOwner>();
}
magma::Status SubmitBatch(std::unique_ptr<MappedBatch> batch) override
{
DASSERT(batch->IsCommandBuffer());
auto command_buffer = static_cast<CommandBuffer*>(batch.release());
DLOG("command buffer received 0x%" PRIx64,
TestCommandBuffer::platform_buffer(command_buffer)->id());
callback_(std::unique_ptr<CommandBuffer>(command_buffer));
return MAGMA_STATUS_OK;
}
void DestroyContext(std::shared_ptr<ClientContext> client_context) override {}
magma::PlatformBusMapper* GetBusMapper() override
{
return address_space_owner_->GetBusMapper();
}
std::function<void(std::unique_ptr<CommandBuffer>)> callback_;
std::unique_ptr<magma::PlatformSemaphore> semaphore_;
std::unique_ptr<AddressSpaceOwner> address_space_owner_;
};
std::vector<std::unique_ptr<CommandBuffer>> submitted_command_buffers;
auto finished_semaphore =
std::shared_ptr<magma::PlatformSemaphore>(magma::PlatformSemaphore::Create());
auto owner = std::make_unique<ConnectionOwner>(
[&submitted_command_buffers, finished_semaphore,
command_buffer_count](std::unique_ptr<CommandBuffer> command_buffer) {
submitted_command_buffers.push_back(std::move(command_buffer));
if (submitted_command_buffers.size() == command_buffer_count)
finished_semaphore->Signal();
});
auto connection =
std::shared_ptr<MsdIntelConnection>(MsdIntelConnection::Create(owner.get(), 0u));
auto address_space = std::make_shared<MockAddressSpace>(owner.get(), 0, PAGE_SIZE);
auto context = std::make_shared<ClientContext>(connection, address_space);
std::vector<std::unique_ptr<CommandBuffer>> command_buffers;
std::vector<uint64_t> command_buffer_ids;
std::vector<std::shared_ptr<magma::PlatformSemaphore>> semaphores;
for (uint32_t i = 0; i < command_buffer_count; i++) {
// Don't need a fully initialized command buffer
std::shared_ptr<MsdIntelBuffer> command_buffer_content =
MsdIntelBuffer::Create(PAGE_SIZE, "test");
magma_system_command_buffer* command_buffer_desc;
ASSERT_TRUE(command_buffer_content->platform_buffer()->MapCpu(
reinterpret_cast<void**>(&command_buffer_desc)));
command_buffer_desc->batch_buffer_resource_index = 0;
command_buffer_desc->batch_start_offset = 0;
command_buffer_desc->num_resources = 0;
command_buffer_desc->wait_semaphore_count = 0;
command_buffer_desc->signal_semaphore_count = 0;
std::vector<std::shared_ptr<magma::PlatformSemaphore>> wait_semaphores;
for (uint32_t i = 0; i < semaphore_count; i++) {
auto semaphore =
std::shared_ptr<magma::PlatformSemaphore>(magma::PlatformSemaphore::Create());
wait_semaphores.push_back(semaphore);
semaphores.push_back(semaphore);
}
command_buffer_desc->wait_semaphore_count = semaphore_count;
auto command_buffer =
TestCommandBuffer::Create(command_buffer_content, context, {}, wait_semaphores, {});
ASSERT_NE(command_buffer, nullptr);
command_buffers.push_back(std::move(command_buffer));
command_buffer_ids.push_back(
TestCommandBuffer::platform_buffer(command_buffers[i].get())->id());
magma::Status status = context->SubmitCommandBuffer(std::move(command_buffers[i]));
EXPECT_EQ(MAGMA_STATUS_OK, status.get());
EXPECT_EQ(submitted_command_buffers.empty(), semaphore_count > 0);
}
for (uint32_t i = 0; i < semaphores.size(); i++) {
semaphores[i]->Signal();
}
EXPECT_TRUE(finished_semaphore->Wait(5000));
ASSERT_EQ(submitted_command_buffers.size(), command_buffer_ids.size());
for (uint32_t i = 0; i < command_buffer_ids.size(); i++) {
EXPECT_EQ(TestCommandBuffer::platform_buffer(submitted_command_buffers[i].get())->id(),
command_buffer_ids[i]);
}
context->Shutdown();
}
private:
static MsdIntelBuffer* get_buffer(MsdIntelContext* context, EngineCommandStreamerId id)
{
return context->get_context_buffer(id);
}
static Ringbuffer* get_ringbuffer(MsdIntelContext* context, EngineCommandStreamerId id)
{
return context->get_ringbuffer(id);
}
};
TEST(MsdIntelContext, Init)
{
TestContext test;
test.Init();
}
TEST(MsdIntelContext, ClientMap)
{
TestContext test;
test.Map(false);
}
TEST(MsdIntelContext, CachedMapping) { TestContext().CachedMapping(); }
TEST(GlobalContext, GlobalMap)
{
TestContext test;
test.Map(true);
}
TEST(ClientContext, SubmitCommandBuffer)
{
TestContext::SubmitCommandBuffer(1, 0);
TestContext::SubmitCommandBuffer(1, 1);
TestContext::SubmitCommandBuffer(2, 1);
TestContext::SubmitCommandBuffer(3, 2);
TestContext::SubmitCommandBuffer(2, 5);
}