vo_opengl: unify PBO and normal OSD texture upload path

The main change is actually that e first copy to a "staging" memory
frame, and then upload this at once. The old non-PBO code called
glTexsubImage2D for each OSD sub-bitmap.

The new non-PBO code path is a bit faster now if there are many small
sub-bitmaps (on Linux/nVidia). It's also a bit simpler, so this is a
win.

(Although I don't particularly appreciate the mixed normal/PBO texture
code.)
This commit is contained in:
wm4 committed 2016-05-23 21:27:18 +02:00
1 parent 049e3ccb65
commit 66079048ea
3 files changed
+49 -71

No files matched your search

+49 -44
View File
@@ -57,6 +57,7 @@ struct mpgl_osd_part {
struct sub_bitmap *subparts;
struct vertex *vertices;
struct bitmap_packer *packer;
void *upload;
};
struct mpgl_osd {
@@ -124,6 +125,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);
}
@@ -133,8 +135,8 @@ 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;
@@ -142,30 +144,50 @@ static bool upload_pbo(struct mpgl_osd *ctx, struct mpgl_osd_part *osd,
size_t pix_stride = gl_bytes_per_pixel(fmt->format, fmt->type);
size_t buffer_size = pix_stride * osd->h * osd->w;
if (!osd->buffer) {
gl->GenBuffers(1, &osd->buffer);
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);
}
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, 0);
}
gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, osd->buffer);
char *data = gl->MapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, buffer_size,
GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
if (!data) {
success = false;
} else {
struct pos bb[2];
packer_get_bb(osd->packer, bb);
size_t stride = osd->w * pix_stride;
packer_copy_subbitmaps(osd->packer, imgs, data, pix_stride, stride);
if (!gl->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER))
data = gl->MapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, buffer_size,
GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
if (!data) {
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;
}
} else {
if (!osd->upload)
osd->upload = talloc_size(NULL, buffer_size);
data = osd->upload;
texdata = data;
}
gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
struct pos bb[2];
packer_get_bb(osd->packer, bb);
size_t stride = osd->w * pix_stride;
packer_copy_subbitmaps(osd->packer, imgs, data, pix_stride, stride);
if (pbo) {
if (!gl->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER)) {
success = false;
goto done;
}
}
glUploadTex(gl, GL_TEXTURE_2D, fmt->format, fmt->type, texdata, stride,
bb[0].x, bb[0].y, bb[1].x - bb[0].x, bb[1].y - bb[0].y, 0);
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");
@@ -174,26 +196,6 @@ 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)
{
const struct gl_format *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);
}
}
static bool upload_osd(struct mpgl_osd *ctx, struct mpgl_osd_part *osd,
struct sub_bitmaps *imgs)
{
@@ -234,13 +236,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);
-25
View File
@@ -103,31 +103,6 @@ void glUploadTex(GL *gl, GLenum target, GLenum format, GLenum type,
gl->PixelStorei(GL_UNPACK_ALIGNMENT, 4);
}
// Like glUploadTex, but upload a byte array with all elements set to val.
// If scratch is not NULL, points to a resizeable talloc memory block than can
// be freely used by the function (for avoiding temporary memory allocations).
void glClearTex(GL *gl, GLenum target, GLenum format, GLenum type,
int x, int y, int w, int h, uint8_t val, void **scratch)
{
int bpp = gl_bytes_per_pixel(format, type);
int stride = w * bpp;
int size = h * stride;
if (size < 1 || !bpp)
return;
void *data = scratch ? *scratch : NULL;
if (talloc_get_size(data) < size)
data = talloc_realloc(NULL, data, char *, size);
memset(data, val, size);
gl->PixelStorei(GL_UNPACK_ALIGNMENT, get_alignment(stride));
gl->TexSubImage2D(target, 0, x, y, w, h, format, type, data);
gl->PixelStorei(GL_UNPACK_ALIGNMENT, 4);
if (scratch) {
*scratch = data;
} else {
talloc_free(data);
}
}
mp_image_t *glGetWindowScreenshot(GL *gl)
{
if (gl->es)
-2
View File
@@ -29,8 +29,6 @@ void glCheckError(GL *gl, struct mp_log *log, const char *info);
void glUploadTex(GL *gl, GLenum target, GLenum format, GLenum type,
const void *dataptr, int stride,
int x, int y, int w, int h, int slice);
void glClearTex(GL *gl, GLenum target, GLenum format, GLenum type,
int x, int y, int w, int h, uint8_t val, void **scratch);
mp_image_t *glGetWindowScreenshot(GL *gl);