summaryrefslogtreecommitdiffstats
path: root/video/out/opengl/osd.c
diff options
context:
space:
mode:
Diffstat (limited to 'video/out/opengl/osd.c')
-rw-r--r--video/out/opengl/osd.c211
1 files changed, 122 insertions, 89 deletions
diff --git a/video/out/opengl/osd.c b/video/out/opengl/osd.c
index c554425e0f..7b1ec162fd 100644
--- a/video/out/opengl/osd.c
+++ b/video/out/opengl/osd.c
@@ -17,19 +17,16 @@
#include <stdlib.h>
#include <assert.h>
+#include <limits.h>
+
#include <libavutil/common.h>
#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 +35,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];
@@ -77,16 +59,17 @@ struct mpgl_osd_part {
struct sub_bitmap *subparts;
struct vertex *vertices;
struct bitmap_packer *packer;
+ void *upload;
};
struct mpgl_osd {
struct mp_log *log;
struct osd_state *osd;
GL *gl;
+ GLint max_tex_wh;
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;
@@ -98,37 +81,32 @@ struct mpgl_osd {
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);
-
struct mpgl_osd *ctx = talloc_ptrtype(NULL, ctx);
*ctx = (struct mpgl_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;
- }
+ gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &ctx->max_tex_wh);
+
+ 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);
*p = (struct mpgl_osd_part) {
.packer = talloc_struct(p, struct bitmap_packer, {
- .w_max = max_texture_size,
- .h_max = max_texture_size,
+ .w_max = ctx->max_tex_wh,
+ .h_max = ctx->max_tex_wh,
}),
};
ctx->parts[n] = p;
}
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);
@@ -149,6 +127,7 @@ void mpgl_osd_destroy(struct mpgl_osd *ctx)
gl->DeleteTextures(1, &p->texture);
if (gl->DeleteBuffers)
gl->DeleteBuffers(1, &p->buffer);
+ talloc_free(p->upload);
}
talloc_free(ctx);
}
@@ -158,38 +137,79 @@ 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)
+static bool upload(struct mpgl_osd *ctx, struct mpgl_osd_part *osd,
+ struct sub_bitmaps *imgs, bool pbo)
{
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];
+ size_t pix_stride = gl_bytes_per_pixel(fmt->format, fmt->type);
+ size_t buffer_size = pix_stride * osd->h * osd->w;
+
+ char *data = NULL;
+ void *texdata = NULL;
+
+ if (pbo) {
+ if (!osd->buffer) {
+ gl->GenBuffers(1, &osd->buffer);
+ gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, osd->buffer);
+ gl->BufferData(GL_PIXEL_UNPACK_BUFFER, buffer_size, NULL,
+ GL_DYNAMIC_COPY);
+ }
- if (!osd->buffer) {
- gl->GenBuffers(1, &osd->buffer);
gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, osd->buffer);
- gl->BufferData(GL_PIXEL_UNPACK_BUFFER, osd->w * osd->h * pix_stride,
- NULL, GL_DYNAMIC_COPY);
- gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+ data = gl->MapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, buffer_size,
+ GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
+ if (!data) {
+ success = false;
+ goto done;
+ }
+ } else {
+ if (!imgs->packed) {
+ if (!osd->upload)
+ osd->upload = talloc_size(NULL, buffer_size);
+ data = osd->upload;
+ texdata = data;
+ }
}
- gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, osd->buffer);
- char *data = gl->MapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
- if (!data) {
- success = false;
+ int copy_w = 0;
+ int copy_h = 0;
+ size_t stride = 0;
+ if (imgs->packed) {
+ copy_w = imgs->packed_w;
+ copy_h = imgs->packed_h;
+ stride = imgs->packed->stride[0];
+ texdata = imgs->packed->planes[0];
+ if (pbo) {
+ memcpy_pic(data, texdata, pix_stride * copy_w, copy_h,
+ osd->w * pix_stride, stride);
+ stride = osd->w * pix_stride;
+ texdata = NULL;
+ }
} else {
struct pos bb[2];
packer_get_bb(osd->packer, bb);
- size_t stride = osd->w * pix_stride;
+ copy_w = bb[1].x;
+ copy_h = bb[1].y;
+ stride = osd->w * pix_stride;
packer_copy_subbitmaps(osd->packer, imgs, data, pix_stride, stride);
- if (!gl->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER))
+ }
+
+ if (pbo) {
+ 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);
+ goto done;
+ }
}
- gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+ gl_upload_tex(gl, GL_TEXTURE_2D, fmt->format, fmt->type, texdata, stride,
+ 0, 0, copy_w, copy_h);
+
+ if (pbo)
+ gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+
+done:
if (!success) {
MP_FATAL(ctx, "Error: can't upload subtitles! "
"Remove the 'pbo' suboption.\n");
@@ -198,24 +218,13 @@ static bool upload_pbo(struct mpgl_osd *ctx, struct mpgl_osd_part *osd,
return success;
}
-static void upload_tex(struct mpgl_osd *ctx, struct mpgl_osd_part *osd,
- struct sub_bitmaps *imgs)
+static int next_pow2(int v)
{
- struct osd_fmt_entry 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,
- bb[0].x, bb[0].y, bb[1].x - bb[0].y, bb[1].y - bb[0].y,
- 0, &ctx->scratch);
- }
- for (int n = 0; n < osd->packer->count; n++) {
- struct sub_bitmap *s = &imgs->parts[n];
- struct pos p = osd->packer->result[n];
-
- glUploadTex(ctx->gl, GL_TEXTURE_2D, fmt.format, fmt.type,
- s->bitmap, s->stride, p.x, p.y, s->w, s->h, 0);
+ for (int x = 0; x < 30; x++) {
+ if ((1 << x) >= v)
+ return 1 << x;
}
+ return INT_MAX;
}
static bool upload_osd(struct mpgl_osd *ctx, struct mpgl_osd_part *osd,
@@ -223,32 +232,46 @@ static bool upload_osd(struct mpgl_osd *ctx, struct mpgl_osd_part *osd,
{
GL *gl = ctx->gl;
- // assume 2x2 filter on scaling
- osd->packer->padding = ctx->scaled || imgs->scaled;
- int r = packer_pack_from_subbitmaps(osd->packer, imgs);
- if (r < 0) {
+ int req_w = 0;
+ int req_h = 0;
+
+ if (imgs->packed) {
+ req_w = next_pow2(imgs->packed_w);
+ req_h = next_pow2(imgs->packed_h);
+ } else {
+ // assume 2x2 filter on scaling
+ osd->packer->padding = imgs->scaled;
+ int r = packer_pack_from_subbitmaps(osd->packer, imgs);
+ if (r < 0) {
+ MP_ERR(ctx, "OSD bitmaps do not fit on a surface with the maximum "
+ "supported size %dx%d.\n", osd->packer->w_max, osd->packer->h_max);
+ return false;
+ }
+ req_w = osd->packer->w;
+ req_h = osd->packer->h;
+ }
+
+ if (req_w > ctx->max_tex_wh || req_h > ctx->max_tex_wh) {
MP_ERR(ctx, "OSD bitmaps do not fit on a surface with the maximum "
- "supported size %dx%d.\n", osd->packer->w_max, osd->packer->h_max);
+ "supported size %dx%d.\n", ctx->max_tex_wh, ctx->max_tex_wh);
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);
gl->BindTexture(GL_TEXTURE_2D, osd->texture);
- if (osd->packer->w > osd->w || osd->packer->h > osd->h
- || osd->format != imgs->format)
- {
+ if (req_w > osd->w || req_h > osd->h || osd->format != imgs->format) {
osd->format = imgs->format;
- osd->w = FFMAX(32, osd->packer->w);
- osd->h = FFMAX(32, osd->packer->h);
+ osd->w = FFMAX(32, req_w);
+ osd->h = FFMAX(32, req_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);
@@ -258,13 +281,16 @@ static bool upload_osd(struct mpgl_osd *ctx, struct mpgl_osd_part *osd,
if (gl->DeleteBuffers)
gl->DeleteBuffers(1, &osd->buffer);
osd->buffer = 0;
+
+ talloc_free(osd->upload);
+ osd->upload = NULL;
}
bool uploaded = false;
if (ctx->use_pbo)
- uploaded = upload_pbo(ctx, osd, imgs);
+ uploaded = upload(ctx, osd, imgs, true);
if (!uploaded)
- upload_tex(ctx, osd, imgs);
+ upload(ctx, osd, imgs, false);
gl->BindTexture(GL_TEXTURE_2D, 0);
@@ -280,18 +306,26 @@ static void gen_osd_cb(void *pctx, struct sub_bitmaps *imgs)
struct mpgl_osd_part *osd = ctx->parts[imgs->render_index];
+ bool ok = true;
if (imgs->change_id != osd->change_id) {
if (!upload_osd(ctx, osd, imgs))
- osd->packer->count = 0;
+ ok = false;
osd->change_id = imgs->change_id;
ctx->change_counter += 1;
}
- osd->num_subparts = osd->packer->count;
+ osd->num_subparts = ok ? imgs->num_parts : 0;
MP_TARRAY_GROW(osd, osd->subparts, osd->num_subparts);
memcpy(osd->subparts, imgs->parts,
osd->num_subparts * sizeof(osd->subparts[0]));
+
+ if (!imgs->packed) {
+ for (int n = 0; n < osd->num_subparts; n++) {
+ osd->subparts[n].src_x = osd->packer->result[n].x;
+ osd->subparts[n].src_y = osd->packer->result[n].y;
+ }
+ }
}
static void write_quad(struct vertex *va, struct gl_transform t,
@@ -319,7 +353,6 @@ static int generate_verts(struct mpgl_osd_part *part, struct gl_transform t)
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;
// NOTE: the blend color is used with SUBBITMAP_LIBASS only, so it
@@ -330,7 +363,7 @@ static int generate_verts(struct mpgl_osd_part *part, struct gl_transform t)
write_quad(&va[n * 6], t,
b->x, b->y, b->x + b->dw, b->y + b->dh,
- pos.x, pos.y, pos.x + b->w, pos.y + b->h,
+ b->src_x, b->src_y, b->src_x + b->w, b->src_y + b->h,
part->w, part->h, color);
}