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