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