1
0
mirror of https://github.com/mpv-player/mpv synced 2024-12-25 16:33:02 +00:00

vo_opengl: further GL API use separation

Move multiple GL-specific things from the renderer to other places like
vo_opengl.c, vo_opengl_cb.c, and ra_gl.c.

The vp_w/vp_h parameters to gl_video_resize() make no sense anymore, and
are implicitly part of struct fbodst.

Checking the main framebuffer depth is moved to vo_opengl.c. For
vo_opengl_cb.c it always assumes 8. The API user now has to override
this manually. The previous heuristic didn't make much sense anyway.

The only remaining dependency on GL is the hwdec stuff, which is harder
to change.
This commit is contained in:
wm4 2017-08-07 19:14:18 +02:00
parent 1adf324d8b
commit 47ea771b7a
15 changed files with 172 additions and 122 deletions

View File

@ -30,6 +30,11 @@ Interface changes
- --opengl-fbo-format changes from a choice to a string. Also, its value
will be checked only on renderer initialization, rather than when the
option is set.
- Using opengl-cb now always assumes 8 bit per component depth, and dithers
to this size. Before, it tried to figure out the depth of the first
framebuffer that was ever passed to the renderer. Having GL framebuffers
with a size larger than 8 bit per component is quite rare. If you need
it, set the --dither-depth option instead.
--- mpv 0.26.0 ---
- remove remaining deprecated audio device options, like --alsa-device
Some of them were removed in earlier releases.

View File

@ -115,6 +115,12 @@ bool mp_rect_intersection(struct mp_rect *rc, const struct mp_rect *rc2)
return rc->x1 > rc->x0 && rc->y1 > rc->y0;
}
bool mp_rect_equals(struct mp_rect *rc1, struct mp_rect *rc2)
{
return rc1->x0 == rc2->x0 && rc1->y0 == rc2->y0 &&
rc1->x1 == rc2->x1 && rc1->y1 == rc2->y1;
}
// This works like snprintf(), except that it starts writing the first output
// character to str[strlen(str)]. This returns the number of characters the
// string would have *appended* assuming a large enough buffer, will make sure

View File

@ -82,6 +82,7 @@ struct mp_rect {
void mp_rect_union(struct mp_rect *rc, const struct mp_rect *src);
bool mp_rect_intersection(struct mp_rect *rc, const struct mp_rect *rc2);
bool mp_rect_contains(struct mp_rect *rc, int x, int y);
bool mp_rect_equals(struct mp_rect *rc1, struct mp_rect *rc2);
int mp_snprintf_cat(char *str, size_t size, const char *format, ...)
PRINTF_ATTRIBUTE(3, 4);

View File

@ -625,10 +625,8 @@ void mpgl_load_functions2(GL *gl, void *(*get_fn)(void *ctx, const char *n),
}
// GL_ARB_compute_shader & GL_ARB_shader_image_load_store
if (gl->DispatchCompute && gl->BindImageTexture) {
if (gl->DispatchCompute && gl->BindImageTexture)
gl->mpgl_caps |= MPGL_CAP_COMPUTE_SHADER;
gl->GetIntegerv(GL_MAX_COMPUTE_SHARED_MEMORY_SIZE, &gl->max_shmem);
}
// Provided for simpler handling if no framebuffer support is available.
if (!gl->BindFramebuffer)

View File

@ -87,7 +87,6 @@ struct GL {
int glsl_version; // e.g. 130 for GLSL 1.30
char *extensions; // Equivalent to GL_EXTENSIONS
int mpgl_caps; // Bitfield of MPGL_CAP_* constants
int max_shmem; // Maximum shared memory for compute shaders
bool debug_context; // use of e.g. GLX_CONTEXT_DEBUG_BIT_ARB
// Use mpgl_get_native_display() instead. Also, this is set to use the

View File

@ -76,7 +76,7 @@ struct gl_hwdec_driver {
int (*overlay_frame)(struct gl_hwdec *hw, struct mp_image *hw_image);
// Move overlay position within the "window".
void (*overlay_adjust)(struct gl_hwdec *hw, int w, int h,
void (*overlay_adjust)(struct gl_hwdec *hw,
struct mp_rect *src, struct mp_rect *dst);
};

View File

@ -50,7 +50,6 @@ struct priv {
struct mp_image *current_frame;
int w, h;
struct mp_rect src, dst;
int cur_window[4]; // raw user params
};
@ -131,9 +130,6 @@ static void update_overlay(struct gl_hwdec *hw, bool check_window_only)
struct mp_rect src = p->src;
struct mp_rect dst = p->dst;
if (!p->w || !p->h)
return;
int defs[4] = {0, 0, 0, 0};
int *z = mpgl_get_native_display(gl, "MPV_RPI_WINDOW");
if (!z)
@ -248,13 +244,11 @@ static int enable_renderer(struct gl_hwdec *hw)
return 0;
}
static void overlay_adjust(struct gl_hwdec *hw, int w, int h,
static void overlay_adjust(struct gl_hwdec *hw,
struct mp_rect *src, struct mp_rect *dst)
{
struct priv *p = hw->priv;
p->w = w;
p->h = h;
p->src = *src;
p->dst = *dst;

View File

@ -28,6 +28,14 @@ void ra_buf_free(struct ra *ra, struct ra_buf **buf)
*buf = NULL;
}
void ra_free(struct ra **ra)
{
if (*ra)
(*ra)->fns->destroy(*ra);
talloc_free(*ra);
*ra = NULL;
}
static size_t vartype_size(enum ra_vartype type)
{
switch (type) {

View File

@ -21,6 +21,10 @@ struct ra {
// at init time.
int max_texture_wh;
// Maximum shared memory for compute shaders. Set by the RA backend at init
// time.
size_t max_shmem;
// Set of supported texture formats. Must be added by RA backend at init time.
struct ra_format **formats;
int num_formats;
@ -391,6 +395,12 @@ struct ra_fns {
// always produce a value - and the values it does produce are typically
// delayed by a few frames. When no value is available, this returns 0.
uint64_t (*timer_stop)(struct ra *ra, ra_timer *timer);
// Hint that possibly queued up commands should be sent to the GPU. Optional.
void (*flush)(struct ra *ra);
// Optional.
void (*debug_marker)(struct ra *ra, const char *msg);
};
struct ra_tex *ra_tex_create(struct ra *ra, const struct ra_tex_params *params);
@ -399,6 +409,8 @@ void ra_tex_free(struct ra *ra, struct ra_tex **tex);
struct ra_buf *ra_buf_create(struct ra *ra, const struct ra_buf_params *params);
void ra_buf_free(struct ra *ra, struct ra_buf **buf);
void ra_free(struct ra **ra);
const struct ra_format *ra_find_unorm_format(struct ra *ra,
int bytes_per_component,
int n_components);

View File

@ -6,7 +6,7 @@
static struct ra_fns ra_fns_gl;
int ra_init_gl(struct ra *ra, GL *gl)
static int ra_init_gl(struct ra *ra, GL *gl)
{
if (gl->version < 210 && gl->es < 200) {
MP_ERR(ra, "At least OpenGL 2.1 or OpenGL ES 2.0 required.\n");
@ -16,6 +16,8 @@ int ra_init_gl(struct ra *ra, GL *gl)
struct ra_gl *p = ra->priv = talloc_zero(NULL, struct ra_gl);
p->gl = gl;
ra_gl_set_debug(ra, true);
ra->fns = &ra_fns_gl;
ra->caps = 0;
if (gl->mpgl_caps & MPGL_CAP_1D_TEX)
@ -100,20 +102,46 @@ int ra_init_gl(struct ra *ra, GL *gl)
MP_TARRAY_APPEND(ra, ra->formats, ra->num_formats, fmt);
}
GLint max_wh;
gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_wh);
ra->max_texture_wh = max_wh;
GLint ival;
gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &ival);
ra->max_texture_wh = ival;
if (ra->caps & RA_CAP_COMPUTE) {
gl->GetIntegerv(GL_MAX_COMPUTE_SHARED_MEMORY_SIZE, &ival);
ra->max_shmem = ival;
}
gl->Disable(GL_DITHER);
return 0;
}
struct ra *ra_create_gl(GL *gl, struct mp_log *log)
{
struct ra *ra = talloc_zero(NULL, struct ra);
ra->log = log;
if (ra_init_gl(ra, gl) < 0) {
talloc_free(ra);
return NULL;
}
return ra;
}
static void gl_destroy(struct ra *ra)
{
talloc_free(ra->priv);
}
void ra_gl_set_debug(struct ra *ra, bool enable)
{
struct ra_gl *p = ra->priv;
GL *gl = ra_gl_get(ra);
p->debug_enable = enable;
if (gl->debug_context)
gl_set_debug_logger(gl, enable ? ra->log : NULL);
}
static void gl_tex_destroy(struct ra *ra, struct ra_tex *tex)
{
GL *gl = ra_gl_get(ra);
@ -949,6 +977,20 @@ static uint64_t gl_timer_stop(struct ra *ra, ra_timer *ratimer)
return timer->result;
}
static void gl_flush(struct ra *ra)
{
GL *gl = ra_gl_get(ra);
gl->Flush();
}
static void gl_debug_marker(struct ra *ra, const char *msg)
{
struct ra_gl *p = ra->priv;
if (p->debug_enable)
gl_check_error(p->gl, ra->log, msg);
}
static struct ra_fns ra_fns_gl = {
.destroy = gl_destroy,
.tex_create = gl_tex_create,
@ -966,4 +1008,6 @@ static struct ra_fns ra_fns_gl = {
.timer_destroy = gl_timer_destroy,
.timer_start = gl_timer_start,
.timer_stop = gl_timer_stop,
.flush = gl_flush,
.debug_marker = gl_debug_marker,
};

View File

@ -7,6 +7,7 @@
// For ra.priv
struct ra_gl {
GL *gl;
bool debug_enable;
};
// For ra_tex.priv
@ -37,11 +38,11 @@ struct ra_renderpass_gl {
struct gl_vao vao;
};
int ra_init_gl(struct ra *ra, GL *gl);
struct ra *ra_create_gl(GL *gl, struct mp_log *log);
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);
GL *ra_gl_get(struct ra *ra);
void ra_gl_set_debug(struct ra *ra, bool enable);

View File

@ -176,7 +176,6 @@ struct dr_buffer {
};
struct gl_video {
GL *gl;
struct ra *ra;
struct mpv_global *global;
@ -184,7 +183,6 @@ struct gl_video {
struct gl_video_opts opts;
struct m_config_cache *opts_cache;
struct gl_lcms *cms;
bool gl_debug;
int fb_depth; // actual bits available in GL main framebuffer
@ -252,7 +250,6 @@ struct gl_video {
struct mp_rect src_rect; // displayed part of the source video
struct mp_rect dst_rect; // video rectangle on output window
struct mp_osd_res osd_rect; // OSD size/margins
int vp_w, vp_h;
// temporary during rendering
struct img_tex pass_tex[TEXUNIT_VIDEO_NUM];
@ -459,17 +456,8 @@ static struct bstr load_cached_file(struct gl_video *p, const char *path)
static void debug_check_gl(struct gl_video *p, const char *msg)
{
if (p->gl_debug)
gl_check_error(p->gl, p->log, msg);
}
void gl_video_set_debug(struct gl_video *p, bool enable)
{
GL *gl = p->gl;
p->gl_debug = enable;
if (p->gl->debug_context)
gl_set_debug_logger(gl, enable ? p->log : NULL);
if (p->ra->fns->debug_marker)
p->ra->fns->debug_marker(p->ra, msg);
}
static void gl_video_reset_surfaces(struct gl_video *p)
@ -1094,8 +1082,8 @@ static void pass_prepare_src_tex(struct gl_video *p)
gl_sc_uniform_vec2(sc, texture_size, f);
gl_sc_uniform_mat2(sc, texture_rot, true, (float *)s->transform.m);
gl_sc_uniform_vec2(sc, texture_off, (float *)s->transform.t);
gl_sc_uniform_vec2(sc, pixel_size, (GLfloat[]){1.0f / f[0],
1.0f / f[1]});
gl_sc_uniform_vec2(sc, pixel_size, (float[]){1.0f / f[0],
1.0f / f[1]});
}
}
@ -1137,7 +1125,7 @@ static void dispatch_compute(struct gl_video *p, int w, int h,
// 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]){
gl_sc_uniform_vec2(p->sc, tex_scale, (float[2]){
(float)s->w / s->tex->params.w,
(float)s->h / s->tex->params.h,
});
@ -1514,18 +1502,18 @@ static void load_shader(struct gl_video *p, struct bstr body)
gl_sc_uniform_f(p->sc, "random", (double)av_lfg_get(&p->lfg) / UINT32_MAX);
gl_sc_uniform_i(p->sc, "frame", p->frames_uploaded);
gl_sc_uniform_vec2(p->sc, "input_size",
(GLfloat[]){(p->src_rect.x1 - p->src_rect.x0) *
p->texture_offset.m[0][0],
(p->src_rect.y1 - p->src_rect.y0) *
p->texture_offset.m[1][1]});
(float[]){(p->src_rect.x1 - p->src_rect.x0) *
p->texture_offset.m[0][0],
(p->src_rect.y1 - p->src_rect.y0) *
p->texture_offset.m[1][1]});
gl_sc_uniform_vec2(p->sc, "target_size",
(GLfloat[]){p->dst_rect.x1 - p->dst_rect.x0,
p->dst_rect.y1 - p->dst_rect.y0});
(float[]){p->dst_rect.x1 - p->dst_rect.x0,
p->dst_rect.y1 - p->dst_rect.y0});
gl_sc_uniform_vec2(p->sc, "tex_offset",
(GLfloat[]){p->src_rect.x0 * p->texture_offset.m[0][0] +
p->texture_offset.t[0],
p->src_rect.y0 * p->texture_offset.m[1][1] +
p->texture_offset.t[1]});
(float[]){p->src_rect.x0 * p->texture_offset.m[0][0] +
p->texture_offset.t[0],
p->src_rect.y0 * p->texture_offset.m[1][1] +
p->texture_offset.t[1]});
}
// Semantic equality
@ -1688,8 +1676,6 @@ static void pass_sample_separated(struct gl_video *p, struct img_tex src,
static void pass_dispatch_sample_polar(struct gl_video *p, struct scaler *scaler,
struct img_tex tex, int w, int h)
{
GL *gl = p->gl;
uint64_t reqs = RA_CAP_COMPUTE | RA_CAP_NESTED_ARRAY;
if ((p->ra->caps & reqs) != reqs)
goto fallback;
@ -1713,8 +1699,8 @@ static void pass_dispatch_sample_polar(struct gl_video *p, struct scaler *scaler
int iw = (int)ceil(bw / ratiox) + padding + 1,
ih = (int)ceil(bh / ratioy) + padding + 1;
int shmem_req = iw * ih * tex.components * sizeof(GLfloat);
if (shmem_req > gl->max_shmem)
int shmem_req = iw * ih * tex.components * sizeof(float);
if (shmem_req > p->ra->max_shmem)
goto fallback;
pass_is_compute(p, bw, bh);
@ -2499,10 +2485,15 @@ static void pass_colormanage(struct gl_video *p, struct mp_colorspace src, bool
}
}
void gl_video_set_fb_depth(struct gl_video *p, int fb_depth)
{
p->fb_depth = fb_depth;
}
static void pass_dither(struct gl_video *p)
{
// Assume 8 bits per component if unknown.
int dst_depth = p->fb_depth;
int dst_depth = p->fb_depth > 0 ? p->fb_depth : 8;
if (p->opts.dither_depth > 0)
dst_depth = p->opts.dither_depth;
@ -3001,40 +2992,16 @@ static void gl_video_interpolate_frame(struct gl_video *p, struct vo_frame *t,
p->frames_drawn += 1;
}
// (fbo==0 makes BindFramebuffer select the screen backbuffer)
void gl_video_render_frame(struct gl_video *p, struct vo_frame *frame, int fbo)
void gl_video_render_frame(struct gl_video *p, struct vo_frame *frame,
struct fbodst target)
{
GL *gl = p->gl;
if (fbo && !(gl->mpgl_caps & MPGL_CAP_FB)) {
MP_FATAL(p, "Rendering to FBO requested, but no FBO extension found!\n");
return;
}
if (p->fb_depth == 0) {
debug_check_gl(p, "before retrieving framebuffer depth");
p->fb_depth = gl_get_fb_depth(gl, fbo);
debug_check_gl(p, "retrieving framebuffer depth");
if (p->fb_depth > 0) {
MP_VERBOSE(p, "Reported display depth: %d\n", p->fb_depth);
} else {
p->fb_depth = 8;
}
}
struct fbodst target = {
.tex = ra_create_wrapped_fb(p->ra, fbo, p->vp_w, abs(p->vp_h)),
.flip = p->vp_h < 0,
};
struct mp_rect target_rc = {0, 0, p->vp_w, abs(p->vp_h)};
struct mp_rect target_rc = {0, 0, target.tex->params.w, target.tex->params.h};
p->broken_frame = false;
bool has_frame = !!frame->current;
if (!has_frame || p->dst_rect.x0 > 0 || p->dst_rect.y0 > 0 ||
p->dst_rect.x1 < p->vp_w || p->dst_rect.y1 < abs(p->vp_h))
{
if (!has_frame || !mp_rect_equals(&p->dst_rect, &target_rc)) {
struct m_color c = p->opts.background;
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.tex, color, &target_rc);
@ -3140,32 +3107,27 @@ done:
p->ra->fns->clear(p->ra, target.tex, color, &target_rc);
}
ra_tex_free(p->ra, &target.tex);
// 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).
if ((p->opts.early_flush == -1 && !frame->display_synced) ||
p->opts.early_flush == 1)
{
gl->Flush();
if (p->ra->fns->flush)
p->ra->fns->flush(p->ra);
}
p->frames_rendered++;
pass_report_performance(p);
}
// vp_w/vp_h is the implicit size of the target framebuffer.
// vp_h can be negative to flip the screen.
void gl_video_resize(struct gl_video *p, int vp_w, int vp_h,
void gl_video_resize(struct gl_video *p,
struct mp_rect *src, struct mp_rect *dst,
struct mp_osd_res *osd)
{
p->src_rect = *src;
p->dst_rect = *dst;
p->osd_rect = *osd;
p->vp_w = vp_w;
p->vp_h = vp_h;
gl_video_reset_surfaces(p);
@ -3173,7 +3135,7 @@ void gl_video_resize(struct gl_video *p, int vp_w, int vp_h,
mpgl_osd_resize(p->osd, p->osd_rect, p->image_params.stereo_out);
if (p->hwdec && p->hwdec->driver->overlay_adjust)
p->hwdec->driver->overlay_adjust(p->hwdec, vp_w, abs(vp_h), src, dst);
p->hwdec->driver->overlay_adjust(p->hwdec, src, dst);
}
static void frame_perf_data(struct pass_info pass[], struct mp_frame_perf *out)
@ -3375,10 +3337,10 @@ static bool check_dumb_mode(struct gl_video *p)
static void check_gl_features(struct gl_video *p)
{
struct ra *ra = p->ra;
GL *gl = p->gl;
bool have_float_tex = !!ra_find_float16_format(ra, 1);
bool have_mglsl = ra->glsl_version >= 130; // modern GLSL
bool have_texrg = gl->mpgl_caps & MPGL_CAP_TEX_RG;
const struct ra_format *rg_tex = ra_find_unorm_format(p->ra, 1, 2);
bool have_texrg = rg_tex && !rg_tex->luminance_alpha;
bool have_compute = ra->caps & RA_CAP_COMPUTE;
bool have_ssbo = ra->caps & RA_CAP_BUF_RW;
@ -3512,8 +3474,6 @@ void gl_video_uninit(struct gl_video *p)
if (!p)
return;
GL *gl = p->gl;
uninit_video(p);
gl_sc_destroy(p->sc);
@ -3532,8 +3492,6 @@ void gl_video_uninit(struct gl_video *p)
mpgl_osd_destroy(p->osd);
gl_set_debug_logger(gl, NULL);
// Forcibly destroy possibly remaining image references. This should also
// cause gl_video_dr_free_buffer() to be called for the remaining buffers.
gc_pending_dr_fences(p, true);
@ -3541,8 +3499,7 @@ void gl_video_uninit(struct gl_video *p)
// Should all have been unreffed already.
assert(!p->num_dr_buffers);
p->ra->fns->destroy(p->ra);
talloc_free(p->ra);
ra_free(&p->ra);
talloc_free(p);
}
@ -3603,18 +3560,11 @@ void gl_video_set_osd_source(struct gl_video *p, struct osd_state *osd)
reinit_osd(p);
}
struct gl_video *gl_video_init(GL *gl, struct mp_log *log, struct mpv_global *g)
struct gl_video *gl_video_init(struct ra *ra, struct mp_log *log,
struct mpv_global *g)
{
struct ra *ra = talloc_zero(NULL, struct ra);
ra->log = log;
if (ra_init_gl(ra, gl) < 0) {
talloc_free(ra);
return NULL;
}
struct gl_video *p = talloc_ptrtype(NULL, p);
*p = (struct gl_video) {
.gl = gl,
.ra = ra,
.global = g,
.log = log,
@ -3628,7 +3578,6 @@ struct gl_video *gl_video_init(GL *gl, struct mp_log *log, struct mpv_global *g)
p->opts = *opts;
for (int n = 0; n < SCALER_COUNT; n++)
p->scaler[n] = (struct scaler){.index = n};
gl_video_set_debug(p, true);
init_gl(p);
reinit_from_options(p);
return p;

View File

@ -24,7 +24,6 @@
#include "sub/osd.h"
#include "common.h"
#include "utils.h"
#include "gl_utils.h"
#include "lcms.h"
#include "shader_cache.h"
#include "video/out/filter_kernels.h"
@ -150,24 +149,25 @@ extern const struct m_sub_options gl_video_conf;
struct gl_video;
struct vo_frame;
struct gl_video *gl_video_init(GL *gl, struct mp_log *log, struct mpv_global *g);
struct gl_video *gl_video_init(struct ra *ra, struct mp_log *log,
struct mpv_global *g);
void gl_video_uninit(struct gl_video *p);
void gl_video_set_osd_source(struct gl_video *p, struct osd_state *osd);
void gl_video_update_options(struct gl_video *p);
bool gl_video_check_format(struct gl_video *p, int mp_format);
void gl_video_config(struct gl_video *p, struct mp_image_params *params);
void gl_video_set_output_depth(struct gl_video *p, int r, int g, int b);
void gl_video_render_frame(struct gl_video *p, struct vo_frame *frame, int fbo);
void gl_video_resize(struct gl_video *p, int vp_w, int vp_h,
void gl_video_render_frame(struct gl_video *p, struct vo_frame *frame,
struct fbodst target);
void gl_video_resize(struct gl_video *p,
struct mp_rect *src, struct mp_rect *dst,
struct mp_osd_res *osd);
void gl_video_set_fb_depth(struct gl_video *p, int fb_depth);
void gl_video_perfdata(struct gl_video *p, struct voctrl_performance_data *out);
struct mp_csp_equalizer;
struct mp_csp_equalizer *gl_video_eq_ptr(struct gl_video *p);
void gl_video_eq_update(struct gl_video *p);
void gl_video_set_debug(struct gl_video *p, bool enable);
float gl_video_scale_ambient_lux(float lmin, float lmax,
float rmin, float rmax, float lux);
void gl_video_set_ambient_lux(struct gl_video *p, int lux);

View File

@ -45,6 +45,7 @@
#include "filter_kernels.h"
#include "video/hwdec.h"
#include "opengl/video.h"
#include "opengl/ra_gl.h"
#define NUM_VSYNC_FENCES 10
@ -65,6 +66,7 @@ struct gl_priv {
struct mp_log *log;
MPGLContext *glctx;
GL *gl;
struct ra *ra;
struct vo_opengl_opts opts;
@ -95,8 +97,7 @@ static void resize(struct gl_priv *p)
struct mp_osd_res osd;
vo_get_src_dst_rects(vo, &src, &dst, &osd);
int height = p->glctx->flip_v ? vo->dheight : -vo->dheight;
gl_video_resize(p->renderer, vo->dwidth, height, &src, &dst, &osd);
gl_video_resize(p->renderer, &src, &dst, &osd);
vo->want_redraw = true;
}
@ -130,7 +131,13 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame)
p->vsync_fences[p->num_vsync_fences++] = fence;
}
gl_video_render_frame(p->renderer, frame, p->glctx->main_fb);
struct fbodst target = {
.tex = ra_create_wrapped_fb(p->ra, p->glctx->main_fb,
vo->dwidth, vo->dheight),
.flip = !p->glctx->flip_v,
};
gl_video_render_frame(p->renderer, frame, target);
ra_tex_free(p->ra, &target.tex);
if (p->opts.use_glFinish)
gl->Finish();
@ -145,7 +152,7 @@ static void flip_page(struct vo *vo)
p->frames_rendered++;
if (p->frames_rendered > 5 && !p->opts.use_gl_debug)
gl_video_set_debug(p->renderer, false);
ra_gl_set_debug(p->ra, false);
if (p->opts.use_glFinish)
gl->Finish();
@ -422,9 +429,11 @@ static int preinit(struct vo *vo)
MP_VERBOSE(vo, "swap_control extension missing.\n");
}
p->renderer = gl_video_init(p->gl, vo->log, vo->global);
if (!p->renderer)
p->ra = ra_create_gl(p->gl, vo->log);
if (!p->ra)
goto err_out;
p->renderer = gl_video_init(p->ra, vo->log, vo->global);
gl_video_set_osd_source(p->renderer, vo->osd);
gl_video_configure_queue(p->renderer, vo);
@ -438,6 +447,13 @@ static int preinit(struct vo *vo)
vo->hwdec_devs, vo->opts->gl_hwdec_interop);
gl_video_set_hwdec(p->renderer, p->hwdec);
gl_check_error(p->gl, p->log, "before retrieving framebuffer depth");
int fb_depth = gl_get_fb_depth(p->gl, p->glctx->main_fb);
gl_check_error(p->gl, p->log, "retrieving framebuffer depth");
if (fb_depth)
MP_VERBOSE(p, "Reported display depth: %d\n", fb_depth);
gl_video_set_fb_depth(p->renderer, fb_depth);
return 0;
err_out:

View File

@ -27,6 +27,7 @@
#include "opengl/common.h"
#include "opengl/video.h"
#include "opengl/hwdec.h"
#include "opengl/ra_gl.h"
#include "libmpv/opengl_cb.h"
@ -87,6 +88,7 @@ struct mpv_opengl_cb_context {
// application's OpenGL context is current - i.e. only while the
// host application is calling certain mpv_opengl_cb_* APIs.
GL *gl;
struct ra *ra;
struct gl_video *renderer;
struct gl_hwdec *hwdec;
struct m_config_cache *vo_opts_cache;
@ -171,10 +173,12 @@ int mpv_opengl_cb_init_gl(struct mpv_opengl_cb_context *ctx, const char *exts,
return MPV_ERROR_UNSUPPORTED;
}
ctx->renderer = gl_video_init(ctx->gl, ctx->log, ctx->global);
if (!ctx->renderer)
ctx->ra = ra_create_gl(ctx->gl, ctx->log);
if (!ctx->ra)
return MPV_ERROR_UNSUPPORTED;
ctx->renderer = gl_video_init(ctx->ra, ctx->log, ctx->global);
m_config_cache_update(ctx->vo_opts_cache);
ctx->hwdec_devs = hwdec_devices_create();
@ -223,6 +227,7 @@ int mpv_opengl_cb_uninit_gl(struct mpv_opengl_cb_context *ctx)
ctx->hwdec = NULL;
hwdec_devices_destroy(ctx->hwdec_devs);
ctx->hwdec_devs = NULL;
ra_free(&ctx->ra);
talloc_free(ctx->gl);
ctx->gl = NULL;
return 0;
@ -232,6 +237,16 @@ int mpv_opengl_cb_draw(mpv_opengl_cb_context *ctx, int fbo, int vp_w, int vp_h)
{
assert(ctx->renderer);
if (fbo && !(ctx->gl->mpgl_caps & MPGL_CAP_FB)) {
MP_FATAL(ctx, "Rendering to FBO requested, but no FBO extension found!\n");
return MPV_ERROR_UNSUPPORTED;
}
struct fbodst target = {
.tex = ra_create_wrapped_fb(ctx->ra, fbo, vp_w, abs(vp_h)),
.flip = vp_h < 0,
};
reset_gl_state(ctx->gl);
pthread_mutex_lock(&ctx->lock);
@ -256,7 +271,7 @@ int mpv_opengl_cb_draw(mpv_opengl_cb_context *ctx, int fbo, int vp_w, int vp_h)
&ctx->img_params, vp_w, abs(vp_h),
1.0, &src, &dst, &osd);
gl_video_resize(ctx->renderer, vp_w, vp_h, &src, &dst, &osd);
gl_video_resize(ctx->renderer, &src, &dst, &osd);
}
if (ctx->reconfigured) {
@ -272,7 +287,7 @@ int mpv_opengl_cb_draw(mpv_opengl_cb_context *ctx, int fbo, int vp_w, int vp_h)
mp_read_option_raw(ctx->global, "opengl-debug", &m_option_type_flag,
&debug);
ctx->gl->debug_context = debug;
gl_video_set_debug(ctx->renderer, debug);
ra_gl_set_debug(ctx->ra, debug);
if (gl_video_icc_auto_enabled(ctx->renderer))
MP_ERR(ctx, "icc-profile-auto is not available with opengl-cb\n");
}
@ -315,7 +330,7 @@ int mpv_opengl_cb_draw(mpv_opengl_cb_context *ctx, int fbo, int vp_w, int vp_h)
pthread_mutex_unlock(&ctx->lock);
MP_STATS(ctx, "glcb-render");
gl_video_render_frame(ctx->renderer, frame, fbo);
gl_video_render_frame(ctx->renderer, frame, target);
reset_gl_state(ctx->gl);
@ -327,6 +342,8 @@ int mpv_opengl_cb_draw(mpv_opengl_cb_context *ctx, int fbo, int vp_w, int vp_h)
pthread_cond_wait(&ctx->wakeup, &ctx->lock);
pthread_mutex_unlock(&ctx->lock);
ra_tex_free(ctx->ra, &target.tex);
return 0;
}