blob: b4caf9a5a0657e8419ee8afce81b2a6598d18884 [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 <lib/async-loop/loop.h>
#include <lib/async/cpp/task.h>
#include <gtest/gtest.h>
#include "helper/platform_msd_device_helper.h"
#include "msd/msd_cc.h"
#include "platform_semaphore.h"
#include "sys_driver_cpp/magma_driver.h"
#include "sys_driver_cpp/magma_system_connection.h"
#include "sys_driver_cpp/magma_system_context.h"
// a class to create and own the command buffer were trying to execute
class CommandBufferHelper final : public msd::NotificationHandler {
public:
static std::unique_ptr<CommandBufferHelper> Create() {
auto msd_drv = msd::Driver::Create();
if (!msd_drv)
return MAGMA_DRETP(nullptr, "failed to create msd driver");
msd_drv->Configure(MSD_DRIVER_CONFIG_TEST_NO_DEVICE_THREAD);
auto msd_dev = msd_drv->CreateDevice(GetTestDeviceHandle());
if (!msd_dev)
return MAGMA_DRETP(nullptr, "failed to create msd device");
auto dev = std::shared_ptr<MagmaSystemDevice>(
MagmaSystemDevice::Create(msd_drv.get(), std::move(msd_dev)));
uint32_t ctx_id = 0;
auto msd_connection = dev->msd_dev()->Open(0);
if (!msd_connection)
return MAGMA_DRETP(nullptr, "msd_device_open failed");
auto connection = std::unique_ptr<MagmaSystemConnection>(
new MagmaSystemConnection(dev, std::move(msd_connection)));
if (!connection)
return MAGMA_DRETP(nullptr, "failed to connect to msd device");
connection->CreateContext(ctx_id);
auto ctx = connection->LookupContext(ctx_id);
if (!ctx)
return MAGMA_DRETP(nullptr, "failed to create context");
return std::unique_ptr<CommandBufferHelper>(
new CommandBufferHelper(std::move(msd_drv), std::move(dev), std::move(connection), ctx));
}
static constexpr uint32_t kNumResources = 3;
static constexpr uint32_t kBufferSize = PAGE_SIZE * 2;
static constexpr uint32_t kWaitSemaphoreCount = 2;
static constexpr uint32_t kSignalSemaphoreCount = 2;
std::vector<MagmaSystemBuffer*>& resources() { return resources_; }
std::vector<msd::Buffer*>& msd_resources() { return msd_resources_; }
msd::Context* ctx() { return ctx_->msd_ctx(); }
MagmaSystemDevice* dev() { return dev_.get(); }
MagmaSystemConnection* connection() { return connection_.get(); }
magma::PlatformBuffer* buffer() {
MAGMA_DASSERT(buffer_);
return buffer_.get();
}
msd::Semaphore** msd_wait_semaphores() { return msd_wait_semaphores_.data(); }
msd::Semaphore** msd_signal_semaphores() { return msd_signal_semaphores_.data(); }
magma_command_buffer* abi_cmd_buf() {
MAGMA_DASSERT(buffer_data_);
return reinterpret_cast<magma_command_buffer*>(buffer_data_);
}
uint64_t* abi_wait_semaphore_ids() { return reinterpret_cast<uint64_t*>(abi_cmd_buf() + 1); }
uint64_t* abi_signal_semaphore_ids() {
return reinterpret_cast<uint64_t*>(abi_wait_semaphore_ids() + kWaitSemaphoreCount);
}
magma_exec_resource* abi_resources() {
return reinterpret_cast<magma_exec_resource*>(abi_signal_semaphore_ids() +
kSignalSemaphoreCount);
}
void set_command_buffer_flags(uint64_t flags) { abi_cmd_buf()->flags = flags; }
bool Execute() {
auto command_buffer = std::make_unique<magma_command_buffer>(*abi_cmd_buf());
std::vector<magma_exec_resource> resources;
for (uint32_t i = 0; i < kNumResources; i++) {
resources.emplace_back(abi_resources()[i]);
}
std::vector<uint64_t> semaphores;
for (uint32_t i = 0; i < kWaitSemaphoreCount; i++) {
semaphores.emplace_back(abi_wait_semaphore_ids()[i]);
}
for (uint32_t i = 0; i < kSignalSemaphoreCount; i++) {
semaphores.emplace_back(abi_signal_semaphore_ids()[i]);
}
if (!ctx_->ExecuteCommandBufferWithResources(std::move(command_buffer), std::move(resources),
std::move(semaphores)))
return false;
ProcessNotifications();
return true;
}
void ProcessNotifications() { loop_.RunUntilIdle(); }
bool ExecuteAndWait() {
if (!Execute())
return false;
for (uint32_t i = 0; i < signal_semaphores_.size(); i++) {
if (!signal_semaphores_[i]->Wait(5000))
return MAGMA_DRETF(false, "timed out waiting for signal semaphore %d", i);
}
return true;
}
// msd::NotificationHandler implementation.
void NotificationChannelSend(cpp20::span<uint8_t> data) override {}
void ContextKilled() override {}
void PerformanceCounterReadCompleted(const msd::PerfCounterResult& result) override {}
async_dispatcher_t* GetAsyncDispatcher() override { return loop_.dispatcher(); }
private:
CommandBufferHelper(std::unique_ptr<msd::Driver> msd_drv, std::shared_ptr<MagmaSystemDevice> dev,
std::unique_ptr<MagmaSystemConnection> connection, MagmaSystemContext* ctx)
: msd_drv_(std::move(msd_drv)),
dev_(std::move(dev)),
connection_(std::move(connection)),
ctx_(ctx) {
connection_->SetNotificationCallback(this);
uint64_t buffer_size = sizeof(magma_command_buffer) + sizeof(uint64_t) * kSignalSemaphoreCount +
sizeof(magma_exec_resource) * kNumResources;
buffer_ = magma::PlatformBuffer::Create(buffer_size, "command-buffer-backing");
MAGMA_DASSERT(buffer_);
MAGMA_DLOG("CommandBuffer backing buffer: %p", buffer_.get());
bool success = buffer_->MapCpu(&buffer_data_);
MAGMA_DASSERT(success);
MAGMA_DASSERT(buffer_data_);
abi_cmd_buf()->resource_count = kNumResources;
abi_cmd_buf()->batch_buffer_resource_index = 0;
abi_cmd_buf()->batch_start_offset = 0;
abi_cmd_buf()->wait_semaphore_count = kWaitSemaphoreCount;
abi_cmd_buf()->signal_semaphore_count = kSignalSemaphoreCount;
// batch buffer
{
auto batch_buf = &abi_resources()[0];
auto buffer = MagmaSystemBuffer::Create(
dev_->driver(), magma::PlatformBuffer::Create(kBufferSize, "command-buffer-batch"));
MAGMA_DASSERT(buffer);
zx::handle duplicate_handle;
success = buffer->platform_buffer()->duplicate_handle(&duplicate_handle);
MAGMA_DASSERT(success);
uint64_t id = buffer->platform_buffer()->id();
success = connection_->ImportBuffer(std::move(duplicate_handle), id).ok();
MAGMA_DASSERT(success);
resources_.push_back(connection_->LookupBuffer(id).get());
success = buffer->platform_buffer()->duplicate_handle(&duplicate_handle);
MAGMA_DASSERT(success);
batch_buf->buffer_id = id;
batch_buf->offset = 0;
batch_buf->length = buffer->platform_buffer()->size();
}
// other buffers
for (uint32_t i = 1; i < kNumResources; i++) {
auto resource = &abi_resources()[i];
auto buffer = MagmaSystemBuffer::Create(
dev_->driver(), magma::PlatformBuffer::Create(kBufferSize, "resource"));
MAGMA_DASSERT(buffer);
zx::handle duplicate_handle;
success = buffer->platform_buffer()->duplicate_handle(&duplicate_handle);
MAGMA_DASSERT(success);
uint64_t id = buffer->platform_buffer()->id();
success = connection_->ImportBuffer(std::move(duplicate_handle), id).ok();
MAGMA_DASSERT(success);
resources_.push_back(connection_->LookupBuffer(id).get());
success = buffer->platform_buffer()->duplicate_handle(&duplicate_handle);
MAGMA_DASSERT(success);
resource->buffer_id = id;
resource->offset = 0;
resource->length = buffer->platform_buffer()->size();
}
for (auto resource : resources_)
msd_resources_.push_back(resource->msd_buf());
// wait semaphores
for (uint32_t i = 0; i < kWaitSemaphoreCount; i++) {
auto semaphore =
std::shared_ptr<magma::PlatformSemaphore>(magma::PlatformSemaphore::Create());
MAGMA_DASSERT(semaphore);
zx::handle duplicate_handle;
success = semaphore->duplicate_handle(&duplicate_handle);
MAGMA_DASSERT(success);
wait_semaphores_.push_back(semaphore);
success = connection_
->ImportObject(zx::event(std::move(duplicate_handle)),
fuchsia_gpu_magma::wire::ObjectType::kEvent, semaphore->id())
.ok();
MAGMA_DASSERT(success);
abi_wait_semaphore_ids()[i] = semaphore->id();
msd_wait_semaphores_.push_back(
connection_->LookupSemaphore(semaphore->id())->msd_semaphore());
}
// signal semaphores
for (uint32_t i = 0; i < kSignalSemaphoreCount; i++) {
auto semaphore =
std::shared_ptr<magma::PlatformSemaphore>(magma::PlatformSemaphore::Create());
MAGMA_DASSERT(semaphore);
zx::handle duplicate_handle;
success = semaphore->duplicate_handle(&duplicate_handle);
MAGMA_DASSERT(success);
signal_semaphores_.push_back(semaphore);
success = connection_
->ImportObject(zx::event(std::move(duplicate_handle)),
fuchsia_gpu_magma::wire::ObjectType::kEvent, semaphore->id())
.ok();
MAGMA_DASSERT(success);
abi_signal_semaphore_ids()[i] = semaphore->id();
msd_signal_semaphores_.push_back(
connection_->LookupSemaphore(semaphore->id())->msd_semaphore());
}
}
std::unique_ptr<msd::Driver> msd_drv_;
std::shared_ptr<MagmaSystemDevice> dev_;
std::unique_ptr<MagmaSystemConnection> connection_;
MagmaSystemContext* ctx_; // owned by the connection
async::Loop loop_{&kAsyncLoopConfigNeverAttachToThread};
std::unique_ptr<magma::PlatformBuffer> buffer_;
// mapped address of buffer_, do not free
void* buffer_data_ = nullptr;
std::vector<MagmaSystemBuffer*> resources_;
std::vector<msd::Buffer*> msd_resources_;
std::vector<std::shared_ptr<magma::PlatformSemaphore>> wait_semaphores_;
std::vector<msd::Semaphore*> msd_wait_semaphores_;
std::vector<std::shared_ptr<magma::PlatformSemaphore>> signal_semaphores_;
std::vector<msd::Semaphore*> msd_signal_semaphores_;
};