summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Ross-Gowan <rossy@jrg.systems>2017-12-30 19:48:53 +1100
committerJames Ross-Gowan <rossy@jrg.systems>2018-01-01 20:31:45 +1100
commit7677c7c32c3ccf0801b63c7a23262c5b121cfbe8 (patch)
tree16d3f4a29513fbf37c9e2167a13d32b2e2789653
parent4a6bb492151358afa4c5ae22a2497490dbb73e12 (diff)
downloadmpv-7677c7c32c3ccf0801b63c7a23262c5b121cfbe8.tar.bz2
mpv-7677c7c32c3ccf0801b63c7a23262c5b121cfbe8.tar.xz
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
-rw-r--r--video/out/d3d11/ra_d3d11.c63
1 files changed, 15 insertions, 48 deletions
diff --git a/video/out/d3d11/ra_d3d11.c b/video/out/d3d11/ra_d3d11.c
index 63dc5b9509..4246a8d71e 100644
--- a/video/out/d3d11/ra_d3d11.c
+++ b/video/out/d3d11/ra_d3d11.c
@@ -86,9 +86,9 @@ struct d3d_tex {
struct d3d_buf {
ID3D11Buffer *buf;
- ID3D11Buffer *staging;
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 {
@@ -655,13 +655,8 @@ static void buf_destroy(struct ra *ra, struct ra_buf *buf)
{
if (!buf)
return;
- struct ra_d3d11 *p = ra->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->staging);
SAFE_RELEASE(buf_p->uav);
talloc_free(buf);
}
@@ -705,24 +700,13 @@ static struct ra_buf *buf_create(struct ra *ra,
goto error;
}
- if (params->host_mutable) {
- // D3D11 doesn't allow constant buffer updates that aren't aligned to a
- // full constant boundary (vec4,) and some drivers don't allow partial
- // constant buffer updates at all, but the RA consumer is allowed to
- // partially update an ra_buf. The best way to handle partial updates
- // without causing a pipeline stall is probably to keep a copy of the
- // data in a staging buffer.
-
- 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;
- }
- }
+ // D3D11 doesn't allow constant buffer updates that aren't aligned to a
+ // full constant boundary (vec4,) and some drivers don't allow partial
+ // constant buffer updates at all. To support partial buffer updates, keep
+ // a mirror of the buffer data in system memory and upload the whole thing
+ // before the buffer is used.
+ if (params->host_mutable)
+ buf_p->data = talloc_zero_size(buf, desc.ByteWidth);
if (params->type == RA_BUF_TYPE_SHADER_STORAGE) {
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 d3d_buf *buf_p = buf->priv;
- assert(buf->params.host_mutable);
- if (!buf_p->data)
+ if (!buf->params.host_mutable || !buf_p->dirty)
return;
- ID3D11DeviceContext_Unmap(p->ctx, (ID3D11Resource *)buf_p->staging, 0);
- buf_p->data = NULL;
-
- // Synchronize the GPU buffer with the staging buffer
- ID3D11DeviceContext_CopyResource(p->ctx, (ID3D11Resource *)buf_p->buf,
- (ID3D11Resource *)buf_p->staging);
+ // Synchronize the GPU buffer with the system-memory copy
+ ID3D11DeviceContext_UpdateSubresource(p->ctx, (ID3D11Resource *)buf_p->buf,
+ 0, NULL, buf_p->data, 0, 0);
+ buf_p->dirty = false;
}
static void buf_update(struct ra *ra, struct ra_buf *buf, ptrdiff_t offset,
const void *data, size_t size)
{
- struct ra_d3d11 *p = ra->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;
memcpy(cdata + offset, data, size);
+ buf_p->dirty = true;
}
static const char *get_shader_target(struct ra *ra, enum glsl_shader type)