summaryrefslogtreecommitdiffstats
path: root/video/out/opengl/utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'video/out/opengl/utils.c')
-rw-r--r--video/out/opengl/utils.c222
1 files changed, 127 insertions, 95 deletions
diff --git a/video/out/opengl/utils.c b/video/out/opengl/utils.c
index 7329240593..40f1beba5f 100644
--- a/video/out/opengl/utils.c
+++ b/video/out/opengl/utils.c
@@ -355,13 +355,18 @@ bool fbotex_change(struct fbotex *fbo, GL *gl, struct mp_log *log, int w, int h,
int cw = w, ch = h;
- if ((flags & FBOTEX_FUZZY_W) && cw < fbo->w)
- cw = fbo->w;
- if ((flags & FBOTEX_FUZZY_H) && ch < fbo->h)
- ch = fbo->h;
-
- if (fbo->w == cw && fbo->h == ch && fbo->iformat == iformat)
+ if ((flags & FBOTEX_FUZZY_W) && cw < fbo->rw)
+ cw = fbo->rw;
+ if ((flags & FBOTEX_FUZZY_H) && ch < fbo->rh)
+ ch = fbo->rh;
+
+ if (fbo->rw == cw && fbo->rh == ch && fbo->iformat == iformat) {
+ fbo->lw = w;
+ fbo->lh = h;
return true;
+ }
+
+ int lw = w, lh = h;
if (flags & FBOTEX_FUZZY_W)
w = MP_ALIGN_UP(w, 256);
@@ -384,12 +389,15 @@ bool fbotex_change(struct fbotex *fbo, GL *gl, struct mp_log *log, int w, int h,
*fbo = (struct fbotex) {
.gl = gl,
- .w = w,
- .h = h,
+ .rw = w,
+ .rh = h,
+ .lw = lw,
+ .lh = lh,
.iformat = iformat,
};
- mp_verbose(log, "Create FBO: %dx%d\n", fbo->w, fbo->h);
+ mp_verbose(log, "Create FBO: %dx%d -> %dx%d\n", fbo->lw, fbo->lh,
+ fbo->rw, fbo->rh);
if (!(gl->mpgl_caps & MPGL_CAP_FB))
return false;
@@ -397,7 +405,7 @@ bool fbotex_change(struct fbotex *fbo, GL *gl, struct mp_log *log, int w, int h,
gl->GenFramebuffers(1, &fbo->fbo);
gl->GenTextures(1, &fbo->texture);
gl->BindTexture(GL_TEXTURE_2D, fbo->texture);
- gl->TexImage2D(GL_TEXTURE_2D, 0, format.internal_format, fbo->w, fbo->h, 0,
+ gl->TexImage2D(GL_TEXTURE_2D, 0, format.internal_format, fbo->rw, fbo->rh, 0,
format.format, format.type, NULL);
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);
@@ -472,11 +480,11 @@ void gl_transform_ortho(struct gl_transform *t, float x0, float x1,
// process. In other words: post-composes t onto x
void gl_transform_trans(struct gl_transform t, struct gl_transform *x)
{
- float x00 = x->m[0][0], x01 = x->m[0][1], x10 = x->m[1][0], x11 = x->m[1][1];
- x->m[0][0] = t.m[0][0] * x00 + t.m[0][1] * x10;
- x->m[1][0] = t.m[0][0] * x01 + t.m[0][1] * x11;
- x->m[0][1] = t.m[1][0] * x00 + t.m[1][1] * x10;
- x->m[1][1] = t.m[1][0] * x01 + t.m[1][1] * x11;
+ struct gl_transform xt = *x;
+ x->m[0][0] = t.m[0][0] * xt.m[0][0] + t.m[0][1] * xt.m[1][0];
+ x->m[1][0] = t.m[1][0] * xt.m[0][0] + t.m[1][1] * xt.m[1][0];
+ x->m[0][1] = t.m[0][0] * xt.m[0][1] + t.m[0][1] * xt.m[1][1];
+ x->m[1][1] = t.m[1][0] * xt.m[0][1] + t.m[1][1] * xt.m[1][1];
gl_transform_vec(t, &x->t[0], &x->t[1]);
}
@@ -498,13 +506,8 @@ static void GLAPIENTRY gl_debug_cb(GLenum source, GLenum type, GLuint id,
void gl_set_debug_logger(GL *gl, struct mp_log *log)
{
- if (gl->DebugMessageCallback) {
- if (log) {
- gl->DebugMessageCallback(gl_debug_cb, log);
- } else {
- gl->DebugMessageCallback(NULL, NULL);
- }
- }
+ if (gl->DebugMessageCallback)
+ gl->DebugMessageCallback(log ? gl_debug_cb : NULL, log);
}
#define SC_ENTRIES 32
@@ -518,26 +521,30 @@ enum uniform_type {
UT_buffer,
};
+union uniform_val {
+ GLfloat f[9];
+ GLint i[4];
+ struct {
+ char* text;
+ GLint binding;
+ } buffer;
+};
+
struct sc_uniform {
char *name;
enum uniform_type type;
const char *glsl_type;
int size;
GLint loc;
- union {
- GLfloat f[9];
- GLint i[4];
- struct {
- char* text;
- GLint binding;
- } buffer;
- } v;
+ union uniform_val v;
};
struct sc_entry {
GLuint gl_shader;
- // the following fields define the shader's contents
- char *key; // vertex+frag shader (mangled)
+ GLint uniform_locs[SC_UNIFORM_ENTRIES];
+ union uniform_val cached_v[SC_UNIFORM_ENTRIES];
+ bstr frag;
+ bstr vert;
struct gl_vao *vao;
};
@@ -546,9 +553,9 @@ struct gl_shader_cache {
struct mp_log *log;
// this is modified during use (gl_sc_add() etc.)
- char *prelude_text;
- char *header_text;
- char *text;
+ bstr prelude_text;
+ bstr header_text;
+ bstr text;
struct gl_vao *vao;
struct sc_entry entries[SC_ENTRIES];
@@ -556,6 +563,9 @@ struct gl_shader_cache {
struct sc_uniform uniforms[SC_UNIFORM_ENTRIES];
int num_uniforms;
+
+ // temporary buffers (avoids frequent reallocations)
+ bstr tmp[5];
};
struct gl_shader_cache *gl_sc_create(GL *gl, struct mp_log *log)
@@ -564,18 +574,15 @@ struct gl_shader_cache *gl_sc_create(GL *gl, struct mp_log *log)
*sc = (struct gl_shader_cache){
.gl = gl,
.log = log,
- .prelude_text = talloc_strdup(sc, ""),
- .header_text = talloc_strdup(sc, ""),
- .text = talloc_strdup(sc, ""),
};
return sc;
}
void gl_sc_reset(struct gl_shader_cache *sc)
{
- sc->prelude_text[0] = '\0';
- sc->header_text[0] = '\0';
- sc->text[0] = '\0';
+ sc->prelude_text.len = 0;
+ sc->header_text.len = 0;
+ sc->text.len = 0;
for (int n = 0; n < sc->num_uniforms; n++) {
talloc_free(sc->uniforms[n].name);
if (sc->uniforms[n].type == UT_buffer)
@@ -589,7 +596,8 @@ static void sc_flush_cache(struct gl_shader_cache *sc)
for (int n = 0; n < sc->num_entries; n++) {
struct sc_entry *e = &sc->entries[n];
sc->gl->DeleteProgram(e->gl_shader);
- talloc_free(e->key);
+ talloc_free(e->vert.start);
+ talloc_free(e->frag.start);
}
sc->num_entries = 0;
}
@@ -605,33 +613,34 @@ void gl_sc_destroy(struct gl_shader_cache *sc)
void gl_sc_enable_extension(struct gl_shader_cache *sc, char *name)
{
- sc->prelude_text = talloc_asprintf_append(sc->prelude_text,
- "#extension %s : enable\n", name);
+ bstr_xappend_asprintf(sc, &sc->prelude_text, "#extension %s : enable\n", name);
}
+#define bstr_xappend0(sc, b, s) bstr_xappend(sc, b, bstr0(s))
+
void gl_sc_add(struct gl_shader_cache *sc, const char *text)
{
- sc->text = talloc_strdup_append(sc->text, text);
+ bstr_xappend0(sc, &sc->text, text);
}
void gl_sc_addf(struct gl_shader_cache *sc, const char *textf, ...)
{
va_list ap;
va_start(ap, textf);
- ta_xvasprintf_append(&sc->text, textf, ap);
+ bstr_xappend_vasprintf(sc, &sc->text, textf, ap);
va_end(ap);
}
void gl_sc_hadd(struct gl_shader_cache *sc, const char *text)
{
- sc->header_text = talloc_strdup_append(sc->header_text, text);
+ bstr_xappend0(sc, &sc->header_text, text);
}
void gl_sc_haddf(struct gl_shader_cache *sc, const char *textf, ...)
{
va_list ap;
va_start(ap, textf);
- ta_xvasprintf_append(&sc->header_text, textf, ap);
+ bstr_xappend_vasprintf(sc, &sc->header_text, textf, ap);
va_end(ap);
}
@@ -789,35 +798,45 @@ static const char *vao_glsl_type(const struct gl_vao_entry *e)
}
// Assumes program is current (gl->UseProgram(program)).
-static void update_uniform(GL *gl, GLuint program, struct sc_uniform *u)
+static void update_uniform(GL *gl, struct sc_entry *e, struct sc_uniform *u, int n)
{
if (u->type == UT_buffer) {
- GLuint idx = gl->GetUniformBlockIndex(program, u->name);
- gl->UniformBlockBinding(program, idx, u->v.buffer.binding);
+ GLuint idx = gl->GetUniformBlockIndex(e->gl_shader, u->name);
+ gl->UniformBlockBinding(e->gl_shader, idx, u->v.buffer.binding);
return;
}
- GLint loc = gl->GetUniformLocation(program, u->name);
+ GLint loc = e->uniform_locs[n];
if (loc < 0)
return;
switch (u->type) {
case UT_i:
assert(u->size == 1);
- gl->Uniform1i(loc, u->v.i[0]);
+ if (memcmp(e->cached_v[n].i, u->v.i, sizeof(u->v.i)) != 0) {
+ memcpy(e->cached_v[n].i, u->v.i, sizeof(u->v.i));
+ gl->Uniform1i(loc, u->v.i[0]);
+ }
break;
case UT_f:
- switch (u->size) {
- case 1: gl->Uniform1f(loc, u->v.f[0]); break;
- case 2: gl->Uniform2f(loc, u->v.f[0], u->v.f[1]); break;
- case 3: gl->Uniform3f(loc, u->v.f[0], u->v.f[1], u->v.f[2]); break;
- case 4: gl->Uniform4f(loc, u->v.f[0], u->v.f[1], u->v.f[2], u->v.f[3]); break;
- default: abort();
+ if (memcmp(e->cached_v[n].f, u->v.f, sizeof(u->v.f)) != 0) {
+ memcpy(e->cached_v[n].f, u->v.f, sizeof(u->v.f));
+ switch (u->size) {
+ case 1: gl->Uniform1f(loc, u->v.f[0]); break;
+ case 2: gl->Uniform2f(loc, u->v.f[0], u->v.f[1]); break;
+ case 3: gl->Uniform3f(loc, u->v.f[0], u->v.f[1], u->v.f[2]); break;
+ case 4: gl->Uniform4f(loc, u->v.f[0], u->v.f[1], u->v.f[2],
+ u->v.f[3]); break;
+ default: abort();
+ }
}
break;
case UT_m:
- switch (u->size) {
- case 2: gl->UniformMatrix2fv(loc, 1, GL_FALSE, &u->v.f[0]); break;
- case 3: gl->UniformMatrix3fv(loc, 1, GL_FALSE, &u->v.f[0]); break;
- default: abort();
+ if (memcmp(e->cached_v[n].f, u->v.f, sizeof(u->v.f)) != 0) {
+ memcpy(e->cached_v[n].f, u->v.f, sizeof(u->v.f));
+ switch (u->size) {
+ case 2: gl->UniformMatrix2fv(loc, 1, GL_FALSE, &u->v.f[0]); break;
+ case 3: gl->UniformMatrix3fv(loc, 1, GL_FALSE, &u->v.f[0]); break;
+ default: abort();
+ }
}
break;
default:
@@ -879,12 +898,13 @@ static GLuint create_program(struct gl_shader_cache *sc, const char *vertex,
{
GL *gl = sc->gl;
MP_VERBOSE(sc, "recompiling a shader program:\n");
- if (sc->header_text[0]) {
+ if (sc->header_text.len) {
MP_VERBOSE(sc, "header:\n");
- mp_log_source(sc->log, MSGL_V, sc->header_text);
+ mp_log_source(sc->log, MSGL_V, sc->header_text.start);
MP_VERBOSE(sc, "body:\n");
}
- mp_log_source(sc->log, MSGL_V, sc->text);
+ if (sc->text.len)
+ mp_log_source(sc->log, MSGL_V, sc->text.start);
GLuint prog = gl->CreateProgram();
compile_attach_shader(sc, prog, GL_VERTEX_SHADER, vertex);
compile_attach_shader(sc, prog, GL_FRAGMENT_SHADER, frag);
@@ -897,7 +917,8 @@ static GLuint create_program(struct gl_shader_cache *sc, const char *vertex,
return prog;
}
-#define ADD(x, ...) (x) = talloc_asprintf_append(x, __VA_ARGS__)
+#define ADD(x, ...) bstr_xappend_asprintf(sc, (x), __VA_ARGS__)
+#define ADD_BSTR(x, s) bstr_xappend(sc, (x), (s))
// 1. Generate vertex and fragment shaders from the fragment shader text added
// with gl_sc_add(). The generated shader program is cached (based on the
@@ -909,25 +930,29 @@ static GLuint create_program(struct gl_shader_cache *sc, const char *vertex,
void gl_sc_gen_shader_and_reset(struct gl_shader_cache *sc)
{
GL *gl = sc->gl;
- void *tmp = talloc_new(NULL);
assert(sc->vao);
+ for (int n = 0; n < MP_ARRAY_SIZE(sc->tmp); n++)
+ sc->tmp[n].len = 0;
+
// set up shader text (header + uniforms + body)
- char *header = talloc_asprintf(tmp, "#version %d%s\n", gl->glsl_version,
- gl->es >= 300 ? " es" : "");
+ bstr *header = &sc->tmp[0];
+ ADD(header, "#version %d%s\n", gl->glsl_version, gl->es >= 300 ? " es" : "");
if (gl->es)
ADD(header, "precision mediump float;\n");
- ADD(header, "%s", sc->prelude_text);
+ ADD_BSTR(header, sc->prelude_text);
char *vert_in = gl->glsl_version >= 130 ? "in" : "attribute";
char *vert_out = gl->glsl_version >= 130 ? "out" : "varying";
char *frag_in = gl->glsl_version >= 130 ? "in" : "varying";
// vertex shader: we don't use the vertex shader, so just setup a dummy,
// which passes through the vertex array attributes.
- char *vert_head = talloc_strdup(tmp, header);
- char *vert_body = talloc_strdup(tmp, "void main() {\n");
- char *frag_vaos = talloc_strdup(tmp, "");
+ bstr *vert_head = &sc->tmp[1];
+ ADD_BSTR(vert_head, *header);
+ bstr *vert_body = &sc->tmp[2];
+ ADD(vert_body, "void main() {\n");
+ bstr *frag_vaos = &sc->tmp[3];
for (int n = 0; sc->vao->entries[n].name; n++) {
const struct gl_vao_entry *e = &sc->vao->entries[n];
const char *glsl_type = vao_glsl_type(e);
@@ -944,10 +969,12 @@ void gl_sc_gen_shader_and_reset(struct gl_shader_cache *sc)
}
}
ADD(vert_body, "}\n");
- char *vert = talloc_asprintf(tmp, "%s%s", vert_head, vert_body);
+ bstr *vert = vert_head;
+ ADD_BSTR(vert, *vert_body);
// fragment shader; still requires adding used uniforms and VAO elements
- char *frag = talloc_strdup(tmp, header);
+ bstr *frag = &sc->tmp[4];
+ ADD_BSTR(frag, *header);
ADD(frag, "#define RG %s\n", gl->mpgl_caps & MPGL_CAP_TEX_RG ? "rg" : "ra");
if (gl->glsl_version >= 130) {
ADD(frag, "#define texture1D texture\n");
@@ -956,13 +983,14 @@ void gl_sc_gen_shader_and_reset(struct gl_shader_cache *sc)
} else {
ADD(frag, "#define texture texture2D\n");
}
- ADD(frag, "%s", frag_vaos);
+ ADD_BSTR(frag, *frag_vaos);
for (int n = 0; n < sc->num_uniforms; n++) {
struct sc_uniform *u = &sc->uniforms[n];
- if (u->type == UT_buffer)
+ if (u->type == UT_buffer) {
ADD(frag, "uniform %s { %s };\n", u->name, u->v.buffer.text);
- else
+ } else {
ADD(frag, "uniform %s %s;\n", u->glsl_type, u->name);
+ }
}
// Additional helpers.
@@ -970,15 +998,15 @@ void gl_sc_gen_shader_and_reset(struct gl_shader_cache *sc)
" mix(0.5 / (lut_size), 1.0 - 0.5 / (lut_size), (x))\n");
// custom shader header
- if (sc->header_text[0]) {
+ if (sc->header_text.len) {
ADD(frag, "// header\n");
- ADD(frag, "%s\n", sc->header_text);
+ ADD_BSTR(frag, sc->header_text);
ADD(frag, "// body\n");
}
ADD(frag, "void main() {\n");
// we require _all_ frag shaders to write to a "vec4 color"
- ADD(frag, "vec4 color;\n");
- ADD(frag, "%s", sc->text);
+ ADD(frag, "vec4 color = vec4(0.0, 0.0, 0.0, 1.0);\n");
+ ADD_BSTR(frag, sc->text);
if (gl->glsl_version >= 130) {
ADD(frag, "out_color = color;\n");
} else {
@@ -986,11 +1014,11 @@ void gl_sc_gen_shader_and_reset(struct gl_shader_cache *sc)
}
ADD(frag, "}\n");
- char *key = talloc_asprintf(tmp, "%s%s", vert, frag);
struct sc_entry *entry = NULL;
for (int n = 0; n < sc->num_entries; n++) {
- if (strcmp(key, sc->entries[n].key) == 0) {
- entry = &sc->entries[n];
+ struct sc_entry *cur = &sc->entries[n];
+ if (bstr_equals(cur->frag, *frag) && bstr_equals(cur->vert, *vert)) {
+ entry = cur;
break;
}
}
@@ -998,20 +1026,24 @@ void gl_sc_gen_shader_and_reset(struct gl_shader_cache *sc)
if (sc->num_entries == SC_ENTRIES)
sc_flush_cache(sc);
entry = &sc->entries[sc->num_entries++];
- *entry = (struct sc_entry){.key = talloc_strdup(NULL, key)};
+ *entry = (struct sc_entry){
+ .vert = bstrdup(NULL, *vert),
+ .frag = bstrdup(NULL, *frag),
+ };
+ }
+ // build vertex shader from vao and cache the locations of the uniform variables
+ if (!entry->gl_shader) {
+ entry->gl_shader = create_program(sc, vert->start, frag->start);
+ for (int n = 0; n < sc->num_uniforms; n++) {
+ entry->uniform_locs[n] = gl->GetUniformLocation(entry->gl_shader,
+ sc->uniforms[n].name);
+ }
}
- // build vertex shader from vao
- if (!entry->gl_shader)
- entry->gl_shader = create_program(sc, vert, frag);
gl->UseProgram(entry->gl_shader);
- // For now we set the uniforms every time. This is probably bad, and we
- // should switch to caching them.
for (int n = 0; n < sc->num_uniforms; n++)
- update_uniform(gl, entry->gl_shader, &sc->uniforms[n]);
-
- talloc_free(tmp);
+ update_uniform(gl, entry, &sc->uniforms[n], n);
gl_sc_reset(sc);
}