diff options
-rw-r--r-- | DOCS/man/options.rst | 22 | ||||
-rw-r--r-- | video/out/opengl/user_shaders.c | 79 | ||||
-rw-r--r-- | video/out/opengl/user_shaders.h | 12 | ||||
-rw-r--r-- | video/out/opengl/video.c | 28 |
4 files changed, 62 insertions, 79 deletions
diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index 814f6fe2d9..02cb4d826d 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -4249,20 +4249,22 @@ The following video options are currently all specific to ``--vo=opengl`` and The name of this texture. Hooks can then bind the texture under this name using BIND. This must be the first option of the texture block. - SIZE <width> [<height>] [<depth>] + SIZE <width> [<height>] [<depth>] (required) The dimensions of the texture. The height and depth are optional. The type of texture (1D, 2D or 3D) depends on the number of components specified. - COMPONENTS <n> - The number of components per texel contained in the texture. Defaults - to 1. - - FORMAT <spec> - The texture format for the samples. A valid texture specification is - the number of bits followed by a single letter which is either ``f`` - (for float), ``i`` (for uint) or ``u`` (for unorm), for example - ``32f``. Defaults to ``8i``. + FORMAT <name> (required) + The texture format for the samples. Supported texture formats are listed + in debug logging when the ``opengl`` VO is initialized (look for + ``Texture formats:``). Usually, this follows OpenGL naming conventions. + For example, ``rgb16`` provides 3 channels with normalized 16 bit + components. One oddity are float formats: for example, ``rgba16f`` has + 16 bit internal precision, but the texture data is provided as 32 bit + floats, and the driver converts the data on texture upload. + + Although format names follow a common naming convention, not all of them + are available on all hardware, drivers, GL versions, and so on. FILTER <LINEAR|NEAREST> The min/magnification filter used when sampling from this texture. diff --git a/video/out/opengl/user_shaders.c b/video/out/opengl/user_shaders.c index a2cb766d48..799367f3e1 100644 --- a/video/out/opengl/user_shaders.c +++ b/video/out/opengl/user_shaders.c @@ -286,16 +286,19 @@ static bool parse_hook(struct mp_log *log, struct bstr *body, return true; } -static bool parse_tex(struct mp_log *log, struct bstr *body, +static bool parse_tex(struct mp_log *log, struct ra *ra, struct bstr *body, struct gl_user_shader_tex *out) { *out = (struct gl_user_shader_tex){ .name = bstr0("USER_TEX"), - .w = 1, .h = 1, .d = 1, - .components = 1, - .bytes = 1, - .ctype = RA_CTYPE_UINT, + .params = { + .dimensions = 2, + .w = 1, .h = 1, .d = 1, + .render_src = true, + .src_linear = true, + }, }; + struct ra_tex_params *p = &out->params; while (true) { struct bstr rest; @@ -312,36 +315,29 @@ static bool parse_tex(struct mp_log *log, struct bstr *body, } if (bstr_eatstart0(&line, "SIZE")) { - int num = bstr_sscanf(line, "%d %d %d", &out->w, &out->h, &out->d); - if (num < 1 || num > 3 || out->w < 1 || out->h < 1 || out->d < 1) { + p->dimensions = bstr_sscanf(line, "%d %d %d", &p->w, &p->h, &p->d); + if (p->dimensions < 1 || p->dimensions > 3 || + p->w < 1 || p->h < 1 || p->d < 1) + { mp_err(log, "Error while parsing SIZE!\n"); return false; } - out->dimensions = num; continue; } - if (bstr_eatstart0(&line, "COMPONENTS")) { - if (bstr_sscanf(line, "%d", &out->components) != 1) { - mp_err(log, "Error while parsing COMPONENTS!\n"); - return false; - } - continue; - } - - if (bstr_eatstart0(&line, "FORMAT")) { - int bits; - char fmt; - if (bstr_sscanf(line, "%d%c", &bits, &fmt) != 2) { - mp_err(log, "Error while parsing FORMAT!\n"); - return false; + if (bstr_eatstart0(&line, "FORMAT ")) { + p->format = NULL; + for (int n = 0; n < ra->num_formats; n++) { + const struct ra_format *fmt = ra->formats[n]; + if (bstr_equals0(line, fmt->name)) { + p->format = fmt; + break; + } } - - out->bytes = bits / 8; - switch (fmt) { - case 'u': out->ctype = RA_CTYPE_UINT; break; - default: - mp_err(log, "Unrecognized FORMAT description: '%c'!\n", fmt); + // (pixel_size==0 is for opaque formats) + if (!p->format || !p->format->pixel_size) { + mp_err(log, "Unrecognized/unavailable FORMAT name: '%.*s'!\n", + BSTR_P(line)); return false; } continue; @@ -350,9 +346,9 @@ static bool parse_tex(struct mp_log *log, struct bstr *body, if (bstr_eatstart0(&line, "FILTER")) { line = bstr_strip(line); if (bstr_equals0(line, "LINEAR")) { - out->filter = true; + p->src_linear = true; } else if (bstr_equals0(line, "NEAREST")) { - out->filter = false; + p->src_linear = false; } else { mp_err(log, "Unrecognized FILTER: '%.*s'!\n", BSTR_P(line)); return false; @@ -363,9 +359,9 @@ static bool parse_tex(struct mp_log *log, struct bstr *body, if (bstr_eatstart0(&line, "BORDER")) { line = bstr_strip(line); if (bstr_equals0(line, "CLAMP")) { - out->border = GL_CLAMP_TO_EDGE; + p->src_repeat = false; } else if (bstr_equals0(line, "REPEAT")) { - out->border = true; + p->src_repeat = true; } else { mp_err(log, "Unrecognized BORDER: '%.*s'!\n", BSTR_P(line)); return false; @@ -377,6 +373,16 @@ static bool parse_tex(struct mp_log *log, struct bstr *body, return false; } + if (!p->format) { + mp_err(log, "No FORMAT specified.\n"); + return false; + } + + if (p->src_linear && !p->format->linear_filter) { + mp_err(log, "The specified texture format cannot be filtered!\n"); + return false; + } + // Decode the rest of the section (up to the next //! marker) as raw hex // data for the texture struct bstr hexdata; @@ -393,7 +399,7 @@ static bool parse_tex(struct mp_log *log, struct bstr *body, return false; } - int expected_len = out->w * out->h * out->d * out->components * out->bytes; + int expected_len = p->w * p->h * p->d * p->format->pixel_size; if (tex.len != expected_len) { mp_err(log, "Shader TEXTURE size mismatch: got %zd bytes, expected %d!\n", tex.len, expected_len); @@ -401,11 +407,12 @@ static bool parse_tex(struct mp_log *log, struct bstr *body, return false; } - out->texdata = tex.start; + p->initial_data = tex.start; return true; } -void parse_user_shader(struct mp_log *log, struct bstr shader, void *priv, +void parse_user_shader(struct mp_log *log, struct ra *ra, struct bstr shader, + void *priv, bool (*dohook)(void *p, struct gl_user_shader_hook hook), bool (*dotex)(void *p, struct gl_user_shader_tex tex)) { @@ -426,7 +433,7 @@ void parse_user_shader(struct mp_log *log, struct bstr shader, void *priv, // Peek at the first header to dispatch the right type if (bstr_startswith0(shader, "//!TEXTURE")) { struct gl_user_shader_tex t; - if (!parse_tex(log, &shader, &t) || !dotex(priv, t)) + if (!parse_tex(log, ra, &shader, &t) || !dotex(priv, t)) return; continue; } diff --git a/video/out/opengl/user_shaders.h b/video/out/opengl/user_shaders.h index bd36387de9..888422608c 100644 --- a/video/out/opengl/user_shaders.h +++ b/video/out/opengl/user_shaders.h @@ -72,21 +72,15 @@ struct gl_user_shader_hook { struct gl_user_shader_tex { struct bstr name; - int dimensions; - int w, h, d; - int components; - int bytes; - enum ra_ctype ctype; - bool filter; - bool border; - void *texdata; + struct ra_tex_params params; // for video.c struct ra_tex *tex; }; // Parse the next shader block from `body`. The callbacks are invoked on every // valid shader block parsed. -void parse_user_shader(struct mp_log *log, struct bstr shader, void *priv, +void parse_user_shader(struct mp_log *log, struct ra *ra, struct bstr shader, + void *priv, bool (*dohook)(void *p, struct gl_user_shader_hook hook), bool (*dotex)(void *p, struct gl_user_shader_tex tex)); diff --git a/video/out/opengl/video.c b/video/out/opengl/video.c index 0cd7ef3688..b6be230b53 100644 --- a/video/out/opengl/video.c +++ b/video/out/opengl/video.c @@ -1973,34 +1973,14 @@ static bool add_user_tex(void *priv, struct gl_user_shader_tex tex) goto err; } - const struct ra_format *format = ra_find_unorm_format(p->ra, tex.components, - tex.bytes); - - if (!format) { - MP_ERR(p, "Could not satisfy format requirements for user " - "shader texture '%.*s'!\n", BSTR_P(tex.name)); - goto err; - } - - struct ra_tex_params params = { - .dimensions = tex.dimensions, - .w = tex.w, - .h = tex.h, - .d = tex.d, - .format = format, - .render_src = true, - .src_linear = tex.filter, - .src_repeat = tex.border, - .initial_data = tex.texdata, - }; - tex.tex = ra_tex_create(p->ra, ¶ms); - talloc_free(tex.texdata); + tex.tex = ra_tex_create(p->ra, &tex.params); + TA_FREEP(&tex.params.initial_data); p->user_textures[p->user_tex_num++] = tex; return true; err: - talloc_free(tex.texdata); + talloc_free(tex.params.initial_data); return false; } @@ -2011,7 +1991,7 @@ static void load_user_shaders(struct gl_video *p, char **shaders) for (int n = 0; shaders[n] != NULL; n++) { struct bstr file = load_cached_file(p, shaders[n]); - parse_user_shader(p->log, file, p, add_user_hook, add_user_tex); + parse_user_shader(p->log, p->ra, file, p, add_user_hook, add_user_tex); } } |