[Mesa-dev] [PATCH 1/3] gallium: add renderonly library

Christian Gmeiner christian.gmeiner at gmail.com
Mon Dec 19 19:54:04 UTC 2016


Hi Thierry,

2016-12-19 14:08 GMT+01:00 Thierry Reding <thierry.reding at gmail.com>:
> On Wed, Nov 30, 2016 at 02:44:34PM +0100, Christian Gmeiner wrote:
>> This a very lightweight library to add basic support for
>> renderonly GPUs. It does all the magic regarding in/exporting
>> buffers etc. This library will likely break android support and
>> hopefully will get replaced with a better solution based on gbm2.
>>
>> Signed-off-by: Christian Gmeiner <christian.gmeiner at gmail.com>
>> ---
>>  src/gallium/Automake.inc                      |   5 +
>>  src/gallium/auxiliary/Makefile.am             |  10 ++
>>  src/gallium/auxiliary/Makefile.sources        |   4 +
>>  src/gallium/auxiliary/renderonly/renderonly.c | 199 ++++++++++++++++++++++++++
>>  src/gallium/auxiliary/renderonly/renderonly.h |  81 +++++++++++
>>  5 files changed, 299 insertions(+)
>>  create mode 100644 src/gallium/auxiliary/renderonly/renderonly.c
>>  create mode 100644 src/gallium/auxiliary/renderonly/renderonly.h
>
> Hi Christian,
>
> sorry for being late to the party. I only ran across this by accident.
> Would you mind keeping me in Cc for subsequent versions of this? It's
> been more than two years since I wrote the original proposal for this,
> but I'm still interested in seeing a solution emerge.
>

Sure will add you to CC list. Btw. your timing could not be better I
wanted to send out
v2 today. But I will hold it back and incooperate your feedback.

> Anyway, thanks for picking this up.
>
> From a diff point of view this is certainly much more terse than the
> original proposal. I find it slightly unfortunate that the drivers for
> the render GPU have to be changed. But it's hard to argue with the
> reduction in size.
>
> I still think that Tegra will eventually require more than the stub that
> you have in this series because the same device that exposes the scanout
> engine also contains units that can do video compositing, decoding and
> encoding. There's in fact recently been discussions on how best to
> provide that functionality and Mesa looks like the best long-term target
> currently. Anyway, that's a bridge I think we can cross when we get
> there, this concept looks fine to get started.
>
>> diff --git a/src/gallium/Automake.inc b/src/gallium/Automake.inc
>> index 6fe2e22..6aadcb9 100644
>> --- a/src/gallium/Automake.inc
>> +++ b/src/gallium/Automake.inc
>> @@ -50,6 +50,11 @@ GALLIUM_COMMON_LIB_DEPS = \
>>       $(PTHREAD_LIBS) \
>>       $(DLOPEN_LIBS)
>>
>> +if HAVE_LIBDRM
>> +GALLIUM_COMMON_LIB_DEPS += \
>> +     $(LIBDRM_LIBS)
>> +endif
>
> Nit: Is the conditional necessary here? LIBDRM_LIBS would be empty if
> libdrm wasn't found, right? So no harm in just appending it to the
> GALLIUM_COMMON_LIB_DEPS variable unconditonally?
>

Done.

>>  GALLIUM_WINSYS_CFLAGS = \
>>       -I$(top_srcdir)/src \
>>       -I$(top_srcdir)/include \
>> diff --git a/src/gallium/auxiliary/Makefile.am b/src/gallium/auxiliary/Makefile.am
>> index 4a4a4fb..6b63cf1 100644
>> --- a/src/gallium/auxiliary/Makefile.am
>> +++ b/src/gallium/auxiliary/Makefile.am
>> @@ -20,6 +20,16 @@ libgallium_la_SOURCES = \
>>       $(NIR_SOURCES) \
>>       $(GENERATED_SOURCES)
>>
>> +if HAVE_LIBDRM
>> +
>> +AM_CFLAGS += \
>> +     $(LIBDRM_CFLAGS)
>
> Same here.

I just redone what other have done in that file. There are some if's
in that file and I am unsure
what to do here.

>
>> diff --git a/src/gallium/auxiliary/Makefile.sources b/src/gallium/auxiliary/Makefile.sources
>> index 5d4fe30..8d3e4a9 100644
>> --- a/src/gallium/auxiliary/Makefile.sources
>> +++ b/src/gallium/auxiliary/Makefile.sources
>> @@ -435,3 +435,7 @@ GALLIVM_SOURCES := \
>>       draw/draw_llvm_sample.c \
>>       draw/draw_pt_fetch_shade_pipeline_llvm.c \
>>       draw/draw_vs_llvm.c
>> +
>> +RENDERONLY_SOURCES := \
>> +     renderonly/renderonly.c \
>> +     renderonly/renderonly.h
>> diff --git a/src/gallium/auxiliary/renderonly/renderonly.c b/src/gallium/auxiliary/renderonly/renderonly.c
>> new file mode 100644
>> index 0000000..c4ea784
>> --- /dev/null
>> +++ b/src/gallium/auxiliary/renderonly/renderonly.c
>> @@ -0,0 +1,199 @@
>> +/*
>> + * Copyright (C) 2016 Christian Gmeiner <christian.gmeiner at gmail.com>
>> + *
>> + * 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, sublicense,
>> + * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
>> + * THE AUTHORS OR COPYRIGHT HOLDERS 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.
>> + *
>> + * Authors:
>> + *    Christian Gmeiner <christian.gmeiner at gmail.com>
>> + */
>> +
>> +#include "renderonly/renderonly.h"
>
> This include is oddly placed. Should it not go below all other includes?
>

I think thats a matter of style but I can puit it above #include
"state_tracker/drm_driver.h"

>> +
>> +#include <errno.h>
>> +#include <fcntl.h>
>> +#include <stdio.h>
>> +#include <sys/ioctl.h>
>> +#include <xf86drm.h>
>> +
>> +#include "state_tracker/drm_driver.h"
>> +#include "pipe/p_screen.h"
>> +#include "util/u_memory.h"
>> +
>> +struct pipe_screen *
>> +renderonly_screen_create(int fd, const struct renderonly_ops *ops, void *priv)
>
> This is slightly nit-picky, but I found it confusing when first reading
> through the patches: I know this started out as an effort to support the
> various render-only devices out there, but what you're creating here is
> really an abstraction for the scanout engine. Reading renderonly_* the
> first thing I think of is that this creates a render-only device, where
> in fact is creates the scanout engine.
>
> Perhaps renaming this to struct scanout, struct scanout_engine or any
> other number of possibilities would remove that confusion.
>

In my current version I have only one struct left:

struct renderonly {
   int (*tiling)(int fd, uint32_t handle); /**< for !intermediate_rendering */
   bool intermediate_rendering;
   int kms_fd;
   int gpu_fd;
};

And here is how the only function in imx-drm winsys looks like:

struct pipe_screen *imx_drm_screen_create(int fd)
{
   struct renderonly ro = {
      .intermediate_rendering = true,
      .kms_fd = fd,
      .gpu_fd = open("/dev/dri/renderD128", O_RDWR | O_CLOEXEC)
   };

   if (ro.gpu_fd < 0)
      return NULL;

   struct pipe_screen *screen = etna_drm_screen_create_renderonly(&ro);
   if (!screen)
      close(ro.gpu_fd);

   return screen;
}

So everything got more explicit regarding file handles and the struct represents
the combination of the kms and a gpu device now. I am not sure if the rename
is still needed but if it is maybe something like renderonly_ctx would work.

>> +{
>> +   struct renderonly *ro;
>> +
>> +   ro = CALLOC_STRUCT(renderonly);
>> +   if (!ro)
>> +      return NULL;
>> +
>> +   ro->kms_fd = fd;
>
> The kms_ prefix seems rather redundant to me, given that struct
> renderonly represents the KMS device.
>

Was true for V1 but in V2 everything looks quite different.

>> +   ro->ops = ops;
>> +   ro->priv = priv;
>> +
>> +   ro->screen = ops->create(ro);
>
> It's somewhat odd that drivers need to jump through this hoop in order
> to create their screens. I think it would be easier if they just
> embedded the struct renderonly and initialized it in their create
> function.
>
> I think that's probably what Nicolai and Emil were saying as well.

Yeah.. with V2 everything feels much easier to understand and cleaner.

>
>> +   if (!ro->screen)
>> +      goto cleanup;
>> +
>> +   return ro->screen;
>> +
>> +cleanup:
>> +   FREE(ro);
>> +
>> +   return NULL;
>> +}
>> +
>> +static bool
>> +use_kms_bumb_buffer(struct renderonly_scanout *scanout,
>
> You probably meant "dumb" here. Somehow you managed to get it right in
> the variables, but the function name and the callsite consistently have
> the same typo. =)
>

Upps.. :)

>> +      struct pipe_resource *rsc, struct renderonly *ro)
>> +{
>> +   struct winsys_handle handle;
>> +   int prime_fd, err;
>> +   struct drm_mode_create_dumb create_dumb = {
>> +      .width = rsc->width0,
>> +      .height = rsc->height0,
>> +      .bpp = 32,
>
> This seems like maybe too strong an assumption. Or at the very least a
> waste of memory. What if somebody wanted to use 16- or 24-bit buffers?
>

Good point... have an answer for this later in the mail.

>> +static bool
>> +import_gpu_scanout(struct renderonly_scanout *scanout,
>> +      struct pipe_resource *rsc, struct renderonly *ro)
>> +{
>> +   struct pipe_screen *screen = ro->screen;
>> +   boolean status;
>> +   int fd, err;
>> +   struct winsys_handle handle = {
>> +      .type = DRM_API_HANDLE_TYPE_FD
>> +   };
>> +
>> +   status = screen->resource_get_handle(screen, NULL, rsc, &handle,
>> +         PIPE_HANDLE_USAGE_READ_WRITE);
>> +   if (!status)
>> +      return false;
>> +
>> +   scanout->stride = handle.stride;
>> +   fd = handle.handle;
>> +
>> +   err = drmPrimeFDToHandle(ro->kms_fd, fd, &scanout->handle);
>> +   close(fd);
>> +
>> +   if (err < 0) {
>> +      fprintf(stderr, "drmPrimeFDToHandle() failed: %s\n", strerror(errno));
>> +      return false;
>> +   }
>> +
>> +   if (ro->ops->tiling) {
>
> tiling is maybe not the best name for this, since arguable the scanout
> driver might want to do any number of other things while importing.
> Perhaps ->import() would be generic enough?
>

import() sounds fine to me but maybe we can drop it.

>> +      err = ro->ops->tiling(ro->kms_fd, scanout->handle);
>> +      if (err < 0) {
>> +         fprintf(stderr, "failed to set tiling parameters: %s\n", strerror(errno));
>> +         close(scanout->handle);
>
> I don't think scanout->handle is something you should be passing to
> close().
>

Yeah.. looks you are right.. fill fix that in V2.

>> +         return false;
>> +      }
>> +   }
>> +
>> +   return true;
>> +}
>> +
>> +struct renderonly_scanout *
>> +renderonly_scanout_for_resource(struct pipe_resource *rsc, struct renderonly *ro)
>> +{
>> +   struct renderonly_scanout *scanout;
>> +   bool ret;
>> +
>> +   scanout = CALLOC_STRUCT(renderonly_scanout);
>> +   if (!scanout)
>> +      return NULL;
>> +
>> +   if (ro->ops->intermediate_rendering)
>> +       ret = use_kms_bumb_buffer(scanout, rsc, ro);
>> +   else
>> +       ret = import_gpu_scanout(scanout, rsc, ro);
>
> Given my kernel background I've grown allergic to this kind of
> construct. What you're creating here is a midlayer that's very likely to
> cause headaches down the road. I think a better alternative would be to
> add a callback to the struct renderonly_ops that drivers have to set to
> whatever the implementation is that they want.

This is a very good point and I thought about it some days ago.

> If you want to provide standard helpers, that's fine. Turn both the
> use_kms_bumb_buffer() and import_gpu_scanout() functions into public
> functions that drivers can reference. Then drivers can simply assign
> them to the new operation, or implement their own if they find that the
> defaults aren't flexible enough.
>

So the struct renderonly could look like:

struct renderonly {
   struct renderonly_scanout *(*create_for_resource)(struct pipe_resource *rsc);
   int kms_fd;
   int gpu_fd;
};

Now the kms winsys part can define what needs to be done in a generic way. I
am not sure if it would make lot of sense to provide a use_kms_bumb_buffer()
or import_gpu_scanout() public functions at all as every driver may need a small
variation if them. This also solves the 16 vs. 24 vs 32 bit buffer
problem by pushing
it directly to the kms winsys part - nice!

> On of the problem, the most immediate in this case, with this kind of
> midlayer is that if intermediate_rendering == {false,true} is not enough
> for a given use-case, we end up having to add yet another flag that
> specifies behaviour.
>

Thanks for your review!

greets
--
Christian Gmeiner, MSc

https://soundcloud.com/christian-gmeiner


More information about the mesa-dev mailing list