summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Jones <jajones@nvidia.com>2019-09-12 23:00:03 -0700
committerThierry Reding <treding@nvidia.com>2019-12-04 12:00:11 +0100
commit78486627f673ed00feffbff11847516533507d22 (patch)
tree403d73669378336a9ad200a53b89c0262a150e00
parent0f782934ad9f1e327b17d0ee944d1e9160980dc7 (diff)
nouveau: Improve framebuffer modifier supportgv11b
The nvc0 subsystem of the nouveau driver previously contained sufficient format modifier support to report the format modifiers supported on a given chipset and the format modifier used by a given image/texture. However, when importing a dma-buf object as an EGLImage, the format modifier specified was ignored unless it was DRM_FORMAT_MOD_LINEAR. Since the nouveau kernel driver lacked any support for format modifiers, this effectively limited the useage to exporting block linear buffers on a Tegra GPU and importing them as framebuffers with the Tegra DRM kernel driver. This change fleshes out the existing support and switches to the more descriptive DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D() format modifier macro to export support for specific page kinds, including compressed surfaces. This allows differentiating between surfaces compatible with Tegra GPUs and desktop GPUs, improved performance when using the compressed layouts, and differentiating between formats supported by nvc0- class hardware and other GPU families which use slightly different variations of the block linear buffer layout. Note this change does not add support for format modifiers to the NV5x driver backend, nor does it attempt to add modifier support for Turing- class hardware. The code would be very similar, but each would use a slightly different set of format modifiers than those exposed here. XXX Need to disable compressed modifiers (0xdb page kind) for 32-bit color buffers on Fermi? XXX Test on Fermi hardware. XXX Test on Tegra TK1-TX2 class hardware with Tegra DRM. Signed-off-by: Thierry Reding <treding@nvidia.com>
-rw-r--r--src/gallium/drivers/nouveau/nvc0/nvc0_miptree.c184
-rw-r--r--src/gallium/drivers/nouveau/nvc0/nvc0_resource.c87
-rw-r--r--src/gallium/state_trackers/dri/dri2.c24
3 files changed, 232 insertions, 63 deletions
diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_miptree.c b/src/gallium/drivers/nouveau/nvc0/nvc0_miptree.c
index c897e4e8b97..5c7402dcd40 100644
--- a/src/gallium/drivers/nouveau/nvc0/nvc0_miptree.c
+++ b/src/gallium/drivers/nouveau/nvc0/nvc0_miptree.c
@@ -1,5 +1,6 @@
/*
* Copyright 2008 Ben Skeggs
+ * Copyright (c) 2019 NVIDIA Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -38,16 +39,104 @@ nvc0_tex_choose_tile_dims(unsigned nx, unsigned ny, unsigned nz, bool is_3d)
}
static uint32_t
-nvc0_mt_choose_storage_type(struct nv50_miptree *mt, bool compressed)
+nvc0_tile_mode_from_modifier_helper(uint64_t modifier)
+{
+ assert(modifier != DRM_FORMAT_MOD_INVALID);
+ assert(modifier != DRM_FORMAT_MOD_LINEAR);
+
+ /* Bits 3:0 of the 2D block linear format modifiers are log2(tile height) */
+ return ((uint32_t)modifier & 0xf) << 4;
+}
+
+static uint32_t
+nvc0_storage_type_from_modifier_helper(uint64_t modifier)
+{
+ uint32_t storage_type;
+
+ assert(modifier != DRM_FORMAT_MOD_INVALID);
+ assert(modifier != DRM_FORMAT_MOD_LINEAR);
+
+ /* Bits 19:12 of the 2D block linear format modifiers are the page kind */
+ storage_type = (uint32_t)(modifier >> 12) & 0xff;
+
+ /* There is no need to support legacy format modifiers (Defined before the
+ * page kind field) here, because there was no prior code in Mesa that
+ * supported importing these memory types. However, if there is a desire
+ * to support importing buffers with these modifiers on older kernels that
+ * may report them from TegraDRM, uncomment these lines to substitute the
+ * default page kind for 0, which is reserved for linear tiling.
+ *
+ * if (!storage_type)
+ * storage_type = 0xfe;
+ */
+
+ return storage_type;
+}
+
+static bool
+nvc0_validate_modifier_helper(struct pipe_screen *pscreen,
+ uint64_t modifier,
+ bool compression_supported)
+{
+ uint32_t modLow = (uint32_t)modifier;
+ bool tegra_sector_layout = nouveau_screen(pscreen)->tegra_sector_layout;
+
+ /* Must be an NVIDIA modifier */
+ if ((uint32_t)(modifier >> 56) != DRM_FORMAT_MOD_VENDOR_NVIDIA)
+ return false;
+ /* Must be a block-linear modifier */
+ if (!(modLow & 0x10))
+ return false;
+ /* Reserved/unused fields must all be 0 */
+ if (modifier & 0x00fffffffe000fe0llu)
+ return false;
+ /* block height must be <= 32 */
+ if ((modLow & 0xf) > 5)
+ return false;
+ /* Only generic and 32-bit compressed color page kinds supported right now */
+ switch ((modLow >> 12) & 0xff) {
+ case 0xfe:
+ break;
+ case 0xdb:
+ if (compression_supported)
+ break;
+ else
+ return false;
+ default:
+ return false;
+ }
+ /* Tesla and Turing Gob Height/Page Kinds not supported */
+ if (((modLow >> 20) & 3) != 0)
+ return false;
+ /* Verify sector layout matches GPU */
+ if (!((modLow >> 22) & 1) != tegra_sector_layout)
+ return false;
+ /* CDE compression not supported */
+ if (((modLow >> 23) & 3) & 2)
+ return false;
+
+ return true;
+}
+
+static uint32_t
+nvc0_mt_choose_storage_type(struct nv50_miptree *mt,
+ uint64_t modifier,
+ bool compressed)
{
const unsigned ms = util_logbase2(mt->base.base.nr_samples);
uint32_t tile_flags;
+ if (modifier != DRM_FORMAT_MOD_INVALID &&
+ modifier != DRM_FORMAT_MOD_LINEAR)
+ return nvc0_storage_type_from_modifier_helper(modifier);
+
if (unlikely(mt->base.base.bind & PIPE_BIND_CURSOR))
return 0;
if (unlikely(mt->base.base.flags & NOUVEAU_RESOURCE_FLAG_LINEAR))
return 0;
+ if (unlikely(modifier == DRM_FORMAT_MOD_LINEAR))
+ return 0;
switch (mt->base.base.format) {
case PIPE_FORMAT_Z16_UNORM:
@@ -188,11 +277,13 @@ nvc0_miptree_init_layout_video(struct nv50_miptree *mt)
}
static void
-nvc0_miptree_init_layout_tiled(struct nv50_miptree *mt)
+nvc0_miptree_init_layout_tiled(struct nv50_miptree *mt, uint64_t modifier)
{
struct pipe_resource *pt = &mt->base.base;
unsigned w, h, d, l;
const unsigned blocksize = util_format_get_blocksize(pt->format);
+ bool use_modifier = modifier != DRM_FORMAT_MOD_INVALID && pt->depth0 <= 1;
+
mt->layout_3d = pt->target == PIPE_TEXTURE_3D;
@@ -214,7 +305,10 @@ nvc0_miptree_init_layout_tiled(struct nv50_miptree *mt)
lvl->offset = mt->total_size;
- lvl->tile_mode = nvc0_tex_choose_tile_dims(nbx, nby, d, mt->layout_3d);
+ if (l == 0 && use_modifier)
+ lvl->tile_mode = nvc0_tile_mode_from_modifier_helper(modifier);
+ else
+ lvl->tile_mode = nvc0_tex_choose_tile_dims(nbx, nby, d, mt->layout_3d);
tsx = NVC0_TILE_SIZE_X(lvl->tile_mode); /* x is tile row pitch in bytes */
tsy = NVC0_TILE_SIZE_Y(lvl->tile_mode);
@@ -236,8 +330,10 @@ nvc0_miptree_init_layout_tiled(struct nv50_miptree *mt)
}
}
-static uint64_t nvc0_miptree_get_modifier(struct nv50_miptree *mt)
+static uint64_t nvc0_miptree_get_modifier(struct pipe_screen *pscreen,
+ struct nv50_miptree *mt)
{
+ struct nouveau_screen *screen = nouveau_screen(pscreen);
union nouveau_bo_config *config = &mt->base.bo->config;
uint64_t modifier;
@@ -250,37 +346,14 @@ static uint64_t nvc0_miptree_get_modifier(struct nv50_miptree *mt)
break;
case 0xfe:
- switch (NVC0_TILE_MODE_Y(config->nvc0.tile_mode)) {
- case 0:
- modifier = DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_ONE_GOB;
- break;
-
- case 1:
- modifier = DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_TWO_GOB;
- break;
-
- case 2:
- modifier = DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_FOUR_GOB;
- break;
-
- case 3:
- modifier = DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_EIGHT_GOB;
- break;
-
- case 4:
- modifier = DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_SIXTEEN_GOB;
- break;
-
- case 5:
- modifier = DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_THIRTYTWO_GOB;
- break;
-
- default:
- modifier = DRM_FORMAT_MOD_INVALID;
- break;
- }
+ case 0xdb:
+ modifier = DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(
+ config->nvc0.memtype == 0xdb ? 1 : 0,
+ screen->tegra_sector_layout ? 0 : 1,
+ 0,
+ config->nvc0.memtype,
+ NVC0_TILE_MODE_Y(config->nvc0.tile_mode));
break;
-
default:
modifier = DRM_FORMAT_MOD_INVALID;
break;
@@ -301,7 +374,7 @@ nvc0_miptree_get_handle(struct pipe_screen *pscreen,
if (!ret)
return ret;
- whandle->modifier = nvc0_miptree_get_modifier(mt);
+ whandle->modifier = nvc0_miptree_get_modifier(pscreen, mt);
return true;
}
@@ -324,6 +397,10 @@ nvc0_miptree_create(struct pipe_screen *pscreen,
struct nouveau_drm *drm = nouveau_screen(pscreen)->drm;
struct nv50_miptree *mt = CALLOC_STRUCT(nv50_miptree);
struct pipe_resource *pt = &mt->base.base;
+ uint64_t modifier = DRM_FORMAT_MOD_INVALID;
+ uint64_t uncompressed_mod = DRM_FORMAT_MOD_INVALID;
+ unsigned int i;
+ bool linear_allowed = false;
bool compressed = drm->version >= 0x01000101;
int ret;
union nouveau_bo_config bo_config;
@@ -351,13 +428,41 @@ nvc0_miptree_create(struct pipe_screen *pscreen,
}
}
- if (count == 1 && modifiers[0] == DRM_FORMAT_MOD_LINEAR)
- pt->flags |= NOUVEAU_RESOURCE_FLAG_LINEAR;
+ for (i = 0; i < count; i++) {
+ if (modifiers[i] == DRM_FORMAT_MOD_LINEAR) {
+ linear_allowed = true;
+ /* Only use linear as a last resort */
+ continue;
+ }
+
+ if (nvc0_validate_modifier_helper(pscreen, modifiers[i], compressed)) {
+ /* Can not use block-linear layout with linear bindings */
+ if (pt->bind & PIPE_BIND_LINEAR)
+ continue;
+
+ /* Prefer modifiers with compression, but fall back to uncompressed */
+ if ((modifiers[i] >> 23) & 0x3) {
+ modifier = modifiers[i];
+ break;
+ } else {
+ uncompressed_mod = modifiers[i];
+ }
+ }
+ }
+
+ if (modifier == DRM_FORMAT_MOD_INVALID && count > 0) {
+ if (uncompressed_mod != DRM_FORMAT_MOD_INVALID)
+ modifier = uncompressed_mod;
+ else if (linear_allowed)
+ pt->flags |= NOUVEAU_RESOURCE_FLAG_LINEAR;
+ else
+ return NULL;
+ }
if (pt->bind & PIPE_BIND_LINEAR)
pt->flags |= NOUVEAU_RESOURCE_FLAG_LINEAR;
- bo_config.nvc0.memtype = nvc0_mt_choose_storage_type(mt, compressed);
+ bo_config.nvc0.memtype = nvc0_mt_choose_storage_type(mt, modifier, compressed);
if (!nvc0_miptree_init_ms_mode(mt)) {
FREE(mt);
@@ -366,9 +471,10 @@ nvc0_miptree_create(struct pipe_screen *pscreen,
if (unlikely(pt->flags & NVC0_RESOURCE_FLAG_VIDEO)) {
nvc0_miptree_init_layout_video(mt);
+ /* TODO: Validate modifier against video layout */
} else
if (likely(bo_config.nvc0.memtype)) {
- nvc0_miptree_init_layout_tiled(mt);
+ nvc0_miptree_init_layout_tiled(mt, modifier);
} else
if (!nv50_miptree_init_layout_linear(mt, 128)) {
FREE(mt);
diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_resource.c b/src/gallium/drivers/nouveau/nvc0/nvc0_resource.c
index d73ecf71624..b514ce3ae45 100644
--- a/src/gallium/drivers/nouveau/nvc0/nvc0_resource.c
+++ b/src/gallium/drivers/nouveau/nvc0/nvc0_resource.c
@@ -9,13 +9,11 @@ static struct pipe_resource *
nvc0_resource_create(struct pipe_screen *screen,
const struct pipe_resource *templ)
{
- const uint64_t modifier = DRM_FORMAT_MOD_INVALID;
-
switch (templ->target) {
case PIPE_BUFFER:
return nouveau_buffer_create(screen, templ);
default:
- return nvc0_miptree_create(screen, templ, &modifier, 1);
+ return nvc0_miptree_create(screen, templ, NULL, 0);
}
}
@@ -33,39 +31,80 @@ nvc0_resource_create_with_modifiers(struct pipe_screen *screen,
}
static void
-nvc0_query_dmabuf_modifiers(struct pipe_screen *screen,
+nvc0_query_dmabuf_modifiers(struct pipe_screen *pscreen,
enum pipe_format format, int max,
uint64_t *modifiers, unsigned int *external_only,
int *count)
{
- static const uint64_t supported_modifiers[] = {
- DRM_FORMAT_MOD_LINEAR,
- DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_ONE_GOB,
- DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_TWO_GOB,
- DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_FOUR_GOB,
- DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_EIGHT_GOB,
- DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_SIXTEEN_GOB,
- DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_THIRTYTWO_GOB,
+ static const uint64_t desktop_modifiers[] = {
+ DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(1, 1, 0, 0xdb, 0),
+ DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(1, 1, 0, 0xdb, 1),
+ DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(1, 1, 0, 0xdb, 2),
+ DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(1, 1, 0, 0xdb, 3),
+ DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(1, 1, 0, 0xdb, 4),
+ DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(1, 1, 0, 0xdb, 5),
+ DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 0, 0xfe, 0),
+ DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 0, 0xfe, 1),
+ DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 0, 0xfe, 2),
+ DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 0, 0xfe, 3),
+ DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 0, 0xfe, 4),
+ DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 0, 0xfe, 5),
+ };
+ static const uint64_t tegra_modifiers[] = {
+ DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(1, 0, 0, 0xdb, 0),
+ DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(1, 0, 0, 0xdb, 1),
+ DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(1, 0, 0, 0xdb, 2),
+ DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(1, 0, 0, 0xdb, 3),
+ DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(1, 0, 0, 0xdb, 4),
+ DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(1, 0, 0, 0xdb, 5),
+ DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 0, 0, 0xfe, 0),
+ DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 0, 0, 0xfe, 1),
+ DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 0, 0, 0xfe, 2),
+ DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 0, 0, 0xfe, 3),
+ DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 0, 0, 0xfe, 4),
+ DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 0, 0, 0xfe, 5),
};
- int i, num = 0;
+ struct nouveau_screen *screen = nouveau_screen(pscreen);
+ int i, num = 0, num_supported = 1; /* LINEAR is always supported */
- if (max > ARRAY_SIZE(supported_modifiers))
- max = ARRAY_SIZE(supported_modifiers);
+ if (screen->tegra_sector_layout)
+ num_supported += ARRAY_SIZE(tegra_modifiers);
+ else
+ num_supported += ARRAY_SIZE(desktop_modifiers);
if (!max) {
- max = ARRAY_SIZE(supported_modifiers);
- external_only = NULL;
- modifiers = NULL;
+ *count = num_supported;
+ return;
}
- for (i = 0; i < max; i++) {
- if (modifiers)
- modifiers[num] = supported_modifiers[i];
+ if (max > num_supported)
+ max = num_supported;
+
+ modifiers[num] = DRM_FORMAT_MOD_LINEAR;
+
+ if (external_only)
+ external_only[num] = 0;
+
+ num++;
+
+ if (screen->tegra_sector_layout) {
+ for (i = 0; i < ARRAY_SIZE(tegra_modifiers) && num < max; i++) {
+ modifiers[num] = tegra_modifiers[i];
+
+ if (external_only)
+ external_only[num] = 0;
+
+ num++;
+ }
+ } else {
+ for (i = 0; i < ARRAY_SIZE(desktop_modifiers) && num < max; i++) {
+ modifiers[num] = desktop_modifiers[i];
- if (external_only)
- external_only[num] = 0;
+ if (external_only)
+ external_only[num] = 0;
- num++;
+ num++;
+ }
}
*count = num;
diff --git a/src/gallium/state_trackers/dri/dri2.c b/src/gallium/state_trackers/dri/dri2.c
index d62cf89f737..cdb0d163219 100644
--- a/src/gallium/state_trackers/dri/dri2.c
+++ b/src/gallium/state_trackers/dri/dri2.c
@@ -867,6 +867,30 @@ dri2_get_modifier_num_planes(uint64_t modifier)
/* FD_FORMAT_MOD_QCOM_TILED is not in drm_fourcc.h */
case I915_FORMAT_MOD_X_TILED:
case I915_FORMAT_MOD_Y_TILED:
+ case DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(1, 1, 0, 0xdb, 0):
+ case DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(1, 1, 0, 0xdb, 1):
+ case DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(1, 1, 0, 0xdb, 2):
+ case DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(1, 1, 0, 0xdb, 3):
+ case DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(1, 1, 0, 0xdb, 4):
+ case DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(1, 1, 0, 0xdb, 5):
+ case DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 0, 0xfe, 0):
+ case DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 0, 0xfe, 1):
+ case DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 0, 0xfe, 2):
+ case DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 0, 0xfe, 3):
+ case DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 0, 0xfe, 4):
+ case DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 0, 0xfe, 5):
+ case DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(1, 0, 0, 0xdb, 0):
+ case DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(1, 0, 0, 0xdb, 1):
+ case DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(1, 0, 0, 0xdb, 2):
+ case DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(1, 0, 0, 0xdb, 3):
+ case DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(1, 0, 0, 0xdb, 4):
+ case DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(1, 0, 0, 0xdb, 5):
+ case DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 0, 0, 0xfe, 0):
+ case DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 0, 0, 0xfe, 1):
+ case DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 0, 0, 0xfe, 2):
+ case DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 0, 0, 0xfe, 3):
+ case DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 0, 0, 0xfe, 4):
+ case DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 0, 0, 0xfe, 5):
return 1;
case DRM_FORMAT_MOD_INVALID:
default: