summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2017-08-04 15:47:50 +0200
committerwm4 <wm4@nowhere>2017-08-05 13:09:05 +0200
commit0206efa94aea3d4d20584c4446654a5ddd8e7896 (patch)
tree67bd0d8da79023e6b4e4fe6f04bf846a45350637
parenta796745fd272701c9ed435337a161f643d34a26a (diff)
downloadmpv-0206efa94aea3d4d20584c4446654a5ddd8e7896.tar.bz2
mpv-0206efa94aea3d4d20584c4446654a5ddd8e7896.tar.xz
vo_opengl: pass ra objects during rendering instead of GL objects
Another "small" step towards removing GL dependencies from the renderer. This commit generally passes ra_tex objects instead of GL FBO integer IDs to various rendering functions. video.c still manually binds the FBOs when calling shaders. This also happens to fix a memory leak with output_fbo.
-rw-r--r--video/out/opengl/ra.h21
-rw-r--r--video/out/opengl/ra_gl.c157
-rw-r--r--video/out/opengl/ra_gl.h10
-rw-r--r--video/out/opengl/video.c230
4 files changed, 274 insertions, 144 deletions
diff --git a/video/out/opengl/ra.h b/video/out/opengl/ra.h
index bd7a904860..21d9cf15d7 100644
--- a/video/out/opengl/ra.h
+++ b/video/out/opengl/ra.h
@@ -21,6 +21,7 @@ struct ra {
enum {
RA_CAP_TEX_1D = 1 << 0, // supports 1D textures (as shader source textures)
RA_CAP_TEX_3D = 1 << 1, // supports 3D textures (as shader source textures)
+ RA_CAP_BLIT = 1 << 2, // supports ra_fns.blit
};
enum ra_ctype {
@@ -144,6 +145,26 @@ struct ra_fns {
// whether it was signalled yet. If true, write accesses are allowed again.
// Optional, only available if flush_mapping is.
bool (*poll_mapped_buffer)(struct ra *ra, struct ra_mapped_buffer *buf);
+
+ // Clear the dst with the given color (rgba) and within the given scissor.
+ // dst must have dst->params.render_dst==true. Content outside of the
+ // scissor is preserved.
+ void (*clear)(struct ra *ra, struct ra_tex *dst, float color[4],
+ struct mp_rect *scissor);
+
+ // Copy a sub-rectangle from one texture to another. The source/dest region
+ // is always within the texture bounds. Areas outside the dest region are
+ // preserved. The formats of the textures will be losely compatible (this
+ // probably has to be defined strictly). The dst texture can be a swapchain
+ // framebuffer, but src can not. Only 2D textures are supported.
+ // Both textures must have tex->params.render_dst==true (even src, which is
+ // an odd GL requirement).
+ // A rectangle with negative width or height means a flipped copy should be
+ // done. Coordinates are always in pixels.
+ // Optional. Only available if RA_CAP_BLIT is set (if it's not set, the must
+ // not be called, even if it's non-NULL).
+ void (*blit)(struct ra *ra, struct ra_tex *dst, struct ra_tex *src,
+ int dst_x, int dst_y, struct mp_rect *src_rc);
};
struct ra_tex *ra_tex_create(struct ra *ra, const struct ra_tex_params *params);
diff --git a/video/out/opengl/ra_gl.c b/video/out/opengl/ra_gl.c
index a52eeec94b..227bd58fbf 100644
--- a/video/out/opengl/ra_gl.c
+++ b/video/out/opengl/ra_gl.c
@@ -20,6 +20,8 @@ int ra_init_gl(struct ra *ra, GL *gl)
ra->caps |= RA_CAP_TEX_1D;
if (gl->mpgl_caps & MPGL_CAP_3D_TEX)
ra->caps |= RA_CAP_TEX_3D;
+ if (gl->BlitFramebuffer)
+ ra->caps |= RA_CAP_BLIT;
int gl_fmt_features = gl_format_feature_flags(gl);
@@ -101,10 +103,12 @@ static void gl_tex_destroy(struct ra *ra, struct ra_tex *tex)
struct ra_gl *p = ra->priv;
struct ra_tex_gl *tex_gl = tex->priv;
- if (tex_gl->fbo)
- p->gl->DeleteFramebuffers(1, &tex_gl->fbo);
+ if (tex_gl->own_objects) {
+ if (tex_gl->fbo)
+ p->gl->DeleteFramebuffers(1, &tex_gl->fbo);
- p->gl->DeleteTextures(1, &tex_gl->texture);
+ p->gl->DeleteTextures(1, &tex_gl->texture);
+ }
gl_pbo_upload_uninit(&tex_gl->pbo);
talloc_free(tex_gl);
talloc_free(tex);
@@ -121,6 +125,7 @@ static struct ra_tex *gl_tex_create(struct ra *ra,
struct ra_tex_gl *tex_gl = tex->priv = talloc_zero(NULL, struct ra_tex_gl);
const struct gl_format *fmt = params->format->priv;
+ tex_gl->own_objects = true;
tex_gl->internal_format = fmt->internal_format;
tex_gl->format = fmt->format;
tex_gl->type = fmt->type;
@@ -204,6 +209,103 @@ static struct ra_tex *gl_tex_create(struct ra *ra,
return tex;
}
+static const struct ra_format fbo_dummy_format = {
+ .name = "unknown_fbo",
+ .priv = (void *)&(const struct gl_format){
+ .name = "unknown",
+ .format = GL_RGBA,
+ .flags = F_CR,
+ },
+ .renderable = true,
+};
+
+static const struct ra_format tex_dummy_format = {
+ .name = "unknown_tex",
+ .priv = (void *)&(const struct gl_format){
+ .name = "unknown",
+ .format = GL_RGBA,
+ .flags = F_TF,
+ },
+ .renderable = true,
+ .linear_filter = true,
+};
+
+static const struct ra_format *find_similar_format(struct ra *ra,
+ GLint gl_iformat,
+ GLenum gl_format,
+ GLenum gl_type)
+{
+ if (gl_iformat || gl_format || gl_type) {
+ for (int n = 0; n < ra->num_formats; n++) {
+ const struct ra_format *fmt = ra->formats[n];
+ const struct gl_format *gl_fmt = fmt->priv;
+ if ((gl_fmt->internal_format == gl_iformat || !gl_iformat) &&
+ (gl_fmt->format == gl_format || !gl_format) &&
+ (gl_fmt->type == gl_type || !gl_type))
+ return fmt;
+ }
+ }
+ return NULL;
+}
+
+static struct ra_tex *wrap_tex_fbo(struct ra *ra, GLuint gl_obj, bool is_fbo,
+ GLenum gl_target, GLint gl_iformat,
+ GLenum gl_format, GLenum gl_type,
+ int w, int h)
+{
+ const struct ra_format *format =
+ find_similar_format(ra, gl_iformat, gl_format, gl_type);
+ if (!format)
+ format = is_fbo ? &fbo_dummy_format : &tex_dummy_format;
+
+ struct ra_tex *tex = talloc_zero(ra, struct ra_tex);
+ *tex = (struct ra_tex){
+ .params = {
+ .dimensions = 2,
+ .w = w, .h = h, .d = 1,
+ .format = format,
+ .render_dst = is_fbo,
+ .render_src = !is_fbo,
+ .non_normalized = gl_target == GL_TEXTURE_RECTANGLE,
+ },
+ };
+
+ struct ra_tex_gl *tex_gl = tex->priv = talloc_zero(NULL, struct ra_tex_gl);
+ *tex_gl = (struct ra_tex_gl){
+ .target = gl_target,
+ .texture = is_fbo ? 0 : gl_obj,
+ .fbo = is_fbo ? gl_obj : 0,
+ .internal_format = gl_iformat,
+ .format = gl_format,
+ .type = gl_type,
+ };
+
+ return tex;
+}
+
+// Create a ra_tex that merely wraps an existing texture. gl_format and gl_type
+// can be 0, in which case possibly nonsensical fallbacks are chosen.
+// Works for 2D textures only. Integer textures are not supported.
+// The returned object is freed with ra_tex_free(), but this will not delete
+// the texture passed to this function.
+struct ra_tex *ra_create_wrapped_texture(struct ra *ra, GLuint gl_texture,
+ GLenum gl_target, GLint gl_iformat,
+ GLenum gl_format, GLenum gl_type,
+ int w, int h)
+{
+ return wrap_tex_fbo(ra, gl_texture, false, gl_target, gl_iformat, gl_format,
+ gl_type, w, h);
+}
+
+// Create a ra_tex that merely wraps an existing framebuffer. gl_fbo can be 0
+// to wrap the default framebuffer.
+// The returned object is freed with ra_tex_free(), but this will not delete
+// the framebuffer object passed to this function.
+struct ra_tex *ra_create_wrapped_fb(struct ra *ra, GLuint gl_fbo, int w, int h)
+{
+ return wrap_tex_fbo(ra, gl_fbo, true, 0, GL_RGBA, 0, 0, w, h);
+}
+
static void gl_tex_upload(struct ra *ra, struct ra_tex *tex,
const void *src, ptrdiff_t stride,
struct ra_mapped_buffer *buf)
@@ -319,6 +421,53 @@ static bool gl_poll_mapped_buffer(struct ra *ra, struct ra_mapped_buffer *buf)
return !buf_gl->fence;
}
+static void gl_clear(struct ra *ra, struct ra_tex *dst, float color[4],
+ struct mp_rect *scissor)
+{
+ struct ra_gl *p = ra->priv;
+ GL *gl = p->gl;
+
+ assert(dst->params.render_dst);
+ struct ra_tex_gl *dst_gl = dst->priv;
+
+ gl->BindFramebuffer(GL_FRAMEBUFFER, dst_gl->fbo);
+
+ gl->Scissor(scissor->x0, scissor->y0,
+ scissor->x1 - scissor->x0,
+ scissor->y1 - scissor->y0);
+
+ gl->Enable(GL_SCISSOR_TEST);
+ gl->ClearColor(color[0], color[1], color[2], color[3]);
+ gl->Clear(GL_COLOR_BUFFER_BIT);
+ gl->Disable(GL_SCISSOR_TEST);
+
+ gl->BindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+}
+
+static void gl_blit(struct ra *ra, struct ra_tex *dst, struct ra_tex *src,
+ int dst_x, int dst_y, struct mp_rect *src_rc)
+{
+ struct ra_gl *p = ra->priv;
+ GL *gl = p->gl;
+
+ assert(dst->params.render_dst);
+ assert(src->params.render_dst); // even src must have a FBO
+
+ struct ra_tex_gl *src_gl = src->priv;
+ struct ra_tex_gl *dst_gl = dst->priv;
+
+ int w = mp_rect_w(*src_rc);
+ int h = mp_rect_h(*src_rc);
+
+ gl->BindFramebuffer(GL_READ_FRAMEBUFFER, src_gl->fbo);
+ gl->BindFramebuffer(GL_DRAW_FRAMEBUFFER, dst_gl->fbo);
+ gl->BlitFramebuffer(src_rc->x0, src_rc->y0, src_rc->x1, src_rc->y1,
+ dst_x, dst_y, dst_x + w, dst_y + h,
+ GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ gl->BindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+ gl->BindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+}
+
static struct ra_fns ra_fns_gl = {
.destroy = gl_destroy,
.tex_create = gl_tex_create,
@@ -327,4 +476,6 @@ static struct ra_fns ra_fns_gl = {
.create_mapped_buffer = gl_create_mapped_buffer,
.destroy_mapped_buffer = gl_destroy_mapped_buffer,
.poll_mapped_buffer = gl_poll_mapped_buffer,
+ .clear = gl_clear,
+ .blit = gl_blit,
};
diff --git a/video/out/opengl/ra_gl.h b/video/out/opengl/ra_gl.h
index d17b576afc..23e3199aeb 100644
--- a/video/out/opengl/ra_gl.h
+++ b/video/out/opengl/ra_gl.h
@@ -11,9 +11,10 @@ struct ra_gl {
// For ra_tex.priv
struct ra_tex_gl {
+ bool own_objects;
GLenum target;
- GLuint texture;
- GLuint fbo; // 0 if no rendering requested
+ GLuint texture; // 0 if no texture data associated
+ GLuint fbo; // 0 if no rendering requested, or it default framebuffer
// These 3 fields can be 0 if unknown.
GLint internal_format;
GLenum format;
@@ -28,3 +29,8 @@ struct ra_mapped_buffer_gl {
};
int ra_init_gl(struct ra *ra, GL *gl);
+struct ra_tex *ra_create_wrapped_texture(struct ra *ra, GLuint gl_texture,
+ GLenum gl_target, GLint gl_iformat,
+ GLenum gl_format, GLenum gl_type,
+ int w, int h);
+struct ra_tex *ra_create_wrapped_fb(struct ra *ra, GLuint gl_fbo, int w, int h);
diff --git a/video/out/opengl/video.c b/video/out/opengl/video.c
index 3fa85019df..0923d626d1 100644
--- a/video/out/opengl/video.c
+++ b/video/out/opengl/video.c
@@ -86,14 +86,8 @@ static const struct gl_vao_entry vertex_vao[] = {
};
struct texplane {
- struct ra_tex *texture;
+ struct ra_tex *tex;
int w, h;
- int tex_w, tex_h;
- GLint gl_internal_format;
- GLenum gl_target;
- GLenum gl_format;
- GLenum gl_type;
- GLuint gl_texture;
bool flipped;
};
@@ -102,6 +96,8 @@ struct video_image {
struct mp_image *mpi; // original input image
uint64_t id; // unique ID identifying mpi contents
bool hwdec_mapped;
+ // Temporary wrappers for GL hwdec textures.
+ struct ra_tex *hwdec_tex[4];
};
enum plane_type {
@@ -128,10 +124,7 @@ struct img_tex {
enum plane_type type; // must be set to something non-zero
int components; // number of relevant coordinates
float multiplier; // multiplier to be used when sampling
- GLuint gl_tex;
- GLenum gl_target;
- GLenum gl_format;
- int tex_w, tex_h; // source texture size
+ struct ra_tex *tex;
int w, h; // logical size (after transformation)
struct gl_transform transform; // rendering transformation
};
@@ -442,14 +435,6 @@ static void gl_video_setup_hooks(struct gl_video *p);
#define GLSLHF(...) gl_sc_haddf(p->sc, __VA_ARGS__)
#define PRELUDE(...) gl_sc_paddf(p->sc, __VA_ARGS__)
-static GLuint get_fbo(struct fbotex *fbo)
-{
- if (!fbo->tex)
- return -1;
- struct ra_tex_gl *tex_gl = fbo->tex->priv;
- return tex_gl->fbo ? tex_gl->fbo : -1;
-}
-
static struct bstr load_cached_file(struct gl_video *p, const char *path)
{
if (!path || !path[0])
@@ -542,6 +527,7 @@ static void uninit_rendering(struct gl_video *p)
fbotex_uninit(&p->indirect_fbo);
fbotex_uninit(&p->blend_subs_fbo);
fbotex_uninit(&p->screen_fbo);
+ fbotex_uninit(&p->output_fbo);
for (int n = 0; n < FBOSURFACES_MAX; n++)
fbotex_uninit(&p->surfaces[n].fbotex);
@@ -641,14 +627,10 @@ static struct img_tex img_tex_fbo(struct fbotex *fbo, enum plane_type type,
int components)
{
assert(type != PLANE_NONE);
- struct ra_tex_gl *tex_gl = fbo->tex->priv;
return (struct img_tex){
.type = type,
- .gl_tex = tex_gl->texture,
- .gl_target = GL_TEXTURE_2D,
+ .tex = fbo->tex,
.multiplier = 1.0,
- .tex_w = fbo->rw,
- .tex_h = fbo->rh,
.w = fbo->lw,
.h = fbo->lh,
.transform = identity_trans,
@@ -772,12 +754,8 @@ static void pass_get_img_tex(struct gl_video *p, struct video_image *vimg,
tex[n] = (struct img_tex){
.type = type,
- .gl_tex = t->gl_texture,
- .gl_target = t->gl_target,
- .gl_format = t->gl_format,
+ .tex = t->tex,
.multiplier = tex_mul,
- .tex_w = t->tex_w,
- .tex_h = t->tex_h,
.w = t->w,
.h = t->h,
};
@@ -907,35 +885,25 @@ static void init_video(struct gl_video *p)
plane->w = mp_image_plane_w(&layout, n);
plane->h = mp_image_plane_h(&layout, n);
- plane->tex_w = plane->w + p->opts.tex_pad_x;
- plane->tex_h = plane->h + p->opts.tex_pad_y;
struct ra_tex_params params = {
.dimensions = 2,
- .w = plane->tex_w,
- .h = plane->tex_h,
+ .w = plane->w + p->opts.tex_pad_x,
+ .h = plane->h + p->opts.tex_pad_y,
.d = 1,
.format = format,
.src_linear = format->linear_filter,
.non_normalized = p->opts.use_rectangle,
};
- plane->texture = p->ra->fns->tex_create(p->ra, &params);
- if (!plane->texture)
- abort(); // shit happens
-
- struct ra_tex_gl *tex_gl = plane->texture->priv;
+ MP_VERBOSE(p, "Texture for plane %d: %dx%d\n", n,
+ params.w, params.h);
- plane->gl_texture = tex_gl->texture;
- plane->gl_target = tex_gl->target;
- plane->gl_format = tex_gl->format;
- plane->gl_internal_format = tex_gl->internal_format;
- plane->gl_type = tex_gl->type;
+ plane->tex = ra_tex_create(p->ra, &params);
+ if (!plane->tex)
+ abort(); // shit happens
p->use_integer_conversion |= format->ctype == RA_CTYPE_UINT;
-
- MP_VERBOSE(p, "Texture for plane %d: %dx%d\n", n,
- plane->tex_w, plane->tex_h);
}
}
@@ -951,6 +919,8 @@ static void unmap_current_image(struct gl_video *p)
if (vimg->hwdec_mapped) {
assert(p->hwdec_active);
+ for (int n = 0; n < 4; n++)
+ ra_tex_free(p->ra, &vimg->hwdec_tex[n]);
if (p->hwdec->driver->unmap)
p->hwdec->driver->unmap(p->hwdec);
memset(vimg->planes, 0, sizeof(vimg->planes));
@@ -1030,8 +1000,7 @@ static void uninit_video(struct gl_video *p)
for (int n = 0; n < p->plane_count; n++) {
struct texplane *plane = &vimg->planes[n];
- if (plane->texture)
- p->ra->fns->tex_destroy(p->ra, plane->texture);
+ ra_tex_free(p->ra, &plane->tex);
}
*vimg = (struct video_image){0};
@@ -1107,7 +1076,7 @@ static void pass_prepare_src_tex(struct gl_video *p)
for (int n = 0; n < p->pass_tex_num; n++) {
struct img_tex *s = &p->pass_tex[n];
- if (!s->gl_tex)
+ if (!s->tex)
continue;
char *texture_name = mp_tprintf(32, "texture%d", n);
@@ -1116,15 +1085,11 @@ static void pass_prepare_src_tex(struct gl_video *p)
char *texture_off = mp_tprintf(32, "texture_off%d", n);
char *pixel_size = mp_tprintf(32, "pixel_size%d", n);
- if (gl_is_integer_format(s->gl_format)) {
- gl_sc_uniform_tex_ui(sc, texture_name, s->gl_tex);
- } else {
- gl_sc_uniform_tex(sc, texture_name, s->gl_target, s->gl_tex);
- }
+ gl_sc_uniform_texture(sc, texture_name, s->tex);
float f[2] = {1, 1};
- if (s->gl_target != GL_TEXTURE_RECTANGLE) {
- f[0] = s->tex_w;
- f[1] = s->tex_h;
+ if (!s->tex->params.non_normalized) {
+ f[0] = s->tex->params.w;
+ f[1] = s->tex->params.h;
}
gl_sc_uniform_vec2(sc, texture_size, f);
gl_sc_uniform_mat2(sc, texture_rot, true, (float *)s->transform.m);
@@ -1168,15 +1133,15 @@ static void dispatch_compute(struct gl_video *p, int w, int h,
for (int n = 0; n < TEXUNIT_VIDEO_NUM; n++) {
struct img_tex *s = &p->pass_tex[n];
- if (!s->gl_tex)
+ if (!s->tex)
continue;
// We need to rescale the coordinates to the true texture size
char tex_scale[32];
snprintf(tex_scale, sizeof(tex_scale), "tex_scale%d", n);
gl_sc_uniform_vec2(p->sc, tex_scale, (GLfloat[2]){
- (float)s->w / s->tex_w,
- (float)s->h / s->tex_h,
+ (float)s->w / s->tex->params.w,
+ (float)s->h / s->tex->params.h,
});
PRELUDE("#define texcoord%d_raw(id) (tex_scale%d * outcoord(id))\n", n, n);
@@ -1223,15 +1188,15 @@ static void render_pass_quad(struct gl_video *p, int vp_w, int vp_h,
v->position.y = y[n % 2];
for (int i = 0; i < p->pass_tex_num; i++) {
struct img_tex *s = &p->pass_tex[i];
- if (!s->gl_tex)
+ if (!s->tex)
continue;
struct gl_transform tr = s->transform;
float tx = (n / 2) * s->w;
float ty = (n % 2) * s->h;
gl_transform_vec(tr, &tx, &ty);
- bool rect = s->gl_target == GL_TEXTURE_RECTANGLE;
- v->texcoord[i].x = tx / (rect ? 1 : s->tex_w);
- v->texcoord[i].y = ty / (rect ? 1 : s->tex_h);
+ bool rect = s->tex->params.non_normalized;
+ v->texcoord[i].x = tx / (rect ? 1 : s->tex->params.w);
+ v->texcoord[i].y = ty / (rect ? 1 : s->tex->params.h);
}
}
@@ -1241,13 +1206,15 @@ static void render_pass_quad(struct gl_video *p, int vp_w, int vp_h,
debug_check_gl(p, "after rendering");
}
-static void finish_pass_direct(struct gl_video *p, GLint fbo, int vp_w, int vp_h,
- const struct mp_rect *dst)
+static void finish_pass_direct(struct gl_video *p, struct ra_tex *target,
+ int vp_w, int vp_h, const struct mp_rect *dst)
{
GL *gl = p->gl;
pass_prepare_src_tex(p);
gl_sc_set_vertex_format(p->sc, vertex_vao, sizeof(struct vertex));
pass_record(p, gl_sc_generate(p->sc, GL_FRAGMENT_SHADER));
+ struct ra_tex_gl *tex_gl = target ? target->priv : NULL;
+ int fbo = tex_gl ? tex_gl->fbo : 0;
gl->BindFramebuffer(GL_FRAMEBUFFER, fbo);
render_pass_quad(p, vp_w, vp_h, dst);
gl->BindFramebuffer(GL_FRAMEBUFFER, 0);
@@ -1280,14 +1247,14 @@ static void finish_pass_fbo(struct gl_video *p, struct fbotex *dst_fbo,
p->gl->MemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
p->pass_compute = (struct compute_info){0};
} else {
- finish_pass_direct(p, get_fbo(dst_fbo), dst_fbo->rw, dst_fbo->rh,
+ finish_pass_direct(p, dst_fbo->tex, dst_fbo->rw, dst_fbo->rh,
&(struct mp_rect){0, 0, w, h});
}
}
static const char *get_tex_swizzle(struct img_tex *img)
{
- return img->gl_format == GL_LUMINANCE_ALPHA ? "raaa" : "rgba";
+ return img->tex->params.format->luminance_alpha ? "raaa" : "rgba";
}
// Copy a texture to the vec4 color, while increasing offset. Also applies
@@ -1307,7 +1274,7 @@ static void copy_img_tex(struct gl_video *p, int *offset, struct img_tex img)
dst[i] = dst_fmt[*offset + i];
}
- if (gl_is_integer_format(img.gl_format)) {
+ if (img.tex && img.tex->params.format->ctype == RA_CTYPE_UINT) {
uint64_t tex_max = 1ull << p->ra_format.component_bits;
img.multiplier *= 1.0 / (tex_max - 1);
}
@@ -1836,10 +1803,9 @@ static bool img_tex_equiv(struct img_tex a, struct img_tex b)
return a.type == b.type &&
a.components == b.components &&
a.multiplier == b.multiplier &&
- a.gl_target == b.gl_target &&
- a.gl_format == b.gl_format &&
- a.tex_w == b.tex_w &&
- a.tex_h == b.tex_h &&
+ a.tex->params.format == b.tex->params.format &&
+ a.tex->params.w == b.tex->params.w &&
+ a.tex->params.h == b.tex->params.h &&
a.w == b.w &&
a.h == b.h &&
gl_transform_eq(a.transform, b.transform);
@@ -2075,7 +2041,7 @@ static void pass_read_video(struct gl_video *p)
// If any textures are still in integer format by this point, we need
// to introduce an explicit conversion pass to avoid breaking hooks/scaling
for (int n = 0; n < 4; n++) {
- if (gl_is_integer_format(tex[n].gl_format)) {
+ if (tex[n].tex && tex[n].tex->params.format->ctype == RA_CTYPE_UINT) {
GLSLF("// use_integer fix for plane %d\n", n);
copy_img_tex(p, &(int){0}, tex[n]);
pass_describe(p, "use_integer fix");
@@ -2650,12 +2616,14 @@ static void pass_dither(struct gl_video *p)
// Draws the OSD, in scene-referred colors.. If cms is true, subtitles are
// instead adapted to the display's gamut.
static void pass_draw_osd(struct gl_video *p, int draw_flags, double pts,
- struct mp_osd_res rect, int vp_w, int vp_h, int fbo,
- bool cms)
+ struct mp_osd_res rect, int vp_w, int vp_h,
+ struct ra_tex *target, bool cms)
{
+ struct ra_tex_gl *tex_gl = target->priv;
+
mpgl_osd_generate(p->osd, rect, pts, p->image_params.stereo_out, draw_flags);
- p->gl->BindFramebuffer(GL_FRAMEBUFFER, fbo);
+ p->gl->BindFramebuffer(GL_FRAMEBUFFER, tex_gl->fbo);
for (int n = 0; n < MAX_OSD_PARTS; n++) {
// (This returns false if this part is empty with nothing to draw.)
if (!mpgl_osd_draw_prepare(p->osd, n, p->sc))
@@ -2684,10 +2652,8 @@ static float chroma_realign(int size, int pixel)
}
// Minimal rendering code path, for GLES or OpenGL 2.1 without proper FBOs.
-static void pass_render_frame_dumb(struct gl_video *p, int fbo)
+static void pass_render_frame_dumb(struct gl_video *p)
{
- p->gl->BindFramebuffer(GL_FRAMEBUFFER, fbo);
-
struct img_tex tex[4];
struct gl_transform off[4];
pass_get_img_tex(p, &p->image, tex, off);
@@ -2763,7 +2729,7 @@ static bool pass_render_frame(struct gl_video *p, struct mp_image *mpi, uint64_t
};
finish_pass_fbo(p, &p->blend_subs_fbo, rect.w, rect.h, 0);
pass_draw_osd(p, OSD_DRAW_SUB_ONLY, vpts, rect,
- rect.w, rect.h, get_fbo(&p->blend_subs_fbo), false);
+ rect.w, rect.h, p->blend_subs_fbo.tex, false);
pass_read_fbo(p, &p->blend_subs_fbo);
pass_describe(p, "blend subs video");
}
@@ -2793,7 +2759,7 @@ static bool pass_render_frame(struct gl_video *p, struct mp_image *mpi, uint64_t
}
finish_pass_fbo(p, &p->blend_subs_fbo, p->texture_w, p->texture_h, 0);
pass_draw_osd(p, OSD_DRAW_SUB_ONLY, vpts, rect,
- p->texture_w, p->texture_h, get_fbo(&p->blend_subs_fbo),
+ p->texture_w, p->texture_h, p->blend_subs_fbo.tex,
false);
pass_read_fbo(p, &p->blend_subs_fbo);
pass_describe(p, "blend subs");
@@ -2804,10 +2770,10 @@ static bool pass_render_frame(struct gl_video *p, struct mp_image *mpi, uint64_t
return true;
}
-static void pass_draw_to_screen(struct gl_video *p, int fbo)
+static void pass_draw_to_screen(struct gl_video *p, struct ra_tex *fbo)
{
if (p->dumb_mode)
- pass_render_frame_dumb(p, fbo);
+ pass_render_frame_dumb(p);
// Adjust the overall gamma before drawing to screen
if (p->user_gamma != 1) {
@@ -2878,7 +2844,7 @@ static bool update_fbosurface(struct gl_video *p, struct mp_image *mpi,
// Draws an interpolate frame to fbo, based on the frame timing in t
static void gl_video_interpolate_frame(struct gl_video *p, struct vo_frame *t,
- int fbo)
+ struct ra_tex *fbo)
{
bool is_new = false;
@@ -3069,9 +3035,11 @@ void gl_video_render_frame(struct gl_video *p, struct vo_frame *frame, int fbo)
}
}
- p->broken_frame = false;
+ struct ra_tex *target =
+ ra_create_wrapped_fb(p->ra, fbo, p->vp_w, abs(p->vp_h));
+ struct mp_rect target_rc = {0, 0, p->vp_w, abs(p->vp_h)};
- gl->BindFramebuffer(GL_FRAMEBUFFER, fbo);
+ p->broken_frame = false;
bool has_frame = !!frame->current;
@@ -3079,20 +3047,14 @@ void gl_video_render_frame(struct gl_video *p, struct vo_frame *frame, int fbo)
p->dst_rect.x1 < p->vp_w || p->dst_rect.y1 < abs(p->vp_h))
{
struct m_color c = p->opts.background;
- gl->ClearColor(c.r / 255.0, c.g / 255.0, c.b / 255.0, c.a / 255.0);
- gl->Clear(GL_COLOR_BUFFER_BIT);
+ float color[4] = {c.r / 255.0, c.g / 255.0, c.b / 255.0, c.a / 255.0};
+ p->ra->fns->clear(p->ra, target, color, &target_rc);
}
if (p->hwdec_active && p->hwdec->driver->overlay_frame) {
if (has_frame) {
- float *c = p->hwdec->overlay_colorkey;
- gl->Scissor(p->dst_rect.x0, p->dst_rect.y0,
- p->dst_rect.x1 - p->dst_rect.x0,
- p->dst_rect.y1 - p->dst_rect.y0);
- gl->Enable(GL_SCISSOR_TEST);
- gl->ClearColor(c[0], c[1], c[2], c[3]);
- gl->Clear(GL_COLOR_BUFFER_BIT);
- gl->Disable(GL_SCISSOR_TEST);
+ float *color = p->hwdec->overlay_colorkey;
+ p->ra->fns->clear(p->ra, target, color, &p->dst_rect);
}
if (frame->frame_id != p->image.id || !frame->current)
@@ -3115,7 +3077,7 @@ void gl_video_render_frame(struct gl_video *p, struct vo_frame *frame, int fbo)
}
if (interpolate) {
- gl_video_interpolate_frame(p, frame, fbo);
+ gl_video_interpolate_frame(p, frame, target);
} else {
bool is_new = frame->frame_id != p->image.id;
@@ -3132,14 +3094,14 @@ void gl_video_render_frame(struct gl_video *p, struct vo_frame *frame, int fbo)
// For the non-interpolation case, we draw to a single "cache"
// FBO to speed up subsequent re-draws (if any exist)
- int dest_fbo = fbo;
+ struct ra_tex *dest_fbo = target;
if (frame->num_vsyncs > 1 && frame->display_synced &&
- !p->dumb_mode && gl->BlitFramebuffer)
+ !p->dumb_mode && (p->ra->caps & RA_CAP_BLIT))
{
fbotex_change(&p->output_fbo, p->ra, p->log,
p->vp_w, abs(p->vp_h),
p->fbo_format, FBOTEX_FUZZY);
- dest_fbo = get_fbo(&p->output_fbo);
+ dest_fbo = p->output_fbo.tex;
p->output_fbo_valid = true;
}
pass_draw_to_screen(p, dest_fbo);
@@ -3149,20 +3111,15 @@ void gl_video_render_frame(struct gl_video *p, struct vo_frame *frame, int fbo)
if (p->output_fbo_valid) {
pass_info_reset(p, true);
pass_describe(p, "redraw cached frame");
- gl->BindFramebuffer(GL_READ_FRAMEBUFFER, get_fbo(&p->output_fbo));
- gl->BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
struct mp_rect rc = p->dst_rect;
if (p->vp_h < 0) {
rc.y1 = -p->vp_h - p->dst_rect.y0;
rc.y0 = -p->vp_h - p->dst_rect.y1;
}
gl_timer_start(p->blit_timer);
- gl->BlitFramebuffer(rc.x0, rc.y0, rc.x1, rc.y1,
- rc.x0, rc.y0, rc.x1, rc.y1,
- GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ p->ra->fns->blit(p->ra, target, p->output_fbo.tex,
+ rc.x0, rc.y0, &rc);
gl_timer_stop(gl);
- gl->BindFramebuffer(GL_READ_FRAMEBUFFER, 0);
- gl->BindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
pass_record(p, gl_timer_measure(p->blit_timer));
}
}
@@ -3174,8 +3131,6 @@ done:
debug_check_gl(p, "after video rendering");
- gl->BindFramebuffer(GL_FRAMEBUFFER, fbo);
-
if (p->osd) {
// If we haven't actually drawn anything so far, then we technically
// need to consider this the start of a new pass. Let's call it a
@@ -3184,20 +3139,21 @@ done:
pass_info_reset(p, true);
pass_draw_osd(p, p->opts.blend_subs ? OSD_DRAW_OSD_ONLY : 0,
- p->osd_pts, p->osd_rect, p->vp_w, p->vp_h, fbo, true);
+ p->osd_pts, p->osd_rect, p->vp_w, p->vp_h, target, true);
debug_check_gl(p, "after OSD rendering");
}
- gl->UseProgram(0);
if (gl_sc_error_state(p->sc) || p->broken_frame) {
// Make the screen solid blue to make it visually clear that an
// error has occurred
- gl->ClearColor(0.0, 0.05, 0.5, 1.0);
- gl->Clear(GL_COLOR_BUFFER_BIT);
+ float color[4] = {0.0, 0.05, 0.5, 1.0};
+ p->ra->fns->clear(p->ra, target, color, &target_rc);
}
gl->BindFramebuffer(GL_FRAMEBUFFER, 0);
+ ra_tex_free(p->ra, &target);
+
// The playloop calls this last before waiting some time until it decides
// to call flip_page(). Tell OpenGL to start execution of the GPU commands
// while we sleep (this happens asynchronously).
@@ -3251,7 +3207,8 @@ void gl_video_perfdata(struct gl_video *p, struct voctrl_performance_data *out)
}
// This assumes nv12, with textures set to GL_NEAREST filtering.
-static void reinterleave_vdpau(struct gl_video *p, struct gl_hwdec_frame *frame)
+static void reinterleave_vdpau(struct gl_video *p, struct gl_hwdec_frame *frame,
+ struct ra_tex *output[4])
{
struct gl_hwdec_frame res = {0};
for (int n = 0; n < 2; n++) {
@@ -3261,14 +3218,14 @@ static void reinterleave_vdpau(struct gl_video *p, struct gl_hwdec_frame *frame)
int w = src[0].tex_w;
int h = src[0].tex_h;
int ids[2];
+ struct ra_tex *tmp[2];
for (int t = 0; t < 2; t++) {
+ tmp[t] = ra_create_wrapped_texture(p->ra, src[t].gl_texture,
+ GL_TEXTURE_2D, 0, 0, 0, w, h);
ids[t] = pass_bind(p, (struct img_tex){
- .gl_tex = src[t].gl_texture,
- .gl_target = src[t].gl_target,
+ .tex = tmp[t],
.multiplier = 1.0,
.transform = identity_trans,
- .tex_w = w,
- .tex_h = h,
.w = w,
.h = h,
});
@@ -3283,20 +3240,13 @@ static void reinterleave_vdpau(struct gl_video *p, struct gl_hwdec_frame *frame)
fbotex_change(fbo, p->ra, p->log, w, h * 2, fmt, 0);
pass_describe(p, "vdpau reinterleaving");
- finish_pass_direct(p, get_fbo(fbo), fbo->rw, fbo->rh,
+ finish_pass_direct(p, fbo->tex, fbo->rw, fbo->rh,
&(struct mp_rect){0, 0, w, h * 2});
- GLuint tex = 0;
- if (fbo->tex) {
- struct ra_tex_gl *tex_gl = fbo->tex->priv;
- tex = tex_gl->texture;
- }
- res.planes[n] = (struct gl_hwdec_plane){
- .gl_texture = tex,
- .gl_target = GL_TEXTURE_2D,
- .tex_w = w,
- .tex_h = h * 2,
- };
+ for (int t = 0; t < 2; t++)
+ ra_tex_free(p->ra, &tmp[t]);
+
+ output[n] = fbo->tex;
}
*frame = res;
}
@@ -3335,18 +3285,20 @@ static bool pass_upload_image(struct gl_video *p, struct mp_image *mpi, uint64_t
if (ok) {
struct mp_image layout = {0};
mp_image_set_params(&layout, &p->image_params);
+ struct ra_tex *tex[4] = {0};
if (gl_frame.vdpau_fields)
- reinterleave_vdpau(p, &gl_frame);
+ reinterleave_vdpau(p, &gl_frame, tex);
for (int n = 0; n < p->plane_count; n++) {
struct gl_hwdec_plane *plane = &gl_frame.planes[n];
+ if (!tex[n]) {
+ vimg->hwdec_tex[n] = ra_create_wrapped_texture(p->ra,
+ plane->gl_texture, plane->gl_target, 0,
+ plane->gl_format, 0, plane->tex_w, plane->tex_h);
+ }
vimg->planes[n] = (struct texplane){
.w = mp_image_plane_w(&layout, n),
.h = mp_image_plane_h(&layout, n),
- .tex_w = plane->tex_w,
- .tex_h = plane->tex_h,
- .gl_target = plane->gl_target,
- .gl_texture = plane->gl_texture,
- .gl_format = plane->gl_format,
+ .tex = tex[n] ? tex[n] : vimg->hwdec_tex[n],
};
}
} else {
@@ -3366,11 +3318,11 @@ static bool pass_upload_image(struct gl_video *p, struct mp_image *mpi, uint64_t
plane->flipped = mpi->stride[0] < 0;
// (It's unclear whether this should be changeable on the fly.)
- plane->texture->use_pbo = p->opts.pbo;
+ plane->tex->use_pbo = p->opts.pbo;
struct dr_buffer *mapped = gl_find_dr_buffer(p, mpi->planes[n]);
- p->ra->fns->tex_upload(p->ra, plane->texture, mpi->planes[n],
+ p->ra->fns->tex_upload(p->ra, plane->tex, mpi->planes[n],
mpi->stride[n], mapped ? mapped->buffer : NULL);