mirror of
https://github.com/mpv-player/mpv.git
synced 2026-10-29 15:11:09 +08:00
Merge branch 'gl_rework'
This commit is contained in:
@@ -14,7 +14,6 @@
|
||||
/input/input_conf.h
|
||||
/tags
|
||||
/TAGS
|
||||
/video/out/gl_video_shaders.h
|
||||
/video/out/x11_icon.inc
|
||||
/demux/ebml_defs.c
|
||||
/demux/ebml_types.h
|
||||
|
||||
+44
-24
@@ -352,6 +352,10 @@ Available video output drivers are:
|
||||
blurrier. Defaults to 1. Note that setting this too low (eg. 0.5)
|
||||
leads to bad results. It's recommended to stay between 0.9 and 1.1.
|
||||
|
||||
``sharpen3``, ``sharpen5``
|
||||
Sharpening strength. Increasing this makes the image sharper but
|
||||
adds more ringing and aliasing. Defaults to 0.5.
|
||||
|
||||
``scale-radius=<r>``
|
||||
Set radius for filters listed below, must be a float number between 1.0
|
||||
and 16.0. Defaults to be 3.0 if not specified.
|
||||
@@ -377,21 +381,6 @@ Available video output drivers are:
|
||||
will reproduce the source image perfectly if no scaling is performed.
|
||||
Note that this option never affects ``cscale``.
|
||||
|
||||
``srgb``
|
||||
Convert and color correct the output to sRGB before displaying it on
|
||||
the screen. This option enables ``linear-scaling``.
|
||||
|
||||
This option is equivalent to using ``icc-profile`` with an sRGB ICC
|
||||
profile, but it is implemented without a 3DLUT and does not require
|
||||
LittleCMS 2. If both ``srgb`` and ``icc-profile`` are present, the
|
||||
latter takes precedence, as they are somewhat redundant.
|
||||
|
||||
Note: When playing back BT.2020 content with this option enabled, out
|
||||
of gamut colors will be numerically clipped, which can potentially
|
||||
change the hue and/or luminance. If this is not desired, it is
|
||||
recommended to use ``icc-profile`` with an sRGB ICC profile instead,
|
||||
when playing back wide-gamut BT.2020 content.
|
||||
|
||||
``pbo``
|
||||
Enable use of PBOs. This is slightly faster, but can sometimes lead to
|
||||
sporadic and temporary image corruption (in theory, because reupload
|
||||
@@ -460,9 +449,10 @@ Available video output drivers are:
|
||||
``scale-antiring``.
|
||||
|
||||
``linear-scaling``
|
||||
Scale in linear light. This is automatically enabled if ``srgb``,
|
||||
``icc-profile`` or ``sigmoid-upscaling`` is set. It should only
|
||||
be used with a ``fbo-format`` that has at least 16 bit precision.
|
||||
Scale in linear light. This is automatically enabled if
|
||||
``target-prim``, ``target-trc``, ``icc-profile`` or
|
||||
``sigmoid-upscaling`` is set. It should only be used with a
|
||||
``fbo-format`` that has at least 16 bit precision.
|
||||
|
||||
``fancy-downscaling``
|
||||
When using convolution based filters, extend the filter size
|
||||
@@ -553,13 +543,44 @@ Available video output drivers are:
|
||||
|
||||
NOTE: Only implemented on OS X.
|
||||
|
||||
``target-prim=<value>``
|
||||
Specifies the primaries of the display. Video colors will be adapted
|
||||
to this colorspace if necessary. Valid values are:
|
||||
|
||||
auto
|
||||
Disable any adaptation (default)
|
||||
bt470m
|
||||
ITU-R BT.470 M
|
||||
bt601-525
|
||||
ITU-R BT.601 (525-line SD systems, eg. NTSC), SMPTE 170M/240M
|
||||
bt601-625
|
||||
ITU-R BT.601 (625-line SD systems, eg. PAL/SECAM), ITU-R BT.470 B/G
|
||||
bt709
|
||||
ITU-R BT.709 (HD), IEC 61966-2-4 (sRGB), SMPTE RP177 Annex B
|
||||
bt2020
|
||||
ITU-R BT.2020 (UHD)
|
||||
|
||||
``target-trc=<value>``
|
||||
Specifies the transfer characteristics (gamma) of the display. Video
|
||||
colors will be adjusted to this curve. Valid values are:
|
||||
|
||||
auto
|
||||
Disable any adaptation (default)
|
||||
bt1886
|
||||
ITU-R BT.1886 curve, without the brightness drop (approx. 1.961)
|
||||
srgb
|
||||
IEC 61966-2-4 (sRGB)
|
||||
linear
|
||||
Linear light output
|
||||
gamma22
|
||||
Pure power curve (gamma 2.2)
|
||||
|
||||
``icc-profile=<file>``
|
||||
Load an ICC profile and use it to transform linear RGB to screen output.
|
||||
Needs LittleCMS 2 support compiled in. This option overrides the ``srgb``
|
||||
property, as using both is somewhat redundant. It also enables
|
||||
Needs LittleCMS 2 support compiled in. This option overrides the
|
||||
``target-prim`` and ``target-trc`` options. It also enables
|
||||
``linear-scaling``.
|
||||
|
||||
|
||||
``icc-profile-auto``
|
||||
Automatically select the ICC display profile currently specified by
|
||||
the display settings of the operating system.
|
||||
@@ -573,9 +594,8 @@ Available video output drivers are:
|
||||
Its size depends on the ``3dlut-size``, and can be very big.
|
||||
|
||||
``icc-intent=<value>``
|
||||
Specifies the ICC Intent used for transformations between color spaces.
|
||||
This affects the rendering when using ``icc-profile`` or ``srgb`` and
|
||||
also affects the way DCP XYZ content gets converted to RGB.
|
||||
Specifies the ICC intent used for the color transformation (when using
|
||||
``icc-profile``).
|
||||
|
||||
0
|
||||
perceptual
|
||||
|
||||
@@ -358,10 +358,6 @@ demux/ebml.c: demux/ebml_defs.c
|
||||
demux/ebml_defs.c: TOOLS/matroska.pl $(MKVLIB_DEPS)
|
||||
./$< --generate-definitions > $@
|
||||
|
||||
video/out/gl_video.c: video/out/gl_video_shaders.h
|
||||
video/out/gl_video_shaders.h: TOOLS/file2string.pl video/out/gl_video_shaders.glsl
|
||||
./$^ >$@
|
||||
|
||||
video/out/x11_common.c: video/out/x11_icon.inc
|
||||
video/out/x11_icon.inc: TOOLS/file2string.pl video/out/x11_icon.bin
|
||||
./$^ >$@
|
||||
@@ -475,7 +471,6 @@ clean:
|
||||
-$(RM) input/input_conf.h
|
||||
-$(RM) video/out/vdpau_template.c
|
||||
-$(RM) demux/ebml_types.h demux/ebml_defs.c
|
||||
-$(RM) video/out/gl_video_shaders.h
|
||||
-$(RM) video/out/x11_icon.inc
|
||||
-$(RM) sub/osd_font.h
|
||||
-$(RM) player/lua/defaults.inc
|
||||
|
||||
@@ -70,6 +70,7 @@ const char *const mp_csp_trc_names[MP_CSP_TRC_COUNT] = {
|
||||
"BT.1886 (SD, HD, UHD)",
|
||||
"sRGB (IEC 61966-2-1)",
|
||||
"Linear light",
|
||||
"Pure power (gamma 2.2)",
|
||||
};
|
||||
|
||||
const char *const mp_csp_equalizer_names[MP_CSP_EQ_COUNT] = {
|
||||
@@ -156,6 +157,7 @@ enum mp_csp_trc avcol_trc_to_mp_csp_trc(int avtrc)
|
||||
case AVCOL_TRC_BT2020_12: return MP_CSP_TRC_BT_1886;
|
||||
case AVCOL_TRC_IEC61966_2_1: return MP_CSP_TRC_SRGB;
|
||||
case AVCOL_TRC_LINEAR: return MP_CSP_TRC_LINEAR;
|
||||
case AVCOL_TRC_GAMMA22: return MP_CSP_TRC_GAMMA22;
|
||||
default: return MP_CSP_TRC_AUTO;
|
||||
}
|
||||
}
|
||||
@@ -202,6 +204,7 @@ int mp_csp_trc_to_avcol_trc(enum mp_csp_trc trc)
|
||||
case MP_CSP_TRC_BT_1886: return AVCOL_TRC_BT709;
|
||||
case MP_CSP_TRC_SRGB: return AVCOL_TRC_IEC61966_2_1;
|
||||
case MP_CSP_TRC_LINEAR: return AVCOL_TRC_LINEAR;
|
||||
case MP_CSP_TRC_GAMMA22: return AVCOL_TRC_GAMMA22;
|
||||
default: return AVCOL_TRC_UNSPECIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +76,7 @@ enum mp_csp_trc {
|
||||
MP_CSP_TRC_BT_1886,
|
||||
MP_CSP_TRC_SRGB,
|
||||
MP_CSP_TRC_LINEAR,
|
||||
MP_CSP_TRC_GAMMA22,
|
||||
MP_CSP_TRC_COUNT
|
||||
};
|
||||
|
||||
|
||||
+125
-77
@@ -55,20 +55,46 @@ static const struct osd_fmt_entry osd_to_gl2_formats[SUBBITMAP_COUNT] = {
|
||||
|
||||
struct vertex {
|
||||
float position[2];
|
||||
uint8_t color[4];
|
||||
float texcoord[2];
|
||||
uint8_t ass_color[4];
|
||||
};
|
||||
|
||||
static const struct gl_vao_entry vertex_vao[] = {
|
||||
{"vertex_position", 2, GL_FLOAT, false, offsetof(struct vertex, position)},
|
||||
{"vertex_color", 4, GL_UNSIGNED_BYTE, true, offsetof(struct vertex, color)},
|
||||
{"vertex_texcoord", 2, GL_FLOAT, false, offsetof(struct vertex, texcoord)},
|
||||
{"position", 2, GL_FLOAT, false, offsetof(struct vertex, position)},
|
||||
{"texcoord" , 2, GL_FLOAT, false, offsetof(struct vertex, texcoord)},
|
||||
{"ass_color", 4, GL_UNSIGNED_BYTE, true, offsetof(struct vertex, ass_color)},
|
||||
{0}
|
||||
};
|
||||
|
||||
// programs: SUBBITMAP_COUNT elements
|
||||
struct mpgl_osd *mpgl_osd_init(GL *gl, struct mp_log *log, struct osd_state *osd,
|
||||
GLuint *programs)
|
||||
struct mpgl_osd_part {
|
||||
enum sub_bitmap_format format;
|
||||
int bitmap_id, bitmap_pos_id;
|
||||
GLuint texture;
|
||||
int w, h;
|
||||
GLuint buffer;
|
||||
int num_subparts;
|
||||
struct sub_bitmap *subparts;
|
||||
struct vertex *vertices;
|
||||
struct bitmap_packer *packer;
|
||||
};
|
||||
|
||||
struct mpgl_osd {
|
||||
struct mp_log *log;
|
||||
struct osd_state *osd;
|
||||
GL *gl;
|
||||
bool use_pbo;
|
||||
bool scaled;
|
||||
struct mpgl_osd_part *parts[MAX_OSD_PARTS];
|
||||
const struct osd_fmt_entry *fmt_table;
|
||||
bool formats[SUBBITMAP_COUNT];
|
||||
struct gl_vao vao;
|
||||
// temporary
|
||||
int stereo_mode;
|
||||
int display_size[2];
|
||||
void *scratch;
|
||||
};
|
||||
|
||||
struct mpgl_osd *mpgl_osd_init(GL *gl, struct mp_log *log, struct osd_state *osd)
|
||||
{
|
||||
GLint max_texture_size;
|
||||
gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
|
||||
@@ -79,7 +105,6 @@ struct mpgl_osd *mpgl_osd_init(GL *gl, struct mp_log *log, struct osd_state *osd
|
||||
.osd = osd,
|
||||
.gl = gl,
|
||||
.fmt_table = osd_to_gl3_formats,
|
||||
.programs = programs,
|
||||
.scratch = talloc_zero_size(ctx, 1),
|
||||
};
|
||||
|
||||
@@ -126,6 +151,11 @@ void mpgl_osd_destroy(struct mpgl_osd *ctx)
|
||||
talloc_free(ctx);
|
||||
}
|
||||
|
||||
void mpgl_osd_set_options(struct mpgl_osd *ctx, bool pbo)
|
||||
{
|
||||
ctx->use_pbo = pbo;
|
||||
}
|
||||
|
||||
static bool upload_pbo(struct mpgl_osd *ctx, struct mpgl_osd_part *osd,
|
||||
struct sub_bitmaps *imgs)
|
||||
{
|
||||
@@ -154,8 +184,7 @@ static bool upload_pbo(struct mpgl_osd *ctx, struct mpgl_osd_part *osd,
|
||||
if (!gl->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER))
|
||||
success = false;
|
||||
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);
|
||||
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);
|
||||
|
||||
@@ -240,11 +269,12 @@ static bool upload_osd(struct mpgl_osd *ctx, struct mpgl_osd_part *osd,
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct mpgl_osd_part *mpgl_osd_generate(struct mpgl_osd *ctx,
|
||||
struct sub_bitmaps *imgs)
|
||||
static void gen_osd_cb(void *pctx, struct sub_bitmaps *imgs)
|
||||
{
|
||||
struct mpgl_osd *ctx = pctx;
|
||||
|
||||
if (imgs->num_parts == 0 || !ctx->formats[imgs->format])
|
||||
return NULL;
|
||||
return;
|
||||
|
||||
struct mpgl_osd_part *osd = ctx->parts[imgs->render_index];
|
||||
|
||||
@@ -256,83 +286,76 @@ static struct mpgl_osd_part *mpgl_osd_generate(struct mpgl_osd *ctx,
|
||||
|
||||
osd->bitmap_id = imgs->bitmap_id;
|
||||
osd->bitmap_pos_id = imgs->bitmap_pos_id;
|
||||
osd->num_vertices = 0;
|
||||
}
|
||||
osd->num_subparts = osd->packer->count;
|
||||
|
||||
return osd->packer->count ? osd : NULL;
|
||||
MP_TARRAY_GROW(osd, osd->subparts, osd->num_subparts);
|
||||
memcpy(osd->subparts, imgs->parts,
|
||||
osd->num_subparts * sizeof(osd->subparts[0]));
|
||||
}
|
||||
|
||||
static void write_quad(struct vertex *va,
|
||||
static void write_quad(struct vertex *va, float matrix[3][2],
|
||||
float x0, float y0, float x1, float y1,
|
||||
float tx0, float ty0, float tx1, float ty1,
|
||||
float tex_w, float tex_h, const uint8_t color[4])
|
||||
{
|
||||
gl_matrix_mul_vec(matrix, &x0, &y0);
|
||||
gl_matrix_mul_vec(matrix, &x1, &y1);
|
||||
|
||||
#define COLOR_INIT {color[0], color[1], color[2], color[3]}
|
||||
va[0] = (struct vertex){ {x0, y0}, COLOR_INIT, {tx0 / tex_w, ty0 / tex_h} };
|
||||
va[1] = (struct vertex){ {x0, y1}, COLOR_INIT, {tx0 / tex_w, ty1 / tex_h} };
|
||||
va[2] = (struct vertex){ {x1, y0}, COLOR_INIT, {tx1 / tex_w, ty0 / tex_h} };
|
||||
va[3] = (struct vertex){ {x1, y1}, COLOR_INIT, {tx1 / tex_w, ty1 / tex_h} };
|
||||
va[0] = (struct vertex){ {x0, y0}, {tx0 / tex_w, ty0 / tex_h}, COLOR_INIT };
|
||||
va[1] = (struct vertex){ {x0, y1}, {tx0 / tex_w, ty1 / tex_h}, COLOR_INIT };
|
||||
va[2] = (struct vertex){ {x1, y0}, {tx1 / tex_w, ty0 / tex_h}, COLOR_INIT };
|
||||
va[3] = (struct vertex){ {x1, y1}, {tx1 / tex_w, ty1 / tex_h}, COLOR_INIT };
|
||||
va[4] = va[2];
|
||||
va[5] = va[1];
|
||||
#undef COLOR_INIT
|
||||
}
|
||||
|
||||
static void draw_osd_cb(void *pctx, struct sub_bitmaps *imgs)
|
||||
static int generate_verts(struct mpgl_osd_part *part, float matrix[3][2])
|
||||
{
|
||||
struct mpgl_osd *ctx = pctx;
|
||||
GL *gl = ctx->gl;
|
||||
|
||||
struct mpgl_osd_part *part = mpgl_osd_generate(ctx, imgs);
|
||||
if (!part)
|
||||
return;
|
||||
|
||||
assert(part->format != SUBBITMAP_EMPTY);
|
||||
|
||||
if (!part->num_vertices) {
|
||||
part->vertices = talloc_realloc(part, part->vertices, struct vertex,
|
||||
part->packer->count * 6);
|
||||
int num_vertices = part->num_subparts * 6;
|
||||
MP_TARRAY_GROW(part, part->vertices, num_vertices);
|
||||
|
||||
for (int n = 0; n < part->num_subparts; n++) {
|
||||
struct sub_bitmap *b = &part->subparts[n];
|
||||
struct pos pos = part->packer->result[n];
|
||||
struct vertex *va = part->vertices;
|
||||
|
||||
for (int n = 0; n < part->packer->count; n++) {
|
||||
struct sub_bitmap *b = &imgs->parts[n];
|
||||
struct pos pos = part->packer->result[n];
|
||||
// NOTE: the blend color is used with SUBBITMAP_LIBASS only, so it
|
||||
// doesn't matter that we upload garbage for the other formats
|
||||
uint32_t c = b->libass.color;
|
||||
uint8_t color[4] = { c >> 24, (c >> 16) & 0xff,
|
||||
(c >> 8) & 0xff, 255 - (c & 0xff) };
|
||||
|
||||
// NOTE: the blend color is used with SUBBITMAP_LIBASS only, so it
|
||||
// doesn't matter that we upload garbage for the other formats
|
||||
uint32_t c = b->libass.color;
|
||||
uint8_t color[4] = { c >> 24, (c >> 16) & 0xff,
|
||||
(c >> 8) & 0xff, 255 - (c & 0xff) };
|
||||
|
||||
write_quad(&va[part->num_vertices],
|
||||
b->x, b->y, b->x + b->dw, b->y + b->dh,
|
||||
pos.x, pos.y, pos.x + b->w, pos.y + b->h,
|
||||
part->w, part->h, color);
|
||||
part->num_vertices += 6;
|
||||
}
|
||||
write_quad(&va[n * 6], matrix,
|
||||
b->x, b->y, b->x + b->dw, b->y + b->dh,
|
||||
pos.x, pos.y, pos.x + b->w, pos.y + b->h,
|
||||
part->w, part->h, color);
|
||||
}
|
||||
|
||||
return num_vertices;
|
||||
}
|
||||
|
||||
static void draw_part(struct mpgl_osd *ctx, int index, float matrix[3][2])
|
||||
{
|
||||
GL *gl = ctx->gl;
|
||||
struct mpgl_osd_part *part = ctx->parts[index];
|
||||
|
||||
int num_vertices = generate_verts(part, matrix);
|
||||
if (!num_vertices)
|
||||
return;
|
||||
|
||||
gl->Enable(GL_BLEND);
|
||||
gl->BindTexture(GL_TEXTURE_2D, part->texture);
|
||||
|
||||
const int *factors = &blend_factors[part->format][0];
|
||||
gl->BlendFuncSeparate(factors[0], factors[1], factors[2], factors[3]);
|
||||
int program = ctx->programs[part->format];
|
||||
|
||||
gl->UseProgram(program);
|
||||
gl_vao_draw_data(&ctx->vao, GL_TRIANGLES, part->vertices, num_vertices);
|
||||
|
||||
bool set_offset = ctx->offset[0] != 0.0f || ctx->offset[1] != 0.0f;
|
||||
if (set_offset) {
|
||||
gl->Uniform3f(gl->GetUniformLocation(program, "translation"),
|
||||
ctx->offset[0], ctx->offset[1], 0);
|
||||
}
|
||||
|
||||
gl_vao_draw_data(&ctx->vao, GL_TRIANGLES, part->vertices, part->num_vertices);
|
||||
|
||||
if (set_offset)
|
||||
gl->Uniform3f(gl->GetUniformLocation(program, "translation"), 0, 0, 0);
|
||||
|
||||
gl->UseProgram(0);
|
||||
gl->BindTexture(GL_TEXTURE_2D, 0);
|
||||
gl->Disable(GL_BLEND);
|
||||
}
|
||||
|
||||
// number of screen divisions per axis (x=0, y=1) for the current 3D mode
|
||||
@@ -347,26 +370,51 @@ static void get_3d_side_by_side(int stereo_mode, int div[2])
|
||||
}
|
||||
}
|
||||
|
||||
void mpgl_osd_draw(struct mpgl_osd *ctx, struct mp_osd_res res, double pts,
|
||||
int stereo_mode)
|
||||
void mpgl_osd_draw_part(struct mpgl_osd *ctx, int vp_w, int vp_h, int index)
|
||||
{
|
||||
GL *gl = ctx->gl;
|
||||
int div[2];
|
||||
get_3d_side_by_side(ctx->stereo_mode, div);
|
||||
|
||||
gl->Enable(GL_BLEND);
|
||||
for (int x = 0; x < div[0]; x++) {
|
||||
for (int y = 0; y < div[1]; y++) {
|
||||
float matrix[3][2];
|
||||
|
||||
gl_matrix_ortho2d(matrix, 0, vp_w, 0, vp_h);
|
||||
|
||||
float a_x = ctx->display_size[0] * x;
|
||||
float a_y = ctx->display_size[1] * y;
|
||||
matrix[2][0] += a_x * matrix[0][0] + a_y * matrix[1][0];
|
||||
matrix[2][1] += a_x * matrix[0][1] + a_y * matrix[1][1];
|
||||
|
||||
draw_part(ctx, index, matrix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum sub_bitmap_format mpgl_osd_get_part_format(struct mpgl_osd *ctx, int index)
|
||||
{
|
||||
assert(index >= 0 && index < MAX_OSD_PARTS);
|
||||
return ctx->parts[index]->format;
|
||||
}
|
||||
|
||||
struct gl_vao *mpgl_osd_get_vao(struct mpgl_osd *ctx)
|
||||
{
|
||||
return &ctx->vao;
|
||||
}
|
||||
|
||||
void mpgl_osd_generate(struct mpgl_osd *ctx, struct mp_osd_res res, double pts,
|
||||
int stereo_mode)
|
||||
{
|
||||
for (int n = 0; n < MAX_OSD_PARTS; n++)
|
||||
ctx->parts[n]->num_subparts = 0;
|
||||
|
||||
int div[2];
|
||||
get_3d_side_by_side(stereo_mode, div);
|
||||
|
||||
for (int x = 0; x < div[0]; x++) {
|
||||
for (int y = 0; y < div[1]; y++) {
|
||||
struct mp_osd_res s_res = res;
|
||||
s_res.w /= div[0];
|
||||
s_res.h /= div[1];
|
||||
ctx->offset[0] = s_res.w * x;
|
||||
ctx->offset[1] = s_res.h * y;
|
||||
osd_draw(ctx->osd, s_res, pts, 0, ctx->formats, draw_osd_cb, ctx);
|
||||
}
|
||||
}
|
||||
struct mp_osd_res s_res = res;
|
||||
ctx->display_size[0] = s_res.w = s_res.w / div[0];
|
||||
ctx->display_size[1] = s_res.h = s_res.h / div[1];
|
||||
|
||||
gl->Disable(GL_BLEND);
|
||||
osd_draw(ctx->osd, s_res, pts, 0, ctx->formats, gen_osd_cb, ctx);
|
||||
ctx->stereo_mode = stereo_mode;
|
||||
}
|
||||
|
||||
+8
-31
@@ -7,38 +7,15 @@
|
||||
#include "gl_utils.h"
|
||||
#include "sub/osd.h"
|
||||
|
||||
struct mpgl_osd_part {
|
||||
enum sub_bitmap_format format;
|
||||
int bitmap_id, bitmap_pos_id;
|
||||
GLuint texture;
|
||||
int w, h;
|
||||
GLuint buffer;
|
||||
int num_vertices;
|
||||
void *vertices;
|
||||
struct bitmap_packer *packer;
|
||||
};
|
||||
|
||||
struct mpgl_osd {
|
||||
struct mp_log *log;
|
||||
struct osd_state *osd;
|
||||
GL *gl;
|
||||
bool use_pbo;
|
||||
bool scaled;
|
||||
struct mpgl_osd_part *parts[MAX_OSD_PARTS];
|
||||
const struct osd_fmt_entry *fmt_table;
|
||||
bool formats[SUBBITMAP_COUNT];
|
||||
struct gl_vao vao;
|
||||
GLuint *programs; // SUBBITMAP_COUNT elements
|
||||
// temporary
|
||||
float offset[2];
|
||||
void *scratch;
|
||||
};
|
||||
|
||||
struct mpgl_osd *mpgl_osd_init(GL *gl, struct mp_log *log, struct osd_state *osd,
|
||||
GLuint *programs);
|
||||
struct mpgl_osd *mpgl_osd_init(GL *gl, struct mp_log *log, struct osd_state *osd);
|
||||
void mpgl_osd_destroy(struct mpgl_osd *ctx);
|
||||
|
||||
void mpgl_osd_draw(struct mpgl_osd *ctx, struct mp_osd_res res, double pts,
|
||||
int stereo_mode);
|
||||
void mpgl_osd_set_options(struct mpgl_osd *ctx, bool pbo);
|
||||
|
||||
void mpgl_osd_generate(struct mpgl_osd *ctx, struct mp_osd_res res, double pts,
|
||||
int stereo_mode);
|
||||
enum sub_bitmap_format mpgl_osd_get_part_format(struct mpgl_osd *ctx, int index);
|
||||
struct gl_vao *mpgl_osd_get_vao(struct mpgl_osd *ctx);
|
||||
void mpgl_osd_draw_part(struct mpgl_osd *ctx, int vp_w, int vp_h, int index);
|
||||
|
||||
#endif
|
||||
|
||||
+477
-25
@@ -25,6 +25,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "common/common.h"
|
||||
@@ -290,14 +291,6 @@ void gl_vao_unbind(struct gl_vao *vao)
|
||||
}
|
||||
}
|
||||
|
||||
void gl_vao_bind_attribs(struct gl_vao *vao, GLuint program)
|
||||
{
|
||||
GL *gl = vao->gl;
|
||||
|
||||
for (int n = 0; vao->entries[n].name; n++)
|
||||
gl->BindAttribLocation(program, n, vao->entries[n].name);
|
||||
}
|
||||
|
||||
// Draw the vertex data (as described by the gl_vao_entry entries) in ptr
|
||||
// to the screen. num is the number of vertexes. prim is usually GL_TRIANGLES.
|
||||
// If ptr is NULL, then skip the upload, and use the data uploaded with the
|
||||
@@ -320,24 +313,47 @@ void gl_vao_draw_data(struct gl_vao *vao, GLenum prim, void *ptr, size_t num)
|
||||
}
|
||||
|
||||
// Create a texture and a FBO using the texture as color attachments.
|
||||
// gl_target: GL_TEXTURE_2D
|
||||
// gl_filter: GL_LINEAR
|
||||
// iformat: texture internal format
|
||||
// Returns success.
|
||||
bool fbotex_init(struct fbotex *fbo, GL *gl, struct mp_log *log, int w, int h,
|
||||
GLenum gl_target, GLenum gl_filter, GLenum iformat)
|
||||
GLenum iformat)
|
||||
{
|
||||
assert(!fbo->fbo);
|
||||
assert(!fbo->texture);
|
||||
return fbotex_change(fbo, gl, log, w, h, iformat, 0);
|
||||
}
|
||||
|
||||
// Like fbotex_init(), except it can be called on an already initialized FBO;
|
||||
// and if the parameters are the same as the previous call, do not touch it.
|
||||
// flags can be 0, or a combination of FBOTEX_FUZZY_W and FBOTEX_FUZZY_H.
|
||||
// Enabling FUZZY for W or H means the w or h does not need to be exact.
|
||||
bool fbotex_change(struct fbotex *fbo, GL *gl, struct mp_log *log, int w, int h,
|
||||
GLenum iformat, int flags)
|
||||
{
|
||||
bool res = true;
|
||||
|
||||
assert(!fbo->fbo);
|
||||
assert(!fbo->texture);
|
||||
int cw = w, ch = h;
|
||||
|
||||
if ((flags & FBOTEX_FUZZY_W) && cw < fbo->tex_w)
|
||||
cw = fbo->tex_w;
|
||||
if ((flags & FBOTEX_FUZZY_H) && ch < fbo->tex_h)
|
||||
ch = fbo->tex_h;
|
||||
|
||||
if (fbo->tex_w == cw && fbo->tex_h == ch && fbo->iformat == iformat)
|
||||
return true;
|
||||
|
||||
if (flags & FBOTEX_FUZZY_W)
|
||||
w = MP_ALIGN_UP(w, 256);
|
||||
if (flags & FBOTEX_FUZZY_H)
|
||||
h = MP_ALIGN_UP(h, 256);
|
||||
|
||||
GLenum filter = fbo->tex_filter;
|
||||
|
||||
*fbo = (struct fbotex) {
|
||||
.gl = gl,
|
||||
.vp_w = w,
|
||||
.vp_h = h,
|
||||
.tex_w = w,
|
||||
.tex_h = h,
|
||||
.iformat = iformat,
|
||||
};
|
||||
|
||||
mp_verbose(log, "Create FBO: %dx%d\n", fbo->tex_w, fbo->tex_h);
|
||||
@@ -347,19 +363,20 @@ bool fbotex_init(struct fbotex *fbo, GL *gl, struct mp_log *log, int w, int h,
|
||||
|
||||
gl->GenFramebuffers(1, &fbo->fbo);
|
||||
gl->GenTextures(1, &fbo->texture);
|
||||
gl->BindTexture(gl_target, fbo->texture);
|
||||
gl->TexImage2D(gl_target, 0, iformat, fbo->tex_w, fbo->tex_h, 0,
|
||||
gl->BindTexture(GL_TEXTURE_2D, fbo->texture);
|
||||
gl->TexImage2D(GL_TEXTURE_2D, 0, iformat, fbo->tex_w, fbo->tex_h, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
gl->TexParameteri(gl_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
gl->TexParameteri(gl_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
gl->TexParameteri(gl_target, GL_TEXTURE_MIN_FILTER, gl_filter);
|
||||
gl->TexParameteri(gl_target, GL_TEXTURE_MAG_FILTER, gl_filter);
|
||||
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);
|
||||
|
||||
fbotex_set_filter(fbo, filter ? filter : GL_LINEAR);
|
||||
|
||||
glCheckError(gl, log, "after creating framebuffer texture");
|
||||
|
||||
gl->BindFramebuffer(GL_FRAMEBUFFER, fbo->fbo);
|
||||
gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
gl_target, fbo->texture, 0);
|
||||
GL_TEXTURE_2D, fbo->texture, 0);
|
||||
|
||||
GLenum err = gl->CheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (err != GL_FRAMEBUFFER_COMPLETE) {
|
||||
@@ -375,6 +392,19 @@ bool fbotex_init(struct fbotex *fbo, GL *gl, struct mp_log *log, int w, int h,
|
||||
return res;
|
||||
}
|
||||
|
||||
void fbotex_set_filter(struct fbotex *fbo, GLenum tex_filter)
|
||||
{
|
||||
GL *gl = fbo->gl;
|
||||
|
||||
if (fbo->tex_filter != tex_filter && fbo->texture) {
|
||||
gl->BindTexture(GL_TEXTURE_2D, fbo->texture);
|
||||
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, tex_filter);
|
||||
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, tex_filter);
|
||||
gl->BindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
fbo->tex_filter = tex_filter;
|
||||
}
|
||||
|
||||
void fbotex_uninit(struct fbotex *fbo)
|
||||
{
|
||||
GL *gl = fbo->gl;
|
||||
@@ -386,14 +416,22 @@ void fbotex_uninit(struct fbotex *fbo)
|
||||
}
|
||||
}
|
||||
|
||||
void gl_matrix_ortho2d(float m[3][3], float x0, float x1, float y0, float y1)
|
||||
// Standard parallel 2D projection, except y1 < y0 means that the coordinate
|
||||
// system is flipped, not the projection.
|
||||
void gl_matrix_ortho2d(float m[3][2], float x0, float x1, float y0, float y1)
|
||||
{
|
||||
memset(m, 0, 9 * sizeof(float));
|
||||
if (y1 < y0) {
|
||||
float t = y0;
|
||||
y0 = t - y1;
|
||||
y1 = t;
|
||||
}
|
||||
|
||||
m[0][0] = 2.0f / (x1 - x0);
|
||||
m[0][1] = 0.0f;
|
||||
m[1][0] = 0.0f;
|
||||
m[1][1] = 2.0f / (y1 - y0);
|
||||
m[2][0] = -(x1 + x0) / (x1 - x0);
|
||||
m[2][1] = -(y1 + y0) / (y1 - y0);
|
||||
m[2][2] = 1.0f;
|
||||
}
|
||||
|
||||
static void GLAPIENTRY gl_debug_cb(GLenum source, GLenum type, GLuint id,
|
||||
@@ -422,3 +460,417 @@ void gl_set_debug_logger(GL *gl, struct mp_log *log)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define SC_ENTRIES 10
|
||||
#define SC_UNIFORM_ENTRIES 20
|
||||
|
||||
enum uniform_type {
|
||||
UT_invalid,
|
||||
UT_i,
|
||||
UT_f,
|
||||
UT_m,
|
||||
};
|
||||
|
||||
struct sc_uniform {
|
||||
char *name;
|
||||
enum uniform_type type;
|
||||
const char *glsl_type;
|
||||
int size;
|
||||
GLint loc;
|
||||
union {
|
||||
GLfloat f[9];
|
||||
GLint i[4];
|
||||
} v;
|
||||
};
|
||||
|
||||
struct sc_entry {
|
||||
GLuint gl_shader;
|
||||
// the following fields define the shader's contents
|
||||
char *key; // vertex+frag shader (mangled)
|
||||
struct gl_vao *vao;
|
||||
};
|
||||
|
||||
struct gl_shader_cache {
|
||||
GL *gl;
|
||||
struct mp_log *log;
|
||||
|
||||
// this is modified during use (gl_sc_add() etc.)
|
||||
char *text;
|
||||
struct gl_vao *vao;
|
||||
|
||||
struct sc_entry entries[SC_ENTRIES];
|
||||
int num_entries;
|
||||
|
||||
struct sc_uniform uniforms[SC_UNIFORM_ENTRIES];
|
||||
int num_uniforms;
|
||||
};
|
||||
|
||||
struct gl_shader_cache *gl_sc_create(GL *gl, struct mp_log *log)
|
||||
{
|
||||
struct gl_shader_cache *sc = talloc_ptrtype(NULL, sc);
|
||||
*sc = (struct gl_shader_cache){
|
||||
.gl = gl,
|
||||
.log = log,
|
||||
.text = talloc_strdup(sc, ""),
|
||||
};
|
||||
return sc;
|
||||
}
|
||||
|
||||
void gl_sc_reset(struct gl_shader_cache *sc)
|
||||
{
|
||||
sc->text[0] = '\0';
|
||||
for (int n = 0; n < sc->num_uniforms; n++)
|
||||
talloc_free(sc->uniforms[n].name);
|
||||
sc->num_uniforms = 0;
|
||||
}
|
||||
|
||||
static void sc_flush_cache(struct gl_shader_cache *sc)
|
||||
{
|
||||
for (int n = 0; n < sc->num_entries; n++) {
|
||||
struct sc_entry *e = &sc->entries[n];
|
||||
sc->gl->DeleteProgram(e->gl_shader);
|
||||
talloc_free(e->key);
|
||||
}
|
||||
sc->num_entries = 0;
|
||||
}
|
||||
|
||||
void gl_sc_destroy(struct gl_shader_cache *sc)
|
||||
{
|
||||
gl_sc_reset(sc);
|
||||
sc_flush_cache(sc);
|
||||
talloc_free(sc);
|
||||
}
|
||||
|
||||
void gl_sc_add(struct gl_shader_cache *sc, const char *text)
|
||||
{
|
||||
sc->text = talloc_strdup_append(sc->text, text);
|
||||
}
|
||||
|
||||
void gl_sc_addf(struct gl_shader_cache *sc, const char *textf, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, textf);
|
||||
ta_xvasprintf_append(&sc->text, textf, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static struct sc_uniform *find_uniform(struct gl_shader_cache *sc,
|
||||
const char *name)
|
||||
{
|
||||
for (int n = 0; n < sc->num_uniforms; n++) {
|
||||
if (strcmp(sc->uniforms[n].name, name) == 0)
|
||||
return &sc->uniforms[n];
|
||||
}
|
||||
// not found -> add it
|
||||
assert(sc->num_uniforms < SC_UNIFORM_ENTRIES); // just don't have too many
|
||||
struct sc_uniform *new = &sc->uniforms[sc->num_uniforms++];
|
||||
*new = (struct sc_uniform) { .loc = -1, .name = talloc_strdup(NULL, name) };
|
||||
return new;
|
||||
}
|
||||
|
||||
void gl_sc_uniform_sampler(struct gl_shader_cache *sc, char *name, GLenum target,
|
||||
int unit)
|
||||
{
|
||||
struct sc_uniform *u = find_uniform(sc, name);
|
||||
u->type = UT_i;
|
||||
u->size = 1;
|
||||
switch (target) {
|
||||
case GL_TEXTURE_1D: u->glsl_type = "sampler1D"; break;
|
||||
case GL_TEXTURE_2D: u->glsl_type = "sampler2D"; break;
|
||||
case GL_TEXTURE_RECTANGLE: u->glsl_type = "sampler2DRect"; break;
|
||||
case GL_TEXTURE_3D: u->glsl_type = "sampler3D"; break;
|
||||
default: abort();
|
||||
}
|
||||
u->v.i[0] = unit;
|
||||
}
|
||||
|
||||
void gl_sc_uniform_f(struct gl_shader_cache *sc, char *name, GLfloat f)
|
||||
{
|
||||
struct sc_uniform *u = find_uniform(sc, name);
|
||||
u->type = UT_f;
|
||||
u->size = 1;
|
||||
u->glsl_type = "float";
|
||||
u->v.f[0] = f;
|
||||
}
|
||||
|
||||
void gl_sc_uniform_vec2(struct gl_shader_cache *sc, char *name, GLfloat f[2])
|
||||
{
|
||||
struct sc_uniform *u = find_uniform(sc, name);
|
||||
u->type = UT_f;
|
||||
u->size = 2;
|
||||
u->glsl_type = "vec2";
|
||||
u->v.f[0] = f[0];
|
||||
u->v.f[1] = f[1];
|
||||
}
|
||||
|
||||
void gl_sc_uniform_vec3(struct gl_shader_cache *sc, char *name, GLfloat f[3])
|
||||
{
|
||||
struct sc_uniform *u = find_uniform(sc, name);
|
||||
u->type = UT_f;
|
||||
u->size = 3;
|
||||
u->glsl_type = "vec3";
|
||||
u->v.f[0] = f[0];
|
||||
u->v.f[1] = f[1];
|
||||
u->v.f[2] = f[2];
|
||||
}
|
||||
|
||||
static void transpose2x2(float r[2 * 2])
|
||||
{
|
||||
MPSWAP(float, r[0+2*1], r[1+2*0]);
|
||||
}
|
||||
|
||||
void gl_sc_uniform_mat2(struct gl_shader_cache *sc, char *name,
|
||||
bool transpose, GLfloat *v)
|
||||
{
|
||||
struct sc_uniform *u = find_uniform(sc, name);
|
||||
u->type = UT_m;
|
||||
u->size = 2;
|
||||
u->glsl_type = "mat2";
|
||||
for (int n = 0; n < 4; n++)
|
||||
u->v.f[n] = v[n];
|
||||
if (transpose)
|
||||
transpose2x2(&u->v.f[0]);
|
||||
}
|
||||
|
||||
static void transpose3x3(float r[3 * 3])
|
||||
{
|
||||
MPSWAP(float, r[0+3*1], r[1+3*0]);
|
||||
MPSWAP(float, r[0+3*2], r[2+3*0]);
|
||||
MPSWAP(float, r[1+3*2], r[2+3*1]);
|
||||
}
|
||||
|
||||
void gl_sc_uniform_mat3(struct gl_shader_cache *sc, char *name,
|
||||
bool transpose, GLfloat *v)
|
||||
{
|
||||
struct sc_uniform *u = find_uniform(sc, name);
|
||||
u->type = UT_m;
|
||||
u->size = 3;
|
||||
u->glsl_type = "mat3";
|
||||
for (int n = 0; n < 9; n++)
|
||||
u->v.f[n] = v[n];
|
||||
if (transpose)
|
||||
transpose3x3(&u->v.f[0]);
|
||||
}
|
||||
|
||||
// This will call glBindAttribLocation() on the shader before it's linked
|
||||
// (OpenGL requires this to happen before linking). Basically, it associates
|
||||
// the input variable names with the fields in the vao.
|
||||
// The vertex shader is setup such that the elements are available as fragment
|
||||
// shader variables using the names in the vao entries, which "position" being
|
||||
// set to gl_Position.
|
||||
void gl_sc_set_vao(struct gl_shader_cache *sc, struct gl_vao *vao)
|
||||
{
|
||||
sc->vao = vao;
|
||||
}
|
||||
|
||||
static const char *vao_glsl_type(const struct gl_vao_entry *e)
|
||||
{
|
||||
// pretty dumb... too dumb, but works for us
|
||||
switch (e->num_elems) {
|
||||
case 1: return "float";
|
||||
case 2: return "vec2";
|
||||
case 3: return "vec3";
|
||||
case 4: return "vec4";
|
||||
default: abort();
|
||||
}
|
||||
}
|
||||
|
||||
// Assumes program is current (gl->UseProgram(program)).
|
||||
static void update_uniform(GL *gl, GLuint program, struct sc_uniform *u)
|
||||
{
|
||||
GLint loc = gl->GetUniformLocation(program, u->name);
|
||||
if (loc < 0)
|
||||
return;
|
||||
switch (u->type) {
|
||||
case UT_i:
|
||||
assert(u->size == 1);
|
||||
gl->Uniform1i(loc, u->v.i[0]);
|
||||
break;
|
||||
case UT_f:
|
||||
switch (u->size) {
|
||||
case 1: gl->Uniform1f(loc, u->v.f[0]); break;
|
||||
case 2: gl->Uniform2f(loc, u->v.f[0], u->v.f[1]); break;
|
||||
case 3: gl->Uniform3f(loc, u->v.f[0], u->v.f[1], u->v.f[2]); break;
|
||||
case 4: gl->Uniform4f(loc, u->v.f[0], u->v.f[1], u->v.f[2], u->v.f[3]); break;
|
||||
default: abort();
|
||||
}
|
||||
break;
|
||||
case UT_m:
|
||||
switch (u->size) {
|
||||
case 2: gl->UniformMatrix2fv(loc, 1, GL_FALSE, &u->v.f[0]); break;
|
||||
case 3: gl->UniformMatrix3fv(loc, 1, GL_FALSE, &u->v.f[0]); break;
|
||||
default: abort();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void compile_attach_shader(struct gl_shader_cache *sc, GLuint program,
|
||||
GLenum type, const char *source)
|
||||
{
|
||||
GL *gl = sc->gl;
|
||||
|
||||
GLuint shader = gl->CreateShader(type);
|
||||
gl->ShaderSource(shader, 1, &source, NULL);
|
||||
gl->CompileShader(shader);
|
||||
GLint status;
|
||||
gl->GetShaderiv(shader, GL_COMPILE_STATUS, &status);
|
||||
GLint log_length;
|
||||
gl->GetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
|
||||
|
||||
int pri = status ? (log_length > 1 ? MSGL_V : MSGL_DEBUG) : MSGL_ERR;
|
||||
const char *typestr = type == GL_VERTEX_SHADER ? "vertex" : "fragment";
|
||||
if (mp_msg_test(sc->log, pri)) {
|
||||
MP_MSG(sc, pri, "%s shader source:\n", typestr);
|
||||
mp_log_source(sc->log, pri, source);
|
||||
}
|
||||
if (log_length > 1) {
|
||||
GLchar *logstr = talloc_zero_size(NULL, log_length + 1);
|
||||
gl->GetShaderInfoLog(shader, log_length, NULL, logstr);
|
||||
MP_MSG(sc, pri, "%s shader compile log (status=%d):\n%s\n",
|
||||
typestr, status, logstr);
|
||||
talloc_free(logstr);
|
||||
}
|
||||
|
||||
gl->AttachShader(program, shader);
|
||||
gl->DeleteShader(shader);
|
||||
}
|
||||
|
||||
static void link_shader(struct gl_shader_cache *sc, GLuint program)
|
||||
{
|
||||
GL *gl = sc->gl;
|
||||
gl->LinkProgram(program);
|
||||
GLint status;
|
||||
gl->GetProgramiv(program, GL_LINK_STATUS, &status);
|
||||
GLint log_length;
|
||||
gl->GetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length);
|
||||
|
||||
int pri = status ? (log_length > 1 ? MSGL_V : MSGL_DEBUG) : MSGL_ERR;
|
||||
if (mp_msg_test(sc->log, pri)) {
|
||||
GLchar *logstr = talloc_zero_size(NULL, log_length + 1);
|
||||
gl->GetProgramInfoLog(program, log_length, NULL, logstr);
|
||||
MP_MSG(sc, pri, "shader link log (status=%d): %s\n", status, logstr);
|
||||
talloc_free(logstr);
|
||||
}
|
||||
}
|
||||
|
||||
static GLuint create_program(struct gl_shader_cache *sc, const char *vertex,
|
||||
const char *frag)
|
||||
{
|
||||
GL *gl = sc->gl;
|
||||
MP_VERBOSE(sc, "recompiling a shader program:\n");
|
||||
mp_log_source(sc->log, MSGL_V, sc->text);
|
||||
GLuint prog = gl->CreateProgram();
|
||||
compile_attach_shader(sc, prog, GL_VERTEX_SHADER, vertex);
|
||||
compile_attach_shader(sc, prog, GL_FRAGMENT_SHADER, frag);
|
||||
for (int n = 0; sc->vao->entries[n].name; n++) {
|
||||
char vname[80];
|
||||
snprintf(vname, sizeof(vname), "vertex_%s", sc->vao->entries[n].name);
|
||||
gl->BindAttribLocation(prog, n, vname);
|
||||
}
|
||||
link_shader(sc, prog);
|
||||
return prog;
|
||||
}
|
||||
|
||||
#define ADD(x, ...) (x) = talloc_asprintf_append(x, __VA_ARGS__)
|
||||
|
||||
// 1. Generate vertex and fragment shaders from the fragment shader text added
|
||||
// with gl_sc_add(). The generated shader program is cached (based on the
|
||||
// text), so actual compilation happens only the first time.
|
||||
// 2. Update the uniforms set with gl_sc_uniform_*.
|
||||
// 3. Make the new shader program current (glUseProgram()).
|
||||
// 4. Reset the sc state and prepare for a new shader program. (All uniforms
|
||||
// and fragment operations needed for the next program have to be re-added.)
|
||||
void gl_sc_gen_shader_and_reset(struct gl_shader_cache *sc)
|
||||
{
|
||||
GL *gl = sc->gl;
|
||||
void *tmp = talloc_new(NULL);
|
||||
|
||||
assert(sc->vao);
|
||||
|
||||
// set up shader text (header + uniforms + body)
|
||||
char *header = talloc_asprintf(tmp, "#version %d%s\n", gl->glsl_version,
|
||||
gl->es >= 300 ? " es" : "");
|
||||
if (gl->es)
|
||||
ADD(header, "precision mediump float;\n");
|
||||
char *vert_in = gl->glsl_version >= 130 ? "in" : "attribute";
|
||||
char *vert_out = gl->glsl_version >= 130 ? "out" : "varying";
|
||||
char *frag_in = gl->glsl_version >= 130 ? "in" : "varying";
|
||||
|
||||
// vertex shader: we don't use the vertex shader, so just setup a dummy,
|
||||
// which passes through the vertex array attributes.
|
||||
char *vert_head = talloc_strdup(tmp, header);
|
||||
char *vert_body = talloc_strdup(tmp, "void main() {\n");
|
||||
char *frag_vaos = talloc_strdup(tmp, "");
|
||||
for (int n = 0; sc->vao->entries[n].name; n++) {
|
||||
const struct gl_vao_entry *e = &sc->vao->entries[n];
|
||||
const char *glsl_type = vao_glsl_type(e);
|
||||
if (strcmp(e->name, "position") == 0) {
|
||||
// setting raster pos. requires setting gl_Position magic variable
|
||||
assert(e->num_elems == 2 && e->type == GL_FLOAT);
|
||||
ADD(vert_head, "%s vec2 position;\n", vert_in);
|
||||
ADD(vert_body, "gl_Position = vec4(position, 1.0, 1.0);\n");
|
||||
} else {
|
||||
ADD(vert_head, "%s %s vertex_%s;\n", vert_in, glsl_type, e->name);
|
||||
ADD(vert_head, "%s %s %s;\n", vert_out, glsl_type, e->name);
|
||||
ADD(vert_body, "%s = vertex_%s;\n", e->name, e->name);
|
||||
ADD(frag_vaos, "%s %s %s;\n", frag_in, glsl_type, e->name);
|
||||
}
|
||||
}
|
||||
ADD(vert_body, "}\n");
|
||||
char *vert = talloc_asprintf(tmp, "%s%s", vert_head, vert_body);
|
||||
|
||||
// fragment shader; still requires adding used uniforms and VAO elements
|
||||
char *frag = talloc_strdup(tmp, header);
|
||||
ADD(frag, "#define RG %s\n", gl->mpgl_caps & MPGL_CAP_TEX_RG ? "rg" : "ra");
|
||||
if (gl->glsl_version >= 130) {
|
||||
ADD(frag, "#define texture1D texture\n");
|
||||
ADD(frag, "#define texture3D texture\n");
|
||||
ADD(frag, "out vec4 out_color;\n");
|
||||
}
|
||||
ADD(frag, "%s", frag_vaos);
|
||||
for (int n = 0; n < sc->num_uniforms; n++) {
|
||||
struct sc_uniform *u = &sc->uniforms[n];
|
||||
ADD(frag, "uniform %s %s;\n", u->glsl_type, u->name);
|
||||
}
|
||||
ADD(frag, "void main() {\n");
|
||||
ADD(frag, "%s", sc->text);
|
||||
// we require _all_ frag shaders to write to a "vec4 color"
|
||||
if (gl->glsl_version >= 130) {
|
||||
ADD(frag, "out_color = color;\n");
|
||||
} else {
|
||||
ADD(frag, "gl_FragColor = color;\n");
|
||||
}
|
||||
ADD(frag, "}\n");
|
||||
|
||||
char *key = talloc_asprintf(tmp, "%s%s", vert, frag);
|
||||
struct sc_entry *entry = NULL;
|
||||
for (int n = 0; n < sc->num_entries; n++) {
|
||||
if (strcmp(key, sc->entries[n].key) == 0) {
|
||||
entry = &sc->entries[n];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!entry) {
|
||||
if (sc->num_entries == SC_ENTRIES)
|
||||
sc_flush_cache(sc);
|
||||
entry = &sc->entries[sc->num_entries++];
|
||||
*entry = (struct sc_entry){.key = talloc_strdup(NULL, key)};
|
||||
}
|
||||
// build vertex shader from vao
|
||||
if (!entry->gl_shader)
|
||||
entry->gl_shader = create_program(sc, vert, frag);
|
||||
|
||||
gl->UseProgram(entry->gl_shader);
|
||||
|
||||
// For now we set the uniforms every time. This is probably bad, and we
|
||||
// should switch to caching them.
|
||||
for (int n = 0; n < sc->num_uniforms; n++)
|
||||
update_uniform(gl, entry->gl_shader, &sc->uniforms[n]);
|
||||
|
||||
talloc_free(tmp);
|
||||
|
||||
gl_sc_reset(sc);
|
||||
}
|
||||
|
||||
+48
-5
@@ -66,23 +66,66 @@ void gl_vao_init(struct gl_vao *vao, GL *gl, int stride,
|
||||
void gl_vao_uninit(struct gl_vao *vao);
|
||||
void gl_vao_bind(struct gl_vao *vao);
|
||||
void gl_vao_unbind(struct gl_vao *vao);
|
||||
void gl_vao_bind_attribs(struct gl_vao *vao, GLuint program);
|
||||
void gl_vao_draw_data(struct gl_vao *vao, GLenum prim, void *ptr, size_t num);
|
||||
|
||||
struct fbotex {
|
||||
GL *gl;
|
||||
GLuint fbo;
|
||||
GLuint texture;
|
||||
int tex_w, tex_h; // size of .texture
|
||||
int vp_x, vp_y, vp_w, vp_h; // viewport of fbo / used part of the texture
|
||||
GLenum iformat;
|
||||
GLenum tex_filter;
|
||||
int tex_w, tex_h; // size of .texture
|
||||
};
|
||||
|
||||
bool fbotex_init(struct fbotex *fbo, GL *gl, struct mp_log *log, int w, int h,
|
||||
GLenum gl_target, GLenum gl_filter, GLenum iformat);
|
||||
GLenum iformat);
|
||||
void fbotex_uninit(struct fbotex *fbo);
|
||||
bool fbotex_change(struct fbotex *fbo, GL *gl, struct mp_log *log, int w, int h,
|
||||
GLenum iformat, int flags);
|
||||
#define FBOTEX_FUZZY_W 1
|
||||
#define FBOTEX_FUZZY_H 2
|
||||
void fbotex_set_filter(struct fbotex *fbo, GLenum gl_filter);
|
||||
|
||||
void gl_matrix_ortho2d(float m[3][3], float x0, float x1, float y0, float y1);
|
||||
void gl_matrix_ortho2d(float m[3][2], float x0, float x1, float y0, float y1);
|
||||
|
||||
// This treats m as an affine transformation, in other words m[2][n] gets
|
||||
// added to the output.
|
||||
static inline void gl_matrix_mul_vec(float m[3][2], float *x, float *y)
|
||||
{
|
||||
float vx = *x, vy = *y;
|
||||
*x = vx * m[0][0] + vy * m[1][0] + m[2][0];
|
||||
*y = vx * m[0][1] + vy * m[1][1] + m[2][1];
|
||||
}
|
||||
|
||||
struct mp_rect_f {
|
||||
float x0, y0, x1, y1;
|
||||
};
|
||||
|
||||
static inline void gl_matrix_mul_rect(float m[3][2], struct mp_rect_f *r)
|
||||
{
|
||||
gl_matrix_mul_vec(m, &r->x0, &r->y0);
|
||||
gl_matrix_mul_vec(m, &r->x1, &r->y1);
|
||||
}
|
||||
|
||||
void gl_set_debug_logger(GL *gl, struct mp_log *log);
|
||||
|
||||
struct gl_shader_cache;
|
||||
|
||||
struct gl_shader_cache *gl_sc_create(GL *gl, struct mp_log *log);
|
||||
void gl_sc_destroy(struct gl_shader_cache *sc);
|
||||
void gl_sc_add(struct gl_shader_cache *sc, const char *text);
|
||||
void gl_sc_addf(struct gl_shader_cache *sc, const char *textf, ...);
|
||||
void gl_sc_uniform_sampler(struct gl_shader_cache *sc, char *name, GLenum target,
|
||||
int unit);
|
||||
void gl_sc_uniform_f(struct gl_shader_cache *sc, char *name, GLfloat f);
|
||||
void gl_sc_uniform_vec2(struct gl_shader_cache *sc, char *name, GLfloat f[2]);
|
||||
void gl_sc_uniform_vec3(struct gl_shader_cache *sc, char *name, GLfloat f[3]);
|
||||
void gl_sc_uniform_mat2(struct gl_shader_cache *sc, char *name,
|
||||
bool transpose, GLfloat *v);
|
||||
void gl_sc_uniform_mat3(struct gl_shader_cache *sc, char *name,
|
||||
bool transpose, GLfloat *v);
|
||||
void gl_sc_set_vao(struct gl_shader_cache *sc, struct gl_vao *vao);
|
||||
void gl_sc_gen_shader_and_reset(struct gl_shader_cache *sc);
|
||||
void gl_sc_reset(struct gl_shader_cache *sc);
|
||||
|
||||
#endif
|
||||
|
||||
+1163
-1342
File diff suppressed because it is too large
Load Diff
@@ -31,12 +31,13 @@ struct lut3d {
|
||||
struct gl_video_opts {
|
||||
char *scalers[2];
|
||||
char *dscaler;
|
||||
float gamma;
|
||||
int gamma_auto;
|
||||
int target_prim;
|
||||
int target_trc;
|
||||
float scaler_params[2][2];
|
||||
float scaler_radius[2];
|
||||
float scaler_antiring[2];
|
||||
float gamma;
|
||||
int gamma_auto;
|
||||
int srgb;
|
||||
int linear_scaling;
|
||||
int fancy_downscaling;
|
||||
int sigmoid_upscaling;
|
||||
@@ -73,9 +74,9 @@ void gl_video_set_output_depth(struct gl_video *p, int r, int g, int b);
|
||||
void gl_video_set_lut3d(struct gl_video *p, struct lut3d *lut3d);
|
||||
void gl_video_upload_image(struct gl_video *p, struct mp_image *img);
|
||||
void gl_video_render_frame(struct gl_video *p, int fbo, struct frame_timing *t);
|
||||
void gl_video_resize(struct gl_video *p, struct mp_rect *window,
|
||||
void gl_video_resize(struct gl_video *p, int vp_w, int vp_h,
|
||||
struct mp_rect *src, struct mp_rect *dst,
|
||||
struct mp_osd_res *osd, bool vflip);
|
||||
struct mp_osd_res *osd);
|
||||
void gl_video_get_colorspace(struct gl_video *p, struct mp_image_params *params);
|
||||
struct mp_csp_equalizer;
|
||||
struct mp_csp_equalizer *gl_video_eq_ptr(struct gl_video *p);
|
||||
|
||||
@@ -1,542 +0,0 @@
|
||||
/*
|
||||
* This file is part of mpv.
|
||||
*
|
||||
* mpv is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* mpv is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* You can alternatively redistribute this file and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
// Note that this file is not directly passed as shader, but run through some
|
||||
// text processing functions, and in fact contains multiple vertex and fragment
|
||||
// shaders.
|
||||
|
||||
// inserted at the beginning of all shaders
|
||||
#!section prelude
|
||||
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
|
||||
// GLSL 1.20 compatibility layer
|
||||
// texture() should be assumed to always map to texture2D()
|
||||
#if __VERSION__ >= 130
|
||||
# define texture1D texture
|
||||
# define texture3D texture
|
||||
# define DECLARE_FRAGPARMS \
|
||||
out vec4 out_color;
|
||||
#else
|
||||
# define texture texture2D
|
||||
# define DECLARE_FRAGPARMS
|
||||
# define out_color gl_FragColor
|
||||
# define in varying
|
||||
#endif
|
||||
|
||||
#if HAVE_RG
|
||||
#define RG rg
|
||||
#else
|
||||
#define RG ra
|
||||
#endif
|
||||
|
||||
// Earlier GLSL doesn't support mix() with bvec
|
||||
#if __VERSION__ >= 130
|
||||
vec3 srgb_expand(vec3 v)
|
||||
{
|
||||
return mix(v / vec3(12.92), pow((v + vec3(0.055))/vec3(1.055), vec3(2.4)),
|
||||
lessThanEqual(vec3(0.04045), v));
|
||||
}
|
||||
|
||||
vec3 srgb_compand(vec3 v)
|
||||
{
|
||||
return mix(v * vec3(12.92), vec3(1.055) * pow(v, vec3(1.0/2.4)) - vec3(0.055),
|
||||
lessThanEqual(vec3(0.0031308), v));
|
||||
}
|
||||
|
||||
vec3 bt2020_expand(vec3 v)
|
||||
{
|
||||
return mix(v / vec3(4.5), pow((v + vec3(0.0993))/vec3(1.0993), vec3(1.0/0.45)),
|
||||
lessThanEqual(vec3(0.08145), v));
|
||||
}
|
||||
|
||||
vec3 bt2020_compand(vec3 v)
|
||||
{
|
||||
return mix(v * vec3(4.5), vec3(1.0993) * pow(v, vec3(0.45)) - vec3(0.0993),
|
||||
lessThanEqual(vec3(0.0181), v));
|
||||
}
|
||||
#endif
|
||||
|
||||
#!section vertex_all
|
||||
|
||||
#if __VERSION__ < 130
|
||||
# undef in
|
||||
# define in attribute
|
||||
# define out varying
|
||||
#endif
|
||||
|
||||
uniform mat3 transform;
|
||||
uniform vec3 translation;
|
||||
#if HAVE_3DTEX
|
||||
uniform sampler3D lut_3d;
|
||||
#endif
|
||||
uniform mat3 cms_matrix; // transformation from file's gamut to bt.2020
|
||||
|
||||
in vec2 vertex_position;
|
||||
in vec4 vertex_color;
|
||||
out vec4 color;
|
||||
in vec2 vertex_texcoord;
|
||||
out vec2 texcoord;
|
||||
|
||||
void main() {
|
||||
vec3 position = vec3(vertex_position, 1) + translation;
|
||||
#ifndef FIXED_SCALE
|
||||
position = transform * position;
|
||||
#endif
|
||||
gl_Position = vec4(position, 1);
|
||||
color = vertex_color;
|
||||
|
||||
// Although we are not scaling in linear light, both 3DLUT and SRGB still
|
||||
// operate on linear light inputs so we have to convert to it before
|
||||
// either step can be applied.
|
||||
#ifdef USE_OSD_LINEAR_CONV_BT1886
|
||||
color.rgb = pow(color.rgb, vec3(1.961));
|
||||
#endif
|
||||
#ifdef USE_OSD_LINEAR_CONV_SRGB
|
||||
color.rgb = srgb_expand(color.rgb);
|
||||
#endif
|
||||
#ifdef USE_OSD_CMS_MATRIX
|
||||
// Convert to the right target gamut first (to BT.709 for sRGB,
|
||||
// and to BT.2020 for 3DLUT). Normal clamping here as perceptually
|
||||
// accurate colorimetry is probably not worth the performance trade-off
|
||||
// here.
|
||||
color.rgb = clamp(cms_matrix * color.rgb, 0.0, 1.0);
|
||||
#endif
|
||||
#ifdef USE_OSD_3DLUT
|
||||
color.rgb = pow(color.rgb, vec3(1.0/2.4)); // linear -> 2.4 3DLUT space
|
||||
color = vec4(texture3D(lut_3d, color.rgb).rgb, color.a);
|
||||
#endif
|
||||
#ifdef USE_OSD_SRGB
|
||||
color.rgb = srgb_compand(color.rgb);
|
||||
#endif
|
||||
|
||||
texcoord = vertex_texcoord;
|
||||
}
|
||||
|
||||
#!section frag_osd_libass
|
||||
uniform sampler2D texture0;
|
||||
|
||||
in vec2 texcoord;
|
||||
in vec4 color;
|
||||
DECLARE_FRAGPARMS
|
||||
|
||||
void main() {
|
||||
out_color = vec4(color.rgb, color.a * texture(texture0, texcoord).r);
|
||||
}
|
||||
|
||||
#!section frag_osd_rgba
|
||||
uniform sampler2D texture0;
|
||||
|
||||
in vec2 texcoord;
|
||||
DECLARE_FRAGPARMS
|
||||
|
||||
void main() {
|
||||
out_color = texture(texture0, texcoord).bgra;
|
||||
}
|
||||
|
||||
#!section frag_video
|
||||
uniform VIDEO_SAMPLER texture0;
|
||||
uniform VIDEO_SAMPLER texture1;
|
||||
uniform VIDEO_SAMPLER texture2;
|
||||
uniform VIDEO_SAMPLER texture3;
|
||||
uniform vec2 textures_size[4];
|
||||
uniform vec2 chroma_center_offset;
|
||||
uniform vec2 chroma_div;
|
||||
uniform vec2 chroma_fix;
|
||||
uniform sampler2D lut_2d_c;
|
||||
uniform sampler2D lut_2d_l;
|
||||
#if HAVE_1DTEX
|
||||
uniform sampler1D lut_1d_c;
|
||||
uniform sampler1D lut_1d_l;
|
||||
#endif
|
||||
#if HAVE_3DTEX
|
||||
uniform sampler3D lut_3d;
|
||||
#endif
|
||||
uniform sampler2D dither;
|
||||
uniform mat3 colormatrix;
|
||||
uniform vec3 colormatrix_c;
|
||||
uniform mat3 cms_matrix;
|
||||
uniform mat2 dither_trafo;
|
||||
uniform float inv_gamma;
|
||||
uniform float input_gamma;
|
||||
uniform float conv_gamma;
|
||||
uniform float sig_center;
|
||||
uniform float sig_slope;
|
||||
uniform float sig_scale;
|
||||
uniform float sig_offset;
|
||||
uniform float dither_quantization;
|
||||
uniform float dither_center;
|
||||
uniform float filter_param1_l;
|
||||
uniform float filter_param1_c;
|
||||
uniform float antiring_factor;
|
||||
uniform vec2 dither_size;
|
||||
uniform float inter_coeff;
|
||||
|
||||
in vec2 texcoord;
|
||||
DECLARE_FRAGPARMS
|
||||
|
||||
#define CONV_NV12 1
|
||||
#define CONV_PLANAR 2
|
||||
|
||||
vec4 sample_bilinear(VIDEO_SAMPLER tex, vec2 texsize, vec2 texcoord, float param1) {
|
||||
return texture(tex, texcoord);
|
||||
}
|
||||
|
||||
#define SAMPLE_TRIVIAL(tex, texsize, texcoord) texture(tex, texcoord)
|
||||
|
||||
// Explanation how bicubic scaling with only 4 texel fetches is done:
|
||||
// http://www.mate.tue.nl/mate/pdfs/10318.pdf
|
||||
// 'Efficient GPU-Based Texture Interpolation using Uniform B-Splines'
|
||||
// Explanation why this algorithm normally always blurs, even with unit scaling:
|
||||
// http://bigwww.epfl.ch/preprints/ruijters1001p.pdf
|
||||
// 'GPU Prefilter for Accurate Cubic B-spline Interpolation'
|
||||
vec4 calcweights(float s) {
|
||||
vec4 t = vec4(-0.5, 0.1666, 0.3333, -0.3333) * s + vec4(1, 0, -0.5, 0.5);
|
||||
t = t * s + vec4(0, 0, -0.5, 0.5);
|
||||
t = t * s + vec4(-0.6666, 0, 0.8333, 0.1666);
|
||||
vec2 a = vec2(1, 1) / vec2(t.z, t.w);
|
||||
t.xy = t.xy * a + vec2(1, 1);
|
||||
t.x = t.x + s;
|
||||
t.y = t.y - s;
|
||||
return t;
|
||||
}
|
||||
|
||||
vec4 sample_bicubic_fast(VIDEO_SAMPLER tex, vec2 texsize, vec2 texcoord, float param1) {
|
||||
vec2 pt = 1.0 / texsize;
|
||||
vec2 fcoord = fract(texcoord * texsize + vec2(0.5, 0.5));
|
||||
vec4 parmx = calcweights(fcoord.x);
|
||||
vec4 parmy = calcweights(fcoord.y);
|
||||
vec4 cdelta;
|
||||
cdelta.xz = parmx.RG * vec2(-pt.x, pt.x);
|
||||
cdelta.yw = parmy.RG * vec2(-pt.y, pt.y);
|
||||
// first y-interpolation
|
||||
vec4 ar = texture(tex, texcoord + cdelta.xy);
|
||||
vec4 ag = texture(tex, texcoord + cdelta.xw);
|
||||
vec4 ab = mix(ag, ar, parmy.b);
|
||||
// second y-interpolation
|
||||
vec4 br = texture(tex, texcoord + cdelta.zy);
|
||||
vec4 bg = texture(tex, texcoord + cdelta.zw);
|
||||
vec4 aa = mix(bg, br, parmy.b);
|
||||
// x-interpolation
|
||||
return mix(aa, ab, parmx.b);
|
||||
}
|
||||
|
||||
#if HAVE_ARRAYS
|
||||
float[2] weights2(sampler2D lookup, float f) {
|
||||
vec2 c = texture(lookup, vec2(0.5, f)).RG;
|
||||
return float[2](c.r, c.g);
|
||||
}
|
||||
float[6] weights6(sampler2D lookup, float f) {
|
||||
vec4 c1 = texture(lookup, vec2(0.25, f));
|
||||
vec4 c2 = texture(lookup, vec2(0.75, f));
|
||||
return float[6](c1.r, c1.g, c1.b, c2.r, c2.g, c2.b);
|
||||
}
|
||||
|
||||
// For N=n*4 with n>1.
|
||||
#define WEIGHTS_N(NAME, N) \
|
||||
float[N] NAME(sampler2D lookup, float f) { \
|
||||
float r[N]; \
|
||||
for (int n = 0; n < N / 4; n++) { \
|
||||
vec4 c = texture(lookup, \
|
||||
vec2(1.0 / (N / 2) + n / float(N / 4), f)); \
|
||||
r[n * 4 + 0] = c.r; \
|
||||
r[n * 4 + 1] = c.g; \
|
||||
r[n * 4 + 2] = c.b; \
|
||||
r[n * 4 + 3] = c.a; \
|
||||
} \
|
||||
return r; \
|
||||
}
|
||||
|
||||
// The DIR parameter is (0, 1) or (1, 0), and we expect the shader compiler to
|
||||
// remove all the redundant multiplications and additions, and also to unroll
|
||||
// the loop and remove the conditional completely
|
||||
#define SAMPLE_CONVOLUTION_SEP_N(NAME, DIR, N, LUT, WEIGHTS_FUNC, ANTIRING) \
|
||||
vec4 NAME(VIDEO_SAMPLER tex, vec2 texsize, vec2 texcoord) { \
|
||||
vec2 pt = (vec2(1.0) / texsize) * DIR; \
|
||||
float fcoord = dot(fract(texcoord * texsize - vec2(0.5)), DIR); \
|
||||
vec2 base = texcoord - fcoord * pt - pt * vec2(N / 2 - 1); \
|
||||
float weights[N] = WEIGHTS_FUNC(LUT, fcoord); \
|
||||
vec4 res = vec4(0); \
|
||||
vec4 hi = vec4(0); \
|
||||
vec4 lo = vec4(1); \
|
||||
for (int n = 0; n < N; n++) { \
|
||||
vec4 c = texture(tex, base + pt * vec2(n)); \
|
||||
res += vec4(weights[n]) * c; \
|
||||
if (n == N/2-1 || n == N/2) { \
|
||||
lo = min(lo, c); \
|
||||
hi = max(hi, c); \
|
||||
} \
|
||||
} \
|
||||
return mix(res, clamp(res, lo, hi), ANTIRING); \
|
||||
}
|
||||
|
||||
#define SAMPLE_CONVOLUTION_N(NAME, N, LUT, WEIGHTS_FUNC) \
|
||||
vec4 NAME(VIDEO_SAMPLER tex, vec2 texsize, vec2 texcoord) { \
|
||||
vec2 pt = vec2(1.0) / texsize; \
|
||||
vec2 fcoord = fract(texcoord * texsize - vec2(0.5)); \
|
||||
vec2 base = texcoord - fcoord * pt - pt * vec2(N / 2 - 1); \
|
||||
vec4 res = vec4(0); \
|
||||
float w_x[N] = WEIGHTS_FUNC(LUT, fcoord.x); \
|
||||
float w_y[N] = WEIGHTS_FUNC(LUT, fcoord.y); \
|
||||
for (int y = 0; y < N; y++) { \
|
||||
vec4 line = vec4(0); \
|
||||
for (int x = 0; x < N; x++) \
|
||||
line += vec4(w_x[x]) * texture(tex, base + pt * vec2(x, y));\
|
||||
res += vec4(w_y[y]) * line; \
|
||||
} \
|
||||
return res; \
|
||||
}
|
||||
|
||||
#define SAMPLE_POLAR_HELPER(LUT, R, X, Y) \
|
||||
w = texture1D(LUT, length(vec2(X, Y) - fcoord)/R).r; \
|
||||
c = texture(tex, base + pt * vec2(X, Y)); \
|
||||
wsum += w; \
|
||||
res += vec4(w) * c;
|
||||
|
||||
#define SAMPLE_POLAR_PRIMARY(LUT, R, X, Y) \
|
||||
SAMPLE_POLAR_HELPER(LUT, R, X, Y) \
|
||||
lo = min(lo, c); \
|
||||
hi = max(hi, c);
|
||||
|
||||
#define SAMPLE_POLAR_POTENTIAL(LUT, R, X, Y) \
|
||||
if (length(vec2(X, Y) - fcoord)/R < 1.0) { \
|
||||
SAMPLE_POLAR_HELPER(LUT, R, X, Y) \
|
||||
}
|
||||
|
||||
#define SAMPLE_CONVOLUTION_POLAR_R(NAME, R, LUT, WEIGHTS_FN, ANTIRING) \
|
||||
vec4 NAME(VIDEO_SAMPLER tex, vec2 texsize, vec2 texcoord) { \
|
||||
vec2 pt = vec2(1.0) / texsize; \
|
||||
vec2 fcoord = fract(texcoord * texsize - vec2(0.5)); \
|
||||
vec2 base = texcoord - fcoord * pt; \
|
||||
vec4 res = vec4(0.0); \
|
||||
vec4 lo = vec4(1.0); \
|
||||
vec4 hi = vec4(0.0); \
|
||||
float wsum = 0.0; \
|
||||
float w; \
|
||||
vec4 c; \
|
||||
WEIGHTS_FN(LUT); \
|
||||
res = res / vec4(wsum); \
|
||||
return mix(res, clamp(res, lo, hi), ANTIRING); \
|
||||
}
|
||||
|
||||
#endif /* HAVE_ARRAYS */
|
||||
|
||||
#ifdef DEF_SCALER0
|
||||
DEF_SCALER0
|
||||
#endif
|
||||
#ifdef DEF_SCALER1
|
||||
DEF_SCALER1
|
||||
#endif
|
||||
|
||||
// Unsharp masking
|
||||
vec4 sample_sharpen3(VIDEO_SAMPLER tex, vec2 texsize, vec2 texcoord, float param1) {
|
||||
vec2 pt = 1.0 / texsize;
|
||||
vec2 st = pt * 0.5;
|
||||
vec4 p = texture(tex, texcoord);
|
||||
vec4 sum = texture(tex, texcoord + st * vec2(+1, +1))
|
||||
+ texture(tex, texcoord + st * vec2(+1, -1))
|
||||
+ texture(tex, texcoord + st * vec2(-1, +1))
|
||||
+ texture(tex, texcoord + st * vec2(-1, -1));
|
||||
return p + (p - 0.25 * sum) * param1;
|
||||
}
|
||||
|
||||
vec4 sample_sharpen5(VIDEO_SAMPLER tex, vec2 texsize, vec2 texcoord, float param1) {
|
||||
vec2 pt = 1.0 / texsize;
|
||||
vec2 st1 = pt * 1.2;
|
||||
vec4 p = texture(tex, texcoord);
|
||||
vec4 sum1 = texture(tex, texcoord + st1 * vec2(+1, +1))
|
||||
+ texture(tex, texcoord + st1 * vec2(+1, -1))
|
||||
+ texture(tex, texcoord + st1 * vec2(-1, +1))
|
||||
+ texture(tex, texcoord + st1 * vec2(-1, -1));
|
||||
vec2 st2 = pt * 1.5;
|
||||
vec4 sum2 = texture(tex, texcoord + st2 * vec2(+1, 0))
|
||||
+ texture(tex, texcoord + st2 * vec2( 0, +1))
|
||||
+ texture(tex, texcoord + st2 * vec2(-1, 0))
|
||||
+ texture(tex, texcoord + st2 * vec2( 0, -1));
|
||||
vec4 t = p * 0.859375 + sum2 * -0.1171875 + sum1 * -0.09765625;
|
||||
return p + t * param1;
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 chr_texcoord = texcoord;
|
||||
#ifdef USE_CHROMA_FIX
|
||||
chr_texcoord = chr_texcoord * chroma_fix;
|
||||
#endif
|
||||
#ifdef USE_RECTANGLE
|
||||
chr_texcoord = chr_texcoord * chroma_div;
|
||||
#else
|
||||
// Texture coordinates are [0,1], and chroma plane coordinates are
|
||||
// magically rescaled.
|
||||
#endif
|
||||
chr_texcoord = chr_texcoord + chroma_center_offset;
|
||||
#ifndef USE_CONV
|
||||
#define USE_CONV 0
|
||||
#endif
|
||||
#ifndef USE_LINEAR_INTERPOLATION
|
||||
#define USE_LINEAR_INTERPOLATION 0
|
||||
#endif
|
||||
#if USE_LINEAR_INTERPOLATION == 1
|
||||
vec4 acolor = mix(
|
||||
texture(texture0, texcoord),
|
||||
texture(texture1, texcoord),
|
||||
inter_coeff);
|
||||
#elif USE_CONV == CONV_PLANAR
|
||||
vec4 acolor = vec4(SAMPLE(texture0, textures_size[0], texcoord).r,
|
||||
SAMPLE_C(texture1, textures_size[1], chr_texcoord).r,
|
||||
SAMPLE_C(texture2, textures_size[2], chr_texcoord).r,
|
||||
1.0);
|
||||
#elif USE_CONV == CONV_NV12
|
||||
vec4 acolor = vec4(SAMPLE(texture0, textures_size[0], texcoord).r,
|
||||
SAMPLE_C(texture1, textures_size[1], chr_texcoord).RG,
|
||||
1.0);
|
||||
#else
|
||||
vec4 acolor = SAMPLE(texture0, textures_size[0], texcoord);
|
||||
#endif
|
||||
#ifdef USE_COLOR_SWIZZLE
|
||||
acolor = acolor. USE_COLOR_SWIZZLE ;
|
||||
#endif
|
||||
#ifdef USE_ALPHA_PLANE
|
||||
acolor.a = SAMPLE(texture3, textures_size[3], texcoord).r;
|
||||
#endif
|
||||
vec3 color = acolor.rgb;
|
||||
float alpha = acolor.a;
|
||||
#ifdef USE_INPUT_GAMMA
|
||||
// Pre-colormatrix input gamma correction (eg. for MP_IMGFLAG_XYZ)
|
||||
color = pow(color, vec3(input_gamma));
|
||||
#endif
|
||||
#ifdef USE_COLORMATRIX
|
||||
// Conversion from Y'CbCr or other spaces to RGB
|
||||
color = mat3(colormatrix) * color + colormatrix_c;
|
||||
#endif
|
||||
#ifdef USE_CONV_GAMMA
|
||||
// Post-colormatrix converted gamma correction (eg. for MP_IMGFLAG_XYZ)
|
||||
color = pow(color, vec3(conv_gamma));
|
||||
#endif
|
||||
#ifdef USE_CONST_LUMA
|
||||
// Conversion from C'rcY'cC'bc to R'Y'cB' via the BT.2020 CL system:
|
||||
// C'bc = (B'-Y'c) / 1.9404 | C'bc <= 0
|
||||
// = (B'-Y'c) / 1.5816 | C'bc > 0
|
||||
//
|
||||
// C'rc = (R'-Y'c) / 1.7184 | C'rc <= 0
|
||||
// = (R'-Y'c) / 0.9936 | C'rc > 0
|
||||
//
|
||||
// as per the BT.2020 specification, table 4. This is a non-linear
|
||||
// transformation because (constant) luminance receives non-equal
|
||||
// contributions from the three different channels.
|
||||
color.br = color.br * mix(vec2(1.5816, 0.9936), vec2(1.9404, 1.7184),
|
||||
lessThanEqual(color.br, vec2(0))) + color.gg;
|
||||
|
||||
// Expand channels to camera-linear light. This shader currently just
|
||||
// assumes everything uses the BT.2020 12-bit gamma function, since the
|
||||
// difference between 10 and 12-bit is negligible for anything other than
|
||||
// 12-bit content.
|
||||
color = bt2020_expand(color);
|
||||
// Calculate the green channel from the expanded RYcB
|
||||
// The BT.2020 specification says Yc = 0.2627*R + 0.6780*G + 0.0593*B
|
||||
color.g = (color.g - 0.2627*color.r - 0.0593*color.b)/0.6780;
|
||||
// Re-compand to receive the R'G'B' result, same as other systems
|
||||
color = bt2020_compand(color);
|
||||
#endif
|
||||
#ifdef USE_COLORMATRIX
|
||||
// CONST_LUMA involves numbers outside the [0,1] range so we make sure
|
||||
// to clip here, after the (possible) USE_CONST_LUMA calculations are done,
|
||||
// instead of immediately after the colormatrix conversion.
|
||||
color = clamp(color, 0.0, 1.0);
|
||||
#endif
|
||||
// If we are scaling in linear light (SRGB or 3DLUT option enabled), we
|
||||
// expand our source colors before scaling. We distinguish between
|
||||
// BT.1886 (typical video files) and sRGB (typical image files).
|
||||
#ifdef USE_LINEAR_LIGHT_BT1886
|
||||
// This calculation is derived from the BT.1886 recommendation which
|
||||
// is itself derived from the curves of typical CRT monitors. It claims
|
||||
// that a correct video playback environment should have a pure power
|
||||
// curve transfer function (in contrast to the complex BT.709 function)
|
||||
// with a gamma value of 2.40, but this includes the typical gamma boost
|
||||
// of ~1.2 for dark viewing environments. The figure used here instead
|
||||
// (1.961) is therefore a pure power curve but without the boost, which
|
||||
// is a very close approximation of the true BT.709 function.
|
||||
color = pow(color, vec3(1.961));
|
||||
#endif
|
||||
#ifdef USE_LINEAR_LIGHT_SRGB
|
||||
// This is not needed for most sRGB content since we can use GL_SRGB to
|
||||
// directly sample RGB texture in linear light, but for things which are
|
||||
// also sRGB but in a different format (such as JPEG's YUV), we need
|
||||
// to convert to linear light manually.
|
||||
color = srgb_expand(color);
|
||||
#endif
|
||||
#ifdef USE_SIGMOID
|
||||
color = sig_center - log(1.0/(color * sig_scale + sig_offset) - 1.0)/sig_slope;
|
||||
#endif
|
||||
// Image upscaling happens roughly here
|
||||
#ifdef USE_SIGMOID_INV
|
||||
// Inverse of USE_SIGMOID
|
||||
color = (1.0/(1.0 + exp(sig_slope * (sig_center - color))) - sig_offset) / sig_scale;
|
||||
#endif
|
||||
#ifdef USE_CMS_MATRIX
|
||||
// Convert to the right target gamut first (to BT.709 for sRGB,
|
||||
// and to BT.2020 for 3DLUT).
|
||||
color = cms_matrix * color;
|
||||
#endif
|
||||
// Clamp to the target gamut. This clamp is needed because the gamma
|
||||
// functions are not well-defined outside this range, which is related to
|
||||
// the fact that they're not representable on the target device.
|
||||
// TODO: Desaturate colorimetrically; this happens automatically for
|
||||
// 3dlut targets but not for sRGB mode. Not sure if this is a requirement.
|
||||
color = clamp(color, 0.0, 1.0);
|
||||
#ifdef USE_INV_GAMMA
|
||||
// User-defined gamma correction factor (via the gamma sub-option)
|
||||
color = pow(color, vec3(inv_gamma));
|
||||
#endif
|
||||
#ifdef USE_3DLUT
|
||||
// For the 3DLUT we are arbitrarily using 2.4 as input gamma to reduce
|
||||
// the amount of rounding errors, so we pull up to that space first and
|
||||
// then pass it through the 3D texture.
|
||||
color = pow(color, vec3(1.0/2.4));
|
||||
color = texture3D(lut_3d, color).rgb;
|
||||
#endif
|
||||
#ifdef USE_SRGB
|
||||
// Adapt and compand from the linear BT2020 source to the sRGB output
|
||||
color = srgb_compand(color);
|
||||
#endif
|
||||
#ifdef USE_INV_BT1886
|
||||
color = pow(color, vec3(1.0/1.961));
|
||||
#endif
|
||||
#ifdef USE_DITHER
|
||||
vec2 dither_pos = gl_FragCoord.xy / dither_size;
|
||||
#ifdef USE_TEMPORAL_DITHER
|
||||
dither_pos = dither_trafo * dither_pos;
|
||||
#endif
|
||||
float dither_value = texture(dither, dither_pos).r;
|
||||
color = floor(color * dither_quantization + dither_value + dither_center) /
|
||||
dither_quantization;
|
||||
#endif
|
||||
#ifdef USE_ALPHA_BLEND
|
||||
color = color * alpha;
|
||||
#endif
|
||||
#ifdef USE_ALPHA
|
||||
out_color = vec4(color, alpha);
|
||||
#else
|
||||
out_color = vec4(color, 1.0);
|
||||
#endif
|
||||
}
|
||||
@@ -93,12 +93,11 @@ static void resize(struct gl_priv *p)
|
||||
|
||||
MP_VERBOSE(vo, "Resize: %dx%d\n", vo->dwidth, vo->dheight);
|
||||
|
||||
struct mp_rect wnd = {0, 0, vo->dwidth, vo->dheight};
|
||||
struct mp_rect src, dst;
|
||||
struct mp_osd_res osd;
|
||||
vo_get_src_dst_rects(vo, &src, &dst, &osd);
|
||||
|
||||
gl_video_resize(p->renderer, &wnd, &src, &dst, &osd, false);
|
||||
gl_video_resize(p->renderer, vo->dwidth, -vo->dheight, &src, &dst, &osd);
|
||||
|
||||
vo->want_redraw = true;
|
||||
}
|
||||
@@ -198,7 +197,7 @@ static int query_format(struct vo *vo, int format)
|
||||
static void video_resize_redraw_callback(struct vo *vo, int w, int h)
|
||||
{
|
||||
struct gl_priv *p = vo->priv;
|
||||
gl_video_resize_redraw(p->renderer, w, h);
|
||||
gl_video_resize_redraw(p->renderer, w, -h);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ struct mpv_opengl_cb_context {
|
||||
int queued_frames;
|
||||
struct mp_image_params img_params;
|
||||
bool reconfigured;
|
||||
struct mp_rect wnd;
|
||||
int vp_w, vp_h;
|
||||
bool flip;
|
||||
bool force_update;
|
||||
bool imgfmt_supported[IMGFMT_END - IMGFMT_START];
|
||||
@@ -282,28 +282,22 @@ int mpv_opengl_cb_render(struct mpv_opengl_cb_context *ctx, int fbo, int vp[4])
|
||||
|
||||
ctx->force_update |= ctx->reconfigured;
|
||||
|
||||
int h = vp[3];
|
||||
bool flip = h < 0 && h > INT_MIN;
|
||||
if (flip)
|
||||
h = -h;
|
||||
struct mp_rect wnd = {vp[0], vp[1], vp[0] + vp[2], vp[1] + h};
|
||||
if (wnd.x0 != ctx->wnd.x0 || wnd.y0 != ctx->wnd.y0 ||
|
||||
wnd.x1 != ctx->wnd.x1 || wnd.y1 != ctx->wnd.y1 ||
|
||||
ctx->flip != flip)
|
||||
int vp_w = vp[2], vp_h = vp[3];
|
||||
if (ctx->vp_w != vp_w || ctx->vp_h != vp_h)
|
||||
ctx->force_update = true;
|
||||
|
||||
if (ctx->force_update && vo) {
|
||||
ctx->force_update = false;
|
||||
ctx->wnd = wnd;
|
||||
ctx->flip = flip;
|
||||
ctx->vp_w = vp_w;
|
||||
ctx->vp_h = vp_h;
|
||||
|
||||
struct mp_rect src, dst;
|
||||
struct mp_osd_res osd;
|
||||
mp_get_src_dst_rects(ctx->log, &ctx->vo_opts, vo->driver->caps,
|
||||
&ctx->img_params, wnd.x1 - wnd.x0, wnd.y1 - wnd.y0,
|
||||
&ctx->img_params, vp_w, abs(vp_h),
|
||||
1.0, &src, &dst, &osd);
|
||||
|
||||
gl_video_resize(ctx->renderer, &wnd, &src, &dst, &osd, !ctx->flip);
|
||||
gl_video_resize(ctx->renderer, vp_w, vp_h, &src, &dst, &osd);
|
||||
}
|
||||
|
||||
if (ctx->reconfigured)
|
||||
|
||||
@@ -53,10 +53,6 @@ def build(ctx):
|
||||
source = "etc/input.conf",
|
||||
target = "input/input_conf.h")
|
||||
|
||||
ctx.file2string(
|
||||
source = "video/out/gl_video_shaders.glsl",
|
||||
target = "video/out/gl_video_shaders.h")
|
||||
|
||||
ctx.file2string(
|
||||
source = "sub/osd_font.otf",
|
||||
target = "sub/osd_font.h")
|
||||
|
||||
Reference in New Issue
Block a user