2019-05-26 09:43:12 +01:00
|
|
|
|
/*
|
|
|
|
|
* Copyright © Microsoft Corporation
|
|
|
|
|
*
|
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
|
|
|
* to deal in the Software without restriction, including without limitation
|
|
|
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
|
|
|
*
|
|
|
|
|
* The above copyright notice and this permission notice (including the next
|
|
|
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
|
|
|
* Software.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
|
|
|
* IN THE SOFTWARE.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "d3d12_resource.h"
|
|
|
|
|
|
|
|
|
|
#include "d3d12_blit.h"
|
|
|
|
|
#include "d3d12_context.h"
|
|
|
|
|
#include "d3d12_format.h"
|
|
|
|
|
#include "d3d12_screen.h"
|
|
|
|
|
#include "d3d12_debug.h"
|
|
|
|
|
|
|
|
|
|
#include "pipebuffer/pb_bufmgr.h"
|
|
|
|
|
#include "util/slab.h"
|
|
|
|
|
#include "util/format/u_format.h"
|
|
|
|
|
#include "util/u_inlines.h"
|
|
|
|
|
#include "util/u_memory.h"
|
|
|
|
|
#include "util/format/u_format_zs.h"
|
|
|
|
|
|
|
|
|
|
#include "frontend/sw_winsys.h"
|
|
|
|
|
|
2020-12-08 18:02:35 +00:00
|
|
|
|
#include <dxguids/dxguids.h>
|
2019-05-26 09:43:12 +01:00
|
|
|
|
#include <memory>
|
|
|
|
|
|
2021-08-08 03:18:19 +01:00
|
|
|
|
#ifndef GENERIC_ALL
|
|
|
|
|
// This is only added to winadapter.h in newer DirectX-Headers
|
|
|
|
|
#define GENERIC_ALL 0x10000000L
|
|
|
|
|
#endif
|
|
|
|
|
|
2019-05-26 09:43:12 +01:00
|
|
|
|
static bool
|
|
|
|
|
can_map_directly(struct pipe_resource *pres)
|
|
|
|
|
{
|
2020-12-14 19:59:53 +00:00
|
|
|
|
return pres->target == PIPE_BUFFER &&
|
2020-12-14 19:53:13 +00:00
|
|
|
|
pres->usage != PIPE_USAGE_DEFAULT &&
|
2020-12-14 19:59:53 +00:00
|
|
|
|
pres->usage != PIPE_USAGE_IMMUTABLE;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
init_valid_range(struct d3d12_resource *res)
|
|
|
|
|
{
|
2021-11-03 17:23:14 +00:00
|
|
|
|
if (can_map_directly(&res->base.b))
|
2019-05-26 09:43:12 +01:00
|
|
|
|
util_range_init(&res->valid_buffer_range);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
d3d12_resource_destroy(struct pipe_screen *pscreen,
|
|
|
|
|
struct pipe_resource *presource)
|
|
|
|
|
{
|
|
|
|
|
struct d3d12_resource *resource = d3d12_resource(presource);
|
2021-11-03 17:23:14 +00:00
|
|
|
|
threaded_resource_deinit(presource);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
if (can_map_directly(presource))
|
|
|
|
|
util_range_destroy(&resource->valid_buffer_range);
|
|
|
|
|
if (resource->bo)
|
|
|
|
|
d3d12_bo_unreference(resource->bo);
|
|
|
|
|
FREE(resource);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
resource_is_busy(struct d3d12_context *ctx,
|
2021-11-04 00:05:05 +00:00
|
|
|
|
struct d3d12_resource *res,
|
|
|
|
|
bool want_to_write)
|
2019-05-26 09:43:12 +01:00
|
|
|
|
{
|
2022-02-10 19:08:16 +00:00
|
|
|
|
if (d3d12_batch_has_references(d3d12_current_batch(ctx), res->bo, want_to_write))
|
|
|
|
|
return true;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
2022-02-10 19:08:16 +00:00
|
|
|
|
bool busy = false;
|
|
|
|
|
d3d12_foreach_submitted_batch(ctx, batch) {
|
|
|
|
|
if (!d3d12_reset_batch(ctx, batch, 0))
|
|
|
|
|
busy |= d3d12_batch_has_references(batch, res->bo, want_to_write);
|
|
|
|
|
}
|
2019-05-26 09:43:12 +01:00
|
|
|
|
return busy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
d3d12_resource_wait_idle(struct d3d12_context *ctx,
|
2021-11-04 00:05:05 +00:00
|
|
|
|
struct d3d12_resource *res,
|
|
|
|
|
bool want_to_write)
|
2019-05-26 09:43:12 +01:00
|
|
|
|
{
|
2021-11-04 00:05:05 +00:00
|
|
|
|
if (d3d12_batch_has_references(d3d12_current_batch(ctx), res->bo, want_to_write)) {
|
2019-05-26 09:43:12 +01:00
|
|
|
|
d3d12_flush_cmdlist_and_wait(ctx);
|
|
|
|
|
} else {
|
|
|
|
|
d3d12_foreach_submitted_batch(ctx, batch) {
|
2022-02-10 19:08:16 +00:00
|
|
|
|
if (d3d12_batch_has_references(batch, res->bo, want_to_write))
|
2021-11-03 22:25:18 +00:00
|
|
|
|
d3d12_reset_batch(ctx, batch, PIPE_TIMEOUT_INFINITE);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
d3d12_resource_release(struct d3d12_resource *resource)
|
|
|
|
|
{
|
|
|
|
|
if (!resource->bo)
|
|
|
|
|
return;
|
|
|
|
|
d3d12_bo_unreference(resource->bo);
|
|
|
|
|
resource->bo = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
init_buffer(struct d3d12_screen *screen,
|
|
|
|
|
struct d3d12_resource *res,
|
|
|
|
|
const struct pipe_resource *templ)
|
|
|
|
|
{
|
|
|
|
|
struct pb_desc buf_desc;
|
|
|
|
|
struct pb_manager *bufmgr;
|
|
|
|
|
struct pb_buffer *buf;
|
|
|
|
|
|
|
|
|
|
/* Assert that we don't want to create a buffer with one of the emulated
|
|
|
|
|
* formats, these are (currently) only supported when passing the vertex
|
|
|
|
|
* element state */
|
|
|
|
|
assert(templ->format == d3d12_emulated_vtx_format(templ->format));
|
|
|
|
|
|
2020-12-14 19:53:13 +00:00
|
|
|
|
switch (templ->usage) {
|
|
|
|
|
case PIPE_USAGE_DEFAULT:
|
|
|
|
|
case PIPE_USAGE_IMMUTABLE:
|
|
|
|
|
bufmgr = screen->cache_bufmgr;
|
|
|
|
|
buf_desc.usage = (pb_usage_flags)PB_USAGE_GPU_READ_WRITE;
|
|
|
|
|
break;
|
|
|
|
|
case PIPE_USAGE_DYNAMIC:
|
|
|
|
|
case PIPE_USAGE_STREAM:
|
|
|
|
|
bufmgr = screen->slab_bufmgr;
|
|
|
|
|
buf_desc.usage = (pb_usage_flags)(PB_USAGE_CPU_WRITE | PB_USAGE_GPU_READ);
|
|
|
|
|
break;
|
|
|
|
|
case PIPE_USAGE_STAGING:
|
|
|
|
|
bufmgr = screen->readback_slab_bufmgr;
|
|
|
|
|
buf_desc.usage = (pb_usage_flags)(PB_USAGE_GPU_WRITE | PB_USAGE_CPU_READ_WRITE);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
unreachable("Invalid pipe usage");
|
|
|
|
|
}
|
2022-02-08 15:26:10 +00:00
|
|
|
|
|
|
|
|
|
/* We can't suballocate buffers that might be bound as a sampler view, *only*
|
|
|
|
|
* because in the case of R32G32B32 formats (12 bytes per pixel), it's not possible
|
|
|
|
|
* to guarantee the offset will be divisible.
|
|
|
|
|
*/
|
|
|
|
|
if (templ->bind & PIPE_BIND_SAMPLER_VIEW)
|
|
|
|
|
bufmgr = screen->cache_bufmgr;
|
|
|
|
|
|
2022-02-07 22:13:20 +00:00
|
|
|
|
buf_desc.alignment = D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
res->dxgi_format = DXGI_FORMAT_UNKNOWN;
|
|
|
|
|
buf = bufmgr->create_buffer(bufmgr, templ->width0, &buf_desc);
|
|
|
|
|
if (!buf)
|
|
|
|
|
return false;
|
2022-07-19 22:47:47 +01:00
|
|
|
|
res->bo = d3d12_bo_wrap_buffer(screen, buf);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
init_texture(struct d3d12_screen *screen,
|
|
|
|
|
struct d3d12_resource *res,
|
2022-07-10 02:53:53 +01:00
|
|
|
|
const struct pipe_resource *templ,
|
|
|
|
|
ID3D12Heap *heap,
|
|
|
|
|
uint64_t placed_offset)
|
2019-05-26 09:43:12 +01:00
|
|
|
|
{
|
|
|
|
|
ID3D12Resource *d3d12_res;
|
|
|
|
|
|
|
|
|
|
res->mip_levels = templ->last_level + 1;
|
|
|
|
|
res->dxgi_format = d3d12_get_format(templ->format);
|
|
|
|
|
|
|
|
|
|
D3D12_RESOURCE_DESC desc;
|
|
|
|
|
desc.Format = res->dxgi_format;
|
|
|
|
|
desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
|
|
|
|
|
desc.Width = templ->width0;
|
|
|
|
|
desc.Height = templ->height0;
|
|
|
|
|
desc.DepthOrArraySize = templ->array_size;
|
|
|
|
|
desc.MipLevels = templ->last_level + 1;
|
|
|
|
|
|
|
|
|
|
desc.SampleDesc.Count = MAX2(templ->nr_samples, 1);
|
2022-07-10 02:53:53 +01:00
|
|
|
|
desc.SampleDesc.Quality = 0;
|
|
|
|
|
|
|
|
|
|
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
|
|
|
|
desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
|
|
|
|
switch (templ->target) {
|
2022-07-10 02:53:53 +01:00
|
|
|
|
case PIPE_BUFFER:
|
|
|
|
|
desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
|
|
|
|
desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
|
|
|
|
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
|
|
|
|
break;
|
|
|
|
|
|
2019-05-26 09:43:12 +01:00
|
|
|
|
case PIPE_TEXTURE_1D:
|
|
|
|
|
case PIPE_TEXTURE_1D_ARRAY:
|
|
|
|
|
desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE1D;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PIPE_TEXTURE_CUBE:
|
|
|
|
|
case PIPE_TEXTURE_CUBE_ARRAY:
|
|
|
|
|
desc.DepthOrArraySize *= 6;
|
2021-04-10 16:11:58 +01:00
|
|
|
|
FALLTHROUGH;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
case PIPE_TEXTURE_2D:
|
|
|
|
|
case PIPE_TEXTURE_2D_ARRAY:
|
|
|
|
|
case PIPE_TEXTURE_RECT:
|
|
|
|
|
desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PIPE_TEXTURE_3D:
|
|
|
|
|
desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE3D;
|
|
|
|
|
desc.DepthOrArraySize = templ->depth0;
|
|
|
|
|
break;
|
2020-11-26 01:10:39 +00:00
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
unreachable("Invalid texture type");
|
2019-05-26 09:43:12 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (templ->bind & PIPE_BIND_SHADER_BUFFER)
|
|
|
|
|
desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
|
|
|
|
|
|
|
|
|
if (templ->bind & PIPE_BIND_RENDER_TARGET)
|
|
|
|
|
desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
|
|
|
|
|
|
|
|
|
|
if (templ->bind & PIPE_BIND_DEPTH_STENCIL) {
|
|
|
|
|
desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
|
|
|
|
|
|
|
|
|
|
/* Sadly, we can't set D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE in the
|
|
|
|
|
* case where PIPE_BIND_SAMPLER_VIEW isn't set, because that would
|
|
|
|
|
* prevent us from using the resource with u_blitter, which requires
|
|
|
|
|
* sneaking in sampler-usage throught the back-door.
|
|
|
|
|
*/
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-29 00:29:41 +00:00
|
|
|
|
if (screen->support_shader_images && templ->nr_samples <= 1) {
|
|
|
|
|
/* Ideally, we'd key off of PIPE_BIND_SHADER_IMAGE for this, but it doesn't
|
|
|
|
|
* seem to be set properly. So, all UAV-capable resources need the UAV flag.
|
|
|
|
|
*/
|
|
|
|
|
D3D12_FEATURE_DATA_FORMAT_SUPPORT support = { desc.Format };
|
|
|
|
|
if (SUCCEEDED(screen->dev->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &support, sizeof(support))) &&
|
|
|
|
|
(support.Support2 & (D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD | D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE)) ==
|
|
|
|
|
(D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD | D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE)) {
|
|
|
|
|
desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
2021-12-31 01:54:05 +00:00
|
|
|
|
desc.Format = d3d12_get_typeless_format(templ->format);
|
2021-12-29 00:29:41 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-10 02:50:01 +01:00
|
|
|
|
if (templ->bind & (PIPE_BIND_SCANOUT | PIPE_BIND_LINEAR))
|
2019-05-26 09:43:12 +01:00
|
|
|
|
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
|
|
|
|
|
2022-07-10 02:53:53 +01:00
|
|
|
|
HRESULT hres = E_FAIL;
|
|
|
|
|
enum d3d12_residency_status init_residency;
|
|
|
|
|
|
|
|
|
|
if (heap) {
|
|
|
|
|
init_residency = d3d12_permanently_resident;
|
|
|
|
|
hres = screen->dev->CreatePlacedResource(heap,
|
|
|
|
|
placed_offset,
|
|
|
|
|
&desc,
|
|
|
|
|
D3D12_RESOURCE_STATE_COMMON,
|
|
|
|
|
nullptr,
|
|
|
|
|
IID_PPV_ARGS(&d3d12_res));
|
|
|
|
|
} else {
|
2022-07-14 22:54:18 +01:00
|
|
|
|
D3D12_HEAP_PROPERTIES heap_pris = GetCustomHeapProperties(screen->dev, D3D12_HEAP_TYPE_DEFAULT);
|
2022-07-10 02:53:53 +01:00
|
|
|
|
|
|
|
|
|
D3D12_HEAP_FLAGS heap_flags = screen->support_create_not_resident ?
|
|
|
|
|
D3D12_HEAP_FLAG_CREATE_NOT_RESIDENT : D3D12_HEAP_FLAG_NONE;
|
|
|
|
|
init_residency = screen->support_create_not_resident ? d3d12_evicted : d3d12_resident;
|
|
|
|
|
|
|
|
|
|
hres = screen->dev->CreateCommittedResource(&heap_pris,
|
|
|
|
|
heap_flags,
|
|
|
|
|
&desc,
|
|
|
|
|
D3D12_RESOURCE_STATE_COMMON,
|
|
|
|
|
NULL,
|
|
|
|
|
IID_PPV_ARGS(&d3d12_res));
|
|
|
|
|
}
|
2022-02-09 20:12:18 +00:00
|
|
|
|
|
2019-05-26 09:43:12 +01:00
|
|
|
|
if (FAILED(hres))
|
|
|
|
|
return false;
|
|
|
|
|
|
2020-12-14 19:59:53 +00:00
|
|
|
|
if (screen->winsys && (templ->bind & PIPE_BIND_DISPLAY_TARGET)) {
|
2019-05-26 09:43:12 +01:00
|
|
|
|
struct sw_winsys *winsys = screen->winsys;
|
|
|
|
|
res->dt = winsys->displaytarget_create(screen->winsys,
|
2021-11-03 17:23:14 +00:00
|
|
|
|
res->base.b.bind,
|
|
|
|
|
res->base.b.format,
|
2019-05-26 09:43:12 +01:00
|
|
|
|
templ->width0,
|
|
|
|
|
templ->height0,
|
|
|
|
|
64, NULL,
|
|
|
|
|
&res->dt_stride);
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-20 15:00:36 +01:00
|
|
|
|
res->bo = d3d12_bo_wrap_res(screen, d3d12_res, init_residency);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-23 16:37:59 +01:00
|
|
|
|
static void
|
|
|
|
|
convert_planar_resource(struct d3d12_resource *res)
|
|
|
|
|
{
|
|
|
|
|
unsigned num_planes = util_format_get_num_planes(res->base.b.format);
|
|
|
|
|
if (num_planes <= 1 || res->base.b.next || !res->bo)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
struct pipe_resource *next = nullptr;
|
|
|
|
|
struct pipe_resource *planes[3] = {
|
|
|
|
|
&res->base.b, nullptr, nullptr
|
|
|
|
|
};
|
|
|
|
|
for (int plane = num_planes - 1; plane >= 0; --plane) {
|
|
|
|
|
struct d3d12_resource *plane_res = d3d12_resource(planes[plane]);
|
|
|
|
|
if (!plane_res) {
|
|
|
|
|
plane_res = CALLOC_STRUCT(d3d12_resource);
|
|
|
|
|
*plane_res = *res;
|
|
|
|
|
d3d12_bo_reference(plane_res->bo);
|
|
|
|
|
pipe_reference_init(&plane_res->base.b.reference, 1);
|
2022-02-18 09:28:58 +00:00
|
|
|
|
threaded_resource_init(&plane_res->base.b, false);
|
2021-09-23 16:37:59 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
plane_res->base.b.next = next;
|
|
|
|
|
next = &plane_res->base.b;
|
|
|
|
|
|
2022-05-02 18:14:29 +01:00
|
|
|
|
plane_res->plane_slice = plane;
|
2021-09-23 16:37:59 +01:00
|
|
|
|
plane_res->base.b.format = util_format_get_plane_format(res->base.b.format, plane);
|
|
|
|
|
plane_res->base.b.width0 = util_format_get_plane_width(res->base.b.format, plane, res->base.b.width0);
|
|
|
|
|
plane_res->base.b.height0 = util_format_get_plane_height(res->base.b.format, plane, res->base.b.height0);
|
|
|
|
|
|
|
|
|
|
#if DEBUG
|
|
|
|
|
struct d3d12_screen *screen = d3d12_screen(res->base.b.screen);
|
2022-07-14 22:54:18 +01:00
|
|
|
|
D3D12_RESOURCE_DESC desc = GetDesc(res->bo->res);
|
2021-09-23 16:37:59 +01:00
|
|
|
|
D3D12_PLACED_SUBRESOURCE_FOOTPRINT placed_footprint = {};
|
|
|
|
|
D3D12_SUBRESOURCE_FOOTPRINT *footprint = &placed_footprint.Footprint;
|
|
|
|
|
unsigned subresource = plane * desc.MipLevels * desc.DepthOrArraySize;
|
|
|
|
|
screen->dev->GetCopyableFootprints(&desc, subresource, 1, 0, &placed_footprint, nullptr, nullptr, nullptr);
|
|
|
|
|
assert(plane_res->base.b.width0 == footprint->Width);
|
|
|
|
|
assert(plane_res->base.b.height0 == footprint->Height);
|
|
|
|
|
assert(plane_res->base.b.depth0 == footprint->Depth);
|
2022-05-02 18:14:29 +01:00
|
|
|
|
assert(plane_res->first_plane == &res->base.b);
|
2021-09-23 16:37:59 +01:00
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-26 09:43:12 +01:00
|
|
|
|
static struct pipe_resource *
|
2022-07-10 02:53:53 +01:00
|
|
|
|
d3d12_resource_create_or_place(struct d3d12_screen *screen,
|
|
|
|
|
struct d3d12_resource *res,
|
|
|
|
|
const struct pipe_resource *templ,
|
|
|
|
|
ID3D12Heap *heap,
|
|
|
|
|
uint64_t placed_offset)
|
2019-05-26 09:43:12 +01:00
|
|
|
|
{
|
|
|
|
|
bool ret;
|
|
|
|
|
|
2021-11-03 17:23:14 +00:00
|
|
|
|
res->base.b = *templ;
|
2022-07-10 02:53:53 +01:00
|
|
|
|
|
2021-09-23 15:42:04 +01:00
|
|
|
|
res->overall_format = templ->format;
|
2022-05-02 18:14:29 +01:00
|
|
|
|
res->plane_slice = 0;
|
|
|
|
|
res->first_plane = &res->base.b;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
|
|
|
|
if (D3D12_DEBUG_RESOURCE & d3d12_debug) {
|
|
|
|
|
debug_printf("D3D12: Create %sresource %s@%d %dx%dx%d as:%d mip:%d\n",
|
|
|
|
|
templ->usage == PIPE_USAGE_STAGING ? "STAGING " :"",
|
|
|
|
|
util_format_name(templ->format), templ->nr_samples,
|
|
|
|
|
templ->width0, templ->height0, templ->depth0,
|
2020-11-26 00:49:43 +00:00
|
|
|
|
templ->array_size, templ->last_level);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
}
|
|
|
|
|
|
2021-11-03 17:23:14 +00:00
|
|
|
|
pipe_reference_init(&res->base.b.reference, 1);
|
2022-07-10 02:53:53 +01:00
|
|
|
|
res->base.b.screen = &screen->base;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
2022-07-10 02:53:53 +01:00
|
|
|
|
if (templ->target == PIPE_BUFFER && !heap) {
|
2019-05-26 09:43:12 +01:00
|
|
|
|
ret = init_buffer(screen, res, templ);
|
|
|
|
|
} else {
|
2022-07-10 02:53:53 +01:00
|
|
|
|
ret = init_texture(screen, res, templ, heap, placed_offset);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ret) {
|
|
|
|
|
FREE(res);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
init_valid_range(res);
|
2022-02-07 22:07:02 +00:00
|
|
|
|
threaded_resource_init(&res->base.b,
|
|
|
|
|
templ->usage == PIPE_USAGE_DEFAULT &&
|
2022-02-18 09:28:58 +00:00
|
|
|
|
templ->target == PIPE_BUFFER);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
d3d12: Fixes stale context bindings after copy, resolve, and clear
Some GL applications, including Blender, are producing rendering
artifacts due to missing resource state barriers.
The d3d12_context keeps track of all resources bound as shader resource
or constant buffers. If any of these resources are used for Copy,
Resolve, or Clear source/target, the context tracking must be updated
so the correct state can be restored before the next draw call.
This change is something of a big hammer. Essentially, if a resource
currently bound as an SRV or CBV gets used for a non-shader access, a
flag is set in the context that invalidates all bindings of the same
type on the same shader stage. Thus the next Draw execution refreshes
the shader views and state transitions state before invoking Draw on the
command list.
A more elegant (and complex) fix would limit the invalidation to
resource state only, rather than also forcing a recreation of resource
views. It is unclear right now whether it is worth the time to
implement a more elegant fix.
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/10871>
2021-05-18 18:56:31 +01:00
|
|
|
|
memset(&res->bind_counts, 0, sizeof(d3d12_resource::bind_counts));
|
|
|
|
|
|
2021-09-23 16:37:59 +01:00
|
|
|
|
convert_planar_resource(res);
|
|
|
|
|
|
2021-11-03 17:23:14 +00:00
|
|
|
|
return &res->base.b;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
}
|
|
|
|
|
|
2022-07-10 02:53:53 +01:00
|
|
|
|
static struct pipe_resource *
|
|
|
|
|
d3d12_resource_create(struct pipe_screen *pscreen,
|
|
|
|
|
const struct pipe_resource *templ)
|
|
|
|
|
{
|
|
|
|
|
struct d3d12_resource *res = CALLOC_STRUCT(d3d12_resource);
|
|
|
|
|
if (!res)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
return d3d12_resource_create_or_place(d3d12_screen(pscreen), res, templ, nullptr, 0);
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-26 09:43:12 +01:00
|
|
|
|
static struct pipe_resource *
|
|
|
|
|
d3d12_resource_from_handle(struct pipe_screen *pscreen,
|
|
|
|
|
const struct pipe_resource *templ,
|
|
|
|
|
struct winsys_handle *handle, unsigned usage)
|
|
|
|
|
{
|
2021-09-23 15:42:04 +01:00
|
|
|
|
struct d3d12_screen *screen = d3d12_screen(pscreen);
|
2021-08-08 03:18:19 +01:00
|
|
|
|
if (handle->type != WINSYS_HANDLE_TYPE_D3D12_RES &&
|
2022-07-10 03:27:03 +01:00
|
|
|
|
handle->type != WINSYS_HANDLE_TYPE_FD &&
|
|
|
|
|
handle->type != WINSYS_HANDLE_TYPE_WIN32_NAME)
|
2020-04-08 13:44:59 +01:00
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
struct d3d12_resource *res = CALLOC_STRUCT(d3d12_resource);
|
|
|
|
|
if (!res)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2021-09-23 15:42:04 +01:00
|
|
|
|
if (templ && templ->next) {
|
|
|
|
|
struct d3d12_resource* next = d3d12_resource(templ->next);
|
|
|
|
|
if (next->bo) {
|
|
|
|
|
res->base.b = *templ;
|
|
|
|
|
res->bo = next->bo;
|
|
|
|
|
d3d12_bo_reference(res->bo);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-10 03:27:03 +01:00
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
HANDLE d3d_handle = handle->handle;
|
|
|
|
|
#else
|
|
|
|
|
HANDLE d3d_handle = (HANDLE) (intptr_t) handle->handle;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
HANDLE d3d_handle_to_close = nullptr;
|
|
|
|
|
if (handle->type == WINSYS_HANDLE_TYPE_WIN32_NAME) {
|
|
|
|
|
screen->dev->OpenSharedHandleByName((LPCWSTR)handle->name, GENERIC_ALL, &d3d_handle_to_close);
|
|
|
|
|
d3d_handle = d3d_handle_to_close;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2021-09-22 22:47:50 +01:00
|
|
|
|
ID3D12Resource *d3d12_res = nullptr;
|
2022-07-10 02:53:53 +01:00
|
|
|
|
ID3D12Heap *d3d12_heap = nullptr;
|
2021-09-23 15:42:04 +01:00
|
|
|
|
if (res->bo) {
|
|
|
|
|
d3d12_res = res->bo->res;
|
|
|
|
|
} else if (handle->type == WINSYS_HANDLE_TYPE_D3D12_RES) {
|
2022-07-10 02:53:53 +01:00
|
|
|
|
IUnknown *obj = (IUnknown *)handle->com_obj;
|
|
|
|
|
(void)obj->QueryInterface(&d3d12_res);
|
|
|
|
|
(void)obj->QueryInterface(&d3d12_heap);
|
|
|
|
|
obj->Release();
|
2021-08-08 03:18:19 +01:00
|
|
|
|
} else {
|
2022-07-10 03:27:03 +01:00
|
|
|
|
screen->dev->OpenSharedHandle(d3d_handle, IID_PPV_ARGS(&d3d12_res));
|
|
|
|
|
}
|
2021-08-08 03:18:19 +01:00
|
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
2022-07-10 03:27:03 +01:00
|
|
|
|
if (d3d_handle_to_close) {
|
|
|
|
|
CloseHandle(d3d_handle_to_close);
|
2021-09-22 22:47:50 +01:00
|
|
|
|
}
|
2022-07-10 03:27:03 +01:00
|
|
|
|
#endif
|
2021-09-22 22:47:50 +01:00
|
|
|
|
|
2021-09-23 15:42:04 +01:00
|
|
|
|
D3D12_PLACED_SUBRESOURCE_FOOTPRINT placed_footprint = {};
|
|
|
|
|
D3D12_SUBRESOURCE_FOOTPRINT *footprint = &placed_footprint.Footprint;
|
2021-09-22 22:47:50 +01:00
|
|
|
|
D3D12_RESOURCE_DESC incoming_res_desc;
|
|
|
|
|
|
2022-07-10 02:53:53 +01:00
|
|
|
|
if (!d3d12_res && !d3d12_heap)
|
2021-09-22 22:47:50 +01:00
|
|
|
|
goto invalid;
|
|
|
|
|
|
2022-07-10 02:53:53 +01:00
|
|
|
|
if (d3d12_heap) {
|
|
|
|
|
assert(templ);
|
|
|
|
|
assert(!res->bo);
|
|
|
|
|
assert(!d3d12_res);
|
|
|
|
|
return d3d12_resource_create_or_place(screen, res, templ, d3d12_heap, handle->offset);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pipe_reference_init(&res->base.b.reference, 1);
|
|
|
|
|
res->base.b.screen = pscreen;
|
2022-07-14 22:54:18 +01:00
|
|
|
|
incoming_res_desc = GetDesc(d3d12_res);
|
2021-09-23 15:42:04 +01:00
|
|
|
|
|
|
|
|
|
/* Get a description for this plane */
|
2021-09-23 16:37:59 +01:00
|
|
|
|
if (templ && handle->format != templ->format) {
|
2021-09-23 15:42:04 +01:00
|
|
|
|
unsigned subresource = handle->plane * incoming_res_desc.MipLevels * incoming_res_desc.DepthOrArraySize;
|
|
|
|
|
screen->dev->GetCopyableFootprints(&incoming_res_desc, subresource, 1, 0, &placed_footprint, nullptr, nullptr, nullptr);
|
2021-09-23 16:37:59 +01:00
|
|
|
|
} else {
|
|
|
|
|
footprint->Format = incoming_res_desc.Format;
|
|
|
|
|
footprint->Width = incoming_res_desc.Width;
|
|
|
|
|
footprint->Height = incoming_res_desc.Height;
|
|
|
|
|
footprint->Depth = incoming_res_desc.DepthOrArraySize;
|
2021-09-23 15:42:04 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (footprint->Width > UINT32_MAX ||
|
|
|
|
|
footprint->Height > UINT16_MAX) {
|
2021-09-22 22:47:50 +01:00
|
|
|
|
debug_printf("d3d12: Importing resource too large\n");
|
|
|
|
|
goto invalid;
|
|
|
|
|
}
|
|
|
|
|
res->base.b.width0 = incoming_res_desc.Width;
|
|
|
|
|
res->base.b.height0 = incoming_res_desc.Height;
|
|
|
|
|
res->base.b.depth0 = 1;
|
|
|
|
|
res->base.b.array_size = 1;
|
|
|
|
|
|
|
|
|
|
switch (incoming_res_desc.Dimension) {
|
|
|
|
|
case D3D12_RESOURCE_DIMENSION_BUFFER:
|
|
|
|
|
res->base.b.target = PIPE_BUFFER;
|
|
|
|
|
res->base.b.bind = PIPE_BIND_VERTEX_BUFFER | PIPE_BIND_CONSTANT_BUFFER |
|
|
|
|
|
PIPE_BIND_INDEX_BUFFER | PIPE_BIND_STREAM_OUTPUT | PIPE_BIND_SHADER_BUFFER |
|
|
|
|
|
PIPE_BIND_COMMAND_ARGS_BUFFER | PIPE_BIND_QUERY_BUFFER;
|
|
|
|
|
break;
|
|
|
|
|
case D3D12_RESOURCE_DIMENSION_TEXTURE1D:
|
|
|
|
|
res->base.b.target = incoming_res_desc.DepthOrArraySize > 1 ?
|
|
|
|
|
PIPE_TEXTURE_1D_ARRAY : PIPE_TEXTURE_1D;
|
|
|
|
|
res->base.b.array_size = incoming_res_desc.DepthOrArraySize;
|
|
|
|
|
break;
|
|
|
|
|
case D3D12_RESOURCE_DIMENSION_TEXTURE2D:
|
|
|
|
|
res->base.b.target = incoming_res_desc.DepthOrArraySize > 1 ?
|
|
|
|
|
PIPE_TEXTURE_2D_ARRAY : PIPE_TEXTURE_2D;
|
|
|
|
|
res->base.b.array_size = incoming_res_desc.DepthOrArraySize;
|
|
|
|
|
break;
|
|
|
|
|
case D3D12_RESOURCE_DIMENSION_TEXTURE3D:
|
|
|
|
|
res->base.b.target = PIPE_TEXTURE_3D;
|
2021-09-23 15:42:04 +01:00
|
|
|
|
res->base.b.depth0 = footprint->Depth;
|
2021-09-22 22:47:50 +01:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
unreachable("Invalid dimension");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
res->base.b.nr_samples = incoming_res_desc.SampleDesc.Count;
|
|
|
|
|
res->base.b.last_level = incoming_res_desc.MipLevels - 1;
|
|
|
|
|
res->base.b.usage = PIPE_USAGE_DEFAULT;
|
2022-07-10 02:50:01 +01:00
|
|
|
|
res->base.b.bind |= PIPE_BIND_SHARED;
|
2021-09-22 22:47:50 +01:00
|
|
|
|
if (incoming_res_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)
|
|
|
|
|
res->base.b.bind |= PIPE_BIND_RENDER_TARGET | PIPE_BIND_BLENDABLE | PIPE_BIND_DISPLAY_TARGET;
|
|
|
|
|
if (incoming_res_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)
|
|
|
|
|
res->base.b.bind |= PIPE_BIND_DEPTH_STENCIL;
|
|
|
|
|
if (incoming_res_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS)
|
|
|
|
|
res->base.b.bind |= PIPE_BIND_SHADER_IMAGE;
|
|
|
|
|
if ((incoming_res_desc.Flags & D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE) == D3D12_RESOURCE_FLAG_NONE)
|
|
|
|
|
res->base.b.bind |= PIPE_BIND_SAMPLER_VIEW;
|
|
|
|
|
|
|
|
|
|
if (templ) {
|
|
|
|
|
if (res->base.b.target == PIPE_TEXTURE_2D_ARRAY &&
|
|
|
|
|
(templ->target == PIPE_TEXTURE_CUBE ||
|
|
|
|
|
templ->target == PIPE_TEXTURE_CUBE_ARRAY)) {
|
|
|
|
|
if (res->base.b.array_size < 6) {
|
|
|
|
|
debug_printf("d3d12: Importing cube resource with too few array layers\n");
|
|
|
|
|
goto invalid;
|
|
|
|
|
}
|
|
|
|
|
res->base.b.target = templ->target;
|
|
|
|
|
res->base.b.array_size /= 6;
|
|
|
|
|
}
|
|
|
|
|
unsigned templ_samples = MAX2(templ->nr_samples, 1);
|
|
|
|
|
if (res->base.b.target != templ->target ||
|
2021-12-20 23:29:57 +00:00
|
|
|
|
footprint->Width != templ->width0 ||
|
|
|
|
|
footprint->Height != templ->height0 ||
|
|
|
|
|
footprint->Depth != templ->depth0 ||
|
2021-09-22 22:47:50 +01:00
|
|
|
|
res->base.b.array_size != templ->array_size ||
|
|
|
|
|
incoming_res_desc.SampleDesc.Count != templ_samples ||
|
|
|
|
|
res->base.b.last_level != templ->last_level) {
|
|
|
|
|
debug_printf("d3d12: Importing resource with mismatched dimensions: "
|
|
|
|
|
"plane: %d, target: %d vs %d, width: %d vs %d, height: %d vs %d, "
|
|
|
|
|
"depth: %d vs %d, array_size: %d vs %d, samples: %d vs %d, mips: %d vs %d\n",
|
|
|
|
|
handle->plane,
|
|
|
|
|
res->base.b.target, templ->target,
|
2021-12-20 23:29:57 +00:00
|
|
|
|
footprint->Width, templ->width0,
|
|
|
|
|
footprint->Height, templ->height0,
|
|
|
|
|
footprint->Depth, templ->depth0,
|
2021-09-22 22:47:50 +01:00
|
|
|
|
res->base.b.array_size, templ->array_size,
|
|
|
|
|
incoming_res_desc.SampleDesc.Count, templ_samples,
|
|
|
|
|
res->base.b.last_level + 1, templ->last_level + 1);
|
|
|
|
|
goto invalid;
|
2021-08-08 03:18:19 +01:00
|
|
|
|
}
|
2022-07-11 23:55:35 +01:00
|
|
|
|
if (templ->target != PIPE_BUFFER) {
|
|
|
|
|
if ((footprint->Format != d3d12_get_format(templ->format) &&
|
|
|
|
|
footprint->Format != d3d12_get_typeless_format(templ->format)) ||
|
|
|
|
|
(incoming_res_desc.Format != d3d12_get_format((enum pipe_format)handle->format) &&
|
|
|
|
|
incoming_res_desc.Format != d3d12_get_typeless_format((enum pipe_format)handle->format))) {
|
|
|
|
|
debug_printf("d3d12: Importing resource with mismatched format: "
|
|
|
|
|
"plane could be DXGI format %d or %d, but is %d, "
|
|
|
|
|
"overall could be DXGI format %d or %d, but is %d\n",
|
|
|
|
|
d3d12_get_format(templ->format),
|
|
|
|
|
d3d12_get_typeless_format(templ->format),
|
|
|
|
|
footprint->Format,
|
|
|
|
|
d3d12_get_format((enum pipe_format)handle->format),
|
|
|
|
|
d3d12_get_typeless_format((enum pipe_format)handle->format),
|
|
|
|
|
incoming_res_desc.Format);
|
|
|
|
|
goto invalid;
|
|
|
|
|
}
|
2021-09-22 22:47:50 +01:00
|
|
|
|
}
|
2022-07-11 23:55:35 +01:00
|
|
|
|
/* In an ideal world we'd be able to validate this, but gallium's use of bind
|
|
|
|
|
* flags during resource creation is pretty bad: some bind flags are always set
|
|
|
|
|
* (like PIPE_BIND_RENDER_TARGET) while others are never set (PIPE_BIND_SHADER_BUFFER)
|
|
|
|
|
*
|
2021-09-22 22:47:50 +01:00
|
|
|
|
if (templ->bind & ~res->base.b.bind) {
|
|
|
|
|
debug_printf("d3d12: Imported resource doesn't have necessary bind flags\n");
|
|
|
|
|
goto invalid;
|
2022-07-11 23:55:35 +01:00
|
|
|
|
} */
|
2021-09-22 22:47:50 +01:00
|
|
|
|
|
|
|
|
|
res->base.b.format = templ->format;
|
2021-09-23 15:42:04 +01:00
|
|
|
|
res->overall_format = (enum pipe_format)handle->format;
|
2021-09-22 22:47:50 +01:00
|
|
|
|
} else {
|
|
|
|
|
/* Search the pipe format lookup table for an entry */
|
|
|
|
|
res->base.b.format = d3d12_get_pipe_format(incoming_res_desc.Format);
|
|
|
|
|
|
|
|
|
|
if (res->base.b.format == PIPE_FORMAT_NONE) {
|
|
|
|
|
/* Convert from typeless to a reasonable default */
|
|
|
|
|
res->base.b.format = d3d12_get_default_pipe_format(incoming_res_desc.Format);
|
2021-08-08 03:18:19 +01:00
|
|
|
|
|
2021-09-22 22:47:50 +01:00
|
|
|
|
if (res->base.b.format == PIPE_FORMAT_NONE) {
|
|
|
|
|
debug_printf("d3d12: Unable to deduce non-typeless resource format %d\n", incoming_res_desc.Format);
|
|
|
|
|
goto invalid;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-09-23 15:42:04 +01:00
|
|
|
|
|
|
|
|
|
res->overall_format = res->base.b.format;
|
2021-08-08 03:18:19 +01:00
|
|
|
|
}
|
2021-09-22 22:47:50 +01:00
|
|
|
|
|
2021-09-23 15:42:04 +01:00
|
|
|
|
if (!templ)
|
|
|
|
|
handle->format = res->overall_format;
|
|
|
|
|
|
|
|
|
|
res->dxgi_format = d3d12_get_format(res->overall_format);
|
2022-05-02 18:14:29 +01:00
|
|
|
|
res->plane_slice = handle->plane;
|
|
|
|
|
res->first_plane = &res->base.b;
|
2021-09-23 15:42:04 +01:00
|
|
|
|
|
|
|
|
|
if (!res->bo) {
|
2022-07-20 15:00:36 +01:00
|
|
|
|
res->bo = d3d12_bo_wrap_res(screen, d3d12_res, d3d12_permanently_resident);
|
2021-09-23 15:42:04 +01:00
|
|
|
|
}
|
2020-04-08 13:44:59 +01:00
|
|
|
|
init_valid_range(res);
|
2021-09-23 16:37:59 +01:00
|
|
|
|
|
2022-02-18 09:28:58 +00:00
|
|
|
|
threaded_resource_init(&res->base.b, false);
|
2021-09-23 16:37:59 +01:00
|
|
|
|
convert_planar_resource(res);
|
|
|
|
|
|
2021-11-03 17:23:14 +00:00
|
|
|
|
return &res->base.b;
|
2021-09-22 22:47:50 +01:00
|
|
|
|
|
|
|
|
|
invalid:
|
2021-09-23 15:42:04 +01:00
|
|
|
|
if (res->bo)
|
|
|
|
|
d3d12_bo_unreference(res->bo);
|
|
|
|
|
else if (d3d12_res)
|
2021-09-22 22:47:50 +01:00
|
|
|
|
d3d12_res->Release();
|
|
|
|
|
FREE(res);
|
|
|
|
|
return NULL;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
d3d12_resource_get_handle(struct pipe_screen *pscreen,
|
|
|
|
|
struct pipe_context *pcontext,
|
|
|
|
|
struct pipe_resource *pres,
|
|
|
|
|
struct winsys_handle *handle,
|
|
|
|
|
unsigned usage)
|
|
|
|
|
{
|
2020-04-08 13:44:59 +01:00
|
|
|
|
struct d3d12_resource *res = d3d12_resource(pres);
|
2021-08-08 03:18:19 +01:00
|
|
|
|
struct d3d12_screen *screen = d3d12_screen(pscreen);
|
2020-04-08 13:44:59 +01:00
|
|
|
|
|
2021-08-08 03:18:19 +01:00
|
|
|
|
switch (handle->type) {
|
|
|
|
|
case WINSYS_HANDLE_TYPE_D3D12_RES:
|
|
|
|
|
handle->com_obj = d3d12_resource_resource(res);
|
|
|
|
|
return true;
|
|
|
|
|
case WINSYS_HANDLE_TYPE_FD: {
|
|
|
|
|
HANDLE d3d_handle = nullptr;
|
|
|
|
|
|
|
|
|
|
screen->dev->CreateSharedHandle(d3d12_resource_resource(res),
|
|
|
|
|
nullptr,
|
|
|
|
|
GENERIC_ALL,
|
|
|
|
|
nullptr,
|
|
|
|
|
&d3d_handle);
|
|
|
|
|
if (!d3d_handle)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
handle->handle = d3d_handle;
|
|
|
|
|
#else
|
|
|
|
|
handle->handle = (int)(intptr_t)d3d_handle;
|
|
|
|
|
#endif
|
|
|
|
|
handle->format = pres->format;
|
|
|
|
|
handle->modifier = ~0ull;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
default:
|
2020-04-08 13:44:59 +01:00
|
|
|
|
return false;
|
2021-08-08 03:18:19 +01:00
|
|
|
|
}
|
2019-05-26 09:43:12 +01:00
|
|
|
|
}
|
|
|
|
|
|
2022-05-02 18:14:29 +01:00
|
|
|
|
struct pipe_resource *
|
|
|
|
|
d3d12_resource_from_resource(struct pipe_screen *pscreen,
|
|
|
|
|
ID3D12Resource* input_res)
|
|
|
|
|
{
|
2022-07-14 22:54:18 +01:00
|
|
|
|
D3D12_RESOURCE_DESC input_desc = GetDesc(input_res);
|
2022-05-02 18:14:29 +01:00
|
|
|
|
struct winsys_handle handle;
|
|
|
|
|
memset(&handle, 0, sizeof(handle));
|
|
|
|
|
handle.type = WINSYS_HANDLE_TYPE_D3D12_RES;
|
|
|
|
|
handle.format = d3d12_get_pipe_format(input_desc.Format);
|
|
|
|
|
handle.com_obj = input_res;
|
|
|
|
|
|
|
|
|
|
struct pipe_resource templ;
|
|
|
|
|
memset(&templ, 0, sizeof(templ));
|
|
|
|
|
if(input_desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER) {
|
|
|
|
|
templ.target = PIPE_BUFFER;
|
|
|
|
|
} else {
|
|
|
|
|
templ.target = (input_desc.DepthOrArraySize > 1) ? PIPE_TEXTURE_2D_ARRAY : PIPE_TEXTURE_2D;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
templ.format = d3d12_get_pipe_format(input_desc.Format);
|
|
|
|
|
templ.width0 = input_desc.Width;
|
|
|
|
|
templ.height0 = input_desc.Height;
|
|
|
|
|
templ.depth0 = input_desc.DepthOrArraySize;
|
|
|
|
|
templ.array_size = input_desc.DepthOrArraySize;
|
|
|
|
|
templ.flags = 0;
|
|
|
|
|
|
|
|
|
|
return d3d12_resource_from_handle(
|
|
|
|
|
pscreen,
|
|
|
|
|
&templ,
|
|
|
|
|
&handle,
|
|
|
|
|
PIPE_USAGE_DEFAULT
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* On Map/Unmap operations, we readback or flush all the underlying planes
|
|
|
|
|
* of planar resources. The map/unmap operation from the caller is
|
|
|
|
|
* expected to be done for res->plane_slice plane only, but some
|
|
|
|
|
* callers expect adjacent allocations for next contiguous plane access
|
|
|
|
|
*
|
|
|
|
|
* In this function, we take the res and box the caller passed, and the plane_* properties
|
|
|
|
|
* that are currently being readback/flushed, and adjust the d3d12_transfer ptrans
|
|
|
|
|
* accordingly for the GPU copy operation between planes.
|
|
|
|
|
*/
|
|
|
|
|
static void d3d12_adjust_transfer_dimensions_for_plane(const struct d3d12_resource *res,
|
|
|
|
|
unsigned plane_slice,
|
|
|
|
|
unsigned plane_stride,
|
|
|
|
|
unsigned plane_layer_stride,
|
|
|
|
|
unsigned plane_offset,
|
|
|
|
|
const struct pipe_box* original_box,
|
|
|
|
|
struct pipe_transfer *ptrans/*inout*/)
|
|
|
|
|
{
|
|
|
|
|
/* Adjust strides, offsets to the corresponding plane*/
|
|
|
|
|
ptrans->stride = plane_stride;
|
|
|
|
|
ptrans->layer_stride = plane_layer_stride;
|
|
|
|
|
ptrans->offset = plane_offset;
|
|
|
|
|
|
|
|
|
|
/* Find multipliers such that:*/
|
|
|
|
|
/* first_plane.width = width_multiplier * planes[res->plane_slice].width*/
|
|
|
|
|
/* first_plane.height = height_multiplier * planes[res->plane_slice].height*/
|
|
|
|
|
float width_multiplier = res->first_plane->width0 / (float) util_format_get_plane_width(res->overall_format, res->plane_slice, res->first_plane->width0);
|
|
|
|
|
float height_multiplier = res->first_plane->height0 / (float) util_format_get_plane_height(res->overall_format, res->plane_slice, res->first_plane->height0);
|
|
|
|
|
|
|
|
|
|
/* Normalize box back to overall dimensions (first plane)*/
|
|
|
|
|
ptrans->box.width = width_multiplier * original_box->width;
|
|
|
|
|
ptrans->box.height = height_multiplier * original_box->height;
|
|
|
|
|
ptrans->box.x = width_multiplier * original_box->x;
|
|
|
|
|
ptrans->box.y = height_multiplier * original_box->y;
|
|
|
|
|
|
|
|
|
|
/* Now adjust dimensions to plane_slice*/
|
|
|
|
|
ptrans->box.width = util_format_get_plane_width(res->overall_format, plane_slice, ptrans->box.width);
|
|
|
|
|
ptrans->box.height = util_format_get_plane_height(res->overall_format, plane_slice, ptrans->box.height);
|
|
|
|
|
ptrans->box.x = util_format_get_plane_width(res->overall_format, plane_slice, ptrans->box.x);
|
|
|
|
|
ptrans->box.y = util_format_get_plane_height(res->overall_format, plane_slice, ptrans->box.y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static
|
|
|
|
|
void d3d12_resource_get_planes_info(pipe_resource *pres,
|
|
|
|
|
unsigned num_planes,
|
|
|
|
|
pipe_resource **planes,
|
|
|
|
|
unsigned *strides,
|
|
|
|
|
unsigned *layer_strides,
|
|
|
|
|
unsigned *offsets,
|
|
|
|
|
unsigned *staging_res_size)
|
|
|
|
|
{
|
|
|
|
|
struct d3d12_resource* res = d3d12_resource(pres);
|
|
|
|
|
*staging_res_size = 0;
|
|
|
|
|
struct pipe_resource *cur_plane_resource = res->first_plane;
|
|
|
|
|
for (uint plane_slice = 0; plane_slice < num_planes; ++plane_slice) {
|
|
|
|
|
planes[plane_slice] = cur_plane_resource;
|
|
|
|
|
int width = util_format_get_plane_width(res->base.b.format, plane_slice, res->first_plane->width0);
|
|
|
|
|
int height = util_format_get_plane_height(res->base.b.format, plane_slice, res->first_plane->height0);
|
|
|
|
|
|
|
|
|
|
strides[plane_slice] = align(util_format_get_stride(cur_plane_resource->format, width),
|
|
|
|
|
D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
|
|
|
|
|
|
|
|
|
|
layer_strides[plane_slice] = align(util_format_get_2d_size(cur_plane_resource->format,
|
|
|
|
|
strides[plane_slice],
|
|
|
|
|
height),
|
|
|
|
|
D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
|
|
|
|
|
|
|
|
|
|
offsets[plane_slice] = *staging_res_size;
|
|
|
|
|
*staging_res_size += layer_strides[plane_slice];
|
|
|
|
|
cur_plane_resource = cur_plane_resource->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-18 17:13:14 +01:00
|
|
|
|
static constexpr unsigned d3d12_max_planes = 3;
|
|
|
|
|
|
2022-05-02 18:14:29 +01:00
|
|
|
|
/**
|
|
|
|
|
* Get stride and offset for the given pipe resource without the need to get
|
|
|
|
|
* a winsys_handle.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
d3d12_resource_get_info(struct pipe_screen *pscreen,
|
|
|
|
|
struct pipe_resource *pres,
|
|
|
|
|
unsigned *stride,
|
|
|
|
|
unsigned *offset)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
struct d3d12_resource* res = d3d12_resource(pres);
|
|
|
|
|
unsigned num_planes = util_format_get_num_planes(res->overall_format);
|
|
|
|
|
|
2022-05-18 17:13:14 +01:00
|
|
|
|
pipe_resource *planes[d3d12_max_planes];
|
|
|
|
|
unsigned int strides[d3d12_max_planes];
|
|
|
|
|
unsigned int layer_strides[d3d12_max_planes];
|
|
|
|
|
unsigned int offsets[d3d12_max_planes];
|
2022-05-02 18:14:29 +01:00
|
|
|
|
unsigned staging_res_size = 0;
|
|
|
|
|
d3d12_resource_get_planes_info(
|
|
|
|
|
pres,
|
|
|
|
|
num_planes,
|
|
|
|
|
planes,
|
|
|
|
|
strides,
|
|
|
|
|
layer_strides,
|
|
|
|
|
offsets,
|
|
|
|
|
&staging_res_size
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if(stride) {
|
|
|
|
|
*stride = strides[res->plane_slice];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(offset) {
|
|
|
|
|
*offset = offsets[res->plane_slice];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-10 02:51:54 +01:00
|
|
|
|
static struct pipe_memory_object *
|
|
|
|
|
d3d12_memobj_create_from_handle(struct pipe_screen *pscreen, struct winsys_handle *handle, bool dedicated)
|
|
|
|
|
{
|
2022-07-10 03:27:03 +01:00
|
|
|
|
if (handle->type != WINSYS_HANDLE_TYPE_WIN32_HANDLE &&
|
|
|
|
|
handle->type != WINSYS_HANDLE_TYPE_WIN32_NAME) {
|
2022-07-10 02:51:54 +01:00
|
|
|
|
debug_printf("d3d12: Unsupported memobj handle type\n");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct d3d12_screen *screen = d3d12_screen(pscreen);
|
|
|
|
|
IUnknown *obj;
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
HANDLE d3d_handle = handle->handle;
|
|
|
|
|
#else
|
|
|
|
|
HANDLE d3d_handle = (HANDLE)(intptr_t)handle->handle;
|
|
|
|
|
#endif
|
2022-07-10 03:27:03 +01:00
|
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
HANDLE d3d_handle_to_close = nullptr;
|
|
|
|
|
if (handle->type == WINSYS_HANDLE_TYPE_WIN32_NAME) {
|
|
|
|
|
screen->dev->OpenSharedHandleByName((LPCWSTR) handle->name, GENERIC_ALL, &d3d_handle_to_close);
|
|
|
|
|
d3d_handle = d3d_handle_to_close;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
screen->dev->OpenSharedHandle(d3d_handle, IID_PPV_ARGS(&obj));
|
|
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
if (d3d_handle_to_close) {
|
|
|
|
|
CloseHandle(d3d_handle_to_close);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (!obj) {
|
2022-07-10 02:51:54 +01:00
|
|
|
|
debug_printf("d3d12: Failed to open memobj handle as anything\n");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct d3d12_memory_object *memobj = CALLOC_STRUCT(d3d12_memory_object);
|
|
|
|
|
if (!memobj) {
|
|
|
|
|
obj->Release();
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
memobj->base.dedicated = dedicated;
|
|
|
|
|
|
|
|
|
|
(void)obj->QueryInterface(&memobj->res);
|
|
|
|
|
(void)obj->QueryInterface(&memobj->heap);
|
|
|
|
|
obj->Release();
|
|
|
|
|
if (!memobj->res && !memobj->heap) {
|
|
|
|
|
debug_printf("d3d12: Memory object isn't a resource or heap\n");
|
|
|
|
|
free(memobj);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool expect_dedicated = memobj->res != nullptr;
|
|
|
|
|
if (dedicated != expect_dedicated)
|
|
|
|
|
debug_printf("d3d12: Expected dedicated to be %s for imported %s\n",
|
|
|
|
|
expect_dedicated ? "true" : "false",
|
|
|
|
|
expect_dedicated ? "resource" : "heap");
|
|
|
|
|
|
|
|
|
|
return &memobj->base;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
d3d12_memobj_destroy(struct pipe_screen *pscreen, struct pipe_memory_object *pmemobj)
|
|
|
|
|
{
|
|
|
|
|
struct d3d12_memory_object *memobj = d3d12_memory_object(pmemobj);
|
|
|
|
|
if (memobj->res)
|
|
|
|
|
memobj->res->Release();
|
|
|
|
|
if (memobj->heap)
|
|
|
|
|
memobj->heap->Release();
|
|
|
|
|
free(memobj);
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-10 02:53:53 +01:00
|
|
|
|
static pipe_resource *
|
|
|
|
|
d3d12_resource_from_memobj(struct pipe_screen *pscreen,
|
|
|
|
|
const struct pipe_resource *templ,
|
|
|
|
|
struct pipe_memory_object *pmemobj,
|
|
|
|
|
uint64_t offset)
|
|
|
|
|
{
|
|
|
|
|
struct d3d12_memory_object *memobj = d3d12_memory_object(pmemobj);
|
|
|
|
|
|
|
|
|
|
struct winsys_handle whandle = {};
|
|
|
|
|
whandle.type = WINSYS_HANDLE_TYPE_D3D12_RES;
|
|
|
|
|
whandle.com_obj = memobj->res ? (void *) memobj->res : (void *) memobj->heap;
|
|
|
|
|
whandle.offset = offset;
|
|
|
|
|
whandle.format = templ->format;
|
|
|
|
|
|
|
|
|
|
// WINSYS_HANDLE_TYPE_D3D12_RES implies taking ownership of the reference
|
|
|
|
|
((IUnknown *)whandle.com_obj)->AddRef();
|
|
|
|
|
return d3d12_resource_from_handle(pscreen, templ, &whandle, 0);
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-26 09:43:12 +01:00
|
|
|
|
void
|
|
|
|
|
d3d12_screen_resource_init(struct pipe_screen *pscreen)
|
|
|
|
|
{
|
|
|
|
|
pscreen->resource_create = d3d12_resource_create;
|
|
|
|
|
pscreen->resource_from_handle = d3d12_resource_from_handle;
|
|
|
|
|
pscreen->resource_get_handle = d3d12_resource_get_handle;
|
|
|
|
|
pscreen->resource_destroy = d3d12_resource_destroy;
|
2022-05-02 18:14:29 +01:00
|
|
|
|
pscreen->resource_get_info = d3d12_resource_get_info;
|
2022-07-10 02:51:54 +01:00
|
|
|
|
|
|
|
|
|
pscreen->memobj_create_from_handle = d3d12_memobj_create_from_handle;
|
|
|
|
|
pscreen->memobj_destroy = d3d12_memobj_destroy;
|
2022-07-10 02:53:53 +01:00
|
|
|
|
pscreen->resource_from_memobj = d3d12_resource_from_memobj;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned int
|
|
|
|
|
get_subresource_id(struct d3d12_resource *res, unsigned resid,
|
|
|
|
|
unsigned z, unsigned base_level)
|
|
|
|
|
{
|
2021-11-03 17:23:14 +00:00
|
|
|
|
unsigned resource_stride = res->base.b.last_level + 1;
|
|
|
|
|
if (res->base.b.target == PIPE_TEXTURE_1D_ARRAY ||
|
|
|
|
|
res->base.b.target == PIPE_TEXTURE_2D_ARRAY)
|
|
|
|
|
resource_stride *= res->base.b.array_size;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
2021-11-03 17:23:14 +00:00
|
|
|
|
if (res->base.b.target == PIPE_TEXTURE_CUBE)
|
2019-05-26 09:43:12 +01:00
|
|
|
|
resource_stride *= 6;
|
|
|
|
|
|
2021-11-03 17:23:14 +00:00
|
|
|
|
if (res->base.b.target == PIPE_TEXTURE_CUBE_ARRAY)
|
|
|
|
|
resource_stride *= 6 * res->base.b.array_size;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
2021-11-03 17:23:14 +00:00
|
|
|
|
unsigned layer_stride = res->base.b.last_level + 1;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
|
|
|
|
return resid * resource_stride + z * layer_stride +
|
2022-05-02 18:14:29 +01:00
|
|
|
|
base_level + res->plane_slice * resource_stride;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static D3D12_TEXTURE_COPY_LOCATION
|
|
|
|
|
fill_texture_location(struct d3d12_resource *res,
|
|
|
|
|
struct d3d12_transfer *trans, unsigned resid, unsigned z)
|
|
|
|
|
{
|
|
|
|
|
D3D12_TEXTURE_COPY_LOCATION tex_loc = {0};
|
2021-11-03 17:27:09 +00:00
|
|
|
|
int subres = get_subresource_id(res, resid, z, trans->base.b.level);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
|
|
|
|
tex_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
|
|
|
|
tex_loc.SubresourceIndex = subres;
|
|
|
|
|
tex_loc.pResource = d3d12_resource_resource(res);
|
|
|
|
|
return tex_loc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static D3D12_TEXTURE_COPY_LOCATION
|
|
|
|
|
fill_buffer_location(struct d3d12_context *ctx,
|
|
|
|
|
struct d3d12_resource *res,
|
|
|
|
|
struct d3d12_resource *staging_res,
|
|
|
|
|
struct d3d12_transfer *trans,
|
|
|
|
|
unsigned depth,
|
|
|
|
|
unsigned resid, unsigned z)
|
|
|
|
|
{
|
|
|
|
|
D3D12_TEXTURE_COPY_LOCATION buf_loc = {0};
|
|
|
|
|
D3D12_PLACED_SUBRESOURCE_FOOTPRINT footprint;
|
|
|
|
|
uint64_t offset = 0;
|
2022-07-14 22:54:18 +01:00
|
|
|
|
auto descr = GetDesc(d3d12_resource_underlying(res, &offset));
|
2021-12-03 18:45:20 +00:00
|
|
|
|
struct d3d12_screen *screen = d3d12_screen(ctx->base.screen);
|
|
|
|
|
ID3D12Device* dev = screen->dev;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
2021-11-03 17:27:09 +00:00
|
|
|
|
unsigned sub_resid = get_subresource_id(res, resid, z, trans->base.b.level);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
dev->GetCopyableFootprints(&descr, sub_resid, 1, 0, &footprint, nullptr, nullptr, nullptr);
|
|
|
|
|
|
|
|
|
|
buf_loc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
|
|
|
|
|
buf_loc.pResource = d3d12_resource_underlying(staging_res, &offset);
|
|
|
|
|
buf_loc.PlacedFootprint = footprint;
|
|
|
|
|
buf_loc.PlacedFootprint.Offset += offset;
|
2022-05-02 18:14:29 +01:00
|
|
|
|
buf_loc.PlacedFootprint.Offset += trans->base.b.offset;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
2021-12-03 18:45:20 +00:00
|
|
|
|
if (util_format_has_depth(util_format_description(res->base.b.format)) &&
|
|
|
|
|
screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED) {
|
|
|
|
|
buf_loc.PlacedFootprint.Footprint.Width = res->base.b.width0;
|
|
|
|
|
buf_loc.PlacedFootprint.Footprint.Height = res->base.b.height0;
|
|
|
|
|
buf_loc.PlacedFootprint.Footprint.Depth = res->base.b.depth0;
|
|
|
|
|
} else {
|
|
|
|
|
buf_loc.PlacedFootprint.Footprint.Width = ALIGN(trans->base.b.box.width,
|
|
|
|
|
util_format_get_blockwidth(res->base.b.format));
|
|
|
|
|
buf_loc.PlacedFootprint.Footprint.Height = ALIGN(trans->base.b.box.height,
|
|
|
|
|
util_format_get_blockheight(res->base.b.format));
|
|
|
|
|
buf_loc.PlacedFootprint.Footprint.Depth = ALIGN(depth,
|
|
|
|
|
util_format_get_blockdepth(res->base.b.format));
|
|
|
|
|
}
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
2021-11-03 17:27:09 +00:00
|
|
|
|
buf_loc.PlacedFootprint.Footprint.RowPitch = trans->base.b.stride;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
|
|
|
|
return buf_loc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct copy_info {
|
|
|
|
|
struct d3d12_resource *dst;
|
|
|
|
|
D3D12_TEXTURE_COPY_LOCATION dst_loc;
|
|
|
|
|
UINT dst_x, dst_y, dst_z;
|
|
|
|
|
struct d3d12_resource *src;
|
|
|
|
|
D3D12_TEXTURE_COPY_LOCATION src_loc;
|
|
|
|
|
D3D12_BOX *src_box;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
copy_texture_region(struct d3d12_context *ctx,
|
|
|
|
|
struct copy_info& info)
|
|
|
|
|
{
|
|
|
|
|
auto batch = d3d12_current_batch(ctx);
|
|
|
|
|
|
2021-11-04 00:05:05 +00:00
|
|
|
|
d3d12_batch_reference_resource(batch, info.src, false);
|
|
|
|
|
d3d12_batch_reference_resource(batch, info.dst, true);
|
2022-07-21 17:10:13 +01:00
|
|
|
|
d3d12_transition_resource_state(ctx, info.src, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
|
|
|
|
|
d3d12_transition_resource_state(ctx, info.dst, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
|
2022-01-26 16:31:33 +00:00
|
|
|
|
d3d12_apply_resource_states(ctx, false);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
ctx->cmdlist->CopyTextureRegion(&info.dst_loc, info.dst_x, info.dst_y, info.dst_z,
|
|
|
|
|
&info.src_loc, info.src_box);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
transfer_buf_to_image_part(struct d3d12_context *ctx,
|
|
|
|
|
struct d3d12_resource *res,
|
|
|
|
|
struct d3d12_resource *staging_res,
|
|
|
|
|
struct d3d12_transfer *trans,
|
|
|
|
|
int z, int depth, int start_z, int dest_z,
|
|
|
|
|
int resid)
|
|
|
|
|
{
|
|
|
|
|
if (D3D12_DEBUG_RESOURCE & d3d12_debug) {
|
|
|
|
|
debug_printf("D3D12: Copy %dx%dx%d + %dx%dx%d from buffer %s to image %s\n",
|
2021-11-03 17:27:09 +00:00
|
|
|
|
trans->base.b.box.x, trans->base.b.box.y, trans->base.b.box.z,
|
|
|
|
|
trans->base.b.box.width, trans->base.b.box.height, trans->base.b.box.depth,
|
2021-11-03 17:23:14 +00:00
|
|
|
|
util_format_name(staging_res->base.b.format),
|
|
|
|
|
util_format_name(res->base.b.format));
|
2019-05-26 09:43:12 +01:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-03 18:45:20 +00:00
|
|
|
|
struct d3d12_screen *screen = d3d12_screen(res->base.b.screen);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
struct copy_info copy_info;
|
|
|
|
|
copy_info.src = staging_res;
|
|
|
|
|
copy_info.src_loc = fill_buffer_location(ctx, res, staging_res, trans, depth, resid, z);
|
2022-02-08 00:29:40 +00:00
|
|
|
|
copy_info.src_loc.PlacedFootprint.Offset += (z - start_z) * trans->base.b.layer_stride;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
copy_info.src_box = nullptr;
|
|
|
|
|
copy_info.dst = res;
|
|
|
|
|
copy_info.dst_loc = fill_texture_location(res, trans, resid, z);
|
2021-12-03 18:45:20 +00:00
|
|
|
|
if (util_format_has_depth(util_format_description(res->base.b.format)) &&
|
|
|
|
|
screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED) {
|
|
|
|
|
copy_info.dst_x = 0;
|
|
|
|
|
copy_info.dst_y = 0;
|
|
|
|
|
} else {
|
|
|
|
|
copy_info.dst_x = trans->base.b.box.x;
|
|
|
|
|
copy_info.dst_y = trans->base.b.box.y;
|
|
|
|
|
}
|
2021-11-03 17:23:14 +00:00
|
|
|
|
copy_info.dst_z = res->base.b.target == PIPE_TEXTURE_CUBE ? 0 : dest_z;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
copy_info.src_box = nullptr;
|
|
|
|
|
|
|
|
|
|
copy_texture_region(ctx, copy_info);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
transfer_buf_to_image(struct d3d12_context *ctx,
|
|
|
|
|
struct d3d12_resource *res,
|
|
|
|
|
struct d3d12_resource *staging_res,
|
|
|
|
|
struct d3d12_transfer *trans, int resid)
|
|
|
|
|
{
|
2021-11-03 17:23:14 +00:00
|
|
|
|
if (res->base.b.target == PIPE_TEXTURE_3D) {
|
2019-05-26 09:43:12 +01:00
|
|
|
|
assert(resid == 0);
|
|
|
|
|
transfer_buf_to_image_part(ctx, res, staging_res, trans,
|
2021-11-03 17:27:09 +00:00
|
|
|
|
0, trans->base.b.box.depth, 0,
|
|
|
|
|
trans->base.b.box.z, 0);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
} else {
|
2021-11-03 17:27:09 +00:00
|
|
|
|
int num_layers = trans->base.b.box.depth;
|
|
|
|
|
int start_z = trans->base.b.box.z;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
|
|
|
|
for (int z = start_z; z < start_z + num_layers; ++z) {
|
|
|
|
|
transfer_buf_to_image_part(ctx, res, staging_res, trans,
|
|
|
|
|
z, 1, start_z, 0, resid);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
transfer_image_part_to_buf(struct d3d12_context *ctx,
|
|
|
|
|
struct d3d12_resource *res,
|
|
|
|
|
struct d3d12_resource *staging_res,
|
|
|
|
|
struct d3d12_transfer *trans,
|
|
|
|
|
unsigned resid, int z, int start_layer,
|
|
|
|
|
int start_box_z, int depth)
|
|
|
|
|
{
|
2021-11-03 17:27:09 +00:00
|
|
|
|
struct pipe_box *box = &trans->base.b.box;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
D3D12_BOX src_box = {};
|
|
|
|
|
|
2021-12-03 18:45:20 +00:00
|
|
|
|
struct d3d12_screen *screen = d3d12_screen(res->base.b.screen);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
struct copy_info copy_info;
|
|
|
|
|
copy_info.src_box = nullptr;
|
|
|
|
|
copy_info.src = res;
|
|
|
|
|
copy_info.src_loc = fill_texture_location(res, trans, resid, z);
|
|
|
|
|
copy_info.dst = staging_res;
|
|
|
|
|
copy_info.dst_loc = fill_buffer_location(ctx, res, staging_res, trans,
|
|
|
|
|
depth, resid, z);
|
2022-02-08 00:29:40 +00:00
|
|
|
|
copy_info.dst_loc.PlacedFootprint.Offset += (z - start_layer) * trans->base.b.layer_stride;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
copy_info.dst_x = copy_info.dst_y = copy_info.dst_z = 0;
|
|
|
|
|
|
2021-12-03 18:45:20 +00:00
|
|
|
|
bool whole_resource = util_texrange_covers_whole_level(&res->base.b, trans->base.b.level,
|
|
|
|
|
box->x, box->y, start_box_z,
|
|
|
|
|
box->width, box->height, depth);
|
|
|
|
|
if (util_format_has_depth(util_format_description(res->base.b.format)) &&
|
|
|
|
|
screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED)
|
|
|
|
|
whole_resource = true;
|
|
|
|
|
if (!whole_resource) {
|
2019-05-26 09:43:12 +01:00
|
|
|
|
src_box.left = box->x;
|
|
|
|
|
src_box.right = box->x + box->width;
|
|
|
|
|
src_box.top = box->y;
|
|
|
|
|
src_box.bottom = box->y + box->height;
|
|
|
|
|
src_box.front = start_box_z;
|
|
|
|
|
src_box.back = start_box_z + depth;
|
|
|
|
|
copy_info.src_box = &src_box;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
copy_texture_region(ctx, copy_info);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
transfer_image_to_buf(struct d3d12_context *ctx,
|
|
|
|
|
struct d3d12_resource *res,
|
|
|
|
|
struct d3d12_resource *staging_res,
|
|
|
|
|
struct d3d12_transfer *trans,
|
|
|
|
|
unsigned resid)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/* We only suppport loading from either an texture array
|
|
|
|
|
* or a ZS texture, so either resid is zero, or num_layers == 1)
|
|
|
|
|
*/
|
2021-11-03 17:27:09 +00:00
|
|
|
|
assert(resid == 0 || trans->base.b.box.depth == 1);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
|
|
|
|
if (D3D12_DEBUG_RESOURCE & d3d12_debug) {
|
|
|
|
|
debug_printf("D3D12: Copy %dx%dx%d + %dx%dx%d from %s@%d to %s\n",
|
2021-11-03 17:27:09 +00:00
|
|
|
|
trans->base.b.box.x, trans->base.b.box.y, trans->base.b.box.z,
|
|
|
|
|
trans->base.b.box.width, trans->base.b.box.height, trans->base.b.box.depth,
|
2021-11-03 17:23:14 +00:00
|
|
|
|
util_format_name(res->base.b.format), resid,
|
|
|
|
|
util_format_name(staging_res->base.b.format));
|
2019-05-26 09:43:12 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct pipe_resource *resolved_resource = nullptr;
|
2021-11-03 17:23:14 +00:00
|
|
|
|
if (res->base.b.nr_samples > 1) {
|
|
|
|
|
struct pipe_resource tmpl = res->base.b;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
tmpl.nr_samples = 0;
|
|
|
|
|
resolved_resource = d3d12_resource_create(ctx->base.screen, &tmpl);
|
2020-12-28 18:50:40 +00:00
|
|
|
|
struct pipe_blit_info resolve_info = {};
|
2021-11-03 17:23:14 +00:00
|
|
|
|
struct pipe_box box = {0,0,0, (int)res->base.b.width0, (int16_t)res->base.b.height0, (int16_t)res->base.b.depth0};
|
2019-05-26 09:43:12 +01:00
|
|
|
|
resolve_info.dst.resource = resolved_resource;
|
|
|
|
|
resolve_info.dst.box = box;
|
2021-11-03 17:23:14 +00:00
|
|
|
|
resolve_info.dst.format = res->base.b.format;
|
|
|
|
|
resolve_info.src.resource = &res->base.b;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
resolve_info.src.box = box;
|
2021-11-03 17:23:14 +00:00
|
|
|
|
resolve_info.src.format = res->base.b.format;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
resolve_info.filter = PIPE_TEX_FILTER_NEAREST;
|
|
|
|
|
resolve_info.mask = util_format_get_mask(tmpl.format);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
d3d12_blit(&ctx->base, &resolve_info);
|
|
|
|
|
res = (struct d3d12_resource *)resolved_resource;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2021-11-03 17:23:14 +00:00
|
|
|
|
if (res->base.b.target == PIPE_TEXTURE_3D) {
|
2019-05-26 09:43:12 +01:00
|
|
|
|
transfer_image_part_to_buf(ctx, res, staging_res, trans, resid,
|
2021-11-03 17:27:09 +00:00
|
|
|
|
0, 0, trans->base.b.box.z, trans->base.b.box.depth);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
} else {
|
2021-11-03 17:27:09 +00:00
|
|
|
|
int start_layer = trans->base.b.box.z;
|
|
|
|
|
for (int z = start_layer; z < start_layer + trans->base.b.box.depth; ++z) {
|
2019-05-26 09:43:12 +01:00
|
|
|
|
transfer_image_part_to_buf(ctx, res, staging_res, trans, resid,
|
|
|
|
|
z, start_layer, 0, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pipe_resource_reference(&resolved_resource, NULL);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-14 19:42:49 +00:00
|
|
|
|
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);
|
|
|
|
|
|
2021-11-04 00:05:05 +00:00
|
|
|
|
d3d12_batch_reference_resource(batch, src, false);
|
|
|
|
|
d3d12_batch_reference_resource(batch, dst, true);
|
2020-12-14 19:42:49 +00:00
|
|
|
|
|
|
|
|
|
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);
|
2022-07-21 17:10:13 +01:00
|
|
|
|
d3d12_transition_resource_state(ctx, src, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
|
|
|
|
|
d3d12_transition_resource_state(ctx, dst, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
|
2022-01-26 16:31:33 +00:00
|
|
|
|
d3d12_apply_resource_states(ctx, false);
|
2020-12-14 19:42:49 +00:00
|
|
|
|
ctx->cmdlist->CopyBufferRegion(dst_d3d12, dst_offset,
|
|
|
|
|
src_d3d12, src_offset,
|
|
|
|
|
width);
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-26 09:43:12 +01:00
|
|
|
|
static unsigned
|
|
|
|
|
linear_offset(int x, int y, int z, unsigned stride, unsigned layer_stride)
|
|
|
|
|
{
|
|
|
|
|
return x +
|
|
|
|
|
y * stride +
|
|
|
|
|
z * layer_stride;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static D3D12_RANGE
|
|
|
|
|
linear_range(const struct pipe_box *box, unsigned stride, unsigned layer_stride)
|
|
|
|
|
{
|
|
|
|
|
D3D12_RANGE range;
|
|
|
|
|
|
|
|
|
|
range.Begin = linear_offset(box->x, box->y, box->z,
|
|
|
|
|
stride, layer_stride);
|
|
|
|
|
range.End = linear_offset(box->x + box->width,
|
|
|
|
|
box->y + box->height - 1,
|
|
|
|
|
box->z + box->depth - 1,
|
|
|
|
|
stride, layer_stride);
|
|
|
|
|
|
|
|
|
|
return range;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
synchronize(struct d3d12_context *ctx,
|
|
|
|
|
struct d3d12_resource *res,
|
|
|
|
|
unsigned usage,
|
|
|
|
|
D3D12_RANGE *range)
|
|
|
|
|
{
|
2021-11-03 17:23:14 +00:00
|
|
|
|
assert(can_map_directly(&res->base.b));
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
|
|
|
|
/* Check whether that range contains valid data; if not, we might not need to sync */
|
|
|
|
|
if (!(usage & PIPE_MAP_UNSYNCHRONIZED) &&
|
|
|
|
|
usage & PIPE_MAP_WRITE &&
|
|
|
|
|
!util_ranges_intersect(&res->valid_buffer_range, range->Begin, range->End)) {
|
|
|
|
|
usage |= PIPE_MAP_UNSYNCHRONIZED;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-04 00:05:05 +00:00
|
|
|
|
if (!(usage & PIPE_MAP_UNSYNCHRONIZED) && resource_is_busy(ctx, res, usage & PIPE_MAP_WRITE)) {
|
2022-02-10 19:08:16 +00:00
|
|
|
|
if (usage & PIPE_MAP_DONTBLOCK) {
|
|
|
|
|
if (d3d12_batch_has_references(d3d12_current_batch(ctx), res->bo, usage & PIPE_MAP_WRITE))
|
|
|
|
|
d3d12_flush_cmdlist(ctx);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
return false;
|
2022-02-10 19:08:16 +00:00
|
|
|
|
}
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
2021-11-04 00:05:05 +00:00
|
|
|
|
d3d12_resource_wait_idle(ctx, res, usage & PIPE_MAP_WRITE);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (usage & PIPE_MAP_WRITE)
|
2021-11-03 17:23:14 +00:00
|
|
|
|
util_range_add(&res->base.b, &res->valid_buffer_range,
|
2019-05-26 09:43:12 +01:00
|
|
|
|
range->Begin, range->End);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* A wrapper to make sure local resources are freed and unmapped with
|
|
|
|
|
* any exit path */
|
|
|
|
|
struct local_resource {
|
2020-12-22 01:52:04 +00:00
|
|
|
|
local_resource(pipe_screen *s, struct pipe_resource *tmpl) :
|
|
|
|
|
mapped(false)
|
2019-05-26 09:43:12 +01:00
|
|
|
|
{
|
|
|
|
|
res = d3d12_resource(d3d12_resource_create(s, tmpl));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~local_resource() {
|
|
|
|
|
if (res) {
|
|
|
|
|
if (mapped)
|
|
|
|
|
d3d12_bo_unmap(res->bo, nullptr);
|
|
|
|
|
pipe_resource_reference((struct pipe_resource **)&res, NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void *
|
|
|
|
|
map() {
|
|
|
|
|
void *ptr;
|
|
|
|
|
ptr = d3d12_bo_map(res->bo, nullptr);
|
|
|
|
|
if (ptr)
|
|
|
|
|
mapped = true;
|
|
|
|
|
return ptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void unmap()
|
|
|
|
|
{
|
|
|
|
|
if (mapped)
|
|
|
|
|
d3d12_bo_unmap(res->bo, nullptr);
|
|
|
|
|
mapped = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
operator struct d3d12_resource *() {
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool operator !() {
|
|
|
|
|
return !res;
|
|
|
|
|
}
|
|
|
|
|
private:
|
|
|
|
|
struct d3d12_resource *res;
|
|
|
|
|
bool mapped;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Combined depth-stencil needs a special handling for reading back: DX handled
|
|
|
|
|
* depth and stencil parts as separate resources and handles copying them only
|
|
|
|
|
* by using seperate texture copy calls with different formats. So create two
|
|
|
|
|
* buffers, read back both resources and interleave the data.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2021-12-03 18:45:20 +00:00
|
|
|
|
prepare_zs_layer_strides(struct d3d12_screen *screen,
|
|
|
|
|
struct d3d12_resource *res,
|
2019-05-26 09:43:12 +01:00
|
|
|
|
const struct pipe_box *box,
|
|
|
|
|
struct d3d12_transfer *trans)
|
|
|
|
|
{
|
2021-12-03 18:45:20 +00:00
|
|
|
|
bool copy_whole_resource = screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED;
|
|
|
|
|
int width = copy_whole_resource ? res->base.b.width0 : box->width;
|
|
|
|
|
int height = copy_whole_resource ? res->base.b.height0 : box->height;
|
|
|
|
|
|
|
|
|
|
trans->base.b.stride = align(util_format_get_stride(res->base.b.format, width),
|
|
|
|
|
D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
|
2021-11-03 17:27:09 +00:00
|
|
|
|
trans->base.b.layer_stride = util_format_get_2d_size(res->base.b.format,
|
2021-12-03 18:45:20 +00:00
|
|
|
|
trans->base.b.stride,
|
|
|
|
|
height);
|
|
|
|
|
|
|
|
|
|
if (copy_whole_resource) {
|
|
|
|
|
trans->zs_cpu_copy_stride = align(util_format_get_stride(res->base.b.format, box->width),
|
|
|
|
|
D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
|
|
|
|
|
trans->zs_cpu_copy_layer_stride = util_format_get_2d_size(res->base.b.format,
|
|
|
|
|
trans->base.b.stride,
|
|
|
|
|
box->height);
|
|
|
|
|
} else {
|
|
|
|
|
trans->zs_cpu_copy_stride = trans->base.b.stride;
|
|
|
|
|
trans->zs_cpu_copy_layer_stride = trans->base.b.layer_stride;
|
|
|
|
|
}
|
2019-05-26 09:43:12 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void *
|
|
|
|
|
read_zs_surface(struct d3d12_context *ctx, struct d3d12_resource *res,
|
|
|
|
|
const struct pipe_box *box,
|
|
|
|
|
struct d3d12_transfer *trans)
|
|
|
|
|
{
|
|
|
|
|
pipe_screen *pscreen = ctx->base.screen;
|
2021-12-03 18:45:20 +00:00
|
|
|
|
struct d3d12_screen *screen = d3d12_screen(pscreen);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
2021-12-03 18:45:20 +00:00
|
|
|
|
prepare_zs_layer_strides(screen, res, box, trans);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
|
|
|
|
struct pipe_resource tmpl;
|
|
|
|
|
memset(&tmpl, 0, sizeof tmpl);
|
|
|
|
|
tmpl.target = PIPE_BUFFER;
|
|
|
|
|
tmpl.format = PIPE_FORMAT_R32_UNORM;
|
|
|
|
|
tmpl.bind = 0;
|
|
|
|
|
tmpl.usage = PIPE_USAGE_STAGING;
|
|
|
|
|
tmpl.flags = 0;
|
2021-11-03 17:27:09 +00:00
|
|
|
|
tmpl.width0 = trans->base.b.layer_stride;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
tmpl.height0 = 1;
|
|
|
|
|
tmpl.depth0 = 1;
|
|
|
|
|
tmpl.array_size = 1;
|
|
|
|
|
|
|
|
|
|
local_resource depth_buffer(pscreen, &tmpl);
|
|
|
|
|
if (!depth_buffer) {
|
|
|
|
|
debug_printf("Allocating staging buffer for depth failed\n");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!transfer_image_to_buf(ctx, res, depth_buffer, trans, 0))
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
tmpl.format = PIPE_FORMAT_R8_UINT;
|
|
|
|
|
|
|
|
|
|
local_resource stencil_buffer(pscreen, &tmpl);
|
|
|
|
|
if (!stencil_buffer) {
|
|
|
|
|
debug_printf("Allocating staging buffer for stencilfailed\n");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!transfer_image_to_buf(ctx, res, stencil_buffer, trans, 1))
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
d3d12_flush_cmdlist_and_wait(ctx);
|
|
|
|
|
|
2021-12-03 18:45:20 +00:00
|
|
|
|
uint8_t *depth_ptr = (uint8_t *)depth_buffer.map();
|
2019-05-26 09:43:12 +01:00
|
|
|
|
if (!depth_ptr) {
|
|
|
|
|
debug_printf("Mapping staging depth buffer failed\n");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t *stencil_ptr = (uint8_t *)stencil_buffer.map();
|
|
|
|
|
if (!stencil_ptr) {
|
|
|
|
|
debug_printf("Mapping staging stencil buffer failed\n");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-03 18:45:20 +00:00
|
|
|
|
uint8_t *buf = (uint8_t *)malloc(trans->zs_cpu_copy_layer_stride);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
if (!buf)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
trans->data = buf;
|
|
|
|
|
|
2021-11-03 17:23:14 +00:00
|
|
|
|
switch (res->base.b.format) {
|
2019-05-26 09:43:12 +01:00
|
|
|
|
case PIPE_FORMAT_Z24_UNORM_S8_UINT:
|
2021-12-03 18:45:20 +00:00
|
|
|
|
if (screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED) {
|
|
|
|
|
depth_ptr += trans->base.b.box.y * trans->base.b.stride + trans->base.b.box.x * 4;
|
|
|
|
|
stencil_ptr += trans->base.b.box.y * trans->base.b.stride + trans->base.b.box.x * 4;
|
|
|
|
|
}
|
|
|
|
|
util_format_z24_unorm_s8_uint_pack_separate(buf, trans->zs_cpu_copy_stride,
|
2021-11-03 17:27:09 +00:00
|
|
|
|
(uint32_t *)depth_ptr, trans->base.b.stride,
|
|
|
|
|
stencil_ptr, trans->base.b.stride,
|
|
|
|
|
trans->base.b.box.width, trans->base.b.box.height);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
break;
|
|
|
|
|
case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
|
2021-12-03 18:45:20 +00:00
|
|
|
|
if (screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED) {
|
|
|
|
|
depth_ptr += trans->base.b.box.y * trans->base.b.stride + trans->base.b.box.x * 4;
|
|
|
|
|
stencil_ptr += trans->base.b.box.y * trans->base.b.stride + trans->base.b.box.x;
|
|
|
|
|
}
|
|
|
|
|
util_format_z32_float_s8x24_uint_pack_z_float(buf, trans->zs_cpu_copy_stride,
|
2021-11-03 17:27:09 +00:00
|
|
|
|
(float *)depth_ptr, trans->base.b.stride,
|
|
|
|
|
trans->base.b.box.width, trans->base.b.box.height);
|
2021-12-03 18:45:20 +00:00
|
|
|
|
util_format_z32_float_s8x24_uint_pack_s_8uint(buf, trans->zs_cpu_copy_stride,
|
2021-11-03 17:27:09 +00:00
|
|
|
|
stencil_ptr, trans->base.b.stride,
|
|
|
|
|
trans->base.b.box.width, trans->base.b.box.height);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
unreachable("Unsupported depth steancil format");
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return trans->data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void *
|
|
|
|
|
prepare_write_zs_surface(struct d3d12_resource *res,
|
|
|
|
|
const struct pipe_box *box,
|
|
|
|
|
struct d3d12_transfer *trans)
|
|
|
|
|
{
|
2021-12-03 18:45:20 +00:00
|
|
|
|
struct d3d12_screen *screen = d3d12_screen(res->base.b.screen);
|
|
|
|
|
prepare_zs_layer_strides(screen, res, box, trans);
|
2021-11-03 17:27:09 +00:00
|
|
|
|
uint32_t *buf = (uint32_t *)malloc(trans->base.b.layer_stride);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
if (!buf)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
trans->data = buf;
|
|
|
|
|
return trans->data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
write_zs_surface(struct pipe_context *pctx, struct d3d12_resource *res,
|
|
|
|
|
struct d3d12_transfer *trans)
|
|
|
|
|
{
|
2021-12-03 18:45:20 +00:00
|
|
|
|
struct d3d12_screen *screen = d3d12_screen(res->base.b.screen);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
struct pipe_resource tmpl;
|
|
|
|
|
memset(&tmpl, 0, sizeof tmpl);
|
|
|
|
|
tmpl.target = PIPE_BUFFER;
|
|
|
|
|
tmpl.format = PIPE_FORMAT_R32_UNORM;
|
|
|
|
|
tmpl.bind = 0;
|
|
|
|
|
tmpl.usage = PIPE_USAGE_STAGING;
|
|
|
|
|
tmpl.flags = 0;
|
2021-11-03 17:27:09 +00:00
|
|
|
|
tmpl.width0 = trans->base.b.layer_stride;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
tmpl.height0 = 1;
|
|
|
|
|
tmpl.depth0 = 1;
|
|
|
|
|
tmpl.array_size = 1;
|
|
|
|
|
|
|
|
|
|
local_resource depth_buffer(pctx->screen, &tmpl);
|
|
|
|
|
if (!depth_buffer) {
|
|
|
|
|
debug_printf("Allocating staging buffer for depth failed\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
local_resource stencil_buffer(pctx->screen, &tmpl);
|
|
|
|
|
if (!stencil_buffer) {
|
|
|
|
|
debug_printf("Allocating staging buffer for depth failed\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-03 18:45:20 +00:00
|
|
|
|
uint8_t *depth_ptr = (uint8_t *)depth_buffer.map();
|
2019-05-26 09:43:12 +01:00
|
|
|
|
if (!depth_ptr) {
|
|
|
|
|
debug_printf("Mapping staging depth buffer failed\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t *stencil_ptr = (uint8_t *)stencil_buffer.map();
|
|
|
|
|
if (!stencil_ptr) {
|
|
|
|
|
debug_printf("Mapping staging stencil buffer failed\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-03 17:23:14 +00:00
|
|
|
|
switch (res->base.b.format) {
|
2019-05-26 09:43:12 +01:00
|
|
|
|
case PIPE_FORMAT_Z24_UNORM_S8_UINT:
|
2021-12-03 18:45:20 +00:00
|
|
|
|
if (screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED) {
|
|
|
|
|
depth_ptr += trans->base.b.box.y * trans->base.b.stride + trans->base.b.box.x * 4;
|
|
|
|
|
stencil_ptr += trans->base.b.box.y * trans->base.b.stride + trans->base.b.box.x * 4;
|
|
|
|
|
}
|
2021-11-03 17:27:09 +00:00
|
|
|
|
util_format_z32_unorm_unpack_z_32unorm((uint32_t *)depth_ptr, trans->base.b.stride, (uint8_t*)trans->data,
|
2021-12-03 18:45:20 +00:00
|
|
|
|
trans->zs_cpu_copy_stride, trans->base.b.box.width,
|
2021-11-03 17:27:09 +00:00
|
|
|
|
trans->base.b.box.height);
|
|
|
|
|
util_format_z24_unorm_s8_uint_unpack_s_8uint(stencil_ptr, trans->base.b.stride, (uint8_t*)trans->data,
|
2021-12-03 18:45:20 +00:00
|
|
|
|
trans->zs_cpu_copy_stride, trans->base.b.box.width,
|
2021-11-03 17:27:09 +00:00
|
|
|
|
trans->base.b.box.height);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
break;
|
|
|
|
|
case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
|
2021-12-03 18:45:20 +00:00
|
|
|
|
if (screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED) {
|
|
|
|
|
depth_ptr += trans->base.b.box.y * trans->base.b.stride + trans->base.b.box.x * 4;
|
|
|
|
|
stencil_ptr += trans->base.b.box.y * trans->base.b.stride + trans->base.b.box.x;
|
|
|
|
|
}
|
2021-11-03 17:27:09 +00:00
|
|
|
|
util_format_z32_float_s8x24_uint_unpack_z_float((float *)depth_ptr, trans->base.b.stride, (uint8_t*)trans->data,
|
2021-12-03 18:45:20 +00:00
|
|
|
|
trans->zs_cpu_copy_stride, trans->base.b.box.width,
|
2021-11-03 17:27:09 +00:00
|
|
|
|
trans->base.b.box.height);
|
|
|
|
|
util_format_z32_float_s8x24_uint_unpack_s_8uint(stencil_ptr, trans->base.b.stride, (uint8_t*)trans->data,
|
2021-12-03 18:45:20 +00:00
|
|
|
|
trans->zs_cpu_copy_stride, trans->base.b.box.width,
|
2021-11-03 17:27:09 +00:00
|
|
|
|
trans->base.b.box.height);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
unreachable("Unsupported depth steancil format");
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
stencil_buffer.unmap();
|
|
|
|
|
depth_buffer.unmap();
|
|
|
|
|
|
|
|
|
|
transfer_buf_to_image(d3d12_context(pctx), res, depth_buffer, trans, 0);
|
|
|
|
|
transfer_buf_to_image(d3d12_context(pctx), res, stencil_buffer, trans, 1);
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-14 19:42:49 +00:00
|
|
|
|
#define BUFFER_MAP_ALIGNMENT 64
|
|
|
|
|
|
2019-05-26 09:43:12 +01:00
|
|
|
|
static void *
|
|
|
|
|
d3d12_transfer_map(struct pipe_context *pctx,
|
|
|
|
|
struct pipe_resource *pres,
|
|
|
|
|
unsigned level,
|
|
|
|
|
unsigned usage,
|
|
|
|
|
const struct pipe_box *box,
|
|
|
|
|
struct pipe_transfer **transfer)
|
|
|
|
|
{
|
|
|
|
|
struct d3d12_context *ctx = d3d12_context(pctx);
|
|
|
|
|
struct d3d12_resource *res = d3d12_resource(pres);
|
2021-12-03 18:45:20 +00:00
|
|
|
|
struct d3d12_screen *screen = d3d12_screen(pres->screen);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
|
|
|
|
if (usage & PIPE_MAP_DIRECTLY || !res->bo)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2021-11-03 17:32:04 +00:00
|
|
|
|
slab_child_pool* transfer_pool = (usage & TC_TRANSFER_MAP_THREADED_UNSYNC) ?
|
|
|
|
|
&ctx->transfer_pool_unsync : &ctx->transfer_pool;
|
2022-03-08 10:56:31 +00:00
|
|
|
|
struct d3d12_transfer *trans = (struct d3d12_transfer *)slab_zalloc(transfer_pool);
|
2021-11-03 17:27:09 +00:00
|
|
|
|
struct pipe_transfer *ptrans = &trans->base.b;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
if (!trans)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
ptrans->level = level;
|
|
|
|
|
ptrans->usage = (enum pipe_map_flags)usage;
|
|
|
|
|
ptrans->box = *box;
|
|
|
|
|
|
|
|
|
|
D3D12_RANGE range;
|
|
|
|
|
range.Begin = 0;
|
|
|
|
|
|
|
|
|
|
void *ptr;
|
2021-11-03 17:23:14 +00:00
|
|
|
|
if (can_map_directly(&res->base.b)) {
|
2019-05-26 09:43:12 +01:00
|
|
|
|
if (pres->target == PIPE_BUFFER) {
|
|
|
|
|
ptrans->stride = 0;
|
|
|
|
|
ptrans->layer_stride = 0;
|
|
|
|
|
} else {
|
|
|
|
|
ptrans->stride = util_format_get_stride(pres->format, box->width);
|
|
|
|
|
ptrans->layer_stride = util_format_get_2d_size(pres->format,
|
|
|
|
|
ptrans->stride,
|
|
|
|
|
box->height);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
range = linear_range(box, ptrans->stride, ptrans->layer_stride);
|
2022-04-26 20:48:20 +01:00
|
|
|
|
if (!synchronize(ctx, res, usage, &range)) {
|
|
|
|
|
slab_free(transfer_pool, trans);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
return NULL;
|
2022-04-26 20:48:20 +01:00
|
|
|
|
}
|
2019-05-26 09:43:12 +01:00
|
|
|
|
ptr = d3d12_bo_map(res->bo, &range);
|
|
|
|
|
} else if (unlikely(pres->format == PIPE_FORMAT_Z24_UNORM_S8_UINT ||
|
|
|
|
|
pres->format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT)) {
|
|
|
|
|
if (usage & PIPE_MAP_READ) {
|
|
|
|
|
ptr = read_zs_surface(ctx, res, box, trans);
|
|
|
|
|
} else if (usage & PIPE_MAP_WRITE){
|
|
|
|
|
ptr = prepare_write_zs_surface(res, box, trans);
|
2020-11-26 01:15:11 +00:00
|
|
|
|
} else {
|
|
|
|
|
ptr = nullptr;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
}
|
2022-05-02 18:14:29 +01:00
|
|
|
|
} else if(util_format_is_yuv(res->overall_format)) {
|
|
|
|
|
|
|
|
|
|
/* Get planes information*/
|
|
|
|
|
|
|
|
|
|
unsigned num_planes = util_format_get_num_planes(res->overall_format);
|
2022-05-18 17:13:14 +01:00
|
|
|
|
pipe_resource *planes[d3d12_max_planes];
|
|
|
|
|
unsigned int strides[d3d12_max_planes];
|
|
|
|
|
unsigned int layer_strides[d3d12_max_planes];
|
|
|
|
|
unsigned int offsets[d3d12_max_planes];
|
2022-05-02 18:14:29 +01:00
|
|
|
|
unsigned staging_res_size = 0;
|
|
|
|
|
|
|
|
|
|
d3d12_resource_get_planes_info(
|
|
|
|
|
pres,
|
|
|
|
|
num_planes,
|
|
|
|
|
planes,
|
|
|
|
|
strides,
|
|
|
|
|
layer_strides,
|
|
|
|
|
offsets,
|
|
|
|
|
&staging_res_size
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/* Allocate a buffer for all the planes to fit in adjacent memory*/
|
|
|
|
|
|
|
|
|
|
pipe_resource_usage staging_usage = (usage & (PIPE_MAP_READ | PIPE_MAP_READ_WRITE)) ?
|
|
|
|
|
PIPE_USAGE_STAGING : PIPE_USAGE_STREAM;
|
|
|
|
|
trans->staging_res = pipe_buffer_create(pctx->screen, 0,
|
|
|
|
|
staging_usage,
|
|
|
|
|
staging_res_size);
|
|
|
|
|
if (!trans->staging_res)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
struct d3d12_resource *staging_res = d3d12_resource(trans->staging_res);
|
|
|
|
|
|
|
|
|
|
/* Readback contents into the buffer allocation now if map was intended for read*/
|
|
|
|
|
|
|
|
|
|
/* Read all planes if readback needed*/
|
|
|
|
|
if (usage & PIPE_MAP_READ) {
|
|
|
|
|
pipe_box original_box = ptrans->box;
|
|
|
|
|
for (uint plane_slice = 0; plane_slice < num_planes; ++plane_slice) {
|
|
|
|
|
/* Adjust strides, offsets, box to the corresponding plane for the copytexture operation*/
|
|
|
|
|
d3d12_adjust_transfer_dimensions_for_plane(res,
|
|
|
|
|
plane_slice,
|
|
|
|
|
strides[plane_slice],
|
|
|
|
|
layer_strides[plane_slice],
|
|
|
|
|
offsets[plane_slice],
|
|
|
|
|
&original_box,
|
|
|
|
|
ptrans/*inout*/);
|
|
|
|
|
/* Perform the readback*/
|
|
|
|
|
if(!transfer_image_to_buf(ctx, d3d12_resource(planes[plane_slice]), staging_res, trans, 0)){
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
d3d12_flush_cmdlist_and_wait(ctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Map the whole staging buffer containing all the planes contiguously*/
|
|
|
|
|
/* Just offset the resulting ptr to the according plane offset*/
|
|
|
|
|
|
|
|
|
|
range.End = staging_res_size - range.Begin;
|
|
|
|
|
uint8_t* all_planes_map = (uint8_t*) d3d12_bo_map(staging_res->bo, &range);
|
|
|
|
|
|
|
|
|
|
ptrans->stride = strides[res->plane_slice];
|
|
|
|
|
ptrans->layer_stride = layer_strides[res->plane_slice];
|
|
|
|
|
ptr = all_planes_map + offsets[res->plane_slice];
|
|
|
|
|
|
2019-05-26 09:43:12 +01:00
|
|
|
|
} else {
|
|
|
|
|
ptrans->stride = align(util_format_get_stride(pres->format, box->width),
|
|
|
|
|
D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
|
|
|
|
|
ptrans->layer_stride = util_format_get_2d_size(pres->format,
|
|
|
|
|
ptrans->stride,
|
|
|
|
|
box->height);
|
|
|
|
|
|
2021-11-03 17:23:14 +00:00
|
|
|
|
if (res->base.b.target != PIPE_TEXTURE_3D)
|
2019-05-26 09:43:12 +01:00
|
|
|
|
ptrans->layer_stride = align(ptrans->layer_stride,
|
|
|
|
|
D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
|
|
|
|
|
|
2021-12-03 18:45:20 +00:00
|
|
|
|
if (util_format_has_depth(util_format_description(pres->format)) &&
|
|
|
|
|
screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED) {
|
|
|
|
|
trans->zs_cpu_copy_stride = ptrans->stride;
|
|
|
|
|
trans->zs_cpu_copy_layer_stride = ptrans->layer_stride;
|
|
|
|
|
|
|
|
|
|
ptrans->stride = align(util_format_get_stride(pres->format, pres->width0),
|
|
|
|
|
D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
|
|
|
|
|
ptrans->layer_stride = util_format_get_2d_size(pres->format,
|
|
|
|
|
ptrans->stride,
|
|
|
|
|
pres->height0);
|
|
|
|
|
|
|
|
|
|
range.Begin = box->y * ptrans->stride +
|
|
|
|
|
box->x * util_format_get_blocksize(pres->format);
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-14 19:42:49 +00:00
|
|
|
|
unsigned staging_res_size = ptrans->layer_stride * box->depth;
|
2021-11-03 17:23:14 +00:00
|
|
|
|
if (res->base.b.target == PIPE_BUFFER) {
|
2020-12-14 19:42:49 +00:00
|
|
|
|
/* 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;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-17 18:29:45 +00:00
|
|
|
|
pipe_resource_usage staging_usage = (usage & (PIPE_MAP_DISCARD_RANGE | PIPE_MAP_DISCARD_WHOLE_RESOURCE)) ?
|
|
|
|
|
PIPE_USAGE_STREAM : PIPE_USAGE_STAGING;
|
2020-12-14 19:53:39 +00:00
|
|
|
|
|
2019-05-26 09:43:12 +01:00
|
|
|
|
trans->staging_res = pipe_buffer_create(pctx->screen, 0,
|
2020-12-14 19:53:39 +00:00
|
|
|
|
staging_usage,
|
2020-12-14 19:42:49 +00:00
|
|
|
|
staging_res_size);
|
2022-04-26 20:48:20 +01:00
|
|
|
|
if (!trans->staging_res) {
|
|
|
|
|
slab_free(transfer_pool, trans);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
return NULL;
|
2022-04-26 20:48:20 +01:00
|
|
|
|
}
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
|
|
|
|
struct d3d12_resource *staging_res = d3d12_resource(trans->staging_res);
|
|
|
|
|
|
2022-01-17 18:29:45 +00:00
|
|
|
|
if ((usage & (PIPE_MAP_DISCARD_RANGE | PIPE_MAP_DISCARD_WHOLE_RESOURCE | TC_TRANSFER_MAP_THREADED_UNSYNC)) == 0) {
|
2020-12-14 19:42:49 +00:00
|
|
|
|
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)
|
2019-05-26 09:43:12 +01:00
|
|
|
|
return NULL;
|
|
|
|
|
d3d12_flush_cmdlist_and_wait(ctx);
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-14 19:42:49 +00:00
|
|
|
|
range.End = staging_res_size - range.Begin;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
|
|
|
|
ptr = d3d12_bo_map(staging_res->bo, &range);
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-26 20:48:20 +01:00
|
|
|
|
pipe_resource_reference(&ptrans->resource, pres);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
*transfer = ptrans;
|
|
|
|
|
return ptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
d3d12_transfer_unmap(struct pipe_context *pctx,
|
|
|
|
|
struct pipe_transfer *ptrans)
|
|
|
|
|
{
|
2022-05-02 18:14:29 +01:00
|
|
|
|
struct d3d12_context *ctx = d3d12_context(pctx);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
struct d3d12_resource *res = d3d12_resource(ptrans->resource);
|
|
|
|
|
struct d3d12_transfer *trans = (struct d3d12_transfer *)ptrans;
|
|
|
|
|
D3D12_RANGE range = { 0, 0 };
|
|
|
|
|
|
|
|
|
|
if (trans->data != nullptr) {
|
2021-11-03 17:27:09 +00:00
|
|
|
|
if (trans->base.b.usage & PIPE_MAP_WRITE)
|
2019-05-26 09:43:12 +01:00
|
|
|
|
write_zs_surface(pctx, res, trans);
|
|
|
|
|
free(trans->data);
|
|
|
|
|
} else if (trans->staging_res) {
|
2022-05-02 18:14:29 +01:00
|
|
|
|
if(util_format_is_yuv(res->overall_format)) {
|
|
|
|
|
|
|
|
|
|
/* Get planes information*/
|
|
|
|
|
unsigned num_planes = util_format_get_num_planes(res->overall_format);
|
2022-05-18 17:13:14 +01:00
|
|
|
|
pipe_resource *planes[d3d12_max_planes];
|
|
|
|
|
unsigned int strides[d3d12_max_planes];
|
|
|
|
|
unsigned int layer_strides[d3d12_max_planes];
|
|
|
|
|
unsigned int offsets[d3d12_max_planes];
|
2022-05-02 18:14:29 +01:00
|
|
|
|
unsigned staging_res_size = 0;
|
|
|
|
|
|
|
|
|
|
d3d12_resource_get_planes_info(
|
|
|
|
|
ptrans->resource,
|
|
|
|
|
num_planes,
|
|
|
|
|
planes,
|
|
|
|
|
strides,
|
|
|
|
|
layer_strides,
|
|
|
|
|
offsets,
|
|
|
|
|
&staging_res_size
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/* Flush the changed contents into the GPU texture*/
|
|
|
|
|
|
|
|
|
|
/* In theory we should just flush only the contents for the plane*/
|
|
|
|
|
/* requested in res->plane_slice, but the VAAPI frontend has this*/
|
|
|
|
|
/* behaviour in which they assume that mapping the first plane of*/
|
|
|
|
|
/* NV12, P010, etc resources will will give them a buffer containing*/
|
|
|
|
|
/* both Y and UV planes contigously in vaDeriveImage and then vaMapBuffer*/
|
|
|
|
|
/* so, flush them all*/
|
|
|
|
|
|
|
|
|
|
struct d3d12_resource *staging_res = d3d12_resource(trans->staging_res);
|
|
|
|
|
if (trans->base.b.usage & PIPE_MAP_WRITE) {
|
|
|
|
|
assert(ptrans->box.x >= 0);
|
|
|
|
|
range.Begin = res->base.b.target == PIPE_BUFFER ?
|
|
|
|
|
(unsigned)ptrans->box.x % BUFFER_MAP_ALIGNMENT : 0;
|
|
|
|
|
range.End = staging_res->base.b.width0 - range.Begin;
|
|
|
|
|
|
|
|
|
|
d3d12_bo_unmap(staging_res->bo, &range);
|
|
|
|
|
pipe_box original_box = ptrans->box;
|
|
|
|
|
for (uint plane_slice = 0; plane_slice < num_planes; ++plane_slice) {
|
|
|
|
|
/* Adjust strides, offsets to the corresponding plane for the copytexture operation*/
|
|
|
|
|
d3d12_adjust_transfer_dimensions_for_plane(res,
|
|
|
|
|
plane_slice,
|
|
|
|
|
strides[plane_slice],
|
|
|
|
|
layer_strides[plane_slice],
|
|
|
|
|
offsets[plane_slice],
|
|
|
|
|
&original_box,
|
|
|
|
|
ptrans/*inout*/);
|
|
|
|
|
|
|
|
|
|
transfer_buf_to_image(ctx, d3d12_resource(planes[plane_slice]), staging_res, trans, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
2022-05-02 18:14:29 +01:00
|
|
|
|
pipe_resource_reference(&trans->staging_res, NULL);
|
|
|
|
|
} else {
|
|
|
|
|
struct d3d12_resource *staging_res = d3d12_resource(trans->staging_res);
|
|
|
|
|
if (trans->base.b.usage & PIPE_MAP_WRITE) {
|
|
|
|
|
assert(ptrans->box.x >= 0);
|
|
|
|
|
range.Begin = res->base.b.target == PIPE_BUFFER ?
|
|
|
|
|
(unsigned)ptrans->box.x % BUFFER_MAP_ALIGNMENT : 0;
|
|
|
|
|
range.End = staging_res->base.b.width0 - range.Begin;
|
|
|
|
|
}
|
|
|
|
|
d3d12_bo_unmap(staging_res->bo, &range);
|
|
|
|
|
|
|
|
|
|
if (trans->base.b.usage & PIPE_MAP_WRITE) {
|
|
|
|
|
struct d3d12_context *ctx = d3d12_context(pctx);
|
|
|
|
|
if (res->base.b.target == PIPE_BUFFER) {
|
|
|
|
|
uint64_t dst_offset = trans->base.b.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);
|
|
|
|
|
}
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
2022-05-02 18:14:29 +01:00
|
|
|
|
pipe_resource_reference(&trans->staging_res, NULL);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
}
|
|
|
|
|
} else {
|
2021-11-03 17:27:09 +00:00
|
|
|
|
if (trans->base.b.usage & PIPE_MAP_WRITE) {
|
2019-05-26 09:43:12 +01:00
|
|
|
|
range.Begin = ptrans->box.x;
|
|
|
|
|
range.End = ptrans->box.x + ptrans->box.width;
|
|
|
|
|
}
|
|
|
|
|
d3d12_bo_unmap(res->bo, &range);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pipe_resource_reference(&ptrans->resource, NULL);
|
|
|
|
|
slab_free(&d3d12_context(pctx)->transfer_pool, ptrans);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
d3d12_context_resource_init(struct pipe_context *pctx)
|
|
|
|
|
{
|
2021-05-05 20:27:46 +01:00
|
|
|
|
pctx->buffer_map = d3d12_transfer_map;
|
|
|
|
|
pctx->buffer_unmap = d3d12_transfer_unmap;
|
|
|
|
|
pctx->texture_map = d3d12_transfer_map;
|
|
|
|
|
pctx->texture_unmap = d3d12_transfer_unmap;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
|
|
|
|
pctx->transfer_flush_region = u_default_transfer_flush_region;
|
|
|
|
|
pctx->buffer_subdata = u_default_buffer_subdata;
|
|
|
|
|
pctx->texture_subdata = u_default_texture_subdata;
|
|
|
|
|
}
|