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 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)56 get_subresource_id(enum pipe_texture_target target, unsigned subres, unsigned stride,
57 unsigned z, unsigned *updated_z, unsigned array_size, unsigned plane_slice)
58 {
59 if (d3d12_subresource_id_uses_layer(target)) {
60 subres += stride * z;
61 if (updated_z)
62 *updated_z = 0;
63 }
64 return subres + plane_slice * array_size * stride;
65 }
66
67 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)68 copy_subregion_no_barriers(struct d3d12_context *ctx,
69 struct d3d12_resource *dst,
70 unsigned dst_level,
71 unsigned dstx, unsigned dsty, unsigned dstz,
72 struct d3d12_resource *src,
73 unsigned src_level,
74 const struct pipe_box *psrc_box,
75 unsigned mask)
76 {
77 UNUSED struct d3d12_screen *screen = d3d12_screen(ctx->base.screen);
78 D3D12_TEXTURE_COPY_LOCATION src_loc, dst_loc;
79 unsigned src_z = psrc_box->z;
80
81 int src_subres_stride = src->base.b.last_level + 1;
82 int dst_subres_stride = dst->base.b.last_level + 1;
83
84 int src_array_size = src->base.b.array_size;
85 int dst_array_size = dst->base.b.array_size;
86
87 int stencil_src_res_offset = 1;
88 int stencil_dst_res_offset = 1;
89
90 int src_nres = 1;
91 int dst_nres = 1;
92
93 if (dst->base.b.format == PIPE_FORMAT_Z24_UNORM_S8_UINT ||
94 dst->base.b.format == PIPE_FORMAT_S8_UINT_Z24_UNORM ||
95 dst->base.b.format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT) {
96 stencil_dst_res_offset = dst_subres_stride * dst_array_size;
97 src_nres = 2;
98 }
99
100 if (src->base.b.format == PIPE_FORMAT_Z24_UNORM_S8_UINT ||
101 src->base.b.format == PIPE_FORMAT_S8_UINT_Z24_UNORM ||
102 dst->base.b.format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT) {
103 stencil_src_res_offset = src_subres_stride * src_array_size;
104 dst_nres = 2;
105 }
106
107 static_assert(PIPE_MASK_S == 0x20 && PIPE_MASK_Z == 0x10, "unexpected ZS format mask");
108 int nsubres = MIN2(src_nres, dst_nres);
109 unsigned subresource_copy_mask = nsubres > 1 ? mask >> 4 : 1;
110
111 for (int subres = 0; subres < nsubres; ++subres) {
112
113 if (!(subresource_copy_mask & (1 << subres)))
114 continue;
115
116 src_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
117 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) +
118 subres * stencil_src_res_offset;
119 src_loc.pResource = d3d12_resource_resource(src);
120
121 dst_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
122 dst_loc.SubresourceIndex = get_subresource_id(dst->base.b.target, dst_level, dst_subres_stride, dstz, &dstz, dst_array_size, dst->plane_slice) +
123 subres * stencil_dst_res_offset;
124 dst_loc.pResource = d3d12_resource_resource(dst);
125
126 if (psrc_box->x == 0 && psrc_box->y == 0 && psrc_box->z == 0 &&
127 psrc_box->width == (int)u_minify(src->base.b.width0, src_level) &&
128 psrc_box->height == (int)u_minify(src->base.b.height0, src_level) &&
129 psrc_box->depth == (int)u_minify(src->base.b.depth0, src_level)) {
130
131 assert((dstx == 0 && dsty == 0 && dstz == 0) ||
132 screen->opts2.ProgrammableSamplePositionsTier !=
133 D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED ||
134 (!util_format_is_depth_or_stencil(dst->base.b.format) &&
135 !util_format_is_depth_or_stencil(src->base.b.format) &&
136 dst->base.b.nr_samples == src->base.b.nr_samples));
137
138 ctx->cmdlist->CopyTextureRegion(&dst_loc, dstx, dsty, dstz,
139 &src_loc, NULL);
140
141 } else {
142 D3D12_BOX src_box;
143 src_box.left = psrc_box->x;
144 src_box.right = MIN2(psrc_box->x + psrc_box->width, (int)u_minify(src->base.b.width0, src_level));
145 src_box.top = psrc_box->y;
146 src_box.bottom = MIN2(psrc_box->y + psrc_box->height, (int)u_minify(src->base.b.height0, src_level));
147 src_box.front = src_z;
148 src_box.back = src_z + psrc_box->depth;
149
150 assert((screen->opts2.ProgrammableSamplePositionsTier !=
151 D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED ||
152 (!util_format_is_depth_or_stencil(dst->base.b.format) &&
153 !util_format_is_depth_or_stencil(src->base.b.format))) &&
154 dst->base.b.nr_samples == src->base.b.nr_samples);
155
156 ctx->cmdlist->CopyTextureRegion(&dst_loc, dstx, dsty, dstz,
157 &src_loc, &src_box);
158 }
159 }
160 }
161
162 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)163 copy_resource_y_flipped_no_barriers(struct d3d12_context *ctx,
164 struct d3d12_resource *dst,
165 unsigned dst_level,
166 const struct pipe_box *pdst_box,
167 struct d3d12_resource *src,
168 unsigned src_level,
169 const struct pipe_box *psrc_box,
170 unsigned mask)
171 {
172 if (D3D12_DEBUG_BLIT & d3d12_debug) {
173 debug_printf("D3D12 BLIT as COPY: from %s@%d %dx%dx%d + %dx%dx%d\n",
174 util_format_name(src->base.b.format), src_level,
175 psrc_box->x, psrc_box->y, psrc_box->z,
176 psrc_box->width, psrc_box->height, psrc_box->depth);
177 debug_printf(" to %s@%d %dx%dx%d\n",
178 util_format_name(dst->base.b.format), dst_level,
179 pdst_box->x, pdst_box->y, pdst_box->z);
180 }
181
182 struct pipe_box src_box = *psrc_box;
183 int src_inc = psrc_box->height > 0 ? 1 : -1;
184 int dst_inc = pdst_box->height > 0 ? 1 : -1;
185 src_box.height = 1;
186 int rows_to_copy = abs(psrc_box->height);
187
188 if (psrc_box->height < 0)
189 --src_box.y;
190
191 for (int y = 0, dest_y = pdst_box->y; y < rows_to_copy;
192 ++y, src_box.y += src_inc, dest_y += dst_inc) {
193 copy_subregion_no_barriers(ctx, dst, dst_level,
194 pdst_box->x, dest_y, pdst_box->z,
195 src, src_level, &src_box, mask);
196 }
197 }
198
199 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)200 d3d12_direct_copy(struct d3d12_context *ctx,
201 struct d3d12_resource *dst,
202 unsigned dst_level,
203 const struct pipe_box *pdst_box,
204 struct d3d12_resource *src,
205 unsigned src_level,
206 const struct pipe_box *psrc_box,
207 unsigned mask)
208 {
209 struct d3d12_batch *batch = d3d12_current_batch(ctx);
210
211 unsigned src_subres = get_subresource_id(src->base.b.target, src_level, src->base.b.last_level + 1,
212 psrc_box->z, nullptr, src->base.b.array_size, src->plane_slice);
213 unsigned dst_subres = get_subresource_id(dst->base.b.target, dst_level, dst->base.b.last_level + 1,
214 pdst_box->z, nullptr, dst->base.b.array_size, dst->plane_slice);
215
216 if (D3D12_DEBUG_BLIT & d3d12_debug)
217 debug_printf("BLIT: Direct copy from subres %d to subres %d\n",
218 src_subres, dst_subres);
219
220 d3d12_transition_subresources_state(ctx, src, src_subres, 1, 0, 1,
221 d3d12_get_format_start_plane(src->base.b.format),
222 d3d12_get_format_num_planes(src->base.b.format),
223 D3D12_RESOURCE_STATE_COPY_SOURCE,
224 D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
225
226 d3d12_transition_subresources_state(ctx, dst, dst_subres, 1, 0, 1,
227 d3d12_get_format_start_plane(dst->base.b.format),
228 d3d12_get_format_num_planes(dst->base.b.format),
229 D3D12_RESOURCE_STATE_COPY_DEST,
230 D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
231
232 d3d12_apply_resource_states(ctx, false);
233
234 d3d12_batch_reference_resource(batch, src, false);
235 d3d12_batch_reference_resource(batch, dst, true);
236
237 if (src->base.b.target == PIPE_BUFFER) {
238 copy_buffer_region_no_barriers(ctx, dst, pdst_box->x,
239 src, psrc_box->x, psrc_box->width);
240 } else if (psrc_box->height == pdst_box->height) {
241 /* No flipping, we can forward this directly to resource_copy_region */
242 copy_subregion_no_barriers(ctx, dst, dst_level,
243 pdst_box->x, pdst_box->y, pdst_box->z,
244 src, src_level, psrc_box, mask);
245 } else {
246 assert(psrc_box->height == -pdst_box->height);
247 copy_resource_y_flipped_no_barriers(ctx, dst, dst_level, pdst_box,
248 src, src_level, psrc_box, mask);
249 }
250 }
251
252 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)253 create_staging_resource(struct d3d12_context *ctx,
254 struct d3d12_resource *src,
255 unsigned src_level,
256 const struct pipe_box *src_box,
257 struct pipe_box *dst_box,
258 unsigned mask)
259
260 {
261 struct pipe_resource templ = {};
262 struct pipe_resource *staging_res;
263 struct pipe_box copy_src;
264
265 u_box_3d(MIN2(src_box->x, src_box->x + src_box->width),
266 MIN2(src_box->y, src_box->y + src_box->height),
267 MIN2(src_box->z, src_box->z + src_box->depth),
268 abs(src_box->width), abs(src_box->height), abs(src_box->depth),
269 ©_src);
270
271 templ.format = src->base.b.format;
272 templ.width0 = copy_src.width;
273 templ.height0 = copy_src.height;
274 templ.depth0 = copy_src.depth;
275 templ.array_size = 1;
276 templ.nr_samples = src->base.b.nr_samples;
277 templ.nr_storage_samples = src->base.b.nr_storage_samples;
278 templ.usage = PIPE_USAGE_STAGING;
279 templ.bind = util_format_is_depth_or_stencil(templ.format) ? PIPE_BIND_DEPTH_STENCIL :
280 util_format_is_compressed(templ.format) ? 0 : PIPE_BIND_RENDER_TARGET;
281 templ.target = src->base.b.target;
282
283 staging_res = ctx->base.screen->resource_create(ctx->base.screen, &templ);
284
285 dst_box->x = 0;
286 dst_box->y = 0;
287 dst_box->z = 0;
288 dst_box->width = copy_src.width;
289 dst_box->height = copy_src.height;
290 dst_box->depth = copy_src.depth;
291
292 d3d12_direct_copy(ctx, d3d12_resource(staging_res), 0, dst_box,
293 src, src_level, ©_src, mask);
294
295 if (src_box->width < 0) {
296 dst_box->x = dst_box->width;
297 dst_box->width = src_box->width;
298 }
299
300 if (src_box->height < 0) {
301 dst_box->y = dst_box->height;
302 dst_box->height = src_box->height;
303 }
304
305 if (src_box->depth < 0) {
306 dst_box->z = dst_box->depth;
307 dst_box->depth = src_box->depth;
308 }
309 return staging_res;
310 }
311
312 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)313 d3d12_resource_copy_region(struct pipe_context *pctx,
314 struct pipe_resource *pdst,
315 unsigned dst_level,
316 unsigned dstx, unsigned dsty, unsigned dstz,
317 struct pipe_resource *psrc,
318 unsigned src_level,
319 const struct pipe_box *psrc_box)
320 {
321 struct d3d12_context *ctx = d3d12_context(pctx);
322 struct d3d12_resource *dst = d3d12_resource(pdst);
323 struct d3d12_resource *src = d3d12_resource(psrc);
324 struct pipe_resource *staging_res = NULL;
325 const struct pipe_box *src_box = psrc_box;
326 struct pipe_box staging_box, dst_box;
327
328 if (D3D12_DEBUG_BLIT & d3d12_debug) {
329 debug_printf("D3D12 COPY: from %s@%d msaa:%d mips:%d %dx%dx%d + %dx%dx%d\n",
330 util_format_name(psrc->format), src_level, psrc->nr_samples,
331 psrc->last_level,
332 psrc_box->x, psrc_box->y, psrc_box->z,
333 psrc_box->width, psrc_box->height, psrc_box->depth);
334 debug_printf(" to %s@%d msaa:%d mips:%d %dx%dx%d\n",
335 util_format_name(pdst->format), dst_level, psrc->nr_samples,
336 psrc->last_level, dstx, dsty, dstz);
337 }
338
339 /* Use an intermediate resource if copying from/to the same subresource */
340 if (d3d12_resource_resource(dst) == d3d12_resource_resource(src) && dst_level == src_level) {
341 staging_res = create_staging_resource(ctx, src, src_level, psrc_box, &staging_box, PIPE_MASK_RGBAZS);
342 src = d3d12_resource(staging_res);
343 src_level = 0;
344 src_box = &staging_box;
345 }
346
347 dst_box.x = dstx;
348 dst_box.y = dsty;
349 dst_box.z = dstz;
350 dst_box.width = psrc_box->width;
351 dst_box.height = psrc_box->height;
352
353 d3d12_direct_copy(ctx, dst, dst_level, &dst_box,
354 src, src_level, src_box, PIPE_MASK_RGBAZS);
355
356 if (staging_res)
357 pipe_resource_reference(&staging_res, NULL);
358 }
359
360 void
d3d12_context_copy_init(struct pipe_context * ctx)361 d3d12_context_copy_init(struct pipe_context *ctx)
362 {
363 ctx->resource_copy_region = d3d12_resource_copy_region;
364 }
365