diff options
Diffstat (limited to 'video/out/opengl/utils.c')
-rw-r--r-- | video/out/opengl/utils.c | 222 |
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); } |