summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2017-08-05 13:39:20 +0200
committerwm4 <wm4@nowhere>2017-08-05 13:44:30 +0200
commitdd096863fa00f1c0c9268932a46ddc321122f552 (patch)
tree49956dd4bcd2a0d12e298107f7aeeff7a61e28e4
parent8dd4ae13ffd5ff11b97b84bbb4fdfe6185eeeb50 (diff)
downloadmpv-dd096863fa00f1c0c9268932a46ddc321122f552.tar.bz2
mpv-dd096863fa00f1c0c9268932a46ddc321122f552.tar.xz
vo_opengl: make OSD code use ra for textures
This requires a silly extension to ra_fns.tex_upload: since the OSD texture can be much larger than the actual OSD image data to upload, a mechanism for uploading only to a small part of the texture is needed. Otherwise, we'd have to realloc/copy the data, just to pad it, and then pay for uploading the padding too. The RA_TEX_UPLOAD_DISCARD flag is not interpreted by GL (not sure how you'd tell GL about this), but it clarifies the API and might be helpful if we support other backend APIs in the future.
-rw-r--r--video/out/opengl/osd.c77
-rw-r--r--video/out/opengl/osd.h3
-rw-r--r--video/out/opengl/ra.h21
-rw-r--r--video/out/opengl/ra_gl.c16
-rw-r--r--video/out/opengl/video.c5
5 files changed, 78 insertions, 44 deletions
diff --git a/video/out/opengl/osd.c b/video/out/opengl/osd.c
index aa0791139d..8b178f212d 100644
--- a/video/out/opengl/osd.c
+++ b/video/out/opengl/osd.c
@@ -22,6 +22,7 @@
#include <libavutil/common.h>
#include "formats.h"
+#include "ra_gl.h"
#include "osd.h"
#define GLSL(x) gl_sc_add(sc, #x "\n");
@@ -50,7 +51,7 @@ static const struct gl_vao_entry vertex_vao[] = {
struct mpgl_osd_part {
enum sub_bitmap_format format;
int change_id;
- GLuint texture;
+ struct ra_tex *texture;
int w, h;
struct gl_pbo_upload pbo;
int num_subparts;
@@ -63,10 +64,11 @@ struct mpgl_osd_part {
struct mpgl_osd {
struct mp_log *log;
struct osd_state *osd;
+ struct ra *ra;
GL *gl;
bool use_pbo;
struct mpgl_osd_part *parts[MAX_OSD_PARTS];
- const struct gl_format *fmt_table[SUBBITMAP_COUNT];
+ const struct ra_format *fmt_table[SUBBITMAP_COUNT];
bool formats[SUBBITMAP_COUNT];
int64_t change_counter;
// temporary
@@ -75,18 +77,22 @@ struct mpgl_osd {
void *scratch;
};
-struct mpgl_osd *mpgl_osd_init(GL *gl, struct mp_log *log, struct osd_state *osd)
+struct mpgl_osd *mpgl_osd_init(struct ra *ra, struct mp_log *log,
+ struct osd_state *osd)
{
+ struct ra_gl *ra_gl = ra->priv;
+
struct mpgl_osd *ctx = talloc_ptrtype(NULL, ctx);
*ctx = (struct mpgl_osd) {
.log = log,
.osd = osd,
- .gl = gl,
+ .ra = ra,
+ .gl = ra_gl->gl,
.scratch = talloc_zero_size(ctx, 1),
};
- ctx->fmt_table[SUBBITMAP_LIBASS] = gl_find_unorm_format(gl, 1, 1);
- ctx->fmt_table[SUBBITMAP_RGBA] = gl_find_unorm_format(gl, 1, 4);
+ ctx->fmt_table[SUBBITMAP_LIBASS] = ra_find_unorm_format(ra, 1, 1);
+ ctx->fmt_table[SUBBITMAP_RGBA] = ra_find_unorm_format(ra, 1, 4);
for (int n = 0; n < MAX_OSD_PARTS; n++)
ctx->parts[n] = talloc_zero(ctx, struct mpgl_osd_part);
@@ -102,12 +108,9 @@ void mpgl_osd_destroy(struct mpgl_osd *ctx)
if (!ctx)
return;
- GL *gl = ctx->gl;
-
for (int n = 0; n < MAX_OSD_PARTS; n++) {
struct mpgl_osd_part *p = ctx->parts[n];
- gl->DeleteTextures(1, &p->texture);
- gl_pbo_upload_uninit(&p->pbo);
+ ra_tex_free(ctx->ra, &p->texture);
}
talloc_free(ctx);
}
@@ -129,7 +132,7 @@ static int next_pow2(int v)
static bool upload_osd(struct mpgl_osd *ctx, struct mpgl_osd_part *osd,
struct sub_bitmaps *imgs)
{
- GL *gl = ctx->gl;
+ struct ra *ra = ctx->ra;
bool ok = false;
assert(imgs->packed);
@@ -137,47 +140,51 @@ static bool upload_osd(struct mpgl_osd *ctx, struct mpgl_osd_part *osd,
int req_w = next_pow2(imgs->packed_w);
int req_h = next_pow2(imgs->packed_h);
- const struct gl_format *fmt = ctx->fmt_table[imgs->format];
+ const struct ra_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->texture || req_w > osd->w || req_h > osd->h ||
+ osd->format != imgs->format)
+ {
+ ra_tex_free(ra, &osd->texture);
- if (req_w > osd->w || req_h > osd->h || osd->format != imgs->format) {
osd->format = imgs->format;
osd->w = FFMAX(32, req_w);
osd->h = FFMAX(32, req_h);
MP_VERBOSE(ctx, "Reallocating OSD texture to %dx%d.\n", osd->w, osd->h);
- GLint max_wh;
- gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_wh);
-
- if (osd->w > max_wh || osd->h > max_wh) {
+ if (osd->w > ra->max_texture_wh || osd->h > ra->max_texture_wh) {
MP_ERR(ctx, "OSD bitmaps do not fit on a surface with the maximum "
- "supported size %dx%d.\n", max_wh, max_wh);
+ "supported size %dx%d.\n", ra->max_texture_wh,
+ ra->max_texture_wh);
goto done;
}
- 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);
- 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);
+ struct ra_tex_params params = {
+ .dimensions = 2,
+ .w = osd->w,
+ .h = osd->h,
+ .d = 1,
+ .format = fmt,
+ .render_src = true,
+ .src_linear = true,
+ };
+ osd->texture = ra_tex_create(ra, &params);
+ if (!osd->texture)
+ goto done;
}
- gl_pbo_upload_tex(&osd->pbo, gl, ctx->use_pbo, GL_TEXTURE_2D, fmt->format,
- fmt->type, osd->w, osd->h, imgs->packed->planes[0],
- imgs->packed->stride[0], 0, 0,
- imgs->packed_w, imgs->packed_h);
+ osd->texture->use_pbo = ctx->use_pbo;
+
+ struct mp_rect rc = {0, 0, imgs->packed_w, imgs->packed_h};
+ ra->fns->tex_upload(ra, osd->texture, imgs->packed->planes[0],
+ imgs->packed->stride[0], &rc, RA_TEX_UPLOAD_DISCARD,
+ NULL);
+
ok = true;
done:
- gl->BindTexture(GL_TEXTURE_2D, 0);
return ok;
}
@@ -215,7 +222,7 @@ bool mpgl_osd_draw_prepare(struct mpgl_osd *ctx, int index,
if (!fmt || !part->num_subparts)
return false;
- gl_sc_uniform_tex(sc, "osdtex", GL_TEXTURE_2D, part->texture);
+ gl_sc_uniform_texture(sc, "osdtex", part->texture);
switch (fmt) {
case SUBBITMAP_RGBA: {
GLSL(color = texture(osdtex, texcoord).bgra;)
diff --git a/video/out/opengl/osd.h b/video/out/opengl/osd.h
index 36926f95f0..89d52f313e 100644
--- a/video/out/opengl/osd.h
+++ b/video/out/opengl/osd.h
@@ -9,7 +9,8 @@
#include "shader_cache.h"
#include "sub/osd.h"
-struct mpgl_osd *mpgl_osd_init(GL *gl, struct mp_log *log, struct osd_state *osd);
+struct mpgl_osd *mpgl_osd_init(struct ra *ra, struct mp_log *log,
+ struct osd_state *osd);
void mpgl_osd_destroy(struct mpgl_osd *ctx);
void mpgl_osd_set_options(struct mpgl_osd *ctx, bool pbo);
diff --git a/video/out/opengl/ra.h b/video/out/opengl/ra.h
index 21d9cf15d7..3249bc7448 100644
--- a/video/out/opengl/ra.h
+++ b/video/out/opengl/ra.h
@@ -13,6 +13,10 @@ struct ra {
// time.
uint64_t caps;
+ // Maximum supported width and height of a 2D texture. Set by the RA backend
+ // at init time.
+ int max_texture_wh;
+
// Set of supported texture formats. Must be added by RA backend at init time.
struct ra_format **formats;
int num_formats;
@@ -101,6 +105,11 @@ struct ra_mapped_buffer {
size_t size; // total size of the mapping, starting at data
};
+enum {
+ // Flags for the texture_upload flags parameter.
+ RA_TEX_UPLOAD_DISCARD = 1 << 0, // discard pre-existing data not in the region
+};
+
// Rendering API entrypoints. (Note: there are some additional hidden features
// you need to take care of. For example, hwdec mapping will be provided
// separately from ra, but might need to call into ra private code.)
@@ -120,10 +129,15 @@ struct ra_fns {
// This is an extremely common operation.
// Unlike with OpenGL, the src data has to have exactly the same format as
// the texture, and no conversion is supported.
- // tex->params.require_upload must be true.
- // For 1D textures, stride is ignored.
+ // region can be NULL - if it's not NULL, then the provided pointer only
+ // contains data for the given region. Only part of the texture data is
+ // updated, and ptr points to the first pixel in the region. If
+ // RA_TEX_UPLOAD_DISCARD is set, data outside of the region can return to
+ // an uninitialized state. The region is always strictly within the texture
+ // and has a size >0 in both dimensions. 2D textures only.
+ // For 1D textures, stride is ignored, and region must be NULL.
// For 3D textures, stride is not supported. All data is fully packed with
- // no padding, and stride is ignored.
+ // no padding, and stride is ignored, and region must be NULL.
// If buf is not NULL, then src must be within the provided buffer. The
// operation is implied to have dramatically better performance, but
// requires correct flushing and fencing operations by the caller to deal
@@ -131,6 +145,7 @@ struct ra_fns {
// met, undefined behavior will result.
void (*tex_upload)(struct ra *ra, struct ra_tex *tex,
const void *src, ptrdiff_t stride,
+ struct mp_rect *region, uint64_t flags,
struct ra_mapped_buffer *buf);
// Create a persistently mapped buffer for tex_upload.
diff --git a/video/out/opengl/ra_gl.c b/video/out/opengl/ra_gl.c
index 62d16cbdbc..411adddec6 100644
--- a/video/out/opengl/ra_gl.c
+++ b/video/out/opengl/ra_gl.c
@@ -88,6 +88,10 @@ int ra_init_gl(struct ra *ra, GL *gl)
MP_TARRAY_APPEND(ra, ra->formats, ra->num_formats, fmt);
}
+ GLint max_wh;
+ gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_wh);
+ ra->max_texture_wh = max_wh;
+
gl->Disable(GL_DITHER);
return 0;
@@ -307,13 +311,15 @@ struct ra_tex *ra_create_wrapped_fb(struct ra *ra, GLuint gl_fbo, int w, int h)
}
static void gl_tex_upload(struct ra *ra, struct ra_tex *tex,
- const void *src, ptrdiff_t stride,
- struct ra_mapped_buffer *buf)
+ const void *src, ptrdiff_t stride,
+ struct mp_rect *rc, uint64_t flags,
+ struct ra_mapped_buffer *buf)
{
struct ra_gl *p = ra->priv;
GL *gl = p->gl;
struct ra_tex_gl *tex_gl = tex->priv;
struct ra_mapped_buffer_gl *buf_gl = NULL;
+ struct mp_rect full = {0, 0, tex->params.w, tex->params.h};
if (buf) {
buf_gl = buf->priv;
@@ -325,16 +331,20 @@ static void gl_tex_upload(struct ra *ra, struct ra_tex *tex,
switch (tex->params.dimensions) {
case 1:
+ assert(!rc);
gl->TexImage1D(tex_gl->target, 0, tex_gl->internal_format,
tex->params.w, 0, tex_gl->format, tex_gl->type, src);
break;
case 2:
+ if (!rc)
+ rc = &full;
gl_pbo_upload_tex(&tex_gl->pbo, gl, tex->use_pbo && !buf,
tex_gl->target, tex_gl->format, tex_gl->type,
tex->params.w, tex->params.h, src, stride,
- 0, 0, tex->params.w, tex->params.h);
+ rc->x0, rc->y0, rc->x1 - rc->x0, rc->y1 - rc->y0);
break;
case 3:
+ assert(!rc);
gl->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
gl->TexImage3D(GL_TEXTURE_3D, 0, tex_gl->internal_format, tex->params.w,
tex->params.h, tex->params.d, 0, tex_gl->format,
diff --git a/video/out/opengl/video.c b/video/out/opengl/video.c
index 1274cc6e3c..3442e9fb59 100644
--- a/video/out/opengl/video.c
+++ b/video/out/opengl/video.c
@@ -506,7 +506,7 @@ static void reinit_osd(struct gl_video *p)
mpgl_osd_destroy(p->osd);
p->osd = NULL;
if (p->osd_state) {
- p->osd = mpgl_osd_init(p->gl, p->log, p->osd_state);
+ p->osd = mpgl_osd_init(p->ra, p->log, p->osd_state);
mpgl_osd_set_options(p->osd, p->opts.pbo);
}
}
@@ -3326,7 +3326,8 @@ static bool pass_upload_image(struct gl_video *p, struct mp_image *mpi, uint64_t
struct dr_buffer *mapped = gl_find_dr_buffer(p, mpi->planes[n]);
p->ra->fns->tex_upload(p->ra, plane->tex, mpi->planes[n],
- mpi->stride[n], mapped ? mapped->buffer : NULL);
+ mpi->stride[n], NULL, 0,
+ mapped ? mapped->buffer : NULL);
if (mapped && !mapped->mpi)
mapped->mpi = mp_image_new_ref(mpi);