diff options
author | Niklas Haas <git@haasn.xyz> | 2017-09-14 08:04:55 +0200 |
---|---|---|
committer | Niklas Haas <git@haasn.xyz> | 2017-09-21 15:00:55 +0200 |
commit | 65979986a923a8f08019b257c3fe72cd5e8ecf68 (patch) | |
tree | b8f4b8c17d583594aef0ca509064f8b2ff7128d4 /video/out/vo_opengl.c | |
parent | 20f958c9775652c3213588c2a0824f5353276adc (diff) | |
download | mpv-65979986a923a8f08019b257c3fe72cd5e8ecf68.tar.bz2 mpv-65979986a923a8f08019b257c3fe72cd5e8ecf68.tar.xz |
vo_opengl: refactor into vo_gpu
This is done in several steps:
1. refactor MPGLContext -> struct ra_ctx
2. move GL-specific stuff in vo_opengl into opengl/context.c
3. generalize context creation to support other APIs, and add --gpu-api
4. rename all of the --opengl- options that are no longer opengl-specific
5. move all of the stuff from opengl/* that isn't GL-specific into gpu/
(note: opengl/gl_utils.h became opengl/utils.h)
6. rename vo_opengl to vo_gpu
7. to handle window screenshots, the short-term approach was to just add
it to ra_swchain_fns. Long term (and for vulkan) this has to be moved to
ra itself (and vo_gpu altered to compensate), but this was a stop-gap
measure to prevent this commit from getting too big
8. move ra->fns->flush to ra_gl_ctx instead
9. some other minor changes that I've probably already forgotten
Note: This is one half of a major refactor, the other half of which is
provided by rossy's following commit. This commit enables support for
all linux platforms, while his version enables support for all non-linux
platforms.
Note 2: vo_opengl_cb.c also re-uses ra_gl_ctx so it benefits from the
--opengl- options like --opengl-early-flush, --opengl-finish etc. Should
be a strict superset of the old functionality.
Disclaimer: Since I have no way of compiling mpv on all platforms, some
of these ports were done blindly. Specifically, the blind ports included
context_mali_fbdev.c and context_rpi.c. Since they're both based on
egl_helpers, the port should have gone smoothly without any major
changes required. But if somebody complains about a compile error on
those platforms (assuming anybody actually uses them), you know where to
complain.
Diffstat (limited to 'video/out/vo_opengl.c')
-rw-r--r-- | video/out/vo_opengl.c | 470 |
1 files changed, 0 insertions, 470 deletions
diff --git a/video/out/vo_opengl.c b/video/out/vo_opengl.c deleted file mode 100644 index 72691e56c2..0000000000 --- a/video/out/vo_opengl.c +++ /dev/null @@ -1,470 +0,0 @@ -/* - * Based on vo_gl.c by Reimar Doeffinger. - * - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * mpv is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with mpv. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <math.h> -#include <stdbool.h> -#include <assert.h> - -#include <libavutil/common.h> - -#include "config.h" - -#include "mpv_talloc.h" -#include "common/common.h" -#include "misc/bstr.h" -#include "common/msg.h" -#include "common/global.h" -#include "options/m_config.h" -#include "vo.h" -#include "video/mp_image.h" -#include "sub/osd.h" - -#include "opengl/context.h" -#include "opengl/utils.h" -#include "opengl/hwdec.h" -#include "opengl/osd.h" -#include "filter_kernels.h" -#include "video/hwdec.h" -#include "opengl/video.h" -#include "opengl/ra_gl.h" - -#define NUM_VSYNC_FENCES 10 - -struct vo_opengl_opts { - int use_glFinish; - int waitvsync; - int use_gl_debug; - int allow_sw; - int swap_interval; - int vsync_fences; - char *backend; - int es; - int pattern[2]; -}; - -struct gl_priv { - struct vo *vo; - struct mp_log *log; - MPGLContext *glctx; - GL *gl; - struct ra *ra; - - struct vo_opengl_opts opts; - - struct gl_video *renderer; - - struct ra_hwdec *hwdec; - - int events; - - int frames_rendered; - unsigned int prev_sgi_sync_count; - - // check-pattern sub-option; for testing/debugging - int last_pattern; - int matches, mismatches; - - GLsync vsync_fences[NUM_VSYNC_FENCES]; - int num_vsync_fences; -}; - -static void resize(struct gl_priv *p) -{ - struct vo *vo = p->vo; - - MP_VERBOSE(vo, "Resize: %dx%d\n", vo->dwidth, vo->dheight); - - struct mp_rect src, dst; - struct mp_osd_res osd; - vo_get_src_dst_rects(vo, &src, &dst, &osd); - - gl_video_resize(p->renderer, &src, &dst, &osd); - - vo->want_redraw = true; -} - -static void check_pattern(struct vo *vo, int item) -{ - struct gl_priv *p = vo->priv; - int expected = p->opts.pattern[p->last_pattern]; - if (item == expected) { - p->last_pattern++; - if (p->last_pattern >= 2) - p->last_pattern = 0; - p->matches++; - } else { - p->mismatches++; - MP_WARN(vo, "wrong pattern, expected %d got %d (hit: %d, mis: %d)\n", - expected, item, p->matches, p->mismatches); - } -} - -static void draw_frame(struct vo *vo, struct vo_frame *frame) -{ - struct gl_priv *p = vo->priv; - GL *gl = p->gl; - - mpgl_start_frame(p->glctx); - - if (gl->FenceSync && p->num_vsync_fences < p->opts.vsync_fences) { - GLsync fence = gl->FenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);; - if (fence) - p->vsync_fences[p->num_vsync_fences++] = fence; - } - - 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(); -} - -static void flip_page(struct vo *vo) -{ - struct gl_priv *p = vo->priv; - GL *gl = p->gl; - - mpgl_swap_buffers(p->glctx); - - p->frames_rendered++; - if (p->frames_rendered > 5 && !p->opts.use_gl_debug) - ra_gl_set_debug(p->ra, false); - - if (p->opts.use_glFinish) - gl->Finish(); - - if (p->opts.waitvsync || p->opts.pattern[0]) { - if (gl->GetVideoSync) { - unsigned int n1 = 0, n2 = 0; - gl->GetVideoSync(&n1); - if (p->opts.waitvsync) - gl->WaitVideoSync(2, (n1 + 1) % 2, &n2); - int step = n1 - p->prev_sgi_sync_count; - p->prev_sgi_sync_count = n1; - MP_DBG(vo, "Flip counts: %u->%u, step=%d\n", n1, n2, step); - if (p->opts.pattern[0]) - check_pattern(vo, step); - } else { - MP_WARN(vo, "GLX_SGI_video_sync not available, disabling.\n"); - p->opts.waitvsync = 0; - p->opts.pattern[0] = 0; - } - } - while (p->opts.vsync_fences > 0 && p->num_vsync_fences >= p->opts.vsync_fences) { - gl->ClientWaitSync(p->vsync_fences[0], GL_SYNC_FLUSH_COMMANDS_BIT, 1e9); - gl->DeleteSync(p->vsync_fences[0]); - MP_TARRAY_REMOVE_AT(p->vsync_fences, p->num_vsync_fences, 0); - } -} - -static int query_format(struct vo *vo, int format) -{ - struct gl_priv *p = vo->priv; - if (!gl_video_check_format(p->renderer, format)) - return 0; - return 1; -} - -static int reconfig(struct vo *vo, struct mp_image_params *params) -{ - struct gl_priv *p = vo->priv; - - if (mpgl_reconfig_window(p->glctx) < 0) - return -1; - - resize(p); - - gl_video_config(p->renderer, params); - - return 0; -} - -static void request_hwdec_api(struct vo *vo, void *api) -{ - struct gl_priv *p = vo->priv; - - if (p->hwdec) - return; - - p->hwdec = ra_hwdec_load_api(p->vo->log, p->ra, p->vo->global, - vo->hwdec_devs, (intptr_t)api); - gl_video_set_hwdec(p->renderer, p->hwdec); -} - -static void call_request_hwdec_api(void *ctx, enum hwdec_type type) -{ - // Roundabout way to run hwdec loading on the VO thread. - // Redirects to request_hwdec_api(). - vo_control(ctx, VOCTRL_LOAD_HWDEC_API, (void *)(intptr_t)type); -} - -static void get_and_update_icc_profile(struct gl_priv *p) -{ - if (gl_video_icc_auto_enabled(p->renderer)) { - MP_VERBOSE(p, "Querying ICC profile...\n"); - bstr icc = bstr0(NULL); - int r = mpgl_control(p->glctx, &p->events, VOCTRL_GET_ICC_PROFILE, &icc); - - if (r != VO_NOTAVAIL) { - if (r == VO_FALSE) { - MP_WARN(p, "Could not retrieve an ICC profile.\n"); - } else if (r == VO_NOTIMPL) { - MP_ERR(p, "icc-profile-auto not implemented on this platform.\n"); - } - - gl_video_set_icc_profile(p->renderer, icc); - } - } -} - -static void get_and_update_ambient_lighting(struct gl_priv *p) -{ - int lux; - int r = mpgl_control(p->glctx, &p->events, VOCTRL_GET_AMBIENT_LUX, &lux); - if (r == VO_TRUE) { - gl_video_set_ambient_lux(p->renderer, lux); - } - if (r != VO_TRUE && gl_video_gamma_auto_enabled(p->renderer)) { - MP_ERR(p, "gamma_auto option provided, but querying for ambient" - " lighting is not supported on this platform\n"); - } -} - -static int control(struct vo *vo, uint32_t request, void *data) -{ - struct gl_priv *p = vo->priv; - - switch (request) { - case VOCTRL_SET_PANSCAN: - resize(p); - return VO_TRUE; - case VOCTRL_SET_EQUALIZER: - vo->want_redraw = true; - return VO_TRUE; - case VOCTRL_SCREENSHOT_WIN: { - 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 - screen->params.color = gl_video_get_output_colorspace(p->renderer); - if (p->glctx->flip_v) - mp_image_vflip(screen); - *(struct mp_image **)data = screen; - return true; - } - case VOCTRL_LOAD_HWDEC_API: - request_hwdec_api(vo, data); - return true; - case VOCTRL_UPDATE_RENDER_OPTS: { - gl_video_update_options(p->renderer); - get_and_update_icc_profile(p); - gl_video_configure_queue(p->renderer, p->vo); - p->vo->want_redraw = true; - return true; - } - case VOCTRL_RESET: - gl_video_reset(p->renderer); - return true; - case VOCTRL_PAUSE: - if (gl_video_showing_interpolated_frame(p->renderer)) - vo->want_redraw = true; - return true; - case VOCTRL_PERFORMANCE_DATA: - gl_video_perfdata(p->renderer, (struct voctrl_performance_data *)data); - return true; - } - - int events = 0; - int r = mpgl_control(p->glctx, &events, request, data); - if (events & VO_EVENT_ICC_PROFILE_CHANGED) { - get_and_update_icc_profile(p); - vo->want_redraw = true; - } - if (events & VO_EVENT_AMBIENT_LIGHTING_CHANGED) { - get_and_update_ambient_lighting(p); - vo->want_redraw = true; - } - events |= p->events; - p->events = 0; - if (events & VO_EVENT_RESIZE) - resize(p); - if (events & VO_EVENT_EXPOSE) - vo->want_redraw = true; - vo_event(vo, events); - - return r; -} - -static void wakeup(struct vo *vo) -{ - struct gl_priv *p = vo->priv; - if (p->glctx && p->glctx->driver->wakeup) - p->glctx->driver->wakeup(p->glctx); -} - -static void wait_events(struct vo *vo, int64_t until_time_us) -{ - struct gl_priv *p = vo->priv; - if (p->glctx->driver->wait_events) { - p->glctx->driver->wait_events(p->glctx, until_time_us); - } else { - vo_wait_default(vo, until_time_us); - } -} - -static struct mp_image *get_image(struct vo *vo, int imgfmt, int w, int h, - int stride_align) -{ - struct gl_priv *p = vo->priv; - - return gl_video_get_image(p->renderer, imgfmt, w, h, stride_align); -} - -static void uninit(struct vo *vo) -{ - struct gl_priv *p = vo->priv; - - gl_video_uninit(p->renderer); - ra_hwdec_uninit(p->hwdec); - if (vo->hwdec_devs) { - hwdec_devices_set_loader(vo->hwdec_devs, NULL, NULL); - hwdec_devices_destroy(vo->hwdec_devs); - } - ra_free(&p->ra); - mpgl_uninit(p->glctx); -} - -static int preinit(struct vo *vo) -{ - struct gl_priv *p = vo->priv; - p->vo = vo; - p->log = vo->log; - - int vo_flags = 0; - - int alpha_mode; - mp_read_option_raw(vo->global, "alpha", &m_option_type_choice, &alpha_mode); - - if (alpha_mode == 1) - vo_flags |= VOFLAG_ALPHA; - - if (p->opts.use_gl_debug) - vo_flags |= VOFLAG_GL_DEBUG; - - if (p->opts.es == 1) - vo_flags |= VOFLAG_GLES; - if (p->opts.es == 2) - vo_flags |= VOFLAG_GLES | VOFLAG_GLES2; - if (p->opts.es == -1) - vo_flags |= VOFLAG_NO_GLES; - - if (p->opts.allow_sw) - vo_flags |= VOFLAG_SW; - - p->glctx = mpgl_init(vo, p->opts.backend, vo_flags); - if (!p->glctx) - goto err_out; - p->gl = p->glctx->gl; - - if (p->gl->SwapInterval) { - p->gl->SwapInterval(p->opts.swap_interval); - } else { - MP_VERBOSE(vo, "swap_control extension missing.\n"); - } - - 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); - - get_and_update_icc_profile(p); - - vo->hwdec_devs = hwdec_devices_create(); - - hwdec_devices_set_loader(vo->hwdec_devs, call_request_hwdec_api, vo); - - p->hwdec = ra_hwdec_load(p->vo->log, p->ra, vo->global, - 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: - uninit(vo); - return -1; -} - -#define OPT_BASE_STRUCT struct gl_priv - -const struct vo_driver video_out_opengl = { - .description = "Extended OpenGL Renderer", - .name = "opengl", - .caps = VO_CAP_ROTATE90, - .preinit = preinit, - .query_format = query_format, - .reconfig = reconfig, - .control = control, - .get_image = get_image, - .draw_frame = draw_frame, - .flip_page = flip_page, - .wait_events = wait_events, - .wakeup = wakeup, - .uninit = uninit, - .priv_size = sizeof(struct gl_priv), - .options = (const m_option_t[]) { - OPT_FLAG("opengl-glfinish", opts.use_glFinish, 0), - OPT_FLAG("opengl-waitvsync", opts.waitvsync, 0), - OPT_INT("opengl-swapinterval", opts.swap_interval, 0), - OPT_FLAG("opengl-debug", opts.use_gl_debug, 0), - OPT_STRING_VALIDATE("opengl-backend", opts.backend, 0, - mpgl_validate_backend_opt), - OPT_FLAG("opengl-sw", opts.allow_sw, 0), - OPT_CHOICE("opengl-es", opts.es, 0, ({"no", -1}, {"auto", 0}, - {"yes", 1}, {"force2", 2})), - OPT_INTPAIR("opengl-check-pattern", opts.pattern, 0), - OPT_INTRANGE("opengl-vsync-fences", opts.vsync_fences, 0, - 0, NUM_VSYNC_FENCES), - - {0} - }, - .priv_defaults = &(const struct gl_priv){ - .opts = { - .swap_interval = 1, - }, - }, -}; |