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_context.h"
25 #include "d3d12_compiler.h"
26 #include "d3d12_debug.h"
27 #include "d3d12_format.h"
28 #include "d3d12_query.h"
29 #include "d3d12_resource.h"
30 #include "d3d12_screen.h"
31
32 #include "util/u_blitter.h"
33 #include "util/format/u_format.h"
34
35 #include "nir_to_dxil.h"
36 #include "nir_builder.h"
37
38 static void
copy_buffer_region_no_barriers(struct d3d12_context * ctx,struct d3d12_resource * dst,uint64_t dst_offset,struct d3d12_resource * src,uint64_t src_offset,uint64_t size)39 copy_buffer_region_no_barriers(struct d3d12_context *ctx,
40 struct d3d12_resource *dst,
41 uint64_t dst_offset,
42 struct d3d12_resource *src,
43 uint64_t src_offset,
44 uint64_t size)
45 {
46 uint64_t dst_off, src_off;
47 ID3D12Resource *dst_buf = d3d12_resource_underlying(dst, &dst_off);
48 ID3D12Resource *src_buf = d3d12_resource_underlying(src, &src_off);
49
50 ctx->cmdlist->CopyBufferRegion(dst_buf, dst_offset + dst_off,
51 src_buf, src_offset + src_off,
52 size);
53 }
54
55 static bool
is_resolve(const struct pipe_blit_info * info)56 is_resolve(const struct pipe_blit_info *info)
57 {
58 return info->src.resource->nr_samples > 1 &&
59 info->dst.resource->nr_samples <= 1;
60 }
61
62 static bool
resolve_supported(const struct pipe_blit_info * info)63 resolve_supported(const struct pipe_blit_info *info)
64 {
65 assert(is_resolve(info));
66
67 // check for unsupported operations
68 if (util_format_is_depth_or_stencil(info->src.format) &&
69 info->mask != PIPE_MASK_Z) {
70 return false;
71 } else {
72 if (util_format_get_mask(info->dst.format) != info->mask ||
73 util_format_get_mask(info->src.format) != info->mask ||
74 util_format_has_alpha1(info->src.format))
75 return false;
76 }
77
78 if (info->filter != PIPE_TEX_FILTER_NEAREST ||
79 info->scissor_enable ||
80 info->num_window_rectangles > 0 ||
81 info->alpha_blend)
82 return false;
83
84 // formats need to match
85 struct d3d12_resource *src = d3d12_resource(info->src.resource);
86 struct d3d12_resource *dst = d3d12_resource(info->dst.resource);
87 if (src->dxgi_format != dst->dxgi_format)
88 return false;
89
90 if (util_format_is_pure_integer(src->base.b.format))
91 return false;
92
93 // sizes needs to match
94 if (info->src.box.width != info->dst.box.width ||
95 info->src.box.height != info->dst.box.height)
96 return false;
97
98 // can only resolve full subresource
99 if (info->src.box.width != (int)u_minify(info->src.resource->width0,
100 info->src.level) ||
101 info->src.box.height != (int)u_minify(info->src.resource->height0,
102 info->src.level) ||
103 info->dst.box.width != (int)u_minify(info->dst.resource->width0,
104 info->dst.level) ||
105 info->dst.box.height != (int)u_minify(info->dst.resource->height0,
106 info->dst.level))
107 return false;
108
109 return true;
110 }
111
112 static void
blit_resolve(struct d3d12_context * ctx,const struct pipe_blit_info * info)113 blit_resolve(struct d3d12_context *ctx, const struct pipe_blit_info *info)
114 {
115 struct d3d12_batch *batch = d3d12_current_batch(ctx);
116 struct d3d12_resource *src = d3d12_resource(info->src.resource);
117 struct d3d12_resource *dst = d3d12_resource(info->dst.resource);
118
119 d3d12_transition_resource_state(ctx, src,
120 D3D12_RESOURCE_STATE_RESOLVE_SOURCE,
121 D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
122 d3d12_transition_resource_state(ctx, dst,
123 D3D12_RESOURCE_STATE_RESOLVE_DEST,
124 D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
125
126 d3d12_apply_resource_states(ctx, false);
127
128 d3d12_batch_reference_resource(batch, src, false);
129 d3d12_batch_reference_resource(batch, dst, true);
130
131 DXGI_FORMAT dxgi_format = d3d12_get_resource_srv_format(src->base.b.format, src->base.b.target);
132
133 assert(src->dxgi_format == dst->dxgi_format);
134 ctx->cmdlist->ResolveSubresource(
135 d3d12_resource_resource(dst), info->dst.level,
136 d3d12_resource_resource(src), info->src.level,
137 dxgi_format);
138 }
139
140 static bool
formats_are_copy_compatible(enum pipe_format src,enum pipe_format dst)141 formats_are_copy_compatible(enum pipe_format src, enum pipe_format dst)
142 {
143 if (src == dst)
144 return true;
145
146 /* We can skip the stencil copy */
147 if (util_format_get_depth_only(src) == dst ||
148 util_format_get_depth_only(dst) == src)
149 return true;
150
151 return false;
152 }
153
154 static bool
box_fits(const struct pipe_box * box,const struct pipe_resource * res,int level)155 box_fits(const struct pipe_box *box, const struct pipe_resource *res, int level)
156 {
157 unsigned lwidth = u_minify(res->width0, level);
158 unsigned lheight= u_minify(res->height0, level);
159 unsigned ldepth = res->target == PIPE_TEXTURE_3D ? u_minify(res->depth0, level) :
160 res->array_size;
161
162 unsigned wb = box->x;
163 unsigned we = box->x + box->width;
164
165 unsigned hb = box->y;
166 unsigned he = box->y + box->height;
167
168 unsigned db = box->z;
169 unsigned de = box->z + box->depth;
170
171 return (wb <= lwidth && we <= lwidth &&
172 hb <= lheight && he <= lheight &&
173 db <= ldepth && de <= ldepth);
174 }
175
176 static bool
direct_copy_supported(struct d3d12_screen * screen,const struct pipe_blit_info * info,bool have_predication)177 direct_copy_supported(struct d3d12_screen *screen,
178 const struct pipe_blit_info *info,
179 bool have_predication)
180 {
181 if (info->scissor_enable || info->alpha_blend ||
182 (have_predication && info->render_condition_enable) ||
183 MAX2(info->src.resource->nr_samples, 1) != MAX2(info->dst.resource->nr_samples, 1)) {
184 return false;
185 }
186
187 if (!formats_are_copy_compatible(info->src.format, info->dst.format))
188 return false;
189
190 if (info->src.format != info->src.resource->format ||
191 info->dst.format != info->dst.resource->format)
192 return false;
193
194 if (util_format_is_depth_or_stencil(info->src.format) && !(info->mask & PIPE_MASK_ZS)) {
195 return false;
196 }
197
198 if (!util_format_is_depth_or_stencil(info->src.format)) {
199 if (util_format_get_mask(info->dst.format) != info->mask ||
200 util_format_get_mask(info->src.format) != info->mask)
201 return false;
202 }
203
204 if (abs(info->src.box.height) != info->dst.box.height) {
205 return false;
206 }
207
208 if (info->src.box.height != info->dst.box.height &&
209 (!util_format_is_depth_or_stencil(info->src.format) ||
210 screen->opts2.ProgrammableSamplePositionsTier ==
211 D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED)) {
212 return false;
213 }
214
215 if (!box_fits(&info->dst.box, info->dst.resource, info->dst.level)) {
216 return false;
217 }
218 if (!box_fits(&info->src.box, info->src.resource, info->src.level)) {
219 return false;
220 }
221
222 if (info->src.box.width != info->dst.box.width) {
223 return false;
224 }
225
226 if (info->src.box.depth != info->dst.box.depth) {
227 return false;
228 }
229
230 if ((screen->opts2.ProgrammableSamplePositionsTier ==
231 D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED &&
232 (info->src.resource->bind & PIPE_BIND_DEPTH_STENCIL ||
233 info->dst.resource->bind & PIPE_BIND_DEPTH_STENCIL)) ||
234 info->src.resource->nr_samples != info->dst.resource->nr_samples) {
235
236 if (info->dst.box.x != 0 ||
237 info->dst.box.y != 0 ||
238 info->dst.box.z != 0)
239 return false;
240
241 if (info->src.box.x != 0 ||
242 info->src.box.y != 0 ||
243 info->src.box.z != 0 ||
244 info->src.box.width != (int)u_minify(info->src.resource->width0,
245 info->src.level) ||
246 info->src.box.height != (int)u_minify(info->src.resource->height0,
247 info->src.level) ||
248 info->src.box.depth != (int)u_minify(info->src.resource->depth0,
249 info->src.level))
250 return false;
251 }
252
253 return true;
254 }
255
256 inline static unsigned
get_subresource_id(enum pipe_texture_target target,unsigned subres,unsigned stride,unsigned z,unsigned * updated_z,unsigned array_size,unsigned plane_slice)257 get_subresource_id(enum pipe_texture_target target, unsigned subres, unsigned stride,
258 unsigned z, unsigned *updated_z, unsigned array_size, unsigned plane_slice)
259 {
260 if (d3d12_subresource_id_uses_layer(target)) {
261 subres += stride * z;
262 if (updated_z)
263 *updated_z = 0;
264 }
265 return subres + plane_slice * array_size * stride;
266 }
267
268 static void
copy_subregion_no_barriers(struct d3d12_context * ctx,struct d3d12_resource * dst,unsigned dst_level,unsigned dstx,unsigned dsty,unsigned dstz,struct d3d12_resource * src,unsigned src_level,const struct pipe_box * psrc_box,unsigned mask)269 copy_subregion_no_barriers(struct d3d12_context *ctx,
270 struct d3d12_resource *dst,
271 unsigned dst_level,
272 unsigned dstx, unsigned dsty, unsigned dstz,
273 struct d3d12_resource *src,
274 unsigned src_level,
275 const struct pipe_box *psrc_box,
276 unsigned mask)
277 {
278 UNUSED struct d3d12_screen *screen = d3d12_screen(ctx->base.screen);
279 D3D12_TEXTURE_COPY_LOCATION src_loc, dst_loc;
280 unsigned src_z = psrc_box->z;
281
282 int src_subres_stride = src->base.b.last_level + 1;
283 int dst_subres_stride = dst->base.b.last_level + 1;
284
285 int src_array_size = src->base.b.array_size;
286 int dst_array_size = dst->base.b.array_size;
287
288 int stencil_src_res_offset = 1;
289 int stencil_dst_res_offset = 1;
290
291 int src_nres = 1;
292 int dst_nres = 1;
293
294 if (dst->base.b.format == PIPE_FORMAT_Z24_UNORM_S8_UINT ||
295 dst->base.b.format == PIPE_FORMAT_S8_UINT_Z24_UNORM ||
296 dst->base.b.format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT) {
297 stencil_dst_res_offset = dst_subres_stride * dst_array_size;
298 src_nres = 2;
299 }
300
301 if (src->base.b.format == PIPE_FORMAT_Z24_UNORM_S8_UINT ||
302 src->base.b.format == PIPE_FORMAT_S8_UINT_Z24_UNORM ||
303 dst->base.b.format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT) {
304 stencil_src_res_offset = src_subres_stride * src_array_size;
305 dst_nres = 2;
306 }
307
308 static_assert(PIPE_MASK_S == 0x20 && PIPE_MASK_Z == 0x10, "unexpected ZS format mask");
309 int nsubres = MIN2(src_nres, dst_nres);
310 unsigned subresource_copy_mask = nsubres > 1 ? mask >> 4 : 1;
311
312 for (int subres = 0; subres < nsubres; ++subres) {
313
314 if (!(subresource_copy_mask & (1 << subres)))
315 continue;
316
317 src_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
318 src_loc.SubresourceIndex = get_subresource_id(src->base.b.target, src_level, src_subres_stride, src_z, &src_z, src_array_size, src->plane_slice) +
319 subres * stencil_src_res_offset;
320 src_loc.pResource = d3d12_resource_resource(src);
321
322 dst_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
323 dst_loc.SubresourceIndex = get_subresource_id(dst->base.b.target, dst_level, dst_subres_stride, dstz, &dstz, dst_array_size, dst->plane_slice) +
324 subres * stencil_dst_res_offset;
325 dst_loc.pResource = d3d12_resource_resource(dst);
326
327 if (psrc_box->x == 0 && psrc_box->y == 0 && psrc_box->z == 0 &&
328 psrc_box->width == (int)u_minify(src->base.b.width0, src_level) &&
329 psrc_box->height == (int)u_minify(src->base.b.height0, src_level) &&
330 psrc_box->depth == (int)u_minify(src->base.b.depth0, src_level)) {
331
332 assert((dstx == 0 && dsty == 0 && dstz == 0) ||
333 screen->opts2.ProgrammableSamplePositionsTier !=
334 D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED ||
335 (!util_format_is_depth_or_stencil(dst->base.b.format) &&
336 !util_format_is_depth_or_stencil(src->base.b.format) &&
337 dst->base.b.nr_samples == src->base.b.nr_samples));
338
339 ctx->cmdlist->CopyTextureRegion(&dst_loc, dstx, dsty, dstz,
340 &src_loc, NULL);
341
342 } else {
343 D3D12_BOX src_box;
344 src_box.left = psrc_box->x;
345 src_box.right = MIN2(psrc_box->x + psrc_box->width, (int)u_minify(src->base.b.width0, src_level));
346 src_box.top = psrc_box->y;
347 src_box.bottom = MIN2(psrc_box->y + psrc_box->height, (int)u_minify(src->base.b.height0, src_level));
348 src_box.front = src_z;
349 src_box.back = src_z + psrc_box->depth;
350
351 assert((screen->opts2.ProgrammableSamplePositionsTier !=
352 D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED ||
353 (!util_format_is_depth_or_stencil(dst->base.b.format) &&
354 !util_format_is_depth_or_stencil(src->base.b.format))) &&
355 dst->base.b.nr_samples == src->base.b.nr_samples);
356
357 ctx->cmdlist->CopyTextureRegion(&dst_loc, dstx, dsty, dstz,
358 &src_loc, &src_box);
359 }
360 }
361 }
362
363 static void
copy_resource_y_flipped_no_barriers(struct d3d12_context * ctx,struct d3d12_resource * dst,unsigned dst_level,const struct pipe_box * pdst_box,struct d3d12_resource * src,unsigned src_level,const struct pipe_box * psrc_box,unsigned mask)364 copy_resource_y_flipped_no_barriers(struct d3d12_context *ctx,
365 struct d3d12_resource *dst,
366 unsigned dst_level,
367 const struct pipe_box *pdst_box,
368 struct d3d12_resource *src,
369 unsigned src_level,
370 const struct pipe_box *psrc_box,
371 unsigned mask)
372 {
373 if (D3D12_DEBUG_BLIT & d3d12_debug) {
374 debug_printf("D3D12 BLIT as COPY: from %s@%d %dx%dx%d + %dx%dx%d\n",
375 util_format_name(src->base.b.format), src_level,
376 psrc_box->x, psrc_box->y, psrc_box->z,
377 psrc_box->width, psrc_box->height, psrc_box->depth);
378 debug_printf(" to %s@%d %dx%dx%d\n",
379 util_format_name(dst->base.b.format), dst_level,
380 pdst_box->x, pdst_box->y, pdst_box->z);
381 }
382
383 struct pipe_box src_box = *psrc_box;
384 int src_inc = psrc_box->height > 0 ? 1 : -1;
385 int dst_inc = pdst_box->height > 0 ? 1 : -1;
386 src_box.height = 1;
387 int rows_to_copy = abs(psrc_box->height);
388
389 if (psrc_box->height < 0)
390 --src_box.y;
391
392 for (int y = 0, dest_y = pdst_box->y; y < rows_to_copy;
393 ++y, src_box.y += src_inc, dest_y += dst_inc) {
394 copy_subregion_no_barriers(ctx, dst, dst_level,
395 pdst_box->x, dest_y, pdst_box->z,
396 src, src_level, &src_box, mask);
397 }
398 }
399
400 void
d3d12_direct_copy(struct d3d12_context * ctx,struct d3d12_resource * dst,unsigned dst_level,const struct pipe_box * pdst_box,struct d3d12_resource * src,unsigned src_level,const struct pipe_box * psrc_box,unsigned mask)401 d3d12_direct_copy(struct d3d12_context *ctx,
402 struct d3d12_resource *dst,
403 unsigned dst_level,
404 const struct pipe_box *pdst_box,
405 struct d3d12_resource *src,
406 unsigned src_level,
407 const struct pipe_box *psrc_box,
408 unsigned mask)
409 {
410 struct d3d12_batch *batch = d3d12_current_batch(ctx);
411
412 unsigned src_subres = get_subresource_id(src->base.b.target, src_level, src->base.b.last_level + 1,
413 psrc_box->z, nullptr, src->base.b.array_size, src->plane_slice);
414 unsigned dst_subres = get_subresource_id(dst->base.b.target, dst_level, dst->base.b.last_level + 1,
415 pdst_box->z, nullptr, dst->base.b.array_size, dst->plane_slice);
416
417 if (D3D12_DEBUG_BLIT & d3d12_debug)
418 debug_printf("BLIT: Direct copy from subres %d to subres %d\n",
419 src_subres, dst_subres);
420
421 d3d12_transition_subresources_state(ctx, src, src_subres, 1, 0, 1,
422 d3d12_get_format_start_plane(src->base.b.format),
423 d3d12_get_format_num_planes(src->base.b.format),
424 D3D12_RESOURCE_STATE_COPY_SOURCE,
425 D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
426
427 d3d12_transition_subresources_state(ctx, dst, dst_subres, 1, 0, 1,
428 d3d12_get_format_start_plane(dst->base.b.format),
429 d3d12_get_format_num_planes(dst->base.b.format),
430 D3D12_RESOURCE_STATE_COPY_DEST,
431 D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
432
433 d3d12_apply_resource_states(ctx, false);
434
435 d3d12_batch_reference_resource(batch, src, false);
436 d3d12_batch_reference_resource(batch, dst, true);
437
438 if (src->base.b.target == PIPE_BUFFER) {
439 copy_buffer_region_no_barriers(ctx, dst, pdst_box->x,
440 src, psrc_box->x, psrc_box->width);
441 } else if (psrc_box->height == pdst_box->height) {
442 /* No flipping, we can forward this directly to resource_copy_region */
443 copy_subregion_no_barriers(ctx, dst, dst_level,
444 pdst_box->x, pdst_box->y, pdst_box->z,
445 src, src_level, psrc_box, mask);
446 } else {
447 assert(psrc_box->height == -pdst_box->height);
448 copy_resource_y_flipped_no_barriers(ctx, dst, dst_level, pdst_box,
449 src, src_level, psrc_box, mask);
450 }
451 }
452
453 static bool
is_same_resource(const struct pipe_blit_info * info)454 is_same_resource(const struct pipe_blit_info *info)
455 {
456 return d3d12_resource_resource(d3d12_resource(info->src.resource)) ==
457 d3d12_resource_resource(d3d12_resource(info->dst.resource)) &&
458 info->src.level == info->dst.level;
459 }
460
461 static struct pipe_resource *
create_staging_resource(struct d3d12_context * ctx,struct d3d12_resource * src,unsigned src_level,const struct pipe_box * src_box,struct pipe_box * dst_box,unsigned mask)462 create_staging_resource(struct d3d12_context *ctx,
463 struct d3d12_resource *src,
464 unsigned src_level,
465 const struct pipe_box *src_box,
466 struct pipe_box *dst_box,
467 unsigned mask)
468
469 {
470 struct pipe_resource templ = {};
471 struct pipe_resource *staging_res;
472 struct pipe_box copy_src;
473
474 u_box_3d(MIN2(src_box->x, src_box->x + src_box->width),
475 MIN2(src_box->y, src_box->y + src_box->height),
476 MIN2(src_box->z, src_box->z + src_box->depth),
477 abs(src_box->width), abs(src_box->height), abs(src_box->depth),
478 ©_src);
479
480 templ.format = src->base.b.format;
481 templ.width0 = copy_src.width;
482 templ.height0 = copy_src.height;
483 templ.depth0 = copy_src.depth;
484 templ.array_size = 1;
485 templ.nr_samples = src->base.b.nr_samples;
486 templ.nr_storage_samples = src->base.b.nr_storage_samples;
487 templ.usage = PIPE_USAGE_STAGING;
488 templ.bind = util_format_is_depth_or_stencil(templ.format) ? PIPE_BIND_DEPTH_STENCIL :
489 util_format_is_compressed(templ.format) ? 0 : PIPE_BIND_RENDER_TARGET;
490 templ.target = src->base.b.target;
491
492 staging_res = ctx->base.screen->resource_create(ctx->base.screen, &templ);
493
494 dst_box->x = 0;
495 dst_box->y = 0;
496 dst_box->z = 0;
497 dst_box->width = copy_src.width;
498 dst_box->height = copy_src.height;
499 dst_box->depth = copy_src.depth;
500
501 d3d12_direct_copy(ctx, d3d12_resource(staging_res), 0, dst_box,
502 src, src_level, ©_src, mask);
503
504 if (src_box->width < 0) {
505 dst_box->x = dst_box->width;
506 dst_box->width = src_box->width;
507 }
508
509 if (src_box->height < 0) {
510 dst_box->y = dst_box->height;
511 dst_box->height = src_box->height;
512 }
513
514 if (src_box->depth < 0) {
515 dst_box->z = dst_box->depth;
516 dst_box->depth = src_box->depth;
517 }
518 return staging_res;
519 }
520
521 static void
blit_same_resource(struct d3d12_context * ctx,const struct pipe_blit_info * info)522 blit_same_resource(struct d3d12_context *ctx,
523 const struct pipe_blit_info *info)
524 {
525 struct pipe_blit_info dst_info = *info;
526
527 dst_info.src.level = 0;
528 dst_info.src.resource = create_staging_resource(ctx, d3d12_resource(info->src.resource),
529 info->src.level,
530 &info->src.box,
531 &dst_info.src.box, PIPE_MASK_RGBAZS);
532 ctx->base.blit(&ctx->base, &dst_info);
533 pipe_resource_reference(&dst_info.src.resource, NULL);
534 }
535
536 static void
util_blit_save_state(struct d3d12_context * ctx)537 util_blit_save_state(struct d3d12_context *ctx)
538 {
539 util_blitter_save_blend(ctx->blitter, ctx->gfx_pipeline_state.blend);
540 util_blitter_save_depth_stencil_alpha(ctx->blitter, ctx->gfx_pipeline_state.zsa);
541 util_blitter_save_vertex_elements(ctx->blitter, ctx->gfx_pipeline_state.ves);
542 util_blitter_save_stencil_ref(ctx->blitter, &ctx->stencil_ref);
543 util_blitter_save_rasterizer(ctx->blitter, ctx->gfx_pipeline_state.rast);
544 util_blitter_save_fragment_shader(ctx->blitter, ctx->gfx_stages[PIPE_SHADER_FRAGMENT]);
545 util_blitter_save_vertex_shader(ctx->blitter, ctx->gfx_stages[PIPE_SHADER_VERTEX]);
546 util_blitter_save_geometry_shader(ctx->blitter, ctx->gfx_stages[PIPE_SHADER_GEOMETRY]);
547 util_blitter_save_tessctrl_shader(ctx->blitter, ctx->gfx_stages[PIPE_SHADER_TESS_CTRL]);
548 util_blitter_save_tesseval_shader(ctx->blitter, ctx->gfx_stages[PIPE_SHADER_TESS_EVAL]);
549
550 util_blitter_save_framebuffer(ctx->blitter, &ctx->fb);
551 util_blitter_save_viewport(ctx->blitter, ctx->viewport_states);
552 util_blitter_save_scissor(ctx->blitter, ctx->scissor_states);
553 util_blitter_save_fragment_sampler_states(ctx->blitter,
554 ctx->num_samplers[PIPE_SHADER_FRAGMENT],
555 (void **)ctx->samplers[PIPE_SHADER_FRAGMENT]);
556 util_blitter_save_fragment_sampler_views(ctx->blitter,
557 ctx->num_sampler_views[PIPE_SHADER_FRAGMENT],
558 ctx->sampler_views[PIPE_SHADER_FRAGMENT]);
559 util_blitter_save_fragment_constant_buffer_slot(ctx->blitter, ctx->cbufs[PIPE_SHADER_FRAGMENT]);
560 util_blitter_save_vertex_buffers(ctx->blitter, ctx->vbs, ctx->num_vbs);
561 util_blitter_save_sample_mask(ctx->blitter, ctx->gfx_pipeline_state.sample_mask, 0);
562 util_blitter_save_so_targets(ctx->blitter, ctx->gfx_pipeline_state.num_so_targets, ctx->so_targets);
563 }
564
565 static void
util_blit(struct d3d12_context * ctx,const struct pipe_blit_info * info)566 util_blit(struct d3d12_context *ctx,
567 const struct pipe_blit_info *info)
568 {
569 util_blit_save_state(ctx);
570
571 util_blitter_blit(ctx->blitter, info);
572 }
573
574 static bool
resolve_stencil_supported(struct d3d12_context * ctx,const struct pipe_blit_info * info)575 resolve_stencil_supported(struct d3d12_context *ctx,
576 const struct pipe_blit_info *info)
577 {
578 assert(is_resolve(info));
579
580 if (!util_format_is_depth_or_stencil(info->src.format) ||
581 !(info->mask & PIPE_MASK_S))
582 return false;
583
584 if (info->mask & PIPE_MASK_Z) {
585 struct pipe_blit_info new_info = *info;
586 new_info.mask = PIPE_MASK_Z;
587 if (!resolve_supported(&new_info) &&
588 !util_blitter_is_blit_supported(ctx->blitter, &new_info))
589 return false;
590 }
591
592 struct pipe_blit_info new_info = *info;
593 new_info.dst.format = PIPE_FORMAT_R8_UINT;
594 return util_blitter_is_blit_supported(ctx->blitter, &new_info);
595 }
596
597 static struct pipe_resource *
create_tmp_resource(struct pipe_screen * screen,const struct pipe_blit_info * info)598 create_tmp_resource(struct pipe_screen *screen,
599 const struct pipe_blit_info *info)
600 {
601 struct pipe_resource tpl = {};
602 tpl.width0 = info->dst.box.width;
603 tpl.height0 = info->dst.box.height;
604 tpl.depth0 = info->dst.box.depth;
605 tpl.array_size = 1;
606 tpl.format = PIPE_FORMAT_R8_UINT;
607 tpl.target = info->dst.resource->target;
608 tpl.nr_samples = info->dst.resource->nr_samples;
609 tpl.nr_storage_samples = info->dst.resource->nr_storage_samples;
610 tpl.usage = PIPE_USAGE_STREAM;
611 tpl.bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
612 return screen->resource_create(screen, &tpl);
613 }
614
615 static void *
get_stencil_resolve_vs(struct d3d12_context * ctx)616 get_stencil_resolve_vs(struct d3d12_context *ctx)
617 {
618 if (ctx->stencil_resolve_vs)
619 return ctx->stencil_resolve_vs;
620
621 nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_VERTEX,
622 &d3d12_screen(ctx->base.screen)->nir_options,
623 "linear_blit_vs");
624
625 const struct glsl_type *vec4 = glsl_vec4_type();
626 nir_variable *pos_in = nir_variable_create(b.shader, nir_var_shader_in,
627 vec4, "pos");
628
629 nir_variable *pos_out = nir_variable_create(b.shader, nir_var_shader_out,
630 vec4, "gl_Position");
631 pos_out->data.location = VARYING_SLOT_POS;
632
633 nir_store_var(&b, pos_out, nir_load_var(&b, pos_in), 0xf);
634
635 struct pipe_shader_state state = {};
636 state.type = PIPE_SHADER_IR_NIR;
637 state.ir.nir = b.shader;
638 ctx->stencil_resolve_vs = ctx->base.create_vs_state(&ctx->base, &state);
639
640 return ctx->stencil_resolve_vs;
641 }
642
643 static void *
get_stencil_resolve_fs(struct d3d12_context * ctx,bool no_flip)644 get_stencil_resolve_fs(struct d3d12_context *ctx, bool no_flip)
645 {
646 if (!no_flip && ctx->stencil_resolve_fs)
647 return ctx->stencil_resolve_fs;
648
649 if (no_flip && ctx->stencil_resolve_fs_no_flip)
650 return ctx->stencil_resolve_fs_no_flip;
651
652 nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_FRAGMENT,
653 &d3d12_screen(ctx->base.screen)->nir_options,
654 no_flip ? "stencil_resolve_fs_no_flip" : "stencil_resolve_fs");
655
656 nir_variable *stencil_out = nir_variable_create(b.shader,
657 nir_var_shader_out,
658 glsl_uint_type(),
659 "stencil_out");
660 stencil_out->data.location = FRAG_RESULT_COLOR;
661
662 const struct glsl_type *sampler_type =
663 glsl_sampler_type(GLSL_SAMPLER_DIM_MS, false, false, GLSL_TYPE_UINT);
664 nir_variable *sampler = nir_variable_create(b.shader, nir_var_uniform,
665 sampler_type, "stencil_tex");
666 sampler->data.binding = 0;
667 sampler->data.explicit_binding = true;
668
669 nir_def *tex_deref = &nir_build_deref_var(&b, sampler)->def;
670
671 nir_variable *pos_in = nir_variable_create(b.shader, nir_var_shader_in,
672 glsl_vec4_type(), "pos");
673 pos_in->data.location = VARYING_SLOT_POS; // VARYING_SLOT_VAR0?
674 nir_def *pos = nir_load_var(&b, pos_in);
675
676 nir_def *pos_src;
677
678 if (no_flip)
679 pos_src = pos;
680 else {
681 nir_tex_instr *txs = nir_tex_instr_create(b.shader, 1);
682 txs->op = nir_texop_txs;
683 txs->sampler_dim = GLSL_SAMPLER_DIM_MS;
684 txs->src[0] = nir_tex_src_for_ssa(nir_tex_src_texture_deref, tex_deref);
685 txs->is_array = false;
686 txs->dest_type = nir_type_int;
687
688 nir_def_init(&txs->instr, &txs->def, 2, 32);
689 nir_builder_instr_insert(&b, &txs->instr);
690
691 pos_src = nir_vec4(&b,
692 nir_channel(&b, pos, 0),
693 /*Height - pos_dest.y - 1*/
694 nir_fsub(&b,
695 nir_fsub(&b,
696 nir_channel(&b, nir_i2f32(&b, &txs->def), 1),
697 nir_channel(&b, pos, 1)),
698 nir_imm_float(&b, 1.0)),
699 nir_channel(&b, pos, 2),
700 nir_channel(&b, pos, 3));
701 }
702
703 nir_tex_instr *tex = nir_tex_instr_create(b.shader, 3);
704 tex->sampler_dim = GLSL_SAMPLER_DIM_MS;
705 tex->op = nir_texop_txf_ms;
706 tex->src[0] = nir_tex_src_for_ssa(nir_tex_src_coord,
707 nir_trim_vector(&b, nir_f2i32(&b, pos_src), 2));
708 tex->src[1] = nir_tex_src_for_ssa(nir_tex_src_ms_index, nir_imm_int(&b, 0)); /* just use first sample */
709 tex->src[2] = nir_tex_src_for_ssa(nir_tex_src_texture_deref, tex_deref);
710 tex->dest_type = nir_type_uint32;
711 tex->is_array = false;
712 tex->coord_components = 2;
713
714 nir_def_init(&tex->instr, &tex->def, 4, 32);
715 nir_builder_instr_insert(&b, &tex->instr);
716
717 nir_store_var(&b, stencil_out, nir_channel(&b, &tex->def, 1), 0x1);
718
719 struct pipe_shader_state state = {};
720 state.type = PIPE_SHADER_IR_NIR;
721 state.ir.nir = b.shader;
722 void *result;
723 if (no_flip) {
724 result = ctx->base.create_fs_state(&ctx->base, &state);
725 ctx->stencil_resolve_fs_no_flip = result;
726 } else {
727 result = ctx->base.create_fs_state(&ctx->base, &state);
728 ctx->stencil_resolve_fs = result;
729 }
730
731 return result;
732 }
733
734 static void *
get_sampler_state(struct d3d12_context * ctx)735 get_sampler_state(struct d3d12_context *ctx)
736 {
737 if (ctx->sampler_state)
738 return ctx->sampler_state;
739
740 struct pipe_sampler_state state;
741 memset(&state, 0, sizeof(state));
742 state.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
743 state.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
744 state.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
745
746 return ctx->sampler_state = ctx->base.create_sampler_state(&ctx->base, &state);
747 }
748
749 static struct pipe_resource *
resolve_stencil_to_temp(struct d3d12_context * ctx,const struct pipe_blit_info * info)750 resolve_stencil_to_temp(struct d3d12_context *ctx,
751 const struct pipe_blit_info *info)
752 {
753 struct pipe_context *pctx = &ctx->base;
754 struct pipe_resource *tmp = create_tmp_resource(pctx->screen, info);
755 if (!tmp) {
756 debug_printf("D3D12: failed to create stencil-resolve temp-resource\n");
757 return NULL;
758 }
759 assert(tmp->nr_samples < 2);
760
761 /* resolve stencil into tmp */
762 struct pipe_surface dst_tmpl;
763 util_blitter_default_dst_texture(&dst_tmpl, tmp, 0, 0);
764 dst_tmpl.format = tmp->format;
765 struct pipe_surface *dst_surf = pctx->create_surface(pctx, tmp, &dst_tmpl);
766 if (!dst_surf) {
767 debug_printf("D3D12: failed to create stencil-resolve dst-surface\n");
768 return NULL;
769 }
770
771 struct pipe_sampler_view src_templ, *src_view;
772 util_blitter_default_src_texture(ctx->blitter, &src_templ,
773 info->src.resource, info->src.level);
774 src_templ.format = util_format_stencil_only(info->src.format);
775 src_view = pctx->create_sampler_view(pctx, info->src.resource, &src_templ);
776
777 void *sampler_state = get_sampler_state(ctx);
778
779 util_blit_save_state(ctx);
780 pctx->set_sampler_views(pctx, PIPE_SHADER_FRAGMENT, 0, 1, 0, false, &src_view);
781 pctx->bind_sampler_states(pctx, PIPE_SHADER_FRAGMENT, 0, 1, &sampler_state);
782 util_blitter_custom_shader(ctx->blitter, dst_surf,
783 get_stencil_resolve_vs(ctx),
784 get_stencil_resolve_fs(ctx, info->src.box.height == info->dst.box.height));
785 util_blitter_restore_textures(ctx->blitter);
786 pipe_surface_reference(&dst_surf, NULL);
787 pipe_sampler_view_reference(&src_view, NULL);
788 return tmp;
789 }
790
791 static void
blit_resolve_stencil(struct d3d12_context * ctx,const struct pipe_blit_info * info)792 blit_resolve_stencil(struct d3d12_context *ctx,
793 const struct pipe_blit_info *info)
794 {
795 assert(info->mask & PIPE_MASK_S);
796
797 if (D3D12_DEBUG_BLIT & d3d12_debug)
798 debug_printf("D3D12 BLIT: blit_resolve_stencil\n");
799
800 if (info->mask & PIPE_MASK_Z) {
801 /* resolve depth into dst */
802 struct pipe_blit_info new_info = *info;
803 new_info.mask = PIPE_MASK_Z;
804
805 if (resolve_supported(&new_info))
806 blit_resolve(ctx, &new_info);
807 else
808 util_blit(ctx, &new_info);
809 }
810
811 struct pipe_resource *tmp = resolve_stencil_to_temp(ctx, info);
812
813
814 /* copy resolved stencil into dst */
815 struct d3d12_resource *dst = d3d12_resource(info->dst.resource);
816 d3d12_transition_subresources_state(ctx, d3d12_resource(tmp),
817 0, 1, 0, 1, 0, 1,
818 D3D12_RESOURCE_STATE_COPY_SOURCE,
819 D3D12_TRANSITION_FLAG_NONE);
820 d3d12_transition_subresources_state(ctx, dst,
821 0, 1, 0, 1, 1, 1,
822 D3D12_RESOURCE_STATE_COPY_DEST,
823 D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
824 d3d12_apply_resource_states(ctx, false);
825
826 struct d3d12_batch *batch = d3d12_current_batch(ctx);
827 d3d12_batch_reference_resource(batch, d3d12_resource(tmp), false);
828 d3d12_batch_reference_resource(batch, dst, true);
829
830 D3D12_BOX src_box;
831 src_box.left = src_box.top = src_box.front = 0;
832 src_box.right = tmp->width0;
833 src_box.bottom = tmp->height0;
834 src_box.back = tmp->depth0;
835
836 D3D12_TEXTURE_COPY_LOCATION src_loc;
837 src_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
838 src_loc.SubresourceIndex = 0;
839 src_loc.pResource = d3d12_resource_resource(d3d12_resource(tmp));
840
841 D3D12_TEXTURE_COPY_LOCATION dst_loc;
842 dst_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
843 dst_loc.SubresourceIndex = 1;
844 dst_loc.pResource = d3d12_resource_resource(dst);
845
846 ctx->cmdlist->CopyTextureRegion(&dst_loc, info->dst.box.x,
847 info->dst.box.y, info->dst.box.z,
848 &src_loc, &src_box);
849
850 pipe_resource_reference(&tmp, NULL);
851 }
852
853 static bool
replicate_stencil_supported(struct d3d12_context * ctx,const struct pipe_blit_info * info)854 replicate_stencil_supported(struct d3d12_context *ctx,
855 const struct pipe_blit_info *info)
856 {
857 if (!util_format_is_depth_or_stencil(info->src.format) ||
858 !(info->mask & PIPE_MASK_S))
859 return false;
860
861 if (info->mask & PIPE_MASK_Z) {
862 struct pipe_blit_info new_info = *info;
863 new_info.mask = PIPE_MASK_Z;
864 if (!util_blitter_is_blit_supported(ctx->blitter, &new_info))
865 return false;
866 }
867
868 return true;
869 }
870
871 static void
blit_replicate_stencil(struct d3d12_context * ctx,const struct pipe_blit_info * info)872 blit_replicate_stencil(struct d3d12_context *ctx,
873 const struct pipe_blit_info *info)
874 {
875 assert(info->mask & PIPE_MASK_S);
876
877 if (D3D12_DEBUG_BLIT & d3d12_debug)
878 debug_printf("D3D12 BLIT: blit_replicate_stencil\n");
879
880 if (info->mask & PIPE_MASK_Z) {
881 /* resolve depth into dst */
882 struct pipe_blit_info new_info = *info;
883 new_info.mask = PIPE_MASK_Z;
884 util_blit(ctx, &new_info);
885 }
886
887 util_blit_save_state(ctx);
888 util_blitter_stencil_fallback(ctx->blitter, info->dst.resource,
889 info->dst.level,
890 &info->dst.box,
891 info->src.resource,
892 info->src.level,
893 &info->src.box,
894 info->scissor_enable ? &info->scissor : NULL);
895 }
896
897 void
d3d12_blit(struct pipe_context * pctx,const struct pipe_blit_info * info)898 d3d12_blit(struct pipe_context *pctx,
899 const struct pipe_blit_info *info)
900 {
901 struct d3d12_context *ctx = d3d12_context(pctx);
902
903 if (!info->render_condition_enable && ctx->current_predication) {
904 if (D3D12_DEBUG_BLIT & d3d12_debug)
905 debug_printf("D3D12 BLIT: Disable predication\n");
906 ctx->cmdlist->SetPredication(nullptr, 0, D3D12_PREDICATION_OP_EQUAL_ZERO);
907 }
908
909 if (D3D12_DEBUG_BLIT & d3d12_debug) {
910 debug_printf("D3D12 BLIT: from %s@%d msaa:%d %dx%dx%d + %dx%dx%d\n",
911 util_format_name(info->src.format), info->src.level,
912 info->src.resource->nr_samples,
913 info->src.box.x, info->src.box.y, info->src.box.z,
914 info->src.box.width, info->src.box.height, info->src.box.depth);
915 debug_printf(" to %s@%d msaa:%d %dx%dx%d + %dx%dx%d ",
916 util_format_name(info->dst.format), info->dst.level,
917 info->dst.resource->nr_samples,
918 info->dst.box.x, info->dst.box.y, info->dst.box.z,
919 info->dst.box.width, info->dst.box.height, info->dst.box.depth);
920 debug_printf("| flags %s%s%s\n",
921 info->render_condition_enable ? "cond " : "",
922 info->scissor_enable ? "scissor " : "",
923 info->alpha_blend ? "blend" : "");
924 }
925
926 if (is_same_resource(info))
927 blit_same_resource(ctx, info);
928 else if (is_resolve(info)) {
929 if (resolve_supported(info))
930 blit_resolve(ctx, info);
931 else if (util_blitter_is_blit_supported(ctx->blitter, info))
932 util_blit(ctx, info);
933 else if (resolve_stencil_supported(ctx, info))
934 blit_resolve_stencil(ctx, info);
935 else
936 debug_printf("D3D12: resolve unsupported %s -> %s\n",
937 util_format_short_name(info->src.resource->format),
938 util_format_short_name(info->dst.resource->format));
939 } else if (direct_copy_supported(d3d12_screen(pctx->screen), info,
940 ctx->current_predication != nullptr))
941 d3d12_direct_copy(ctx, d3d12_resource(info->dst.resource),
942 info->dst.level, &info->dst.box,
943 d3d12_resource(info->src.resource),
944 info->src.level, &info->src.box, info->mask);
945 else if (util_blitter_is_blit_supported(ctx->blitter, info))
946 util_blit(ctx, info);
947 else if (replicate_stencil_supported(ctx, info))
948 blit_replicate_stencil(ctx, info);
949 else
950 debug_printf("D3D12: blit unsupported %s -> %s\n",
951 util_format_short_name(info->src.resource->format),
952 util_format_short_name(info->dst.resource->format));
953
954 if (!info->render_condition_enable && ctx->current_predication) {
955 d3d12_enable_predication(ctx);
956 if (D3D12_DEBUG_BLIT & d3d12_debug)
957 debug_printf("D3D12 BLIT: Re-enable predication\n");
958 }
959
960 }
961
962 static void
d3d12_resource_copy_region(struct pipe_context * pctx,struct pipe_resource * pdst,unsigned dst_level,unsigned dstx,unsigned dsty,unsigned dstz,struct pipe_resource * psrc,unsigned src_level,const struct pipe_box * psrc_box)963 d3d12_resource_copy_region(struct pipe_context *pctx,
964 struct pipe_resource *pdst,
965 unsigned dst_level,
966 unsigned dstx, unsigned dsty, unsigned dstz,
967 struct pipe_resource *psrc,
968 unsigned src_level,
969 const struct pipe_box *psrc_box)
970 {
971 struct d3d12_context *ctx = d3d12_context(pctx);
972 struct d3d12_resource *dst = d3d12_resource(pdst);
973 struct d3d12_resource *src = d3d12_resource(psrc);
974 struct pipe_resource *staging_res = NULL;
975 const struct pipe_box *src_box = psrc_box;
976 struct pipe_box staging_box, dst_box;
977
978 if (D3D12_DEBUG_BLIT & d3d12_debug) {
979 debug_printf("D3D12 COPY: from %s@%d msaa:%d mips:%d %dx%dx%d + %dx%dx%d\n",
980 util_format_name(psrc->format), src_level, psrc->nr_samples,
981 psrc->last_level,
982 psrc_box->x, psrc_box->y, psrc_box->z,
983 psrc_box->width, psrc_box->height, psrc_box->depth);
984 debug_printf(" to %s@%d msaa:%d mips:%d %dx%dx%d\n",
985 util_format_name(pdst->format), dst_level, psrc->nr_samples,
986 psrc->last_level, dstx, dsty, dstz);
987 }
988
989 /* Use an intermediate resource if copying from/to the same subresource */
990 if (d3d12_resource_resource(dst) == d3d12_resource_resource(src) && dst_level == src_level) {
991 staging_res = create_staging_resource(ctx, src, src_level, psrc_box, &staging_box, PIPE_MASK_RGBAZS);
992 src = d3d12_resource(staging_res);
993 src_level = 0;
994 src_box = &staging_box;
995 }
996
997 dst_box.x = dstx;
998 dst_box.y = dsty;
999 dst_box.z = dstz;
1000 dst_box.width = psrc_box->width;
1001 dst_box.height = psrc_box->height;
1002
1003 d3d12_direct_copy(ctx, dst, dst_level, &dst_box,
1004 src, src_level, src_box, PIPE_MASK_RGBAZS);
1005
1006 if (staging_res)
1007 pipe_resource_reference(&staging_res, NULL);
1008 }
1009
1010 void
d3d12_context_blit_init(struct pipe_context * ctx)1011 d3d12_context_blit_init(struct pipe_context *ctx)
1012 {
1013 ctx->resource_copy_region = d3d12_resource_copy_region;
1014 ctx->blit = d3d12_blit;
1015 }
1016