[magma] Implement buffer creation

This change adds support for host-allocated buffer creation.

Bug: b/272307395
Bug: b/277219980
Bug: b/279921814

Test: m libgfxstream_backend
Change-Id: Ie3b61834cd6d05ca7a50a3ea081e54c51dc8937e
diff --git a/host/magma/Connection.cpp b/host/magma/Connection.cpp
index e6e3a37..0f68a9c 100644
--- a/host/magma/Connection.cpp
+++ b/host/magma/Connection.cpp
@@ -28,6 +28,10 @@
 
 Connection::Connection(DrmDevice& device) : mDevice(device) {}
 
+DrmDevice& Connection::getDevice() {
+    return mDevice;
+}
+
 std::optional<uint32_t> Connection::createContext() {
     auto context = DrmContext::create(*this);
     if (!context) {
diff --git a/host/magma/Connection.h b/host/magma/Connection.h
index 429f16c..3e0c5a3 100644
--- a/host/magma/Connection.h
+++ b/host/magma/Connection.h
@@ -35,6 +35,9 @@
     Connection(Connection&&) noexcept = default;
     Connection& operator=(Connection&&) = delete;
 
+    // Get the parent device for this connection.
+    DrmDevice& getDevice();
+
     // Creates a new context and returns its ID. Returns nullopt on error.
     std::optional<uint32_t> createContext();
 
diff --git a/host/magma/IntelDrmDecoder.cpp b/host/magma/IntelDrmDecoder.cpp
index 83839d1..129c1a4 100644
--- a/host/magma/IntelDrmDecoder.cpp
+++ b/host/magma/IntelDrmDecoder.cpp
@@ -66,6 +66,10 @@
     MAGMA_DECODER_BIND_METHOD(magma_connection_unmap_buffer);
 }
 
+// TODO(b/279936417): Make objects and their IDs orthogonal.
+#define MAGMA_OBJECT_TO_ID(x) ((x) << 32ull)
+#define MAGMA_ID_TO_OBJECT(x) ((x) >> 32ull)
+
 magma_status_t IntelDrmDecoder::magma_device_import(magma_handle_t device_channel,
                                                     magma_device_t* device_out) {
     *device_out = 0;
@@ -223,7 +227,8 @@
                 WARN("Guest-allocated buffers are not currently supported.");
                 return MAGMA_STATUS_UNIMPLEMENTED;
             }
-            auto buffer = DrmBuffer::create(*dev, mContextId, sizeof(magma_intel_gen_timestamp_query));
+            auto buffer =
+                DrmBuffer::create(*dev, mContextId, sizeof(magma_intel_gen_timestamp_query));
             if (!buffer) {
                 return MAGMA_STATUS_MEMORY_ERROR;
             }
@@ -340,13 +345,38 @@
                                                                uint64_t size, uint64_t* size_out,
                                                                magma_buffer_t* buffer_out,
                                                                magma_buffer_id_t* id_out) {
-    WARN("%s not implemented", __FUNCTION__);
-    return MAGMA_STATUS_UNIMPLEMENTED;
+    *size_out = 0;
+    *buffer_out = MAGMA_INVALID_OBJECT_ID;
+    *id_out = MAGMA_INVALID_OBJECT_ID;
+    auto con = mConnections.get(connection);
+    if (!con) {
+        return MAGMA_STATUS_INVALID_ARGS;
+    }
+    auto buffer = DrmBuffer::create(con->getDevice(), mContextId, size);
+    if (!buffer) {
+        return MAGMA_STATUS_MEMORY_ERROR;
+    }
+    auto gem_handle = buffer->getHandle();
+    auto magma_handle = mBuffers.create(std::move(*buffer));
+    mGemHandleToBuffer.emplace(gem_handle, magma_handle);
+    *size_out = buffer->size();
+    *buffer_out = magma_handle;
+    *id_out = MAGMA_OBJECT_TO_ID(magma_handle);
+    return MAGMA_STATUS_OK;
 }
 
 void IntelDrmDecoder::magma_connection_release_buffer(magma_connection_t connection,
                                                       magma_buffer_t buffer) {
-    WARN("%s not implemented", __FUNCTION__);
+    auto con = mConnections.get(connection);
+    if (!con) {
+        return;
+    }
+    auto buf = mBuffers.get(buffer);
+    if (!buf) {
+        return;
+    }
+    mGemHandleToBuffer.erase(buf->getHandle());
+    mBuffers.erase(buffer);
 }
 
 magma_status_t IntelDrmDecoder::magma_connection_create_semaphore(
@@ -363,7 +393,8 @@
     WARN("%s not implemented", __FUNCTION__);
 }
 
-magma_status_t IntelDrmDecoder::magma_buffer_get_info(magma_buffer_t buffer, magma_buffer_info_t* info_out) {
+magma_status_t IntelDrmDecoder::magma_buffer_get_info(magma_buffer_t buffer,
+                                                      magma_buffer_info_t* info_out) {
     auto buf = mBuffers.get(buffer);
     if (!buf) {
         return MAGMA_STATUS_INVALID_ARGS;