OSDN Git Service

tegra: Support tiled buffers
authorLauri Peltonen <lpeltonen@nvidia.com>
Thu, 18 Dec 2014 07:01:37 +0000 (23:01 -0800)
committerStéphane Marchesin <marcheu@chromium.org>
Mon, 12 Jan 2015 20:07:24 +0000 (20:07 +0000)
If GBM_BO_USE_RENDERING flag is passed, allocate tiled buffers.  Add logic
to the Tegra backend to compute tiled buffer dimensions and tiling
parameters (kind and block height).

The tiling parameters must somehow be passed to EGL at EGLImage creation.
The long term plan is to introduce an extensible structure that can contain
arbitrary vendor specific metadata.  For now, we abuse the PITCH attribute
to pass tiling parameters.

Add a new GBM utility function gbm_bo_get_stride_or_tiling, which returns
either the tiling parameters or byte pitch, depending whether the buffer
is tiled or not.

The Nvidia term for our tiled layout is "blocklinear".

BUG=None
TEST=null_platform_test on Tegra

Change-Id: I4e0226efa401b08f7e4a009a7f74b3453c622a10
Signed-off-by: Lauri Peltonen <lpeltonen@nvidia.com>
Reviewed-on: https://chromium-review.googlesource.com/236663
Reviewed-by: Stéphane Marchesin <marcheu@chromium.org>
Commit-Queue: Stéphane Marchesin <marcheu@chromium.org>
Tested-by: Stéphane Marchesin <marcheu@chromium.org>
gbm.c
gbm.h
gbm_priv.h
tegra.c

diff --git a/gbm.c b/gbm.c
index 483dfcf..b9f08f2 100644 (file)
--- a/gbm.c
+++ b/gbm.c
@@ -244,6 +244,12 @@ gbm_bo_get_stride(struct gbm_bo *bo)
 }
 
 PUBLIC uint32_t
+gbm_bo_get_stride_or_tiling(struct gbm_bo *bo)
+{
+       return bo->tiling ? bo->tiling : bo->stride;
+}
+
+PUBLIC uint32_t
 gbm_bo_get_format(struct gbm_bo *bo)
 {
        return bo->format;
diff --git a/gbm.h b/gbm.h
index 374cef8..094d746 100644 (file)
--- a/gbm.h
+++ b/gbm.h
@@ -257,6 +257,10 @@ gbm_bo_get_height(struct gbm_bo *bo);
 uint32_t
 gbm_bo_get_stride(struct gbm_bo *bo);
 
+/* Tegra bringup hack to pass tiling parameters at EGLImage creation. */
+uint32_t
+gbm_bo_get_stride_or_tiling(struct gbm_bo *bo);
+
 uint32_t
 gbm_bo_get_format(struct gbm_bo *bo);
 
index 1cda331..0e42934 100644 (file)
@@ -31,6 +31,7 @@ struct gbm_bo
        uint32_t size;
        uint32_t stride;
        uint32_t format;
+       uint32_t tiling;
        union gbm_bo_handle handle;
        void *priv;
        void *user_data;
diff --git a/tegra.c b/tegra.c
index 0463ca7..84ee537 100644 (file)
--- a/tegra.c
+++ b/tegra.c
 #include "gbm_priv.h"
 #include "helpers.h"
 
-int gbm_tegra_bo_create(struct gbm_bo *bo, uint32_t width, uint32_t height, uint32_t format, uint32_t flags)
+/*
+ * GOB (Group Of Bytes) is the basic unit of the blocklinear layout.
+ * GOBs are arranged to blocks, where the height of the block (measured
+ * in GOBs) is configurable.
+ */
+#define NV_BLOCKLINEAR_GOB_HEIGHT 8
+#define NV_BLOCKLINEAR_GOB_WIDTH 64
+#define NV_DEFAULT_BLOCK_HEIGHT_LOG2 4
+#define NV_PREFERRED_PAGE_SIZE (128 * 1024)
+
+enum nv_mem_kind
+{
+       NV_MEM_KIND_PITCH = 0,
+       NV_MEM_KIND_GENERIC_16Bx2 = 0xfe,
+};
+
+static int compute_block_height_log2(int height)
+{
+       int block_height_log2 = NV_DEFAULT_BLOCK_HEIGHT_LOG2;
+
+       if (block_height_log2 > 0) {
+               /* Shrink, if a smaller block height could cover the whole
+                * surface height. */
+               int proposed = NV_BLOCKLINEAR_GOB_HEIGHT << (block_height_log2 - 1);
+               while (proposed >= height) {
+                       block_height_log2--;
+                       if (block_height_log2 == 0)
+                               break;
+                       proposed /= 2;
+               }
+       }
+       return block_height_log2;
+}
+
+static inline uint32_t align_up(uint32_t value, uint32_t alignment)
+{
+       return (value + (alignment-1)) & ~(alignment-1);
+}
+
+static void compute_layout_blocklinear(int width, int height, int format,
+                                      enum nv_mem_kind *kind, uint32_t *block_height_log2,
+                                      uint32_t *stride, uint32_t *size)
+{
+       int pitch = width * gbm_bytes_from_format(format);
+
+       /* Align to blocklinear blocks. */
+       pitch = align_up(pitch, NV_BLOCKLINEAR_GOB_WIDTH);
+
+       /* Compute padded height. */
+       *block_height_log2 = compute_block_height_log2(height);
+       int block_height = 1 << *block_height_log2;
+       int padded_height = align_up(height, NV_BLOCKLINEAR_GOB_HEIGHT * block_height);
+
+       int bytes = pitch * padded_height;
+
+       /* Pad the allocation to the preferred page size.
+        * This will reduce the required page table size (see discussion in NV
+        * bug 1321091), and also acts as a WAR for NV bug 1325421.
+        */
+       bytes = align_up(bytes, NV_PREFERRED_PAGE_SIZE);
+
+       *kind = NV_MEM_KIND_GENERIC_16Bx2;
+       *stride = pitch;
+       *size = bytes;
+}
+
+static void compute_layout_linear(int width, int height, int format,
+                                 uint32_t *stride, uint32_t *size)
+{
+       *stride = width * gbm_bytes_from_format(format);
+       *size = *stride * height;
+}
+
+static int gbm_tegra_bo_create(struct gbm_bo *bo, uint32_t width, uint32_t height,
+                              uint32_t format, uint32_t flags)
 {
-       size_t size = width * height * gbm_bytes_from_format(format);
+       uint32_t size, stride, block_height_log2 = 0;
+       enum nv_mem_kind kind = NV_MEM_KIND_PITCH;
        struct drm_tegra_gem_create gem_create;
        int ret;
 
+       if (flags & GBM_BO_USE_RENDERING)
+               compute_layout_blocklinear(width, height, format, &kind,
+                                          &block_height_log2, &stride, &size);
+       else
+               compute_layout_linear(width, height, format, &stride, &size);
+
        memset(&gem_create, 0, sizeof(gem_create));
        gem_create.size = size;
        gem_create.flags = 0;
@@ -29,7 +110,37 @@ int gbm_tegra_bo_create(struct gbm_bo *bo, uint32_t width, uint32_t height, uint
 
        bo->handle.u32 = gem_create.handle;
        bo->size = size;
-       bo->stride = width * gbm_bytes_from_format(format);
+       bo->stride = stride;
+
+       if (kind != NV_MEM_KIND_PITCH) {
+               struct drm_tegra_gem_set_tiling gem_tile;
+
+               memset(&gem_tile, 0, sizeof(gem_tile));
+               gem_tile.handle = bo->handle.u32;
+               gem_tile.mode = DRM_TEGRA_GEM_TILING_MODE_BLOCK;
+               gem_tile.value = block_height_log2;
+
+               ret = drmCommandWriteRead(bo->gbm->fd, DRM_TEGRA_GEM_SET_TILING, &gem_tile,
+                                         sizeof(gem_tile));
+               if (ret < 0) {
+                       gbm_gem_bo_destroy(bo);
+                       return ret;
+               }
+
+               /* Encode blocklinear parameters for EGLImage creation. */
+
+               /* XXX Bringup hack: If the highest order bit is set in
+                * EGL_DMA_BUF_PLANE0_PITCH_EXT, Nvidia driver treats it as
+                * a hint that the buffer is tiled, and the remaining bits in
+                * the pitch attribute are treated as vendor specific tiling
+                * arguments.  Using this hack means that we don't need to add
+                * a new FOURCC format, or EGL_DMA_BUF_PLANE0_TILING_EXT
+                * attribute to the dma-buf import extension.
+                */
+               bo->tiling = (1 << 31) |
+                            (kind & 0xff) |
+                            ((block_height_log2 & 0xf) << 8);
+       }
 
        return 0;
 }
@@ -40,8 +151,12 @@ struct gbm_driver gbm_driver_tegra =
        .bo_create = gbm_tegra_bo_create,
        .bo_destroy = gbm_gem_bo_destroy,
        .format_list = {
-               {GBM_FORMAT_XRGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_CURSOR | GBM_BO_USE_RENDERING | GBM_BO_USE_WRITE},
-               {GBM_FORMAT_ARGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_CURSOR | GBM_BO_USE_RENDERING | GBM_BO_USE_WRITE},
+               /* Linear support */
+               {GBM_FORMAT_XRGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE},
+               {GBM_FORMAT_ARGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE},
+               /* Blocklinear support */
+               {GBM_FORMAT_XRGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING},
+               {GBM_FORMAT_ARGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING},
        }
 };