1/* 2 * Copyright © Microsoft Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23 24#include "d3d12_resource.h" 25 26#include "d3d12_blit.h" 27#include "d3d12_context.h" 28#include "d3d12_format.h" 29#include "d3d12_screen.h" 30#include "d3d12_debug.h" 31 32#include "pipebuffer/pb_bufmgr.h" 33#include "util/slab.h" 34#include "util/format/u_format.h" 35#include "util/u_inlines.h" 36#include "util/u_memory.h" 37#include "util/format/u_format_zs.h" 38 39#include "frontend/sw_winsys.h" 40 41#include <dxguids/dxguids.h> 42#include <memory> 43 44#ifndef GENERIC_ALL 45 // This is only added to winadapter.h in newer DirectX-Headers 46#define GENERIC_ALL 0x10000000L 47#endif 48 49static bool 50can_map_directly(struct pipe_resource *pres) 51{ 52 return pres->target == PIPE_BUFFER && 53 pres->usage != PIPE_USAGE_DEFAULT && 54 pres->usage != PIPE_USAGE_IMMUTABLE; 55} 56 57static void 58init_valid_range(struct d3d12_resource *res) 59{ 60 if (can_map_directly(&res->base.b)) 61 util_range_init(&res->valid_buffer_range); 62} 63 64static void 65d3d12_resource_destroy(struct pipe_screen *pscreen, 66 struct pipe_resource *presource) 67{ 68 struct d3d12_resource *resource = d3d12_resource(presource); 69 threaded_resource_deinit(presource); 70 if (can_map_directly(presource)) 71 util_range_destroy(&resource->valid_buffer_range); 72 if (resource->bo) 73 d3d12_bo_unreference(resource->bo); 74 FREE(resource); 75} 76 77static bool 78resource_is_busy(struct d3d12_context *ctx, 79 struct d3d12_resource *res, 80 bool want_to_write) 81{ 82 if (d3d12_batch_has_references(d3d12_current_batch(ctx), res->bo, want_to_write)) 83 return true; 84 85 bool busy = false; 86 d3d12_foreach_submitted_batch(ctx, batch) { 87 if (!d3d12_reset_batch(ctx, batch, 0)) 88 busy |= d3d12_batch_has_references(batch, res->bo, want_to_write); 89 } 90 return busy; 91} 92 93void 94d3d12_resource_wait_idle(struct d3d12_context *ctx, 95 struct d3d12_resource *res, 96 bool want_to_write) 97{ 98 if (d3d12_batch_has_references(d3d12_current_batch(ctx), res->bo, want_to_write)) { 99 d3d12_flush_cmdlist_and_wait(ctx); 100 } else { 101 d3d12_foreach_submitted_batch(ctx, batch) { 102 if (d3d12_batch_has_references(batch, res->bo, want_to_write)) 103 d3d12_reset_batch(ctx, batch, PIPE_TIMEOUT_INFINITE); 104 } 105 } 106} 107 108void 109d3d12_resource_release(struct d3d12_resource *resource) 110{ 111 if (!resource->bo) 112 return; 113 d3d12_bo_unreference(resource->bo); 114 resource->bo = NULL; 115} 116 117static bool 118init_buffer(struct d3d12_screen *screen, 119 struct d3d12_resource *res, 120 const struct pipe_resource *templ) 121{ 122 struct pb_desc buf_desc; 123 struct pb_manager *bufmgr; 124 struct pb_buffer *buf; 125 126 /* Assert that we don't want to create a buffer with one of the emulated 127 * formats, these are (currently) only supported when passing the vertex 128 * element state */ 129 assert(templ->format == d3d12_emulated_vtx_format(templ->format)); 130 131 switch (templ->usage) { 132 case PIPE_USAGE_DEFAULT: 133 case PIPE_USAGE_IMMUTABLE: 134 bufmgr = screen->cache_bufmgr; 135 buf_desc.usage = (pb_usage_flags)PB_USAGE_GPU_READ_WRITE; 136 break; 137 case PIPE_USAGE_DYNAMIC: 138 case PIPE_USAGE_STREAM: 139 bufmgr = screen->slab_bufmgr; 140 buf_desc.usage = (pb_usage_flags)(PB_USAGE_CPU_WRITE | PB_USAGE_GPU_READ); 141 break; 142 case PIPE_USAGE_STAGING: 143 bufmgr = screen->readback_slab_bufmgr; 144 buf_desc.usage = (pb_usage_flags)(PB_USAGE_GPU_WRITE | PB_USAGE_CPU_READ_WRITE); 145 break; 146 default: 147 unreachable("Invalid pipe usage"); 148 } 149 150 /* We can't suballocate buffers that might be bound as a sampler view, *only* 151 * because in the case of R32G32B32 formats (12 bytes per pixel), it's not possible 152 * to guarantee the offset will be divisible. 153 */ 154 if (templ->bind & PIPE_BIND_SAMPLER_VIEW) 155 bufmgr = screen->cache_bufmgr; 156 157 buf_desc.alignment = D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT; 158 res->dxgi_format = DXGI_FORMAT_UNKNOWN; 159 buf = bufmgr->create_buffer(bufmgr, templ->width0, &buf_desc); 160 if (!buf) 161 return false; 162 res->bo = d3d12_bo_wrap_buffer(screen, buf); 163 164 return true; 165} 166 167static bool 168init_texture(struct d3d12_screen *screen, 169 struct d3d12_resource *res, 170 const struct pipe_resource *templ, 171 ID3D12Heap *heap, 172 uint64_t placed_offset) 173{ 174 ID3D12Resource *d3d12_res; 175 176 res->mip_levels = templ->last_level + 1; 177 res->dxgi_format = d3d12_get_format(templ->format); 178 179 D3D12_RESOURCE_DESC desc; 180 desc.Format = res->dxgi_format; 181 desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT; 182 desc.Width = templ->width0; 183 desc.Height = templ->height0; 184 desc.DepthOrArraySize = templ->array_size; 185 desc.MipLevels = templ->last_level + 1; 186 187 desc.SampleDesc.Count = MAX2(templ->nr_samples, 1); 188 desc.SampleDesc.Quality = 0; 189 190 desc.Flags = D3D12_RESOURCE_FLAG_NONE; 191 desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; 192 193 switch (templ->target) { 194 case PIPE_BUFFER: 195 desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; 196 desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; 197 desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; 198 break; 199 200 case PIPE_TEXTURE_1D: 201 case PIPE_TEXTURE_1D_ARRAY: 202 desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE1D; 203 break; 204 205 case PIPE_TEXTURE_CUBE: 206 case PIPE_TEXTURE_CUBE_ARRAY: 207 desc.DepthOrArraySize *= 6; 208 FALLTHROUGH; 209 case PIPE_TEXTURE_2D: 210 case PIPE_TEXTURE_2D_ARRAY: 211 case PIPE_TEXTURE_RECT: 212 desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; 213 break; 214 215 case PIPE_TEXTURE_3D: 216 desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE3D; 217 desc.DepthOrArraySize = templ->depth0; 218 break; 219 220 default: 221 unreachable("Invalid texture type"); 222 } 223 224 if (templ->bind & PIPE_BIND_SHADER_BUFFER) 225 desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; 226 227 if (templ->bind & PIPE_BIND_RENDER_TARGET) 228 desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; 229 230 if (templ->bind & PIPE_BIND_DEPTH_STENCIL) { 231 desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; 232 233 /* Sadly, we can't set D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE in the 234 * case where PIPE_BIND_SAMPLER_VIEW isn't set, because that would 235 * prevent us from using the resource with u_blitter, which requires 236 * sneaking in sampler-usage throught the back-door. 237 */ 238 } 239 240 if (screen->support_shader_images && templ->nr_samples <= 1) { 241 /* Ideally, we'd key off of PIPE_BIND_SHADER_IMAGE for this, but it doesn't 242 * seem to be set properly. So, all UAV-capable resources need the UAV flag. 243 */ 244 D3D12_FEATURE_DATA_FORMAT_SUPPORT support = { desc.Format }; 245 if (SUCCEEDED(screen->dev->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &support, sizeof(support))) && 246 (support.Support2 & (D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD | D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE)) == 247 (D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD | D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE)) { 248 desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; 249 desc.Format = d3d12_get_typeless_format(templ->format); 250 } 251 } 252 253 if (templ->bind & (PIPE_BIND_SCANOUT | PIPE_BIND_LINEAR)) 254 desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; 255 256 HRESULT hres = E_FAIL; 257 enum d3d12_residency_status init_residency; 258 259 if (heap) { 260 init_residency = d3d12_permanently_resident; 261 hres = screen->dev->CreatePlacedResource(heap, 262 placed_offset, 263 &desc, 264 D3D12_RESOURCE_STATE_COMMON, 265 nullptr, 266 IID_PPV_ARGS(&d3d12_res)); 267 } else { 268 D3D12_HEAP_PROPERTIES heap_pris = GetCustomHeapProperties(screen->dev, D3D12_HEAP_TYPE_DEFAULT); 269 270 D3D12_HEAP_FLAGS heap_flags = screen->support_create_not_resident ? 271 D3D12_HEAP_FLAG_CREATE_NOT_RESIDENT : D3D12_HEAP_FLAG_NONE; 272 init_residency = screen->support_create_not_resident ? d3d12_evicted : d3d12_resident; 273 274 hres = screen->dev->CreateCommittedResource(&heap_pris, 275 heap_flags, 276 &desc, 277 D3D12_RESOURCE_STATE_COMMON, 278 NULL, 279 IID_PPV_ARGS(&d3d12_res)); 280 } 281 282 if (FAILED(hres)) 283 return false; 284 285 if (screen->winsys && (templ->bind & PIPE_BIND_DISPLAY_TARGET)) { 286 struct sw_winsys *winsys = screen->winsys; 287 res->dt = winsys->displaytarget_create(screen->winsys, 288 res->base.b.bind, 289 res->base.b.format, 290 templ->width0, 291 templ->height0, 292 64, NULL, 293 &res->dt_stride); 294 } 295 296 res->bo = d3d12_bo_wrap_res(screen, d3d12_res, init_residency); 297 298 return true; 299} 300 301static void 302convert_planar_resource(struct d3d12_resource *res) 303{ 304 unsigned num_planes = util_format_get_num_planes(res->base.b.format); 305 if (num_planes <= 1 || res->base.b.next || !res->bo) 306 return; 307 308 struct pipe_resource *next = nullptr; 309 struct pipe_resource *planes[3] = { 310 &res->base.b, nullptr, nullptr 311 }; 312 for (int plane = num_planes - 1; plane >= 0; --plane) { 313 struct d3d12_resource *plane_res = d3d12_resource(planes[plane]); 314 if (!plane_res) { 315 plane_res = CALLOC_STRUCT(d3d12_resource); 316 *plane_res = *res; 317 d3d12_bo_reference(plane_res->bo); 318 pipe_reference_init(&plane_res->base.b.reference, 1); 319 threaded_resource_init(&plane_res->base.b, false); 320 } 321 322 plane_res->base.b.next = next; 323 next = &plane_res->base.b; 324 325 plane_res->plane_slice = plane; 326 plane_res->base.b.format = util_format_get_plane_format(res->base.b.format, plane); 327 plane_res->base.b.width0 = util_format_get_plane_width(res->base.b.format, plane, res->base.b.width0); 328 plane_res->base.b.height0 = util_format_get_plane_height(res->base.b.format, plane, res->base.b.height0); 329 330#if DEBUG 331 struct d3d12_screen *screen = d3d12_screen(res->base.b.screen); 332 D3D12_RESOURCE_DESC desc = GetDesc(res->bo->res); 333 D3D12_PLACED_SUBRESOURCE_FOOTPRINT placed_footprint = {}; 334 D3D12_SUBRESOURCE_FOOTPRINT *footprint = &placed_footprint.Footprint; 335 unsigned subresource = plane * desc.MipLevels * desc.DepthOrArraySize; 336 screen->dev->GetCopyableFootprints(&desc, subresource, 1, 0, &placed_footprint, nullptr, nullptr, nullptr); 337 assert(plane_res->base.b.width0 == footprint->Width); 338 assert(plane_res->base.b.height0 == footprint->Height); 339 assert(plane_res->base.b.depth0 == footprint->Depth); 340 assert(plane_res->first_plane == &res->base.b); 341#endif 342 } 343} 344 345static struct pipe_resource * 346d3d12_resource_create_or_place(struct d3d12_screen *screen, 347 struct d3d12_resource *res, 348 const struct pipe_resource *templ, 349 ID3D12Heap *heap, 350 uint64_t placed_offset) 351{ 352 bool ret; 353 354 res->base.b = *templ; 355 356 res->overall_format = templ->format; 357 res->plane_slice = 0; 358 res->first_plane = &res->base.b; 359 360 if (D3D12_DEBUG_RESOURCE & d3d12_debug) { 361 debug_printf("D3D12: Create %sresource %s@%d %dx%dx%d as:%d mip:%d\n", 362 templ->usage == PIPE_USAGE_STAGING ? "STAGING " :"", 363 util_format_name(templ->format), templ->nr_samples, 364 templ->width0, templ->height0, templ->depth0, 365 templ->array_size, templ->last_level); 366 } 367 368 pipe_reference_init(&res->base.b.reference, 1); 369 res->base.b.screen = &screen->base; 370 371 if (templ->target == PIPE_BUFFER && !heap) { 372 ret = init_buffer(screen, res, templ); 373 } else { 374 ret = init_texture(screen, res, templ, heap, placed_offset); 375 } 376 377 if (!ret) { 378 FREE(res); 379 return NULL; 380 } 381 382 init_valid_range(res); 383 threaded_resource_init(&res->base.b, 384 templ->usage == PIPE_USAGE_DEFAULT && 385 templ->target == PIPE_BUFFER); 386 387 memset(&res->bind_counts, 0, sizeof(d3d12_resource::bind_counts)); 388 389 convert_planar_resource(res); 390 391 return &res->base.b; 392} 393 394static struct pipe_resource * 395d3d12_resource_create(struct pipe_screen *pscreen, 396 const struct pipe_resource *templ) 397{ 398 struct d3d12_resource *res = CALLOC_STRUCT(d3d12_resource); 399 if (!res) 400 return NULL; 401 402 return d3d12_resource_create_or_place(d3d12_screen(pscreen), res, templ, nullptr, 0); 403} 404 405static struct pipe_resource * 406d3d12_resource_from_handle(struct pipe_screen *pscreen, 407 const struct pipe_resource *templ, 408 struct winsys_handle *handle, unsigned usage) 409{ 410 struct d3d12_screen *screen = d3d12_screen(pscreen); 411 if (handle->type != WINSYS_HANDLE_TYPE_D3D12_RES && 412 handle->type != WINSYS_HANDLE_TYPE_FD && 413 handle->type != WINSYS_HANDLE_TYPE_WIN32_NAME) 414 return NULL; 415 416 struct d3d12_resource *res = CALLOC_STRUCT(d3d12_resource); 417 if (!res) 418 return NULL; 419 420 if (templ && templ->next) { 421 struct d3d12_resource* next = d3d12_resource(templ->next); 422 if (next->bo) { 423 res->base.b = *templ; 424 res->bo = next->bo; 425 d3d12_bo_reference(res->bo); 426 } 427 } 428 429#ifdef _WIN32 430 HANDLE d3d_handle = handle->handle; 431#else 432 HANDLE d3d_handle = (HANDLE) (intptr_t) handle->handle; 433#endif 434 435#ifdef _WIN32 436 HANDLE d3d_handle_to_close = nullptr; 437 if (handle->type == WINSYS_HANDLE_TYPE_WIN32_NAME) { 438 screen->dev->OpenSharedHandleByName((LPCWSTR)handle->name, GENERIC_ALL, &d3d_handle_to_close); 439 d3d_handle = d3d_handle_to_close; 440 } 441#endif 442 443 ID3D12Resource *d3d12_res = nullptr; 444 ID3D12Heap *d3d12_heap = nullptr; 445 if (res->bo) { 446 d3d12_res = res->bo->res; 447 } else if (handle->type == WINSYS_HANDLE_TYPE_D3D12_RES) { 448 IUnknown *obj = (IUnknown *)handle->com_obj; 449 (void)obj->QueryInterface(&d3d12_res); 450 (void)obj->QueryInterface(&d3d12_heap); 451 obj->Release(); 452 } else { 453 screen->dev->OpenSharedHandle(d3d_handle, IID_PPV_ARGS(&d3d12_res)); 454 } 455 456#ifdef _WIN32 457 if (d3d_handle_to_close) { 458 CloseHandle(d3d_handle_to_close); 459 } 460#endif 461 462 D3D12_PLACED_SUBRESOURCE_FOOTPRINT placed_footprint = {}; 463 D3D12_SUBRESOURCE_FOOTPRINT *footprint = &placed_footprint.Footprint; 464 D3D12_RESOURCE_DESC incoming_res_desc; 465 466 if (!d3d12_res && !d3d12_heap) 467 goto invalid; 468 469 if (d3d12_heap) { 470 assert(templ); 471 assert(!res->bo); 472 assert(!d3d12_res); 473 return d3d12_resource_create_or_place(screen, res, templ, d3d12_heap, handle->offset); 474 } 475 476 pipe_reference_init(&res->base.b.reference, 1); 477 res->base.b.screen = pscreen; 478 incoming_res_desc = GetDesc(d3d12_res); 479 480 /* Get a description for this plane */ 481 if (templ && handle->format != templ->format) { 482 unsigned subresource = handle->plane * incoming_res_desc.MipLevels * incoming_res_desc.DepthOrArraySize; 483 screen->dev->GetCopyableFootprints(&incoming_res_desc, subresource, 1, 0, &placed_footprint, nullptr, nullptr, nullptr); 484 } else { 485 footprint->Format = incoming_res_desc.Format; 486 footprint->Width = incoming_res_desc.Width; 487 footprint->Height = incoming_res_desc.Height; 488 footprint->Depth = incoming_res_desc.DepthOrArraySize; 489 } 490 491 if (footprint->Width > UINT32_MAX || 492 footprint->Height > UINT16_MAX) { 493 debug_printf("d3d12: Importing resource too large\n"); 494 goto invalid; 495 } 496 res->base.b.width0 = incoming_res_desc.Width; 497 res->base.b.height0 = incoming_res_desc.Height; 498 res->base.b.depth0 = 1; 499 res->base.b.array_size = 1; 500 501 switch (incoming_res_desc.Dimension) { 502 case D3D12_RESOURCE_DIMENSION_BUFFER: 503 res->base.b.target = PIPE_BUFFER; 504 res->base.b.bind = PIPE_BIND_VERTEX_BUFFER | PIPE_BIND_CONSTANT_BUFFER | 505 PIPE_BIND_INDEX_BUFFER | PIPE_BIND_STREAM_OUTPUT | PIPE_BIND_SHADER_BUFFER | 506 PIPE_BIND_COMMAND_ARGS_BUFFER | PIPE_BIND_QUERY_BUFFER; 507 break; 508 case D3D12_RESOURCE_DIMENSION_TEXTURE1D: 509 res->base.b.target = incoming_res_desc.DepthOrArraySize > 1 ? 510 PIPE_TEXTURE_1D_ARRAY : PIPE_TEXTURE_1D; 511 res->base.b.array_size = incoming_res_desc.DepthOrArraySize; 512 break; 513 case D3D12_RESOURCE_DIMENSION_TEXTURE2D: 514 res->base.b.target = incoming_res_desc.DepthOrArraySize > 1 ? 515 PIPE_TEXTURE_2D_ARRAY : PIPE_TEXTURE_2D; 516 res->base.b.array_size = incoming_res_desc.DepthOrArraySize; 517 break; 518 case D3D12_RESOURCE_DIMENSION_TEXTURE3D: 519 res->base.b.target = PIPE_TEXTURE_3D; 520 res->base.b.depth0 = footprint->Depth; 521 break; 522 default: 523 unreachable("Invalid dimension"); 524 break; 525 } 526 res->base.b.nr_samples = incoming_res_desc.SampleDesc.Count; 527 res->base.b.last_level = incoming_res_desc.MipLevels - 1; 528 res->base.b.usage = PIPE_USAGE_DEFAULT; 529 res->base.b.bind |= PIPE_BIND_SHARED; 530 if (incoming_res_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET) 531 res->base.b.bind |= PIPE_BIND_RENDER_TARGET | PIPE_BIND_BLENDABLE | PIPE_BIND_DISPLAY_TARGET; 532 if (incoming_res_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL) 533 res->base.b.bind |= PIPE_BIND_DEPTH_STENCIL; 534 if (incoming_res_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS) 535 res->base.b.bind |= PIPE_BIND_SHADER_IMAGE; 536 if ((incoming_res_desc.Flags & D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE) == D3D12_RESOURCE_FLAG_NONE) 537 res->base.b.bind |= PIPE_BIND_SAMPLER_VIEW; 538 539 if (templ) { 540 if (res->base.b.target == PIPE_TEXTURE_2D_ARRAY && 541 (templ->target == PIPE_TEXTURE_CUBE || 542 templ->target == PIPE_TEXTURE_CUBE_ARRAY)) { 543 if (res->base.b.array_size < 6) { 544 debug_printf("d3d12: Importing cube resource with too few array layers\n"); 545 goto invalid; 546 } 547 res->base.b.target = templ->target; 548 res->base.b.array_size /= 6; 549 } 550 unsigned templ_samples = MAX2(templ->nr_samples, 1); 551 if (res->base.b.target != templ->target || 552 footprint->Width != templ->width0 || 553 footprint->Height != templ->height0 || 554 footprint->Depth != templ->depth0 || 555 res->base.b.array_size != templ->array_size || 556 incoming_res_desc.SampleDesc.Count != templ_samples || 557 res->base.b.last_level != templ->last_level) { 558 debug_printf("d3d12: Importing resource with mismatched dimensions: " 559 "plane: %d, target: %d vs %d, width: %d vs %d, height: %d vs %d, " 560 "depth: %d vs %d, array_size: %d vs %d, samples: %d vs %d, mips: %d vs %d\n", 561 handle->plane, 562 res->base.b.target, templ->target, 563 footprint->Width, templ->width0, 564 footprint->Height, templ->height0, 565 footprint->Depth, templ->depth0, 566 res->base.b.array_size, templ->array_size, 567 incoming_res_desc.SampleDesc.Count, templ_samples, 568 res->base.b.last_level + 1, templ->last_level + 1); 569 goto invalid; 570 } 571 if (templ->target != PIPE_BUFFER) { 572 if ((footprint->Format != d3d12_get_format(templ->format) && 573 footprint->Format != d3d12_get_typeless_format(templ->format)) || 574 (incoming_res_desc.Format != d3d12_get_format((enum pipe_format)handle->format) && 575 incoming_res_desc.Format != d3d12_get_typeless_format((enum pipe_format)handle->format))) { 576 debug_printf("d3d12: Importing resource with mismatched format: " 577 "plane could be DXGI format %d or %d, but is %d, " 578 "overall could be DXGI format %d or %d, but is %d\n", 579 d3d12_get_format(templ->format), 580 d3d12_get_typeless_format(templ->format), 581 footprint->Format, 582 d3d12_get_format((enum pipe_format)handle->format), 583 d3d12_get_typeless_format((enum pipe_format)handle->format), 584 incoming_res_desc.Format); 585 goto invalid; 586 } 587 } 588 /* In an ideal world we'd be able to validate this, but gallium's use of bind 589 * flags during resource creation is pretty bad: some bind flags are always set 590 * (like PIPE_BIND_RENDER_TARGET) while others are never set (PIPE_BIND_SHADER_BUFFER) 591 * 592 if (templ->bind & ~res->base.b.bind) { 593 debug_printf("d3d12: Imported resource doesn't have necessary bind flags\n"); 594 goto invalid; 595 } */ 596 597 res->base.b.format = templ->format; 598 res->overall_format = (enum pipe_format)handle->format; 599 } else { 600 /* Search the pipe format lookup table for an entry */ 601 res->base.b.format = d3d12_get_pipe_format(incoming_res_desc.Format); 602 603 if (res->base.b.format == PIPE_FORMAT_NONE) { 604 /* Convert from typeless to a reasonable default */ 605 res->base.b.format = d3d12_get_default_pipe_format(incoming_res_desc.Format); 606 607 if (res->base.b.format == PIPE_FORMAT_NONE) { 608 debug_printf("d3d12: Unable to deduce non-typeless resource format %d\n", incoming_res_desc.Format); 609 goto invalid; 610 } 611 } 612 613 res->overall_format = res->base.b.format; 614 } 615 616 if (!templ) 617 handle->format = res->overall_format; 618 619 res->dxgi_format = d3d12_get_format(res->overall_format); 620 res->plane_slice = handle->plane; 621 res->first_plane = &res->base.b; 622 623 if (!res->bo) { 624 res->bo = d3d12_bo_wrap_res(screen, d3d12_res, d3d12_permanently_resident); 625 } 626 init_valid_range(res); 627 628 threaded_resource_init(&res->base.b, false); 629 convert_planar_resource(res); 630 631 return &res->base.b; 632 633invalid: 634 if (res->bo) 635 d3d12_bo_unreference(res->bo); 636 else if (d3d12_res) 637 d3d12_res->Release(); 638 FREE(res); 639 return NULL; 640} 641 642static bool 643d3d12_resource_get_handle(struct pipe_screen *pscreen, 644 struct pipe_context *pcontext, 645 struct pipe_resource *pres, 646 struct winsys_handle *handle, 647 unsigned usage) 648{ 649 struct d3d12_resource *res = d3d12_resource(pres); 650 struct d3d12_screen *screen = d3d12_screen(pscreen); 651 652 switch (handle->type) { 653 case WINSYS_HANDLE_TYPE_D3D12_RES: 654 handle->com_obj = d3d12_resource_resource(res); 655 return true; 656 case WINSYS_HANDLE_TYPE_FD: { 657 HANDLE d3d_handle = nullptr; 658 659 screen->dev->CreateSharedHandle(d3d12_resource_resource(res), 660 nullptr, 661 GENERIC_ALL, 662 nullptr, 663 &d3d_handle); 664 if (!d3d_handle) 665 return false; 666 667#ifdef _WIN32 668 handle->handle = d3d_handle; 669#else 670 handle->handle = (int)(intptr_t)d3d_handle; 671#endif 672 handle->format = pres->format; 673 handle->modifier = ~0ull; 674 return true; 675 } 676 default: 677 return false; 678 } 679} 680 681struct pipe_resource * 682d3d12_resource_from_resource(struct pipe_screen *pscreen, 683 ID3D12Resource* input_res) 684{ 685 D3D12_RESOURCE_DESC input_desc = GetDesc(input_res); 686 struct winsys_handle handle; 687 memset(&handle, 0, sizeof(handle)); 688 handle.type = WINSYS_HANDLE_TYPE_D3D12_RES; 689 handle.format = d3d12_get_pipe_format(input_desc.Format); 690 handle.com_obj = input_res; 691 692 struct pipe_resource templ; 693 memset(&templ, 0, sizeof(templ)); 694 if(input_desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER) { 695 templ.target = PIPE_BUFFER; 696 } else { 697 templ.target = (input_desc.DepthOrArraySize > 1) ? PIPE_TEXTURE_2D_ARRAY : PIPE_TEXTURE_2D; 698 } 699 700 templ.format = d3d12_get_pipe_format(input_desc.Format); 701 templ.width0 = input_desc.Width; 702 templ.height0 = input_desc.Height; 703 templ.depth0 = input_desc.DepthOrArraySize; 704 templ.array_size = input_desc.DepthOrArraySize; 705 templ.flags = 0; 706 707 return d3d12_resource_from_handle( 708 pscreen, 709 &templ, 710 &handle, 711 PIPE_USAGE_DEFAULT 712 ); 713} 714 715/** 716 * On Map/Unmap operations, we readback or flush all the underlying planes 717 * of planar resources. The map/unmap operation from the caller is 718 * expected to be done for res->plane_slice plane only, but some 719 * callers expect adjacent allocations for next contiguous plane access 720 * 721 * In this function, we take the res and box the caller passed, and the plane_* properties 722 * that are currently being readback/flushed, and adjust the d3d12_transfer ptrans 723 * accordingly for the GPU copy operation between planes. 724 */ 725static void d3d12_adjust_transfer_dimensions_for_plane(const struct d3d12_resource *res, 726 unsigned plane_slice, 727 unsigned plane_stride, 728 unsigned plane_layer_stride, 729 unsigned plane_offset, 730 const struct pipe_box* original_box, 731 struct pipe_transfer *ptrans/*inout*/) 732{ 733 /* Adjust strides, offsets to the corresponding plane*/ 734 ptrans->stride = plane_stride; 735 ptrans->layer_stride = plane_layer_stride; 736 ptrans->offset = plane_offset; 737 738 /* Find multipliers such that:*/ 739 /* first_plane.width = width_multiplier * planes[res->plane_slice].width*/ 740 /* first_plane.height = height_multiplier * planes[res->plane_slice].height*/ 741 float width_multiplier = res->first_plane->width0 / (float) util_format_get_plane_width(res->overall_format, res->plane_slice, res->first_plane->width0); 742 float height_multiplier = res->first_plane->height0 / (float) util_format_get_plane_height(res->overall_format, res->plane_slice, res->first_plane->height0); 743 744 /* Normalize box back to overall dimensions (first plane)*/ 745 ptrans->box.width = width_multiplier * original_box->width; 746 ptrans->box.height = height_multiplier * original_box->height; 747 ptrans->box.x = width_multiplier * original_box->x; 748 ptrans->box.y = height_multiplier * original_box->y; 749 750 /* Now adjust dimensions to plane_slice*/ 751 ptrans->box.width = util_format_get_plane_width(res->overall_format, plane_slice, ptrans->box.width); 752 ptrans->box.height = util_format_get_plane_height(res->overall_format, plane_slice, ptrans->box.height); 753 ptrans->box.x = util_format_get_plane_width(res->overall_format, plane_slice, ptrans->box.x); 754 ptrans->box.y = util_format_get_plane_height(res->overall_format, plane_slice, ptrans->box.y); 755} 756 757static 758void d3d12_resource_get_planes_info(pipe_resource *pres, 759 unsigned num_planes, 760 pipe_resource **planes, 761 unsigned *strides, 762 unsigned *layer_strides, 763 unsigned *offsets, 764 unsigned *staging_res_size) 765{ 766 struct d3d12_resource* res = d3d12_resource(pres); 767 *staging_res_size = 0; 768 struct pipe_resource *cur_plane_resource = res->first_plane; 769 for (uint plane_slice = 0; plane_slice < num_planes; ++plane_slice) { 770 planes[plane_slice] = cur_plane_resource; 771 int width = util_format_get_plane_width(res->base.b.format, plane_slice, res->first_plane->width0); 772 int height = util_format_get_plane_height(res->base.b.format, plane_slice, res->first_plane->height0); 773 774 strides[plane_slice] = align(util_format_get_stride(cur_plane_resource->format, width), 775 D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); 776 777 layer_strides[plane_slice] = align(util_format_get_2d_size(cur_plane_resource->format, 778 strides[plane_slice], 779 height), 780 D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT); 781 782 offsets[plane_slice] = *staging_res_size; 783 *staging_res_size += layer_strides[plane_slice]; 784 cur_plane_resource = cur_plane_resource->next; 785 } 786} 787 788static constexpr unsigned d3d12_max_planes = 3; 789 790/** 791 * Get stride and offset for the given pipe resource without the need to get 792 * a winsys_handle. 793 */ 794void 795d3d12_resource_get_info(struct pipe_screen *pscreen, 796 struct pipe_resource *pres, 797 unsigned *stride, 798 unsigned *offset) 799{ 800 801 struct d3d12_resource* res = d3d12_resource(pres); 802 unsigned num_planes = util_format_get_num_planes(res->overall_format); 803 804 pipe_resource *planes[d3d12_max_planes]; 805 unsigned int strides[d3d12_max_planes]; 806 unsigned int layer_strides[d3d12_max_planes]; 807 unsigned int offsets[d3d12_max_planes]; 808 unsigned staging_res_size = 0; 809 d3d12_resource_get_planes_info( 810 pres, 811 num_planes, 812 planes, 813 strides, 814 layer_strides, 815 offsets, 816 &staging_res_size 817 ); 818 819 if(stride) { 820 *stride = strides[res->plane_slice]; 821 } 822 823 if(offset) { 824 *offset = offsets[res->plane_slice]; 825 } 826} 827 828static struct pipe_memory_object * 829d3d12_memobj_create_from_handle(struct pipe_screen *pscreen, struct winsys_handle *handle, bool dedicated) 830{ 831 if (handle->type != WINSYS_HANDLE_TYPE_WIN32_HANDLE && 832 handle->type != WINSYS_HANDLE_TYPE_WIN32_NAME) { 833 debug_printf("d3d12: Unsupported memobj handle type\n"); 834 return NULL; 835 } 836 837 struct d3d12_screen *screen = d3d12_screen(pscreen); 838 IUnknown *obj; 839#ifdef _WIN32 840 HANDLE d3d_handle = handle->handle; 841#else 842 HANDLE d3d_handle = (HANDLE)(intptr_t)handle->handle; 843#endif 844 845#ifdef _WIN32 846 HANDLE d3d_handle_to_close = nullptr; 847 if (handle->type == WINSYS_HANDLE_TYPE_WIN32_NAME) { 848 screen->dev->OpenSharedHandleByName((LPCWSTR) handle->name, GENERIC_ALL, &d3d_handle_to_close); 849 d3d_handle = d3d_handle_to_close; 850 } 851#endif 852 853 screen->dev->OpenSharedHandle(d3d_handle, IID_PPV_ARGS(&obj)); 854 855#ifdef _WIN32 856 if (d3d_handle_to_close) { 857 CloseHandle(d3d_handle_to_close); 858 } 859#endif 860 861 if (!obj) { 862 debug_printf("d3d12: Failed to open memobj handle as anything\n"); 863 return NULL; 864 } 865 866 struct d3d12_memory_object *memobj = CALLOC_STRUCT(d3d12_memory_object); 867 if (!memobj) { 868 obj->Release(); 869 return NULL; 870 } 871 memobj->base.dedicated = dedicated; 872 873 (void)obj->QueryInterface(&memobj->res); 874 (void)obj->QueryInterface(&memobj->heap); 875 obj->Release(); 876 if (!memobj->res && !memobj->heap) { 877 debug_printf("d3d12: Memory object isn't a resource or heap\n"); 878 free(memobj); 879 return NULL; 880 } 881 882 bool expect_dedicated = memobj->res != nullptr; 883 if (dedicated != expect_dedicated) 884 debug_printf("d3d12: Expected dedicated to be %s for imported %s\n", 885 expect_dedicated ? "true" : "false", 886 expect_dedicated ? "resource" : "heap"); 887 888 return &memobj->base; 889} 890 891static void 892d3d12_memobj_destroy(struct pipe_screen *pscreen, struct pipe_memory_object *pmemobj) 893{ 894 struct d3d12_memory_object *memobj = d3d12_memory_object(pmemobj); 895 if (memobj->res) 896 memobj->res->Release(); 897 if (memobj->heap) 898 memobj->heap->Release(); 899 free(memobj); 900} 901 902static pipe_resource * 903d3d12_resource_from_memobj(struct pipe_screen *pscreen, 904 const struct pipe_resource *templ, 905 struct pipe_memory_object *pmemobj, 906 uint64_t offset) 907{ 908 struct d3d12_memory_object *memobj = d3d12_memory_object(pmemobj); 909 910 struct winsys_handle whandle = {}; 911 whandle.type = WINSYS_HANDLE_TYPE_D3D12_RES; 912 whandle.com_obj = memobj->res ? (void *) memobj->res : (void *) memobj->heap; 913 whandle.offset = offset; 914 whandle.format = templ->format; 915 916 // WINSYS_HANDLE_TYPE_D3D12_RES implies taking ownership of the reference 917 ((IUnknown *)whandle.com_obj)->AddRef(); 918 return d3d12_resource_from_handle(pscreen, templ, &whandle, 0); 919} 920 921void 922d3d12_screen_resource_init(struct pipe_screen *pscreen) 923{ 924 pscreen->resource_create = d3d12_resource_create; 925 pscreen->resource_from_handle = d3d12_resource_from_handle; 926 pscreen->resource_get_handle = d3d12_resource_get_handle; 927 pscreen->resource_destroy = d3d12_resource_destroy; 928 pscreen->resource_get_info = d3d12_resource_get_info; 929 930 pscreen->memobj_create_from_handle = d3d12_memobj_create_from_handle; 931 pscreen->memobj_destroy = d3d12_memobj_destroy; 932 pscreen->resource_from_memobj = d3d12_resource_from_memobj; 933} 934 935unsigned int 936get_subresource_id(struct d3d12_resource *res, unsigned resid, 937 unsigned z, unsigned base_level) 938{ 939 unsigned resource_stride = res->base.b.last_level + 1; 940 if (res->base.b.target == PIPE_TEXTURE_1D_ARRAY || 941 res->base.b.target == PIPE_TEXTURE_2D_ARRAY) 942 resource_stride *= res->base.b.array_size; 943 944 if (res->base.b.target == PIPE_TEXTURE_CUBE) 945 resource_stride *= 6; 946 947 if (res->base.b.target == PIPE_TEXTURE_CUBE_ARRAY) 948 resource_stride *= 6 * res->base.b.array_size; 949 950 unsigned layer_stride = res->base.b.last_level + 1; 951 952 return resid * resource_stride + z * layer_stride + 953 base_level + res->plane_slice * resource_stride; 954} 955 956static D3D12_TEXTURE_COPY_LOCATION 957fill_texture_location(struct d3d12_resource *res, 958 struct d3d12_transfer *trans, unsigned resid, unsigned z) 959{ 960 D3D12_TEXTURE_COPY_LOCATION tex_loc = {0}; 961 int subres = get_subresource_id(res, resid, z, trans->base.b.level); 962 963 tex_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; 964 tex_loc.SubresourceIndex = subres; 965 tex_loc.pResource = d3d12_resource_resource(res); 966 return tex_loc; 967} 968 969static D3D12_TEXTURE_COPY_LOCATION 970fill_buffer_location(struct d3d12_context *ctx, 971 struct d3d12_resource *res, 972 struct d3d12_resource *staging_res, 973 struct d3d12_transfer *trans, 974 unsigned depth, 975 unsigned resid, unsigned z) 976{ 977 D3D12_TEXTURE_COPY_LOCATION buf_loc = {0}; 978 D3D12_PLACED_SUBRESOURCE_FOOTPRINT footprint; 979 uint64_t offset = 0; 980 auto descr = GetDesc(d3d12_resource_underlying(res, &offset)); 981 struct d3d12_screen *screen = d3d12_screen(ctx->base.screen); 982 ID3D12Device* dev = screen->dev; 983 984 unsigned sub_resid = get_subresource_id(res, resid, z, trans->base.b.level); 985 dev->GetCopyableFootprints(&descr, sub_resid, 1, 0, &footprint, nullptr, nullptr, nullptr); 986 987 buf_loc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; 988 buf_loc.pResource = d3d12_resource_underlying(staging_res, &offset); 989 buf_loc.PlacedFootprint = footprint; 990 buf_loc.PlacedFootprint.Offset += offset; 991 buf_loc.PlacedFootprint.Offset += trans->base.b.offset; 992 993 if (util_format_has_depth(util_format_description(res->base.b.format)) && 994 screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED) { 995 buf_loc.PlacedFootprint.Footprint.Width = res->base.b.width0; 996 buf_loc.PlacedFootprint.Footprint.Height = res->base.b.height0; 997 buf_loc.PlacedFootprint.Footprint.Depth = res->base.b.depth0; 998 } else { 999 buf_loc.PlacedFootprint.Footprint.Width = ALIGN(trans->base.b.box.width, 1000 util_format_get_blockwidth(res->base.b.format)); 1001 buf_loc.PlacedFootprint.Footprint.Height = ALIGN(trans->base.b.box.height, 1002 util_format_get_blockheight(res->base.b.format)); 1003 buf_loc.PlacedFootprint.Footprint.Depth = ALIGN(depth, 1004 util_format_get_blockdepth(res->base.b.format)); 1005 } 1006 1007 buf_loc.PlacedFootprint.Footprint.RowPitch = trans->base.b.stride; 1008 1009 return buf_loc; 1010} 1011 1012struct copy_info { 1013 struct d3d12_resource *dst; 1014 D3D12_TEXTURE_COPY_LOCATION dst_loc; 1015 UINT dst_x, dst_y, dst_z; 1016 struct d3d12_resource *src; 1017 D3D12_TEXTURE_COPY_LOCATION src_loc; 1018 D3D12_BOX *src_box; 1019}; 1020 1021 1022static void 1023copy_texture_region(struct d3d12_context *ctx, 1024 struct copy_info& info) 1025{ 1026 auto batch = d3d12_current_batch(ctx); 1027 1028 d3d12_batch_reference_resource(batch, info.src, false); 1029 d3d12_batch_reference_resource(batch, info.dst, true); 1030 d3d12_transition_resource_state(ctx, info.src, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS); 1031 d3d12_transition_resource_state(ctx, info.dst, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS); 1032 d3d12_apply_resource_states(ctx, false); 1033 ctx->cmdlist->CopyTextureRegion(&info.dst_loc, info.dst_x, info.dst_y, info.dst_z, 1034 &info.src_loc, info.src_box); 1035} 1036 1037static void 1038transfer_buf_to_image_part(struct d3d12_context *ctx, 1039 struct d3d12_resource *res, 1040 struct d3d12_resource *staging_res, 1041 struct d3d12_transfer *trans, 1042 int z, int depth, int start_z, int dest_z, 1043 int resid) 1044{ 1045 if (D3D12_DEBUG_RESOURCE & d3d12_debug) { 1046 debug_printf("D3D12: Copy %dx%dx%d + %dx%dx%d from buffer %s to image %s\n", 1047 trans->base.b.box.x, trans->base.b.box.y, trans->base.b.box.z, 1048 trans->base.b.box.width, trans->base.b.box.height, trans->base.b.box.depth, 1049 util_format_name(staging_res->base.b.format), 1050 util_format_name(res->base.b.format)); 1051 } 1052 1053 struct d3d12_screen *screen = d3d12_screen(res->base.b.screen); 1054 struct copy_info copy_info; 1055 copy_info.src = staging_res; 1056 copy_info.src_loc = fill_buffer_location(ctx, res, staging_res, trans, depth, resid, z); 1057 copy_info.src_loc.PlacedFootprint.Offset += (z - start_z) * trans->base.b.layer_stride; 1058 copy_info.src_box = nullptr; 1059 copy_info.dst = res; 1060 copy_info.dst_loc = fill_texture_location(res, trans, resid, z); 1061 if (util_format_has_depth(util_format_description(res->base.b.format)) && 1062 screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED) { 1063 copy_info.dst_x = 0; 1064 copy_info.dst_y = 0; 1065 } else { 1066 copy_info.dst_x = trans->base.b.box.x; 1067 copy_info.dst_y = trans->base.b.box.y; 1068 } 1069 copy_info.dst_z = res->base.b.target == PIPE_TEXTURE_CUBE ? 0 : dest_z; 1070 copy_info.src_box = nullptr; 1071 1072 copy_texture_region(ctx, copy_info); 1073} 1074 1075static bool 1076transfer_buf_to_image(struct d3d12_context *ctx, 1077 struct d3d12_resource *res, 1078 struct d3d12_resource *staging_res, 1079 struct d3d12_transfer *trans, int resid) 1080{ 1081 if (res->base.b.target == PIPE_TEXTURE_3D) { 1082 assert(resid == 0); 1083 transfer_buf_to_image_part(ctx, res, staging_res, trans, 1084 0, trans->base.b.box.depth, 0, 1085 trans->base.b.box.z, 0); 1086 } else { 1087 int num_layers = trans->base.b.box.depth; 1088 int start_z = trans->base.b.box.z; 1089 1090 for (int z = start_z; z < start_z + num_layers; ++z) { 1091 transfer_buf_to_image_part(ctx, res, staging_res, trans, 1092 z, 1, start_z, 0, resid); 1093 } 1094 } 1095 return true; 1096} 1097 1098static void 1099transfer_image_part_to_buf(struct d3d12_context *ctx, 1100 struct d3d12_resource *res, 1101 struct d3d12_resource *staging_res, 1102 struct d3d12_transfer *trans, 1103 unsigned resid, int z, int start_layer, 1104 int start_box_z, int depth) 1105{ 1106 struct pipe_box *box = &trans->base.b.box; 1107 D3D12_BOX src_box = {}; 1108 1109 struct d3d12_screen *screen = d3d12_screen(res->base.b.screen); 1110 struct copy_info copy_info; 1111 copy_info.src_box = nullptr; 1112 copy_info.src = res; 1113 copy_info.src_loc = fill_texture_location(res, trans, resid, z); 1114 copy_info.dst = staging_res; 1115 copy_info.dst_loc = fill_buffer_location(ctx, res, staging_res, trans, 1116 depth, resid, z); 1117 copy_info.dst_loc.PlacedFootprint.Offset += (z - start_layer) * trans->base.b.layer_stride; 1118 copy_info.dst_x = copy_info.dst_y = copy_info.dst_z = 0; 1119 1120 bool whole_resource = util_texrange_covers_whole_level(&res->base.b, trans->base.b.level, 1121 box->x, box->y, start_box_z, 1122 box->width, box->height, depth); 1123 if (util_format_has_depth(util_format_description(res->base.b.format)) && 1124 screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED) 1125 whole_resource = true; 1126 if (!whole_resource) { 1127 src_box.left = box->x; 1128 src_box.right = box->x + box->width; 1129 src_box.top = box->y; 1130 src_box.bottom = box->y + box->height; 1131 src_box.front = start_box_z; 1132 src_box.back = start_box_z + depth; 1133 copy_info.src_box = &src_box; 1134 } 1135 1136 copy_texture_region(ctx, copy_info); 1137} 1138 1139static bool 1140transfer_image_to_buf(struct d3d12_context *ctx, 1141 struct d3d12_resource *res, 1142 struct d3d12_resource *staging_res, 1143 struct d3d12_transfer *trans, 1144 unsigned resid) 1145{ 1146 1147 /* We only suppport loading from either an texture array 1148 * or a ZS texture, so either resid is zero, or num_layers == 1) 1149 */ 1150 assert(resid == 0 || trans->base.b.box.depth == 1); 1151 1152 if (D3D12_DEBUG_RESOURCE & d3d12_debug) { 1153 debug_printf("D3D12: Copy %dx%dx%d + %dx%dx%d from %s@%d to %s\n", 1154 trans->base.b.box.x, trans->base.b.box.y, trans->base.b.box.z, 1155 trans->base.b.box.width, trans->base.b.box.height, trans->base.b.box.depth, 1156 util_format_name(res->base.b.format), resid, 1157 util_format_name(staging_res->base.b.format)); 1158 } 1159 1160 struct pipe_resource *resolved_resource = nullptr; 1161 if (res->base.b.nr_samples > 1) { 1162 struct pipe_resource tmpl = res->base.b; 1163 tmpl.nr_samples = 0; 1164 resolved_resource = d3d12_resource_create(ctx->base.screen, &tmpl); 1165 struct pipe_blit_info resolve_info = {}; 1166 struct pipe_box box = {0,0,0, (int)res->base.b.width0, (int16_t)res->base.b.height0, (int16_t)res->base.b.depth0}; 1167 resolve_info.dst.resource = resolved_resource; 1168 resolve_info.dst.box = box; 1169 resolve_info.dst.format = res->base.b.format; 1170 resolve_info.src.resource = &res->base.b; 1171 resolve_info.src.box = box; 1172 resolve_info.src.format = res->base.b.format; 1173 resolve_info.filter = PIPE_TEX_FILTER_NEAREST; 1174 resolve_info.mask = util_format_get_mask(tmpl.format); 1175 1176 1177 1178 d3d12_blit(&ctx->base, &resolve_info); 1179 res = (struct d3d12_resource *)resolved_resource; 1180 } 1181 1182 1183 if (res->base.b.target == PIPE_TEXTURE_3D) { 1184 transfer_image_part_to_buf(ctx, res, staging_res, trans, resid, 1185 0, 0, trans->base.b.box.z, trans->base.b.box.depth); 1186 } else { 1187 int start_layer = trans->base.b.box.z; 1188 for (int z = start_layer; z < start_layer + trans->base.b.box.depth; ++z) { 1189 transfer_image_part_to_buf(ctx, res, staging_res, trans, resid, 1190 z, start_layer, 0, 1); 1191 } 1192 } 1193 1194 pipe_resource_reference(&resolved_resource, NULL); 1195 1196 return true; 1197} 1198 1199static void 1200transfer_buf_to_buf(struct d3d12_context *ctx, 1201 struct d3d12_resource *src, 1202 struct d3d12_resource *dst, 1203 uint64_t src_offset, 1204 uint64_t dst_offset, 1205 uint64_t width) 1206{ 1207 auto batch = d3d12_current_batch(ctx); 1208 1209 d3d12_batch_reference_resource(batch, src, false); 1210 d3d12_batch_reference_resource(batch, dst, true); 1211 1212 uint64_t src_offset_suballoc = 0; 1213 uint64_t dst_offset_suballoc = 0; 1214 auto src_d3d12 = d3d12_resource_underlying(src, &src_offset_suballoc); 1215 auto dst_d3d12 = d3d12_resource_underlying(dst, &dst_offset_suballoc); 1216 src_offset += src_offset_suballoc; 1217 dst_offset += dst_offset_suballoc; 1218 1219 // Same-resource copies not supported, since the resource would need to be in both states 1220 assert(src_d3d12 != dst_d3d12); 1221 d3d12_transition_resource_state(ctx, src, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS); 1222 d3d12_transition_resource_state(ctx, dst, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS); 1223 d3d12_apply_resource_states(ctx, false); 1224 ctx->cmdlist->CopyBufferRegion(dst_d3d12, dst_offset, 1225 src_d3d12, src_offset, 1226 width); 1227} 1228 1229static unsigned 1230linear_offset(int x, int y, int z, unsigned stride, unsigned layer_stride) 1231{ 1232 return x + 1233 y * stride + 1234 z * layer_stride; 1235} 1236 1237static D3D12_RANGE 1238linear_range(const struct pipe_box *box, unsigned stride, unsigned layer_stride) 1239{ 1240 D3D12_RANGE range; 1241 1242 range.Begin = linear_offset(box->x, box->y, box->z, 1243 stride, layer_stride); 1244 range.End = linear_offset(box->x + box->width, 1245 box->y + box->height - 1, 1246 box->z + box->depth - 1, 1247 stride, layer_stride); 1248 1249 return range; 1250} 1251 1252static bool 1253synchronize(struct d3d12_context *ctx, 1254 struct d3d12_resource *res, 1255 unsigned usage, 1256 D3D12_RANGE *range) 1257{ 1258 assert(can_map_directly(&res->base.b)); 1259 1260 /* Check whether that range contains valid data; if not, we might not need to sync */ 1261 if (!(usage & PIPE_MAP_UNSYNCHRONIZED) && 1262 usage & PIPE_MAP_WRITE && 1263 !util_ranges_intersect(&res->valid_buffer_range, range->Begin, range->End)) { 1264 usage |= PIPE_MAP_UNSYNCHRONIZED; 1265 } 1266 1267 if (!(usage & PIPE_MAP_UNSYNCHRONIZED) && resource_is_busy(ctx, res, usage & PIPE_MAP_WRITE)) { 1268 if (usage & PIPE_MAP_DONTBLOCK) { 1269 if (d3d12_batch_has_references(d3d12_current_batch(ctx), res->bo, usage & PIPE_MAP_WRITE)) 1270 d3d12_flush_cmdlist(ctx); 1271 return false; 1272 } 1273 1274 d3d12_resource_wait_idle(ctx, res, usage & PIPE_MAP_WRITE); 1275 } 1276 1277 if (usage & PIPE_MAP_WRITE) 1278 util_range_add(&res->base.b, &res->valid_buffer_range, 1279 range->Begin, range->End); 1280 1281 return true; 1282} 1283 1284/* A wrapper to make sure local resources are freed and unmapped with 1285 * any exit path */ 1286struct local_resource { 1287 local_resource(pipe_screen *s, struct pipe_resource *tmpl) : 1288 mapped(false) 1289 { 1290 res = d3d12_resource(d3d12_resource_create(s, tmpl)); 1291 } 1292 1293 ~local_resource() { 1294 if (res) { 1295 if (mapped) 1296 d3d12_bo_unmap(res->bo, nullptr); 1297 pipe_resource_reference((struct pipe_resource **)&res, NULL); 1298 } 1299 } 1300 1301 void * 1302 map() { 1303 void *ptr; 1304 ptr = d3d12_bo_map(res->bo, nullptr); 1305 if (ptr) 1306 mapped = true; 1307 return ptr; 1308 } 1309 1310 void unmap() 1311 { 1312 if (mapped) 1313 d3d12_bo_unmap(res->bo, nullptr); 1314 mapped = false; 1315 } 1316 1317 operator struct d3d12_resource *() { 1318 return res; 1319 } 1320 1321 bool operator !() { 1322 return !res; 1323 } 1324private: 1325 struct d3d12_resource *res; 1326 bool mapped; 1327}; 1328 1329/* Combined depth-stencil needs a special handling for reading back: DX handled 1330 * depth and stencil parts as separate resources and handles copying them only 1331 * by using seperate texture copy calls with different formats. So create two 1332 * buffers, read back both resources and interleave the data. 1333 */ 1334static void 1335prepare_zs_layer_strides(struct d3d12_screen *screen, 1336 struct d3d12_resource *res, 1337 const struct pipe_box *box, 1338 struct d3d12_transfer *trans) 1339{ 1340 bool copy_whole_resource = screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED; 1341 int width = copy_whole_resource ? res->base.b.width0 : box->width; 1342 int height = copy_whole_resource ? res->base.b.height0 : box->height; 1343 1344 trans->base.b.stride = align(util_format_get_stride(res->base.b.format, width), 1345 D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); 1346 trans->base.b.layer_stride = util_format_get_2d_size(res->base.b.format, 1347 trans->base.b.stride, 1348 height); 1349 1350 if (copy_whole_resource) { 1351 trans->zs_cpu_copy_stride = align(util_format_get_stride(res->base.b.format, box->width), 1352 D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); 1353 trans->zs_cpu_copy_layer_stride = util_format_get_2d_size(res->base.b.format, 1354 trans->base.b.stride, 1355 box->height); 1356 } else { 1357 trans->zs_cpu_copy_stride = trans->base.b.stride; 1358 trans->zs_cpu_copy_layer_stride = trans->base.b.layer_stride; 1359 } 1360} 1361 1362static void * 1363read_zs_surface(struct d3d12_context *ctx, struct d3d12_resource *res, 1364 const struct pipe_box *box, 1365 struct d3d12_transfer *trans) 1366{ 1367 pipe_screen *pscreen = ctx->base.screen; 1368 struct d3d12_screen *screen = d3d12_screen(pscreen); 1369 1370 prepare_zs_layer_strides(screen, res, box, trans); 1371 1372 struct pipe_resource tmpl; 1373 memset(&tmpl, 0, sizeof tmpl); 1374 tmpl.target = PIPE_BUFFER; 1375 tmpl.format = PIPE_FORMAT_R32_UNORM; 1376 tmpl.bind = 0; 1377 tmpl.usage = PIPE_USAGE_STAGING; 1378 tmpl.flags = 0; 1379 tmpl.width0 = trans->base.b.layer_stride; 1380 tmpl.height0 = 1; 1381 tmpl.depth0 = 1; 1382 tmpl.array_size = 1; 1383 1384 local_resource depth_buffer(pscreen, &tmpl); 1385 if (!depth_buffer) { 1386 debug_printf("Allocating staging buffer for depth failed\n"); 1387 return NULL; 1388 } 1389 1390 if (!transfer_image_to_buf(ctx, res, depth_buffer, trans, 0)) 1391 return NULL; 1392 1393 tmpl.format = PIPE_FORMAT_R8_UINT; 1394 1395 local_resource stencil_buffer(pscreen, &tmpl); 1396 if (!stencil_buffer) { 1397 debug_printf("Allocating staging buffer for stencilfailed\n"); 1398 return NULL; 1399 } 1400 1401 if (!transfer_image_to_buf(ctx, res, stencil_buffer, trans, 1)) 1402 return NULL; 1403 1404 d3d12_flush_cmdlist_and_wait(ctx); 1405 1406 uint8_t *depth_ptr = (uint8_t *)depth_buffer.map(); 1407 if (!depth_ptr) { 1408 debug_printf("Mapping staging depth buffer failed\n"); 1409 return NULL; 1410 } 1411 1412 uint8_t *stencil_ptr = (uint8_t *)stencil_buffer.map(); 1413 if (!stencil_ptr) { 1414 debug_printf("Mapping staging stencil buffer failed\n"); 1415 return NULL; 1416 } 1417 1418 uint8_t *buf = (uint8_t *)malloc(trans->zs_cpu_copy_layer_stride); 1419 if (!buf) 1420 return NULL; 1421 1422 trans->data = buf; 1423 1424 switch (res->base.b.format) { 1425 case PIPE_FORMAT_Z24_UNORM_S8_UINT: 1426 if (screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED) { 1427 depth_ptr += trans->base.b.box.y * trans->base.b.stride + trans->base.b.box.x * 4; 1428 stencil_ptr += trans->base.b.box.y * trans->base.b.stride + trans->base.b.box.x * 4; 1429 } 1430 util_format_z24_unorm_s8_uint_pack_separate(buf, trans->zs_cpu_copy_stride, 1431 (uint32_t *)depth_ptr, trans->base.b.stride, 1432 stencil_ptr, trans->base.b.stride, 1433 trans->base.b.box.width, trans->base.b.box.height); 1434 break; 1435 case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT: 1436 if (screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED) { 1437 depth_ptr += trans->base.b.box.y * trans->base.b.stride + trans->base.b.box.x * 4; 1438 stencil_ptr += trans->base.b.box.y * trans->base.b.stride + trans->base.b.box.x; 1439 } 1440 util_format_z32_float_s8x24_uint_pack_z_float(buf, trans->zs_cpu_copy_stride, 1441 (float *)depth_ptr, trans->base.b.stride, 1442 trans->base.b.box.width, trans->base.b.box.height); 1443 util_format_z32_float_s8x24_uint_pack_s_8uint(buf, trans->zs_cpu_copy_stride, 1444 stencil_ptr, trans->base.b.stride, 1445 trans->base.b.box.width, trans->base.b.box.height); 1446 break; 1447 default: 1448 unreachable("Unsupported depth steancil format"); 1449 }; 1450 1451 return trans->data; 1452} 1453 1454static void * 1455prepare_write_zs_surface(struct d3d12_resource *res, 1456 const struct pipe_box *box, 1457 struct d3d12_transfer *trans) 1458{ 1459 struct d3d12_screen *screen = d3d12_screen(res->base.b.screen); 1460 prepare_zs_layer_strides(screen, res, box, trans); 1461 uint32_t *buf = (uint32_t *)malloc(trans->base.b.layer_stride); 1462 if (!buf) 1463 return NULL; 1464 1465 trans->data = buf; 1466 return trans->data; 1467} 1468 1469static void 1470write_zs_surface(struct pipe_context *pctx, struct d3d12_resource *res, 1471 struct d3d12_transfer *trans) 1472{ 1473 struct d3d12_screen *screen = d3d12_screen(res->base.b.screen); 1474 struct pipe_resource tmpl; 1475 memset(&tmpl, 0, sizeof tmpl); 1476 tmpl.target = PIPE_BUFFER; 1477 tmpl.format = PIPE_FORMAT_R32_UNORM; 1478 tmpl.bind = 0; 1479 tmpl.usage = PIPE_USAGE_STAGING; 1480 tmpl.flags = 0; 1481 tmpl.width0 = trans->base.b.layer_stride; 1482 tmpl.height0 = 1; 1483 tmpl.depth0 = 1; 1484 tmpl.array_size = 1; 1485 1486 local_resource depth_buffer(pctx->screen, &tmpl); 1487 if (!depth_buffer) { 1488 debug_printf("Allocating staging buffer for depth failed\n"); 1489 return; 1490 } 1491 1492 local_resource stencil_buffer(pctx->screen, &tmpl); 1493 if (!stencil_buffer) { 1494 debug_printf("Allocating staging buffer for depth failed\n"); 1495 return; 1496 } 1497 1498 uint8_t *depth_ptr = (uint8_t *)depth_buffer.map(); 1499 if (!depth_ptr) { 1500 debug_printf("Mapping staging depth buffer failed\n"); 1501 return; 1502 } 1503 1504 uint8_t *stencil_ptr = (uint8_t *)stencil_buffer.map(); 1505 if (!stencil_ptr) { 1506 debug_printf("Mapping staging stencil buffer failed\n"); 1507 return; 1508 } 1509 1510 switch (res->base.b.format) { 1511 case PIPE_FORMAT_Z24_UNORM_S8_UINT: 1512 if (screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED) { 1513 depth_ptr += trans->base.b.box.y * trans->base.b.stride + trans->base.b.box.x * 4; 1514 stencil_ptr += trans->base.b.box.y * trans->base.b.stride + trans->base.b.box.x * 4; 1515 } 1516 util_format_z32_unorm_unpack_z_32unorm((uint32_t *)depth_ptr, trans->base.b.stride, (uint8_t*)trans->data, 1517 trans->zs_cpu_copy_stride, trans->base.b.box.width, 1518 trans->base.b.box.height); 1519 util_format_z24_unorm_s8_uint_unpack_s_8uint(stencil_ptr, trans->base.b.stride, (uint8_t*)trans->data, 1520 trans->zs_cpu_copy_stride, trans->base.b.box.width, 1521 trans->base.b.box.height); 1522 break; 1523 case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT: 1524 if (screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED) { 1525 depth_ptr += trans->base.b.box.y * trans->base.b.stride + trans->base.b.box.x * 4; 1526 stencil_ptr += trans->base.b.box.y * trans->base.b.stride + trans->base.b.box.x; 1527 } 1528 util_format_z32_float_s8x24_uint_unpack_z_float((float *)depth_ptr, trans->base.b.stride, (uint8_t*)trans->data, 1529 trans->zs_cpu_copy_stride, trans->base.b.box.width, 1530 trans->base.b.box.height); 1531 util_format_z32_float_s8x24_uint_unpack_s_8uint(stencil_ptr, trans->base.b.stride, (uint8_t*)trans->data, 1532 trans->zs_cpu_copy_stride, trans->base.b.box.width, 1533 trans->base.b.box.height); 1534 break; 1535 default: 1536 unreachable("Unsupported depth steancil format"); 1537 }; 1538 1539 stencil_buffer.unmap(); 1540 depth_buffer.unmap(); 1541 1542 transfer_buf_to_image(d3d12_context(pctx), res, depth_buffer, trans, 0); 1543 transfer_buf_to_image(d3d12_context(pctx), res, stencil_buffer, trans, 1); 1544} 1545 1546#define BUFFER_MAP_ALIGNMENT 64 1547 1548static void * 1549d3d12_transfer_map(struct pipe_context *pctx, 1550 struct pipe_resource *pres, 1551 unsigned level, 1552 unsigned usage, 1553 const struct pipe_box *box, 1554 struct pipe_transfer **transfer) 1555{ 1556 struct d3d12_context *ctx = d3d12_context(pctx); 1557 struct d3d12_resource *res = d3d12_resource(pres); 1558 struct d3d12_screen *screen = d3d12_screen(pres->screen); 1559 1560 if (usage & PIPE_MAP_DIRECTLY || !res->bo) 1561 return NULL; 1562 1563 slab_child_pool* transfer_pool = (usage & TC_TRANSFER_MAP_THREADED_UNSYNC) ? 1564 &ctx->transfer_pool_unsync : &ctx->transfer_pool; 1565 struct d3d12_transfer *trans = (struct d3d12_transfer *)slab_zalloc(transfer_pool); 1566 struct pipe_transfer *ptrans = &trans->base.b; 1567 if (!trans) 1568 return NULL; 1569 1570 ptrans->level = level; 1571 ptrans->usage = (enum pipe_map_flags)usage; 1572 ptrans->box = *box; 1573 1574 D3D12_RANGE range; 1575 range.Begin = 0; 1576 1577 void *ptr; 1578 if (can_map_directly(&res->base.b)) { 1579 if (pres->target == PIPE_BUFFER) { 1580 ptrans->stride = 0; 1581 ptrans->layer_stride = 0; 1582 } else { 1583 ptrans->stride = util_format_get_stride(pres->format, box->width); 1584 ptrans->layer_stride = util_format_get_2d_size(pres->format, 1585 ptrans->stride, 1586 box->height); 1587 } 1588 1589 range = linear_range(box, ptrans->stride, ptrans->layer_stride); 1590 if (!synchronize(ctx, res, usage, &range)) { 1591 slab_free(transfer_pool, trans); 1592 return NULL; 1593 } 1594 ptr = d3d12_bo_map(res->bo, &range); 1595 } else if (unlikely(pres->format == PIPE_FORMAT_Z24_UNORM_S8_UINT || 1596 pres->format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT)) { 1597 if (usage & PIPE_MAP_READ) { 1598 ptr = read_zs_surface(ctx, res, box, trans); 1599 } else if (usage & PIPE_MAP_WRITE){ 1600 ptr = prepare_write_zs_surface(res, box, trans); 1601 } else { 1602 ptr = nullptr; 1603 } 1604 } else if(util_format_is_yuv(res->overall_format)) { 1605 1606 /* Get planes information*/ 1607 1608 unsigned num_planes = util_format_get_num_planes(res->overall_format); 1609 pipe_resource *planes[d3d12_max_planes]; 1610 unsigned int strides[d3d12_max_planes]; 1611 unsigned int layer_strides[d3d12_max_planes]; 1612 unsigned int offsets[d3d12_max_planes]; 1613 unsigned staging_res_size = 0; 1614 1615 d3d12_resource_get_planes_info( 1616 pres, 1617 num_planes, 1618 planes, 1619 strides, 1620 layer_strides, 1621 offsets, 1622 &staging_res_size 1623 ); 1624 1625 /* Allocate a buffer for all the planes to fit in adjacent memory*/ 1626 1627 pipe_resource_usage staging_usage = (usage & (PIPE_MAP_READ | PIPE_MAP_READ_WRITE)) ? 1628 PIPE_USAGE_STAGING : PIPE_USAGE_STREAM; 1629 trans->staging_res = pipe_buffer_create(pctx->screen, 0, 1630 staging_usage, 1631 staging_res_size); 1632 if (!trans->staging_res) 1633 return NULL; 1634 1635 struct d3d12_resource *staging_res = d3d12_resource(trans->staging_res); 1636 1637 /* Readback contents into the buffer allocation now if map was intended for read*/ 1638 1639 /* Read all planes if readback needed*/ 1640 if (usage & PIPE_MAP_READ) { 1641 pipe_box original_box = ptrans->box; 1642 for (uint plane_slice = 0; plane_slice < num_planes; ++plane_slice) { 1643 /* Adjust strides, offsets, box to the corresponding plane for the copytexture operation*/ 1644 d3d12_adjust_transfer_dimensions_for_plane(res, 1645 plane_slice, 1646 strides[plane_slice], 1647 layer_strides[plane_slice], 1648 offsets[plane_slice], 1649 &original_box, 1650 ptrans/*inout*/); 1651 /* Perform the readback*/ 1652 if(!transfer_image_to_buf(ctx, d3d12_resource(planes[plane_slice]), staging_res, trans, 0)){ 1653 return NULL; 1654 } 1655 } 1656 1657 d3d12_flush_cmdlist_and_wait(ctx); 1658 } 1659 1660 /* Map the whole staging buffer containing all the planes contiguously*/ 1661 /* Just offset the resulting ptr to the according plane offset*/ 1662 1663 range.End = staging_res_size - range.Begin; 1664 uint8_t* all_planes_map = (uint8_t*) d3d12_bo_map(staging_res->bo, &range); 1665 1666 ptrans->stride = strides[res->plane_slice]; 1667 ptrans->layer_stride = layer_strides[res->plane_slice]; 1668 ptr = all_planes_map + offsets[res->plane_slice]; 1669 1670 } else { 1671 ptrans->stride = align(util_format_get_stride(pres->format, box->width), 1672 D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); 1673 ptrans->layer_stride = util_format_get_2d_size(pres->format, 1674 ptrans->stride, 1675 box->height); 1676 1677 if (res->base.b.target != PIPE_TEXTURE_3D) 1678 ptrans->layer_stride = align(ptrans->layer_stride, 1679 D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT); 1680 1681 if (util_format_has_depth(util_format_description(pres->format)) && 1682 screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED) { 1683 trans->zs_cpu_copy_stride = ptrans->stride; 1684 trans->zs_cpu_copy_layer_stride = ptrans->layer_stride; 1685 1686 ptrans->stride = align(util_format_get_stride(pres->format, pres->width0), 1687 D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); 1688 ptrans->layer_stride = util_format_get_2d_size(pres->format, 1689 ptrans->stride, 1690 pres->height0); 1691 1692 range.Begin = box->y * ptrans->stride + 1693 box->x * util_format_get_blocksize(pres->format); 1694 } 1695 1696 unsigned staging_res_size = ptrans->layer_stride * box->depth; 1697 if (res->base.b.target == PIPE_BUFFER) { 1698 /* To properly support ARB_map_buffer_alignment, we need to return a pointer 1699 * that's appropriately offset from a 64-byte-aligned base address. 1700 */ 1701 assert(box->x >= 0); 1702 unsigned aligned_x = (unsigned)box->x % BUFFER_MAP_ALIGNMENT; 1703 staging_res_size = align(box->width + aligned_x, 1704 D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); 1705 range.Begin = aligned_x; 1706 } 1707 1708 pipe_resource_usage staging_usage = (usage & (PIPE_MAP_DISCARD_RANGE | PIPE_MAP_DISCARD_WHOLE_RESOURCE)) ? 1709 PIPE_USAGE_STREAM : PIPE_USAGE_STAGING; 1710 1711 trans->staging_res = pipe_buffer_create(pctx->screen, 0, 1712 staging_usage, 1713 staging_res_size); 1714 if (!trans->staging_res) { 1715 slab_free(transfer_pool, trans); 1716 return NULL; 1717 } 1718 1719 struct d3d12_resource *staging_res = d3d12_resource(trans->staging_res); 1720 1721 if ((usage & (PIPE_MAP_DISCARD_RANGE | PIPE_MAP_DISCARD_WHOLE_RESOURCE | TC_TRANSFER_MAP_THREADED_UNSYNC)) == 0) { 1722 bool ret = true; 1723 if (pres->target == PIPE_BUFFER) { 1724 uint64_t src_offset = box->x; 1725 uint64_t dst_offset = src_offset % BUFFER_MAP_ALIGNMENT; 1726 transfer_buf_to_buf(ctx, res, staging_res, src_offset, dst_offset, box->width); 1727 } else 1728 ret = transfer_image_to_buf(ctx, res, staging_res, trans, 0); 1729 if (!ret) 1730 return NULL; 1731 d3d12_flush_cmdlist_and_wait(ctx); 1732 } 1733 1734 range.End = staging_res_size - range.Begin; 1735 1736 ptr = d3d12_bo_map(staging_res->bo, &range); 1737 } 1738 1739 pipe_resource_reference(&ptrans->resource, pres); 1740 *transfer = ptrans; 1741 return ptr; 1742} 1743 1744static void 1745d3d12_transfer_unmap(struct pipe_context *pctx, 1746 struct pipe_transfer *ptrans) 1747{ 1748 struct d3d12_context *ctx = d3d12_context(pctx); 1749 struct d3d12_resource *res = d3d12_resource(ptrans->resource); 1750 struct d3d12_transfer *trans = (struct d3d12_transfer *)ptrans; 1751 D3D12_RANGE range = { 0, 0 }; 1752 1753 if (trans->data != nullptr) { 1754 if (trans->base.b.usage & PIPE_MAP_WRITE) 1755 write_zs_surface(pctx, res, trans); 1756 free(trans->data); 1757 } else if (trans->staging_res) { 1758 if(util_format_is_yuv(res->overall_format)) { 1759 1760 /* Get planes information*/ 1761 unsigned num_planes = util_format_get_num_planes(res->overall_format); 1762 pipe_resource *planes[d3d12_max_planes]; 1763 unsigned int strides[d3d12_max_planes]; 1764 unsigned int layer_strides[d3d12_max_planes]; 1765 unsigned int offsets[d3d12_max_planes]; 1766 unsigned staging_res_size = 0; 1767 1768 d3d12_resource_get_planes_info( 1769 ptrans->resource, 1770 num_planes, 1771 planes, 1772 strides, 1773 layer_strides, 1774 offsets, 1775 &staging_res_size 1776 ); 1777 1778 /* Flush the changed contents into the GPU texture*/ 1779 1780 /* In theory we should just flush only the contents for the plane*/ 1781 /* requested in res->plane_slice, but the VAAPI frontend has this*/ 1782 /* behaviour in which they assume that mapping the first plane of*/ 1783 /* NV12, P010, etc resources will will give them a buffer containing*/ 1784 /* both Y and UV planes contigously in vaDeriveImage and then vaMapBuffer*/ 1785 /* so, flush them all*/ 1786 1787 struct d3d12_resource *staging_res = d3d12_resource(trans->staging_res); 1788 if (trans->base.b.usage & PIPE_MAP_WRITE) { 1789 assert(ptrans->box.x >= 0); 1790 range.Begin = res->base.b.target == PIPE_BUFFER ? 1791 (unsigned)ptrans->box.x % BUFFER_MAP_ALIGNMENT : 0; 1792 range.End = staging_res->base.b.width0 - range.Begin; 1793 1794 d3d12_bo_unmap(staging_res->bo, &range); 1795 pipe_box original_box = ptrans->box; 1796 for (uint plane_slice = 0; plane_slice < num_planes; ++plane_slice) { 1797 /* Adjust strides, offsets to the corresponding plane for the copytexture operation*/ 1798 d3d12_adjust_transfer_dimensions_for_plane(res, 1799 plane_slice, 1800 strides[plane_slice], 1801 layer_strides[plane_slice], 1802 offsets[plane_slice], 1803 &original_box, 1804 ptrans/*inout*/); 1805 1806 transfer_buf_to_image(ctx, d3d12_resource(planes[plane_slice]), staging_res, trans, 0); 1807 } 1808 } 1809 1810 pipe_resource_reference(&trans->staging_res, NULL); 1811 } else { 1812 struct d3d12_resource *staging_res = d3d12_resource(trans->staging_res); 1813 if (trans->base.b.usage & PIPE_MAP_WRITE) { 1814 assert(ptrans->box.x >= 0); 1815 range.Begin = res->base.b.target == PIPE_BUFFER ? 1816 (unsigned)ptrans->box.x % BUFFER_MAP_ALIGNMENT : 0; 1817 range.End = staging_res->base.b.width0 - range.Begin; 1818 } 1819 d3d12_bo_unmap(staging_res->bo, &range); 1820 1821 if (trans->base.b.usage & PIPE_MAP_WRITE) { 1822 struct d3d12_context *ctx = d3d12_context(pctx); 1823 if (res->base.b.target == PIPE_BUFFER) { 1824 uint64_t dst_offset = trans->base.b.box.x; 1825 uint64_t src_offset = dst_offset % BUFFER_MAP_ALIGNMENT; 1826 transfer_buf_to_buf(ctx, staging_res, res, src_offset, dst_offset, ptrans->box.width); 1827 } else 1828 transfer_buf_to_image(ctx, res, staging_res, trans, 0); 1829 } 1830 1831 pipe_resource_reference(&trans->staging_res, NULL); 1832 } 1833 } else { 1834 if (trans->base.b.usage & PIPE_MAP_WRITE) { 1835 range.Begin = ptrans->box.x; 1836 range.End = ptrans->box.x + ptrans->box.width; 1837 } 1838 d3d12_bo_unmap(res->bo, &range); 1839 } 1840 1841 pipe_resource_reference(&ptrans->resource, NULL); 1842 slab_free(&d3d12_context(pctx)->transfer_pool, ptrans); 1843} 1844 1845void 1846d3d12_context_resource_init(struct pipe_context *pctx) 1847{ 1848 pctx->buffer_map = d3d12_transfer_map; 1849 pctx->buffer_unmap = d3d12_transfer_unmap; 1850 pctx->texture_map = d3d12_transfer_map; 1851 pctx->texture_unmap = d3d12_transfer_unmap; 1852 1853 pctx->transfer_flush_region = u_default_transfer_flush_region; 1854 pctx->buffer_subdata = u_default_buffer_subdata; 1855 pctx->texture_subdata = u_default_texture_subdata; 1856} 1857