winsys/amdgpu: Re-use amdgpu_screen_winsys when possible
authorMichel Dänzer <mdaenzer@redhat.com>
Tue, 28 Jan 2020 10:07:15 +0000 (11:07 +0100)
committerMarge Bot <eric+marge@anholt.net>
Wed, 29 Jan 2020 15:51:01 +0000 (15:51 +0000)
Namely, if os_same_file_description determined that the DRM file
descriptor references the same file description.

v2:
* Adapt to amdgpu_winsys::sws_list_lock.
v3:
* Fix comparison of amdgpu_screen_winsys file descriptions, see
  https://gitlab.freedesktop.org/mesa/mesa/issues/2413 .
* Lock amdgpu_winsys::sws_list_lock for traversing the sws_list in
  amdgpu_winsys_create.

Reviewed-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>
Reviewed-by: Marek Olšák <marek.olsak@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/merge_requests/3582>

src/gallium/winsys/amdgpu/drm/amdgpu_winsys.c
src/gallium/winsys/amdgpu/drm/amdgpu_winsys.h

index 000abd00a145256a4c88f628beb3696436785240..89d3d93bb5f673e6be82c57760d48e24839d9ee5 100644 (file)
@@ -30,6 +30,7 @@
 #include "amdgpu_cs.h"
 #include "amdgpu_public.h"
 
+#include "util/os_file.h"
 #include "util/u_cpu_detect.h"
 #include "util/u_hash_table.h"
 #include "util/hash_table.h"
@@ -172,26 +173,8 @@ static void amdgpu_winsys_destroy(struct radeon_winsys *rws)
 
    simple_mtx_unlock(&dev_tab_mutex);
 
-   if (destroy) {
+   if (destroy)
       do_winsys_deinit(ws);
-   } else {
-      struct amdgpu_screen_winsys **sws_iter;
-
-      /* Remove this amdgpu_screen_winsys from amdgpu_winsys' list */
-      simple_mtx_lock(&ws->sws_list_lock);
-      for (sws_iter = &ws->sws_list; *sws_iter; sws_iter = &(*sws_iter)->next) {
-         if (*sws_iter == sws) {
-            *sws_iter = sws->next;
-            break;
-         }
-      }
-      simple_mtx_unlock(&ws->sws_list_lock);
-   }
-
-   if (sws->kms_handles) {
-      assert(!destroy);
-      _mesa_hash_table_destroy(sws->kms_handles, NULL);
-   }
 
    close(sws->fd);
    FREE(rws);
@@ -297,11 +280,34 @@ static int compare_pointers(void *key1, void *key2)
 
 static bool amdgpu_winsys_unref(struct radeon_winsys *rws)
 {
-   /* radeon_winsys corresponds to amdgpu_screen_winsys, which is never
-    * referenced multiple times, so amdgpu_winsys_destroy always needs to be
-    * called. It handles reference counting for amdgpu_winsys.
-    */
-   return true;
+   struct amdgpu_screen_winsys *sws = amdgpu_screen_winsys(rws);
+   struct amdgpu_winsys *aws = sws->aws;
+   bool ret;
+
+   simple_mtx_lock(&aws->sws_list_lock);
+
+   ret = pipe_reference(&sws->reference, NULL);
+   if (ret) {
+      struct amdgpu_screen_winsys **sws_iter;
+      struct amdgpu_winsys *aws = sws->aws;
+
+      /* Remove this amdgpu_screen_winsys from amdgpu_winsys' list, so that
+       * amdgpu_winsys_create can't re-use it anymore
+       */
+      for (sws_iter = &aws->sws_list; *sws_iter; sws_iter = &(*sws_iter)->next) {
+         if (*sws_iter == sws) {
+            *sws_iter = sws->next;
+            break;
+         }
+      }
+   }
+
+   simple_mtx_unlock(&aws->sws_list_lock);
+
+   if (ret && sws->kms_handles)
+      _mesa_hash_table_destroy(sws->kms_handles, NULL);
+
+   return ret;
 }
 
 static void amdgpu_pin_threads_to_L3_cache(struct radeon_winsys *rws,
@@ -338,6 +344,7 @@ amdgpu_winsys_create(int fd, const struct pipe_screen_config *config,
    if (!ws)
       return NULL;
 
+   pipe_reference_init(&ws->reference, 1);
    ws->fd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
 
    /* Look up the winsys from the dev table. */
@@ -356,12 +363,27 @@ amdgpu_winsys_create(int fd, const struct pipe_screen_config *config,
    /* Lookup a winsys if we have already created one for this device. */
    aws = util_hash_table_get(dev_tab, dev);
    if (aws) {
+      struct amdgpu_screen_winsys *sws_iter;
+
       /* Release the device handle, because we don't need it anymore.
        * This function is returning an existing winsys instance, which
        * has its own device handle.
        */
       amdgpu_device_deinitialize(dev);
 
+      simple_mtx_lock(&aws->sws_list_lock);
+      for (sws_iter = aws->sws_list; sws_iter; sws_iter = sws_iter->next) {
+         if (os_same_file_description(sws_iter->fd, ws->fd)) {
+            close(ws->fd);
+            FREE(ws);
+            ws = sws_iter;
+            pipe_reference(NULL, &ws->reference);
+            simple_mtx_unlock(&aws->sws_list_lock);
+            goto unlock;
+         }
+      }
+      simple_mtx_unlock(&aws->sws_list_lock);
+
       ws->kms_handles = _mesa_hash_table_create(NULL, kms_handle_hash,
                                                 kms_handle_equals);
       if (!ws->kms_handles)
@@ -478,6 +500,7 @@ amdgpu_winsys_create(int fd, const struct pipe_screen_config *config,
    aws->sws_list = ws;
    simple_mtx_unlock(&aws->sws_list_lock);
 
+unlock:
    /* We must unlock the mutex once the winsys is fully initialized, so that
     * other threads attempting to create the winsys from the same fd will
     * get a fully initialized winsys and not just half-way initialized. */
index c2edf4f46dc2df59ab799cd5fd01949ed3521217..a22be6086dcc63ff128e2a6e22458a24bbb6b4bf 100644 (file)
@@ -107,6 +107,7 @@ struct amdgpu_screen_winsys {
    struct radeon_winsys base;
    struct amdgpu_winsys *aws;
    int fd;
+   struct pipe_reference reference;
    struct amdgpu_screen_winsys *next;
 
    /* Maps a BO to its KMS handle valid for this DRM file descriptor