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 ©_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, ©_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