d3d12: Add a path for mapping of not-directly-mappable buffers

Currently all buffers are allocated as mappable, but a future
commit will change that so that some buffers can be allocated
directly in non-CPU-accessible memory for improved performance.

Note that the returned pointer must be appropriately offset from
a 64-byte-aligned base pointer, so if offsets are used, the data
will be read/written to an offset region in the staging buffer.

Reviewed-by: Louis-Francis Ratté-Boulianne <lfrb@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/8095>
This commit is contained in:
Jesse Natalie 2020-12-14 11:42:49 -08:00 committed by Marge Bot
parent 4d83306a9a
commit 47125bce8b

View file

@ -567,6 +567,36 @@ transfer_image_to_buf(struct d3d12_context *ctx,
return true;
}
static void
transfer_buf_to_buf(struct d3d12_context *ctx,
struct d3d12_resource *src,
struct d3d12_resource *dst,
uint64_t src_offset,
uint64_t dst_offset,
uint64_t width)
{
auto batch = d3d12_current_batch(ctx);
d3d12_batch_reference_resource(batch, src);
d3d12_batch_reference_resource(batch, dst);
uint64_t src_offset_suballoc = 0;
uint64_t dst_offset_suballoc = 0;
auto src_d3d12 = d3d12_resource_underlying(src, &src_offset_suballoc);
auto dst_d3d12 = d3d12_resource_underlying(dst, &dst_offset_suballoc);
src_offset += src_offset_suballoc;
dst_offset += dst_offset_suballoc;
// Same-resource copies not supported, since the resource would need to be in both states
assert(src_d3d12 != dst_d3d12);
d3d12_transition_resource_state(ctx, src, D3D12_RESOURCE_STATE_COPY_SOURCE);
d3d12_transition_resource_state(ctx, dst, D3D12_RESOURCE_STATE_COPY_DEST);
d3d12_apply_resource_states(ctx);
ctx->cmdlist->CopyBufferRegion(dst_d3d12, dst_offset,
src_d3d12, src_offset,
width);
}
static unsigned
linear_offset(int x, int y, int z, unsigned stride, unsigned layer_stride)
{
@ -846,6 +876,8 @@ write_zs_surface(struct pipe_context *pctx, struct d3d12_resource *res,
transfer_buf_to_image(d3d12_context(pctx), res, stencil_buffer, trans, 1);
}
#define BUFFER_MAP_ALIGNMENT 64
static void *
d3d12_transfer_map(struct pipe_context *pctx,
struct pipe_resource *pres,
@ -912,23 +944,40 @@ d3d12_transfer_map(struct pipe_context *pctx,
ptrans->layer_stride = align(ptrans->layer_stride,
D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
unsigned staging_res_size = ptrans->layer_stride * box->depth;
if (res->base.target == PIPE_BUFFER) {
/* To properly support ARB_map_buffer_alignment, we need to return a pointer
* that's appropriately offset from a 64-byte-aligned base address.
*/
assert(box->x >= 0);
unsigned aligned_x = (unsigned)box->x % BUFFER_MAP_ALIGNMENT;
staging_res_size = align(box->width + aligned_x,
D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
range.Begin = aligned_x;
}
trans->staging_res = pipe_buffer_create(pctx->screen, 0,
PIPE_USAGE_STAGING,
ptrans->layer_stride * box->depth);
staging_res_size);
if (!trans->staging_res)
return NULL;
struct d3d12_resource *staging_res = d3d12_resource(trans->staging_res);
if (usage & PIPE_MAP_READ) {
bool ret = transfer_image_to_buf(ctx, res, staging_res, trans, 0);
if (ret == false)
bool ret = true;
if (pres->target == PIPE_BUFFER) {
uint64_t src_offset = box->x;
uint64_t dst_offset = src_offset % BUFFER_MAP_ALIGNMENT;
transfer_buf_to_buf(ctx, res, staging_res, src_offset, dst_offset, box->width);
} else
ret = transfer_image_to_buf(ctx, res, staging_res, trans, 0);
if (!ret)
return NULL;
d3d12_flush_cmdlist_and_wait(ctx);
}
range.Begin = 0;
range.End = ptrans->layer_stride * box->depth;
range.End = staging_res_size - range.Begin;
ptr = d3d12_bo_map(staging_res->bo, &range);
}
@ -953,14 +1002,21 @@ d3d12_transfer_unmap(struct pipe_context *pctx,
struct d3d12_resource *staging_res = d3d12_resource(trans->staging_res);
if (trans->base.usage & PIPE_MAP_WRITE) {
range.Begin = 0;
range.End = ptrans->layer_stride * ptrans->box.depth;
assert(ptrans->box.x >= 0);
range.Begin = res->base.target == PIPE_BUFFER ?
(unsigned)ptrans->box.x % BUFFER_MAP_ALIGNMENT : 0;
range.End = staging_res->base.width0 - range.Begin;
}
d3d12_bo_unmap(staging_res->bo, &range);
if (trans->base.usage & PIPE_MAP_WRITE) {
struct d3d12_context *ctx = d3d12_context(pctx);
transfer_buf_to_image(ctx, res, staging_res, trans, 0);
if (res->base.target == PIPE_BUFFER) {
uint64_t dst_offset = trans->base.box.x;
uint64_t src_offset = dst_offset % BUFFER_MAP_ALIGNMENT;
transfer_buf_to_buf(ctx, staging_res, res, src_offset, dst_offset, ptrans->box.width);
} else
transfer_buf_to_image(ctx, res, staging_res, trans, 0);
}
pipe_resource_reference(&trans->staging_res, NULL);