summaryrefslogtreecommitdiffstats
path: root/video/out/gl_osd.c
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2015-03-12 21:57:54 +0100
committerwm4 <wm4@nowhere>2015-03-12 23:20:20 +0100
commite74a4d5bc0b101fbfb371942c00d3a77267dc4a6 (patch)
treea9cc46910567eaf32ba0b47c9539f47418565d41 /video/out/gl_osd.c
parentae6019cbc98cfad2613e89a80bee79ce6b2f1319 (diff)
downloadmpv-e74a4d5bc0b101fbfb371942c00d3a77267dc4a6.tar.bz2
mpv-e74a4d5bc0b101fbfb371942c00d3a77267dc4a6.tar.xz
vo_opengl: refactor shader generation (part 1)
The basic idea is to use dynamically generated shaders instead of a single monolithic file + a ton of ifdefs. Instead of having to setup every aspect of it separately (like compiling shaders, setting uniforms, perfoming the actual rendering steps, the GLSL parts), we generate the GLSL on the fly, and perform the rendering at the same time. The GLSL is regenerated every frame, but the actual compiled OpenGL-level shaders are cached, which makes it fast again. Almost all logic can be in a single place. The new code is significantly more flexible, which allows us to improve the code clarity, performance and add more features easily. This commit is incomplete. It drops almost all previous code, and readds only the most important things (some of them actually buggy). The next commit will complete it - it's separate to preserve authorship information.
Diffstat (limited to 'video/out/gl_osd.c')
-rw-r--r--video/out/gl_osd.c200
1 files changed, 124 insertions, 76 deletions
diff --git a/video/out/gl_osd.c b/video/out/gl_osd.c
index 117d7feedb..0ab85f59c4 100644
--- a/video/out/gl_osd.c
+++ b/video/out/gl_osd.c
@@ -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][3],
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][3])
{
- struct mpgl_osd *ctx = pctx;
- GL *gl = ctx->gl;
+ int num_vertices = part->num_subparts * 6;
+ MP_TARRAY_GROW(part, part->vertices, num_vertices);
- struct mpgl_osd_part *part = mpgl_osd_generate(ctx, imgs);
- if (!part)
- return;
+ 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;
- assert(part->format != SUBBITMAP_EMPTY);
+ // 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) };
- if (!part->num_vertices) {
- part->vertices = talloc_realloc(part, part->vertices, struct vertex,
- part->packer->count * 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);
+ }
- struct vertex *va = part->vertices;
+ return num_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) };
-
- 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;
- }
- }
+static void draw_part(struct mpgl_osd *ctx, int index, float matrix[3][3])
+{
+ 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);
- 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);
+ gl_vao_draw_data(&ctx->vao, GL_TRIANGLES, part->vertices, 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;
-
- gl->Enable(GL_BLEND);
-
int div[2];
- get_3d_side_by_side(stereo_mode, div);
+ get_3d_side_by_side(ctx->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);
+ float matrix[3][3];
+
+ 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);
}
}
+}
- gl->Disable(GL_BLEND);
+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);
+
+ 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];
+
+ osd_draw(ctx->osd, s_res, pts, 0, ctx->formats, gen_osd_cb, ctx);
+ ctx->stereo_mode = stereo_mode;
}