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