1
mirror of https://github.com/mpv-player/mpv synced 2024-11-03 03:19:24 +01:00

vo_opengl: move texture mapping of pixel formats to helper function

All supported pixel formats have a specific "mapping" of CPU data to
textures. This function determines the number and the formats of these
textures. Moving it to a helper will be useful for some hardware decode
interop backends, since they all need similar things.
This commit is contained in:
wm4 2017-02-17 16:16:29 +01:00
parent 9c54b224d8
commit eda69f5333
3 changed files with 163 additions and 128 deletions

View File

@ -106,6 +106,36 @@ static const int special_formats[][2] = {
{0}
};
struct packed_fmt_entry {
int fmt;
int8_t component_size;
int8_t components[4]; // source component - 0 means unmapped
};
// Regular packed formats, which can be mapped to GL formats by finding a
// texture format with same component count/size, and swizzling the result.
static const struct packed_fmt_entry mp_packed_formats[] = {
// w R G B A
{IMGFMT_Y8, 1, {1, 0, 0, 0}},
{IMGFMT_Y16, 2, {1, 0, 0, 0}},
{IMGFMT_YA8, 1, {1, 0, 0, 2}},
{IMGFMT_YA16, 2, {1, 0, 0, 2}},
{IMGFMT_ARGB, 1, {2, 3, 4, 1}},
{IMGFMT_0RGB, 1, {2, 3, 4, 0}},
{IMGFMT_BGRA, 1, {3, 2, 1, 4}},
{IMGFMT_BGR0, 1, {3, 2, 1, 0}},
{IMGFMT_ABGR, 1, {4, 3, 2, 1}},
{IMGFMT_0BGR, 1, {4, 3, 2, 0}},
{IMGFMT_RGBA, 1, {1, 2, 3, 4}},
{IMGFMT_RGB0, 1, {1, 2, 3, 0}},
{IMGFMT_BGR24, 1, {3, 2, 1, 0}},
{IMGFMT_RGB24, 1, {1, 2, 3, 0}},
{IMGFMT_RGB48, 2, {1, 2, 3, 0}},
{IMGFMT_RGBA64, 2, {1, 2, 3, 4}},
{IMGFMT_BGRA64, 2, {3, 2, 1, 4}},
{0},
};
// Return an or-ed combination of all F_ flags that apply.
int gl_format_feature_flags(GL *gl)
{
@ -275,3 +305,113 @@ int gl_bytes_per_pixel(GLenum format, GLenum type)
return gl_format_components(format) * gl_component_size(type);
}
// dest = src.<w> (always using 4 components)
static void packed_fmt_swizzle(char w[5], const struct packed_fmt_entry *fmt)
{
for (int c = 0; c < 4; c++)
w[c] = "rgba"[MPMAX(fmt->components[c] - 1, 0)];
w[4] = '\0';
}
// Like gl_find_unorm_format(), but takes bits (not bytes), and if no fixed
// point format is available, return an unsigned integer format.
static const struct gl_format *find_plane_format(GL *gl, int bits, int n_channels)
{
int bytes = (bits + 7) / 8;
const struct gl_format *f = gl_find_unorm_format(gl, bytes, n_channels);
if (f)
return f;
return gl_find_uint_format(gl, bytes, n_channels);
}
// Put a mapping of imgfmt to OpenGL textures into *out. Basically it selects
// the correct texture formats needed to represent an imgfmt in OpenGL, with
// textures using the same memory organization as on the CPU.
// Each plane is represented by a texture, and each texture has a RGBA
// component order. out->color_swizzle is set to permute the components back.
// May return integer formats for >8 bit formats, if the driver has no
// normalized 16 bit formats.
// Returns false (and *out is set to all-0) if no format found.
bool gl_get_imgfmt_desc(GL *gl, int imgfmt, struct gl_imgfmt_desc *out)
{
*out = (struct gl_imgfmt_desc){0};
struct mp_imgfmt_desc desc = mp_imgfmt_get_desc(imgfmt);
if (!desc.id)
return false;
if (desc.num_planes > 4 || (desc.flags & MP_IMGFLAG_HWACCEL))
return false;
const struct gl_format *planes[4] = {0};
char swizzle_tmp[5] = {0};
char *swizzle = "rgba";
// YUV/planar formats
if (desc.flags & (MP_IMGFLAG_YUV_P | MP_IMGFLAG_RGB_P)) {
int bits = desc.component_bits;
if ((desc.flags & MP_IMGFLAG_NE) && bits >= 8 && bits <= 16) {
planes[0] = find_plane_format(gl, bits, 1);
for (int n = 1; n < desc.num_planes; n++)
planes[n] = planes[0];
// RGB/planar
if (desc.flags & MP_IMGFLAG_RGB_P)
swizzle = "brga";
goto supported;
}
}
// YUV/half-packed
if (desc.flags & MP_IMGFLAG_YUV_NV) {
int bits = desc.component_bits;
if ((desc.flags & MP_IMGFLAG_NE) && bits >= 8 && bits <= 16) {
planes[0] = find_plane_format(gl, bits, 1);
planes[1] = find_plane_format(gl, bits, 2);
if (desc.flags & MP_IMGFLAG_YUV_NV_SWAP)
swizzle = "rbga";
goto supported;
}
}
// XYZ (same organization as RGB packed, but requires conversion matrix)
if (imgfmt == IMGFMT_XYZ12) {
planes[0] = gl_find_unorm_format(gl, 2, 3);
goto supported;
}
// Packed RGB(A) formats
for (const struct packed_fmt_entry *e = mp_packed_formats; e->fmt; e++) {
if (e->fmt == imgfmt) {
int n_comp = desc.bytes[0] / e->component_size;
planes[0] = gl_find_unorm_format(gl, e->component_size, n_comp);
swizzle = swizzle_tmp;
packed_fmt_swizzle(swizzle, e);
goto supported;
}
}
// Special formats for which OpenGL happens to have direct support.
planes[0] = gl_find_special_format(gl, imgfmt);
if (planes[0]) {
// Packed YUV Apple formats color permutation
if (planes[0]->format == GL_RGB_422_APPLE)
swizzle = "gbra";
goto supported;
}
// Unsupported format
return false;
supported:
snprintf(out->swizzle, sizeof(out->swizzle), "%s", swizzle);
out->num_planes = desc.num_planes;
for (int n = 0; n < desc.num_planes; n++) {
out->xs[n] = desc.xs[n];
out->ys[n] = desc.ys[n];
out->planes[n] = planes[n];
assert(planes[n]);
}
return true;
}

View File

@ -35,9 +35,9 @@ enum {
// the format is still GL_FLOAT (32 bit)
// --- Other constants.
MPGL_TYPE_UNORM = 1,
MPGL_TYPE_UINT = 2,
MPGL_TYPE_FLOAT = 3,
MPGL_TYPE_UNORM = 1, // normalized integer (fixed point) formats
MPGL_TYPE_UINT = 2, // full integer formats
MPGL_TYPE_FLOAT = 3, // float formats (both full and half)
};
int gl_format_feature_flags(GL *gl);
@ -57,4 +57,17 @@ int gl_component_size(GLenum type);
int gl_format_components(GLenum format);
int gl_bytes_per_pixel(GLenum format, GLenum type);
struct gl_imgfmt_desc {
int num_planes;
const struct gl_format *planes[4];
// Chroma shift (sub-sampling) for each plane.
int xs[4], ys[4];
// Component order (e.g. "rgba"), applied after all planes are combined.
// This has always 4 components (the excess components have no meaning).
// (For GL_LUMINANCE_ALPHA, it is assumed "ra" has been assigned to "rg".)
char swizzle[5];
};
bool gl_get_imgfmt_desc(GL *gl, int imgfmt, struct gl_imgfmt_desc *out);
#endif

View File

@ -269,34 +269,6 @@ struct gl_video {
bool broken_frame; // temporary error state
};
struct packed_fmt_entry {
int fmt;
int8_t component_size;
int8_t components[4]; // source component - 0 means unmapped
};
static const struct packed_fmt_entry mp_packed_formats[] = {
// w R G B A
{IMGFMT_Y8, 1, {1, 0, 0, 0}},
{IMGFMT_Y16, 2, {1, 0, 0, 0}},
{IMGFMT_YA8, 1, {1, 0, 0, 2}},
{IMGFMT_YA16, 2, {1, 0, 0, 2}},
{IMGFMT_ARGB, 1, {2, 3, 4, 1}},
{IMGFMT_0RGB, 1, {2, 3, 4, 0}},
{IMGFMT_BGRA, 1, {3, 2, 1, 4}},
{IMGFMT_BGR0, 1, {3, 2, 1, 0}},
{IMGFMT_ABGR, 1, {4, 3, 2, 1}},
{IMGFMT_0BGR, 1, {4, 3, 2, 0}},
{IMGFMT_RGBA, 1, {1, 2, 3, 4}},
{IMGFMT_RGB0, 1, {1, 2, 3, 0}},
{IMGFMT_BGR24, 1, {3, 2, 1, 0}},
{IMGFMT_RGB24, 1, {1, 2, 3, 0}},
{IMGFMT_RGB48, 2, {1, 2, 3, 0}},
{IMGFMT_RGBA64, 2, {1, 2, 3, 4}},
{IMGFMT_BGRA64, 2, {3, 2, 1, 4}},
{0},
};
static const struct gl_video_opts gl_video_opts_def = {
.dither_algo = DITHER_FRUIT,
.dither_depth = -1,
@ -3256,25 +3228,6 @@ bool gl_video_showing_interpolated_frame(struct gl_video *p)
return p->is_interpolated;
}
// dest = src.<w> (always using 4 components)
static void packed_fmt_swizzle(char w[5], const struct packed_fmt_entry *fmt)
{
for (int c = 0; c < 4; c++)
w[c] = "rgba"[MPMAX(fmt->components[c] - 1, 0)];
w[4] = '\0';
}
// Like gl_find_unorm_format(), but takes bits (not bytes), and if no fixed
// point format is available, return an unsigned integer format.
static const struct gl_format *find_plane_format(GL *gl, int bits, int n_channels)
{
int bytes = (bits + 7) / 8;
const struct gl_format *f = gl_find_unorm_format(gl, bytes, n_channels);
if (f)
return f;
return gl_find_uint_format(gl, bytes, n_channels);
}
static void init_image_desc(struct gl_video *p, int fmt)
{
p->image_desc = mp_imgfmt_get_desc(fmt);
@ -3292,85 +3245,17 @@ static void init_image_desc(struct gl_video *p, int fmt)
// test_only=false also initializes some rendering parameters accordingly
static bool init_format(struct gl_video *p, int fmt, bool test_only)
{
struct GL *gl = p->gl;
struct mp_imgfmt_desc desc = mp_imgfmt_get_desc(fmt);
if (!desc.id)
int cdepth = mp_imgfmt_get_desc(fmt).component_bits;
if (cdepth > 8 && cdepth < 16 && p->texture_16bit_depth < 16)
return false;
if (desc.num_planes > 4)
struct gl_imgfmt_desc desc;
if (!gl_get_imgfmt_desc(p->gl, fmt, &desc))
return false;
const struct gl_format *plane_format[4] = {0};
char color_swizzle[5] = "";
const struct packed_fmt_entry *packed_format = {0};
// YUV/planar formats
if (desc.flags & (MP_IMGFLAG_YUV_P | MP_IMGFLAG_RGB_P)) {
int bits = desc.component_bits;
if ((desc.flags & MP_IMGFLAG_NE) && bits >= 8 && bits <= 16) {
plane_format[0] = find_plane_format(gl, bits, 1);
for (int n = 1; n < desc.num_planes; n++)
plane_format[n] = plane_format[0];
// RGB/planar
if (desc.flags & MP_IMGFLAG_RGB_P)
snprintf(color_swizzle, sizeof(color_swizzle), "brga");
goto supported;
}
}
// YUV/half-packed
if (desc.flags & MP_IMGFLAG_YUV_NV) {
int bits = desc.component_bits;
if ((desc.flags & MP_IMGFLAG_NE) && bits >= 8 && bits <= 16) {
plane_format[0] = find_plane_format(gl, bits, 1);
plane_format[1] = find_plane_format(gl, bits, 2);
if (desc.flags & MP_IMGFLAG_YUV_NV_SWAP)
snprintf(color_swizzle, sizeof(color_swizzle), "rbga");
goto supported;
}
}
// XYZ (same organization as RGB packed, but requires conversion matrix)
if (fmt == IMGFMT_XYZ12) {
plane_format[0] = gl_find_unorm_format(gl, 2, 3);
goto supported;
}
// Packed RGB(A) formats
for (const struct packed_fmt_entry *e = mp_packed_formats; e->fmt; e++) {
if (e->fmt == fmt) {
int n_comp = desc.bytes[0] / e->component_size;
plane_format[0] = gl_find_unorm_format(gl, e->component_size, n_comp);
packed_format = e;
goto supported;
}
}
// Special formats for which OpenGL happens to have direct support.
plane_format[0] = gl_find_special_format(gl, fmt);
if (plane_format[0]) {
// Packed YUV Apple formats color permutation
if (plane_format[0]->format == GL_RGB_422_APPLE)
snprintf(color_swizzle, sizeof(color_swizzle), "gbra");
goto supported;
}
// Unsupported format
return false;
supported:
if (desc.component_bits > 8 && desc.component_bits < 16) {
if (p->texture_16bit_depth < 16)
return false;
}
int use_integer = -1;
for (int n = 0; n < desc.num_planes; n++) {
if (!plane_format[n])
return false;
int use_int_plane = gl_is_integer_format(plane_format[n]->format);
int use_int_plane = gl_is_integer_format(desc.planes[n]->format);
if (use_integer < 0)
use_integer = use_int_plane;
if (use_integer != use_int_plane)
@ -3383,8 +3268,7 @@ supported:
if (!test_only) {
for (int n = 0; n < desc.num_planes; n++) {
struct texplane *plane = &p->image.planes[n];
const struct gl_format *format = plane_format[n];
assert(format);
const struct gl_format *format = desc.planes[n];
plane->gl_format = format->format;
plane->gl_internal_format = format->internal_format;
plane->gl_type = format->type;
@ -3393,9 +3277,7 @@ supported:
init_image_desc(p, fmt);
p->use_integer_conversion = use_integer;
if (packed_format)
packed_fmt_swizzle(color_swizzle, packed_format);
snprintf(p->color_swizzle, sizeof(p->color_swizzle), "%s", color_swizzle);
snprintf(p->color_swizzle, sizeof(p->color_swizzle), "%s", desc.swizzle);
}
return true;