summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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);