diff options
-rw-r--r-- | video/out/opengl/osd.c | 75 | ||||
-rw-r--r-- | video/out/opengl/utils.c | 65 | ||||
-rw-r--r-- | video/out/opengl/utils.h | 12 | ||||
-rw-r--r-- | video/out/opengl/video.c | 79 |
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); |