summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Ross-Gowan <rossy@jrg.systems>2018-02-12 21:08:17 +1100
committerJames Ross-Gowan <rossy@jrg.systems>2018-02-13 21:25:15 +1100
commit1b80e124dbec1c4bb80b8ce4aaeb84ff841f9b6d (patch)
tree15afbd5e96cd783ee51bc55607d1c17da4fe76fc
parent7d2228c6738b8793bc616c9436cdc7a1cf149a79 (diff)
downloadmpv-1b80e124dbec1c4bb80b8ce4aaeb84ff841f9b6d.tar.bz2
mpv-1b80e124dbec1c4bb80b8ce4aaeb84ff841f9b6d.tar.xz
vo_gpu: d3d11: implement tex_download()
This allows the new GPU screenshot functionality introduced in 9f595f3a80ee to work with the D3D11 backend. It replaces the old window screenshot functionality, which was shared between D3D11 and ANGLE. The old code can be removed, since it's not needed by ANGLE anymore either.
-rw-r--r--video/out/d3d11/context.c7
-rw-r--r--video/out/d3d11/ra_d3d11.c57
-rw-r--r--video/out/gpu/d3d11_helpers.c81
-rw-r--r--video/out/gpu/d3d11_helpers.h2
-rw-r--r--video/out/opengl/context_angle.c12
5 files changed, 57 insertions, 102 deletions
diff --git a/video/out/d3d11/context.c b/video/out/d3d11/context.c
index af664d9988..82c7d162f7 100644
--- a/video/out/d3d11/context.c
+++ b/video/out/d3d11/context.c
@@ -70,12 +70,6 @@ struct priv {
IDXGISwapChain *swapchain;
};
-static struct mp_image *d3d11_screenshot(struct ra_swapchain *sw)
-{
- struct priv *p = sw->ctx->priv;
- return mp_d3d11_screenshot(p->swapchain);
-}
-
static struct ra_tex *get_backbuffer(struct ra_ctx *ctx)
{
struct priv *p = ctx->priv;
@@ -179,7 +173,6 @@ 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/d3d11/ra_d3d11.c b/video/out/d3d11/ra_d3d11.c
index bf2657b6f6..1d2455853b 100644
--- a/video/out/d3d11/ra_d3d11.c
+++ b/video/out/d3d11/ra_d3d11.c
@@ -78,6 +78,9 @@ struct d3d_tex {
ID3D11Texture3D *tex3d;
int array_slice;
+ // Staging texture for tex_download(), 2D only
+ ID3D11Texture2D *staging;
+
ID3D11ShaderResourceView *srv;
ID3D11RenderTargetView *rtv;
ID3D11UnorderedAccessView *uav;
@@ -359,12 +362,17 @@ static void tex_destroy(struct ra *ra, struct ra_tex *tex)
SAFE_RELEASE(tex_p->uav);
SAFE_RELEASE(tex_p->sampler);
SAFE_RELEASE(tex_p->res);
+ SAFE_RELEASE(tex_p->staging);
talloc_free(tex);
}
static struct ra_tex *tex_create(struct ra *ra,
const struct ra_tex_params *params)
{
+ // Only 2D textures may be downloaded for now
+ if (params->downloadable && params->dimensions != 2)
+ return NULL;
+
struct ra_d3d11 *p = ra->priv;
HRESULT hr;
@@ -437,6 +445,21 @@ static struct ra_tex *tex_create(struct ra *ra,
goto error;
}
tex_p->res = (ID3D11Resource *)tex_p->tex2d;
+
+ // Create a staging texture with CPU access for tex_download()
+ if (params->downloadable) {
+ desc2d.BindFlags = 0;
+ desc2d.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
+ desc2d.Usage = D3D11_USAGE_STAGING;
+
+ hr = ID3D11Device_CreateTexture2D(p->dev, &desc2d, NULL,
+ &tex_p->staging);
+ if (FAILED(hr)) {
+ MP_ERR(ra, "Failed to staging texture: %s\n",
+ mp_HRESULT_to_str(hr));
+ goto error;
+ }
+ }
break;
case 3:;
D3D11_TEXTURE3D_DESC desc3d = {
@@ -652,6 +675,39 @@ static bool tex_upload(struct ra *ra, const struct ra_tex_upload_params *params)
return true;
}
+static bool tex_download(struct ra *ra, struct ra_tex_download_params *params)
+{
+ struct ra_d3d11 *p = ra->priv;
+ struct ra_tex *tex = params->tex;
+ struct d3d_tex *tex_p = tex->priv;
+ HRESULT hr;
+
+ if (!tex_p->staging)
+ return false;
+
+ ID3D11DeviceContext_CopyResource(p->ctx, (ID3D11Resource*)tex_p->staging,
+ tex_p->res);
+
+ D3D11_MAPPED_SUBRESOURCE lock;
+ hr = ID3D11DeviceContext_Map(p->ctx, (ID3D11Resource*)tex_p->staging, 0,
+ D3D11_MAP_READ, 0, &lock);
+ if (FAILED(hr)) {
+ MP_ERR(ra, "Failed to map staging texture: %s\n", mp_HRESULT_to_str(hr));
+ return false;
+ }
+
+ char *cdst = params->dst;
+ char *csrc = lock.pData;
+ for (int y = 0; y < tex->params.h; y++) {
+ memcpy(cdst + y * params->stride, csrc + y * lock.RowPitch,
+ MPMIN(params->stride, lock.RowPitch));
+ }
+
+ ID3D11DeviceContext_Unmap(p->ctx, (ID3D11Resource*)tex_p->staging, 0);
+
+ return true;
+}
+
static void buf_destroy(struct ra *ra, struct ra_buf *buf)
{
if (!buf)
@@ -2045,6 +2101,7 @@ static struct ra_fns ra_fns_d3d11 = {
.tex_create = tex_create,
.tex_destroy = tex_destroy,
.tex_upload = tex_upload,
+ .tex_download = tex_download,
.buf_create = buf_create,
.buf_destroy = buf_destroy,
.buf_update = buf_update,
diff --git a/video/out/gpu/d3d11_helpers.c b/video/out/gpu/d3d11_helpers.c
index 7bdd3c2eaa..d267ac3009 100644
--- a/video/out/gpu/d3d11_helpers.c
+++ b/video/out/gpu/d3d11_helpers.c
@@ -374,84 +374,3 @@ 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 481c183b4d..996b93494f 100644
--- a/video/out/gpu/d3d11_helpers.h
+++ b/video/out/gpu/d3d11_helpers.h
@@ -78,6 +78,4 @@ 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 986a50362b..6d45e29496 100644
--- a/video/out/opengl/context_angle.c
+++ b/video/out/opengl/context_angle.c
@@ -525,17 +525,6 @@ static int angle_color_depth(struct ra_swapchain *sw)
return 8;
}
-static struct mp_image *angle_screenshot(struct ra_swapchain *sw)
-{
- 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);
-}
-
static bool angle_submit_frame(struct ra_swapchain *sw,
const struct vo_frame *frame)
{
@@ -611,7 +600,6 @@ static bool angle_init(struct ra_ctx *ctx)
// Custom swapchain impl for the D3D11 swapchain-based surface
static const struct ra_swapchain_fns dxgi_swapchain_fns = {
.color_depth = angle_color_depth,
- .screenshot = angle_screenshot,
.submit_frame = angle_submit_frame,
};
struct ra_gl_ctx_params params = {