From 4b014b3a8125de22350748d97171c63041256d7b Mon Sep 17 00:00:00 2001 From: James Ross-Gowan Date: Wed, 11 Oct 2017 18:10:39 +1100 Subject: vo_gpu: move d3d11_screenshot to shared code This can be used by the ANGLE backend and ra_d3d11. --- video/out/d3d11/context.c | 9 +++++ video/out/gpu/d3d11_helpers.c | 81 +++++++++++++++++++++++++++++++++++++ video/out/gpu/d3d11_helpers.h | 4 ++ video/out/opengl/context_angle.c | 86 +++------------------------------------- 4 files changed, 100 insertions(+), 80 deletions(-) diff --git a/video/out/d3d11/context.c b/video/out/d3d11/context.c index 018fd99934..b02d2e80ce 100644 --- a/video/out/d3d11/context.c +++ b/video/out/d3d11/context.c @@ -70,6 +70,14 @@ struct priv { IDXGISwapChain *swapchain; }; +static struct mp_image *d3d11_screenshot(struct ra_swapchain *sw) +{ + struct priv *p = sw->ctx->priv; + if (!p->swapchain) + return NULL; + return mp_d3d11_screenshot(p->swapchain); +} + static struct ra_tex *get_backbuffer(struct ra_ctx *ctx) { struct priv *p = ctx->priv; @@ -169,6 +177,7 @@ static void d3d11_uninit(struct ra_ctx *ctx) static const struct ra_swapchain_fns d3d11_swapchain = { .color_depth = d3d11_color_depth, + .screenshot = d3d11_screenshot, .start_frame = d3d11_start_frame, .submit_frame = d3d11_submit_frame, .swap_buffers = d3d11_swap_buffers, diff --git a/video/out/gpu/d3d11_helpers.c b/video/out/gpu/d3d11_helpers.c index 7912a8c23a..6391ed92cd 100644 --- a/video/out/gpu/d3d11_helpers.c +++ b/video/out/gpu/d3d11_helpers.c @@ -399,3 +399,84 @@ done: SAFE_RELEASE(dxgi_dev); return success; } + +struct mp_image *mp_d3d11_screenshot(IDXGISwapChain *swapchain) +{ + ID3D11Device *dev = NULL; + ID3D11DeviceContext *ctx = NULL; + ID3D11Texture2D *frontbuffer = NULL; + ID3D11Texture2D *staging = NULL; + struct mp_image *img = NULL; + HRESULT hr; + + // 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(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(swapchain, scd.BufferCount - 1, + &IID_ID3D11Texture2D, (void**)&frontbuffer); + if (FAILED(hr)) + goto done; + + ID3D11Texture2D_GetDevice(frontbuffer, &dev); + ID3D11Device_GetImmediateContext(dev, &ctx); + + 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(dev, &td, 0, &staging); + if (FAILED(hr)) + goto done; + + ID3D11DeviceContext_CopyResource(ctx, (ID3D11Resource*)staging, + (ID3D11Resource*)frontbuffer); + + // Attempt to map the staging texture to CPU-accessible memory + D3D11_MAPPED_SUBRESOURCE lock; + hr = ID3D11DeviceContext_Map(ctx, (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(ctx, (ID3D11Resource*)staging, 0); + +done: + SAFE_RELEASE(frontbuffer); + SAFE_RELEASE(staging); + SAFE_RELEASE(ctx); + SAFE_RELEASE(dev); + return img; +} diff --git a/video/out/gpu/d3d11_helpers.h b/video/out/gpu/d3d11_helpers.h index 6d99c62a51..481c183b4d 100644 --- a/video/out/gpu/d3d11_helpers.h +++ b/video/out/gpu/d3d11_helpers.h @@ -23,6 +23,8 @@ #include #include +#include "video/mp_image.h" + #define D3D_FEATURE_LEVEL_12_0 (0xc000) #define D3D_FEATURE_LEVEL_12_1 (0xc100) @@ -76,4 +78,6 @@ bool mp_d3d11_create_swapchain(ID3D11Device *dev, struct mp_log *log, struct d3d11_swapchain_opts *opts, IDXGISwapChain **swapchain_out); +struct mp_image *mp_d3d11_screenshot(IDXGISwapChain *swapchain); + #endif diff --git a/video/out/opengl/context_angle.c b/video/out/opengl/context_angle.c index b504293db5..986a50362b 100644 --- a/video/out/opengl/context_angle.c +++ b/video/out/opengl/context_angle.c @@ -518,83 +518,6 @@ 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) { @@ -604,9 +527,12 @@ static int angle_color_depth(struct ra_swapchain *sw) static struct mp_image *angle_screenshot(struct ra_swapchain *sw) { - struct mp_image *img = d3d11_screenshot(sw->ctx); - if (img) - return img; + struct priv *p = sw->ctx->priv; + if (p->dxgi_swapchain) { + struct mp_image *img = mp_d3d11_screenshot(p->dxgi_swapchain); + if (img) + return img; + } return ra_gl_ctx_screenshot(sw); } -- cgit v1.2.3