[Mesa-dev,v5,03/12] gallium: add common pipe_screen reference counting functions

Submitted by Rob Herring on Aug. 7, 2017, 10:58 p.m.

Details

Message ID 20170807225819.13831-4-robh@kernel.org
State New
Headers show
Series "Common pipe screen ref counting" ( rev: 5 ) in Mesa

Not browsing as part of any series.

Commit Message

Rob Herring Aug. 7, 2017, 10:58 p.m.
In order to prevent multiple pipe_screens being created in the same
process, lookup of the DRM FD and reference counting of the pipe_screen
are needed. Several implementations of this exist in various gallium
drivers/winsys already. This creates a common version which is opt-in
for winsys implementations.

The callers of pipe_screen_{un}reference() functions are responsible for
serializing the calls. Currently, this is done by the pipe-loader mutex.

Signed-off-by: Rob Herring <robh@kernel.org>
---
 src/gallium/auxiliary/Makefile.sources |   2 +
 src/gallium/auxiliary/util/u_screen.c  | 112 +++++++++++++++++++++++++++++++++
 src/gallium/auxiliary/util/u_screen.h  |  32 ++++++++++
 src/gallium/include/pipe/p_screen.h    |   3 +
 4 files changed, 149 insertions(+)
 create mode 100644 src/gallium/auxiliary/util/u_screen.c
 create mode 100644 src/gallium/auxiliary/util/u_screen.h

Patch hide | download patch | download mbox

diff --git a/src/gallium/auxiliary/Makefile.sources b/src/gallium/auxiliary/Makefile.sources
index 9ae8e6c8ca53..f84bfec60fe7 100644
--- a/src/gallium/auxiliary/Makefile.sources
+++ b/src/gallium/auxiliary/Makefile.sources
@@ -283,6 +283,8 @@  C_SOURCES := \
 	util/u_ringbuffer.h \
 	util/u_sampler.c \
 	util/u_sampler.h \
+	util/u_screen.c \
+	util/u_screen.h \
 	util/u_simple_shaders.c \
 	util/u_simple_shaders.h \
 	util/u_split_prim.h \
diff --git a/src/gallium/auxiliary/util/u_screen.c b/src/gallium/auxiliary/util/u_screen.c
new file mode 100644
index 000000000000..dec83b736883
--- /dev/null
+++ b/src/gallium/auxiliary/util/u_screen.c
@@ -0,0 +1,112 @@ 
+/*
+ * Copyright 2016-2017 Linaro, Ltd., Rob Herring <robh@kernel.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * Functions for managing pipe_screen's
+ */
+
+#include <sys/stat.h>
+
+#include "pipe/p_screen.h"
+#include "util/u_hash_table.h"
+#include "util/u_inlines.h"
+#include "util/u_pointer.h"
+#include "util/u_screen.h"
+
+static struct util_hash_table *fd_tab = NULL;
+
+static unsigned hash_fd(void *key)
+{
+   int fd = pointer_to_intptr(key);
+   struct stat stat;
+   fstat(fd, &stat);
+
+   return stat.st_dev ^ stat.st_ino ^ stat.st_rdev;
+}
+
+static int compare_fd(void *key1, void *key2)
+{
+   int fd1 = pointer_to_intptr(key1);
+   int fd2 = pointer_to_intptr(key2);
+   struct stat stat1, stat2;
+   fstat(fd1, &stat1);
+   fstat(fd2, &stat2);
+
+   return stat1.st_dev != stat2.st_dev ||
+         stat1.st_ino != stat2.st_ino ||
+         stat1.st_rdev != stat2.st_rdev;
+}
+
+struct pipe_screen *
+pipe_screen_reference(int fd)
+{
+   struct pipe_screen *pscreen;
+
+   if (!fd_tab) {
+      fd_tab = util_hash_table_create(hash_fd, compare_fd);
+      return NULL;
+   }
+
+   pscreen = util_hash_table_get(fd_tab, intptr_to_pointer(fd));
+   if (pscreen)
+      pipe_reference(NULL, &pscreen->reference);
+
+   return pscreen;
+}
+
+boolean
+pipe_screen_unreference(struct pipe_screen *pscreen)
+{
+   boolean destroy;
+
+   if (!pscreen)
+      return FALSE;
+
+   /* Work-around until all pipe_screens have ref counting */
+   if (!pipe_is_referenced(&pscreen->reference)) {
+      pscreen->destroy(pscreen);
+      return TRUE;
+   }
+
+   destroy = pipe_reference(&pscreen->reference, NULL);
+   if (destroy) {
+      int fd = pscreen->fd;
+
+      pscreen->destroy(pscreen);
+
+      if (fd >= 0) {
+         util_hash_table_remove(fd_tab, intptr_to_pointer(fd));
+         close(fd);
+      }
+   }
+   return destroy;
+}
+
+
+void pipe_screen_reference_init(struct pipe_screen *pscreen, int fd)
+{
+   pscreen->fd = fd;
+   pipe_reference_init(&pscreen->reference, 1);
+   util_hash_table_set(fd_tab, intptr_to_pointer(fd), pscreen);
+}
diff --git a/src/gallium/auxiliary/util/u_screen.h b/src/gallium/auxiliary/util/u_screen.h
new file mode 100644
index 000000000000..a7b1e9ff2787
--- /dev/null
+++ b/src/gallium/auxiliary/util/u_screen.h
@@ -0,0 +1,32 @@ 
+/*
+ * Copyright 2016-2017 Linaro, Ltd., Rob Herring <robh@kernel.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "pipe/p_defines.h"
+
+struct pipe_screen;
+
+struct pipe_screen *pipe_screen_reference(int fd);
+
+boolean pipe_screen_unreference(struct pipe_screen *pscreen);
+
+void pipe_screen_reference_init(struct pipe_screen *pscreen, int fd);
diff --git a/src/gallium/include/pipe/p_screen.h b/src/gallium/include/pipe/p_screen.h
index b6623d1dd71e..dbb14ef882c0 100644
--- a/src/gallium/include/pipe/p_screen.h
+++ b/src/gallium/include/pipe/p_screen.h
@@ -41,6 +41,7 @@ 
 #include "pipe/p_compiler.h"
 #include "pipe/p_format.h"
 #include "pipe/p_defines.h"
+#include "pipe/p_state.h"
 #include "pipe/p_video_enums.h"
 
 
@@ -68,6 +69,8 @@  struct driOptionCache;
  * context.
  */
 struct pipe_screen {
+   struct pipe_reference reference;
+   int fd;
    void (*destroy)( struct pipe_screen * );
 
    const char *(*get_name)( struct pipe_screen * );

Comments

Hi Rob,

This is not enough to do screen reference counting. There are primary
FDs and render node FDs, and we want to have only one pipe_screen for
all kinds of FDs pointing to the same device.

Imagine someone creates a pipe_screen with a render node FD, and then
creates another pipe_screen with a primary FD. We want to return the
same pipe_screen instance in both cases.

The pipe_screen should use the render node FD for everything if it was
created first with that FD. However, it also needs to keep the primary
FD in order to be able to do GEM_FLINK when required.

libdrm_amdgpu handles all those cases correctly. It has "fd", which is
the main one, but also has "flink_fd" for GEM_FLINK. If "fd" is a
primary FD or there is no primary FD, "fd == flink_fd". If "fd" is a
render node and a primary FD has also been used to create the device
object, "fd" is the render node and "flink_fd" is the primary FD for
GEM_FLINK.

The code:
https://cgit.freedesktop.org/mesa/drm/tree/amdgpu/amdgpu_device.c

I can't accept this patch, because it effectively disables that
amdgpu_device code.

Marek


On Tue, Aug 8, 2017 at 12:58 AM, Rob Herring <robh@kernel.org> wrote:
> In order to prevent multiple pipe_screens being created in the same
> process, lookup of the DRM FD and reference counting of the pipe_screen
> are needed. Several implementations of this exist in various gallium
> drivers/winsys already. This creates a common version which is opt-in
> for winsys implementations.
>
> The callers of pipe_screen_{un}reference() functions are responsible for
> serializing the calls. Currently, this is done by the pipe-loader mutex.
>
> Signed-off-by: Rob Herring <robh@kernel.org>
> ---
>  src/gallium/auxiliary/Makefile.sources |   2 +
>  src/gallium/auxiliary/util/u_screen.c  | 112 +++++++++++++++++++++++++++++++++
>  src/gallium/auxiliary/util/u_screen.h  |  32 ++++++++++
>  src/gallium/include/pipe/p_screen.h    |   3 +
>  4 files changed, 149 insertions(+)
>  create mode 100644 src/gallium/auxiliary/util/u_screen.c
>  create mode 100644 src/gallium/auxiliary/util/u_screen.h
>
> diff --git a/src/gallium/auxiliary/Makefile.sources b/src/gallium/auxiliary/Makefile.sources
> index 9ae8e6c8ca53..f84bfec60fe7 100644
> --- a/src/gallium/auxiliary/Makefile.sources
> +++ b/src/gallium/auxiliary/Makefile.sources
> @@ -283,6 +283,8 @@ C_SOURCES := \
>         util/u_ringbuffer.h \
>         util/u_sampler.c \
>         util/u_sampler.h \
> +       util/u_screen.c \
> +       util/u_screen.h \
>         util/u_simple_shaders.c \
>         util/u_simple_shaders.h \
>         util/u_split_prim.h \
> diff --git a/src/gallium/auxiliary/util/u_screen.c b/src/gallium/auxiliary/util/u_screen.c
> new file mode 100644
> index 000000000000..dec83b736883
> --- /dev/null
> +++ b/src/gallium/auxiliary/util/u_screen.c
> @@ -0,0 +1,112 @@
> +/*
> + * Copyright 2016-2017 Linaro, Ltd., Rob Herring <robh@kernel.org>
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the
> + * "Software"), to deal in the Software without restriction, including
> + * without limitation the rights to use, copy, modify, merge, publish,
> + * distribute, sub license, and/or sell copies of the Software, and to
> + * permit persons to whom the Software is furnished to do so, subject to
> + * the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the
> + * next paragraph) shall be included in all copies or substantial portions
> + * of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
> + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
> + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
> + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
> + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
> + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
> + */
> +
> +/**
> + * Functions for managing pipe_screen's
> + */
> +
> +#include <sys/stat.h>
> +
> +#include "pipe/p_screen.h"
> +#include "util/u_hash_table.h"
> +#include "util/u_inlines.h"
> +#include "util/u_pointer.h"
> +#include "util/u_screen.h"
> +
> +static struct util_hash_table *fd_tab = NULL;
> +
> +static unsigned hash_fd(void *key)
> +{
> +   int fd = pointer_to_intptr(key);
> +   struct stat stat;
> +   fstat(fd, &stat);
> +
> +   return stat.st_dev ^ stat.st_ino ^ stat.st_rdev;
> +}
> +
> +static int compare_fd(void *key1, void *key2)
> +{
> +   int fd1 = pointer_to_intptr(key1);
> +   int fd2 = pointer_to_intptr(key2);
> +   struct stat stat1, stat2;
> +   fstat(fd1, &stat1);
> +   fstat(fd2, &stat2);
> +
> +   return stat1.st_dev != stat2.st_dev ||
> +         stat1.st_ino != stat2.st_ino ||
> +         stat1.st_rdev != stat2.st_rdev;
> +}
> +
> +struct pipe_screen *
> +pipe_screen_reference(int fd)
> +{
> +   struct pipe_screen *pscreen;
> +
> +   if (!fd_tab) {
> +      fd_tab = util_hash_table_create(hash_fd, compare_fd);
> +      return NULL;
> +   }
> +
> +   pscreen = util_hash_table_get(fd_tab, intptr_to_pointer(fd));
> +   if (pscreen)
> +      pipe_reference(NULL, &pscreen->reference);
> +
> +   return pscreen;
> +}
> +
> +boolean
> +pipe_screen_unreference(struct pipe_screen *pscreen)
> +{
> +   boolean destroy;
> +
> +   if (!pscreen)
> +      return FALSE;
> +
> +   /* Work-around until all pipe_screens have ref counting */
> +   if (!pipe_is_referenced(&pscreen->reference)) {
> +      pscreen->destroy(pscreen);
> +      return TRUE;
> +   }
> +
> +   destroy = pipe_reference(&pscreen->reference, NULL);
> +   if (destroy) {
> +      int fd = pscreen->fd;
> +
> +      pscreen->destroy(pscreen);
> +
> +      if (fd >= 0) {
> +         util_hash_table_remove(fd_tab, intptr_to_pointer(fd));
> +         close(fd);
> +      }
> +   }
> +   return destroy;
> +}
> +
> +
> +void pipe_screen_reference_init(struct pipe_screen *pscreen, int fd)
> +{
> +   pscreen->fd = fd;
> +   pipe_reference_init(&pscreen->reference, 1);
> +   util_hash_table_set(fd_tab, intptr_to_pointer(fd), pscreen);
> +}
> diff --git a/src/gallium/auxiliary/util/u_screen.h b/src/gallium/auxiliary/util/u_screen.h
> new file mode 100644
> index 000000000000..a7b1e9ff2787
> --- /dev/null
> +++ b/src/gallium/auxiliary/util/u_screen.h
> @@ -0,0 +1,32 @@
> +/*
> + * Copyright 2016-2017 Linaro, Ltd., Rob Herring <robh@kernel.org>
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the
> + * "Software"), to deal in the Software without restriction, including
> + * without limitation the rights to use, copy, modify, merge, publish,
> + * distribute, sub license, and/or sell copies of the Software, and to
> + * permit persons to whom the Software is furnished to do so, subject to
> + * the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the
> + * next paragraph) shall be included in all copies or substantial portions
> + * of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
> + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
> + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
> + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
> + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
> + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
> + */
> +#include "pipe/p_defines.h"
> +
> +struct pipe_screen;
> +
> +struct pipe_screen *pipe_screen_reference(int fd);
> +
> +boolean pipe_screen_unreference(struct pipe_screen *pscreen);
> +
> +void pipe_screen_reference_init(struct pipe_screen *pscreen, int fd);
> diff --git a/src/gallium/include/pipe/p_screen.h b/src/gallium/include/pipe/p_screen.h
> index b6623d1dd71e..dbb14ef882c0 100644
> --- a/src/gallium/include/pipe/p_screen.h
> +++ b/src/gallium/include/pipe/p_screen.h
> @@ -41,6 +41,7 @@
>  #include "pipe/p_compiler.h"
>  #include "pipe/p_format.h"
>  #include "pipe/p_defines.h"
> +#include "pipe/p_state.h"
>  #include "pipe/p_video_enums.h"
>
>
> @@ -68,6 +69,8 @@ struct driOptionCache;
>   * context.
>   */
>  struct pipe_screen {
> +   struct pipe_reference reference;
> +   int fd;
>     void (*destroy)( struct pipe_screen * );
>
>     const char *(*get_name)( struct pipe_screen * );
> --
> 2.11.0
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/mesa-dev
On Wed, Aug 9, 2017 at 2:18 PM, Marek Olšák <maraeo@gmail.com> wrote:
> Hi Rob,
>
> This is not enough to do screen reference counting. There are primary
> FDs and render node FDs, and we want to have only one pipe_screen for
> all kinds of FDs pointing to the same device.
>
> Imagine someone creates a pipe_screen with a render node FD, and then
> creates another pipe_screen with a primary FD. We want to return the
> same pipe_screen instance in both cases.
>
> The pipe_screen should use the render node FD for everything if it was
> created first with that FD. However, it also needs to keep the primary
> FD in order to be able to do GEM_FLINK when required.
>
> libdrm_amdgpu handles all those cases correctly. It has "fd", which is
> the main one, but also has "flink_fd" for GEM_FLINK. If "fd" is a
> primary FD or there is no primary FD, "fd == flink_fd". If "fd" is a
> render node and a primary FD has also been used to create the device
> object, "fd" is the render node and "flink_fd" is the primary FD for
> GEM_FLINK.
>
> The code:
> https://cgit.freedesktop.org/mesa/drm/tree/amdgpu/amdgpu_device.c
>
> I can't accept this patch, because it effectively disables that
> amdgpu_device code.

This patch alone doesn't change any driver. I think you mean patch #8
which converts amdgpu and which could be dropped (though I'd like to
keep the radeon winsys parts). However, I believe I've maintained the
behavior for amdgpu.

The amdgpu winsys does not use the fd in these functions (the screen
fd will be -1). The only change should be that the mutex is removed
and the pipe_reference is moved from ws->reference to
ws->base.screen->reference. It's still using the device in the hash
table.

Rob
OK. This patch is:

Reviewed-by: Marek Olšák <marek.olsak@amd.com>

Marek

On Wed, Aug 9, 2017 at 9:53 PM, Rob Herring <robh@kernel.org> wrote:
> On Wed, Aug 9, 2017 at 2:18 PM, Marek Olšák <maraeo@gmail.com> wrote:
>> Hi Rob,
>>
>> This is not enough to do screen reference counting. There are primary
>> FDs and render node FDs, and we want to have only one pipe_screen for
>> all kinds of FDs pointing to the same device.
>>
>> Imagine someone creates a pipe_screen with a render node FD, and then
>> creates another pipe_screen with a primary FD. We want to return the
>> same pipe_screen instance in both cases.
>>
>> The pipe_screen should use the render node FD for everything if it was
>> created first with that FD. However, it also needs to keep the primary
>> FD in order to be able to do GEM_FLINK when required.
>>
>> libdrm_amdgpu handles all those cases correctly. It has "fd", which is
>> the main one, but also has "flink_fd" for GEM_FLINK. If "fd" is a
>> primary FD or there is no primary FD, "fd == flink_fd". If "fd" is a
>> render node and a primary FD has also been used to create the device
>> object, "fd" is the render node and "flink_fd" is the primary FD for
>> GEM_FLINK.
>>
>> The code:
>> https://cgit.freedesktop.org/mesa/drm/tree/amdgpu/amdgpu_device.c
>>
>> I can't accept this patch, because it effectively disables that
>> amdgpu_device code.
>
> This patch alone doesn't change any driver. I think you mean patch #8
> which converts amdgpu and which could be dropped (though I'd like to
> keep the radeon winsys parts). However, I believe I've maintained the
> behavior for amdgpu.
>
> The amdgpu winsys does not use the fd in these functions (the screen
> fd will be -1). The only change should be that the mutex is removed
> and the pipe_reference is moved from ws->reference to
> ws->base.screen->reference. It's still using the device in the hash
> table.
>
> Rob
On Tue, Aug 8, 2017 at 12:58 AM, Rob Herring <robh@kernel.org> wrote:
> In order to prevent multiple pipe_screens being created in the same
> process, lookup of the DRM FD and reference counting of the pipe_screen
> are needed. Several implementations of this exist in various gallium
> drivers/winsys already. This creates a common version which is opt-in
> for winsys implementations.
>
> The callers of pipe_screen_{un}reference() functions are responsible for
> serializing the calls. Currently, this is done by the pipe-loader mutex.
>
> Signed-off-by: Rob Herring <robh@kernel.org>
> ---
>  src/gallium/auxiliary/Makefile.sources |   2 +
>  src/gallium/auxiliary/util/u_screen.c  | 112 +++++++++++++++++++++++++++++++++
>  src/gallium/auxiliary/util/u_screen.h  |  32 ++++++++++
>  src/gallium/include/pipe/p_screen.h    |   3 +
>  4 files changed, 149 insertions(+)
>  create mode 100644 src/gallium/auxiliary/util/u_screen.c
>  create mode 100644 src/gallium/auxiliary/util/u_screen.h
>
> diff --git a/src/gallium/auxiliary/Makefile.sources b/src/gallium/auxiliary/Makefile.sources
> index 9ae8e6c8ca53..f84bfec60fe7 100644
> --- a/src/gallium/auxiliary/Makefile.sources
> +++ b/src/gallium/auxiliary/Makefile.sources
> @@ -283,6 +283,8 @@ C_SOURCES := \
>         util/u_ringbuffer.h \
>         util/u_sampler.c \
>         util/u_sampler.h \
> +       util/u_screen.c \
> +       util/u_screen.h \
>         util/u_simple_shaders.c \
>         util/u_simple_shaders.h \
>         util/u_split_prim.h \
> diff --git a/src/gallium/auxiliary/util/u_screen.c b/src/gallium/auxiliary/util/u_screen.c
> new file mode 100644
> index 000000000000..dec83b736883
> --- /dev/null
> +++ b/src/gallium/auxiliary/util/u_screen.c
> @@ -0,0 +1,112 @@
> +/*
> + * Copyright 2016-2017 Linaro, Ltd., Rob Herring <robh@kernel.org>
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the
> + * "Software"), to deal in the Software without restriction, including
> + * without limitation the rights to use, copy, modify, merge, publish,
> + * distribute, sub license, and/or sell copies of the Software, and to
> + * permit persons to whom the Software is furnished to do so, subject to
> + * the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the
> + * next paragraph) shall be included in all copies or substantial portions
> + * of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
> + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
> + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
> + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
> + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
> + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
> + */
> +
> +/**
> + * Functions for managing pipe_screen's
> + */
> +
> +#include <sys/stat.h>
> +
> +#include "pipe/p_screen.h"
> +#include "util/u_hash_table.h"
> +#include "util/u_inlines.h"
> +#include "util/u_pointer.h"
> +#include "util/u_screen.h"
> +
> +static struct util_hash_table *fd_tab = NULL;
> +
> +static unsigned hash_fd(void *key)
> +{
> +   int fd = pointer_to_intptr(key);
> +   struct stat stat;
> +   fstat(fd, &stat);
> +
> +   return stat.st_dev ^ stat.st_ino ^ stat.st_rdev;
> +}
> +
> +static int compare_fd(void *key1, void *key2)
> +{
> +   int fd1 = pointer_to_intptr(key1);
> +   int fd2 = pointer_to_intptr(key2);
> +   struct stat stat1, stat2;
> +   fstat(fd1, &stat1);
> +   fstat(fd2, &stat2);
> +
> +   return stat1.st_dev != stat2.st_dev ||
> +         stat1.st_ino != stat2.st_ino ||
> +         stat1.st_rdev != stat2.st_rdev;
> +}
> +
> +struct pipe_screen *
> +pipe_screen_reference(int fd)
> +{
> +   struct pipe_screen *pscreen;
> +
> +   if (!fd_tab) {
> +      fd_tab = util_hash_table_create(hash_fd, compare_fd);
> +      return NULL;
> +   }
> +
> +   pscreen = util_hash_table_get(fd_tab, intptr_to_pointer(fd));
> +   if (pscreen)
> +      pipe_reference(NULL, &pscreen->reference);
> +
> +   return pscreen;
> +}
> +
> +boolean
> +pipe_screen_unreference(struct pipe_screen *pscreen)
> +{
> +   boolean destroy;
> +
> +   if (!pscreen)
> +      return FALSE;
> +
> +   /* Work-around until all pipe_screens have ref counting */
> +   if (!pipe_is_referenced(&pscreen->reference)) {
> +      pscreen->destroy(pscreen);
> +      return TRUE;
> +   }
> +
> +   destroy = pipe_reference(&pscreen->reference, NULL);
> +   if (destroy) {
> +      int fd = pscreen->fd;
> +
> +      pscreen->destroy(pscreen);
> +
> +      if (fd >= 0) {
> +         util_hash_table_remove(fd_tab, intptr_to_pointer(fd));
> +         close(fd);
> +      }
> +   }
> +   return destroy;
> +}
> +
> +
> +void pipe_screen_reference_init(struct pipe_screen *pscreen, int fd)
> +{
> +   pscreen->fd = fd;
> +   pipe_reference_init(&pscreen->reference, 1);
> +   util_hash_table_set(fd_tab, intptr_to_pointer(fd), pscreen);
> +}
> diff --git a/src/gallium/auxiliary/util/u_screen.h b/src/gallium/auxiliary/util/u_screen.h
> new file mode 100644
> index 000000000000..a7b1e9ff2787
> --- /dev/null
> +++ b/src/gallium/auxiliary/util/u_screen.h
> @@ -0,0 +1,32 @@
> +/*
> + * Copyright 2016-2017 Linaro, Ltd., Rob Herring <robh@kernel.org>
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the
> + * "Software"), to deal in the Software without restriction, including
> + * without limitation the rights to use, copy, modify, merge, publish,
> + * distribute, sub license, and/or sell copies of the Software, and to
> + * permit persons to whom the Software is furnished to do so, subject to
> + * the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the
> + * next paragraph) shall be included in all copies or substantial portions
> + * of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
> + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
> + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
> + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
> + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
> + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
> + */
> +#include "pipe/p_defines.h"
> +
> +struct pipe_screen;
> +
> +struct pipe_screen *pipe_screen_reference(int fd);
> +
> +boolean pipe_screen_unreference(struct pipe_screen *pscreen);
> +
> +void pipe_screen_reference_init(struct pipe_screen *pscreen, int fd);
> diff --git a/src/gallium/include/pipe/p_screen.h b/src/gallium/include/pipe/p_screen.h
> index b6623d1dd71e..dbb14ef882c0 100644
> --- a/src/gallium/include/pipe/p_screen.h
> +++ b/src/gallium/include/pipe/p_screen.h
> @@ -41,6 +41,7 @@
>  #include "pipe/p_compiler.h"
>  #include "pipe/p_format.h"
>  #include "pipe/p_defines.h"
> +#include "pipe/p_state.h"
>  #include "pipe/p_video_enums.h"
>
>
> @@ -68,6 +69,8 @@ struct driOptionCache;
>   * context.
>   */
>  struct pipe_screen {
> +   struct pipe_reference reference;
> +   int fd;
>     void (*destroy)( struct pipe_screen * );

BTW, I'd like an empty line between "fd" and "destroy".

Marek