// 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;
}
