summaryrefslogtreecommitdiffstats
path: root/video/out
diff options
context:
space:
mode:
Diffstat (limited to 'video/out')
-rw-r--r--video/out/opengl/context_angle.c201
1 files changed, 112 insertions, 89 deletions
diff --git a/video/out/opengl/context_angle.c b/video/out/opengl/context_angle.c
index a8051155e1..c96ae5cc27 100644
--- a/video/out/opengl/context_angle.c
+++ b/video/out/opengl/context_angle.c
@@ -518,6 +518,112 @@ static void angle_swap_buffers(struct ra_ctx *ctx)
egl_swap_buffers(ctx);
}
+static struct mp_image *d3d11_screenshot(struct ra_ctx *ctx)
+{
+ struct priv *p = ctx->priv;
+ ID3D11Texture2D *frontbuffer = NULL;
+ ID3D11Texture2D *staging = NULL;
+ struct mp_image *img = NULL;
+ HRESULT hr;
+
+ if (!p->dxgi_swapchain)
+ goto done;
+
+ // Validate the swap chain. This screenshot method will only work on DXGI
+ // 1.2+ flip/sequential swap chains. It's probably not possible at all with
+ // discard swap chains, since by definition, the backbuffer contents is
+ // discarded on Present().
+ DXGI_SWAP_CHAIN_DESC scd;
+ hr = IDXGISwapChain_GetDesc(p->dxgi_swapchain, &scd);
+ if (FAILED(hr))
+ goto done;
+ if (scd.SwapEffect != DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL)
+ goto done;
+
+ // Get the last buffer that was presented with Present(). This should be
+ // the n-1th buffer for a swap chain of length n.
+ hr = IDXGISwapChain_GetBuffer(p->dxgi_swapchain, scd.BufferCount - 1,
+ &IID_ID3D11Texture2D, (void**)&frontbuffer);
+ if (FAILED(hr))
+ goto done;
+
+ D3D11_TEXTURE2D_DESC td;
+ ID3D11Texture2D_GetDesc(frontbuffer, &td);
+ if (td.SampleDesc.Count > 1)
+ goto done;
+
+ // Validate the backbuffer format and convert to an mpv IMGFMT
+ enum mp_imgfmt fmt;
+ switch (td.Format) {
+ case DXGI_FORMAT_B8G8R8A8_UNORM: fmt = IMGFMT_BGR0; break;
+ case DXGI_FORMAT_R8G8B8A8_UNORM: fmt = IMGFMT_RGB0; break;
+ default:
+ goto done;
+ }
+
+ // Create a staging texture based on the frontbuffer with CPU access
+ td.BindFlags = 0;
+ td.MiscFlags = 0;
+ td.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
+ td.Usage = D3D11_USAGE_STAGING;
+ hr = ID3D11Device_CreateTexture2D(p->d3d11_device, &td, 0, &staging);
+ if (FAILED(hr))
+ goto done;
+
+ ID3D11DeviceContext_CopyResource(p->d3d11_context,
+ (ID3D11Resource*)staging, (ID3D11Resource*)frontbuffer);
+
+ // Attempt to map the staging texture to CPU-accessible memory
+ D3D11_MAPPED_SUBRESOURCE lock;
+ hr = ID3D11DeviceContext_Map(p->d3d11_context, (ID3D11Resource*)staging,
+ 0, D3D11_MAP_READ, 0, &lock);
+ if (FAILED(hr))
+ goto done;
+
+ img = mp_image_alloc(fmt, td.Width, td.Height);
+ if (!img)
+ return NULL;
+ for (int i = 0; i < td.Height; i++) {
+ memcpy(img->planes[0] + img->stride[0] * i,
+ (char*)lock.pData + lock.RowPitch * i, td.Width * 4);
+ }
+
+ ID3D11DeviceContext_Unmap(p->d3d11_context, (ID3D11Resource*)staging, 0);
+
+done:
+ SAFE_RELEASE(frontbuffer);
+ SAFE_RELEASE(staging);
+ return img;
+}
+
+static int angle_color_depth(struct ra_swapchain *sw)
+{
+ // Only 8-bit output is supported at the moment
+ return 8;
+}
+
+static struct mp_image *angle_screenshot(struct ra_swapchain *sw)
+{
+ struct mp_image *img = d3d11_screenshot(sw->ctx);
+ if (img)
+ return img;
+ return ra_gl_ctx_screenshot(sw);
+}
+
+static bool angle_submit_frame(struct ra_swapchain *sw,
+ const struct vo_frame *frame)
+{
+ struct priv *p = sw->ctx->priv;
+ bool ret = ra_gl_ctx_submit_frame(sw, frame);
+ if (p->d3d11_context) {
+ // DXGI Present doesn't flush the immediate context, which can make
+ // timers inaccurate, since the end queries might not be sent until the
+ // next frame. Fix this by flushing the context now.
+ ID3D11DeviceContext_Flush(p->d3d11_context);
+ }
+ return ret;
+}
+
static bool angle_init(struct ra_ctx *ctx)
{
struct priv *p = ctx->priv = talloc_zero(ctx, struct priv);
@@ -576,8 +682,12 @@ static bool angle_init(struct ra_ctx *ctx)
current_ctx = ctx;
gl->SwapInterval = angle_swap_interval;
- // ANGLE doesn't actually need to override any of the functions (yet)
- static const struct ra_swapchain_fns empty_swapchain_fns = {0};
+ // Custom swapchain impl for the D3D11 swapchain-based surface
+ static const struct ra_swapchain_fns empty_swapchain_fns = {
+ .color_depth = angle_color_depth,
+ .screenshot = angle_screenshot,
+ .submit_frame = angle_submit_frame,
+ };
struct ra_gl_ctx_params params = {
.swap_buffers = angle_swap_buffers,
.flipped = p->flipped,
@@ -612,95 +722,8 @@ static bool angle_reconfig(struct ra_ctx *ctx)
return true;
}
-static struct mp_image *d3d11_screenshot(struct ra_ctx *ctx)
-{
- struct priv *p = ctx->priv;
- ID3D11Texture2D *frontbuffer = NULL;
- ID3D11Texture2D *staging = NULL;
- struct mp_image *img = NULL;
- HRESULT hr;
-
- if (!p->dxgi_swapchain)
- goto done;
-
- // Validate the swap chain. This screenshot method will only work on DXGI
- // 1.2+ flip/sequential swap chains. It's probably not possible at all with
- // discard swap chains, since by definition, the backbuffer contents is
- // discarded on Present().
- DXGI_SWAP_CHAIN_DESC scd;
- hr = IDXGISwapChain_GetDesc(p->dxgi_swapchain, &scd);
- if (FAILED(hr))
- goto done;
- if (scd.SwapEffect != DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL)
- goto done;
-
- // Get the last buffer that was presented with Present(). This should be
- // the n-1th buffer for a swap chain of length n.
- hr = IDXGISwapChain_GetBuffer(p->dxgi_swapchain, scd.BufferCount - 1,
- &IID_ID3D11Texture2D, (void**)&frontbuffer);
- if (FAILED(hr))
- goto done;
-
- D3D11_TEXTURE2D_DESC td;
- ID3D11Texture2D_GetDesc(frontbuffer, &td);
- if (td.SampleDesc.Count > 1)
- goto done;
-
- // Validate the backbuffer format and convert to an mpv IMGFMT
- enum mp_imgfmt fmt;
- switch (td.Format) {
- case DXGI_FORMAT_B8G8R8A8_UNORM: fmt = IMGFMT_BGR0; break;
- case DXGI_FORMAT_R8G8B8A8_UNORM: fmt = IMGFMT_RGB0; break;
- default:
- goto done;
- }
-
- // Create a staging texture based on the frontbuffer with CPU access
- td.BindFlags = 0;
- td.MiscFlags = 0;
- td.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
- td.Usage = D3D11_USAGE_STAGING;
- hr = ID3D11Device_CreateTexture2D(p->d3d11_device, &td, 0, &staging);
- if (FAILED(hr))
- goto done;
-
- ID3D11DeviceContext_CopyResource(p->d3d11_context,
- (ID3D11Resource*)staging, (ID3D11Resource*)frontbuffer);
-
- // Attempt to map the staging texture to CPU-accessible memory
- D3D11_MAPPED_SUBRESOURCE lock;
- hr = ID3D11DeviceContext_Map(p->d3d11_context, (ID3D11Resource*)staging,
- 0, D3D11_MAP_READ, 0, &lock);
- if (FAILED(hr))
- goto done;
-
- img = mp_image_alloc(fmt, td.Width, td.Height);
- if (!img)
- return NULL;
- for (int i = 0; i < td.Height; i++) {
- memcpy(img->planes[0] + img->stride[0] * i,
- (char*)lock.pData + lock.RowPitch * i, td.Width * 4);
- }
-
- ID3D11DeviceContext_Unmap(p->d3d11_context, (ID3D11Resource*)staging, 0);
-
-done:
- SAFE_RELEASE(frontbuffer);
- SAFE_RELEASE(staging);
- return img;
-}
-
static int angle_control(struct ra_ctx *ctx, int *events, int request, void *arg)
{
- // Try a D3D11-specific method of taking a window screenshot
- if (request == VOCTRL_SCREENSHOT_WIN) {
- struct mp_image *img = d3d11_screenshot(ctx);
- if (img) {
- *(struct mp_image **)arg = img;
- return true;
- }
- }
-
int ret = vo_w32_control(ctx->vo, events, request, arg);
if (*events & VO_EVENT_RESIZE)
resize(ctx);