vo_opengl: read framebuffer depth from actual FBO used for rendering

In some cases, such as when using the libmpv opengl-cb API, or with
certain vo_opengl backends, the main framebuffer is never accessed.
Instead, rendering is done to a FBO that acts as back buffer. This meant
an incorrect/broken bit depth could be used for dithering.

Change it to read the framebuffer depth lazily on the first render call.

Also move the main FBO field out of the GL struct to MPGLContext,
because the renderer's init function does not need to access it anymore.
This commit is contained in:
wm4 2017-03-20 13:31:28 +01:00
parent 03fe50651b
commit 8fb9cc2534
8 changed files with 25 additions and 21 deletions

View File

@ -94,7 +94,6 @@ struct GL {
char *extensions; // Equivalent to GL_EXTENSIONS
int mpgl_caps; // Bitfield of MPGL_CAP_* constants
bool debug_context; // use of e.g. GLX_CONTEXT_DEBUG_BIT_ARB
GLuint main_fb; // framebuffer to render to (normally 0)
void (GLAPIENTRY *Viewport)(GLint, GLint, GLsizei, GLsizei);
void (GLAPIENTRY *Clear)(GLbitfield);

View File

@ -88,6 +88,9 @@ typedef struct MPGLContext {
// Flip the rendered image vertically. This is useful for dxinterop.
bool flip_v;
// framebuffer to render to (normally 0)
GLuint main_fb;
// For free use by the mpgl_driver.
void *priv;
} MPGLContext;

View File

@ -294,7 +294,7 @@ static int d3d_size_dependent_create(MPGLContext *ctx)
return -1;
}
gl->BindFramebuffer(GL_FRAMEBUFFER, gl->main_fb);
gl->BindFramebuffer(GL_FRAMEBUFFER, ctx->main_fb);
gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, p->texture, 0);
gl->BindFramebuffer(GL_FRAMEBUFFER, 0);
@ -506,7 +506,7 @@ static int dxinterop_init(struct MPGLContext *ctx, int flags)
goto fail;
// Create the shared framebuffer
gl->GenFramebuffers(1, &gl->main_fb);
gl->GenFramebuffers(1, &ctx->main_fb);
current_ctx = ctx;
gl->SwapInterval = dxinterop_swap_interval;

View File

@ -311,7 +311,7 @@ static void glx_next_framebuffer(struct MPGLContext *ctx)
VdpStatus vdp_st;
GL *gl = ctx->gl;
ctx->gl->main_fb = 0;
ctx->main_fb = 0;
int current_surface = p->current_surface++;
p->current_surface = p->current_surface % p->num_surfaces;
@ -348,7 +348,7 @@ static void glx_next_framebuffer(struct MPGLContext *ctx)
gl->VDPAUMapSurfacesNV(1, &surface->registered);
surface->mapped = true;
gl->main_fb = surface->fbo;
ctx->main_fb = surface->fbo;
ctx->flip_v = true;
}

View File

@ -100,15 +100,15 @@ void gl_upload_tex(GL *gl, GLenum target, GLenum format, GLenum type,
gl->PixelStorei(GL_UNPACK_ALIGNMENT, 4);
}
mp_image_t *gl_read_window_contents(GL *gl, int w, int h)
mp_image_t *gl_read_fbo_contents(GL *gl, int fbo, int w, int h)
{
if (gl->es)
return NULL; // ES can't read from front buffer
mp_image_t *image = mp_image_alloc(IMGFMT_RGB24, w, h);
if (!image)
return NULL;
gl->BindFramebuffer(GL_FRAMEBUFFER, gl->main_fb);
GLenum obj = gl->main_fb ? GL_COLOR_ATTACHMENT0 : GL_FRONT;
gl->BindFramebuffer(GL_FRAMEBUFFER, fbo);
GLenum obj = fbo ? GL_COLOR_ATTACHMENT0 : GL_FRONT;
gl->PixelStorei(GL_PACK_ALIGNMENT, 1);
gl->ReadBuffer(obj);
//flip image while reading (and also avoid stride-related trouble)

View File

@ -30,7 +30,7 @@ void gl_upload_tex(GL *gl, GLenum target, GLenum format, GLenum type,
const void *dataptr, int stride,
int x, int y, int w, int h);
mp_image_t *gl_read_window_contents(GL *gl, int w, int h);
mp_image_t *gl_read_fbo_contents(GL *gl, int fbo, int w, int h);
const char* mp_sampler_type(GLenum texture_target);

View File

@ -2643,6 +2643,17 @@ void gl_video_render_frame(struct gl_video *p, struct vo_frame *frame, int fbo)
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;
}
}
p->broken_frame = false;
gl->BindFramebuffer(GL_FRAMEBUFFER, fbo);
@ -3127,15 +3138,6 @@ static void init_gl(struct gl_video *p)
if (p->texture_16bit_depth > 0)
MP_VERBOSE(p, "16 bit texture depth: %d.\n", p->texture_16bit_depth);
debug_check_gl(p, "before retrieving framebuffer depth");
p->fb_depth = gl_get_fb_depth(gl, gl->main_fb);
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;
}
p->upload_timer = gl_timer_create(p->gl);
p->render_timer = gl_timer_create(p->gl);
p->present_timer = gl_timer_create(p->gl);

View File

@ -128,7 +128,7 @@ 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, gl->main_fb);
gl_video_render_frame(p->renderer, frame, p->glctx->main_fb);
if (p->opts.use_glFinish)
gl->Finish();
@ -270,8 +270,8 @@ static int control(struct vo *vo, uint32_t request, void *data)
return VO_NOTIMPL;
}
case VOCTRL_SCREENSHOT_WIN: {
struct mp_image *screen =
gl_read_window_contents(p->gl, vo->dwidth, vo->dheight);
struct mp_image *screen = gl_read_fbo_contents(p->gl, p->glctx->main_fb,
vo->dwidth, vo->dheight);
if (!screen)
break; // redirect to backend
// set image parameters according to the display, if possible