• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 (util_format_is_depth_or_stencil(info->src.format) && !(info->mask & PIPE_MASK_ZS)) {
191       return false;
192    }
193 
194    if (!util_format_is_depth_or_stencil(info->src.format)) {
195       if (util_format_get_mask(info->dst.format) != info->mask ||
196           util_format_get_mask(info->src.format) != info->mask)
197          return false;
198    }
199 
200    if (abs(info->src.box.height) != info->dst.box.height) {
201       return false;
202    }
203 
204    if (info->src.box.height != info->dst.box.height &&
205        (!util_format_is_depth_or_stencil(info->src.format) ||
206         screen->opts2.ProgrammableSamplePositionsTier ==
207         D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED)) {
208       return false;
209    }
210 
211    if (!box_fits(&info->dst.box, info->dst.resource, info->dst.level)) {
212       return false;
213    }
214    if (!box_fits(&info->src.box, info->src.resource, info->src.level)) {
215       return false;
216    }
217 
218    if (info->src.box.width != info->dst.box.width) {
219       return false;
220    }
221 
222    if (info->src.box.depth != info->dst.box.depth) {
223       return false;
224    }
225 
226    if ((screen->opts2.ProgrammableSamplePositionsTier ==
227         D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED &&
228         (info->src.resource->bind & PIPE_BIND_DEPTH_STENCIL ||
229          info->dst.resource->bind & PIPE_BIND_DEPTH_STENCIL)) ||
230         info->src.resource->nr_samples != info->dst.resource->nr_samples) {
231 
232       if (info->dst.box.x != 0 ||
233           info->dst.box.y != 0 ||
234           info->dst.box.z != 0)
235          return false;
236 
237       if (info->src.box.x != 0 ||
238           info->src.box.y != 0 ||
239           info->src.box.z != 0 ||
240           info->src.box.width != (int)u_minify(info->src.resource->width0,
241                                                info->src.level) ||
242           info->src.box.height != (int)u_minify(info->src.resource->height0,
243                                                 info->src.level) ||
244           info->src.box.depth != (int)u_minify(info->src.resource->depth0,
245                                                info->src.level))
246          return false;
247    }
248 
249    return true;
250 }
251 
252 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)253 get_subresource_id(enum pipe_texture_target target, unsigned subres, unsigned stride,
254                    unsigned z, unsigned *updated_z, unsigned array_size, unsigned plane_slice)
255 {
256    if (d3d12_subresource_id_uses_layer(target)) {
257       subres += stride * z;
258       if (updated_z)
259          *updated_z = 0;
260    }
261    return subres + plane_slice * array_size * stride;
262 }
263 
264 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)265 copy_subregion_no_barriers(struct d3d12_context *ctx,
266                            struct d3d12_resource *dst,
267                            unsigned dst_level,
268                            unsigned dstx, unsigned dsty, unsigned dstz,
269                            struct d3d12_resource *src,
270                            unsigned src_level,
271                            const struct pipe_box *psrc_box,
272                            unsigned mask)
273 {
274    UNUSED struct d3d12_screen *screen = d3d12_screen(ctx->base.screen);
275    D3D12_TEXTURE_COPY_LOCATION src_loc, dst_loc;
276    unsigned src_z = psrc_box->z;
277 
278    int src_subres_stride = src->base.b.last_level + 1;
279    int dst_subres_stride = dst->base.b.last_level + 1;
280 
281    int src_array_size = src->base.b.array_size;
282    int dst_array_size = dst->base.b.array_size;
283 
284    if (dst->base.b.target == PIPE_TEXTURE_CUBE)
285       dst_array_size *= 6;
286 
287    if (src->base.b.target == PIPE_TEXTURE_CUBE)
288       src_array_size *= 6;
289 
290    int stencil_src_res_offset = 1;
291    int stencil_dst_res_offset = 1;
292 
293    int src_nres = 1;
294    int dst_nres = 1;
295 
296    if (dst->base.b.format == PIPE_FORMAT_Z24_UNORM_S8_UINT ||
297        dst->base.b.format == PIPE_FORMAT_S8_UINT_Z24_UNORM ||
298        dst->base.b.format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT) {
299       stencil_dst_res_offset = dst_subres_stride * dst_array_size;
300       src_nres = 2;
301    }
302 
303    if (src->base.b.format == PIPE_FORMAT_Z24_UNORM_S8_UINT ||
304        src->base.b.format == PIPE_FORMAT_S8_UINT_Z24_UNORM ||
305        dst->base.b.format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT) {
306       stencil_src_res_offset = src_subres_stride * src_array_size;
307       dst_nres = 2;
308    }
309 
310    static_assert(PIPE_MASK_S == 0x20 && PIPE_MASK_Z == 0x10, "unexpected ZS format mask");
311    int nsubres = MIN2(src_nres, dst_nres);
312    unsigned subresource_copy_mask = nsubres > 1 ? mask >> 4 : 1;
313 
314    for (int subres = 0; subres < nsubres; ++subres) {
315 
316       if (!(subresource_copy_mask & (1 << subres)))
317          continue;
318 
319       src_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
320       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) +
321                                  subres * stencil_src_res_offset;
322       src_loc.pResource = d3d12_resource_resource(src);
323 
324       dst_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
325       dst_loc.SubresourceIndex = get_subresource_id(dst->base.b.target, dst_level, dst_subres_stride, dstz, &dstz, dst_array_size, dst->plane_slice) +
326                                  subres * stencil_dst_res_offset;
327       dst_loc.pResource = d3d12_resource_resource(dst);
328 
329       if (psrc_box->x == 0 && psrc_box->y == 0 && psrc_box->z == 0 &&
330           psrc_box->width == (int)u_minify(src->base.b.width0, src_level) &&
331           psrc_box->height == (int)u_minify(src->base.b.height0, src_level) &&
332           psrc_box->depth == (int)u_minify(src->base.b.depth0, src_level)) {
333 
334          assert((dstx == 0 && dsty == 0 && dstz == 0) ||
335                 screen->opts2.ProgrammableSamplePositionsTier !=
336                 D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED ||
337                 (!util_format_is_depth_or_stencil(dst->base.b.format) &&
338                  !util_format_is_depth_or_stencil(src->base.b.format) &&
339                   dst->base.b.nr_samples == src->base.b.nr_samples));
340 
341          ctx->cmdlist->CopyTextureRegion(&dst_loc, dstx, dsty, dstz,
342                                          &src_loc, NULL);
343 
344       } else {
345          D3D12_BOX src_box;
346          src_box.left = psrc_box->x;
347          src_box.right = MIN2(psrc_box->x + psrc_box->width, (int)u_minify(src->base.b.width0, src_level));
348          src_box.top = psrc_box->y;
349          src_box.bottom = MIN2(psrc_box->y + psrc_box->height, (int)u_minify(src->base.b.height0, src_level));
350          src_box.front = src_z;
351          src_box.back = src_z + psrc_box->depth;
352 
353          assert((screen->opts2.ProgrammableSamplePositionsTier !=
354                  D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED ||
355                  (!util_format_is_depth_or_stencil(dst->base.b.format) &&
356                   !util_format_is_depth_or_stencil(src->base.b.format))) &&
357                 dst->base.b.nr_samples == src->base.b.nr_samples);
358 
359          ctx->cmdlist->CopyTextureRegion(&dst_loc, dstx, dsty, dstz,
360                                          &src_loc, &src_box);
361       }
362    }
363 }
364 
365 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)366 copy_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.b.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.b.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 
402 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)403 d3d12_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.b.target, src_level, src->base.b.last_level + 1,
415                                             psrc_box->z, nullptr, src->base.b.array_size, src->plane_slice);
416    unsigned dst_subres = get_subresource_id(dst->base.b.target, dst_level, dst->base.b.last_level + 1,
417                                             pdst_box->z, nullptr, dst->base.b.array_size, dst->plane_slice);
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.b.format),
425                                        d3d12_get_format_num_planes(src->base.b.format),
426                                        D3D12_RESOURCE_STATE_COPY_SOURCE,
427                                        D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
428 
429    d3d12_transition_subresources_state(ctx, dst, dst_subres, 1, 0, 1,
430                                        d3d12_get_format_start_plane(dst->base.b.format),
431                                        d3d12_get_format_num_planes(dst->base.b.format),
432                                        D3D12_RESOURCE_STATE_COPY_DEST,
433                                        D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
434 
435    d3d12_apply_resource_states(ctx, false);
436 
437    d3d12_batch_reference_resource(batch, src, false);
438    d3d12_batch_reference_resource(batch, dst, true);
439 
440    if (src->base.b.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 
455 static bool
is_same_resource(const struct pipe_blit_info * info)456 is_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 
463 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)464 create_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.b.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 = src->base.b.nr_samples;
488    templ.nr_storage_samples = src->base.b.nr_storage_samples;
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.b.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 
522 static void
blit_same_resource(struct d3d12_context * ctx,const struct pipe_blit_info * info)523 blit_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 
537 static void
util_blit_save_state(struct d3d12_context * ctx)538 util_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    util_blitter_save_tessctrl_shader(ctx->blitter, ctx->gfx_stages[PIPE_SHADER_TESS_CTRL]);
549    util_blitter_save_tesseval_shader(ctx->blitter, ctx->gfx_stages[PIPE_SHADER_TESS_EVAL]);
550 
551    util_blitter_save_framebuffer(ctx->blitter, &ctx->fb);
552    util_blitter_save_viewport(ctx->blitter, ctx->viewport_states);
553    util_blitter_save_scissor(ctx->blitter, ctx->scissor_states);
554    util_blitter_save_fragment_sampler_states(ctx->blitter,
555                                              ctx->num_samplers[PIPE_SHADER_FRAGMENT],
556                                              (void **)ctx->samplers[PIPE_SHADER_FRAGMENT]);
557    util_blitter_save_fragment_sampler_views(ctx->blitter,
558                                             ctx->num_sampler_views[PIPE_SHADER_FRAGMENT],
559                                             ctx->sampler_views[PIPE_SHADER_FRAGMENT]);
560    util_blitter_save_fragment_constant_buffer_slot(ctx->blitter, ctx->cbufs[PIPE_SHADER_FRAGMENT]);
561    util_blitter_save_vertex_buffer_slot(ctx->blitter, ctx->vbs);
562    util_blitter_save_sample_mask(ctx->blitter, ctx->gfx_pipeline_state.sample_mask, 0);
563    util_blitter_save_so_targets(ctx->blitter, ctx->gfx_pipeline_state.num_so_targets, ctx->so_targets);
564 }
565 
566 static void
util_blit(struct d3d12_context * ctx,const struct pipe_blit_info * info)567 util_blit(struct d3d12_context *ctx,
568           const struct pipe_blit_info *info)
569 {
570    util_blit_save_state(ctx);
571 
572    util_blitter_blit(ctx->blitter, info);
573 }
574 
575 static bool
resolve_stencil_supported(struct d3d12_context * ctx,const struct pipe_blit_info * info)576 resolve_stencil_supported(struct d3d12_context *ctx,
577                           const struct pipe_blit_info *info)
578 {
579    assert(is_resolve(info));
580 
581    if (!util_format_is_depth_or_stencil(info->src.format) ||
582        !(info->mask & PIPE_MASK_S))
583       return false;
584 
585    if (info->mask & PIPE_MASK_Z) {
586       struct pipe_blit_info new_info = *info;
587       new_info.mask = PIPE_MASK_Z;
588       if (!resolve_supported(&new_info) &&
589           !util_blitter_is_blit_supported(ctx->blitter, &new_info))
590          return false;
591    }
592 
593    struct pipe_blit_info new_info = *info;
594    new_info.dst.format = PIPE_FORMAT_R8_UINT;
595    return util_blitter_is_blit_supported(ctx->blitter, &new_info);
596 }
597 
598 static struct pipe_resource *
create_tmp_resource(struct pipe_screen * screen,const struct pipe_blit_info * info)599 create_tmp_resource(struct pipe_screen *screen,
600                     const struct pipe_blit_info *info)
601 {
602    struct pipe_resource tpl = {};
603    tpl.width0 = info->dst.box.width;
604    tpl.height0 = info->dst.box.height;
605    tpl.depth0 = info->dst.box.depth;
606    tpl.array_size = 1;
607    tpl.format = PIPE_FORMAT_R8_UINT;
608    tpl.target = info->dst.resource->target;
609    tpl.nr_samples = info->dst.resource->nr_samples;
610    tpl.nr_storage_samples = info->dst.resource->nr_storage_samples;
611    tpl.usage = PIPE_USAGE_STREAM;
612    tpl.bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
613    return screen->resource_create(screen, &tpl);
614 }
615 
616 static void *
get_stencil_resolve_vs(struct d3d12_context * ctx)617 get_stencil_resolve_vs(struct d3d12_context *ctx)
618 {
619    if (ctx->stencil_resolve_vs)
620       return ctx->stencil_resolve_vs;
621 
622    nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_VERTEX,
623                                                   &d3d12_screen(ctx->base.screen)->nir_options,
624                                                   "linear_blit_vs");
625 
626    const struct glsl_type *vec4 = glsl_vec4_type();
627    nir_variable *pos_in = nir_variable_create(b.shader, nir_var_shader_in,
628                                               vec4, "pos");
629 
630    nir_variable *pos_out = nir_variable_create(b.shader, nir_var_shader_out,
631                                                vec4, "gl_Position");
632    pos_out->data.location = VARYING_SLOT_POS;
633 
634    nir_store_var(&b, pos_out, nir_load_var(&b, pos_in), 0xf);
635 
636    struct pipe_shader_state state = {};
637    state.type = PIPE_SHADER_IR_NIR;
638    state.ir.nir = b.shader;
639    ctx->stencil_resolve_vs = ctx->base.create_vs_state(&ctx->base, &state);
640 
641    return ctx->stencil_resolve_vs;
642 }
643 
644 static void *
get_stencil_resolve_fs(struct d3d12_context * ctx,bool no_flip)645 get_stencil_resolve_fs(struct d3d12_context *ctx, bool no_flip)
646 {
647    if (!no_flip && ctx->stencil_resolve_fs)
648       return ctx->stencil_resolve_fs;
649 
650    if (no_flip && ctx->stencil_resolve_fs_no_flip)
651       return ctx->stencil_resolve_fs_no_flip;
652 
653    nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_FRAGMENT,
654                                                   &d3d12_screen(ctx->base.screen)->nir_options,
655                                                   no_flip ? "stencil_resolve_fs_no_flip" : "stencil_resolve_fs");
656 
657    nir_variable *stencil_out = nir_variable_create(b.shader,
658                                                    nir_var_shader_out,
659                                                    glsl_uint_type(),
660                                                    "stencil_out");
661    stencil_out->data.location = FRAG_RESULT_COLOR;
662 
663    const struct glsl_type *sampler_type =
664       glsl_sampler_type(GLSL_SAMPLER_DIM_MS, false, false, GLSL_TYPE_UINT);
665    nir_variable *sampler = nir_variable_create(b.shader, nir_var_uniform,
666                                                sampler_type, "stencil_tex");
667    sampler->data.binding = 0;
668    sampler->data.explicit_binding = true;
669 
670    nir_ssa_def *tex_deref = &nir_build_deref_var(&b, sampler)->dest.ssa;
671 
672    nir_variable *pos_in = nir_variable_create(b.shader, nir_var_shader_in,
673                                               glsl_vec4_type(), "pos");
674    pos_in->data.location = VARYING_SLOT_POS; // VARYING_SLOT_VAR0?
675    nir_ssa_def *pos = nir_load_var(&b, pos_in);
676 
677    nir_ssa_def *pos_src;
678 
679    if (no_flip)
680       pos_src = pos;
681    else {
682       nir_tex_instr *txs = nir_tex_instr_create(b.shader, 1);
683       txs->op = nir_texop_txs;
684       txs->sampler_dim = GLSL_SAMPLER_DIM_MS;
685       txs->src[0].src_type = nir_tex_src_texture_deref;
686       txs->src[0].src = nir_src_for_ssa(tex_deref);
687       txs->is_array = false;
688       txs->dest_type = nir_type_int;
689 
690       nir_ssa_dest_init(&txs->instr, &txs->dest, 2, 32, "tex");
691       nir_builder_instr_insert(&b, &txs->instr);
692 
693       pos_src = nir_vec4(&b,
694                          nir_channel(&b, pos, 0),
695                          /*Height - pos_dest.y - 1*/
696                          nir_fsub(&b,
697                                   nir_fsub(&b,
698                                            nir_channel(&b, nir_i2f32(&b, &txs->dest.ssa), 1),
699                                            nir_channel(&b, pos, 1)),
700                                   nir_imm_float(&b, 1.0)),
701                          nir_channel(&b, pos, 2),
702                          nir_channel(&b, pos, 3));
703    }
704 
705    nir_tex_instr *tex = nir_tex_instr_create(b.shader, 3);
706    tex->sampler_dim = GLSL_SAMPLER_DIM_MS;
707    tex->op = nir_texop_txf_ms;
708    tex->src[0].src_type = nir_tex_src_coord;
709    tex->src[0].src = nir_src_for_ssa(nir_channels(&b, nir_f2i32(&b, pos_src), 0x3));
710    tex->src[1].src_type = nir_tex_src_ms_index;
711    tex->src[1].src = nir_src_for_ssa(nir_imm_int(&b, 0)); /* just use first sample */
712    tex->src[2].src_type = nir_tex_src_texture_deref;
713    tex->src[2].src = nir_src_for_ssa(tex_deref);
714    tex->dest_type = nir_type_uint32;
715    tex->is_array = false;
716    tex->coord_components = 2;
717 
718    nir_ssa_dest_init(&tex->instr, &tex->dest, 4, 32, "tex");
719    nir_builder_instr_insert(&b, &tex->instr);
720 
721    nir_store_var(&b, stencil_out, nir_channel(&b, &tex->dest.ssa, 1), 0x1);
722 
723    struct pipe_shader_state state = {};
724    state.type = PIPE_SHADER_IR_NIR;
725    state.ir.nir = b.shader;
726    void *result;
727    if (no_flip) {
728       result = ctx->base.create_fs_state(&ctx->base, &state);
729       ctx->stencil_resolve_fs_no_flip = result;
730    } else {
731       result = ctx->base.create_fs_state(&ctx->base, &state);
732       ctx->stencil_resolve_fs = result;
733    }
734 
735    return result;
736 }
737 
738 static void *
get_sampler_state(struct d3d12_context * ctx)739 get_sampler_state(struct d3d12_context *ctx)
740 {
741    if (ctx->sampler_state)
742       return ctx->sampler_state;
743 
744    struct pipe_sampler_state state;
745    memset(&state, 0, sizeof(state));
746    state.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
747    state.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
748    state.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
749    state.normalized_coords = 1;
750 
751    return ctx->sampler_state = ctx->base.create_sampler_state(&ctx->base, &state);
752 }
753 
754 static struct pipe_resource *
resolve_stencil_to_temp(struct d3d12_context * ctx,const struct pipe_blit_info * info)755 resolve_stencil_to_temp(struct d3d12_context *ctx,
756                         const struct pipe_blit_info *info)
757 {
758    struct pipe_context *pctx = &ctx->base;
759    struct pipe_resource *tmp = create_tmp_resource(pctx->screen, info);
760    if (!tmp) {
761       debug_printf("D3D12: failed to create stencil-resolve temp-resource\n");
762       return NULL;
763    }
764    assert(tmp->nr_samples < 2);
765 
766    /* resolve stencil into tmp */
767    struct pipe_surface dst_tmpl;
768    util_blitter_default_dst_texture(&dst_tmpl, tmp, 0, 0);
769    dst_tmpl.format = tmp->format;
770    struct pipe_surface *dst_surf = pctx->create_surface(pctx, tmp, &dst_tmpl);
771    if (!dst_surf) {
772       debug_printf("D3D12: failed to create stencil-resolve dst-surface\n");
773       return NULL;
774    }
775 
776    struct pipe_sampler_view src_templ, *src_view;
777    util_blitter_default_src_texture(ctx->blitter, &src_templ,
778                                     info->src.resource, info->src.level);
779    src_templ.format = util_format_stencil_only(info->src.format);
780    src_view = pctx->create_sampler_view(pctx, info->src.resource, &src_templ);
781 
782    void *sampler_state = get_sampler_state(ctx);
783 
784    util_blit_save_state(ctx);
785    pctx->set_sampler_views(pctx, PIPE_SHADER_FRAGMENT, 0, 1, 0, false, &src_view);
786    pctx->bind_sampler_states(pctx, PIPE_SHADER_FRAGMENT, 0, 1, &sampler_state);
787    util_blitter_custom_shader(ctx->blitter, dst_surf,
788                               get_stencil_resolve_vs(ctx),
789                               get_stencil_resolve_fs(ctx, info->src.box.height == info->dst.box.height));
790    util_blitter_restore_textures(ctx->blitter);
791    pipe_surface_reference(&dst_surf, NULL);
792    pipe_sampler_view_reference(&src_view, NULL);
793    return tmp;
794 }
795 
796 static void
blit_resolve_stencil(struct d3d12_context * ctx,const struct pipe_blit_info * info)797 blit_resolve_stencil(struct d3d12_context *ctx,
798                      const struct pipe_blit_info *info)
799 {
800    assert(info->mask & PIPE_MASK_S);
801 
802    if (D3D12_DEBUG_BLIT & d3d12_debug)
803       debug_printf("D3D12 BLIT: blit_resolve_stencil\n");
804 
805    if (info->mask & PIPE_MASK_Z) {
806       /* resolve depth into dst */
807       struct pipe_blit_info new_info = *info;
808       new_info.mask = PIPE_MASK_Z;
809 
810       if (resolve_supported(&new_info))
811          blit_resolve(ctx, &new_info);
812       else
813          util_blit(ctx, &new_info);
814    }
815 
816    struct pipe_resource *tmp = resolve_stencil_to_temp(ctx, info);
817 
818 
819    /* copy resolved stencil into dst */
820    struct d3d12_resource *dst = d3d12_resource(info->dst.resource);
821    d3d12_transition_subresources_state(ctx, d3d12_resource(tmp),
822                                        0, 1, 0, 1, 0, 1,
823                                        D3D12_RESOURCE_STATE_COPY_SOURCE,
824                                        D3D12_TRANSITION_FLAG_NONE);
825    d3d12_transition_subresources_state(ctx, dst,
826                                        0, 1, 0, 1, 1, 1,
827                                        D3D12_RESOURCE_STATE_COPY_DEST,
828                                        D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
829    d3d12_apply_resource_states(ctx, false);
830 
831    struct d3d12_batch *batch = d3d12_current_batch(ctx);
832    d3d12_batch_reference_resource(batch, d3d12_resource(tmp), false);
833    d3d12_batch_reference_resource(batch, dst, true);
834 
835    D3D12_BOX src_box;
836    src_box.left = src_box.top = src_box.front = 0;
837    src_box.right = tmp->width0;
838    src_box.bottom = tmp->height0;
839    src_box.back = tmp->depth0;
840 
841    D3D12_TEXTURE_COPY_LOCATION src_loc;
842    src_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
843    src_loc.SubresourceIndex = 0;
844    src_loc.pResource = d3d12_resource_resource(d3d12_resource(tmp));
845 
846    D3D12_TEXTURE_COPY_LOCATION dst_loc;
847    dst_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
848    dst_loc.SubresourceIndex = 1;
849    dst_loc.pResource = d3d12_resource_resource(dst);
850 
851    ctx->cmdlist->CopyTextureRegion(&dst_loc, info->dst.box.x,
852                                    info->dst.box.y, info->dst.box.z,
853                                    &src_loc, &src_box);
854 
855    pipe_resource_reference(&tmp, NULL);
856 }
857 
858 static bool
replicate_stencil_supported(struct d3d12_context * ctx,const struct pipe_blit_info * info)859 replicate_stencil_supported(struct d3d12_context *ctx,
860                             const struct pipe_blit_info *info)
861 {
862    if (!util_format_is_depth_or_stencil(info->src.format) ||
863        !(info->mask & PIPE_MASK_S))
864       return false;
865 
866    if (info->mask & PIPE_MASK_Z) {
867       struct pipe_blit_info new_info = *info;
868       new_info.mask = PIPE_MASK_Z;
869       if (!util_blitter_is_blit_supported(ctx->blitter, &new_info))
870          return false;
871    }
872 
873    return true;
874 }
875 
876 static void
blit_replicate_stencil(struct d3d12_context * ctx,const struct pipe_blit_info * info)877 blit_replicate_stencil(struct d3d12_context *ctx,
878                        const struct pipe_blit_info *info)
879 {
880    assert(info->mask & PIPE_MASK_S);
881 
882    if (D3D12_DEBUG_BLIT & d3d12_debug)
883       debug_printf("D3D12 BLIT: blit_replicate_stencil\n");
884 
885    if (info->mask & PIPE_MASK_Z) {
886       /* resolve depth into dst */
887       struct pipe_blit_info new_info = *info;
888       new_info.mask = PIPE_MASK_Z;
889       util_blit(ctx, &new_info);
890    }
891 
892    util_blit_save_state(ctx);
893    util_blitter_stencil_fallback(ctx->blitter, info->dst.resource,
894                                  info->dst.level,
895                                  &info->dst.box,
896                                  info->src.resource,
897                                  info->src.level,
898                                  &info->src.box,
899                                  info->scissor_enable ? &info->scissor : NULL);
900 }
901 
902 void
d3d12_blit(struct pipe_context * pctx,const struct pipe_blit_info * info)903 d3d12_blit(struct pipe_context *pctx,
904            const struct pipe_blit_info *info)
905 {
906    struct d3d12_context *ctx = d3d12_context(pctx);
907 
908    if (!info->render_condition_enable && ctx->current_predication) {
909       if (D3D12_DEBUG_BLIT & d3d12_debug)
910          debug_printf("D3D12 BLIT: Disable predication\n");
911       ctx->cmdlist->SetPredication(nullptr, 0, D3D12_PREDICATION_OP_EQUAL_ZERO);
912    }
913 
914    if (D3D12_DEBUG_BLIT & d3d12_debug) {
915       debug_printf("D3D12 BLIT: from %s@%d msaa:%d %dx%dx%d + %dx%dx%d\n",
916                    util_format_name(info->src.format), info->src.level,
917                    info->src.resource->nr_samples,
918                    info->src.box.x, info->src.box.y, info->src.box.z,
919                    info->src.box.width, info->src.box.height, info->src.box.depth);
920       debug_printf("            to   %s@%d msaa:%d %dx%dx%d + %dx%dx%d ",
921                    util_format_name(info->dst.format), info->dst.level,
922                    info->dst.resource->nr_samples,
923                    info->dst.box.x, info->dst.box.y, info->dst.box.z,
924                    info->dst.box.width, info->dst.box.height, info->dst.box.depth);
925       debug_printf("| flags %s%s%s\n",
926                    info->render_condition_enable ? "cond " : "",
927                    info->scissor_enable ? "scissor " : "",
928                    info->alpha_blend ? "blend" : "");
929    }
930 
931    if (is_same_resource(info))
932       blit_same_resource(ctx, info);
933    else if (is_resolve(info)) {
934       if (resolve_supported(info))
935          blit_resolve(ctx, info);
936       else if (util_blitter_is_blit_supported(ctx->blitter, info))
937          util_blit(ctx, info);
938       else if (resolve_stencil_supported(ctx, info))
939          blit_resolve_stencil(ctx, info);
940       else
941          debug_printf("D3D12: resolve unsupported %s -> %s\n",
942                     util_format_short_name(info->src.resource->format),
943                     util_format_short_name(info->dst.resource->format));
944    } else if (direct_copy_supported(d3d12_screen(pctx->screen), info,
945                                     ctx->current_predication != nullptr))
946       d3d12_direct_copy(ctx, d3d12_resource(info->dst.resource),
947                         info->dst.level, &info->dst.box,
948                         d3d12_resource(info->src.resource),
949                         info->src.level, &info->src.box, info->mask);
950    else if (util_blitter_is_blit_supported(ctx->blitter, info))
951       util_blit(ctx, info);
952    else if (replicate_stencil_supported(ctx, info))
953       blit_replicate_stencil(ctx, info);
954    else
955       debug_printf("D3D12: blit unsupported %s -> %s\n",
956                  util_format_short_name(info->src.resource->format),
957                  util_format_short_name(info->dst.resource->format));
958 
959    if (!info->render_condition_enable && ctx->current_predication) {
960       d3d12_enable_predication(ctx);
961       if (D3D12_DEBUG_BLIT & d3d12_debug)
962          debug_printf("D3D12 BLIT: Re-enable predication\n");
963    }
964 
965 }
966 
967 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)968 d3d12_resource_copy_region(struct pipe_context *pctx,
969                            struct pipe_resource *pdst,
970                            unsigned dst_level,
971                            unsigned dstx, unsigned dsty, unsigned dstz,
972                            struct pipe_resource *psrc,
973                            unsigned src_level,
974                            const struct pipe_box *psrc_box)
975 {
976    struct d3d12_context *ctx = d3d12_context(pctx);
977    struct d3d12_resource *dst = d3d12_resource(pdst);
978    struct d3d12_resource *src = d3d12_resource(psrc);
979    struct pipe_resource *staging_res = NULL;
980    const struct pipe_box *src_box = psrc_box;
981    struct pipe_box staging_box, dst_box;
982 
983    if (D3D12_DEBUG_BLIT & d3d12_debug) {
984       debug_printf("D3D12 COPY: from %s@%d msaa:%d mips:%d %dx%dx%d + %dx%dx%d\n",
985                    util_format_name(psrc->format), src_level, psrc->nr_samples,
986                    psrc->last_level,
987                    psrc_box->x, psrc_box->y, psrc_box->z,
988                    psrc_box->width, psrc_box->height, psrc_box->depth);
989       debug_printf("            to   %s@%d msaa:%d mips:%d %dx%dx%d\n",
990                    util_format_name(pdst->format), dst_level, psrc->nr_samples,
991                    psrc->last_level, dstx, dsty, dstz);
992    }
993 
994    /* Use an intermediate resource if copying from/to the same subresource */
995    if (d3d12_resource_resource(dst) == d3d12_resource_resource(src) && dst_level == src_level) {
996       staging_res = create_staging_resource(ctx, src, src_level, psrc_box, &staging_box, PIPE_MASK_RGBAZS);
997       src = d3d12_resource(staging_res);
998       src_level = 0;
999       src_box = &staging_box;
1000    }
1001 
1002    dst_box.x = dstx;
1003    dst_box.y = dsty;
1004    dst_box.z = dstz;
1005    dst_box.width = psrc_box->width;
1006    dst_box.height = psrc_box->height;
1007 
1008    d3d12_direct_copy(ctx, dst, dst_level, &dst_box,
1009                      src, src_level, src_box, PIPE_MASK_RGBAZS);
1010 
1011    if (staging_res)
1012       pipe_resource_reference(&staging_res, NULL);
1013 }
1014 
1015 void
d3d12_context_blit_init(struct pipe_context * ctx)1016 d3d12_context_blit_init(struct pipe_context *ctx)
1017 {
1018    ctx->resource_copy_region = d3d12_resource_copy_region;
1019    ctx->blit = d3d12_blit;
1020 }
1021