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