blob: 9e4e724bafa04930728e9c5824707f6db151ccc4 [file] [log] [blame]
// Copyright 2018 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 "msd_vsi_context.h"
#include "address_space_layout.h"
#include "command_buffer.h"
#include "msd_vsi_semaphore.h"
// static
std::shared_ptr<MsdVsiContext> MsdVsiContext::Create(std::weak_ptr<MsdVsiConnection> connection,
std::shared_ptr<AddressSpace> address_space,
Ringbuffer* ringbuffer) {
auto context = std::make_shared<MsdVsiContext>(connection, address_space);
if (!context->MapRingbuffer(ringbuffer)) {
MAGMA_LOG(ERROR, "failed to map ringbuffer into new context");
return nullptr;
}
return context;
}
std::unique_ptr<MappedBatch> MsdVsiContext::CreateBatch(std::shared_ptr<MsdVsiContext> context,
msd::magma_command_buffer* cmd_buf,
magma_exec_resource* exec_resources,
msd::Buffer** msd_buffers,
msd::Semaphore** msd_wait_semaphores,
msd::Semaphore** msd_signal_semaphores) {
std::vector<CommandBuffer::ExecResource> resources;
resources.reserve(cmd_buf->resource_count);
for (uint32_t i = 0; i < cmd_buf->resource_count; i++) {
resources.emplace_back(CommandBuffer::ExecResource{MsdVsiAbiBuffer::cast(msd_buffers[i])->ptr(),
exec_resources[i].offset,
exec_resources[i].length});
}
// Currently wait semaphores are not used.
std::vector<std::shared_ptr<magma::PlatformSemaphore>> wait_semaphores;
std::vector<std::shared_ptr<magma::PlatformSemaphore>> signal_semaphores;
signal_semaphores.reserve(cmd_buf->signal_semaphore_count);
for (uint32_t i = 0; i < cmd_buf->signal_semaphore_count; i++) {
signal_semaphores.emplace_back(MsdVsiAbiSemaphore::cast(msd_signal_semaphores[i])->ptr());
}
auto connection = context->connection().lock();
if (!connection) {
MAGMA_LOG(ERROR, "Connection is already dead");
return nullptr;
}
std::unique_ptr<MappedBatch> batch;
// The CommandBuffer does not support batches with zero resources.
if (resources.size() > 0) {
auto command_buffer = CommandBuffer::Create(
context, connection->client_id(), std::make_unique<msd::magma_command_buffer>(*cmd_buf),
std::move(resources), std::move(signal_semaphores));
if (!command_buffer) {
MAGMA_LOG(ERROR, "Failed to create command buffer");
return nullptr;
}
batch = std::move(command_buffer);
} else {
batch = std::make_unique<EventBatch>(context, std::move(wait_semaphores),
std::move(signal_semaphores));
}
return batch;
}
magma::Status MsdVsiContext::SubmitBatch(std::unique_ptr<MappedBatch> batch) {
auto connection = connection_.lock();
if (!connection) {
MAGMA_LOG(ERROR, "Can't submit without connection");
return MAGMA_STATUS_OK;
}
std::shared_ptr<MsdVsiContext> context = batch->GetContext().lock();
DASSERT(context.get() == static_cast<MsdVsiContext*>(this));
// If there are any mappings pending release, submit them now.
connection->SubmitPendingReleaseMappings(context);
// TODO(https://fxbug.dev/42118975): handle wait semaphores.
return connection->SubmitBatch(std::move(batch));
}
bool MsdVsiContext::MapRingbuffer(Ringbuffer* ringbuffer) {
uint64_t gpu_addr;
if (exec_address_space()->GetRingbufferGpuAddress(&gpu_addr)) {
// Already mapped.
return true;
}
gpu_addr = AddressSpaceLayout::system_gpu_addr_base();
std::shared_ptr<GpuMapping> gpu_mapping;
// TODO(https://fxbug.dev/42127373): ringbuffer should be mapped read-only
bool res = ringbuffer->MultiMap(exec_address_space(), gpu_addr, &gpu_mapping);
if (res) {
exec_address_space()->SetRingbufferGpuMapping(gpu_mapping);
}
return res;
}
void MsdVsiContext::Kill() {
if (killed_) {
return;
}
killed_ = true;
auto connection = connection_.lock();
if (connection) {
connection->SendContextKilled();
}
}
magma_status_t MsdVsiAbiContext::ExecuteCommandBufferWithResources(
msd::magma_command_buffer* cmd_buf, magma_exec_resource* exec_resources, msd::Buffer** buffers,
msd::Semaphore** wait_semaphores, msd::Semaphore** signal_semaphores) {
if (cmd_buf->flags) {
MAGMA_LOG(ERROR, "Flags not supported");
return MAGMA_STATUS_INVALID_ARGS;
}
auto context = ptr();
std::unique_ptr<MappedBatch> batch = MsdVsiContext::CreateBatch(
context, cmd_buf, exec_resources, buffers, wait_semaphores, signal_semaphores);
if (batch->IsCommandBuffer()) {
auto* command_buffer = static_cast<CommandBuffer*>(batch.get());
if (!command_buffer->PrepareForExecution()) {
MAGMA_LOG(ERROR, "Failed to prepare command buffer for execution");
return MAGMA_STATUS_INTERNAL_ERROR;
}
if (!command_buffer->IsValidBatch()) {
MAGMA_LOG(ERROR, "Command buffer is not a valid batch");
return MAGMA_STATUS_INTERNAL_ERROR;
}
}
magma::Status status = context->SubmitBatch(std::move(batch));
return status.get();
}