svga: Add a more elaborate format compatibility determination v2

dri3 is a bit sloppy about its format compatibility requirements, so add
a possibility to import xrgb surfaces as argb textures and vice versa.

At the same time, make the svga_texture_from_handle() function a bit more
readable and fix the error path where we leaked a winsys surface.

v2: Addressed review comments by Brian.

Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: Brian Paul <brianp@vmware.com>
Reviewed-by: Charmaine Lee <charmainel@vmware.com>
This commit is contained in:
Thomas Hellstrom 2017-04-07 14:54:56 +02:00 committed by Brian Paul
parent 18d5c452d0
commit ca59fd1706
3 changed files with 93 additions and 41 deletions

View file

@ -43,6 +43,11 @@ struct vgpu10_format_entry
unsigned flags;
};
struct format_compat_entry
{
enum pipe_format pformat;
const SVGA3dSurfaceFormat *compat_format;
};
static const struct vgpu10_format_entry format_conversion_table[] =
{
@ -1847,6 +1852,23 @@ static const struct format_cap format_cap_table[] = {
}
};
static const SVGA3dSurfaceFormat compat_x8r8g8b8[] = {
SVGA3D_X8R8G8B8, SVGA3D_A8R8G8B8, SVGA3D_B8G8R8X8_UNORM,
SVGA3D_B8G8R8A8_UNORM, 0
};
static const SVGA3dSurfaceFormat compat_r8[] = {
SVGA3D_R8_UNORM, SVGA3D_NV12, SVGA3D_YV12, 0
};
static const SVGA3dSurfaceFormat compat_g8r8[] = {
SVGA3D_R8G8_UNORM, SVGA3D_NV12, 0
};
static const struct format_compat_entry format_compats[] = {
{PIPE_FORMAT_B8G8R8X8_UNORM, compat_x8r8g8b8},
{PIPE_FORMAT_B8G8R8A8_UNORM, compat_x8r8g8b8},
{PIPE_FORMAT_R8_UNORM, compat_r8},
{PIPE_FORMAT_R8G8_UNORM, compat_g8r8}
};
/**
* Debug only:
@ -2267,3 +2289,51 @@ svga_format_is_typeless(SVGA3dSurfaceFormat format)
return false;
}
}
/**
* \brief Can we import a surface with a given SVGA3D format as a texture?
*
* \param ss[in] pointer to the svga screen.
* \param pformat[in] pipe format of the local texture.
* \param sformat[in] svga3d format of the imported surface.
* \param bind[in] bind flags of the imported texture.
* \param verbose[in] Print out incompatibilities in debug mode.
*/
bool
svga_format_is_shareable(const struct svga_screen *ss,
enum pipe_format pformat,
SVGA3dSurfaceFormat sformat,
unsigned bind,
bool verbose)
{
SVGA3dSurfaceFormat default_format =
svga_translate_format(ss, pformat, bind);
int i;
if (default_format == SVGA3D_FORMAT_INVALID)
return false;
if (default_format == sformat)
return true;
for (i = 0; i < ARRAY_SIZE(format_compats); ++i) {
if (format_compats[i].pformat == pformat) {
const SVGA3dSurfaceFormat *compat_format =
format_compats[i].compat_format;
while (*compat_format != 0) {
if (*compat_format == sformat)
return true;
compat_format++;
}
}
}
if (verbose) {
debug_printf("Incompatible imported surface format.\n");
debug_printf("Texture format: \"%s\". Imported format: \"%s\".\n",
svga_format_name(default_format),
svga_format_name(sformat));
}
return false;
}

View file

@ -111,4 +111,10 @@ svga_format_is_uncompressed_snorm(SVGA3dSurfaceFormat format);
bool
svga_format_is_typeless(SVGA3dSurfaceFormat format);
bool
svga_format_is_shareable(const struct svga_screen *ss,
enum pipe_format pformat,
SVGA3dSurfaceFormat sformat,
unsigned bind,
bool verbose);
#endif /* SVGA_FORMAT_H_ */

View file

@ -1149,8 +1149,8 @@ fail_notex:
struct pipe_resource *
svga_texture_from_handle(struct pipe_screen *screen,
const struct pipe_resource *template,
struct winsys_handle *whandle)
const struct pipe_resource *template,
struct winsys_handle *whandle)
{
struct svga_winsys_screen *sws = svga_winsys_screen(screen);
struct svga_screen *ss = svga_screen(screen);
@ -1172,42 +1172,18 @@ svga_texture_from_handle(struct pipe_screen *screen,
if (!srf)
return NULL;
if (svga_translate_format(svga_screen(screen), template->format,
template->bind) != format) {
unsigned f1 = svga_translate_format(svga_screen(screen),
template->format, template->bind);
unsigned f2 = format;
/* It's okay for XRGB and ARGB or depth with/out stencil to get mixed up.
*/
if (f1 == SVGA3D_B8G8R8A8_UNORM)
f1 = SVGA3D_A8R8G8B8;
if (f1 == SVGA3D_B8G8R8X8_UNORM)
f1 = SVGA3D_X8R8G8B8;
if ( !( (f1 == f2) ||
(f1 == SVGA3D_X8R8G8B8 && f2 == SVGA3D_A8R8G8B8) ||
(f1 == SVGA3D_X8R8G8B8 && f2 == SVGA3D_B8G8R8X8_UNORM) ||
(f1 == SVGA3D_A8R8G8B8 && f2 == SVGA3D_X8R8G8B8) ||
(f1 == SVGA3D_A8R8G8B8 && f2 == SVGA3D_B8G8R8A8_UNORM) ||
(f1 == SVGA3D_Z_D24X8 && f2 == SVGA3D_Z_D24S8) ||
(f1 == SVGA3D_Z_DF24 && f2 == SVGA3D_Z_D24S8_INT) ) ) {
debug_printf("%s wrong format %s != %s\n", __FUNCTION__,
svga_format_name(f1), svga_format_name(f2));
return NULL;
}
}
if (!svga_format_is_shareable(ss, template->format, format,
template->bind, true))
goto out_unref;
tex = CALLOC_STRUCT(svga_texture);
if (!tex)
return NULL;
goto out_unref;
tex->defined = CALLOC(template->depth0 * template->array_size,
sizeof(tex->defined[0]));
if (!tex->defined) {
FREE(tex);
return NULL;
}
if (!tex->defined)
goto out_no_defined;
tex->b.b = *template;
tex->b.vtbl = &svga_texture_vtbl;
@ -1222,11 +1198,11 @@ svga_texture_from_handle(struct pipe_screen *screen,
tex->rendered_to = CALLOC(1, sizeof(tex->rendered_to[0]));
if (!tex->rendered_to)
goto fail;
goto out_no_rendered_to;
tex->dirty = CALLOC(1, sizeof(tex->dirty[0]));
if (!tex->dirty)
goto fail;
goto out_no_dirty;
tex->imported = TRUE;
@ -1234,14 +1210,14 @@ svga_texture_from_handle(struct pipe_screen *screen,
return &tex->b.b;
fail:
if (tex->defined)
FREE(tex->defined);
if (tex->rendered_to)
FREE(tex->rendered_to);
if (tex->dirty)
FREE(tex->dirty);
out_no_dirty:
FREE(tex->rendered_to);
out_no_rendered_to:
FREE(tex->defined);
out_no_defined:
FREE(tex);
out_unref:
sws->surface_reference(sws, &srf, NULL);
return NULL;
}