freedreno: core buffer modifier support
authorRob Clark <robdclark@gmail.com>
Mon, 21 Jan 2019 15:50:13 +0000 (10:50 -0500)
committerRob Clark <robdclark@gmail.com>
Tue, 22 Jan 2019 21:33:27 +0000 (16:33 -0500)
Split out of a patch from Fritz Koenig to decouple from a6xx UBWC
enablement, and added fd_resource_create_with_modifiers().

src/gallium/drivers/freedreno/freedreno_resource.c
src/gallium/drivers/freedreno/freedreno_screen.h

index 14751074aceeab25837123c487238c559193822f..ccd4f7f118d31bd99091a8f655d5f3413cfa3bcd 100644 (file)
@@ -43,6 +43,7 @@
 #include "freedreno_query_hw.h"
 #include "freedreno_util.h"
 
+#include <drm_fourcc.h>
 #include <errno.h>
 
 /* XXX this should go away, needed for 'struct winsys_handle' */
@@ -810,12 +811,26 @@ has_depth(enum pipe_format format)
        }
 }
 
+static bool
+find_modifier(uint64_t needle, const uint64_t *haystack, int count)
+{
+       int i;
+
+       for (i = 0; i < count; i++) {
+               if (haystack[i] == needle)
+                       return true;
+       }
+
+       return false;
+}
+
 /**
  * Create a new texture object, using the given template info.
  */
 static struct pipe_resource *
-fd_resource_create(struct pipe_screen *pscreen,
-               const struct pipe_resource *tmpl)
+fd_resource_create_with_modifiers(struct pipe_screen *pscreen,
+               const struct pipe_resource *tmpl,
+               const uint64_t *modifiers, int count)
 {
        struct fd_screen *screen = fd_screen(pscreen);
        struct fd_resource *rsc = CALLOC_STRUCT(fd_resource);
@@ -840,10 +855,25 @@ fd_resource_create(struct pipe_screen *pscreen,
         PIPE_BIND_LINEAR  | \
         PIPE_BIND_DISPLAY_TARGET)
 
+       bool linear = find_modifier(DRM_FORMAT_MOD_LINEAR, modifiers, count);
+       if (tmpl->bind & LINEAR)
+               linear = true;
+
+       /* Normally, for non-shared buffers, allow buffer compression if
+        * not shared, otherwise only allow if QCOM_COMPRESSED modifier
+        * is requested:
+        *
+        * TODO we should probably also limit tiled in a similar way,
+        * except we don't have a format modifier for tiled.  (We probably
+        * should.)
+        */
+       bool allow_ubwc = find_modifier(DRM_FORMAT_MOD_INVALID, modifiers, count);
+       if (tmpl->bind & PIPE_BIND_SHARED)
+               allow_ubwc = find_modifier(DRM_FORMAT_MOD_QCOM_COMPRESSED, modifiers, count);
+
        if (screen->tile_mode &&
                        (tmpl->target != PIPE_BUFFER) &&
-                       (tmpl->bind & PIPE_BIND_SAMPLER_VIEW) &&
-                       !(tmpl->bind & LINEAR)) {
+                       !linear) {
                rsc->tile_mode = screen->tile_mode(tmpl);
        }
 
@@ -888,6 +918,9 @@ fd_resource_create(struct pipe_screen *pscreen,
 
        size = screen->setup_slices(rsc);
 
+       if (allow_ubwc && screen->fill_ubwc_buffer_sizes && rsc->tile_mode)
+               size += screen->fill_ubwc_buffer_sizes(rsc);
+
        /* special case for hw-query buffer, which we need to allocate before we
         * know the size:
         */
@@ -912,6 +945,34 @@ fail:
        return NULL;
 }
 
+static struct pipe_resource *
+fd_resource_create(struct pipe_screen *pscreen,
+               const struct pipe_resource *tmpl)
+{
+       const uint64_t mod = DRM_FORMAT_MOD_INVALID;
+       return fd_resource_create_with_modifiers(pscreen, tmpl, &mod, 1);
+}
+
+static bool
+is_supported_modifier(struct pipe_screen *pscreen, enum pipe_format pfmt,
+               uint64_t mod)
+{
+       int count;
+
+       /* Get the count of supported modifiers: */
+       pscreen->query_dmabuf_modifiers(pscreen, pfmt, 0, NULL, NULL, &count);
+
+       /* Get the supported modifiers: */
+       uint64_t modifiers[count];
+       pscreen->query_dmabuf_modifiers(pscreen, pfmt, 0, modifiers, NULL, &count);
+
+       for (int i = 0; i < count; i++)
+               if (modifiers[i] == mod)
+                       return true;
+
+       return false;
+}
+
 /**
  * Create a texture from a winsys_handle. The handle is often created in
  * another process by first creating a pipe texture and then calling
@@ -922,6 +983,7 @@ fd_resource_from_handle(struct pipe_screen *pscreen,
                const struct pipe_resource *tmpl,
                struct winsys_handle *handle, unsigned usage)
 {
+       struct fd_screen *screen = fd_screen(pscreen);
        struct fd_resource *rsc = CALLOC_STRUCT(fd_resource);
        struct fd_resource_slice *slice = &rsc->slices[0];
        struct pipe_resource *prsc = &rsc->base;
@@ -960,6 +1022,19 @@ fd_resource_from_handle(struct pipe_screen *pscreen,
                        (slice->pitch & (pitchalign - 1)))
                goto fail;
 
+       if (handle->modifier == DRM_FORMAT_MOD_QCOM_COMPRESSED) {
+               if (!is_supported_modifier(pscreen, tmpl->format,
+                               DRM_FORMAT_MOD_QCOM_COMPRESSED)) {
+                       DBG("bad modifier: %lx", handle->modifier);
+                       goto fail;
+               }
+               debug_assert(screen->fill_ubwc_buffer_sizes);
+               screen->fill_ubwc_buffer_sizes(rsc);
+       } else if (handle->modifier &&
+                       (handle->modifier != DRM_FORMAT_MOD_INVALID)) {
+               goto fail;
+       }
+
        assert(rsc->cpp);
 
        return prsc;
@@ -1131,6 +1206,10 @@ fd_resource_screen_init(struct pipe_screen *pscreen)
        bool fake_rgtc = screen->gpu_id < 400;
 
        pscreen->resource_create = u_transfer_helper_resource_create;
+       /* NOTE: u_transfer_helper does not yet support the _with_modifiers()
+        * variant:
+        */
+       pscreen->resource_create_with_modifiers = fd_resource_create_with_modifiers;
        pscreen->resource_from_handle = fd_resource_from_handle;
        pscreen->resource_get_handle = fd_resource_get_handle;
        pscreen->resource_destroy = u_transfer_helper_resource_destroy;
index 243770ffd900ef13306d565e0311f92e25686fc0..1060f4609f6862bf54720ac7a405ccceda1a5e5d 100644 (file)
@@ -87,6 +87,7 @@ struct fd_screen {
         */
        struct fd_pipe *pipe;
 
+       uint32_t (*fill_ubwc_buffer_sizes)(struct fd_resource *rsc);
        uint32_t (*setup_slices)(struct fd_resource *rsc);
        unsigned (*tile_mode)(const struct pipe_resource *prsc);