summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@mplayer2.org>2011-10-29 19:38:33 +0200
committerwm4 <wm4@mplayer2.org>2011-12-25 20:42:58 +0100
commitadc85b0031867bfc2296f2749e8544e8147b5b60 (patch)
tree019fa759b181cae644e27fda1973c2b317e9faa4
parent4010dd0b1a27e399606299b428d1f9bc645cf8fd (diff)
downloadmpv-adc85b0031867bfc2296f2749e8544e8147b5b60.tar.bz2
mpv-adc85b0031867bfc2296f2749e8544e8147b5b60.tar.xz
vo_gl: use generic eosd code
This is an experiment. The change probably doesn't matter much. One issue with the old code was that "large" images caused each sub-image to be created and rendered as a new texture. "Large" in this case means larger than 32x32 pixels, which actually isn't very large with screen sizes beyond 1500x1000 pixels. This means rendering a simple subtitle for a fullscreened video may allocate many small textures, one for each glyph. On the other hand, the old code could be fixed by tuning the texture sizes for "modern" work loads. Also, the new code uses less deprecated OpenGL features and draws all sub-images in one batch. There are two possible issues the new code could cause: - Drivers could have performance issues with the larger texture sizes and the number of glTexSubImage2D calls on it - There is only one EOSD texture, which could become full (it's enlarged on demand, but restricted by driver texture size limitations) It has been reported that this is faster on OSX with ATI GPUs than the old code.
-rw-r--r--libvo/gl_common.c6
-rw-r--r--libvo/gl_common.h7
-rw-r--r--libvo/vo_gl.c256
3 files changed, 124 insertions, 145 deletions
diff --git a/libvo/gl_common.c b/libvo/gl_common.c
index 7cca800d40..aa34521802 100644
--- a/libvo/gl_common.c
+++ b/libvo/gl_common.c
@@ -360,6 +360,12 @@ static const extfunc_desc_t extfuncs[] = {
DEF_FUNC_DESC(ColorMask),
DEF_FUNC_DESC(ReadPixels),
DEF_FUNC_DESC(ReadBuffer),
+ DEF_FUNC_DESC(VertexPointer),
+ DEF_FUNC_DESC(ColorPointer),
+ DEF_FUNC_DESC(TexCoordPointer),
+ DEF_FUNC_DESC(DrawArrays),
+ DEF_FUNC_DESC(EnableClientState),
+ DEF_FUNC_DESC(DisableClientState),
DEF_EXT_DESC(GenBuffers, NULL,
("glGenBuffers", "glGenBuffersARB")),
diff --git a/libvo/gl_common.h b/libvo/gl_common.h
index 8e3294f441..5a0fd9b8a8 100644
--- a/libvo/gl_common.h
+++ b/libvo/gl_common.h
@@ -463,6 +463,13 @@ struct GL {
void (GLAPIENTRY *ReadPixels)(GLint, GLint, GLsizei, GLsizei, GLenum,
GLenum, GLvoid *);
void (GLAPIENTRY *ReadBuffer)(GLenum);
+ void (GLAPIENTRY *VertexPointer)(GLint, GLenum, GLsizei, const GLvoid *);
+ void (GLAPIENTRY *ColorPointer)(GLint, GLenum, GLsizei, const GLvoid *);
+ void (GLAPIENTRY *TexCoordPointer)(GLint, GLenum, GLsizei, const GLvoid *);
+ void (GLAPIENTRY *DrawArrays)(GLenum, GLint, GLsizei);
+ void (GLAPIENTRY *EnableClientState)(GLenum);
+ void (GLAPIENTRY *DisableClientState)(GLenum);
+
// OpenGL extension functions
void (GLAPIENTRY *GenBuffers)(GLsizei, GLuint *);
diff --git a/libvo/vo_gl.c b/libvo/vo_gl.c
index e68465f009..7bf5cf2ec1 100644
--- a/libvo/vo_gl.c
+++ b/libvo/vo_gl.c
@@ -38,6 +38,7 @@
#include "osd.h"
#include "sub/font_load.h"
#include "sub/sub.h"
+#include "eosd_packer.h"
#include "gl_common.h"
#include "aspect.h"
@@ -49,19 +50,17 @@ static int preinit_nosw(struct vo *vo, const char *arg);
//! How many parts the OSD may consist of at most
#define MAX_OSD_PARTS 20
-#define LARGE_EOSD_TEX_SIZE 512
-#define TINYTEX_SIZE 16
-#define TINYTEX_COLS (LARGE_EOSD_TEX_SIZE / TINYTEX_SIZE)
-#define TINYTEX_MAX (TINYTEX_COLS * TINYTEX_COLS)
-#define SMALLTEX_SIZE 32
-#define SMALLTEX_COLS (LARGE_EOSD_TEX_SIZE / SMALLTEX_SIZE)
-#define SMALLTEX_MAX (SMALLTEX_COLS * SMALLTEX_COLS)
-
//for gl_priv.use_yuv
#define MASK_ALL_YUV (~(1 << YUV_CONVERSION_NONE))
#define MASK_NOT_COMBINERS (~((1 << YUV_CONVERSION_NONE) | (1 << YUV_CONVERSION_COMBINERS)))
#define MASK_GAMMA_SUPPORT (MASK_NOT_COMBINERS & ~(1 << YUV_CONVERSION_FRAGMENT))
+struct vertex_eosd {
+ float x, y;
+ uint8_t color[4];
+ float u, v;
+};
+
struct gl_priv {
MPGLContext *glctx;
GL *gl;
@@ -74,17 +73,17 @@ struct gl_priv {
//! Alpha textures for OSD
GLuint osdatex[MAX_OSD_PARTS];
#endif
- GLuint *eosdtex;
- GLuint largeeosdtex[2];
+ GLuint eosd_texture;
+ int eosd_texture_width, eosd_texture_height;
+ struct eosd_packer *eosd;
+ struct vertex_eosd *eosd_va;
//! Display lists that draw the OSD parts
GLuint osdDispList[MAX_OSD_PARTS];
#ifndef FAST_OSD
GLuint osdaDispList[MAX_OSD_PARTS];
#endif
- GLuint eosdDispList;
//! How many parts the OSD currently consists of
int osdtexCnt;
- int eosdtexCnt;
int osd_color;
int use_ycbcr;
@@ -285,150 +284,111 @@ static void clearOSD(struct vo *vo)
}
/**
- * \brief remove textures, display list and free memory used by EOSD
+ * \brief construct display list from ass image list
+ * \param img image list to create OSD from.
*/
-static void clearEOSD(struct vo *vo)
+static void genEOSD(struct vo *vo, mp_eosd_images_t *imgs)
{
struct gl_priv *p = vo->priv;
GL *gl = p->gl;
- if (p->eosdDispList)
- gl->DeleteLists(p->eosdDispList, 1);
- p->eosdDispList = 0;
- if (p->eosdtexCnt)
- gl->DeleteTextures(p->eosdtexCnt, p->eosdtex);
- p->eosdtexCnt = 0;
- free(p->eosdtex);
- p->eosdtex = NULL;
-}
+ bool need_repos, need_upload, need_allocate;
+ eosd_packer_generate(p->eosd, imgs, &need_repos, &need_upload,
+ &need_allocate);
-static inline int is_tinytex(ASS_Image *i, int tinytexcur)
-{
- return i->w < TINYTEX_SIZE && i->h < TINYTEX_SIZE
- && tinytexcur < TINYTEX_MAX;
-}
+ if (!need_repos)
+ return;
-static inline int is_smalltex(ASS_Image *i, int smalltexcur)
-{
- return i->w < SMALLTEX_SIZE && i->h < SMALLTEX_SIZE
- && smalltexcur < SMALLTEX_MAX;
-}
+ if (!p->eosd_texture)
+ gl->GenTextures(1, &p->eosd_texture);
-static inline void tinytex_pos(int tinytexcur, int *x, int *y)
-{
- *x = (tinytexcur % TINYTEX_COLS) * TINYTEX_SIZE;
- *y = (tinytexcur / TINYTEX_COLS) * TINYTEX_SIZE;
-}
+ gl->BindTexture(p->target, p->eosd_texture);
-static inline void smalltex_pos(int smalltexcur, int *x, int *y)
-{
- *x = (smalltexcur % SMALLTEX_COLS) * SMALLTEX_SIZE;
- *y = (smalltexcur / SMALLTEX_COLS) * SMALLTEX_SIZE;
+ if (need_allocate) {
+ texSize(vo, p->eosd->surface.w, p->eosd->surface.h,
+ &p->eosd_texture_width, &p->eosd_texture_height);
+ // xxx it doesn't need to be cleared, that's a waste of time
+ glCreateClearTex(gl, p->target, GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE,
+ GL_NEAREST, p->eosd_texture_width,
+ p->eosd_texture_height, 0);
+ }
+
+ // 2 triangles primitives per quad = 6 vertices per quad
+ // not using GL_QUADS, as it is deprecated in OpenGL 3.x and later
+ p->eosd_va = talloc_realloc_size(p->eosd, p->eosd_va,
+ p->eosd->targets_count
+ * sizeof(struct vertex_eosd) * 6);
+
+ float eosd_w = p->eosd_texture_width;
+ float eosd_h = p->eosd_texture_height;
+
+ if (p->use_rectangle == 1)
+ eosd_w = eosd_h = 1.0f;
+
+ for (int n = 0; n < p->eosd->targets_count; n++) {
+ struct eosd_target *target = &p->eosd->targets[n];
+ ASS_Image *i = target->ass_img;
+
+ if (need_upload) {
+ glUploadTex(gl, p->target, GL_ALPHA, GL_UNSIGNED_BYTE, i->bitmap,
+ i->stride, target->source.x0, target->source.y0,
+ i->w, i->h, 0);
+ }
+
+ uint8_t color[4] = { i->color >> 24, (i->color >> 16) & 0xff,
+ (i->color >> 8) & 0xff, 255 - (i->color & 0xff) };
+
+ float x0 = target->dest.x0;
+ float y0 = target->dest.y0;
+ float x1 = target->dest.x1;
+ float y1 = target->dest.y1;
+ float tx0 = target->source.x0 / eosd_w;
+ float ty0 = target->source.y0 / eosd_h;
+ float tx1 = target->source.x1 / eosd_w;
+ float ty1 = target->source.y1 / eosd_h;
+
+#define COLOR_INIT {color[0], color[1], color[2], color[3]}
+ struct vertex_eosd *va = &p->eosd_va[n * 6];
+ va[0] = (struct vertex_eosd) { x0, y0, COLOR_INIT, tx0, ty0 };
+ va[1] = (struct vertex_eosd) { x0, y1, COLOR_INIT, tx0, ty1 };
+ va[2] = (struct vertex_eosd) { x1, y0, COLOR_INIT, tx1, ty0 };
+ va[3] = (struct vertex_eosd) { x1, y1, COLOR_INIT, tx1, ty1 };
+ va[4] = va[2];
+ va[5] = va[1];
+#undef COLOR_INIT
+ }
+
+ gl->BindTexture(p->target, 0);
}
-/**
- * \brief construct display list from ass image list
- * \param img image list to create OSD from.
- * A value of NULL has the same effect as clearEOSD()
- */
-static void genEOSD(struct vo *vo, mp_eosd_images_t *imgs)
+// Note: relies on state being setup, like projection matrix and blending
+static void drawEOSD(struct vo *vo)
{
struct gl_priv *p = vo->priv;
GL *gl = p->gl;
- int sx, sy;
- int tinytexcur = 0;
- int smalltexcur = 0;
- GLuint *curtex;
- GLint scale_type = p->scaled_osd ? GL_LINEAR : GL_NEAREST;
- ASS_Image *img = imgs->imgs;
- ASS_Image *i;
-
- if (imgs->changed == 0) // there are elements, but they are unchanged
+ if (p->eosd->targets_count == 0)
return;
- if (img && imgs->changed == 1) // there are elements, but they just moved
- goto skip_upload;
- clearEOSD(vo);
- if (!img)
- return;
- if (!p->largeeosdtex[0]) {
- gl->GenTextures(2, p->largeeosdtex);
- for (int n = 0; n < 2; n++) {
- gl->BindTexture(p->target, p->largeeosdtex[n]);
- glCreateClearTex(gl, p->target, GL_ALPHA, GL_ALPHA,
- GL_UNSIGNED_BYTE, scale_type,
- LARGE_EOSD_TEX_SIZE, LARGE_EOSD_TEX_SIZE, 0);
- }
- }
- for (i = img; i; i = i->next) {
- if (i->w <= 0 || i->h <= 0 || i->stride < i->w)
- continue;
- if (is_tinytex(i, tinytexcur))
- tinytexcur++;
- else if (is_smalltex(i, smalltexcur))
- smalltexcur++;
- else
- p->eosdtexCnt++;
- }
- mp_msg(MSGT_VO, MSGL_DBG2, "EOSD counts (tiny, small, all): %i, %i, %i\n",
- tinytexcur, smalltexcur, p->eosdtexCnt);
- if (p->eosdtexCnt) {
- p->eosdtex = calloc(p->eosdtexCnt, sizeof(GLuint));
- gl->GenTextures(p->eosdtexCnt, p->eosdtex);
- }
- tinytexcur = smalltexcur = 0;
- for (i = img, curtex = p->eosdtex; i; i = i->next) {
- int x = 0, y = 0;
- if (i->w <= 0 || i->h <= 0 || i->stride < i->w) {
- mp_msg(MSGT_VO, MSGL_V, "Invalid dimensions OSD for part!\n");
- continue;
- }
- if (is_tinytex(i, tinytexcur)) {
- tinytex_pos(tinytexcur, &x, &y);
- gl->BindTexture(p->target, p->largeeosdtex[0]);
- tinytexcur++;
- } else if (is_smalltex(i, smalltexcur)) {
- smalltex_pos(smalltexcur, &x, &y);
- gl->BindTexture(p->target, p->largeeosdtex[1]);
- smalltexcur++;
- } else {
- texSize(vo, i->w, i->h, &sx, &sy);
- gl->BindTexture(p->target, *curtex++);
- glCreateClearTex(gl, p->target, GL_ALPHA, GL_ALPHA,
- GL_UNSIGNED_BYTE, scale_type, sx, sy, 0);
- }
- glUploadTex(gl, p->target, GL_ALPHA, GL_UNSIGNED_BYTE, i->bitmap,
- i->stride, x, y, i->w, i->h, 0);
- }
- p->eosdDispList = gl->GenLists(1);
-skip_upload:
- gl->NewList(p->eosdDispList, GL_COMPILE);
- tinytexcur = smalltexcur = 0;
- for (i = img, curtex = p->eosdtex; i; i = i->next) {
- int x = 0, y = 0;
- if (i->w <= 0 || i->h <= 0 || i->stride < i->w)
- continue;
- gl->Color4ub(i->color >> 24, (i->color >> 16) & 0xff,
- (i->color >> 8) & 0xff, 255 - (i->color & 0xff));
- if (is_tinytex(i, tinytexcur)) {
- tinytex_pos(tinytexcur, &x, &y);
- sx = sy = LARGE_EOSD_TEX_SIZE;
- gl->BindTexture(p->target, p->largeeosdtex[0]);
- tinytexcur++;
- } else if (is_smalltex(i, smalltexcur)) {
- smalltex_pos(smalltexcur, &x, &y);
- sx = sy = LARGE_EOSD_TEX_SIZE;
- gl->BindTexture(p->target, p->largeeosdtex[1]);
- smalltexcur++;
- } else {
- texSize(vo, i->w, i->h, &sx, &sy);
- gl->BindTexture(p->target, *curtex++);
- }
- glDrawTex(gl, i->dst_x, i->dst_y, i->w, i->h, x, y, i->w, i->h, sx, sy,
- p->use_rectangle == 1, 0, 0);
- }
- gl->EndList();
+ gl->BindTexture(p->target, p->eosd_texture);
+
+ struct vertex_eosd *va = p->eosd_va;
+ size_t stride = sizeof(struct vertex_eosd);
+
+ gl->VertexPointer(2, GL_FLOAT, stride, &va[0].x);
+ gl->ColorPointer(4, GL_UNSIGNED_BYTE, stride, &va[0].color[0]);
+ gl->TexCoordPointer(2, GL_FLOAT, stride, &va[0].u);
+
+ gl->EnableClientState(GL_VERTEX_ARRAY);
+ gl->EnableClientState(GL_TEXTURE_COORD_ARRAY);
+ gl->EnableClientState(GL_COLOR_ARRAY);
+
+ gl->DrawArrays(GL_TRIANGLES, 0, p->eosd->targets_count * 6);
+
+ gl->DisableClientState(GL_VERTEX_ARRAY);
+ gl->DisableClientState(GL_TEXTURE_COORD_ARRAY);
+ gl->DisableClientState(GL_COLOR_ARRAY);
+
gl->BindTexture(p->target, 0);
}
@@ -450,10 +410,10 @@ static void uninitGl(struct vo *vo)
gl->DeleteTextures(i, p->default_texs);
p->default_texs[0] = 0;
clearOSD(vo);
- clearEOSD(vo);
- if (p->largeeosdtex[0])
- gl->DeleteTextures(2, p->largeeosdtex);
- p->largeeosdtex[0] = 0;
+ if (p->eosd_texture)
+ gl->DeleteTextures(1, &p->eosd_texture);
+ eosd_packer_reinit(p->eosd, 0, 0);
+ p->eosd_texture = 0;
if (gl->DeleteBuffers && p->buffer)
gl->DeleteBuffers(1, &p->buffer);
p->buffer = 0;
@@ -633,6 +593,10 @@ static int initGl(struct vo *vo, uint32_t d_width, uint32_t d_height)
update_yuvconv(vo);
}
+ GLint max_texture_size;
+ gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
+ eosd_packer_reinit(p->eosd, max_texture_size, max_texture_size);
+
resize(vo, d_width, d_height);
gl->ClearColor(0.0f, 0.0f, 0.0f, 0.0f);
@@ -786,7 +750,7 @@ static void do_render_osd(struct vo *vo, int type)
GL *gl = p->gl;
int draw_osd = (type & RENDER_OSD) && p->osdtexCnt > 0;
- int draw_eosd = (type & RENDER_EOSD) && p->eosdDispList;
+ int draw_eosd = (type & RENDER_EOSD);
if (!draw_osd && !draw_eosd)
return;
// set special rendering parameters
@@ -799,7 +763,7 @@ static void do_render_osd(struct vo *vo, int type)
gl->Enable(GL_BLEND);
if (draw_eosd) {
gl->BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- gl->CallList(p->eosdDispList);
+ drawEOSD(vo);
}
if (draw_osd) {
gl->Color4ub((p->osd_color >> 16) & 0xff, (p->osd_color >> 8) & 0xff,
@@ -1239,6 +1203,8 @@ static int preinit_internal(struct vo *vo, const char *arg, int allow_sw,
.osd_color = 0xffffff,
};
+ p->eosd = eosd_packer_create(vo);
+
//essentially unused; for legacy warnings only
int user_colorspace = 0;
int levelconv = -1;