[magma] Stub support for advanced context features.

Multiple address spaces: Intel supports creating multiple address
spaces and sharing them between contexts.  We can assume for now only
a single address space is actually used for executing command buffers
and detect when that assumption is violated.

Command buffer ordering across engines: Intel supports this in the
system driver.  We can assume for now only a single engine is
targeted per context and detect when that assumption is violated.

Test:all nuc_env packages under //src/media/codec/examples

Bug:110484

Change-Id: If2bd5f6866b7a4388ea769c1216064a7c2e76266
Reviewed-on: https://fuchsia-review.googlesource.com/c/third_party/github.com/intel/media-driver/+/731823
Reviewed-by: John Bauman <jbauman@google.com>
diff --git a/media_driver/linux/common/os/magma/mos_bufmgr_magma.cpp b/media_driver/linux/common/os/magma/mos_bufmgr_magma.cpp
index 143d455..3c9edb0 100644
--- a/media_driver/linux/common/os/magma/mos_bufmgr_magma.cpp
+++ b/media_driver/linux/common/os/magma/mos_bufmgr_magma.cpp
@@ -74,6 +74,22 @@
 
     InflightList* inflight_list() { return &inflight_list_;}
 
+    uint32_t next_vm_id() {
+        uint32_t id = next_pseudo_vm_id_.fetch_add(1);
+        // Don't support wrap around.
+        assert(id != 0);
+        return id;
+    }
+
+    static constexpr uint32_t kInvalidVmId = 0;
+
+    // Sets the pseudo VM ID if not already set.
+    uint32_t GetVmId(uint32_t vm_id) {
+        uint32_t invalid_id = kInvalidVmId;
+        vm_id_.compare_exchange_strong(invalid_id, vm_id);
+        return vm_id_.load();
+    }
+
 private:
     magma_connection_t connection_ {};
     magma_handle_t notification_handle_{};
@@ -81,6 +97,8 @@
     std::mutex allocator_mutex_;
     std::unique_ptr<SimpleAllocator> allocator_ __attribute__((__guarded_by__(allocator_mutex_)));
     InflightList inflight_list_;
+    std::atomic_uint next_pseudo_vm_id_ {1};
+    std::atomic_uint vm_id_ { kInvalidVmId };
 };
 
 
@@ -214,8 +232,37 @@
 
     const std::vector<uint32_t>& target_engines() { return target_engines_; }
 
+    // Should only be called once.
+    void set_vm_id(uint32_t vm_id) {
+        assert(vm_id != 0);
+        assert(vm_id_ == 0);
+        vm_id_ = vm_id;
+    }
+
+    uint32_t vm_id() { return vm_id_; }
+
+    // Should only be called once.
+    void set_ensure_ordering_across_engines() {
+        assert(!ensure_ordering_across_engines_);
+        ensure_ordering_across_engines_ = true;
+    }
+
+    bool ensure_ordering_across_engines() { return ensure_ordering_across_engines_; }
+
+    static constexpr uint64_t kInitialFlags = 0;
+
+    // Sets the command buffer flags if not already set.
+    uint64_t GetCommandBufferFlags(uint64_t command_buffer_flags) {
+        uint64_t unset = kInitialFlags;
+        command_buffer_flags_.compare_exchange_strong(unset, command_buffer_flags);
+        return command_buffer_flags_.load();
+    }
+
 private:
     std::vector<uint32_t> target_engines_;
+    uint32_t vm_id_ = 0;
+    bool ensure_ordering_across_engines_ = false;
+    std::atomic_uint64_t command_buffer_flags_ {kInitialFlags};
 };
 
 static void bufmgr_destroy(struct mos_bufmgr* mos_bufmgr)
@@ -596,12 +643,40 @@
     return context;
 }
 
-struct mos_linux_context* mos_gem_context_create_ext(struct mos_bufmgr *bufmgr, __u32 flags)
+struct mos_linux_context *mos_gem_context_create_ext(struct mos_bufmgr *bufmgr, __u32 flags)
 {
     assert(flags == 0);
     return mos_gem_context_create(bufmgr);
 }
 
+// Creates a new context and associates with it the pseudo VM referenced by the given context.
+// Note the reference context may not have been created with mos_gem_context_create_shared.
+// The pseudo VMs are just IDs and are used to track which "VMs" are used to execute command
+// buffers.  We assume that only one VM is ever used for all executed contexts, but if that
+// assumption proves false then we'll have to create additional connections for each VM.
+struct mos_linux_context* mos_gem_context_create_shared(struct mos_bufmgr *bufmgr,
+    mos_linux_context* ref_context, __u32 flags)
+{
+    LOG_VERBOSE("mos_gem_context_create_shared vm_id %u flags 0x%x", ref_context->vm->vm_id, flags);
+
+    bool ensure_ordering_across_engines = flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE;
+
+    flags &= ~I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE;
+    assert(flags == 0);
+
+    auto context = static_cast<MagmaContext*>(mos_gem_context_create(bufmgr));
+    if (!context)
+        return nullptr;
+
+    context->set_vm_id(ref_context->vm->vm_id);
+
+    if (ensure_ordering_across_engines) {
+        context->set_ensure_ordering_across_engines();
+    }
+
+    return context;
+}
+
 void mos_gem_context_destroy(struct mos_linux_context *mos_context)
 {
     auto context = static_cast<MagmaContext*>(mos_context);
@@ -652,6 +727,30 @@
     return 0;
 }
 
+struct drm_i915_gem_vm_control* mos_gem_vm_create(struct mos_bufmgr *mos_bufmgr)
+{
+    // Magma only supports one VM per connection, so for now we fake this support, assuming that
+    // contexts used for command buffer submission will only use one shared VM.
+    auto bufmgr = static_cast<MagmaBufMgr*>(mos_bufmgr);
+
+    auto vm = new drm_i915_gem_vm_control;
+
+    vm->extensions = 0;
+    vm->flags = 0;
+    vm->vm_id = bufmgr->next_vm_id();
+
+    LOG_VERBOSE("mos_gem_vm_create vm_id %u", vm->vm_id);
+
+    return vm;
+}
+
+void mos_gem_vm_destroy(struct mos_bufmgr *bufmgr, struct drm_i915_gem_vm_control* vm)
+{
+    LOG_VERBOSE("mos_gem_vm_destroy vm_id %u", vm->vm_id);
+
+    delete vm;
+}
+
 int mos_bufmgr_gem_get_devid(struct mos_bufmgr *mos_bufmgr)
 {
     auto bufmgr = static_cast<MagmaBufMgr*>(mos_bufmgr);
@@ -717,9 +816,29 @@
 
     uint64_t magma_flags = get_magma_flags(context, flags & I915_EXEC_RING_MASK);
 
-    LOG_VERBOSE("mos_gem_bo_context_exec2 bo %lu used %d context_id %u num_cliprects %d DR4 %d "
-        "flags 0x%x kAllowedFlags 0x%x magma_flags 0x%lx",
-        bo->id(), used, context->ctx_id, num_cliprects, DR4, flags, kAllowedFlags, magma_flags);
+    uint32_t vm_id = bufmgr->GetVmId(context->vm_id());
+
+    LOG_VERBOSE("mos_gem_bo_context_exec2 bo %lu used %d context_id %u vm_id %u bufmgr vm_id %u "
+        "num_cliprects %d DR4 %d flags 0x%x kAllowedFlags 0x%x magma_flags 0x%lx",
+        bo->id(), used, context->ctx_id, context->vm_id(), vm_id, num_cliprects, DR4,
+        flags, kAllowedFlags, magma_flags);
+
+    if (vm_id != context->vm_id()) {
+        // We don't support more than one VM per connection (see mos_gem_context_create_shared)
+        LOG_VERBOSE("Incompatible VM bufmgr vm_id %u context vm_id %u", vm_id, context->vm_id());
+        assert(false);
+        return -1;
+    }
+
+    if (context->ensure_ordering_across_engines()) {
+        uint64_t flags = context->GetCommandBufferFlags(magma_flags);
+        if (flags != magma_flags) {
+            LOG_VERBOSE("Ordering across engines not implemented flags 0x%lx magma_flags 0x%lx",
+                flags, magma_flags);
+            assert(false);
+            return -1;
+        }
+    }
 
     // TODO(fxbug.78281)
     uint64_t* semaphore_ids = nullptr;
diff --git a/media_driver/linux/common/os/magma/mos_bufmgr_stub.c b/media_driver/linux/common/os/magma/mos_bufmgr_stub.c
index cc8d0b1..a525fab 100644
--- a/media_driver/linux/common/os/magma/mos_bufmgr_stub.c
+++ b/media_driver/linux/common/os/magma/mos_bufmgr_stub.c
@@ -94,19 +94,6 @@
     return 0;
 }
 
-struct drm_i915_gem_vm_control* mos_gem_vm_create(struct mos_bufmgr *bufmgr)
-{
-    LOG_VERBOSE("mos_gem_vm_create unimplemented");
-    return NULL;
-}
-
-struct mos_linux_context *
-mos_gem_context_create_shared(struct mos_bufmgr *bufmgr, mos_linux_context* ctx, __u32 flags)
-{
-    LOG_VERBOSE("mos_gem_context_create_shared unimplemented");
-    return NULL;
-}
-
 int
 mos_get_reset_stats(struct mos_linux_context *ctx,
               uint32_t *reset_count,
@@ -117,11 +104,6 @@
     return 0;
 }
 
-void mos_gem_vm_destroy(struct mos_bufmgr *bufmgr, struct drm_i915_gem_vm_control* vm)
-{
-    LOG_VERBOSE("mos_gem_vm_destroy unimplemented");
-}
-
 int mos_get_context_param_sseu(struct mos_linux_context *ctx,
                 struct drm_i915_gem_context_param_sseu *sseu) {
     LOG_VERBOSE("mos_get_context_param_sseu unimplemented");
diff --git a/media_driver/linux/common/os/mos_interface.cpp b/media_driver/linux/common/os/mos_interface.cpp
index fcc0aec..90176da 100644
--- a/media_driver/linux/common/os/mos_interface.cpp
+++ b/media_driver/linux/common/os/mos_interface.cpp
@@ -433,7 +433,10 @@
 
     context->bIsAtomSOC           = false;
     context->bFreeContext         = true;
-#if !defined(ANDROID) && !defined(__Fuchsia__)
+#if defined(__Fuchsia__)
+    // TODO(TBD)
+    context->bKMDHasVCS2          = false;
+#elif !defined(ANDROID)
     {
         drm_i915_getparam_t gp;
         int32_t             ret   = -1;
@@ -453,9 +456,6 @@
             context->bKMDHasVCS2 = false;
         }
     }
-#else
-    //TODO(fxbug.dev/78281) - remove
-    fprintf(stderr, "%s:%d MosInterface::InitStreamParameters not implemented\n", __FILE__, __LINE__);
 #endif
 
     // read "Linux PerformanceTag Enable" user feature key