summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2016-07-03 16:00:51 +0200
committerwm4 <wm4@nowhere>2016-07-03 16:34:32 +0200
commit823c353faaab569264f6d6d8c3d335bb0173b9e1 (patch)
tree68f5a6a63b4a2e96f16d2834b0c9c797895b2def
parent06219c7f880225fdcd23885f1e9363821064012e (diff)
downloadmpv-823c353faaab569264f6d6d8c3d335bb0173b9e1.tar.bz2
mpv-823c353faaab569264f6d6d8c3d335bb0173b9e1.tar.xz
vo_opengl: move PBO upload handling to shared code
This introduces a gl_pbo_upload_tex() function, which works almost like our gl_upload_tex() glTexSubImage2D() wrapper, except it takes a struct which caches the PBO handles. It also takes the full texture size (to make allocating an ideal buffer size easier), and a parameter to disable PBOs (so that the caller doesn't have to duplicate the gl_upload_tex() call if PBOs are disabled or unavailable). This also removes warnings and fallbacks on PBO failure. We just silently try using PBOs on every frame, and if that fails at some point, revert to normal texture uploads. Probably doesn't matter.
-rw-r--r--video/out/opengl/osd.c75
-rw-r--r--video/out/opengl/utils.c65
-rw-r--r--video/out/opengl/utils.h12
-rw-r--r--video/out/opengl/video.c79
4 files changed, 91 insertions, 140 deletions
diff --git a/video/out/opengl/osd.c b/video/out/opengl/osd.c
index e1370a91a5..fde7e868c4 100644
--- a/video/out/opengl/osd.c
+++ b/video/out/opengl/osd.c
@@ -51,7 +51,7 @@ struct mpgl_osd_part {
int change_id;
GLuint texture;
int w, h;
- GLuint buffer;
+ struct gl_pbo_upload pbo;
int num_subparts;
int prev_num_subparts;
struct sub_bitmap *subparts;
@@ -113,8 +113,7 @@ void mpgl_osd_destroy(struct mpgl_osd *ctx)
for (int n = 0; n < MAX_OSD_PARTS; n++) {
struct mpgl_osd_part *p = ctx->parts[n];
gl->DeleteTextures(1, &p->texture);
- if (gl->DeleteBuffers)
- gl->DeleteBuffers(1, &p->buffer);
+ gl_pbo_upload_uninit(&p->pbo);
}
talloc_free(ctx);
}
@@ -124,63 +123,6 @@ void mpgl_osd_set_options(struct mpgl_osd *ctx, bool pbo)
ctx->use_pbo = pbo;
}
-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;
- 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;
- int copy_w = imgs->packed_w;
- int copy_h = imgs->packed_h;
- size_t stride = imgs->packed->stride[0];
- void *texdata = imgs->packed->planes[0];
-
- 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);
- }
-
- gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, osd->buffer);
- 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;
- }
-
- memcpy_pic(data, texdata, pix_stride * copy_w, copy_h,
- osd->w * pix_stride, stride);
- stride = osd->w * pix_stride;
- texdata = NULL;
-
- if (!gl->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER)) {
- success = false;
- goto done;
- }
- }
-
- 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");
- }
-
- return success;
-}
-
static int next_pow2(int v)
{
for (int x = 0; x < 30; x++) {
@@ -226,17 +168,12 @@ static bool upload_osd(struct mpgl_osd *ctx, struct mpgl_osd_part *osd,
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);
-
- if (gl->DeleteBuffers)
- gl->DeleteBuffers(1, &osd->buffer);
- osd->buffer = 0;
}
- bool uploaded = false;
- if (ctx->use_pbo)
- uploaded = upload(ctx, osd, imgs, true);
- if (!uploaded)
- upload(ctx, osd, imgs, false);
+ 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);
gl->BindTexture(GL_TEXTURE_2D, 0);
diff --git a/video/out/opengl/utils.c b/video/out/opengl/utils.c
index 8ddae33d8f..b47da6b1da 100644
--- a/video/out/opengl/utils.c
+++ b/video/out/opengl/utils.c
@@ -1124,3 +1124,68 @@ void gl_timer_stop(struct gl_timer *timer)
if (gl->EndQuery)
gl->EndQuery(GL_TIME_ELAPSED);
}
+
+// Upload a texture, going through a PBO. PBO supposedly can facilitate
+// asynchronous copy from CPU to GPU, so this is an optimization. Note that
+// changing format/type/tex_w/tex_h or reusing the PBO in the same frame can
+// ruin performance.
+// This call is like gl_upload_tex(), plus PBO management/use.
+// target, format, type, dataptr, stride, x, y, w, h: texture upload params
+// (see gl_upload_tex())
+// tex_w, tex_h: maximum size of the used texture
+// use_pbo: for convenience, if false redirects the call to gl_upload_tex
+void gl_pbo_upload_tex(struct gl_pbo_upload *pbo, GL *gl, bool use_pbo,
+ GLenum target, GLenum format, GLenum type,
+ int tex_w, int tex_h, const void *dataptr, int stride,
+ int x, int y, int w, int h)
+{
+ assert(x >= 0 && y >= 0 && w >= 0 && h >= 0);
+ assert(x + w <= tex_w && y + h <= tex_h);
+
+ if (!use_pbo || !gl->MapBufferRange)
+ goto no_pbo;
+
+ size_t pix_stride = gl_bytes_per_pixel(format, type);
+ size_t buffer_size = pix_stride * tex_w * tex_h;
+ size_t needed_size = pix_stride * w * h;
+
+ if (buffer_size != pbo->buffer_size)
+ gl_pbo_upload_uninit(pbo);
+
+ if (!pbo->buffer) {
+ pbo->gl = gl;
+ pbo->buffer_size = buffer_size;
+ gl->GenBuffers(1, &pbo->buffer);
+ gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo->buffer);
+ gl->BufferData(GL_PIXEL_UNPACK_BUFFER, buffer_size, NULL, GL_DYNAMIC_COPY);
+ }
+
+ gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo->buffer);
+ void *data = gl->MapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, needed_size,
+ GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
+ if (!data)
+ goto no_pbo;
+
+ memcpy_pic(data, dataptr, pix_stride * w, h, pix_stride * w, stride);
+
+ if (!gl->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER)) {
+ gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+ goto no_pbo;
+ }
+
+ gl_upload_tex(gl, target, format, type, NULL, pix_stride * w, x, y, w, h);
+
+ gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+
+ return;
+
+no_pbo:
+ gl_upload_tex(gl, target, format, type, dataptr, stride, x, y, w, h);
+}
+
+void gl_pbo_upload_uninit(struct gl_pbo_upload *pbo)
+{
+ if (pbo->gl)
+ pbo->gl->DeleteBuffers(1, &pbo->buffer);
+ *pbo = (struct gl_pbo_upload){0};
+}
diff --git a/video/out/opengl/utils.h b/video/out/opengl/utils.h
index 9b4fd8471d..35211f6485 100644
--- a/video/out/opengl/utils.h
+++ b/video/out/opengl/utils.h
@@ -182,4 +182,16 @@ uint64_t gl_timer_last_us(struct gl_timer *timer);
uint64_t gl_timer_avg_us(struct gl_timer *timer);
uint64_t gl_timer_peak_us(struct gl_timer *timer);
+struct gl_pbo_upload {
+ GL *gl;
+ GLuint buffer;
+ size_t buffer_size;
+};
+
+void gl_pbo_upload_tex(struct gl_pbo_upload *pbo, GL *gl, bool use_pbo,
+ GLenum target, GLenum format, GLenum type,
+ int tex_w, int tex_h, const void *dataptr, int stride,
+ int x, int y, int w, int h);
+void gl_pbo_upload_uninit(struct gl_pbo_upload *pbo);
+
#endif
diff --git a/video/out/opengl/video.c b/video/out/opengl/video.c
index d8343698ca..271725aaeb 100644
--- a/video/out/opengl/video.c
+++ b/video/out/opengl/video.c
@@ -96,8 +96,8 @@ struct texplane {
GLenum gl_format;
GLenum gl_type;
GLuint gl_texture;
- int gl_buffer;
char swizzle[5];
+ struct gl_pbo_upload pbo;
};
struct video_image {
@@ -878,7 +878,7 @@ static void uninit_video(struct gl_video *p)
struct texplane *plane = &vimg->planes[n];
gl->DeleteTextures(1, &plane->gl_texture);
- gl->DeleteBuffers(1, &plane->gl_buffer);
+ gl_pbo_upload_uninit(&plane->pbo);
}
*vimg = (struct video_image){0};
@@ -2890,54 +2890,6 @@ struct voctrl_performance_data gl_video_perfdata(struct gl_video *p)
};
}
-static bool unmap_image(struct gl_video *p, struct mp_image *mpi)
-{
- GL *gl = p->gl;
- bool ok = true;
- struct video_image *vimg = &p->image;
- for (int n = 0; n < p->plane_count; n++) {
- struct texplane *plane = &vimg->planes[n];
- gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, plane->gl_buffer);
- ok = gl->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER) && ok;
- mpi->planes[n] = NULL; // PBO offset 0
- }
- gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
- return ok;
-}
-
-static bool map_image(struct gl_video *p, struct mp_image *mpi)
-{
- GL *gl = p->gl;
-
- if (!p->opts.pbo)
- return false;
-
- struct video_image *vimg = &p->image;
-
- for (int n = 0; n < p->plane_count; n++) {
- struct texplane *plane = &vimg->planes[n];
- mpi->stride[n] = mp_image_plane_w(mpi, n) * p->image_desc.bytes[n];
- size_t buffer_size = mp_image_plane_h(mpi, n) * mpi->stride[n];
- if (!plane->gl_buffer) {
- gl->GenBuffers(1, &plane->gl_buffer);
- gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, plane->gl_buffer);
- gl->BufferData(GL_PIXEL_UNPACK_BUFFER, buffer_size,
- NULL, GL_DYNAMIC_DRAW);
- }
- gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, plane->gl_buffer);
- mpi->planes[n] = gl->MapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0,
- buffer_size, GL_MAP_WRITE_BIT |
- GL_MAP_INVALIDATE_BUFFER_BIT);
- gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
- if (!mpi->planes[n]) {
- unmap_image(p, mpi);
- return false;
- }
- }
- memset(mpi->bufs, 0, sizeof(mpi->bufs));
- return true;
-}
-
// This assumes nv12, with textures set to GL_NEAREST filtering.
static void reinterleave_vdpau(struct gl_video *p, struct gl_hwdec_frame *frame)
{
@@ -3034,32 +2986,17 @@ static bool gl_video_upload_image(struct gl_video *p, struct mp_image *mpi)
gl_timer_start(p->upload_timer);
- mp_image_t pbo_mpi = *mpi;
- bool pbo = map_image(p, &pbo_mpi);
- if (pbo) {
- mp_image_copy(&pbo_mpi, mpi);
- if (unmap_image(p, &pbo_mpi)) {
- mpi = &pbo_mpi;
- } else {
- MP_FATAL(p, "Video PBO upload failed. Disabling PBOs.\n");
- pbo = false;
- p->opts.pbo = 0;
- }
- }
-
vimg->image_flipped = mpi->stride[0] < 0;
for (int n = 0; n < p->plane_count; n++) {
struct texplane *plane = &vimg->planes[n];
- if (pbo)
- gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, plane->gl_buffer);
- gl->ActiveTexture(GL_TEXTURE0 + n);
+
gl->BindTexture(plane->gl_target, plane->gl_texture);
- gl_upload_tex(gl, plane->gl_target, plane->gl_format, plane->gl_type,
- mpi->planes[n], mpi->stride[n], 0, 0, plane->w, plane->h);
+ gl_pbo_upload_tex(&plane->pbo, gl, p->opts.pbo, plane->gl_target,
+ plane->gl_format, plane->gl_type, plane->w, plane->h,
+ mpi->planes[n], mpi->stride[n],
+ 0, 0, plane->w, plane->h);
+ gl->BindTexture(plane->gl_target, 0);
}
- gl->ActiveTexture(GL_TEXTURE0);
- if (pbo)
- gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
gl_timer_stop(p->upload_timer);