Skip to content

Commit

Permalink
vo_gpu: d3d11: implement tex_download()
Browse files Browse the repository at this point in the history
This allows the new GPU screenshot functionality introduced in
9f595f3 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.
  • Loading branch information
rossy committed Feb 13, 2018
1 parent 7d2228c commit 1b80e12
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 102 deletions.
7 changes: 0 additions & 7 deletions video/out/d3d11/context.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down
57 changes: 57 additions & 0 deletions video/out/d3d11/ra_d3d11.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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 = {
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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,
Expand Down
81 changes: 0 additions & 81 deletions video/out/gpu/d3d11_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -374,84 +374,3 @@ bool mp_d3d11_create_swapchain(ID3D11Device *dev, struct mp_log *log,
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;
}
2 changes: 0 additions & 2 deletions video/out/gpu/d3d11_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
12 changes: 0 additions & 12 deletions video/out/opengl/context_angle.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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 = {
Expand Down

0 comments on commit 1b80e12

Please sign in to comment.