blob: 804e291ff00a92e5411227f0fa8300b9b00613a8 [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 "anv_magma.h"
#include "drm_command_buffer.h"
#include "magma_util/inflight_list.h"
#include "magma_util/macros.h"
#include <chrono>
class Connection : public anv_connection {
public:
Connection(magma_connection_t magma_connection)
: inflight_list_(magma_connection)
{
anv_connection::connection = magma_connection;
}
~Connection() { magma_release_connection(magma_connection()); }
magma_connection_t magma_connection() { return anv_connection::connection; }
magma::InflightList* inflight_list() { return &inflight_list_; }
static Connection* cast(anv_connection* connection) { return static_cast<Connection*>(connection); }
private:
magma::InflightList inflight_list_;
};
anv_connection* AnvMagmaCreateConnection(magma_connection_t connection)
{
return new Connection(connection);
}
void AnvMagmaReleaseConnection(anv_connection* connection)
{
delete static_cast<Connection*>(connection);
}
void AnvMagmaConnectionWait(anv_connection* connection, uint64_t buffer_id, int64_t* timeout_ns)
{
magma::InflightList* inflight_list = Connection::cast(connection)->inflight_list();
auto start = std::chrono::high_resolution_clock::now();
while (inflight_list->is_inflight(buffer_id) &&
std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::high_resolution_clock::now() - start)
.count() < *timeout_ns) {
if (inflight_list->WaitForCompletion(magma::ns_to_ms(*timeout_ns))) {
inflight_list->ServiceCompletions(Connection::cast(connection)->magma_connection());
}
}
}
int AnvMagmaConnectionIsBusy(anv_connection* connection, uint64_t buffer_id)
{
magma::InflightList* inflight_list = Connection::cast(connection)->inflight_list();
inflight_list->ServiceCompletions(Connection::cast(connection)->magma_connection());
return inflight_list->is_inflight(buffer_id) ? 1 : 0;
}
int AnvMagmaConnectionExec(anv_connection* connection, uint32_t context_id, struct drm_i915_gem_execbuffer2* execbuf)
{
if (execbuf->buffer_count == 0)
return 0;
uint32_t syncobj_count = execbuf->num_cliprects;
uint64_t required_size = DrmCommandBuffer::RequiredSize(execbuf, syncobj_count);
uint64_t cmd_buf_id;
magma_status_t status =
magma_create_command_buffer(Connection::cast(connection)->magma_connection(), required_size, &cmd_buf_id);
if (status != MAGMA_STATUS_OK)
return DRET_MSG(-1, "magma_alloc_command_buffer failed size 0x%" PRIx64 " : %d",
required_size, status);
void* cmd_buf_data;
status = magma_map(Connection::cast(connection)->magma_connection(), cmd_buf_id, &cmd_buf_data);
if (status != MAGMA_STATUS_OK) {
magma_release_command_buffer(Connection::cast(connection)->magma_connection(), cmd_buf_id);
return DRET_MSG(-1, "magma_system_map failed: %d", status);
}
std::vector<uint64_t> wait_semaphore_ids;
std::vector<uint64_t> signal_semaphore_ids;
for (uint32_t i = 0; i < syncobj_count; i++) {
auto& syncobj = reinterpret_cast<drm_i915_gem_exec_fence*>(execbuf->cliprects_ptr)[i];
if (syncobj.flags & I915_EXEC_FENCE_WAIT) {
wait_semaphore_ids.push_back(magma_get_semaphore_id(syncobj.handle));
} else if (syncobj.flags & I915_EXEC_FENCE_SIGNAL) {
signal_semaphore_ids.push_back(magma_get_semaphore_id(syncobj.handle));
} else {
return DRET_MSG(-1, "syncobj not wait or signal");
}
}
if (!DrmCommandBuffer::Translate(execbuf, std::move(wait_semaphore_ids),
std::move(signal_semaphore_ids), cmd_buf_data)) {
status = magma_unmap(Connection::cast(connection)->magma_connection(), cmd_buf_id);
DASSERT(status == MAGMA_STATUS_OK);
magma_release_command_buffer(Connection::cast(connection)->magma_connection(), cmd_buf_id);
return DRET_MSG(-1, "DrmCommandBuffer::Translate failed");
}
status = magma_unmap(Connection::cast(connection)->magma_connection(), cmd_buf_id);
DASSERT(status == MAGMA_STATUS_OK);
magma_submit_command_buffer(Connection::cast(connection)->magma_connection(), cmd_buf_id, context_id);
magma::InflightList* inflight_list = Connection::cast(connection)->inflight_list();
for (uint32_t i = 0; i < execbuf->buffer_count; i++) {
inflight_list->add(magma_get_buffer_id(
reinterpret_cast<drm_i915_gem_exec_object2*>(execbuf->buffers_ptr)[i].handle));
}
inflight_list->ServiceCompletions(Connection::cast(connection)->magma_connection());
return 0;
}