1
0
mirror of https://github.com/mpv-player/mpv synced 2025-02-12 09:57:15 +00:00

vo_gpu: d3d11: avoid copying staging buffers to cbuffers

Apparently some Intel drivers have a bug where copying from staging
buffers to constant buffers does not work. We used to keep a copy of the
buffer data in a staging buffer to enable partial constant buffer
updates. To work around this bug, keep the copy in talloc-allocated
system memory instead.

There doesn't seem to be any noticable performance difference from
keeping the copy in system memory. Our cbuffers are probably too small
for it to matter anyway.

See also: https://crbug.com/593024

Fixes #5293
This commit is contained in:
James Ross-Gowan 2017-12-30 19:48:53 +11:00
parent 4a6bb49215
commit 7677c7c32c

View File

@ -86,9 +86,9 @@ struct d3d_tex {
struct d3d_buf { struct d3d_buf {
ID3D11Buffer *buf; ID3D11Buffer *buf;
ID3D11Buffer *staging;
ID3D11UnorderedAccessView *uav; ID3D11UnorderedAccessView *uav;
void *data; // Data for mapped staging texture void *data; // System-memory mirror of the data in buf
bool dirty; // Is buf out of date?
}; };
struct d3d_rpass { struct d3d_rpass {
@ -655,13 +655,8 @@ static void buf_destroy(struct ra *ra, struct ra_buf *buf)
{ {
if (!buf) if (!buf)
return; return;
struct ra_d3d11 *p = ra->priv;
struct d3d_buf *buf_p = buf->priv; struct d3d_buf *buf_p = buf->priv;
if (buf_p->data)
ID3D11DeviceContext_Unmap(p->ctx, (ID3D11Resource *)buf_p->staging, 0);
SAFE_RELEASE(buf_p->buf); SAFE_RELEASE(buf_p->buf);
SAFE_RELEASE(buf_p->staging);
SAFE_RELEASE(buf_p->uav); SAFE_RELEASE(buf_p->uav);
talloc_free(buf); talloc_free(buf);
} }
@ -705,24 +700,13 @@ static struct ra_buf *buf_create(struct ra *ra,
goto error; goto error;
} }
if (params->host_mutable) { // D3D11 doesn't allow constant buffer updates that aren't aligned to a
// D3D11 doesn't allow constant buffer updates that aren't aligned to a // full constant boundary (vec4,) and some drivers don't allow partial
// full constant boundary (vec4,) and some drivers don't allow partial // constant buffer updates at all. To support partial buffer updates, keep
// constant buffer updates at all, but the RA consumer is allowed to // a mirror of the buffer data in system memory and upload the whole thing
// partially update an ra_buf. The best way to handle partial updates // before the buffer is used.
// without causing a pipeline stall is probably to keep a copy of the if (params->host_mutable)
// data in a staging buffer. buf_p->data = talloc_zero_size(buf, desc.ByteWidth);
desc.Usage = D3D11_USAGE_STAGING;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
desc.BindFlags = 0;
hr = ID3D11Device_CreateBuffer(p->dev, &desc, NULL, &buf_p->staging);
if (FAILED(hr)) {
MP_ERR(ra, "Failed to create staging buffer: %s\n",
mp_HRESULT_to_str(hr));
goto error;
}
}
if (params->type == RA_BUF_TYPE_SHADER_STORAGE) { if (params->type == RA_BUF_TYPE_SHADER_STORAGE) {
D3D11_UNORDERED_ACCESS_VIEW_DESC udesc = { D3D11_UNORDERED_ACCESS_VIEW_DESC udesc = {
@ -752,40 +736,23 @@ static void buf_resolve(struct ra *ra, struct ra_buf *buf)
struct ra_d3d11 *p = ra->priv; struct ra_d3d11 *p = ra->priv;
struct d3d_buf *buf_p = buf->priv; struct d3d_buf *buf_p = buf->priv;
assert(buf->params.host_mutable); if (!buf->params.host_mutable || !buf_p->dirty)
if (!buf_p->data)
return; return;
ID3D11DeviceContext_Unmap(p->ctx, (ID3D11Resource *)buf_p->staging, 0); // Synchronize the GPU buffer with the system-memory copy
buf_p->data = NULL; ID3D11DeviceContext_UpdateSubresource(p->ctx, (ID3D11Resource *)buf_p->buf,
0, NULL, buf_p->data, 0, 0);
// Synchronize the GPU buffer with the staging buffer buf_p->dirty = false;
ID3D11DeviceContext_CopyResource(p->ctx, (ID3D11Resource *)buf_p->buf,
(ID3D11Resource *)buf_p->staging);
} }
static void buf_update(struct ra *ra, struct ra_buf *buf, ptrdiff_t offset, static void buf_update(struct ra *ra, struct ra_buf *buf, ptrdiff_t offset,
const void *data, size_t size) const void *data, size_t size)
{ {
struct ra_d3d11 *p = ra->priv;
struct d3d_buf *buf_p = buf->priv; struct d3d_buf *buf_p = buf->priv;
HRESULT hr;
if (!buf_p->data) {
// If this is the first update after the buffer was created or after it
// has been used in a renderpass, it will be unmapped, so map it
D3D11_MAPPED_SUBRESOURCE map = {0};
hr = ID3D11DeviceContext_Map(p->ctx, (ID3D11Resource *)buf_p->staging,
0, D3D11_MAP_WRITE, 0, &map);
if (FAILED(hr)) {
MP_ERR(ra, "Failed to map resource\n");
return;
}
buf_p->data = map.pData;
}
char *cdata = buf_p->data; char *cdata = buf_p->data;
memcpy(cdata + offset, data, size); memcpy(cdata + offset, data, size);
buf_p->dirty = true;
} }
static const char *get_shader_target(struct ra *ra, enum glsl_shader type) static const char *get_shader_target(struct ra *ra, enum glsl_shader type)