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