[PATCH v2 libdrm 4/7] tegra: Add channel, job, pushbuf and fence APIs

Erik Faye-Lund kusmabite at gmail.com
Thu Apr 10 10:13:22 PDT 2014


On Wed, Apr 9, 2014 at 1:40 PM, Thierry Reding <thierry.reding at gmail.com> wrote:
> diff --git a/tegra/fence.c b/tegra/fence.c
> new file mode 100644
> index 000000000000..f58725ca8472
> --- /dev/null
> +++ b/tegra/fence.c
> +drm_public
> +int drm_tegra_fence_wait(struct drm_tegra_fence *fence)
> +{
> +       return drm_tegra_fence_wait_timeout(fence, -1);
> +}

Perhaps a convenience-wrapper like this should be inline in the header
to reduce function-call overhead?

> +drm_public
> +int drm_tegra_job_submit(struct drm_tegra_job *job,
> +                        struct drm_tegra_fence **fencep)
> +{
> +       struct drm_tegra *drm = job->channel->drm;
> +       struct drm_tegra_pushbuf_private *pushbuf;
> +       struct drm_tegra_fence *fence = NULL;
> +       struct drm_tegra_cmdbuf *cmdbufs;
> +       struct drm_tegra_syncpt *syncpts;
> +       struct drm_tegra_submit args;
> +       unsigned int i;
> +       int err;
> +
> +       /*
> +        * Make sure the current command stream buffer is queued for
> +        * submission.
> +        */
> +       err = drm_tegra_pushbuf_queue(job->pushbuf);
> +       if (err < 0)
> +               return err;
> +
> +       job->pushbuf = NULL;
> +
> +       if (fencep) {
> +               fence = calloc(1, sizeof(*fence));
> +               if (!fence)
> +                       return -ENOMEM;
> +       }
> +
> +       syncpts = calloc(1, sizeof(*syncpts));
> +       if (!syncpts) {
> +               free(cmdbufs);

cmdbufs never gets assigned to, yet it gets free'd here (and a few
more places further down). I guess this is left-overs from the
previous round that should just die?

But this raises the question, how is job->cmdbufs (and job->relocs)
supposed to get free'd?

I'm a bit curious as to what the expected life-time of these objects
are. Do I need to create a new job-object for each submit, or can I
reuse a job? I think the latter would be preferable... So perhaps we
should have a drm_tegra_job_reset that allows us to throw away the
accumulated cmdbufs and relocs, and start building a new job?

> diff --git a/tegra/private.h b/tegra/private.h
> index 9b6bc9395d23..fc74fb56b58d 100644
> --- a/tegra/private.h
> +++ b/tegra/private.h
> @@ -26,13 +26,31 @@
>  #define __DRM_TEGRA_PRIVATE_H__ 1
>
>  #include <stdbool.h>
> +#include <stddef.h>
>  #include <stdint.h>
>
>  #include <libdrm.h>
> +#include <libdrm_lists.h>
>  #include <xf86atomic.h>
>
> +#include "tegra_drm.h"
>  #include "tegra.h"
>
> +#define container_of(ptr, type, member) ({                             \
> +               const typeof(((type *)0)->member) *__mptr = (ptr);      \
> +               (type *)((char *)__mptr - offsetof(type, member));      \
> +       })
> +
<snip>
> +
> +struct drm_tegra_pushbuf_private {
> +       struct drm_tegra_pushbuf base;
> +       struct drm_tegra_job *job;
> +       drmMMListHead list;
> +       drmMMListHead bos;
> +
> +       struct drm_tegra_bo *bo;
> +       uint32_t *start;
> +       uint32_t *end;
> +};
> +
> +static inline struct drm_tegra_pushbuf_private *
> +pushbuf_priv(struct drm_tegra_pushbuf *pb)
> +{
> +       return container_of(pb, struct drm_tegra_pushbuf_private, base);
> +}
> +

This seems to be the only use-case for container_of, and it just
happens to return the exact same pointer as was passed in... so do we
really need that helper?

> diff --git a/tegra/pushbuf.c b/tegra/pushbuf.c
> new file mode 100644
> index 000000000000..178d5cd57541
> --- /dev/null
> +++ b/tegra/pushbuf.c
> @@ -0,0 +1,205 @@
<snip>
> +drm_public
> +int drm_tegra_pushbuf_new(struct drm_tegra_pushbuf **pushbufp,
> +                         struct drm_tegra_job *job)
> +{
> +       struct drm_tegra_pushbuf_private *pushbuf;
> +       void *ptr;
> +       int err;
> +
> +       pushbuf = calloc(1, sizeof(*pushbuf));
> +       if (!pushbuf)
> +               return -ENOMEM;
> +
> +       DRMINITLISTHEAD(&pushbuf->list);
> +       DRMINITLISTHEAD(&pushbuf->bos);
> +       pushbuf->job = job;
> +
> +       *pushbufp = &pushbuf->base;
> +
> +       DRMLISTADD(&pushbuf->list, &job->pushbufs);

Hmm. So the job keeps a list of pushbufs. What purpose does this
serve? Shouldn't the job only need the cmdbuf-list (which it already
has) and the BOs (so they can be dereferenced after being submitted)?

AFAICT, we could make drm_tegra_pushbuf_queue append the BO to a list
in the job instead. That way we don't need to keep all the
pushbuf-objects around, and we might even be able to reuse the same
object rather than keep reallocating them. No?

> +drm_public
> +int drm_tegra_pushbuf_sync(struct drm_tegra_pushbuf *pushbuf,
> +                          enum drm_tegra_syncpt_cond cond)
> +{
> +       struct drm_tegra_pushbuf_private *priv = pushbuf_priv(pushbuf);
> +
> +       if (cond >= DRM_TEGRA_SYNCPT_COND_MAX)
> +               return -EINVAL;
> +
> +       *pushbuf->ptr++ = HOST1X_OPCODE_NONINCR(0x0, 0x1);
> +       *pushbuf->ptr++ = cond << 8 | priv->job->syncpt;

Perhaps "HOST1X_OPCODE_IMM(0x0, cond << 8 | priv->job->syncpt)", which
saves a word?

Either way, I think this should either call drm_tegra_pushbuf_prepare
to make sure two words are available, or be renamed to reflect that it
causes a push (or two, as in the current form).

> +struct drm_tegra_channel;
> +struct drm_tegra_job;
> +
> +struct drm_tegra_pushbuf {
> +       uint32_t *ptr;
> +};

Hmm, single-member structs always makes me cringe a bit. But in this
case it's much better than a double-pointer IMO.

But perhaps some of the members in the private-struct might be useful
out here? For instance, if "uint32_t *end;" was also available, we
could do:

inline void drm_tegra_pushbuf_push_word(struct drm_tegra_pushbuf
*pushbuf, uint32_t value)
{
       assert(pushbuf->ptr < pushbuf->end);
       *pushbuf->ptr++ = value;
}

...and easily pick up bugs with too few words? The helper would of
course be in the header-file, so the write gets inlined nicely.

But all in all, a really nice read. Thanks!


More information about the dri-devel mailing list