mirror of https://github.com/mpv-player/mpv
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.
This commit is contained in:
parent
a796745fd2
commit
0206efa94a
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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, ¶ms);
|
||||
if (!plane->texture)
|
||||
MP_VERBOSE(p, "Texture for plane %d: %dx%d\n", n,
|
||||
params.w, params.h);
|
||||
|
||||
plane->tex = ra_tex_create(p->ra, ¶ms);
|
||||
if (!plane->tex)
|
||||
abort(); // shit happens
|
||||
|
||||
struct ra_tex_gl *tex_gl = plane->texture->priv;
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
if (mapped && !mapped->mpi)
|
||||
|
|
Loading…
Reference in New Issue