mirror of
https://github.com/mpv-player/mpv
synced 2025-01-29 19:22:48 +00:00
vo_opengl: reorganize texture format handling
This merges all knowledge about texture format into a central table. Most of the work done here is actually identifying which formats exactly are supported by OpenGL(ES) under which circumstances, and keeping this information in the format table in a somewhat declarative way. (Although only to the extend needed by mpv.) In particular, ES and float formats are a horrible mess. Again this is a big refactor that might cause regression on "obscure" configurations.
This commit is contained in:
parent
e68b510a94
commit
84ccebd9b9
@ -72,6 +72,8 @@ struct gl_functions {
|
||||
int provides; // bitfield of MPGL_CAP_* constants
|
||||
int ver_core; // introduced as required function
|
||||
int ver_es_core; // introduced as required GL ES function
|
||||
int ver_exclude; // not applicable to versions >= ver_exclude
|
||||
int ver_es_exclude; // same for GLES
|
||||
const struct gl_function *functions;
|
||||
};
|
||||
|
||||
@ -228,9 +230,28 @@ static const struct gl_functions gl_functions[] = {
|
||||
},
|
||||
// GL_R16 etc.
|
||||
{
|
||||
.ver_core = 300,
|
||||
.extension = "GL_EXT_texture_norm16",
|
||||
.provides = MPGL_CAP_EXT16,
|
||||
.ver_exclude = 1, // never in desktop GL
|
||||
},
|
||||
// Float texture support for GL 2.x
|
||||
{
|
||||
.extension = "GL_ARB_texture_float",
|
||||
.provides = MPGL_CAP_ARB_FLOAT,
|
||||
.ver_exclude = 300,
|
||||
.ver_es_exclude = 1,
|
||||
},
|
||||
// 16 bit float textures filterable with GL_LINEAR in GLES
|
||||
{
|
||||
.extension = "GL_OES_texture_half_float_linear",
|
||||
.provides = MPGL_CAP_OES_HFLOAT_LIN,
|
||||
.ver_exclude = 1,
|
||||
},
|
||||
// 16 bit float textures that can be rendered to in GLES
|
||||
{
|
||||
.extension = "GL_EXT_color_buffer_half_float",
|
||||
.provides = MPGL_CAP_EXT_CR_HFLOAT,
|
||||
.ver_exclude = 1,
|
||||
},
|
||||
{
|
||||
.ver_core = 320,
|
||||
@ -439,6 +460,13 @@ void mpgl_load_functions2(GL *gl, void *(*get_fn)(void *ctx, const char *n),
|
||||
// NOTE: Function entrypoints can exist, even if they do not work.
|
||||
// We must always check extension strings and versions.
|
||||
|
||||
if (gl->version && section->ver_exclude &&
|
||||
gl->version >= section->ver_exclude)
|
||||
continue;
|
||||
if (gl->es && section->ver_es_exclude &&
|
||||
gl->es >= section->ver_es_exclude)
|
||||
continue;
|
||||
|
||||
bool exists = false, must_exist = false;
|
||||
if (ver_core)
|
||||
must_exist = version >= ver_core;
|
||||
@ -505,14 +533,6 @@ void mpgl_load_functions2(GL *gl, void *(*get_fn)(void *ctx, const char *n),
|
||||
mp_verbose(log, "Detected suspected software renderer.\n");
|
||||
}
|
||||
|
||||
// Detect 16F textures that work with GL_LINEAR filtering.
|
||||
if ((!gl->es && (gl->version >= 300 || check_ext(gl, "GL_ARB_texture_float"))) ||
|
||||
(gl->es && (gl->version >= 310 || check_ext(gl, "GL_OES_texture_half_float_linear"))))
|
||||
{
|
||||
mp_verbose(log, "Filterable half-float textures supported.\n");
|
||||
gl->mpgl_caps |= MPGL_CAP_FLOAT_TEX;
|
||||
}
|
||||
|
||||
// Provided for simpler handling if no framebuffer support is available.
|
||||
if (!gl->BindFramebuffer)
|
||||
gl->BindFramebuffer = &dummy_glBindFramebuffer;
|
||||
|
@ -53,7 +53,6 @@ enum {
|
||||
MPGL_CAP_ROW_LENGTH = (1 << 4), // GL_[UN]PACK_ROW_LENGTH
|
||||
MPGL_CAP_FB = (1 << 5),
|
||||
MPGL_CAP_VAO = (1 << 6),
|
||||
MPGL_CAP_FLOAT_TEX = (1 << 9),
|
||||
MPGL_CAP_TEX_RG = (1 << 10), // GL_ARB_texture_rg / GL 3.x
|
||||
MPGL_CAP_VDPAU = (1 << 11), // GL_NV_vdpau_interop
|
||||
MPGL_CAP_APPLE_RGB_422 = (1 << 12), // GL_APPLE_rgb_422
|
||||
@ -62,6 +61,10 @@ enum {
|
||||
MPGL_CAP_DEBUG = (1 << 16),
|
||||
MPGL_CAP_DXINTEROP = (1 << 17), // WGL_NV_DX_interop
|
||||
MPGL_CAP_EXT16 = (1 << 18), // GL_EXT_texture_norm16
|
||||
MPGL_CAP_ARB_FLOAT = (1 << 19), // GL_ARB_texture_float
|
||||
MPGL_CAP_EXT_CR_HFLOAT = (1 << 20), // GL_EXT_color_buffer_half_float
|
||||
MPGL_CAP_OES_HFLOAT_LIN = (1 << 21), // GL_OES_texture_half_float_linear
|
||||
|
||||
MPGL_CAP_SW = (1 << 30), // indirect or sw renderer
|
||||
};
|
||||
|
||||
|
274
video/out/opengl/formats.c
Normal file
274
video/out/opengl/formats.c
Normal file
@ -0,0 +1,274 @@
|
||||
#include "common/common.h"
|
||||
#include "formats.h"
|
||||
|
||||
enum {
|
||||
// --- GL type aliases (for readability)
|
||||
T_U8 = GL_UNSIGNED_BYTE,
|
||||
T_U16 = GL_UNSIGNED_SHORT,
|
||||
T_FL = GL_FLOAT,
|
||||
};
|
||||
|
||||
// List of allowed formats, and their usability for bilinear filtering and FBOs.
|
||||
// This is limited to combinations that are useful for our renderer.
|
||||
const struct gl_format gl_formats[] = {
|
||||
// These are used for desktop GL 3+, and GLES 3+ with GL_EXT_texture_norm16.
|
||||
{GL_R8, GL_RED, T_U8, F_CF | F_GL3 | F_GL2F | F_ES3},
|
||||
{GL_RG8, GL_RG, T_U8, F_CF | F_GL3 | F_GL2F | F_ES3},
|
||||
{GL_RGB8, GL_RGB, T_U8, F_CF | F_GL3 | F_GL2F | F_ES3},
|
||||
{GL_RGBA8, GL_RGBA, T_U8, F_CF | F_GL3 | F_GL2F | F_ES3},
|
||||
{GL_R16, GL_RED, T_U16, F_CF | F_GL3 | F_GL2F | F_EXT16},
|
||||
{GL_RG16, GL_RG, T_U16, F_CF | F_GL3 | F_GL2F | F_EXT16},
|
||||
{GL_RGB16, GL_RGB, T_U16, F_CF | F_GL3 | F_GL2F},
|
||||
{GL_RGBA16, GL_RGBA, T_U16, F_CF | F_GL3 | F_GL2F | F_EXT16},
|
||||
|
||||
// Specifically not color-renderable.
|
||||
{GL_RGB16, GL_RGB, T_U16, F_TF | F_EXT16},
|
||||
|
||||
// GL2 legacy. Ignores possibly present FBO extensions (no CF flag set).
|
||||
{GL_LUMINANCE8, GL_LUMINANCE, T_U8, F_TF | F_GL2},
|
||||
{GL_LUMINANCE8_ALPHA8, GL_LUMINANCE_ALPHA, T_U8, F_TF | F_GL2},
|
||||
{GL_RGB8, GL_RGB, T_U8, F_TF | F_GL2},
|
||||
{GL_RGBA8, GL_RGBA, T_U8, F_TF | F_GL2},
|
||||
{GL_LUMINANCE16, GL_LUMINANCE, T_U16, F_TF | F_GL2},
|
||||
{GL_LUMINANCE16_ALPHA16, GL_LUMINANCE_ALPHA, T_U16, F_TF | F_GL2},
|
||||
{GL_RGB16, GL_RGB, T_U16, F_TF | F_GL2},
|
||||
{GL_RGBA16, GL_RGBA, T_U16, F_TF | F_GL2},
|
||||
|
||||
// ES2 legacy
|
||||
{GL_LUMINANCE, GL_LUMINANCE, T_U8, F_CF | F_ES2},
|
||||
{GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, T_U8, F_CF | F_ES2},
|
||||
{GL_RGB, GL_RGB, T_U8, F_CF | F_ES2},
|
||||
{GL_RGBA, GL_RGBA, T_U8, F_CF | F_ES2},
|
||||
|
||||
// Non-normalized integer formats.
|
||||
// Follows ES 3.0 as to which are color-renderable.
|
||||
{GL_R8UI, GL_RED_INTEGER, T_U8, F_CR | F_GL3 | F_ES3},
|
||||
{GL_RG8UI, GL_RG_INTEGER, T_U8, F_CR | F_GL3 | F_ES3},
|
||||
{GL_RGB8UI, GL_RGB_INTEGER, T_U8, F_GL3 | F_ES3},
|
||||
{GL_RGBA8UI, GL_RGBA_INTEGER, T_U8, F_CR | F_GL3 | F_ES3},
|
||||
{GL_R16UI, GL_RED_INTEGER, T_U16, F_CR | F_GL3 | F_ES3},
|
||||
{GL_RG16UI, GL_RG_INTEGER, T_U16, F_CR | F_GL3 | F_ES3},
|
||||
{GL_RGB16UI, GL_RGB_INTEGER, T_U16, F_GL3 | F_ES3},
|
||||
{GL_RGBA16UI, GL_RGBA_INTEGER, T_U16, F_CR | F_GL3 | F_ES3},
|
||||
|
||||
// On GL3+ or GL2.1 with GL_ARB_texture_float, floats work fully.
|
||||
{GL_R16F, GL_RED, T_FL, F_F16 | F_CF | F_GL3 | F_GL2F},
|
||||
{GL_RG16F, GL_RG, T_FL, F_F16 | F_CF | F_GL3 | F_GL2F},
|
||||
{GL_RGB16F, GL_RGB, T_FL, F_F16 | F_CF | F_GL3 | F_GL2F},
|
||||
{GL_RGBA16F, GL_RGBA, T_FL, F_F16 | F_CF | F_GL3 | F_GL2F},
|
||||
{GL_R32F, GL_RED, T_FL, F_CF | F_GL3 | F_GL2F},
|
||||
{GL_RG32F, GL_RG, T_FL, F_CF | F_GL3 | F_GL2F},
|
||||
{GL_RGB32F, GL_RGB, T_FL, F_CF | F_GL3 | F_GL2F},
|
||||
{GL_RGBA32F, GL_RGBA, T_FL, F_CF | F_GL3 | F_GL2F},
|
||||
|
||||
// Note: we simply don't support float anything on ES2, despite extensions.
|
||||
// We also don't bother with non-filterable float formats, and we ignore
|
||||
// 32 bit float formats that are not blendable when rendering to them.
|
||||
|
||||
// On ES3.2+, both 16 bit floats work fully (except 3-component formats).
|
||||
// F_EXTF16 implies extensions that also enable 16 bit floats fully.
|
||||
{GL_R16F, GL_RED, T_FL, F_F16 | F_CF | F_ES32 | F_EXTF16},
|
||||
{GL_RG16F, GL_RG, T_FL, F_F16 | F_CF | F_ES32 | F_EXTF16},
|
||||
{GL_RGB16F, GL_RGB, T_FL, F_F16 | F_TF | F_ES32 | F_EXTF16},
|
||||
{GL_RGBA16F, GL_RGBA, T_FL, F_F16 | F_CF | F_ES32 | F_EXTF16},
|
||||
|
||||
// On ES3.0+, 16 bit floats are texture-filterable.
|
||||
// Don't bother with 32 bit floats; they exist but are neither CR nor TF.
|
||||
{GL_R16F, GL_RED, T_FL, F_F16 | F_TF | F_ES3},
|
||||
{GL_RG16F, GL_RG, T_FL, F_F16 | F_TF | F_ES3},
|
||||
{GL_RGB16F, GL_RGB, T_FL, F_F16 | F_TF | F_ES3},
|
||||
{GL_RGBA16F, GL_RGBA, T_FL, F_F16 | F_TF | F_ES3},
|
||||
|
||||
// These might be useful as FBO formats.
|
||||
{GL_RGB10_A2, GL_RGBA,
|
||||
GL_UNSIGNED_INT_2_10_10_10_REV, F_CF | F_GL3 | F_ES3},
|
||||
{GL_RGBA12, GL_RGBA, T_U16, F_CF | F_GL2 | F_GL3},
|
||||
{GL_RGB10, GL_RGB, T_U16, F_CF | F_GL2 | F_GL3},
|
||||
|
||||
// Special formats.
|
||||
{GL_RGB8, GL_RGB,
|
||||
GL_UNSIGNED_SHORT_5_6_5, F_TF | F_GL2 | F_GL3},
|
||||
{GL_RGB_RAW_422_APPLE, GL_RGB_422_APPLE,
|
||||
GL_UNSIGNED_SHORT_8_8_APPLE, F_TF | F_APPL},
|
||||
{GL_RGB_RAW_422_APPLE, GL_RGB_422_APPLE,
|
||||
GL_UNSIGNED_SHORT_8_8_REV_APPLE, F_TF | F_APPL},
|
||||
|
||||
{0}
|
||||
};
|
||||
|
||||
// Pairs of mpv formats and OpenGL types that match directly. Code using this
|
||||
// is supposed to look through the gl_formats table, and there is supposed to
|
||||
// be exactly 1 matching entry (which tells you format/internal format).
|
||||
static const int special_formats[][2] = {
|
||||
{IMGFMT_RGB565, GL_UNSIGNED_SHORT_5_6_5},
|
||||
{IMGFMT_UYVY, GL_UNSIGNED_SHORT_8_8_APPLE},
|
||||
{IMGFMT_YUYV, GL_UNSIGNED_SHORT_8_8_REV_APPLE},
|
||||
{0}
|
||||
};
|
||||
|
||||
// Return an or-ed combination of all F_ flags that apply.
|
||||
int gl_format_feature_flags(GL *gl)
|
||||
{
|
||||
return (gl->version == 210 ? F_GL2 : 0)
|
||||
| (gl->version >= 300 ? F_GL3 : 0)
|
||||
| (gl->es == 200 ? F_ES2 : 0)
|
||||
| (gl->es >= 300 ? F_ES3 : 0)
|
||||
| (gl->es >= 320 ? F_ES32 : 0)
|
||||
| (gl->mpgl_caps & MPGL_CAP_EXT16 ? F_EXT16 : 0)
|
||||
| ((gl->es &&
|
||||
(gl->mpgl_caps & MPGL_CAP_TEX_RG) &&
|
||||
(gl->mpgl_caps & MPGL_CAP_EXT_CR_HFLOAT) &&
|
||||
(gl->mpgl_caps & MPGL_CAP_OES_HFLOAT_LIN)) ? F_EXTF16 : 0)
|
||||
| ((gl->version == 210 &&
|
||||
(gl->mpgl_caps & MPGL_CAP_ARB_FLOAT) &&
|
||||
(gl->mpgl_caps & MPGL_CAP_TEX_RG) &&
|
||||
(gl->mpgl_caps & MPGL_CAP_FB)) ? F_GL2F : 0)
|
||||
| (gl->mpgl_caps & MPGL_CAP_APPLE_RGB_422 ? F_APPL : 0);
|
||||
}
|
||||
|
||||
// Return the entry for the given internal format. Return NULL if unsupported.
|
||||
const struct gl_format *gl_find_internal_format(GL *gl, GLint internal_format)
|
||||
{
|
||||
int features = gl_format_feature_flags(gl);
|
||||
for (int n = 0; gl_formats[n].type; n++) {
|
||||
const struct gl_format *f = &gl_formats[n];
|
||||
if (f->internal_format == internal_format && (f->flags & features))
|
||||
return f;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct gl_format *gl_find_special_format(GL *gl, int mpfmt)
|
||||
{
|
||||
int features = gl_format_feature_flags(gl);
|
||||
for (int n = 0; special_formats[n][0]; n++) {
|
||||
if (special_formats[n][0] == mpfmt) {
|
||||
GLenum type = special_formats[n][1];
|
||||
for (int i = 0; gl_formats[i].type; i++) {
|
||||
const struct gl_format *f = &gl_formats[i];
|
||||
if (f->type == type && (f->flags & features))
|
||||
return f;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// type: one of MPGL_TYPE_*
|
||||
// flags: bitset of F_*, all flags must be present
|
||||
const struct gl_format *gl_find_format(GL *gl, int type, int flags,
|
||||
int bytes_per_component, int n_components)
|
||||
{
|
||||
if (!bytes_per_component || !n_components || !type)
|
||||
return NULL;
|
||||
int features = gl_format_feature_flags(gl);
|
||||
for (int n = 0; gl_formats[n].type; n++) {
|
||||
const struct gl_format *f = &gl_formats[n];
|
||||
if ((f->flags & features) &&
|
||||
((f->flags & flags) == flags) &&
|
||||
gl_format_type(f) == type &&
|
||||
gl_component_size(f->type) == bytes_per_component &&
|
||||
gl_format_components(f->format) == n_components)
|
||||
return f;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Return a texture-filterable unsigned normalized fixed point format.
|
||||
const struct gl_format *gl_find_unorm_format(GL *gl, int bytes_per_component,
|
||||
int n_components)
|
||||
{
|
||||
return gl_find_format(gl, MPGL_TYPE_UNORM, F_TF, bytes_per_component,
|
||||
n_components);
|
||||
}
|
||||
|
||||
// Return an unsigned integer format.
|
||||
const struct gl_format *gl_find_uint_format(GL *gl, int bytes_per_component,
|
||||
int n_components)
|
||||
{
|
||||
return gl_find_format(gl, MPGL_TYPE_UINT, 0, bytes_per_component,
|
||||
n_components);
|
||||
}
|
||||
|
||||
// Return a 16 bit float format. Note that this will return a GL_FLOAT format
|
||||
// with 32 bit per component; just the internal representation is smaller.
|
||||
// Some GL versions will allow upload with GL_HALF_FLOAT as well.
|
||||
const struct gl_format *gl_find_float16_format(GL *gl, int n_components)
|
||||
{
|
||||
return gl_find_format(gl, MPGL_TYPE_FLOAT, F_F16, 4, n_components);
|
||||
}
|
||||
|
||||
int gl_format_type(const struct gl_format *format)
|
||||
{
|
||||
if (!format)
|
||||
return 0;
|
||||
if (format->type == GL_FLOAT)
|
||||
return MPGL_TYPE_FLOAT;
|
||||
if (gl_integer_format_to_base(format->format))
|
||||
return MPGL_TYPE_UINT;
|
||||
return MPGL_TYPE_UNORM;
|
||||
}
|
||||
|
||||
// Return an integer pixel "format" to a base internal format.
|
||||
// Return 0 if it's not an integer format.
|
||||
GLenum gl_integer_format_to_base(GLenum format)
|
||||
{
|
||||
switch (format) {
|
||||
case GL_RED_INTEGER: return GL_RED;
|
||||
case GL_RG_INTEGER: return GL_RG;
|
||||
case GL_RGB_INTEGER: return GL_RGB;
|
||||
case GL_RGBA_INTEGER: return GL_RGBA;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Return the number of bytes per component this format implies.
|
||||
// Returns 0 for formats with non-byte alignments and formats which
|
||||
// merge multiple components (like GL_UNSIGNED_SHORT_5_6_5).
|
||||
int gl_component_size(GLenum type)
|
||||
{
|
||||
switch (type) {
|
||||
case GL_UNSIGNED_BYTE: return 1;
|
||||
case GL_UNSIGNED_SHORT: return 2;
|
||||
case GL_FLOAT: return 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Return the number of a pixel "format".
|
||||
int gl_format_components(GLenum format)
|
||||
{
|
||||
switch (format) {
|
||||
case GL_RED:
|
||||
case GL_RED_INTEGER:
|
||||
case GL_LUMINANCE:
|
||||
return 1;
|
||||
case GL_RG:
|
||||
case GL_RG_INTEGER:
|
||||
case GL_LUMINANCE_ALPHA:
|
||||
return 2;
|
||||
case GL_RGB:
|
||||
case GL_RGB_INTEGER:
|
||||
return 3;
|
||||
case GL_RGBA:
|
||||
case GL_RGBA_INTEGER:
|
||||
return 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// return the number of bytes per pixel for the given format
|
||||
// does not handle all possible variants, just those used by mpv
|
||||
int gl_bytes_per_pixel(GLenum format, GLenum type)
|
||||
{
|
||||
// Formats with merged components are special.
|
||||
switch (type) {
|
||||
case GL_UNSIGNED_INT_2_10_10_10_REV: return 4;
|
||||
case GL_UNSIGNED_SHORT_5_6_5: return 2;
|
||||
case GL_UNSIGNED_SHORT_8_8_APPLE: return 2;
|
||||
case GL_UNSIGNED_SHORT_8_8_REV_APPLE: return 2;
|
||||
}
|
||||
|
||||
return gl_format_components(format) * gl_component_size(type);
|
||||
}
|
60
video/out/opengl/formats.h
Normal file
60
video/out/opengl/formats.h
Normal file
@ -0,0 +1,60 @@
|
||||
#ifndef MPGL_FORMATS_H_
|
||||
#define MPGL_FORMATS_H_
|
||||
|
||||
#include "common.h"
|
||||
|
||||
struct gl_format {
|
||||
GLint internal_format; // glTexImage argument
|
||||
GLenum format; // glTexImage argument
|
||||
GLenum type; // e.g. GL_UNSIGNED_SHORT
|
||||
int flags;
|
||||
};
|
||||
|
||||
extern const struct gl_format gl_formats[];
|
||||
|
||||
enum {
|
||||
// --- gl_format.flags
|
||||
|
||||
// Version flags. If at least 1 flag matches, the format entry is considered
|
||||
// supported on the current GL context.
|
||||
F_GL2 = 1 << 0, // GL2.1-only
|
||||
F_GL3 = 1 << 1, // GL3.0 or later
|
||||
F_ES2 = 1 << 2, // ES2-only
|
||||
F_ES3 = 1 << 3, // ES3.0 or later
|
||||
F_ES32 = 1 << 4, // ES3.2 or later
|
||||
F_EXT16 = 1 << 5, // ES with GL_EXT_texture_norm16
|
||||
F_EXTF16 = 1 << 6, // GL_OES_texture_half_float_linear +
|
||||
// GL_EXT_color_buffer_half_float
|
||||
F_GL2F = 1 << 7, // GL2.1-only with texture_rg + texture_float + FBOs
|
||||
F_APPL = 1 << 8, // GL_APPLE_rgb_422
|
||||
|
||||
// Feature flags. They are additional and signal presence of features.
|
||||
F_CR = 1 << 16, // color-renderable
|
||||
F_TF = 1 << 17, // texture-filterable with GL_LINEAR
|
||||
F_CF = F_CR | F_TF,
|
||||
F_F16 = 1 << 18, // uses half-floats (16 bit) internally, even though
|
||||
// the format is still GL_FLOAT (32 bit)
|
||||
|
||||
// --- Other constants.
|
||||
MPGL_TYPE_UNORM = 1,
|
||||
MPGL_TYPE_UINT = 2,
|
||||
MPGL_TYPE_FLOAT = 3,
|
||||
};
|
||||
|
||||
int gl_format_feature_flags(GL *gl);
|
||||
const struct gl_format *gl_find_internal_format(GL *gl, GLint internal_format);
|
||||
const struct gl_format *gl_find_special_format(GL *gl, int mpfmt);
|
||||
const struct gl_format *gl_find_format(GL *gl, int type, int flags,
|
||||
int bytes_per_component, int n_components);
|
||||
const struct gl_format *gl_find_unorm_format(GL *gl, int bytes_per_component,
|
||||
int n_components);
|
||||
const struct gl_format *gl_find_uint_format(GL *gl, int bytes_per_component,
|
||||
int n_components);
|
||||
const struct gl_format *gl_find_float16_format(GL *gl, int n_components);
|
||||
int gl_format_type(const struct gl_format *format);
|
||||
GLenum gl_integer_format_to_base(GLenum format);
|
||||
int gl_component_size(GLenum type);
|
||||
int gl_format_components(GLenum format);
|
||||
int gl_bytes_per_pixel(GLenum format, GLenum type);
|
||||
|
||||
#endif
|
@ -98,6 +98,10 @@
|
||||
#define GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE 0x93A0
|
||||
#endif
|
||||
|
||||
#ifndef GL_RGB_RAW_422_APPLE
|
||||
#define GL_RGB_RAW_422_APPLE 0x8A51
|
||||
#endif
|
||||
|
||||
#undef MP_GET_GL_WORKAROUNDS
|
||||
|
||||
#endif // MP_GET_GL_WORKAROUNDS
|
||||
|
@ -21,15 +21,10 @@
|
||||
|
||||
#include "video/out/bitmap_packer.h"
|
||||
|
||||
#include "formats.h"
|
||||
#include "utils.h"
|
||||
#include "osd.h"
|
||||
|
||||
struct osd_fmt_entry {
|
||||
GLint internal_format;
|
||||
GLint format;
|
||||
GLenum type;
|
||||
};
|
||||
|
||||
// glBlendFuncSeparate() arguments
|
||||
static const int blend_factors[SUBBITMAP_COUNT][4] = {
|
||||
[SUBBITMAP_LIBASS] = {GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
|
||||
@ -38,21 +33,6 @@ static const int blend_factors[SUBBITMAP_COUNT][4] = {
|
||||
GL_ONE, GL_ONE_MINUS_SRC_ALPHA},
|
||||
};
|
||||
|
||||
static const struct osd_fmt_entry osd_to_gl3_formats[SUBBITMAP_COUNT] = {
|
||||
[SUBBITMAP_LIBASS] = {GL_RED, GL_RED, GL_UNSIGNED_BYTE},
|
||||
[SUBBITMAP_RGBA] = {GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE},
|
||||
};
|
||||
|
||||
static const struct osd_fmt_entry osd_to_gles3_formats[SUBBITMAP_COUNT] = {
|
||||
[SUBBITMAP_LIBASS] = {GL_R8, GL_RED, GL_UNSIGNED_BYTE},
|
||||
[SUBBITMAP_RGBA] = {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE},
|
||||
};
|
||||
|
||||
static const struct osd_fmt_entry osd_to_gl2_formats[SUBBITMAP_COUNT] = {
|
||||
[SUBBITMAP_LIBASS] = {GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE},
|
||||
[SUBBITMAP_RGBA] = {GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE},
|
||||
};
|
||||
|
||||
struct vertex {
|
||||
float position[2];
|
||||
float texcoord[2];
|
||||
@ -86,7 +66,7 @@ struct mpgl_osd {
|
||||
bool use_pbo;
|
||||
bool scaled;
|
||||
struct mpgl_osd_part *parts[MAX_OSD_PARTS];
|
||||
const struct osd_fmt_entry *fmt_table;
|
||||
const struct gl_format *fmt_table[SUBBITMAP_COUNT];
|
||||
bool formats[SUBBITMAP_COUNT];
|
||||
struct gl_vao vao;
|
||||
int64_t change_counter;
|
||||
@ -106,15 +86,11 @@ struct mpgl_osd *mpgl_osd_init(GL *gl, struct mp_log *log, struct osd_state *osd
|
||||
.log = log,
|
||||
.osd = osd,
|
||||
.gl = gl,
|
||||
.fmt_table = osd_to_gl3_formats,
|
||||
.scratch = talloc_zero_size(ctx, 1),
|
||||
};
|
||||
|
||||
if (gl->es >= 300) {
|
||||
ctx->fmt_table = osd_to_gles3_formats;
|
||||
} else if (!(gl->mpgl_caps & MPGL_CAP_TEX_RG)) {
|
||||
ctx->fmt_table = osd_to_gl2_formats;
|
||||
}
|
||||
ctx->fmt_table[SUBBITMAP_LIBASS] = gl_find_unorm_format(gl, 1, 1);
|
||||
ctx->fmt_table[SUBBITMAP_RGBA] = gl_find_unorm_format(gl, 1, 4);
|
||||
|
||||
for (int n = 0; n < MAX_OSD_PARTS; n++) {
|
||||
struct mpgl_osd_part *p = talloc_ptrtype(ctx, p);
|
||||
@ -128,7 +104,7 @@ struct mpgl_osd *mpgl_osd_init(GL *gl, struct mp_log *log, struct osd_state *osd
|
||||
}
|
||||
|
||||
for (int n = 0; n < SUBBITMAP_COUNT; n++)
|
||||
ctx->formats[n] = ctx->fmt_table[n].type != 0;
|
||||
ctx->formats[n] = !!ctx->fmt_table[n];
|
||||
|
||||
gl_vao_init(&ctx->vao, gl, sizeof(struct vertex), vertex_vao);
|
||||
|
||||
@ -163,8 +139,8 @@ static bool upload_pbo(struct mpgl_osd *ctx, struct mpgl_osd_part *osd,
|
||||
{
|
||||
GL *gl = ctx->gl;
|
||||
bool success = true;
|
||||
struct osd_fmt_entry fmt = ctx->fmt_table[imgs->format];
|
||||
int pix_stride = glFmt2bpp(fmt.format, fmt.type);
|
||||
const struct gl_format *fmt = ctx->fmt_table[imgs->format];
|
||||
int pix_stride = gl_bytes_per_pixel(fmt->format, fmt->type);
|
||||
|
||||
if (!osd->buffer) {
|
||||
gl->GenBuffers(1, &osd->buffer);
|
||||
@ -185,7 +161,7 @@ static bool upload_pbo(struct mpgl_osd *ctx, struct mpgl_osd_part *osd,
|
||||
packer_copy_subbitmaps(osd->packer, imgs, data, pix_stride, stride);
|
||||
if (!gl->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER))
|
||||
success = false;
|
||||
glUploadTex(gl, GL_TEXTURE_2D, fmt.format, fmt.type, NULL, stride,
|
||||
glUploadTex(gl, GL_TEXTURE_2D, fmt->format, fmt->type, NULL, stride,
|
||||
bb[0].x, bb[0].y, bb[1].x - bb[0].x, bb[1].y - bb[0].y, 0);
|
||||
}
|
||||
gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
@ -201,11 +177,11 @@ static bool upload_pbo(struct mpgl_osd *ctx, struct mpgl_osd_part *osd,
|
||||
static void upload_tex(struct mpgl_osd *ctx, struct mpgl_osd_part *osd,
|
||||
struct sub_bitmaps *imgs)
|
||||
{
|
||||
struct osd_fmt_entry fmt = ctx->fmt_table[imgs->format];
|
||||
const struct gl_format *fmt = ctx->fmt_table[imgs->format];
|
||||
if (osd->packer->padding) {
|
||||
struct pos bb[2];
|
||||
packer_get_bb(osd->packer, bb);
|
||||
glClearTex(ctx->gl, GL_TEXTURE_2D, fmt.format, fmt.type,
|
||||
glClearTex(ctx->gl, GL_TEXTURE_2D, fmt->format, fmt->type,
|
||||
bb[0].x, bb[0].y, bb[1].x - bb[0].y, bb[1].y - bb[0].y,
|
||||
0, &ctx->scratch);
|
||||
}
|
||||
@ -213,7 +189,7 @@ static void upload_tex(struct mpgl_osd *ctx, struct mpgl_osd_part *osd,
|
||||
struct sub_bitmap *s = &imgs->parts[n];
|
||||
struct pos p = osd->packer->result[n];
|
||||
|
||||
glUploadTex(ctx->gl, GL_TEXTURE_2D, fmt.format, fmt.type,
|
||||
glUploadTex(ctx->gl, GL_TEXTURE_2D, fmt->format, fmt->type,
|
||||
s->bitmap, s->stride, p.x, p.y, s->w, s->h, 0);
|
||||
}
|
||||
}
|
||||
@ -232,8 +208,8 @@ static bool upload_osd(struct mpgl_osd *ctx, struct mpgl_osd_part *osd,
|
||||
return false;
|
||||
}
|
||||
|
||||
struct osd_fmt_entry fmt = ctx->fmt_table[imgs->format];
|
||||
assert(fmt.type != 0);
|
||||
const struct gl_format *fmt = ctx->fmt_table[imgs->format];
|
||||
assert(fmt);
|
||||
|
||||
if (!osd->texture)
|
||||
gl->GenTextures(1, &osd->texture);
|
||||
@ -247,8 +223,8 @@ static bool upload_osd(struct mpgl_osd *ctx, struct mpgl_osd_part *osd,
|
||||
osd->w = FFMAX(32, osd->packer->w);
|
||||
osd->h = FFMAX(32, osd->packer->h);
|
||||
|
||||
gl->TexImage2D(GL_TEXTURE_2D, 0, fmt.internal_format, osd->w, osd->h,
|
||||
0, fmt.format, fmt.type, NULL);
|
||||
gl->TexImage2D(GL_TEXTURE_2D, 0, fmt->internal_format, osd->w, osd->h,
|
||||
0, fmt->format, fmt->type, NULL);
|
||||
|
||||
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <assert.h>
|
||||
|
||||
#include "common/common.h"
|
||||
#include "formats.h"
|
||||
#include "utils.h"
|
||||
|
||||
// GLU has this as gluErrorString (we don't use GLU, as it is legacy-OpenGL)
|
||||
@ -50,52 +51,6 @@ void glCheckError(GL *gl, struct mp_log *log, const char *info)
|
||||
}
|
||||
}
|
||||
|
||||
// return the number of bytes per pixel for the given format
|
||||
// does not handle all possible variants, just those used by mpv
|
||||
int glFmt2bpp(GLenum format, GLenum type)
|
||||
{
|
||||
int component_size = 0;
|
||||
switch (type) {
|
||||
case GL_UNSIGNED_BYTE_3_3_2:
|
||||
case GL_UNSIGNED_BYTE_2_3_3_REV:
|
||||
return 1;
|
||||
case GL_UNSIGNED_SHORT_5_5_5_1:
|
||||
case GL_UNSIGNED_SHORT_1_5_5_5_REV:
|
||||
case GL_UNSIGNED_SHORT_5_6_5:
|
||||
case GL_UNSIGNED_SHORT_5_6_5_REV:
|
||||
return 2;
|
||||
case GL_UNSIGNED_BYTE:
|
||||
component_size = 1;
|
||||
break;
|
||||
case GL_UNSIGNED_SHORT:
|
||||
component_size = 2;
|
||||
break;
|
||||
}
|
||||
switch (format) {
|
||||
case GL_LUMINANCE:
|
||||
case GL_ALPHA:
|
||||
return component_size;
|
||||
case GL_RGB_422_APPLE:
|
||||
return 2;
|
||||
case GL_RGB:
|
||||
case GL_BGR:
|
||||
case GL_RGB_INTEGER:
|
||||
return 3 * component_size;
|
||||
case GL_RGBA:
|
||||
case GL_BGRA:
|
||||
case GL_RGBA_INTEGER:
|
||||
return 4 * component_size;
|
||||
case GL_RED:
|
||||
case GL_RED_INTEGER:
|
||||
return component_size;
|
||||
case GL_RG:
|
||||
case GL_LUMINANCE_ALPHA:
|
||||
case GL_RG_INTEGER:
|
||||
return 2 * component_size;
|
||||
}
|
||||
abort(); // unknown
|
||||
}
|
||||
|
||||
static int get_alignment(int stride)
|
||||
{
|
||||
if (stride % 8 == 0)
|
||||
@ -117,9 +72,10 @@ void glUploadTex(GL *gl, GLenum target, GLenum format, GLenum type,
|
||||
const void *dataptr, int stride,
|
||||
int x, int y, int w, int h, int slice)
|
||||
{
|
||||
int bpp = gl_bytes_per_pixel(format, type);
|
||||
const uint8_t *data = dataptr;
|
||||
int y_max = y + h;
|
||||
if (w <= 0 || h <= 0)
|
||||
if (w <= 0 || h <= 0 || !bpp)
|
||||
return;
|
||||
if (slice <= 0)
|
||||
slice = h;
|
||||
@ -131,9 +87,9 @@ void glUploadTex(GL *gl, GLenum target, GLenum format, GLenum type,
|
||||
bool use_rowlength = slice > 1 && (gl->mpgl_caps & MPGL_CAP_ROW_LENGTH);
|
||||
if (use_rowlength) {
|
||||
// this is not always correct, but should work for MPlayer
|
||||
gl->PixelStorei(GL_UNPACK_ROW_LENGTH, stride / glFmt2bpp(format, type));
|
||||
gl->PixelStorei(GL_UNPACK_ROW_LENGTH, stride / bpp);
|
||||
} else {
|
||||
if (stride != glFmt2bpp(format, type) * w)
|
||||
if (stride != bpp * w)
|
||||
slice = 1; // very inefficient, but at least it works
|
||||
}
|
||||
for (; y + slice <= y_max; y += slice) {
|
||||
@ -153,10 +109,10 @@ void glUploadTex(GL *gl, GLenum target, GLenum format, GLenum type,
|
||||
void glClearTex(GL *gl, GLenum target, GLenum format, GLenum type,
|
||||
int x, int y, int w, int h, uint8_t val, void **scratch)
|
||||
{
|
||||
int bpp = glFmt2bpp(format, type);
|
||||
int bpp = gl_bytes_per_pixel(format, type);
|
||||
int stride = w * bpp;
|
||||
int size = h * stride;
|
||||
if (size < 1)
|
||||
if (size < 1 || !bpp)
|
||||
return;
|
||||
void *data = scratch ? *scratch : NULL;
|
||||
if (talloc_get_size(data) < size)
|
||||
@ -307,32 +263,6 @@ void gl_vao_draw_data(struct gl_vao *vao, GLenum prim, void *ptr, size_t num)
|
||||
gl_vao_unbind(vao);
|
||||
}
|
||||
|
||||
struct gl_format {
|
||||
GLenum format;
|
||||
GLenum type;
|
||||
GLint internal_format;
|
||||
};
|
||||
|
||||
static const struct gl_format gl_formats[] = {
|
||||
// GLES 3.0
|
||||
{GL_RGB, GL_UNSIGNED_BYTE, GL_RGB},
|
||||
{GL_RGBA, GL_UNSIGNED_BYTE, GL_RGBA},
|
||||
{GL_RGB, GL_UNSIGNED_BYTE, GL_RGB8},
|
||||
{GL_RGBA, GL_UNSIGNED_BYTE, GL_RGBA8},
|
||||
{GL_RGB, GL_UNSIGNED_SHORT, GL_RGB16},
|
||||
{GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, GL_RGB10_A2},
|
||||
// not texture filterable in GLES 3.0
|
||||
{GL_RGB, GL_FLOAT, GL_RGB16F},
|
||||
{GL_RGBA, GL_FLOAT, GL_RGBA16F},
|
||||
{GL_RGB, GL_FLOAT, GL_RGB32F},
|
||||
{GL_RGBA, GL_FLOAT, GL_RGBA32F},
|
||||
// Desktop GL
|
||||
{GL_RGB, GL_UNSIGNED_SHORT, GL_RGB10},
|
||||
{GL_RGBA, GL_UNSIGNED_SHORT, GL_RGBA12},
|
||||
{GL_RGBA, GL_UNSIGNED_SHORT, GL_RGBA16},
|
||||
{0}
|
||||
};
|
||||
|
||||
// Create a texture and a FBO using the texture as color attachments.
|
||||
// iformat: texture internal format
|
||||
// Returns success.
|
||||
@ -373,19 +303,16 @@ bool fbotex_change(struct fbotex *fbo, GL *gl, struct mp_log *log, int w, int h,
|
||||
if (flags & FBOTEX_FUZZY_H)
|
||||
h = MP_ALIGN_UP(h, 256);
|
||||
|
||||
GLenum filter = fbo->tex_filter;
|
||||
mp_verbose(log, "Create FBO: %dx%d (%dx%d)\n", lw, lh, w, h);
|
||||
|
||||
struct gl_format format = {
|
||||
.format = GL_RGBA,
|
||||
.type = GL_UNSIGNED_BYTE,
|
||||
.internal_format = iformat,
|
||||
};
|
||||
for (int n = 0; gl_formats[n].format; n++) {
|
||||
if (gl_formats[n].internal_format == format.internal_format) {
|
||||
format = gl_formats[n];
|
||||
break;
|
||||
}
|
||||
const struct gl_format *format = gl_find_internal_format(gl, iformat);
|
||||
if (!format || (format->flags & F_CF) != F_CF) {
|
||||
mp_verbose(log, "Format 0x%x not supported.\n", (unsigned)iformat);
|
||||
return false;
|
||||
}
|
||||
assert(gl->mpgl_caps & MPGL_CAP_FB);
|
||||
|
||||
GLenum filter = fbo->tex_filter;
|
||||
|
||||
*fbo = (struct fbotex) {
|
||||
.gl = gl,
|
||||
@ -396,17 +323,11 @@ bool fbotex_change(struct fbotex *fbo, GL *gl, struct mp_log *log, int w, int h,
|
||||
.iformat = iformat,
|
||||
};
|
||||
|
||||
mp_verbose(log, "Create FBO: %dx%d -> %dx%d\n", fbo->lw, fbo->lh,
|
||||
fbo->rw, fbo->rh);
|
||||
|
||||
if (!(gl->mpgl_caps & MPGL_CAP_FB))
|
||||
return false;
|
||||
|
||||
gl->GenFramebuffers(1, &fbo->fbo);
|
||||
gl->GenTextures(1, &fbo->texture);
|
||||
gl->BindTexture(GL_TEXTURE_2D, fbo->texture);
|
||||
gl->TexImage2D(GL_TEXTURE_2D, 0, format.internal_format, fbo->rw, fbo->rh, 0,
|
||||
format.format, format.type, NULL);
|
||||
gl->TexImage2D(GL_TEXTURE_2D, 0, format->internal_format, fbo->rw, fbo->rh, 0,
|
||||
format->format, format->type, NULL);
|
||||
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
gl->BindTexture(GL_TEXTURE_2D, 0);
|
||||
|
@ -25,7 +25,6 @@ struct mp_log;
|
||||
|
||||
void glCheckError(GL *gl, struct mp_log *log, const char *info);
|
||||
|
||||
int glFmt2bpp(GLenum format, GLenum type);
|
||||
void glUploadTex(GL *gl, GLenum target, GLenum format, GLenum type,
|
||||
const void *dataptr, int stride,
|
||||
int x, int y, int w, int h, int slice);
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "common/global.h"
|
||||
#include "options/options.h"
|
||||
#include "common.h"
|
||||
#include "formats.h"
|
||||
#include "utils.h"
|
||||
#include "hwdec.h"
|
||||
#include "osd.h"
|
||||
@ -248,90 +249,6 @@ struct gl_video {
|
||||
bool custom_shader_fn_warned;
|
||||
};
|
||||
|
||||
struct fmt_entry {
|
||||
int mp_format;
|
||||
GLint internal_format;
|
||||
GLenum format;
|
||||
GLenum type;
|
||||
};
|
||||
|
||||
// Very special formats, for which OpenGL happens to have direct support
|
||||
static const struct fmt_entry mp_to_gl_formats[] = {
|
||||
{IMGFMT_RGB565, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5},
|
||||
{0},
|
||||
};
|
||||
|
||||
// These are used for desktop GL 3+, and GLES 3+ with GL_EXT_texture_norm16.
|
||||
static const struct fmt_entry gl_byte_formats[] = {
|
||||
{0, GL_R8, GL_RED, GL_UNSIGNED_BYTE}, // 1 x 8
|
||||
{0, GL_RG8, GL_RG, GL_UNSIGNED_BYTE}, // 2 x 8
|
||||
{0, GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE}, // 3 x 8
|
||||
{0, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE}, // 4 x 8
|
||||
{0, GL_R16, GL_RED, GL_UNSIGNED_SHORT}, // 1 x 16
|
||||
{0, GL_RG16, GL_RG, GL_UNSIGNED_SHORT}, // 2 x 16
|
||||
{0, GL_RGB16, GL_RGB, GL_UNSIGNED_SHORT}, // 3 x 16
|
||||
{0, GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT}, // 4 x 16
|
||||
};
|
||||
|
||||
static const struct fmt_entry gl_byte_formats_gles3[] = {
|
||||
{0, GL_R8, GL_RED, GL_UNSIGNED_BYTE}, // 1 x 8
|
||||
{0, GL_RG8, GL_RG, GL_UNSIGNED_BYTE}, // 2 x 8
|
||||
{0, GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE}, // 3 x 8
|
||||
{0, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE}, // 4 x 8
|
||||
// There are no filterable texture formats that can be uploaded as
|
||||
// GL_UNSIGNED_SHORT, so apparently we're out of luck.
|
||||
{0, 0, 0, 0}, // 1 x 16
|
||||
{0, 0, 0, 0}, // 2 x 16
|
||||
{0, 0, 0, 0}, // 3 x 16
|
||||
{0, 0, 0, 0}, // 4 x 16
|
||||
};
|
||||
|
||||
static const struct fmt_entry gl_ui_byte_formats_gles3[] = {
|
||||
{0, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE}, // 1 x 8
|
||||
{0, GL_RG8UI, GL_RG_INTEGER, GL_UNSIGNED_BYTE}, // 2 x 8
|
||||
{0, GL_RGB8UI, GL_RGB_INTEGER, GL_UNSIGNED_BYTE}, // 3 x 8
|
||||
{0, GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE}, // 4 x 8
|
||||
{0, GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT}, // 1 x 16
|
||||
{0, GL_RG16UI, GL_RG_INTEGER, GL_UNSIGNED_SHORT}, // 2 x 16
|
||||
{0, GL_RGB16UI, GL_RGB_INTEGER, GL_UNSIGNED_SHORT}, // 3 x 16
|
||||
{0, GL_RGBA16UI, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT}, // 4 x 16
|
||||
};
|
||||
|
||||
static const struct fmt_entry gl_byte_formats_gles2[] = {
|
||||
{0, GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE}, // 1 x 8
|
||||
{0, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE}, // 2 x 8
|
||||
{0, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE}, // 3 x 8
|
||||
{0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE}, // 4 x 8
|
||||
{0, 0, 0, 0}, // 1 x 16
|
||||
{0, 0, 0, 0}, // 2 x 16
|
||||
{0, 0, 0, 0}, // 3 x 16
|
||||
{0, 0, 0, 0}, // 4 x 16
|
||||
};
|
||||
|
||||
static const struct fmt_entry gl_byte_formats_legacy[] = {
|
||||
{0, GL_LUMINANCE8, GL_LUMINANCE, GL_UNSIGNED_BYTE}, // 1 x 8
|
||||
{0, GL_LUMINANCE8_ALPHA8, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE}, // 2 x 8
|
||||
{0, GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE}, // 3 x 8
|
||||
{0, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE}, // 4 x 8
|
||||
{0, GL_LUMINANCE16, GL_LUMINANCE, GL_UNSIGNED_SHORT},// 1 x 16
|
||||
{0, GL_LUMINANCE16_ALPHA16, GL_LUMINANCE_ALPHA, GL_UNSIGNED_SHORT},// 2 x 16
|
||||
{0, GL_RGB16, GL_RGB, GL_UNSIGNED_SHORT},// 3 x 16
|
||||
{0, GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT},// 4 x 16
|
||||
};
|
||||
|
||||
static const struct fmt_entry gl_float16_formats[] = {
|
||||
{0, GL_R16F, GL_RED, GL_FLOAT}, // 1 x f
|
||||
{0, GL_RG16F, GL_RG, GL_FLOAT}, // 2 x f
|
||||
{0, GL_RGB16F, GL_RGB, GL_FLOAT}, // 3 x f
|
||||
{0, GL_RGBA16F, GL_RGBA, GL_FLOAT}, // 4 x f
|
||||
};
|
||||
|
||||
static const struct fmt_entry gl_apple_formats[] = {
|
||||
{IMGFMT_UYVY, GL_RGB, GL_RGB_422_APPLE, GL_UNSIGNED_SHORT_8_8_APPLE},
|
||||
{IMGFMT_YUYV, GL_RGB, GL_RGB_422_APPLE, GL_UNSIGNED_SHORT_8_8_REV_APPLE},
|
||||
{0}
|
||||
};
|
||||
|
||||
struct packed_fmt_entry {
|
||||
int fmt;
|
||||
int8_t component_size;
|
||||
@ -547,34 +464,6 @@ static void get_scale_factors(struct gl_video *p, bool transpose_rot, double xy[
|
||||
#define GLSLF(...) gl_sc_addf(p->sc, __VA_ARGS__)
|
||||
#define GLSLHF(...) gl_sc_haddf(p->sc, __VA_ARGS__)
|
||||
|
||||
// Return a fixed point texture format with given characteristics.
|
||||
static const struct fmt_entry *find_tex_format(GL *gl, int bytes_per_comp,
|
||||
int n_channels)
|
||||
{
|
||||
assert(bytes_per_comp == 1 || bytes_per_comp == 2);
|
||||
assert(n_channels >= 1 && n_channels <= 4);
|
||||
const struct fmt_entry *fmts = gl_byte_formats;
|
||||
if (gl->es && !(gl->mpgl_caps & MPGL_CAP_EXT16)) {
|
||||
fmts = gl->es >= 300 ? gl_byte_formats_gles3 : gl_byte_formats_gles2;
|
||||
} else if (!(gl->mpgl_caps & MPGL_CAP_TEX_RG)) {
|
||||
fmts = gl_byte_formats_legacy;
|
||||
}
|
||||
return &fmts[n_channels - 1 + (bytes_per_comp - 1) * 4];
|
||||
}
|
||||
|
||||
static bool is_integer_format(const struct fmt_entry *fmt)
|
||||
{
|
||||
// Tests only the formats which we actually declare somewhere.
|
||||
switch (fmt->format) {
|
||||
case GL_RED_INTEGER:
|
||||
case GL_RG_INTEGER:
|
||||
case GL_RGB_INTEGER:
|
||||
case GL_RGBA_INTEGER:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static const char *load_cached_file(struct gl_video *p, const char *path)
|
||||
{
|
||||
if (!path || !path[0])
|
||||
@ -1246,7 +1135,7 @@ static void reinit_scaler(struct gl_video *p, struct scaler *scaler,
|
||||
}
|
||||
int width = size / elems_per_pixel;
|
||||
assert(size == width * elems_per_pixel);
|
||||
const struct fmt_entry *fmt = &gl_float16_formats[elems_per_pixel - 1];
|
||||
const struct gl_format *fmt = gl_find_float16_format(gl, elems_per_pixel);
|
||||
GLenum target = scaler->gl_target;
|
||||
|
||||
gl->ActiveTexture(GL_TEXTURE0 + TEXUNIT_SCALERS + scaler->index);
|
||||
@ -1957,8 +1846,8 @@ static void pass_dither(struct gl_video *p)
|
||||
|
||||
int tex_size;
|
||||
void *tex_data;
|
||||
GLint tex_iformat;
|
||||
GLint tex_format;
|
||||
GLint tex_iformat = 0;
|
||||
GLint tex_format = 0;
|
||||
GLenum tex_type;
|
||||
unsigned char temp[256];
|
||||
|
||||
@ -1973,15 +1862,14 @@ static void pass_dither(struct gl_video *p)
|
||||
p->last_dither_matrix_size = size;
|
||||
}
|
||||
|
||||
const struct fmt_entry *fmt = find_tex_format(gl, 2, 1);
|
||||
tex_size = size;
|
||||
// Prefer R16 texture since they provide higher precision.
|
||||
if (fmt->internal_format && !gl->es) {
|
||||
const struct gl_format *fmt = gl_find_unorm_format(gl, 2, 1);
|
||||
if (!fmt || gl->es)
|
||||
fmt = gl_find_float16_format(gl, 1);
|
||||
tex_size = size;
|
||||
if (fmt) {
|
||||
tex_iformat = fmt->internal_format;
|
||||
tex_format = fmt->format;
|
||||
} else {
|
||||
tex_iformat = gl_float16_formats[0].internal_format;
|
||||
tex_format = gl_float16_formats[0].format;
|
||||
}
|
||||
tex_type = GL_FLOAT;
|
||||
tex_data = p->last_dither_matrix;
|
||||
@ -1989,7 +1877,7 @@ static void pass_dither(struct gl_video *p)
|
||||
assert(sizeof(temp) >= 8 * 8);
|
||||
mp_make_ordered_dither_matrix(temp, 8);
|
||||
|
||||
const struct fmt_entry *fmt = find_tex_format(gl, 1, 1);
|
||||
const struct gl_format *fmt = gl_find_unorm_format(gl, 1, 1);
|
||||
tex_size = 8;
|
||||
tex_iformat = fmt->internal_format;
|
||||
tex_format = fmt->format;
|
||||
@ -2004,7 +1892,7 @@ static void pass_dither(struct gl_video *p)
|
||||
gl->BindTexture(GL_TEXTURE_2D, p->dither_texture);
|
||||
gl->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
gl->TexImage2D(GL_TEXTURE_2D, 0, tex_iformat, tex_size, tex_size, 0,
|
||||
tex_format, tex_type, tex_data);
|
||||
tex_format, tex_type, tex_data);
|
||||
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
@ -2663,20 +2551,17 @@ static bool check_dumb_mode(struct gl_video *p)
|
||||
static void check_gl_features(struct gl_video *p)
|
||||
{
|
||||
GL *gl = p->gl;
|
||||
bool have_float_tex = gl->mpgl_caps & MPGL_CAP_FLOAT_TEX;
|
||||
bool have_fbo = gl->mpgl_caps & MPGL_CAP_FB;
|
||||
bool have_float_tex = !!gl_find_float16_format(gl, 1);
|
||||
bool have_3d_tex = gl->mpgl_caps & MPGL_CAP_3D_TEX;
|
||||
bool have_mix = gl->glsl_version >= 130;
|
||||
bool have_texrg = gl->mpgl_caps & MPGL_CAP_TEX_RG;
|
||||
|
||||
if (have_fbo) {
|
||||
if (!p->opts.fbo_format) {
|
||||
p->opts.fbo_format = GL_RGBA16;
|
||||
if (gl->es && !(gl->mpgl_caps & MPGL_CAP_EXT16))
|
||||
p->opts.fbo_format = have_float_tex ? GL_RGBA16F : GL_RGB10_A2;
|
||||
}
|
||||
have_fbo = test_fbo(p);
|
||||
if (!p->opts.fbo_format) {
|
||||
p->opts.fbo_format = GL_RGBA16;
|
||||
if (gl->es && !(gl->mpgl_caps & MPGL_CAP_EXT16))
|
||||
p->opts.fbo_format = have_float_tex ? GL_RGBA16F : GL_RGB10_A2;
|
||||
}
|
||||
bool have_fbo = test_fbo(p);
|
||||
|
||||
if (gl->es && p->opts.pbo) {
|
||||
p->opts.pbo = 0;
|
||||
@ -2798,8 +2683,8 @@ static void init_gl(struct gl_video *p)
|
||||
|
||||
// Test whether we can use 10 bit. Hope that testing a single format/channel
|
||||
// is good enough (instead of testing all 1-4 channels variants etc.).
|
||||
const struct fmt_entry *fmt = find_tex_format(gl, 2, 1);
|
||||
if (gl->GetTexLevelParameteriv && fmt->format) {
|
||||
const struct gl_format *fmt = gl_find_unorm_format(gl, 2, 1);
|
||||
if (gl->GetTexLevelParameteriv && fmt) {
|
||||
GLuint tex;
|
||||
gl->GenTextures(1, &tex);
|
||||
gl->BindTexture(GL_TEXTURE_2D, tex);
|
||||
@ -2873,7 +2758,7 @@ bool gl_video_showing_interpolated_frame(struct gl_video *p)
|
||||
}
|
||||
|
||||
// dest = src.<w> (always using 4 components)
|
||||
static void packed_fmt_swizzle(char w[5], const struct fmt_entry *texfmt,
|
||||
static void packed_fmt_swizzle(char w[5], const struct gl_format *texfmt,
|
||||
const struct packed_fmt_entry *fmt)
|
||||
{
|
||||
const char *comp = "rgba";
|
||||
@ -2887,15 +2772,15 @@ static void packed_fmt_swizzle(char w[5], const struct fmt_entry *texfmt,
|
||||
w[4] = '\0';
|
||||
}
|
||||
|
||||
// Like find_tex_format(), but takes bits (not bytes), and but if no fixed point
|
||||
// format is available, return an unsigned integer format.
|
||||
static const struct fmt_entry *find_plane_format(GL *gl, int bytes_per_comp,
|
||||
// Like gl_find_unorm_format(), but takes bits (not bytes), and but if no fixed
|
||||
// point format is available, return an unsigned integer format.
|
||||
static const struct gl_format *find_plane_format(GL *gl, int bytes_per_comp,
|
||||
int n_channels)
|
||||
{
|
||||
const struct fmt_entry *e = find_tex_format(gl, bytes_per_comp, n_channels);
|
||||
if (e->format || gl->es < 300)
|
||||
return e;
|
||||
return &gl_ui_byte_formats_gles3[n_channels - 1 + (bytes_per_comp - 1) * 4];
|
||||
const struct gl_format *f = gl_find_unorm_format(gl, bytes_per_comp, n_channels);
|
||||
if (f)
|
||||
return f;
|
||||
return gl_find_uint_format(gl, bytes_per_comp, n_channels);
|
||||
}
|
||||
|
||||
static void init_image_desc(struct gl_video *p, int fmt)
|
||||
@ -2924,7 +2809,7 @@ static bool init_format(struct gl_video *p, int fmt, bool test_only)
|
||||
if (desc.num_planes > 4)
|
||||
return false;
|
||||
|
||||
const struct fmt_entry *plane_format[4] = {0};
|
||||
const struct gl_format *plane_format[4] = {0};
|
||||
char color_swizzle[5] = "";
|
||||
|
||||
// YUV/planar formats
|
||||
@ -2955,37 +2840,27 @@ static bool init_format(struct gl_video *p, int fmt, bool test_only)
|
||||
|
||||
// XYZ (same organization as RGB packed, but requires conversion matrix)
|
||||
if (fmt == IMGFMT_XYZ12) {
|
||||
plane_format[0] = find_tex_format(gl, 2, 3);
|
||||
plane_format[0] = gl_find_unorm_format(gl, 2, 3);
|
||||
goto supported;
|
||||
}
|
||||
|
||||
// Packed RGB special formats
|
||||
for (const struct fmt_entry *e = mp_to_gl_formats; e->mp_format; e++) {
|
||||
if (!gl->es && e->mp_format == fmt) {
|
||||
plane_format[0] = e;
|
||||
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] = find_tex_format(gl, e->component_size, n_comp);
|
||||
plane_format[0] = gl_find_unorm_format(gl, e->component_size, n_comp);
|
||||
packed_fmt_swizzle(color_swizzle, plane_format[0], e);
|
||||
goto supported;
|
||||
}
|
||||
}
|
||||
|
||||
// Packed YUV Apple formats
|
||||
if (p->gl->mpgl_caps & MPGL_CAP_APPLE_RGB_422) {
|
||||
for (const struct fmt_entry *e = gl_apple_formats; e->mp_format; e++) {
|
||||
if (e->mp_format == fmt) {
|
||||
snprintf(color_swizzle, sizeof(color_swizzle), "gbra");
|
||||
plane_format[0] = 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
|
||||
@ -3000,9 +2875,9 @@ supported:
|
||||
|
||||
int use_integer = -1;
|
||||
for (int n = 0; n < desc.num_planes; n++) {
|
||||
if (!plane_format[n]->format)
|
||||
if (!plane_format[n])
|
||||
return false;
|
||||
int use_int_plane = !!is_integer_format(plane_format[n]);
|
||||
int use_int_plane = !!gl_integer_format_to_base(plane_format[n]->format);
|
||||
if (use_integer < 0)
|
||||
use_integer = use_int_plane;
|
||||
if (use_integer != use_int_plane)
|
||||
@ -3015,7 +2890,7 @@ supported:
|
||||
if (!test_only) {
|
||||
for (int n = 0; n < desc.num_planes; n++) {
|
||||
struct texplane *plane = &p->image.planes[n];
|
||||
const struct fmt_entry *format = plane_format[n];
|
||||
const struct gl_format *format = plane_format[n];
|
||||
assert(format);
|
||||
plane->gl_format = format->format;
|
||||
plane->gl_internal_format = format->internal_format;
|
||||
|
@ -342,6 +342,7 @@ def build(ctx):
|
||||
( "video/out/opengl/context_x11.c", "gl-x11" ),
|
||||
( "video/out/opengl/context_x11egl.c", "egl-x11" ),
|
||||
( "video/out/opengl/egl_helpers.c", "egl-helpers" ),
|
||||
( "video/out/opengl/formats.c", "gl" ),
|
||||
( "video/out/opengl/hwdec.c", "gl" ),
|
||||
( "video/out/opengl/hwdec_d3d11egl.c", "egl-angle" ),
|
||||
( "video/out/opengl/hwdec_dxva2.c", "gl-win32" ),
|
||||
|
Loading…
Reference in New Issue
Block a user