blob: 31c40f3f1c5dc2746c59d94aa5856bf46dabc498 [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 "magma_system_connection.h"
#include "magma_system_device.h"
#include "magma_util/macros.h"
#include <vector>
MagmaSystemConnection::MagmaSystemConnection(std::weak_ptr<MagmaSystemDevice> weak_device,
msd_connection_unique_ptr_t msd_connection_t)
: device_(weak_device), msd_connection_(std::move(msd_connection_t))
{
DASSERT(msd_connection_);
}
MagmaSystemConnection::~MagmaSystemConnection()
{
for (auto iter = buffer_map_.begin(); iter != buffer_map_.end();) {
msd_connection_release_buffer(msd_connection(), iter->second.buffer->msd_buf());
iter = buffer_map_.erase(iter);
}
auto device = device_.lock();
if (device) {
device->ConnectionClosed(std::this_thread::get_id());
}
}
uint32_t MagmaSystemConnection::GetDeviceId()
{
auto device = device_.lock();
return device ? device->GetDeviceId() : 0;
}
bool MagmaSystemConnection::CreateContext(uint32_t context_id)
{
auto iter = context_map_.find(context_id);
if (iter != context_map_.end())
return DRETF(false, "Attempting to add context with duplicate id");
auto msd_ctx = msd_connection_create_context(msd_connection());
if (!msd_ctx)
return DRETF(false, "Failed to create msd context");
auto ctx = std::unique_ptr<MagmaSystemContext>(
new MagmaSystemContext(this, msd_context_unique_ptr_t(msd_ctx, &msd_context_destroy)));
context_map_.insert(std::make_pair(context_id, std::move(ctx)));
return true;
}
bool MagmaSystemConnection::DestroyContext(uint32_t context_id)
{
auto iter = context_map_.find(context_id);
if (iter == context_map_.end())
return DRETF(false, "MagmaSystemConnection:Attempting to destroy invalid context id");
context_map_.erase(iter);
return true;
}
MagmaSystemContext* MagmaSystemConnection::LookupContext(uint32_t context_id)
{
auto iter = context_map_.find(context_id);
if (iter == context_map_.end())
return DRETP(nullptr, "MagmaSystemConnection: Attempting to lookup invalid context id");
return iter->second.get();
}
magma::Status MagmaSystemConnection::ExecuteCommandBuffer(uint32_t command_buffer_handle,
uint32_t context_id)
{
auto command_buffer = magma::PlatformBuffer::Import(command_buffer_handle);
if (!command_buffer)
return DRET_MSG(MAGMA_STATUS_INVALID_ARGS, "Failed to import command buffer");
auto context = LookupContext(context_id);
if (!context)
return DRET_MSG(MAGMA_STATUS_INVALID_ARGS,
"Attempting to execute command buffer on invalid context");
return context->ExecuteCommandBuffer(std::move(command_buffer));
}
magma::Status MagmaSystemConnection::ExecuteImmediateCommands(uint32_t context_id,
uint64_t commands_size,
void* commands,
uint64_t semaphore_count,
uint64_t* semaphore_ids)
{
auto context = LookupContext(context_id);
if (!context)
return DRET_MSG(MAGMA_STATUS_INVALID_ARGS,
"Attempting to execute command buffer on invalid context");
return context->ExecuteImmediateCommands(commands_size, commands, semaphore_count,
semaphore_ids);
}
bool MagmaSystemConnection::ImportBuffer(uint32_t handle, uint64_t* id_out)
{
auto buffer = magma::PlatformBuffer::Import(handle);
if (!buffer)
return DRETF(false, "failed to import buffer");
uint64_t id = buffer->id();
auto iter = buffer_map_.find(id);
if (iter != buffer_map_.end()) {
iter->second.refcount++;
return true;
}
BufferReference ref;
ref.buffer = MagmaSystemBuffer::Create(std::move(buffer));
buffer_map_.insert({id, ref});
*id_out = id;
return true;
}
bool MagmaSystemConnection::ReleaseBuffer(uint64_t id)
{
auto iter = buffer_map_.find(id);
if (iter == buffer_map_.end())
return DRETF(false, "Attempting to free invalid buffer id");
if (--iter->second.refcount > 0)
return true;
msd_connection_release_buffer(msd_connection(), iter->second.buffer->msd_buf());
buffer_map_.erase(iter);
return true;
}
bool MagmaSystemConnection::MapBufferGpu(uint64_t id, uint64_t gpu_va, uint64_t page_offset,
uint64_t page_count, uint64_t flags)
{
auto iter = buffer_map_.find(id);
if (iter == buffer_map_.end())
return DRETF(false, "Attempting to gpu map invalid buffer id");
if (msd_connection_map_buffer_gpu(msd_connection(), iter->second.buffer->msd_buf(), gpu_va,
page_offset, page_count, flags) != MAGMA_STATUS_OK)
return DRETF(false, "msd_connection_map_buffer_gpu failed");
return true;
}
bool MagmaSystemConnection::UnmapBufferGpu(uint64_t id, uint64_t gpu_va)
{
auto iter = buffer_map_.find(id);
if (iter == buffer_map_.end())
return DRETF(false, "Attempting to gpu unmap invalid buffer id");
if (msd_connection_unmap_buffer_gpu(msd_connection(), iter->second.buffer->msd_buf(), gpu_va) !=
MAGMA_STATUS_OK)
return DRETF(false, "msd_connection_unmap_buffer_gpu failed");
return true;
}
bool MagmaSystemConnection::CommitBuffer(uint64_t id, uint64_t page_offset, uint64_t page_count)
{
auto iter = buffer_map_.find(id);
if (iter == buffer_map_.end())
return DRETF(false, "Attempting to commit invalid buffer id");
if (page_count + page_offset < page_count) {
return DRETF(false, "Offset overflows");
}
if (page_count + page_offset > iter->second.buffer->size() / PAGE_SIZE) {
return DRETF(false, "Page offset too large for buffer");
}
if (msd_connection_commit_buffer(msd_connection(), iter->second.buffer->msd_buf(), page_offset,
page_count) != MAGMA_STATUS_OK)
return DRETF(false, "msd_connection_commit_buffer failed");
return true;
}
void MagmaSystemConnection::SetNotificationCallback(msd_connection_notification_callback_t callback,
void* token)
{
msd_connection_set_notification_callback(msd_connection(), callback, token);
}
bool MagmaSystemConnection::ImportObject(uint32_t handle, magma::PlatformObject::Type object_type)
{
auto device = device_.lock();
if (!device)
return DRETF(false, "failed to lock device");
switch (object_type) {
case magma::PlatformObject::SEMAPHORE: {
uint64_t id;
if (!magma::PlatformObject::IdFromHandle(handle, &id))
return DRETF(false, "failed to get semaphore id for handle");
// Always import the handle to to ensure it gets closed
auto platform_sem = magma::PlatformSemaphore::Import(handle);
auto iter = semaphore_map_.find(id);
if (iter != semaphore_map_.end()) {
iter->second.refcount++;
return true;
}
auto semaphore = MagmaSystemSemaphore::Create(std::move(platform_sem));
if (!semaphore)
return DRETF(false, "failed to import platform semaphore");
SemaphoreReference ref;
ref.semaphore = std::move(semaphore);
semaphore_map_.insert(std::make_pair(id, ref));
} break;
}
return true;
}
bool MagmaSystemConnection::ReleaseObject(uint64_t object_id,
magma::PlatformObject::Type object_type)
{
switch (object_type) {
case magma::PlatformObject::SEMAPHORE: {
auto iter = semaphore_map_.find(object_id);
if (iter == semaphore_map_.end())
return DRETF(false, "Attempting to free invalid semaphore id 0x%" PRIx64,
object_id);
if (--iter->second.refcount > 0)
return true;
semaphore_map_.erase(iter);
} break;
}
return true;
}
std::shared_ptr<MagmaSystemBuffer> MagmaSystemConnection::LookupBuffer(uint64_t id)
{
auto iter = buffer_map_.find(id);
if (iter == buffer_map_.end())
return DRETP(nullptr, "Attempting to lookup invalid buffer id");
return iter->second.buffer;
}
std::shared_ptr<MagmaSystemSemaphore> MagmaSystemConnection::LookupSemaphore(uint64_t id)
{
auto iter = semaphore_map_.find(id);
if (iter == semaphore_map_.end())
return nullptr;
return iter->second.semaphore;
}