mirror of https://github.com/mpv-player/mpv
vo_gpu: convert windows/osx hwdecs/contexts to new API
This commit is contained in:
parent
65979986a9
commit
75c0c06640
|
@ -4541,14 +4541,6 @@ The following video options are currently all specific to ``--vo=gpu`` and
|
|||
|
||||
Windows with ANGLE only.
|
||||
|
||||
``--angle-max-frame-latency=<1-16>``
|
||||
Sets the maximum number of frames that the system is allowed to queue for
|
||||
rendering with the ANGLE backend (default: 3). Lower values should make
|
||||
VSync timing more accurate, but a value of ``1`` requires powerful
|
||||
hardware, since the CPU will not be able to "render ahead" of the GPU.
|
||||
|
||||
Windows with ANGLE only.
|
||||
|
||||
``--angle-renderer=<d3d9|d3d11|auto>``
|
||||
Forces a specific renderer when using the ANGLE backend (default: auto). In
|
||||
auto mode this will pick D3D11 for systems that support Direct3D 11 feature
|
||||
|
@ -4561,17 +4553,6 @@ The following video options are currently all specific to ``--vo=gpu`` and
|
|||
|
||||
Windows with ANGLE only.
|
||||
|
||||
``--angle-swapchain-length=<2-16>``
|
||||
Sets the number of buffers in the D3D11 presentation queue when using the
|
||||
ANGLE backend (default: 6). At least 2 are required, since one is the back
|
||||
buffer that mpv renders to and the other is the front buffer that is
|
||||
presented by the DWM. Additional buffers can improve performance, because
|
||||
for example, mpv will not have to wait on the DWM to release the front
|
||||
buffer before rendering a new frame to it. For this reason, Microsoft
|
||||
recommends at least 4.
|
||||
|
||||
Windows with ANGLE only.
|
||||
|
||||
``--cocoa-force-dedicated-gpu=<yes|no>``
|
||||
Deactivates the automatic graphics switching and forces the dedicated GPU.
|
||||
(default: no)
|
||||
|
|
|
@ -40,7 +40,7 @@ extern const struct ra_ctx_fns ra_ctx_cocoa;
|
|||
extern const struct ra_ctx_fns ra_ctx_wayland_egl;
|
||||
extern const struct ra_ctx_fns ra_ctx_wgl;
|
||||
extern const struct ra_ctx_fns ra_ctx_angle;
|
||||
extern const struct ra_ctx_fns ra_ctx_dxinterop;
|
||||
extern const struct ra_ctx_fns ra_ctx_dxgl;
|
||||
extern const struct ra_ctx_fns ra_ctx_rpi;
|
||||
extern const struct ra_ctx_fns ra_ctx_mali;
|
||||
extern const struct ra_ctx_fns ra_ctx_vdpauglx;
|
||||
|
@ -50,7 +50,6 @@ static const struct ra_ctx_fns *contexts[] = {
|
|||
#if HAVE_RPI
|
||||
&ra_ctx_rpi,
|
||||
#endif
|
||||
/*
|
||||
#if HAVE_GL_COCOA
|
||||
&ra_ctx_cocoa,
|
||||
#endif
|
||||
|
@ -61,9 +60,8 @@ static const struct ra_ctx_fns *contexts[] = {
|
|||
&ra_ctx_wgl,
|
||||
#endif
|
||||
#if HAVE_GL_DXINTEROP
|
||||
&ra_ctx_dxinterop,
|
||||
&ra_ctx_dxgl,
|
||||
#endif
|
||||
*/
|
||||
#if HAVE_GL_X11
|
||||
&ra_ctx_glx_probe,
|
||||
#endif
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "video/out/w32_common.h"
|
||||
#include "osdep/windows_utils.h"
|
||||
#include "context.h"
|
||||
#include "utils.h"
|
||||
|
||||
#ifndef EGL_D3D_TEXTURE_ANGLE
|
||||
#define EGL_D3D_TEXTURE_ANGLE 0x33A3
|
||||
|
@ -52,8 +53,6 @@ struct angle_opts {
|
|||
int d3d11_warp;
|
||||
int d3d11_feature_level;
|
||||
int egl_windowing;
|
||||
int swapchain_length; // Currently only works with DXGI 1.2+
|
||||
int max_frame_latency;
|
||||
int flip;
|
||||
};
|
||||
|
||||
|
@ -77,9 +76,9 @@ const struct m_sub_options angle_conf = {
|
|||
({"auto", -1},
|
||||
{"no", 0},
|
||||
{"yes", 1})),
|
||||
OPT_INTRANGE("angle-swapchain-length", swapchain_length, 0, 2, 16),
|
||||
OPT_INTRANGE("angle-max-frame-latency", max_frame_latency, 0, 1, 16),
|
||||
OPT_FLAG("angle-flip", flip, 0),
|
||||
OPT_REPLACED("angle-max-frame-latency", "swapchain-depth"),
|
||||
OPT_REMOVED("angle-swapchain-length", "controlled by --swapchain-depth"),
|
||||
{0}
|
||||
},
|
||||
.defaults = &(const struct angle_opts) {
|
||||
|
@ -87,14 +86,14 @@ const struct m_sub_options angle_conf = {
|
|||
.d3d11_warp = -1,
|
||||
.d3d11_feature_level = D3D_FEATURE_LEVEL_11_0,
|
||||
.egl_windowing = -1,
|
||||
.swapchain_length = 6,
|
||||
.max_frame_latency = 3,
|
||||
.flip = 1,
|
||||
},
|
||||
.size = sizeof(struct angle_opts),
|
||||
};
|
||||
|
||||
struct priv {
|
||||
GL gl;
|
||||
|
||||
IDXGISwapChain *dxgi_swapchain;
|
||||
|
||||
ID3D11Device *d3d11_device;
|
||||
|
@ -110,20 +109,21 @@ struct priv {
|
|||
|
||||
int sc_width, sc_height; // Swap chain width and height
|
||||
int swapinterval;
|
||||
bool flipped;
|
||||
|
||||
struct angle_opts *opts;
|
||||
};
|
||||
|
||||
static __thread struct MPGLContext *current_ctx;
|
||||
static __thread struct ra_ctx *current_ctx;
|
||||
|
||||
static void update_sizes(MPGLContext *ctx)
|
||||
static void update_sizes(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
p->sc_width = ctx->vo->dwidth ? ctx->vo->dwidth : 1;
|
||||
p->sc_height = ctx->vo->dheight ? ctx->vo->dheight : 1;
|
||||
}
|
||||
|
||||
static void d3d11_backbuffer_release(MPGLContext *ctx)
|
||||
static void d3d11_backbuffer_release(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
|
||||
|
@ -137,7 +137,7 @@ static void d3d11_backbuffer_release(MPGLContext *ctx)
|
|||
SAFE_RELEASE(p->d3d11_backbuffer);
|
||||
}
|
||||
|
||||
static bool d3d11_backbuffer_get(MPGLContext *ctx)
|
||||
static bool d3d11_backbuffer_get(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
struct vo *vo = ctx->vo;
|
||||
|
@ -168,7 +168,7 @@ static bool d3d11_backbuffer_get(MPGLContext *ctx)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void d3d11_backbuffer_resize(MPGLContext *ctx)
|
||||
static void d3d11_backbuffer_resize(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
struct vo *vo = ctx->vo;
|
||||
|
@ -197,7 +197,7 @@ static void d3d11_backbuffer_resize(MPGLContext *ctx)
|
|||
MP_FATAL(vo, "Couldn't get back buffer after resize\n");
|
||||
}
|
||||
|
||||
static void d3d11_device_destroy(MPGLContext *ctx)
|
||||
static void d3d11_device_destroy(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
|
||||
|
@ -215,7 +215,7 @@ static void d3d11_device_destroy(MPGLContext *ctx)
|
|||
SAFE_RELEASE(p->d3d11_device);
|
||||
}
|
||||
|
||||
static bool d3d11_device_create(MPGLContext *ctx, int flags)
|
||||
static bool d3d11_device_create(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
struct vo *vo = ctx->vo;
|
||||
|
@ -226,7 +226,7 @@ static bool d3d11_device_create(MPGLContext *ctx, int flags)
|
|||
.force_warp = o->d3d11_warp == 1,
|
||||
.max_feature_level = o->d3d11_feature_level,
|
||||
.min_feature_level = D3D_FEATURE_LEVEL_9_3,
|
||||
.max_frame_latency = o->max_frame_latency,
|
||||
.max_frame_latency = ctx->opts.swapchain_depth,
|
||||
};
|
||||
if (!mp_d3d11_create_present_device(vo->log, &device_opts, &p->d3d11_device))
|
||||
return false;
|
||||
|
@ -262,7 +262,7 @@ static bool d3d11_device_create(MPGLContext *ctx, int flags)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void d3d11_swapchain_surface_destroy(MPGLContext *ctx)
|
||||
static void d3d11_swapchain_surface_destroy(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
|
||||
|
@ -277,7 +277,7 @@ static void d3d11_swapchain_surface_destroy(MPGLContext *ctx)
|
|||
ID3D11DeviceContext_Flush(p->d3d11_context);
|
||||
}
|
||||
|
||||
static bool d3d11_swapchain_surface_create(MPGLContext *ctx, int flags)
|
||||
static bool d3d11_swapchain_surface_create(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
struct vo *vo = ctx->vo;
|
||||
|
@ -292,7 +292,9 @@ static bool d3d11_swapchain_surface_create(MPGLContext *ctx, int flags)
|
|||
.width = p->sc_width,
|
||||
.height = p->sc_height,
|
||||
.flip = o->flip,
|
||||
.length = o->swapchain_length,
|
||||
// Add one frame for the backbuffer and one frame of "slack" to reduce
|
||||
// contention with the window manager when acquiring the backbuffer
|
||||
.length = ctx->opts.swapchain_depth + 2,
|
||||
.usage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_SHADER_INPUT,
|
||||
};
|
||||
if (!mp_d3d11_create_swapchain(p->d3d11_device, vo->log, &swapchain_opts,
|
||||
|
@ -301,8 +303,7 @@ static bool d3d11_swapchain_surface_create(MPGLContext *ctx, int flags)
|
|||
if (!d3d11_backbuffer_get(ctx))
|
||||
goto fail;
|
||||
|
||||
// EGL_D3D_TEXTURE_ANGLE pbuffers are always flipped vertically
|
||||
ctx->flip_v = true;
|
||||
p->flipped = true;
|
||||
return true;
|
||||
|
||||
fail:
|
||||
|
@ -310,7 +311,7 @@ fail:
|
|||
return false;
|
||||
}
|
||||
|
||||
static void d3d9_device_destroy(MPGLContext *ctx)
|
||||
static void d3d9_device_destroy(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
|
||||
|
@ -319,7 +320,7 @@ static void d3d9_device_destroy(MPGLContext *ctx)
|
|||
p->egl_display = EGL_NO_DISPLAY;
|
||||
}
|
||||
|
||||
static bool d3d9_device_create(MPGLContext *ctx, int flags)
|
||||
static bool d3d9_device_create(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
struct vo *vo = ctx->vo;
|
||||
|
@ -348,7 +349,7 @@ static bool d3d9_device_create(MPGLContext *ctx, int flags)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void egl_window_surface_destroy(MPGLContext *ctx)
|
||||
static void egl_window_surface_destroy(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
if (p->egl_window) {
|
||||
|
@ -357,7 +358,7 @@ static void egl_window_surface_destroy(MPGLContext *ctx)
|
|||
}
|
||||
}
|
||||
|
||||
static bool egl_window_surface_create(MPGLContext *ctx, int flags)
|
||||
static bool egl_window_surface_create(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
struct vo *vo = ctx->vo;
|
||||
|
@ -374,7 +375,7 @@ static bool egl_window_surface_create(MPGLContext *ctx, int flags)
|
|||
EGL_SURFACE_ORIENTATION_ANGLE);
|
||||
MP_TARRAY_APPEND(NULL, window_attribs, window_attribs_len,
|
||||
EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE);
|
||||
ctx->flip_v = true;
|
||||
p->flipped = true;
|
||||
MP_VERBOSE(vo, "Rendering flipped.\n");
|
||||
}
|
||||
}
|
||||
|
@ -396,7 +397,7 @@ fail:
|
|||
return false;
|
||||
}
|
||||
|
||||
static void context_destroy(struct MPGLContext *ctx)
|
||||
static void context_destroy(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
if (p->egl_context) {
|
||||
|
@ -407,7 +408,7 @@ static void context_destroy(struct MPGLContext *ctx)
|
|||
p->egl_context = EGL_NO_CONTEXT;
|
||||
}
|
||||
|
||||
static bool context_init(struct MPGLContext *ctx, int flags)
|
||||
static bool context_init(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
struct vo *vo = ctx->vo;
|
||||
|
@ -421,8 +422,8 @@ static bool context_init(struct MPGLContext *ctx, int flags)
|
|||
if (exts)
|
||||
MP_DBG(vo, "EGL extensions: %s\n", exts);
|
||||
|
||||
if (!mpegl_create_context(p->egl_display, vo->log, flags | VOFLAG_GLES,
|
||||
&p->egl_context, &p->egl_config))
|
||||
if (!mpegl_create_context(ctx, p->egl_display, &p->egl_context,
|
||||
&p->egl_config))
|
||||
{
|
||||
MP_FATAL(vo, "Could not create EGL context!\n");
|
||||
goto fail;
|
||||
|
@ -434,10 +435,12 @@ fail:
|
|||
return false;
|
||||
}
|
||||
|
||||
static void angle_uninit(struct MPGLContext *ctx)
|
||||
static void angle_uninit(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
|
||||
ra_gl_ctx_uninit(ctx);
|
||||
|
||||
DwmEnableMMCSS(FALSE);
|
||||
|
||||
// Uninit the EGL surface implementation that is being used. Note: This may
|
||||
|
@ -474,17 +477,56 @@ static int GLAPIENTRY angle_swap_interval(int interval)
|
|||
}
|
||||
}
|
||||
|
||||
static int angle_init(struct MPGLContext *ctx, int flags)
|
||||
static void d3d11_swap_buffers(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
|
||||
// Calling Present() on a flip-sequential swap chain will silently change
|
||||
// the underlying storage of the back buffer to point to the next buffer in
|
||||
// the chain. This results in the RTVs for the back buffer becoming
|
||||
// unbound. Since ANGLE doesn't know we called Present(), it will continue
|
||||
// using the unbound RTVs, so we must save and restore them ourselves.
|
||||
ID3D11RenderTargetView *rtvs[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = {0};
|
||||
ID3D11DepthStencilView *dsv = NULL;
|
||||
ID3D11DeviceContext_OMGetRenderTargets(p->d3d11_context,
|
||||
MP_ARRAY_SIZE(rtvs), rtvs, &dsv);
|
||||
|
||||
HRESULT hr = IDXGISwapChain_Present(p->dxgi_swapchain, p->swapinterval, 0);
|
||||
if (FAILED(hr))
|
||||
MP_FATAL(ctx->vo, "Couldn't present: %s\n", mp_HRESULT_to_str(hr));
|
||||
|
||||
// Restore the RTVs and release the objects
|
||||
ID3D11DeviceContext_OMSetRenderTargets(p->d3d11_context,
|
||||
MP_ARRAY_SIZE(rtvs), rtvs, dsv);
|
||||
for (int i = 0; i < MP_ARRAY_SIZE(rtvs); i++)
|
||||
SAFE_RELEASE(rtvs[i]);
|
||||
SAFE_RELEASE(dsv);
|
||||
}
|
||||
|
||||
static void egl_swap_buffers(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
eglSwapBuffers(p->egl_display, p->egl_window);
|
||||
}
|
||||
|
||||
static void angle_swap_buffers(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
if (p->dxgi_swapchain)
|
||||
d3d11_swap_buffers(ctx);
|
||||
else
|
||||
egl_swap_buffers(ctx);
|
||||
}
|
||||
|
||||
static bool angle_init(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv = talloc_zero(ctx, struct priv);
|
||||
struct vo *vo = ctx->vo;
|
||||
GL *gl = &p->gl;
|
||||
|
||||
p->opts = mp_get_config_group(ctx, ctx->global, &angle_conf);
|
||||
struct angle_opts *o = p->opts;
|
||||
|
||||
// DWM MMCSS cargo-cult. The dxinterop backend also does this.
|
||||
DwmEnableMMCSS(TRUE);
|
||||
|
||||
if (!angle_load()) {
|
||||
MP_VERBOSE(vo, "Failed to load LIBEGL.DLL\n");
|
||||
goto fail;
|
||||
|
@ -493,19 +535,19 @@ static int angle_init(struct MPGLContext *ctx, int flags)
|
|||
// Create the underlying EGL device implementation
|
||||
bool context_ok = false;
|
||||
if ((!context_ok && !o->renderer) || o->renderer == RENDERER_D3D11) {
|
||||
context_ok = d3d11_device_create(ctx, flags);
|
||||
context_ok = d3d11_device_create(ctx);
|
||||
if (context_ok) {
|
||||
context_ok = context_init(ctx, flags);
|
||||
context_ok = context_init(ctx);
|
||||
if (!context_ok)
|
||||
d3d11_device_destroy(ctx);
|
||||
}
|
||||
}
|
||||
if ((!context_ok && !o->renderer) || o->renderer == RENDERER_D3D9) {
|
||||
context_ok = d3d9_device_create(ctx, flags);
|
||||
context_ok = d3d9_device_create(ctx);
|
||||
if (context_ok) {
|
||||
MP_VERBOSE(vo, "Using Direct3D 9\n");
|
||||
|
||||
context_ok = context_init(ctx, flags);
|
||||
context_ok = context_init(ctx);
|
||||
if (!context_ok)
|
||||
d3d9_device_destroy(ctx);
|
||||
}
|
||||
|
@ -519,34 +561,58 @@ static int angle_init(struct MPGLContext *ctx, int flags)
|
|||
// Create the underlying EGL surface implementation
|
||||
bool surface_ok = false;
|
||||
if ((!surface_ok && o->egl_windowing == -1) || o->egl_windowing == 0) {
|
||||
surface_ok = d3d11_swapchain_surface_create(ctx, flags);
|
||||
surface_ok = d3d11_swapchain_surface_create(ctx);
|
||||
}
|
||||
if ((!surface_ok && o->egl_windowing == -1) || o->egl_windowing == 1) {
|
||||
surface_ok = egl_window_surface_create(ctx, flags);
|
||||
surface_ok = egl_window_surface_create(ctx);
|
||||
if (surface_ok)
|
||||
MP_VERBOSE(vo, "Using EGL windowing\n");
|
||||
}
|
||||
if (!surface_ok)
|
||||
goto fail;
|
||||
|
||||
mpegl_load_functions(ctx->gl, vo->log);
|
||||
mpegl_load_functions(gl, vo->log);
|
||||
|
||||
current_ctx = ctx;
|
||||
ctx->gl->SwapInterval = angle_swap_interval;
|
||||
gl->SwapInterval = angle_swap_interval;
|
||||
|
||||
return 0;
|
||||
// ANGLE doesn't actually need to override any of the functions (yet)
|
||||
static const struct ra_swapchain_fns empty_swapchain_fns = {0};
|
||||
struct ra_gl_ctx_params params = {
|
||||
.swap_buffers = angle_swap_buffers,
|
||||
.flipped = p->flipped,
|
||||
.external_swapchain = p->dxgi_swapchain ? &empty_swapchain_fns : NULL,
|
||||
};
|
||||
|
||||
if (!ra_gl_ctx_init(ctx, gl, params))
|
||||
goto fail;
|
||||
|
||||
DwmEnableMMCSS(TRUE); // DWM MMCSS cargo-cult. The dxgl backend also does this.
|
||||
|
||||
return true;
|
||||
fail:
|
||||
angle_uninit(ctx);
|
||||
return -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int angle_reconfig(struct MPGLContext *ctx)
|
||||
static void resize(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
if (p->dxgi_swapchain)
|
||||
d3d11_backbuffer_resize(ctx);
|
||||
else
|
||||
eglWaitClient(); // Should get ANGLE to resize its swapchain
|
||||
ra_gl_ctx_resize(ctx->swapchain, ctx->vo->dwidth, ctx->vo->dheight, 0);
|
||||
}
|
||||
|
||||
static bool angle_reconfig(struct ra_ctx *ctx)
|
||||
{
|
||||
vo_w32_config(ctx->vo);
|
||||
return 0;
|
||||
resize(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct mp_image *d3d11_screenshot(MPGLContext *ctx)
|
||||
static struct mp_image *d3d11_screenshot(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
ID3D11Texture2D *frontbuffer = NULL;
|
||||
|
@ -624,10 +690,8 @@ done:
|
|||
return img;
|
||||
}
|
||||
|
||||
static int angle_control(MPGLContext *ctx, int *events, int request, void *arg)
|
||||
static int angle_control(struct ra_ctx *ctx, int *events, int request, void *arg)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
|
||||
// Try a D3D11-specific method of taking a window screenshot
|
||||
if (request == VOCTRL_SCREENSHOT_WIN) {
|
||||
struct mp_image *img = d3d11_screenshot(ctx);
|
||||
|
@ -637,63 +701,17 @@ static int angle_control(MPGLContext *ctx, int *events, int request, void *arg)
|
|||
}
|
||||
}
|
||||
|
||||
int r = vo_w32_control(ctx->vo, events, request, arg);
|
||||
if (*events & VO_EVENT_RESIZE) {
|
||||
if (p->dxgi_swapchain)
|
||||
d3d11_backbuffer_resize(ctx);
|
||||
else
|
||||
eglWaitClient(); // Should get ANGLE to resize its swapchain
|
||||
}
|
||||
return r;
|
||||
int ret = vo_w32_control(ctx->vo, events, request, arg);
|
||||
if (*events & VO_EVENT_RESIZE)
|
||||
resize(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void d3d11_swap_buffers(MPGLContext *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
|
||||
// Calling Present() on a flip-sequential swap chain will silently change
|
||||
// the underlying storage of the back buffer to point to the next buffer in
|
||||
// the chain. This results in the RTVs for the back buffer becoming
|
||||
// unbound. Since ANGLE doesn't know we called Present(), it will continue
|
||||
// using the unbound RTVs, so we must save and restore them ourselves.
|
||||
ID3D11RenderTargetView *rtvs[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = {0};
|
||||
ID3D11DepthStencilView *dsv = NULL;
|
||||
ID3D11DeviceContext_OMGetRenderTargets(p->d3d11_context,
|
||||
MP_ARRAY_SIZE(rtvs), rtvs, &dsv);
|
||||
|
||||
HRESULT hr = IDXGISwapChain_Present(p->dxgi_swapchain, p->swapinterval, 0);
|
||||
if (FAILED(hr))
|
||||
MP_FATAL(ctx->vo, "Couldn't present: %s\n", mp_HRESULT_to_str(hr));
|
||||
|
||||
// Restore the RTVs and release the objects
|
||||
ID3D11DeviceContext_OMSetRenderTargets(p->d3d11_context,
|
||||
MP_ARRAY_SIZE(rtvs), rtvs, dsv);
|
||||
for (int i = 0; i < MP_ARRAY_SIZE(rtvs); i++)
|
||||
SAFE_RELEASE(rtvs[i]);
|
||||
SAFE_RELEASE(dsv);
|
||||
}
|
||||
|
||||
static void egl_swap_buffers(MPGLContext *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
eglSwapBuffers(p->egl_display, p->egl_window);
|
||||
}
|
||||
|
||||
static void angle_swap_buffers(MPGLContext *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
if (p->dxgi_swapchain)
|
||||
d3d11_swap_buffers(ctx);
|
||||
else
|
||||
egl_swap_buffers(ctx);
|
||||
}
|
||||
|
||||
const struct mpgl_driver mpgl_driver_angle = {
|
||||
const struct ra_ctx_fns ra_ctx_angle = {
|
||||
.type = "opengl",
|
||||
.name = "angle",
|
||||
.priv_size = sizeof(struct priv),
|
||||
.init = angle_init,
|
||||
.reconfig = angle_reconfig,
|
||||
.swap_buffers = angle_swap_buffers,
|
||||
.control = angle_control,
|
||||
.uninit = angle_uninit,
|
||||
};
|
||||
|
|
|
@ -36,6 +36,7 @@ const struct m_sub_options cocoa_conf = {
|
|||
};
|
||||
|
||||
struct priv {
|
||||
GL gl;
|
||||
CGLPixelFormatObj pix;
|
||||
CGLContextObj ctx;
|
||||
|
||||
|
@ -62,7 +63,7 @@ static void *cocoa_glgetaddr(const char *s)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static CGLError test_gl_version(struct MPGLContext *ctx, CGLOpenGLProfile ver)
|
||||
static CGLError test_gl_version(struct ra_ctx *ctx, CGLOpenGLProfile ver)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
|
||||
|
@ -107,9 +108,10 @@ error_out:
|
|||
return err;
|
||||
}
|
||||
|
||||
static bool create_gl_context(struct MPGLContext *ctx, int vo_flags)
|
||||
static bool create_gl_context(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
GL *gl = &p->gl;
|
||||
CGLError err;
|
||||
|
||||
CGLOpenGLProfile gl_versions[] = {
|
||||
|
@ -132,60 +134,82 @@ static bool create_gl_context(struct MPGLContext *ctx, int vo_flags)
|
|||
vo_cocoa_set_opengl_ctx(ctx->vo, p->ctx);
|
||||
CGLSetCurrentContext(p->ctx);
|
||||
|
||||
if (vo_flags & VOFLAG_ALPHA)
|
||||
if (ctx->opts.want_alpha)
|
||||
CGLSetParameter(p->ctx, kCGLCPSurfaceOpacity, &(GLint){0});
|
||||
|
||||
mpgl_load_functions(ctx->gl, (void *)cocoa_glgetaddr, NULL, ctx->vo->log);
|
||||
mpgl_load_functions(gl, (void *)cocoa_glgetaddr, NULL, ctx->vo->log);
|
||||
gl->SwapInterval = set_swap_interval;
|
||||
|
||||
CGLReleasePixelFormat(p->pix);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void cocoa_uninit(MPGLContext *ctx)
|
||||
static void cocoa_uninit(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
ra_gl_ctx_uninit(ctx);
|
||||
CGLReleaseContext(p->ctx);
|
||||
vo_cocoa_uninit(ctx->vo);
|
||||
}
|
||||
|
||||
static int cocoa_init(MPGLContext *ctx, int vo_flags)
|
||||
static void cocoa_swap_buffers(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
GL *gl = &p->gl;
|
||||
vo_cocoa_swap_buffers(ctx->vo);
|
||||
gl->Flush();
|
||||
}
|
||||
|
||||
static bool cocoa_init(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv = talloc_zero(ctx, struct priv);
|
||||
GL *gl = &p->gl;
|
||||
p->opts = mp_get_config_group(ctx, ctx->global, &cocoa_conf);
|
||||
vo_cocoa_init(ctx->vo);
|
||||
|
||||
if (!create_gl_context(ctx, vo_flags))
|
||||
return -1;
|
||||
if (!create_gl_context(ctx))
|
||||
goto fail;
|
||||
|
||||
ctx->gl->SwapInterval = set_swap_interval;
|
||||
return 0;
|
||||
struct ra_gl_ctx_params params = {
|
||||
.swap_buffers = cocoa_swap_buffers,
|
||||
};
|
||||
|
||||
if (!ra_gl_ctx_init(ctx, gl, params))
|
||||
goto fail;
|
||||
|
||||
return true;
|
||||
|
||||
fail:
|
||||
cocoa_uninit(ctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
static int cocoa_reconfig(struct MPGLContext *ctx)
|
||||
static void resize(struct ra_ctx *ctx)
|
||||
{
|
||||
ra_gl_ctx_resize(ctx->swapchain, ctx->vo->dwidth, ctx->vo->dheight, 0);
|
||||
}
|
||||
|
||||
static bool cocoa_reconfig(struct ra_ctx *ctx)
|
||||
{
|
||||
vo_cocoa_config_window(ctx->vo);
|
||||
return 0;
|
||||
resize(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int cocoa_control(struct MPGLContext *ctx, int *events, int request,
|
||||
static int cocoa_control(struct ra_ctx *ctx, int *events, int request,
|
||||
void *arg)
|
||||
{
|
||||
return vo_cocoa_control(ctx->vo, events, request, arg);
|
||||
int ret = vo_cocoa_control(ctx->vo, events, request, arg);
|
||||
if (*events & VO_EVENT_RESIZE)
|
||||
resize(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void cocoa_swap_buffers(struct MPGLContext *ctx)
|
||||
{
|
||||
vo_cocoa_swap_buffers(ctx->vo);
|
||||
ctx->gl->Flush();
|
||||
}
|
||||
|
||||
const struct mpgl_driver mpgl_driver_cocoa = {
|
||||
const struct ra_ctx_fns ra_ctx_cocoa = {
|
||||
.type = "opengl",
|
||||
.name = "cocoa",
|
||||
.priv_size = sizeof(struct priv),
|
||||
.init = cocoa_init,
|
||||
.reconfig = cocoa_reconfig,
|
||||
.swap_buffers = cocoa_swap_buffers,
|
||||
.control = cocoa_control,
|
||||
.uninit = cocoa_uninit,
|
||||
};
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "osdep/windows_utils.h"
|
||||
#include "video/out/w32_common.h"
|
||||
#include "context.h"
|
||||
#include "utils.h"
|
||||
|
||||
// For WGL_ACCESS_WRITE_DISCARD_NV, etc.
|
||||
#include <GL/wglext.h>
|
||||
|
@ -35,6 +36,8 @@ EXTERN_C IMAGE_DOS_HEADER __ImageBase;
|
|||
#endif
|
||||
|
||||
struct priv {
|
||||
GL gl;
|
||||
|
||||
HMODULE d3d9_dll;
|
||||
HRESULT (WINAPI *Direct3DCreate9Ex)(UINT SDKVersion, IDirect3D9Ex **ppD3D);
|
||||
|
||||
|
@ -54,6 +57,7 @@ struct priv {
|
|||
|
||||
// OpenGL resources
|
||||
GLuint texture;
|
||||
GLuint main_fb;
|
||||
|
||||
// Did we lose the device?
|
||||
bool lost_device;
|
||||
|
@ -63,7 +67,7 @@ struct priv {
|
|||
int width, height, swapinterval;
|
||||
};
|
||||
|
||||
static __thread struct MPGLContext *current_ctx;
|
||||
static __thread struct ra_ctx *current_ctx;
|
||||
|
||||
static void pump_message_loop(void)
|
||||
{
|
||||
|
@ -84,10 +88,11 @@ static void *w32gpa(const GLubyte *procName)
|
|||
return GetProcAddress(oglmod, procName);
|
||||
}
|
||||
|
||||
static int os_ctx_create(struct MPGLContext *ctx)
|
||||
static int os_ctx_create(struct ra_ctx *ctx)
|
||||
{
|
||||
static const wchar_t os_wnd_class[] = L"mpv offscreen gl";
|
||||
struct priv *p = ctx->priv;
|
||||
GL *gl = &p->gl;
|
||||
HGLRC legacy_context = NULL;
|
||||
|
||||
RegisterClassExW(&(WNDCLASSEXW) {
|
||||
|
@ -190,8 +195,8 @@ static int os_ctx_create(struct MPGLContext *ctx)
|
|||
goto fail;
|
||||
}
|
||||
|
||||
mpgl_load_functions(ctx->gl, w32gpa, wgl_exts, ctx->vo->log);
|
||||
if (!(ctx->gl->mpgl_caps & MPGL_CAP_DXINTEROP)) {
|
||||
mpgl_load_functions(gl, w32gpa, wgl_exts, ctx->vo->log);
|
||||
if (!(gl->mpgl_caps & MPGL_CAP_DXINTEROP)) {
|
||||
MP_FATAL(ctx->vo, "WGL_NV_DX_interop is not supported\n");
|
||||
goto fail;
|
||||
}
|
||||
|
@ -205,7 +210,7 @@ fail:
|
|||
return -1;
|
||||
}
|
||||
|
||||
static void os_ctx_destroy(MPGLContext *ctx)
|
||||
static void os_ctx_destroy(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
|
||||
|
@ -219,10 +224,10 @@ static void os_ctx_destroy(MPGLContext *ctx)
|
|||
DestroyWindow(p->os_wnd);
|
||||
}
|
||||
|
||||
static int d3d_size_dependent_create(MPGLContext *ctx)
|
||||
static int d3d_size_dependent_create(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
struct GL *gl = ctx->gl;
|
||||
GL *gl = &p->gl;
|
||||
HRESULT hr;
|
||||
|
||||
IDirect3DSwapChain9 *sw9;
|
||||
|
@ -294,7 +299,7 @@ static int d3d_size_dependent_create(MPGLContext *ctx)
|
|||
return -1;
|
||||
}
|
||||
|
||||
gl->BindFramebuffer(GL_FRAMEBUFFER, ctx->main_fb);
|
||||
gl->BindFramebuffer(GL_FRAMEBUFFER, p->main_fb);
|
||||
gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D, p->texture, 0);
|
||||
gl->BindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
@ -302,10 +307,10 @@ static int d3d_size_dependent_create(MPGLContext *ctx)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void d3d_size_dependent_destroy(MPGLContext *ctx)
|
||||
static void d3d_size_dependent_destroy(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
struct GL *gl = ctx->gl;
|
||||
GL *gl = &p->gl;
|
||||
|
||||
if (p->rtarget_h) {
|
||||
gl->DXUnlockObjectsNV(p->device_h, 1, &p->rtarget_h);
|
||||
|
@ -321,7 +326,8 @@ static void d3d_size_dependent_destroy(MPGLContext *ctx)
|
|||
SAFE_RELEASE(p->swapchain);
|
||||
}
|
||||
|
||||
static void fill_presentparams(MPGLContext *ctx, D3DPRESENT_PARAMETERS *pparams)
|
||||
static void fill_presentparams(struct ra_ctx *ctx,
|
||||
D3DPRESENT_PARAMETERS *pparams)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
|
||||
|
@ -338,13 +344,9 @@ static void fill_presentparams(MPGLContext *ctx, D3DPRESENT_PARAMETERS *pparams)
|
|||
.Windowed = TRUE,
|
||||
.BackBufferWidth = ctx->vo->dwidth ? ctx->vo->dwidth : 1,
|
||||
.BackBufferHeight = ctx->vo->dheight ? ctx->vo->dheight : 1,
|
||||
// The length of the backbuffer queue shouldn't affect latency because
|
||||
// swap_buffers() always uses the backbuffer at the head of the queue
|
||||
// and presents it immediately. MSDN says there is a performance
|
||||
// penalty for having a short backbuffer queue and this seems to be
|
||||
// true, at least on Nvidia, where less than four backbuffers causes
|
||||
// very high CPU usage. Use six to be safe.
|
||||
.BackBufferCount = 6,
|
||||
// Add one frame for the backbuffer and one frame of "slack" to reduce
|
||||
// contention with the window manager when acquiring the backbuffer
|
||||
.BackBufferCount = ctx->opts.swapchain_depth + 2,
|
||||
.SwapEffect = IsWindows7OrGreater() ? D3DSWAPEFFECT_FLIPEX : D3DSWAPEFFECT_FLIP,
|
||||
// Automatically get the backbuffer format from the display format
|
||||
.BackBufferFormat = D3DFMT_UNKNOWN,
|
||||
|
@ -353,10 +355,10 @@ static void fill_presentparams(MPGLContext *ctx, D3DPRESENT_PARAMETERS *pparams)
|
|||
};
|
||||
}
|
||||
|
||||
static int d3d_create(MPGLContext *ctx)
|
||||
static int d3d_create(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
struct GL *gl = ctx->gl;
|
||||
GL *gl = &p->gl;
|
||||
HRESULT hr;
|
||||
|
||||
p->d3d9_dll = LoadLibraryW(L"d3d9.dll");
|
||||
|
@ -396,8 +398,7 @@ static int d3d_create(MPGLContext *ctx)
|
|||
return -1;
|
||||
}
|
||||
|
||||
// mpv expects frames to be presented right after swap_buffers() returns
|
||||
IDirect3DDevice9Ex_SetMaximumFrameLatency(p->device, 1);
|
||||
IDirect3DDevice9Ex_SetMaximumFrameLatency(p->device, ctx->opts.swapchain_depth);
|
||||
|
||||
// Register the Direct3D device with WGL_NV_dx_interop
|
||||
p->device_h = gl->DXOpenDeviceNV(p->device);
|
||||
|
@ -410,10 +411,10 @@ static int d3d_create(MPGLContext *ctx)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void d3d_destroy(MPGLContext *ctx)
|
||||
static void d3d_destroy(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
struct GL *gl = ctx->gl;
|
||||
GL *gl = &p->gl;
|
||||
|
||||
if (p->device_h)
|
||||
gl->DXCloseDeviceNV(p->device_h);
|
||||
|
@ -423,8 +424,9 @@ static void d3d_destroy(MPGLContext *ctx)
|
|||
FreeLibrary(p->d3d9_dll);
|
||||
}
|
||||
|
||||
static void dxinterop_uninit(MPGLContext *ctx)
|
||||
static void dxgl_uninit(struct ra_ctx *ctx)
|
||||
{
|
||||
ra_gl_ctx_uninit(ctx);
|
||||
d3d_size_dependent_destroy(ctx);
|
||||
d3d_destroy(ctx);
|
||||
os_ctx_destroy(ctx);
|
||||
|
@ -433,7 +435,7 @@ static void dxinterop_uninit(MPGLContext *ctx)
|
|||
pump_message_loop();
|
||||
}
|
||||
|
||||
static void dxinterop_reset(struct MPGLContext *ctx)
|
||||
static void dxgl_reset(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
HRESULT hr;
|
||||
|
@ -468,18 +470,18 @@ static void dxinterop_reset(struct MPGLContext *ctx)
|
|||
p->lost_device = false;
|
||||
}
|
||||
|
||||
static int GLAPIENTRY dxinterop_swap_interval(int interval)
|
||||
static int GLAPIENTRY dxgl_swap_interval(int interval)
|
||||
{
|
||||
if (!current_ctx)
|
||||
return 0;
|
||||
struct priv *p = current_ctx->priv;
|
||||
|
||||
p->requested_swapinterval = interval;
|
||||
dxinterop_reset(current_ctx);
|
||||
dxgl_reset(current_ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void * GLAPIENTRY dxinterop_get_native_display(const char *name)
|
||||
static void * GLAPIENTRY dxgl_get_native_display(const char *name)
|
||||
{
|
||||
if (!current_ctx || !name)
|
||||
return NULL;
|
||||
|
@ -493,60 +495,17 @@ static void * GLAPIENTRY dxinterop_get_native_display(const char *name)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static int dxinterop_init(struct MPGLContext *ctx, int flags)
|
||||
static void dxgl_swap_buffers(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
struct GL *gl = ctx->gl;
|
||||
|
||||
p->requested_swapinterval = 1;
|
||||
|
||||
if (!vo_w32_init(ctx->vo))
|
||||
goto fail;
|
||||
if (os_ctx_create(ctx) < 0)
|
||||
goto fail;
|
||||
|
||||
// Create the shared framebuffer
|
||||
gl->GenFramebuffers(1, &ctx->main_fb);
|
||||
|
||||
current_ctx = ctx;
|
||||
gl->SwapInterval = dxinterop_swap_interval;
|
||||
gl->MPGetNativeDisplay = dxinterop_get_native_display;
|
||||
|
||||
if (d3d_create(ctx) < 0)
|
||||
goto fail;
|
||||
if (d3d_size_dependent_create(ctx) < 0)
|
||||
goto fail;
|
||||
|
||||
// The OpenGL and Direct3D coordinate systems are flipped vertically
|
||||
// relative to each other. Flip the video during rendering so it can be
|
||||
// copied to the Direct3D backbuffer with a simple (and fast) StretchRect.
|
||||
ctx->flip_v = true;
|
||||
|
||||
DwmEnableMMCSS(TRUE);
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
dxinterop_uninit(ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int dxinterop_reconfig(struct MPGLContext *ctx)
|
||||
{
|
||||
vo_w32_config(ctx->vo);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dxinterop_swap_buffers(MPGLContext *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
struct GL *gl = ctx->gl;
|
||||
GL *gl = &p->gl;
|
||||
HRESULT hr;
|
||||
|
||||
pump_message_loop();
|
||||
|
||||
// If the device is still lost, try to reset it again
|
||||
if (p->lost_device)
|
||||
dxinterop_reset(ctx);
|
||||
dxgl_reset(ctx);
|
||||
if (p->lost_device)
|
||||
return;
|
||||
|
||||
|
@ -571,7 +530,7 @@ static void dxinterop_swap_buffers(MPGLContext *ctx)
|
|||
case D3DERR_DEVICEHUNG:
|
||||
MP_VERBOSE(ctx->vo, "Direct3D device lost! Resetting.\n");
|
||||
p->lost_device = true;
|
||||
dxinterop_reset(ctx);
|
||||
dxgl_reset(ctx);
|
||||
return;
|
||||
default:
|
||||
if (FAILED(hr))
|
||||
|
@ -584,21 +543,75 @@ static void dxinterop_swap_buffers(MPGLContext *ctx)
|
|||
}
|
||||
}
|
||||
|
||||
static int dxinterop_control(MPGLContext *ctx, int *events, int request,
|
||||
void *arg)
|
||||
static bool dxgl_init(struct ra_ctx *ctx)
|
||||
{
|
||||
int r = vo_w32_control(ctx->vo, events, request, arg);
|
||||
if (*events & VO_EVENT_RESIZE)
|
||||
dxinterop_reset(ctx);
|
||||
return r;
|
||||
struct priv *p = ctx->priv = talloc_zero(ctx, struct priv);
|
||||
GL *gl = &p->gl;
|
||||
|
||||
p->requested_swapinterval = 1;
|
||||
|
||||
if (!vo_w32_init(ctx->vo))
|
||||
goto fail;
|
||||
if (os_ctx_create(ctx) < 0)
|
||||
goto fail;
|
||||
|
||||
// Create the shared framebuffer
|
||||
gl->GenFramebuffers(1, &p->main_fb);
|
||||
|
||||
current_ctx = ctx;
|
||||
gl->SwapInterval = dxgl_swap_interval;
|
||||
gl->MPGetNativeDisplay = dxgl_get_native_display;
|
||||
|
||||
if (d3d_create(ctx) < 0)
|
||||
goto fail;
|
||||
if (d3d_size_dependent_create(ctx) < 0)
|
||||
goto fail;
|
||||
|
||||
static const struct ra_swapchain_fns empty_swapchain_fns = {0};
|
||||
struct ra_gl_ctx_params params = {
|
||||
.swap_buffers = dxgl_swap_buffers,
|
||||
.flipped = true,
|
||||
.external_swapchain = &empty_swapchain_fns,
|
||||
};
|
||||
|
||||
if (!ra_gl_ctx_init(ctx, gl, params))
|
||||
goto fail;
|
||||
|
||||
DwmEnableMMCSS(TRUE);
|
||||
return true;
|
||||
fail:
|
||||
dxgl_uninit(ctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
const struct mpgl_driver mpgl_driver_dxinterop = {
|
||||
static void resize(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
dxgl_reset(ctx);
|
||||
ra_gl_ctx_resize(ctx->swapchain, ctx->vo->dwidth, ctx->vo->dheight, p->main_fb);
|
||||
}
|
||||
|
||||
static bool dxgl_reconfig(struct ra_ctx *ctx)
|
||||
{
|
||||
vo_w32_config(ctx->vo);
|
||||
resize(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int dxgl_control(struct ra_ctx *ctx, int *events, int request,
|
||||
void *arg)
|
||||
{
|
||||
int ret = vo_w32_control(ctx->vo, events, request, arg);
|
||||
if (*events & VO_EVENT_RESIZE)
|
||||
resize(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct ra_ctx_fns ra_ctx_dxgl = {
|
||||
.type = "opengl",
|
||||
.name = "dxinterop",
|
||||
.priv_size = sizeof(struct priv),
|
||||
.init = dxinterop_init,
|
||||
.reconfig = dxinterop_reconfig,
|
||||
.swap_buffers = dxinterop_swap_buffers,
|
||||
.control = dxinterop_control,
|
||||
.uninit = dxinterop_uninit,
|
||||
.init = dxgl_init,
|
||||
.reconfig = dxgl_reconfig,
|
||||
.control = dxgl_control,
|
||||
.uninit = dxgl_uninit,
|
||||
};
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "video/out/w32_common.h"
|
||||
#include "video/out/win32/exclusive_hack.h"
|
||||
#include "context.h"
|
||||
#include "utils.h"
|
||||
|
||||
#if !defined(WGL_CONTEXT_MAJOR_VERSION_ARB)
|
||||
/* these are supposed to be defined in wingdi.h but mingw's is too old */
|
||||
|
@ -37,7 +38,9 @@
|
|||
#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
|
||||
#endif
|
||||
|
||||
struct w32_context {
|
||||
struct priv {
|
||||
GL gl;
|
||||
|
||||
int opt_swapinterval;
|
||||
int current_swapinterval;
|
||||
|
||||
|
@ -45,26 +48,25 @@ struct w32_context {
|
|||
|
||||
HGLRC context;
|
||||
HDC hdc;
|
||||
int flags;
|
||||
};
|
||||
|
||||
static void w32_uninit(MPGLContext *ctx);
|
||||
static void wgl_uninit(struct ra_ctx *ctx);
|
||||
|
||||
static __thread struct w32_context *current_w32_context;
|
||||
static __thread struct priv *current_wgl_context;
|
||||
|
||||
static int GLAPIENTRY w32_swap_interval(int interval)
|
||||
static int GLAPIENTRY wgl_swap_interval(int interval)
|
||||
{
|
||||
if (current_w32_context)
|
||||
current_w32_context->opt_swapinterval = interval;
|
||||
if (current_wgl_context)
|
||||
current_wgl_context->opt_swapinterval = interval;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool create_dc(struct MPGLContext *ctx, int flags)
|
||||
static bool create_dc(struct ra_ctx *ctx)
|
||||
{
|
||||
struct w32_context *w32_ctx = ctx->priv;
|
||||
struct priv *p = ctx->priv;
|
||||
HWND win = vo_w32_hwnd(ctx->vo);
|
||||
|
||||
if (w32_ctx->hdc)
|
||||
if (p->hdc)
|
||||
return true;
|
||||
|
||||
HDC hdc = GetDC(win);
|
||||
|
@ -90,11 +92,11 @@ static bool create_dc(struct MPGLContext *ctx, int flags)
|
|||
|
||||
SetPixelFormat(hdc, pf, &pfd);
|
||||
|
||||
w32_ctx->hdc = hdc;
|
||||
p->hdc = hdc;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void *w32gpa(const GLubyte *procName)
|
||||
static void *wglgpa(const GLubyte *procName)
|
||||
{
|
||||
HMODULE oglmod;
|
||||
void *res = wglGetProcAddress(procName);
|
||||
|
@ -104,11 +106,11 @@ static void *w32gpa(const GLubyte *procName)
|
|||
return GetProcAddress(oglmod, procName);
|
||||
}
|
||||
|
||||
static bool create_context_w32_old(struct MPGLContext *ctx)
|
||||
static bool create_context_wgl_old(struct ra_ctx *ctx)
|
||||
{
|
||||
struct w32_context *w32_ctx = ctx->priv;
|
||||
struct priv *p = ctx->priv;
|
||||
|
||||
HDC windc = w32_ctx->hdc;
|
||||
HDC windc = p->hdc;
|
||||
bool res = false;
|
||||
|
||||
HGLRC context = wglCreateContext(windc);
|
||||
|
@ -123,17 +125,15 @@ static bool create_context_w32_old(struct MPGLContext *ctx)
|
|||
return res;
|
||||
}
|
||||
|
||||
w32_ctx->context = context;
|
||||
|
||||
mpgl_load_functions(ctx->gl, w32gpa, NULL, ctx->vo->log);
|
||||
p->context = context;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool create_context_w32_gl3(struct MPGLContext *ctx)
|
||||
static bool create_context_wgl_gl3(struct ra_ctx *ctx)
|
||||
{
|
||||
struct w32_context *w32_ctx = ctx->priv;
|
||||
struct priv *p = ctx->priv;
|
||||
|
||||
HDC windc = w32_ctx->hdc;
|
||||
HDC windc = p->hdc;
|
||||
HGLRC context = 0;
|
||||
|
||||
// A legacy context is needed to get access to the new functions.
|
||||
|
@ -150,7 +150,7 @@ static bool create_context_w32_gl3(struct MPGLContext *ctx)
|
|||
}
|
||||
|
||||
const char *(GLAPIENTRY *wglGetExtensionsStringARB)(HDC hdc)
|
||||
= w32gpa((const GLubyte*)"wglGetExtensionsStringARB");
|
||||
= wglgpa((const GLubyte*)"wglGetExtensionsStringARB");
|
||||
|
||||
if (!wglGetExtensionsStringARB)
|
||||
goto unsupported;
|
||||
|
@ -161,7 +161,7 @@ static bool create_context_w32_gl3(struct MPGLContext *ctx)
|
|||
|
||||
HGLRC (GLAPIENTRY *wglCreateContextAttribsARB)(HDC hDC, HGLRC hShareContext,
|
||||
const int *attribList)
|
||||
= w32gpa((const GLubyte*)"wglCreateContextAttribsARB");
|
||||
= wglgpa((const GLubyte*)"wglCreateContextAttribsARB");
|
||||
|
||||
if (!wglCreateContextAttribsARB)
|
||||
goto unsupported;
|
||||
|
@ -197,11 +197,7 @@ static bool create_context_w32_gl3(struct MPGLContext *ctx)
|
|||
return false;
|
||||
}
|
||||
|
||||
w32_ctx->context = context;
|
||||
|
||||
/* update function pointers */
|
||||
mpgl_load_functions(ctx->gl, w32gpa, NULL, ctx->vo->log);
|
||||
|
||||
p->context = context;
|
||||
return true;
|
||||
|
||||
unsupported:
|
||||
|
@ -214,79 +210,20 @@ out:
|
|||
|
||||
static void create_ctx(void *ptr)
|
||||
{
|
||||
struct MPGLContext *ctx = ptr;
|
||||
struct w32_context *w32_ctx = ctx->priv;
|
||||
struct ra_ctx *ctx = ptr;
|
||||
struct priv *p = ctx->priv;
|
||||
|
||||
if (!create_dc(ctx, w32_ctx->flags))
|
||||
if (!create_dc(ctx))
|
||||
return;
|
||||
|
||||
create_context_w32_gl3(ctx);
|
||||
if (!w32_ctx->context)
|
||||
create_context_w32_old(ctx);
|
||||
create_context_wgl_gl3(ctx);
|
||||
if (!p->context)
|
||||
create_context_wgl_old(ctx);
|
||||
|
||||
wglMakeCurrent(w32_ctx->hdc, NULL);
|
||||
wglMakeCurrent(p->hdc, NULL);
|
||||
}
|
||||
|
||||
static int w32_init(struct MPGLContext *ctx, int flags)
|
||||
{
|
||||
if (!vo_w32_init(ctx->vo))
|
||||
goto fail;
|
||||
|
||||
struct w32_context *w32_ctx = ctx->priv;
|
||||
|
||||
w32_ctx->flags = flags;
|
||||
vo_w32_run_on_thread(ctx->vo, create_ctx, ctx);
|
||||
|
||||
if (!w32_ctx->context)
|
||||
goto fail;
|
||||
|
||||
if (!ctx->gl->SwapInterval)
|
||||
MP_VERBOSE(ctx->vo, "WGL_EXT_swap_control missing.\n");
|
||||
w32_ctx->real_wglSwapInterval = ctx->gl->SwapInterval;
|
||||
ctx->gl->SwapInterval = w32_swap_interval;
|
||||
w32_ctx->current_swapinterval = -1;
|
||||
|
||||
current_w32_context = w32_ctx;
|
||||
wglMakeCurrent(w32_ctx->hdc, w32_ctx->context);
|
||||
DwmEnableMMCSS(TRUE);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
w32_uninit(ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int w32_reconfig(struct MPGLContext *ctx)
|
||||
{
|
||||
vo_w32_config(ctx->vo);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void destroy_gl(void *ptr)
|
||||
{
|
||||
struct MPGLContext *ctx = ptr;
|
||||
struct w32_context *w32_ctx = ctx->priv;
|
||||
if (w32_ctx->context)
|
||||
wglDeleteContext(w32_ctx->context);
|
||||
w32_ctx->context = 0;
|
||||
if (w32_ctx->hdc)
|
||||
ReleaseDC(vo_w32_hwnd(ctx->vo), w32_ctx->hdc);
|
||||
w32_ctx->hdc = NULL;
|
||||
current_w32_context = NULL;
|
||||
}
|
||||
|
||||
static void w32_uninit(MPGLContext *ctx)
|
||||
{
|
||||
struct w32_context *w32_ctx = ctx->priv;
|
||||
if (w32_ctx->context)
|
||||
wglMakeCurrent(w32_ctx->hdc, 0);
|
||||
vo_w32_run_on_thread(ctx->vo, destroy_gl, ctx);
|
||||
|
||||
DwmEnableMMCSS(FALSE);
|
||||
vo_w32_uninit(ctx->vo);
|
||||
}
|
||||
|
||||
static bool compositor_active(MPGLContext *ctx)
|
||||
static bool compositor_active(struct ra_ctx *ctx)
|
||||
{
|
||||
// For Windows 7.
|
||||
BOOL enabled = 0;
|
||||
|
@ -308,13 +245,13 @@ static bool compositor_active(MPGLContext *ctx)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void w32_swap_buffers(MPGLContext *ctx)
|
||||
static void wgl_swap_buffers(struct ra_ctx *ctx)
|
||||
{
|
||||
struct w32_context *w32_ctx = ctx->priv;
|
||||
SwapBuffers(w32_ctx->hdc);
|
||||
struct priv *p = ctx->priv;
|
||||
SwapBuffers(p->hdc);
|
||||
|
||||
// default if we don't DwmFLush
|
||||
int new_swapinterval = w32_ctx->opt_swapinterval;
|
||||
int new_swapinterval = p->opt_swapinterval;
|
||||
|
||||
int dwm_flush_opt;
|
||||
mp_read_option_raw(ctx->global, "opengl-dwmflush", &m_option_type_choice,
|
||||
|
@ -330,26 +267,103 @@ static void w32_swap_buffers(MPGLContext *ctx)
|
|||
}
|
||||
}
|
||||
|
||||
if (new_swapinterval != w32_ctx->current_swapinterval &&
|
||||
w32_ctx->real_wglSwapInterval)
|
||||
if (new_swapinterval != p->current_swapinterval &&
|
||||
p->real_wglSwapInterval)
|
||||
{
|
||||
w32_ctx->real_wglSwapInterval(new_swapinterval);
|
||||
p->real_wglSwapInterval(new_swapinterval);
|
||||
MP_VERBOSE(ctx->vo, "set SwapInterval(%d)\n", new_swapinterval);
|
||||
}
|
||||
w32_ctx->current_swapinterval = new_swapinterval;
|
||||
p->current_swapinterval = new_swapinterval;
|
||||
}
|
||||
|
||||
static int w32_control(MPGLContext *ctx, int *events, int request, void *arg)
|
||||
static bool wgl_init(struct ra_ctx *ctx)
|
||||
{
|
||||
return vo_w32_control(ctx->vo, events, request, arg);
|
||||
struct priv *p = ctx->priv = talloc_zero(ctx, struct priv);
|
||||
GL *gl = &p->gl;
|
||||
|
||||
if (!vo_w32_init(ctx->vo))
|
||||
goto fail;
|
||||
|
||||
vo_w32_run_on_thread(ctx->vo, create_ctx, ctx);
|
||||
if (!p->context)
|
||||
goto fail;
|
||||
|
||||
current_wgl_context = p;
|
||||
wglMakeCurrent(p->hdc, p->context);
|
||||
|
||||
mpgl_load_functions(gl, wglgpa, NULL, ctx->vo->log);
|
||||
|
||||
if (!gl->SwapInterval)
|
||||
MP_VERBOSE(ctx->vo, "WGL_EXT_swap_control missing.\n");
|
||||
p->real_wglSwapInterval = gl->SwapInterval;
|
||||
gl->SwapInterval = wgl_swap_interval;
|
||||
p->current_swapinterval = -1;
|
||||
|
||||
struct ra_gl_ctx_params params = {
|
||||
.swap_buffers = wgl_swap_buffers,
|
||||
};
|
||||
|
||||
if (!ra_gl_ctx_init(ctx, gl, params))
|
||||
goto fail;
|
||||
|
||||
DwmEnableMMCSS(TRUE);
|
||||
return true;
|
||||
|
||||
fail:
|
||||
wgl_uninit(ctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
const struct mpgl_driver mpgl_driver_w32 = {
|
||||
static void resize(struct ra_ctx *ctx)
|
||||
{
|
||||
ra_gl_ctx_resize(ctx->swapchain, ctx->vo->dwidth, ctx->vo->dheight, 0);
|
||||
}
|
||||
|
||||
static bool wgl_reconfig(struct ra_ctx *ctx)
|
||||
{
|
||||
vo_w32_config(ctx->vo);
|
||||
resize(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void destroy_gl(void *ptr)
|
||||
{
|
||||
struct ra_ctx *ctx = ptr;
|
||||
struct priv *p = ctx->priv;
|
||||
if (p->context)
|
||||
wglDeleteContext(p->context);
|
||||
p->context = 0;
|
||||
if (p->hdc)
|
||||
ReleaseDC(vo_w32_hwnd(ctx->vo), p->hdc);
|
||||
p->hdc = NULL;
|
||||
current_wgl_context = NULL;
|
||||
}
|
||||
|
||||
static void wgl_uninit(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
ra_gl_ctx_uninit(ctx);
|
||||
if (p->context)
|
||||
wglMakeCurrent(p->hdc, 0);
|
||||
vo_w32_run_on_thread(ctx->vo, destroy_gl, ctx);
|
||||
|
||||
DwmEnableMMCSS(FALSE);
|
||||
vo_w32_uninit(ctx->vo);
|
||||
}
|
||||
|
||||
static int wgl_control(struct ra_ctx *ctx, int *events, int request, void *arg)
|
||||
{
|
||||
int ret = vo_w32_control(ctx->vo, events, request, arg);
|
||||
if (*events & VO_EVENT_RESIZE)
|
||||
resize(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct ra_ctx_fns ra_ctx_wgl = {
|
||||
.type = "opengl",
|
||||
.name = "win",
|
||||
.priv_size = sizeof(struct w32_context),
|
||||
.init = w32_init,
|
||||
.reconfig = w32_reconfig,
|
||||
.swap_buffers = w32_swap_buffers,
|
||||
.control = w32_control,
|
||||
.uninit = w32_uninit,
|
||||
.init = wgl_init,
|
||||
.reconfig = wgl_reconfig,
|
||||
.control = wgl_control,
|
||||
.uninit = wgl_uninit,
|
||||
};
|
|
@ -27,7 +27,7 @@
|
|||
#include "common/common.h"
|
||||
#include "osdep/timer.h"
|
||||
#include "osdep/windows_utils.h"
|
||||
#include "hwdec.h"
|
||||
#include "video/out/gpu/hwdec.h"
|
||||
#include "ra_gl.h"
|
||||
#include "video/hwdec.h"
|
||||
#include "video/decode/d3d.h"
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#include "common/common.h"
|
||||
#include "osdep/timer.h"
|
||||
#include "osdep/windows_utils.h"
|
||||
#include "hwdec.h"
|
||||
#include "video/out/gpu/hwdec.h"
|
||||
#include "ra_gl.h"
|
||||
#include "video/hwdec.h"
|
||||
#include "video/decode/d3d.h"
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#include "common/common.h"
|
||||
#include "osdep/timer.h"
|
||||
#include "osdep/windows_utils.h"
|
||||
#include "hwdec.h"
|
||||
#include "video/out/gpu/hwdec.h"
|
||||
#include "ra_gl.h"
|
||||
#include "video/hwdec.h"
|
||||
#include "video/decode/d3d.h"
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
#include "common/common.h"
|
||||
#include "osdep/windows_utils.h"
|
||||
#include "hwdec.h"
|
||||
#include "video/out/gpu/hwdec.h"
|
||||
#include "ra_gl.h"
|
||||
#include "video/hwdec.h"
|
||||
#include "video/decode/d3d.h"
|
||||
|
|
|
@ -400,25 +400,25 @@ def build(ctx):
|
|||
( "video/out/opengl/utils.c", "gl" ),
|
||||
( "video/out/opengl/ra_gl.c", "gl" ),
|
||||
( "video/out/opengl/context.c", "gl" ),
|
||||
# ( "video/out/opengl/context_angle.c", "egl-angle-win32" ),
|
||||
# ( "video/out/opengl/context_cocoa.c", "gl-cocoa" ),
|
||||
( "video/out/opengl/context_angle.c", "egl-angle-win32" ),
|
||||
( "video/out/opengl/context_cocoa.c", "gl-cocoa" ),
|
||||
( "video/out/opengl/context_drm_egl.c", "egl-drm" ),
|
||||
# ( "video/out/opengl/context_dxinterop.c","gl-dxinterop" ),
|
||||
( "video/out/opengl/context_dxinterop.c","gl-dxinterop" ),
|
||||
( "video/out/opengl/context_mali_fbdev.c","mali-fbdev" ),
|
||||
( "video/out/opengl/context_rpi.c", "rpi" ),
|
||||
( "video/out/opengl/context_vdpau.c", "vdpau-gl-x11" ),
|
||||
( "video/out/opengl/context_wayland.c", "gl-wayland" ),
|
||||
# ( "video/out/opengl/context_w32.c", "gl-win32" ),
|
||||
( "video/out/opengl/context_win.c", "gl-win32" ),
|
||||
( "video/out/opengl/context_glx.c", "gl-x11" ),
|
||||
( "video/out/opengl/context_x11egl.c", "egl-x11" ),
|
||||
( "video/out/opengl/cuda_dynamic.c", "cuda-hwaccel" ),
|
||||
# ( "video/out/opengl/d3d11_helpers.c", "egl-angle-win32" ),
|
||||
( "video/out/opengl/d3d11_helpers.c", "egl-angle-win32" ),
|
||||
( "video/out/opengl/egl_helpers.c", "egl-helpers" ),
|
||||
( "video/out/opengl/hwdec_cuda.c", "cuda-hwaccel" ),
|
||||
# ( "video/out/opengl/hwdec_d3d11egl.c", "d3d-hwaccel" ),
|
||||
# ( "video/out/opengl/hwdec_d3d11eglrgb.c","d3d-hwaccel" ),
|
||||
# ( "video/out/opengl/hwdec_dxva2gldx.c", "gl-dxinterop-d3d9" ),
|
||||
# ( "video/out/opengl/hwdec_dxva2egl.c", "d3d9-hwaccel" ),
|
||||
( "video/out/opengl/hwdec_d3d11egl.c", "d3d-hwaccel" ),
|
||||
( "video/out/opengl/hwdec_d3d11eglrgb.c","d3d-hwaccel" ),
|
||||
( "video/out/opengl/hwdec_dxva2gldx.c", "gl-dxinterop-d3d9" ),
|
||||
( "video/out/opengl/hwdec_dxva2egl.c", "d3d9-hwaccel" ),
|
||||
( "video/out/opengl/hwdec_osx.c", "videotoolbox-gl" ),
|
||||
( "video/out/opengl/hwdec_ios.m", "ios-gl" ),
|
||||
( "video/out/opengl/hwdec_rpi.c", "rpi" ),
|
||||
|
|
Loading…
Reference in New Issue