1#include "zink_context.h" 2#include "zink_kopper.h" 3#include "zink_helpers.h" 4#include "zink_query.h" 5#include "zink_resource.h" 6#include "zink_screen.h" 7 8#include "util/u_blitter.h" 9#include "util/u_rect.h" 10#include "util/u_surface.h" 11#include "util/format/u_format.h" 12 13static void 14apply_dst_clears(struct zink_context *ctx, const struct pipe_blit_info *info, bool discard_only) 15{ 16 if (info->scissor_enable) { 17 struct u_rect rect = { info->scissor.minx, info->scissor.maxx, 18 info->scissor.miny, info->scissor.maxy }; 19 zink_fb_clears_apply_or_discard(ctx, info->dst.resource, rect, discard_only); 20 } else 21 zink_fb_clears_apply_or_discard(ctx, info->dst.resource, zink_rect_from_box(&info->dst.box), discard_only); 22} 23 24static bool 25blit_resolve(struct zink_context *ctx, const struct pipe_blit_info *info, bool *needs_present_readback) 26{ 27 if (util_format_get_mask(info->dst.format) != info->mask || 28 util_format_get_mask(info->src.format) != info->mask || 29 util_format_is_depth_or_stencil(info->dst.format) || 30 info->scissor_enable || 31 info->alpha_blend) 32 return false; 33 34 if (info->src.box.width < 0 || 35 info->dst.box.width < 0 || 36 info->src.box.height < 0 || 37 info->dst.box.height < 0 || 38 info->src.box.depth < 0 || 39 info->dst.box.depth < 0) 40 return false; 41 42 if (info->render_condition_enable && 43 ctx->render_condition_active) 44 return false; 45 46 struct zink_resource *src = zink_resource(info->src.resource); 47 struct zink_resource *dst = zink_resource(info->dst.resource); 48 49 struct zink_screen *screen = zink_screen(ctx->base.screen); 50 /* aliased/swizzled formats need u_blitter */ 51 if (src->format != zink_get_format(screen, info->src.format) || 52 dst->format != zink_get_format(screen, info->dst.format)) 53 return false; 54 if (src->format != dst->format) 55 return false; 56 57 apply_dst_clears(ctx, info, false); 58 zink_fb_clears_apply_region(ctx, info->src.resource, zink_rect_from_box(&info->src.box)); 59 60 if (src->obj->dt) 61 *needs_present_readback = zink_kopper_acquire_readback(ctx, src); 62 63 struct zink_batch *batch = &ctx->batch; 64 zink_resource_setup_transfer_layouts(ctx, src, dst); 65 VkCommandBuffer cmdbuf = *needs_present_readback ? 66 ctx->batch.state->cmdbuf : 67 zink_get_cmdbuf(ctx, src, dst); 68 zink_batch_reference_resource_rw(batch, src, false); 69 zink_batch_reference_resource_rw(batch, dst, true); 70 71 VkImageResolve region = {0}; 72 73 region.srcSubresource.aspectMask = src->aspect; 74 region.srcSubresource.mipLevel = info->src.level; 75 region.srcOffset.x = info->src.box.x; 76 region.srcOffset.y = info->src.box.y; 77 78 if (src->base.b.array_size > 1) { 79 region.srcOffset.z = 0; 80 region.srcSubresource.baseArrayLayer = info->src.box.z; 81 region.srcSubresource.layerCount = info->src.box.depth; 82 } else { 83 assert(info->src.box.depth == 1); 84 region.srcOffset.z = info->src.box.z; 85 region.srcSubresource.baseArrayLayer = 0; 86 region.srcSubresource.layerCount = 1; 87 } 88 89 region.dstSubresource.aspectMask = dst->aspect; 90 region.dstSubresource.mipLevel = info->dst.level; 91 region.dstOffset.x = info->dst.box.x; 92 region.dstOffset.y = info->dst.box.y; 93 94 if (dst->base.b.array_size > 1) { 95 region.dstOffset.z = 0; 96 region.dstSubresource.baseArrayLayer = info->dst.box.z; 97 region.dstSubresource.layerCount = info->dst.box.depth; 98 } else { 99 assert(info->dst.box.depth == 1); 100 region.dstOffset.z = info->dst.box.z; 101 region.dstSubresource.baseArrayLayer = 0; 102 region.dstSubresource.layerCount = 1; 103 } 104 105 region.extent.width = info->dst.box.width; 106 region.extent.height = info->dst.box.height; 107 region.extent.depth = info->dst.box.depth; 108 VKCTX(CmdResolveImage)(cmdbuf, src->obj->image, src->layout, 109 dst->obj->image, dst->layout, 110 1, ®ion); 111 112 return true; 113} 114 115static VkFormatFeatureFlags 116get_resource_features(struct zink_screen *screen, struct zink_resource *res) 117{ 118 VkFormatProperties props = screen->format_props[res->base.b.format]; 119 return res->optimal_tiling ? props.optimalTilingFeatures : 120 props.linearTilingFeatures; 121} 122 123static bool 124blit_native(struct zink_context *ctx, const struct pipe_blit_info *info, bool *needs_present_readback) 125{ 126 if (util_format_get_mask(info->dst.format) != info->mask || 127 util_format_get_mask(info->src.format) != info->mask || 128 info->scissor_enable || 129 info->alpha_blend) 130 return false; 131 132 if (info->render_condition_enable && 133 ctx->render_condition_active) 134 return false; 135 136 if (util_format_is_depth_or_stencil(info->dst.format) && 137 info->dst.format != info->src.format) 138 return false; 139 140 /* vkCmdBlitImage must not be used for multisampled source or destination images. */ 141 if (info->src.resource->nr_samples > 1 || info->dst.resource->nr_samples > 1) 142 return false; 143 144 struct zink_resource *src = zink_resource(info->src.resource); 145 struct zink_resource *dst = zink_resource(info->dst.resource); 146 147 struct zink_screen *screen = zink_screen(ctx->base.screen); 148 if (src->format != zink_get_format(screen, info->src.format) || 149 dst->format != zink_get_format(screen, info->dst.format)) 150 return false; 151 152 if (!(get_resource_features(screen, src) & VK_FORMAT_FEATURE_BLIT_SRC_BIT) || 153 !(get_resource_features(screen, dst) & VK_FORMAT_FEATURE_BLIT_DST_BIT)) 154 return false; 155 156 if ((util_format_is_pure_sint(info->src.format) != 157 util_format_is_pure_sint(info->dst.format)) || 158 (util_format_is_pure_uint(info->src.format) != 159 util_format_is_pure_uint(info->dst.format))) 160 return false; 161 162 if (info->filter == PIPE_TEX_FILTER_LINEAR && 163 !(get_resource_features(screen, src) & 164 VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)) 165 return false; 166 167 apply_dst_clears(ctx, info, false); 168 zink_fb_clears_apply_region(ctx, info->src.resource, zink_rect_from_box(&info->src.box)); 169 170 if (src->obj->dt) 171 *needs_present_readback = zink_kopper_acquire_readback(ctx, src); 172 173 struct zink_batch *batch = &ctx->batch; 174 zink_resource_setup_transfer_layouts(ctx, src, dst); 175 VkCommandBuffer cmdbuf = *needs_present_readback ? 176 ctx->batch.state->cmdbuf : 177 zink_get_cmdbuf(ctx, src, dst); 178 zink_batch_reference_resource_rw(batch, src, false); 179 zink_batch_reference_resource_rw(batch, dst, true); 180 181 VkImageBlit region = {0}; 182 region.srcSubresource.aspectMask = src->aspect; 183 region.srcSubresource.mipLevel = info->src.level; 184 region.srcOffsets[0].x = info->src.box.x; 185 region.srcOffsets[0].y = info->src.box.y; 186 region.srcOffsets[1].x = info->src.box.x + info->src.box.width; 187 region.srcOffsets[1].y = info->src.box.y + info->src.box.height; 188 189 enum pipe_texture_target src_target = src->base.b.target; 190 if (src->need_2D) 191 src_target = src_target == PIPE_TEXTURE_1D ? PIPE_TEXTURE_2D : PIPE_TEXTURE_2D_ARRAY; 192 switch (src_target) { 193 case PIPE_TEXTURE_CUBE: 194 case PIPE_TEXTURE_CUBE_ARRAY: 195 case PIPE_TEXTURE_2D_ARRAY: 196 case PIPE_TEXTURE_1D_ARRAY: 197 /* these use layer */ 198 region.srcSubresource.baseArrayLayer = info->src.box.z; 199 region.srcSubresource.layerCount = info->src.box.depth; 200 region.srcOffsets[0].z = 0; 201 region.srcOffsets[1].z = 1; 202 break; 203 case PIPE_TEXTURE_3D: 204 /* this uses depth */ 205 region.srcSubresource.baseArrayLayer = 0; 206 region.srcSubresource.layerCount = 1; 207 region.srcOffsets[0].z = info->src.box.z; 208 region.srcOffsets[1].z = info->src.box.z + info->src.box.depth; 209 break; 210 default: 211 /* these must only copy one layer */ 212 region.srcSubresource.baseArrayLayer = 0; 213 region.srcSubresource.layerCount = 1; 214 region.srcOffsets[0].z = 0; 215 region.srcOffsets[1].z = 1; 216 } 217 218 region.dstSubresource.aspectMask = dst->aspect; 219 region.dstSubresource.mipLevel = info->dst.level; 220 region.dstOffsets[0].x = info->dst.box.x; 221 region.dstOffsets[0].y = info->dst.box.y; 222 region.dstOffsets[1].x = info->dst.box.x + info->dst.box.width; 223 region.dstOffsets[1].y = info->dst.box.y + info->dst.box.height; 224 assert(region.dstOffsets[0].x != region.dstOffsets[1].x); 225 assert(region.dstOffsets[0].y != region.dstOffsets[1].y); 226 227 enum pipe_texture_target dst_target = dst->base.b.target; 228 if (dst->need_2D) 229 dst_target = dst_target == PIPE_TEXTURE_1D ? PIPE_TEXTURE_2D : PIPE_TEXTURE_2D_ARRAY; 230 switch (dst_target) { 231 case PIPE_TEXTURE_CUBE: 232 case PIPE_TEXTURE_CUBE_ARRAY: 233 case PIPE_TEXTURE_2D_ARRAY: 234 case PIPE_TEXTURE_1D_ARRAY: 235 /* these use layer */ 236 region.dstSubresource.baseArrayLayer = info->dst.box.z; 237 region.dstSubresource.layerCount = info->dst.box.depth; 238 region.dstOffsets[0].z = 0; 239 region.dstOffsets[1].z = 1; 240 break; 241 case PIPE_TEXTURE_3D: 242 /* this uses depth */ 243 region.dstSubresource.baseArrayLayer = 0; 244 region.dstSubresource.layerCount = 1; 245 region.dstOffsets[0].z = info->dst.box.z; 246 region.dstOffsets[1].z = info->dst.box.z + info->dst.box.depth; 247 break; 248 default: 249 /* these must only copy one layer */ 250 region.dstSubresource.baseArrayLayer = 0; 251 region.dstSubresource.layerCount = 1; 252 region.dstOffsets[0].z = 0; 253 region.dstOffsets[1].z = 1; 254 } 255 assert(region.dstOffsets[0].z != region.dstOffsets[1].z); 256 257 VKCTX(CmdBlitImage)(cmdbuf, src->obj->image, src->layout, 258 dst->obj->image, dst->layout, 259 1, ®ion, 260 zink_filter(info->filter)); 261 262 return true; 263} 264 265static bool 266try_copy_region(struct pipe_context *pctx, const struct pipe_blit_info *info) 267{ 268 struct zink_context *ctx = zink_context(pctx); 269 struct zink_resource *src = zink_resource(info->src.resource); 270 struct zink_resource *dst = zink_resource(info->dst.resource); 271 /* if we're copying between resources with matching aspects then we can probably just copy_region */ 272 if (src->aspect != dst->aspect) 273 return false; 274 struct pipe_blit_info new_info = *info; 275 276 if (src->aspect & VK_IMAGE_ASPECT_STENCIL_BIT && 277 new_info.render_condition_enable && 278 !ctx->render_condition_active) 279 new_info.render_condition_enable = false; 280 281 return util_try_blit_via_copy_region(pctx, &new_info, ctx->render_condition_active); 282} 283 284void 285zink_blit(struct pipe_context *pctx, 286 const struct pipe_blit_info *info) 287{ 288 struct zink_context *ctx = zink_context(pctx); 289 const struct util_format_description *src_desc = util_format_description(info->src.format); 290 const struct util_format_description *dst_desc = util_format_description(info->dst.format); 291 292 if (info->render_condition_enable && 293 unlikely(!zink_screen(pctx->screen)->info.have_EXT_conditional_rendering && !zink_check_conditional_render(ctx))) 294 return; 295 296 struct zink_resource *src = zink_resource(info->src.resource); 297 struct zink_resource *dst = zink_resource(info->dst.resource); 298 bool needs_present_readback = false; 299 if (zink_is_swapchain(dst)) { 300 if (!zink_kopper_acquire(ctx, dst, UINT64_MAX)) 301 return; 302 } 303 304 if (src_desc == dst_desc || 305 src_desc->nr_channels != 4 || src_desc->layout != UTIL_FORMAT_LAYOUT_PLAIN || 306 (src_desc->nr_channels == 4 && src_desc->channel[3].type != UTIL_FORMAT_TYPE_VOID)) { 307 /* we can't blit RGBX -> RGBA formats directly since they're emulated 308 * so we have to use sampler views 309 */ 310 if (info->src.resource->nr_samples > 1 && 311 info->dst.resource->nr_samples <= 1) { 312 if (blit_resolve(ctx, info, &needs_present_readback)) 313 goto end; 314 } else { 315 if (try_copy_region(pctx, info)) 316 goto end; 317 if (blit_native(ctx, info, &needs_present_readback)) 318 goto end; 319 } 320 } 321 322 323 324 bool stencil_blit = false; 325 if (!util_blitter_is_blit_supported(ctx->blitter, info)) { 326 if (util_format_is_depth_or_stencil(info->src.resource->format)) { 327 struct pipe_blit_info depth_blit = *info; 328 depth_blit.mask = PIPE_MASK_Z; 329 stencil_blit = util_blitter_is_blit_supported(ctx->blitter, &depth_blit); 330 if (stencil_blit) { 331 zink_blit_begin(ctx, ZINK_BLIT_SAVE_FB | ZINK_BLIT_SAVE_FS | ZINK_BLIT_SAVE_TEXTURES); 332 util_blitter_blit(ctx->blitter, &depth_blit); 333 } 334 } 335 if (!stencil_blit) { 336 mesa_loge("ZINK: blit unsupported %s -> %s", 337 util_format_short_name(info->src.resource->format), 338 util_format_short_name(info->dst.resource->format)); 339 goto end; 340 } 341 } 342 343 if (src->obj->dt) { 344 zink_fb_clears_apply_region(ctx, info->src.resource, zink_rect_from_box(&info->src.box)); 345 needs_present_readback = zink_kopper_acquire_readback(ctx, src); 346 } 347 348 /* this is discard_only because we're about to start a renderpass that will 349 * flush all pending clears anyway 350 */ 351 apply_dst_clears(ctx, info, true); 352 353 /* this will draw a full-resource quad, so ignore existing data */ 354 if (util_blit_covers_whole_resource(info)) 355 pctx->invalidate_resource(pctx, info->dst.resource); 356 zink_blit_begin(ctx, ZINK_BLIT_SAVE_FB | ZINK_BLIT_SAVE_FS | ZINK_BLIT_SAVE_TEXTURES); 357 358 if (stencil_blit) { 359 struct pipe_surface *dst_view, dst_templ; 360 util_blitter_default_dst_texture(&dst_templ, info->dst.resource, info->dst.level, info->dst.box.z); 361 dst_view = pctx->create_surface(pctx, info->dst.resource, &dst_templ); 362 363 util_blitter_clear_depth_stencil(ctx->blitter, dst_view, PIPE_CLEAR_STENCIL, 364 0, 0, info->dst.box.x, info->dst.box.y, 365 info->dst.box.width, info->dst.box.height); 366 zink_blit_begin(ctx, ZINK_BLIT_SAVE_FB | ZINK_BLIT_SAVE_FS | ZINK_BLIT_SAVE_TEXTURES); 367 util_blitter_stencil_fallback(ctx->blitter, 368 info->dst.resource, 369 info->dst.level, 370 &info->dst.box, 371 info->src.resource, 372 info->src.level, 373 &info->src.box, 374 info->scissor_enable ? &info->scissor : NULL); 375 376 pipe_surface_release(pctx, &dst_view); 377 } else { 378 util_blitter_blit(ctx->blitter, info); 379 } 380end: 381 if (needs_present_readback) 382 zink_kopper_present_readback(ctx, src); 383} 384 385/* similar to radeonsi */ 386void 387zink_blit_begin(struct zink_context *ctx, enum zink_blit_flags flags) 388{ 389 util_blitter_save_vertex_elements(ctx->blitter, ctx->element_state); 390 util_blitter_save_viewport(ctx->blitter, ctx->vp_state.viewport_states); 391 392 util_blitter_save_vertex_buffer_slot(ctx->blitter, ctx->vertex_buffers); 393 util_blitter_save_vertex_shader(ctx->blitter, ctx->gfx_stages[PIPE_SHADER_VERTEX]); 394 util_blitter_save_tessctrl_shader(ctx->blitter, ctx->gfx_stages[PIPE_SHADER_TESS_CTRL]); 395 util_blitter_save_tesseval_shader(ctx->blitter, ctx->gfx_stages[PIPE_SHADER_TESS_EVAL]); 396 util_blitter_save_geometry_shader(ctx->blitter, ctx->gfx_stages[PIPE_SHADER_GEOMETRY]); 397 util_blitter_save_rasterizer(ctx->blitter, ctx->rast_state); 398 util_blitter_save_so_targets(ctx->blitter, ctx->num_so_targets, ctx->so_targets); 399 400 if (flags & ZINK_BLIT_SAVE_FS) { 401 util_blitter_save_fragment_constant_buffer_slot(ctx->blitter, ctx->ubos[PIPE_SHADER_FRAGMENT]); 402 util_blitter_save_blend(ctx->blitter, ctx->gfx_pipeline_state.blend_state); 403 util_blitter_save_depth_stencil_alpha(ctx->blitter, ctx->dsa_state); 404 util_blitter_save_stencil_ref(ctx->blitter, &ctx->stencil_ref); 405 util_blitter_save_sample_mask(ctx->blitter, ctx->gfx_pipeline_state.sample_mask, 0); 406 util_blitter_save_scissor(ctx->blitter, ctx->vp_state.scissor_states); 407 /* also util_blitter_save_window_rectangles when we have that? */ 408 409 util_blitter_save_fragment_shader(ctx->blitter, ctx->gfx_stages[PIPE_SHADER_FRAGMENT]); 410 } 411 412 if (flags & ZINK_BLIT_SAVE_FB) 413 util_blitter_save_framebuffer(ctx->blitter, &ctx->fb_state); 414 415 416 if (flags & ZINK_BLIT_SAVE_TEXTURES) { 417 util_blitter_save_fragment_sampler_states(ctx->blitter, 418 ctx->di.num_samplers[PIPE_SHADER_FRAGMENT], 419 (void**)ctx->sampler_states[PIPE_SHADER_FRAGMENT]); 420 util_blitter_save_fragment_sampler_views(ctx->blitter, 421 ctx->di.num_sampler_views[PIPE_SHADER_FRAGMENT], 422 ctx->sampler_views[PIPE_SHADER_FRAGMENT]); 423 } 424 425 if (flags & ZINK_BLIT_NO_COND_RENDER && ctx->render_condition_active) 426 zink_stop_conditional_render(ctx); 427} 428 429bool 430zink_blit_region_fills(struct u_rect region, unsigned width, unsigned height) 431{ 432 struct u_rect intersect = {0, width, 0, height}; 433 struct u_rect r = { 434 MIN2(region.x0, region.x1), 435 MAX2(region.x0, region.x1), 436 MIN2(region.y0, region.y1), 437 MAX2(region.y0, region.y1), 438 }; 439 440 if (!u_rect_test_intersection(&r, &intersect)) 441 /* is this even a thing? */ 442 return false; 443 444 u_rect_find_intersection(&r, &intersect); 445 if (intersect.x0 != 0 || intersect.y0 != 0 || 446 intersect.x1 != width || intersect.y1 != height) 447 return false; 448 449 return true; 450} 451 452bool 453zink_blit_region_covers(struct u_rect region, struct u_rect covers) 454{ 455 struct u_rect r = { 456 MIN2(region.x0, region.x1), 457 MAX2(region.x0, region.x1), 458 MIN2(region.y0, region.y1), 459 MAX2(region.y0, region.y1), 460 }; 461 struct u_rect c = { 462 MIN2(covers.x0, covers.x1), 463 MAX2(covers.x0, covers.x1), 464 MIN2(covers.y0, covers.y1), 465 MAX2(covers.y0, covers.y1), 466 }; 467 struct u_rect intersect; 468 if (!u_rect_test_intersection(&r, &c)) 469 return false; 470 471 u_rect_union(&intersect, &r, &c); 472 return intersect.x0 == c.x0 && intersect.y0 == c.y0 && 473 intersect.x1 == c.x1 && intersect.y1 == c.y1; 474} 475