mirror of
https://github.com/mpv-player/mpv
synced 2025-03-23 11:47:45 +00:00
vo_gpu: move d3d11_screenshot to shared code
This can be used by the ANGLE backend and ra_d3d11.
This commit is contained in:
parent
9b2dae79b1
commit
4b014b3a81
video/out
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -23,6 +23,8 @@
|
||||
#include <d3d11.h>
|
||||
#include <dxgi1_2.h>
|
||||
|
||||
#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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user