radeonsi: Add modifier support.

This adds basic modifier support in radeonsi.

Support for import/export of DCC comes in a later patch as that
needs support for multiple memory planes.

Reviewed-by: Marek Olšák <marek.olsak@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6176>
This commit is contained in:
Bas Nieuwenhuizen 2019-12-17 14:15:56 +01:00 committed by Marge Bot
parent f7a4051b83
commit c786150dfa
1 changed files with 150 additions and 14 deletions

View File

@ -216,8 +216,8 @@ static unsigned si_texture_get_offset(struct si_screen *sscreen, struct si_textu
static int si_init_surface(struct si_screen *sscreen, struct radeon_surf *surface,
const struct pipe_resource *ptex, enum radeon_surf_mode array_mode,
bool is_imported, bool is_scanout, bool is_flushed_depth,
bool tc_compatible_htile)
uint64_t modifier, bool is_imported, bool is_scanout,
bool is_flushed_depth, bool tc_compatible_htile)
{
const struct util_format_description *desc = util_format_description(ptex->format);
bool is_depth, is_stencil;
@ -316,7 +316,7 @@ static int si_init_surface(struct si_screen *sscreen, struct radeon_surf *surfac
surface->u.gfx9.surf.swizzle_mode = ADDR_SW_64KB_R_X;
}
surface->modifier = DRM_FORMAT_MOD_INVALID;
surface->modifier = modifier;
r = sscreen->ws->surface_init(sscreen->ws, ptex, flags, bpe, array_mode, surface);
if (r) {
@ -627,7 +627,7 @@ static bool si_resource_get_param(struct pipe_screen *screen, struct pipe_contex
return true;
case PIPE_RESOURCE_PARAM_MODIFIER:
*value = DRM_FORMAT_MOD_INVALID;
*value = tex->surface.modifier;
return true;
case PIPE_RESOURCE_PARAM_HANDLE_TYPE_SHARED:
@ -679,6 +679,7 @@ static bool si_texture_get_handle(struct pipe_screen *screen, struct pipe_contex
struct si_texture *tex = (struct si_texture *)resource;
bool update_metadata = false;
unsigned stride, offset, slice_size;
uint64_t modifier = DRM_FORMAT_MOD_INVALID;
bool flush = false;
ctx = threaded_context_unwrap_sync(ctx);
@ -750,6 +751,8 @@ static bool si_texture_get_handle(struct pipe_screen *screen, struct pipe_contex
} else {
slice_size = (uint64_t)tex->surface.u.legacy.level[0].slice_size_dw * 4;
}
modifier = tex->surface.modifier;
} else {
/* Buffer exports are for the OpenCL interop. */
/* Move a suballocated buffer into a non-suballocated allocation. */
@ -803,6 +806,7 @@ static bool si_texture_get_handle(struct pipe_screen *screen, struct pipe_contex
whandle->stride = stride;
whandle->offset = offset + slice_size * whandle->layer;
whandle->modifier = modifier;
return sscreen->ws->buffer_get_handle(sscreen->ws, res->buf, whandle);
}
@ -1289,8 +1293,10 @@ static enum radeon_surf_mode si_choose_tiling(struct si_screen *sscreen,
return RADEON_SURF_MODE_2D;
}
struct pipe_resource *si_texture_create(struct pipe_screen *screen,
const struct pipe_resource *templ)
static struct pipe_resource *
si_texture_create_with_modifier(struct pipe_screen *screen,
const struct pipe_resource *templ,
uint64_t modifier)
{
struct si_screen *sscreen = (struct si_screen *)screen;
bool is_zs = util_format_is_depth_or_stencil(templ->format);
@ -1352,9 +1358,9 @@ struct pipe_resource *si_texture_create(struct pipe_screen *screen,
if (num_planes > 1)
plane_templ[i].bind |= PIPE_BIND_SHARED;
if (si_init_surface(sscreen, &surface[i], &plane_templ[i], tile_mode, false,
plane_templ[i].bind & PIPE_BIND_SCANOUT, is_flushed_depth,
tc_compatible_htile))
if (si_init_surface(sscreen, &surface[i], &plane_templ[i], tile_mode, modifier,
false, plane_templ[i].bind & PIPE_BIND_SCANOUT,
is_flushed_depth, tc_compatible_htile))
return NULL;
plane_offset[i] = align64(total_size, surface[i].surf_alignment);
@ -1387,11 +1393,138 @@ struct pipe_resource *si_texture_create(struct pipe_screen *screen,
return (struct pipe_resource *)plane0;
}
struct pipe_resource *si_texture_create(struct pipe_screen *screen,
const struct pipe_resource *templ)
{
return si_texture_create_with_modifier(screen, templ, DRM_FORMAT_MOD_INVALID);
}
static void si_query_dmabuf_modifiers(struct pipe_screen *screen,
enum pipe_format format,
int max,
uint64_t *modifiers,
unsigned int *external_only,
int *count)
{
struct si_screen *sscreen = (struct si_screen *)screen;
if (util_format_is_yuv(format)) {
if (max) {
*modifiers = DRM_FORMAT_MOD_LINEAR;
if (external_only)
*external_only = 1;
}
*count = 1;
return;
}
unsigned ac_mod_count = max;
ac_get_supported_modifiers(&sscreen->info, &(struct ac_modifier_options) {
/* Disable DCC until we have support for auxiliary planes. */
.dcc = false,
/* Do not support DCC with retiling yet. This needs explicit
* resource flushes, but the app has no way to promise doing
* flushes with modifiers. */
.dcc_retile = false,
}, format, &ac_mod_count, max ? modifiers : NULL);
if (max && external_only) {
for (unsigned i = 0; i < ac_mod_count; ++i)
external_only[i] = 0;
}
*count = ac_mod_count;
}
static bool
si_is_dmabuf_modifier_supported(struct pipe_screen *screen,
uint64_t modifier,
enum pipe_format format,
bool *external_only)
{
int allowed_mod_count;
si_query_dmabuf_modifiers(screen, format, 0, NULL, NULL, &allowed_mod_count);
uint64_t *allowed_modifiers = (uint64_t *)calloc(allowed_mod_count, sizeof(uint64_t));
if (!allowed_modifiers)
return false;
unsigned *external_array = NULL;
if (external_only) {
external_array = (unsigned *)calloc(allowed_mod_count, sizeof(unsigned));
if (!external_array) {
free(allowed_modifiers);
return false;
}
}
si_query_dmabuf_modifiers(screen, format, allowed_mod_count, allowed_modifiers,
external_array, &allowed_mod_count);
bool supported = false;
for (int i = 0; i < allowed_mod_count && !supported; ++i) {
if (allowed_modifiers[i] != modifier)
continue;
supported = true;
if (external_only)
*external_only = external_array[i];
}
free(allowed_modifiers);
free(external_array);
return supported;
}
static struct pipe_resource *
si_texture_create_with_modifiers(struct pipe_screen *screen,
const struct pipe_resource *templ,
const uint64_t *modifiers,
int modifier_count)
{
/* Buffers with modifiers make zero sense. */
assert(templ->target != PIPE_BUFFER);
/* Select modifier. */
int allowed_mod_count;
si_query_dmabuf_modifiers(screen, templ->format, 0, NULL, NULL, &allowed_mod_count);
uint64_t *allowed_modifiers = (uint64_t *)calloc(allowed_mod_count, sizeof(uint64_t));
if (!allowed_modifiers) {
return NULL;
}
/* This does not take external_only into account. We assume it is the same for all modifiers. */
si_query_dmabuf_modifiers(screen, templ->format, allowed_mod_count, allowed_modifiers, NULL, &allowed_mod_count);
uint64_t modifier = DRM_FORMAT_MOD_INVALID;
/* Try to find the first allowed modifier that is in the application provided
* list. We assume that the allowed modifiers are ordered in descending
* preference in the list provided by si_query_dmabuf_modifiers. */
for (int i = 0; i < allowed_mod_count; ++i) {
bool found = false;
for (int j = 0; j < modifier_count && !found; ++j)
if (modifiers[j] == allowed_modifiers[i])
found = true;
if (found) {
modifier = allowed_modifiers[i];
break;
}
}
free(allowed_modifiers);
if (modifier == DRM_FORMAT_MOD_INVALID) {
return NULL;
}
return si_texture_create_with_modifier(screen, templ, modifier);
}
static struct pipe_resource *si_texture_from_winsys_buffer(struct si_screen *sscreen,
const struct pipe_resource *templ,
struct pb_buffer *buf, unsigned stride,
uint64_t offset, unsigned usage,
bool dedicated)
uint64_t offset, uint64_t modifier,
unsigned usage, bool dedicated)
{
struct radeon_surf surface = {};
struct radeon_bo_metadata metadata = {};
@ -1430,7 +1563,7 @@ static struct pipe_resource *si_texture_from_winsys_buffer(struct si_screen *ssc
metadata.mode = RADEON_SURF_MODE_LINEAR_ALIGNED;
}
r = si_init_surface(sscreen, &surface, templ, metadata.mode, true,
r = si_init_surface(sscreen, &surface, templ, metadata.mode, modifier, true,
surface.flags & RADEON_SURF_SCANOUT, false, false);
if (r)
return NULL;
@ -1503,7 +1636,7 @@ static struct pipe_resource *si_texture_from_handle(struct pipe_screen *screen,
return NULL;
return si_texture_from_winsys_buffer(sscreen, templ, buf, whandle->stride, whandle->offset,
usage, true);
whandle->modifier, usage, true);
}
bool si_init_flushed_depth_texture(struct pipe_context *ctx, struct pipe_resource *texture)
@ -2301,7 +2434,7 @@ static struct pipe_resource *si_resource_from_memobj(struct pipe_screen *screen,
else
res = si_texture_from_winsys_buffer(sscreen, templ, memobj->buf,
memobj->stride,
offset,
offset, DRM_FORMAT_MOD_INVALID,
PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE | PIPE_HANDLE_USAGE_SHADER_WRITE,
memobj->b.dedicated);
@ -2342,9 +2475,12 @@ void si_init_screen_texture_functions(struct si_screen *sscreen)
sscreen->b.resource_get_param = si_resource_get_param;
sscreen->b.resource_get_info = si_texture_get_info;
sscreen->b.resource_from_memobj = si_resource_from_memobj;
sscreen->b.resource_create_with_modifiers = si_texture_create_with_modifiers;
sscreen->b.memobj_create_from_handle = si_memobj_from_handle;
sscreen->b.memobj_destroy = si_memobj_destroy;
sscreen->b.check_resource_capability = si_check_resource_capability;
sscreen->b.query_dmabuf_modifiers = si_query_dmabuf_modifiers;
sscreen->b.is_dmabuf_modifier_supported = si_is_dmabuf_modifier_supported;
}
void si_init_context_texture_functions(struct si_context *sctx)