• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "zink_clear.h"
2 #include "zink_context.h"
3 #include "zink_format.h"
4 #include "zink_inlines.h"
5 #include "zink_kopper.h"
6 #include "zink_helpers.h"
7 #include "zink_query.h"
8 #include "zink_resource.h"
9 #include "zink_screen.h"
10 
11 #include "util/u_blitter.h"
12 #include "util/u_rect.h"
13 #include "util/u_surface.h"
14 #include "util/format/u_format.h"
15 
16 static void
apply_dst_clears(struct zink_context * ctx,const struct pipe_blit_info * info,bool discard_only)17 apply_dst_clears(struct zink_context *ctx, const struct pipe_blit_info *info, bool discard_only)
18 {
19    if (info->scissor_enable) {
20       struct u_rect rect = { info->scissor.minx, info->scissor.maxx,
21                              info->scissor.miny, info->scissor.maxy };
22       zink_fb_clears_apply_or_discard(ctx, info->dst.resource, rect, discard_only);
23    } else
24       zink_fb_clears_apply_or_discard(ctx, info->dst.resource, zink_rect_from_box(&info->dst.box), discard_only);
25 }
26 
27 static bool
blit_resolve(struct zink_context * ctx,const struct pipe_blit_info * info,bool * needs_present_readback)28 blit_resolve(struct zink_context *ctx, const struct pipe_blit_info *info, bool *needs_present_readback)
29 {
30    if (util_format_get_mask(info->dst.format) != info->mask ||
31        util_format_get_mask(info->src.format) != info->mask ||
32        util_format_is_depth_or_stencil(info->dst.format) ||
33        info->scissor_enable ||
34        info->swizzle_enable ||
35        info->alpha_blend)
36       return false;
37 
38    if (info->src.box.width < 0 ||
39        info->dst.box.width < 0 ||
40        info->src.box.height < 0 ||
41        info->dst.box.height < 0 ||
42        info->src.box.depth < 0 ||
43        info->dst.box.depth < 0)
44       return false;
45    /* vulkan resolves can't downscale */
46    if (info->src.box.width > info->dst.box.width ||
47        info->src.box.height > info->dst.box.height ||
48        info->src.box.depth > info->dst.box.depth)
49       return false;
50 
51    if (info->render_condition_enable &&
52        ctx->render_condition_active)
53       return false;
54 
55    struct zink_resource *src = zink_resource(info->src.resource);
56    struct zink_resource *use_src = src;
57    struct zink_resource *dst = zink_resource(info->dst.resource);
58 
59    struct zink_screen *screen = zink_screen(ctx->base.screen);
60    /* aliased/swizzled formats need u_blitter */
61    if (src->format != zink_get_format(screen, info->src.format) ||
62        dst->format != zink_get_format(screen, info->dst.format))
63       return false;
64    if (src->format != dst->format)
65       return false;
66 
67 
68    apply_dst_clears(ctx, info, false);
69    zink_fb_clears_apply_region(ctx, info->src.resource, zink_rect_from_box(&info->src.box));
70 
71    if (src->obj->dt)
72       *needs_present_readback = zink_kopper_acquire_readback(ctx, src, &use_src);
73 
74    zink_resource_setup_transfer_layouts(ctx, use_src, dst);
75    VkCommandBuffer cmdbuf = *needs_present_readback ?
76                             ctx->bs->cmdbuf :
77                             zink_get_cmdbuf(ctx, src, dst);
78    zink_batch_reference_resource_rw(ctx, use_src, false);
79    zink_batch_reference_resource_rw(ctx, dst, true);
80 
81    bool marker = zink_cmd_debug_marker_begin(ctx, cmdbuf, "blit_resolve(%s->%s, %dx%d->%dx%d)",
82                                              util_format_short_name(info->src.format),
83                                              util_format_short_name(info->src.format),
84                                              info->src.box.width, info->src.box.height,
85                                              info->dst.box.width, info->dst.box.height);
86    VkImageResolve region = {0};
87 
88    region.srcSubresource.aspectMask = src->aspect;
89    region.srcSubresource.mipLevel = info->src.level;
90    region.srcOffset.x = info->src.box.x;
91    region.srcOffset.y = info->src.box.y;
92 
93    if (src->base.b.array_size > 1) {
94       region.srcOffset.z = 0;
95       region.srcSubresource.baseArrayLayer = info->src.box.z;
96       region.srcSubresource.layerCount = info->src.box.depth;
97    } else {
98       assert(info->src.box.depth == 1);
99       region.srcOffset.z = info->src.box.z;
100       region.srcSubresource.baseArrayLayer = 0;
101       region.srcSubresource.layerCount = 1;
102    }
103 
104    region.dstSubresource.aspectMask = dst->aspect;
105    region.dstSubresource.mipLevel = info->dst.level;
106    region.dstOffset.x = info->dst.box.x;
107    region.dstOffset.y = info->dst.box.y;
108 
109    if (dst->base.b.array_size > 1) {
110       region.dstOffset.z = 0;
111       region.dstSubresource.baseArrayLayer = info->dst.box.z;
112       region.dstSubresource.layerCount = info->dst.box.depth;
113    } else {
114       assert(info->dst.box.depth == 1);
115       region.dstOffset.z = info->dst.box.z;
116       region.dstSubresource.baseArrayLayer = 0;
117       region.dstSubresource.layerCount = 1;
118    }
119 
120    region.extent.width = info->dst.box.width;
121    region.extent.height = info->dst.box.height;
122    region.extent.depth = info->dst.box.depth;
123    if (region.srcOffset.x + region.extent.width >= u_minify(src->base.b.width0, region.srcSubresource.mipLevel))
124       region.extent.width = u_minify(src->base.b.width0, region.srcSubresource.mipLevel) - region.srcOffset.x;
125    if (region.dstOffset.x + region.extent.width >= u_minify(dst->base.b.width0, region.dstSubresource.mipLevel))
126       region.extent.width = u_minify(dst->base.b.width0, region.dstSubresource.mipLevel) - region.dstOffset.x;
127    if (region.srcOffset.y + region.extent.height >= u_minify(src->base.b.height0, region.srcSubresource.mipLevel))
128       region.extent.height = u_minify(src->base.b.height0, region.srcSubresource.mipLevel) - region.srcOffset.y;
129    if (region.dstOffset.y + region.extent.height >= u_minify(dst->base.b.height0, region.dstSubresource.mipLevel))
130       region.extent.height = u_minify(dst->base.b.height0, region.dstSubresource.mipLevel) - region.dstOffset.y;
131    if (region.srcOffset.z + region.extent.depth >= u_minify(src->base.b.depth0, region.srcSubresource.mipLevel))
132       region.extent.depth = u_minify(src->base.b.depth0, region.srcSubresource.mipLevel) - region.srcOffset.z;
133    if (region.dstOffset.z + region.extent.depth >= u_minify(dst->base.b.depth0, region.dstSubresource.mipLevel))
134       region.extent.depth = u_minify(dst->base.b.depth0, region.dstSubresource.mipLevel) - region.dstOffset.z;
135    VKCTX(CmdResolveImage)(cmdbuf, use_src->obj->image, src->layout,
136                      dst->obj->image, dst->layout,
137                      1, &region);
138    zink_cmd_debug_marker_end(ctx, cmdbuf, marker);
139 
140    return true;
141 }
142 
143 static bool
blit_native(struct zink_context * ctx,const struct pipe_blit_info * info,bool * needs_present_readback)144 blit_native(struct zink_context *ctx, const struct pipe_blit_info *info, bool *needs_present_readback)
145 {
146    if (util_format_get_mask(info->dst.format) != info->mask ||
147        util_format_get_mask(info->src.format) != info->mask ||
148        info->scissor_enable ||
149        info->swizzle_enable ||
150        info->alpha_blend)
151       return false;
152 
153    if (info->render_condition_enable &&
154        ctx->render_condition_active)
155       return false;
156 
157    if (util_format_is_depth_or_stencil(info->dst.format) &&
158        (info->dst.format != info->src.format || info->filter == PIPE_TEX_FILTER_LINEAR))
159       return false;
160 
161    /* vkCmdBlitImage must not be used for multisampled source or destination images. */
162    if (info->src.resource->nr_samples > 1 || info->dst.resource->nr_samples > 1)
163       return false;
164 
165    struct zink_resource *src = zink_resource(info->src.resource);
166    struct zink_resource *use_src = src;
167    struct zink_resource *dst = zink_resource(info->dst.resource);
168 
169    struct zink_screen *screen = zink_screen(ctx->base.screen);
170    if (src->format != zink_get_format(screen, info->src.format) ||
171        dst->format != zink_get_format(screen, info->dst.format))
172       return false;
173    if (src->format != VK_FORMAT_A8_UNORM_KHR && zink_format_is_emulated_alpha(info->src.format))
174       return false;
175 
176    if (!(src->obj->vkfeats & VK_FORMAT_FEATURE_BLIT_SRC_BIT) ||
177        !(dst->obj->vkfeats & VK_FORMAT_FEATURE_BLIT_DST_BIT))
178       return false;
179 
180    if ((util_format_is_pure_sint(info->src.format) !=
181         util_format_is_pure_sint(info->dst.format)) ||
182        (util_format_is_pure_uint(info->src.format) !=
183         util_format_is_pure_uint(info->dst.format)))
184       return false;
185 
186    if (info->filter == PIPE_TEX_FILTER_LINEAR &&
187        !(src->obj->vkfeats & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT))
188       return false;
189 
190 
191    VkImageBlit region = {0};
192    region.srcSubresource.aspectMask = src->aspect;
193    region.srcSubresource.mipLevel = info->src.level;
194    region.srcOffsets[0].x = info->src.box.x;
195    region.srcOffsets[0].y = info->src.box.y;
196    region.srcOffsets[1].x = info->src.box.x + info->src.box.width;
197    region.srcOffsets[1].y = info->src.box.y + info->src.box.height;
198 
199    enum pipe_texture_target src_target = src->base.b.target;
200    if (src->need_2D)
201       src_target = src_target == PIPE_TEXTURE_1D ? PIPE_TEXTURE_2D : PIPE_TEXTURE_2D_ARRAY;
202    switch (src_target) {
203    case PIPE_TEXTURE_CUBE:
204    case PIPE_TEXTURE_CUBE_ARRAY:
205    case PIPE_TEXTURE_2D_ARRAY:
206    case PIPE_TEXTURE_1D_ARRAY:
207       /* these use layer */
208       region.srcSubresource.baseArrayLayer = info->src.box.z;
209       /* VUID-vkCmdBlitImage-srcImage-00240 */
210       if (region.srcSubresource.baseArrayLayer && dst->base.b.target == PIPE_TEXTURE_3D)
211          return false;
212       region.srcSubresource.layerCount = info->src.box.depth;
213       region.srcOffsets[0].z = 0;
214       region.srcOffsets[1].z = 1;
215       break;
216    case PIPE_TEXTURE_3D:
217       /* this uses depth */
218       region.srcSubresource.baseArrayLayer = 0;
219       region.srcSubresource.layerCount = 1;
220       region.srcOffsets[0].z = info->src.box.z;
221       region.srcOffsets[1].z = info->src.box.z + info->src.box.depth;
222       break;
223    default:
224       /* these must only copy one layer */
225       region.srcSubresource.baseArrayLayer = 0;
226       region.srcSubresource.layerCount = 1;
227       region.srcOffsets[0].z = 0;
228       region.srcOffsets[1].z = 1;
229    }
230 
231    region.dstSubresource.aspectMask = dst->aspect;
232    region.dstSubresource.mipLevel = info->dst.level;
233    region.dstOffsets[0].x = info->dst.box.x;
234    region.dstOffsets[0].y = info->dst.box.y;
235    region.dstOffsets[1].x = info->dst.box.x + info->dst.box.width;
236    region.dstOffsets[1].y = info->dst.box.y + info->dst.box.height;
237    assert(region.dstOffsets[0].x != region.dstOffsets[1].x);
238    assert(region.dstOffsets[0].y != region.dstOffsets[1].y);
239 
240    enum pipe_texture_target dst_target = dst->base.b.target;
241    if (dst->need_2D)
242       dst_target = dst_target == PIPE_TEXTURE_1D ? PIPE_TEXTURE_2D : PIPE_TEXTURE_2D_ARRAY;
243    switch (dst_target) {
244    case PIPE_TEXTURE_CUBE:
245    case PIPE_TEXTURE_CUBE_ARRAY:
246    case PIPE_TEXTURE_2D_ARRAY:
247    case PIPE_TEXTURE_1D_ARRAY:
248       /* these use layer */
249       region.dstSubresource.baseArrayLayer = info->dst.box.z;
250       /* VUID-vkCmdBlitImage-srcImage-00240 */
251       if (region.dstSubresource.baseArrayLayer && src->base.b.target == PIPE_TEXTURE_3D)
252          return false;
253       region.dstSubresource.layerCount = info->dst.box.depth;
254       region.dstOffsets[0].z = 0;
255       region.dstOffsets[1].z = 1;
256       break;
257    case PIPE_TEXTURE_3D:
258       /* this uses depth */
259       region.dstSubresource.baseArrayLayer = 0;
260       region.dstSubresource.layerCount = 1;
261       region.dstOffsets[0].z = info->dst.box.z;
262       region.dstOffsets[1].z = info->dst.box.z + info->dst.box.depth;
263       break;
264    default:
265       /* these must only copy one layer */
266       region.dstSubresource.baseArrayLayer = 0;
267       region.dstSubresource.layerCount = 1;
268       region.dstOffsets[0].z = 0;
269       region.dstOffsets[1].z = 1;
270    }
271    assert(region.dstOffsets[0].z != region.dstOffsets[1].z);
272 
273    apply_dst_clears(ctx, info, false);
274    zink_fb_clears_apply_region(ctx, info->src.resource, zink_rect_from_box(&info->src.box));
275 
276    if (src->obj->dt)
277       *needs_present_readback = zink_kopper_acquire_readback(ctx, src, &use_src);
278 
279    zink_resource_setup_transfer_layouts(ctx, use_src, dst);
280    VkCommandBuffer cmdbuf = *needs_present_readback ?
281                             ctx->bs->cmdbuf :
282                             zink_get_cmdbuf(ctx, src, dst);
283    zink_batch_reference_resource_rw(ctx, use_src, false);
284    zink_batch_reference_resource_rw(ctx, dst, true);
285 
286    bool marker = zink_cmd_debug_marker_begin(ctx, cmdbuf, "blit_native(%s->%s, %dx%d->%dx%d)",
287                                              util_format_short_name(info->src.format),
288                                              util_format_short_name(info->src.format),
289                                              info->src.box.width, info->src.box.height,
290                                              info->dst.box.width, info->dst.box.height);
291 
292    VKCTX(CmdBlitImage)(cmdbuf, use_src->obj->image, src->layout,
293                   dst->obj->image, dst->layout,
294                   1, &region,
295                   zink_filter(info->filter));
296 
297    zink_cmd_debug_marker_end(ctx, cmdbuf, marker);
298 
299    return true;
300 }
301 
302 static bool
try_copy_region(struct pipe_context * pctx,const struct pipe_blit_info * info)303 try_copy_region(struct pipe_context *pctx, const struct pipe_blit_info *info)
304 {
305    struct zink_context *ctx = zink_context(pctx);
306    struct zink_resource *src = zink_resource(info->src.resource);
307    struct zink_resource *dst = zink_resource(info->dst.resource);
308    /* if we're copying between resources with matching aspects then we can probably just copy_region */
309    if (src->aspect != dst->aspect)
310       return false;
311    struct pipe_blit_info new_info = *info;
312 
313    if (src->aspect & VK_IMAGE_ASPECT_STENCIL_BIT &&
314        new_info.render_condition_enable &&
315        !ctx->render_condition_active)
316       new_info.render_condition_enable = false;
317 
318    return util_try_blit_via_copy_region(pctx, &new_info, ctx->render_condition_active);
319 }
320 
321 void
zink_blit(struct pipe_context * pctx,const struct pipe_blit_info * info)322 zink_blit(struct pipe_context *pctx,
323           const struct pipe_blit_info *info)
324 {
325    struct zink_context *ctx = zink_context(pctx);
326    const struct util_format_description *src_desc = util_format_description(info->src.format);
327    const struct util_format_description *dst_desc = util_format_description(info->dst.format);
328 
329    struct zink_resource *src = zink_resource(info->src.resource);
330    struct zink_resource *use_src = src;
331    struct zink_resource *dst = zink_resource(info->dst.resource);
332    bool needs_present_readback = false;
333    if (zink_is_swapchain(dst)) {
334       if (!zink_kopper_acquire(ctx, dst, UINT64_MAX))
335          return;
336    }
337 
338    if (src_desc == dst_desc ||
339        src_desc->nr_channels != 4 || src_desc->layout != UTIL_FORMAT_LAYOUT_PLAIN ||
340        (src_desc->nr_channels == 4 && src_desc->channel[3].type != UTIL_FORMAT_TYPE_VOID)) {
341       /* we can't blit RGBX -> RGBA formats directly since they're emulated
342        * so we have to use sampler views
343        */
344       if (info->src.resource->nr_samples > 1 &&
345           info->dst.resource->nr_samples <= 1) {
346          if (blit_resolve(ctx, info, &needs_present_readback))
347             goto end;
348       } else {
349          if (try_copy_region(pctx, info))
350             goto end;
351          if (blit_native(ctx, info, &needs_present_readback))
352             goto end;
353       }
354    }
355 
356 
357 
358    bool stencil_blit = false;
359    if (!util_blitter_is_blit_supported(ctx->blitter, info)) {
360       if (util_format_is_depth_or_stencil(info->src.resource->format)) {
361          if (info->mask & PIPE_MASK_Z) {
362             struct pipe_blit_info depth_blit = *info;
363             depth_blit.mask = PIPE_MASK_Z;
364             if (util_blitter_is_blit_supported(ctx->blitter, &depth_blit)) {
365                zink_blit_begin(ctx, ZINK_BLIT_SAVE_FB | ZINK_BLIT_SAVE_FS | ZINK_BLIT_SAVE_TEXTURES);
366                util_blitter_blit(ctx->blitter, &depth_blit, NULL);
367             } else {
368                mesa_loge("ZINK: depth blit unsupported %s -> %s",
369                          util_format_short_name(info->src.resource->format),
370                          util_format_short_name(info->dst.resource->format));
371             }
372          }
373          if (info->mask & PIPE_MASK_S)
374             stencil_blit = true;
375       }
376       if (!stencil_blit) {
377          mesa_loge("ZINK: blit unsupported %s -> %s",
378                  util_format_short_name(info->src.resource->format),
379                  util_format_short_name(info->dst.resource->format));
380          goto end;
381       }
382    }
383 
384    if (src->obj->dt) {
385       zink_fb_clears_apply_region(ctx, info->src.resource, zink_rect_from_box(&info->src.box));
386       needs_present_readback = zink_kopper_acquire_readback(ctx, src, &use_src);
387    }
388 
389    /* this is discard_only because we're about to start a renderpass that will
390     * flush all pending clears anyway
391     */
392    apply_dst_clears(ctx, info, true);
393    zink_fb_clears_apply_region(ctx, info->src.resource, zink_rect_from_box(&info->src.box));
394    unsigned rp_clears_enabled = ctx->rp_clears_enabled;
395    unsigned clears_enabled = ctx->clears_enabled;
396    if (!dst->fb_bind_count) {
397       /* avoid applying clears from fb unbind by storing and re-setting them after the blit */
398       ctx->rp_clears_enabled = 0;
399       ctx->clears_enabled = 0;
400    } else {
401       unsigned bit;
402       /* convert to PIPE_CLEAR_XYZ */
403       if (dst->fb_binds & BITFIELD_BIT(PIPE_MAX_COLOR_BUFS))
404          bit = PIPE_CLEAR_DEPTHSTENCIL;
405       else
406          bit = dst->fb_binds << 2;
407       rp_clears_enabled &= ~bit;
408       clears_enabled &= ~bit;
409       ctx->rp_clears_enabled &= bit;
410       ctx->clears_enabled &= bit;
411    }
412 
413    /* this will draw a full-resource quad, so ignore existing data */
414    bool whole = util_blit_covers_whole_resource(info);
415    if (whole)
416       pctx->invalidate_resource(pctx, info->dst.resource);
417 
418    ctx->unordered_blitting = !(info->render_condition_enable && ctx->render_condition_active) &&
419                              zink_screen(ctx->base.screen)->info.have_KHR_dynamic_rendering &&
420                              !needs_present_readback &&
421                              zink_get_cmdbuf(ctx, src, dst) == ctx->bs->reordered_cmdbuf;
422    VkCommandBuffer cmdbuf = ctx->bs->cmdbuf;
423    VkPipeline pipeline = ctx->gfx_pipeline_state.pipeline;
424    bool in_rp = ctx->in_rp;
425    uint64_t tc_data = ctx->dynamic_fb.tc_info.data;
426    bool queries_disabled = ctx->queries_disabled;
427    bool rp_changed = ctx->rp_changed || (!ctx->fb_state.zsbuf && util_format_is_depth_or_stencil(info->dst.format));
428    unsigned ds3_states = ctx->ds3_states;
429    bool rp_tc_info_updated = ctx->rp_tc_info_updated;
430    if (ctx->unordered_blitting) {
431       /* for unordered blit, swap the unordered cmdbuf for the main one for the whole op to avoid conditional hell */
432       ctx->bs->cmdbuf = ctx->bs->reordered_cmdbuf;
433       ctx->in_rp = false;
434       ctx->rp_changed = true;
435       ctx->queries_disabled = true;
436       ctx->pipeline_changed[0] = true;
437       zink_reset_ds3_states(ctx);
438       zink_select_draw_vbo(ctx);
439    }
440    zink_blit_begin(ctx, ZINK_BLIT_SAVE_FB | ZINK_BLIT_SAVE_FS | ZINK_BLIT_SAVE_TEXTURES);
441    if (zink_format_needs_mutable(info->src.format, info->src.resource->format))
442       zink_resource_object_init_mutable(ctx, src);
443    if (zink_format_needs_mutable(info->dst.format, info->dst.resource->format))
444       zink_resource_object_init_mutable(ctx, dst);
445    zink_blit_barriers(ctx, use_src, dst, whole);
446    ctx->blitting = true;
447    ctx->blit_scissor = info->scissor_enable;
448    ctx->blit_nearest = info->filter == PIPE_TEX_FILTER_NEAREST;
449 
450    if (stencil_blit) {
451       struct pipe_surface *dst_view, dst_templ;
452       util_blitter_default_dst_texture(&dst_templ, info->dst.resource, info->dst.level, info->dst.box.z);
453       dst_view = pctx->create_surface(pctx, info->dst.resource, &dst_templ);
454 
455       util_blitter_clear_depth_stencil(ctx->blitter, dst_view, PIPE_CLEAR_STENCIL,
456                                        0, 0, info->dst.box.x, info->dst.box.y,
457                                        info->dst.box.width, info->dst.box.height);
458       zink_blit_begin(ctx, ZINK_BLIT_SAVE_FB | ZINK_BLIT_SAVE_FS | ZINK_BLIT_SAVE_TEXTURES | ZINK_BLIT_SAVE_FS_CONST_BUF);
459       util_blitter_stencil_fallback(ctx->blitter,
460                                     info->dst.resource,
461                                     info->dst.level,
462                                     &info->dst.box,
463                                     info->src.resource,
464                                     info->src.level,
465                                     &info->src.box,
466                                     info->scissor_enable ? &info->scissor : NULL);
467 
468       pipe_surface_release(pctx, &dst_view);
469    } else {
470       struct pipe_blit_info new_info = *info;
471       new_info.src.resource = &use_src->base.b;
472       util_blitter_blit(ctx->blitter, &new_info, NULL);
473    }
474    ctx->blitting = false;
475    ctx->rp_clears_enabled = rp_clears_enabled;
476    ctx->clears_enabled = clears_enabled;
477    if (ctx->unordered_blitting) {
478       zink_batch_no_rp(ctx);
479       ctx->in_rp = in_rp;
480       ctx->gfx_pipeline_state.rp_state = zink_update_rendering_info(ctx);
481       ctx->rp_changed = rp_changed;
482       ctx->rp_tc_info_updated |= rp_tc_info_updated;
483       ctx->queries_disabled = queries_disabled;
484       ctx->dynamic_fb.tc_info.data = tc_data;
485       ctx->bs->cmdbuf = cmdbuf;
486       ctx->gfx_pipeline_state.pipeline = pipeline;
487       ctx->pipeline_changed[0] = true;
488       ctx->ds3_states = ds3_states;
489       zink_select_draw_vbo(ctx);
490    }
491    ctx->unordered_blitting = false;
492 end:
493    if (needs_present_readback) {
494       src->obj->unordered_read = false;
495       dst->obj->unordered_write = false;
496       zink_kopper_present_readback(ctx, src);
497    }
498 }
499 
500 /* similar to radeonsi */
501 void
zink_blit_begin(struct zink_context * ctx,enum zink_blit_flags flags)502 zink_blit_begin(struct zink_context *ctx, enum zink_blit_flags flags)
503 {
504    util_blitter_save_vertex_elements(ctx->blitter, ctx->element_state);
505    util_blitter_save_viewport(ctx->blitter, ctx->vp_state.viewport_states);
506 
507    util_blitter_save_vertex_buffers(ctx->blitter, ctx->vertex_buffers,
508                                     util_last_bit(ctx->gfx_pipeline_state.vertex_buffers_enabled_mask));
509    util_blitter_save_vertex_shader(ctx->blitter, ctx->gfx_stages[MESA_SHADER_VERTEX]);
510    util_blitter_save_tessctrl_shader(ctx->blitter, ctx->gfx_stages[MESA_SHADER_TESS_CTRL]);
511    util_blitter_save_tesseval_shader(ctx->blitter, ctx->gfx_stages[MESA_SHADER_TESS_EVAL]);
512    util_blitter_save_geometry_shader(ctx->blitter, ctx->gfx_stages[MESA_SHADER_GEOMETRY]);
513    util_blitter_save_rasterizer(ctx->blitter, ctx->rast_state);
514    util_blitter_save_so_targets(ctx->blitter, ctx->num_so_targets, ctx->so_targets, MESA_PRIM_UNKNOWN);
515 
516    if (flags & ZINK_BLIT_SAVE_FS_CONST_BUF)
517       util_blitter_save_fragment_constant_buffer_slot(ctx->blitter, ctx->ubos[MESA_SHADER_FRAGMENT]);
518 
519    if (flags & ZINK_BLIT_SAVE_FS) {
520       util_blitter_save_blend(ctx->blitter, ctx->gfx_pipeline_state.blend_state);
521       util_blitter_save_depth_stencil_alpha(ctx->blitter, ctx->dsa_state);
522       util_blitter_save_stencil_ref(ctx->blitter, &ctx->stencil_ref);
523       util_blitter_save_sample_mask(ctx->blitter, ctx->gfx_pipeline_state.sample_mask, ctx->gfx_pipeline_state.min_samples + 1);
524       util_blitter_save_scissor(ctx->blitter, ctx->vp_state.scissor_states);
525       /* also util_blitter_save_window_rectangles when we have that? */
526 
527       util_blitter_save_fragment_shader(ctx->blitter, ctx->gfx_stages[MESA_SHADER_FRAGMENT]);
528    }
529 
530    if (flags & ZINK_BLIT_SAVE_FB)
531       util_blitter_save_framebuffer(ctx->blitter, &ctx->fb_state);
532 
533 
534    if (flags & ZINK_BLIT_SAVE_TEXTURES) {
535       util_blitter_save_fragment_sampler_states(ctx->blitter,
536                                                 ctx->di.num_samplers[MESA_SHADER_FRAGMENT],
537                                                 (void**)ctx->sampler_states[MESA_SHADER_FRAGMENT]);
538       util_blitter_save_fragment_sampler_views(ctx->blitter,
539                                                ctx->di.num_sampler_views[MESA_SHADER_FRAGMENT],
540                                                ctx->sampler_views[MESA_SHADER_FRAGMENT]);
541    }
542 
543    if (flags & ZINK_BLIT_NO_COND_RENDER && ctx->render_condition_active)
544       zink_stop_conditional_render(ctx);
545 }
546 
547 void
zink_blit_barriers(struct zink_context * ctx,struct zink_resource * src,struct zink_resource * dst,bool whole_dst)548 zink_blit_barriers(struct zink_context *ctx, struct zink_resource *src, struct zink_resource *dst, bool whole_dst)
549 {
550    struct zink_screen *screen = zink_screen(ctx->base.screen);
551    if (src && zink_is_swapchain(src)) {
552       if (!zink_kopper_acquire(ctx, src, UINT64_MAX))
553          return;
554    } else if (dst && zink_is_swapchain(dst)) {
555       if (!zink_kopper_acquire(ctx, dst, UINT64_MAX))
556          return;
557    }
558 
559    VkAccessFlagBits flags;
560    VkPipelineStageFlagBits pipeline;
561    if (util_format_is_depth_or_stencil(dst->base.b.format)) {
562       flags = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
563       if (!whole_dst)
564          flags |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
565       pipeline = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
566    } else {
567       flags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
568       if (!whole_dst)
569          flags |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
570       pipeline = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
571    }
572    if (src == dst) {
573       VkImageLayout layout = zink_screen(ctx->base.screen)->info.have_EXT_attachment_feedback_loop_layout ?
574                              VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT :
575                              VK_IMAGE_LAYOUT_GENERAL;
576       screen->image_barrier(ctx, src, layout, VK_ACCESS_SHADER_READ_BIT | flags, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | pipeline);
577    } else {
578       if (src) {
579          VkImageLayout layout = util_format_is_depth_or_stencil(src->base.b.format) &&
580                                 src->obj->vkusage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ?
581                                 VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL :
582                                 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
583          screen->image_barrier(ctx, src, layout,
584                               VK_ACCESS_SHADER_READ_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
585          if (!ctx->unordered_blitting)
586             src->obj->unordered_read = false;
587       }
588       VkImageLayout layout = util_format_is_depth_or_stencil(dst->base.b.format) ?
589                            VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL :
590                            VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
591       screen->image_barrier(ctx, dst, layout, flags, pipeline);
592    }
593    if (!ctx->unordered_blitting)
594       dst->obj->unordered_read = dst->obj->unordered_write = false;
595 }
596 
597 bool
zink_blit_region_fills(struct u_rect region,unsigned width,unsigned height)598 zink_blit_region_fills(struct u_rect region, unsigned width, unsigned height)
599 {
600    struct u_rect intersect = {0, width, 0, height};
601    struct u_rect r = {
602       MIN2(region.x0, region.x1),
603       MAX2(region.x0, region.x1),
604       MIN2(region.y0, region.y1),
605       MAX2(region.y0, region.y1),
606    };
607 
608    if (!u_rect_test_intersection(&r, &intersect))
609       /* is this even a thing? */
610       return false;
611 
612    u_rect_find_intersection(&r, &intersect);
613    if (intersect.x0 != 0 || intersect.y0 != 0 ||
614        intersect.x1 != width || intersect.y1 != height)
615       return false;
616 
617    return true;
618 }
619 
620 bool
zink_blit_region_covers(struct u_rect region,struct u_rect covers)621 zink_blit_region_covers(struct u_rect region, struct u_rect covers)
622 {
623    struct u_rect r = {
624       MIN2(region.x0, region.x1),
625       MAX2(region.x0, region.x1),
626       MIN2(region.y0, region.y1),
627       MAX2(region.y0, region.y1),
628    };
629    struct u_rect c = {
630       MIN2(covers.x0, covers.x1),
631       MAX2(covers.x0, covers.x1),
632       MIN2(covers.y0, covers.y1),
633       MAX2(covers.y0, covers.y1),
634    };
635    struct u_rect intersect;
636    if (!u_rect_test_intersection(&r, &c))
637       return false;
638 
639     u_rect_union(&intersect, &r, &c);
640     return intersect.x0 == c.x0 && intersect.y0 == c.y0 &&
641            intersect.x1 == c.x1 && intersect.y1 == c.y1;
642 }
643 
644 void
zink_draw_rectangle(struct blitter_context * blitter,void * vertex_elements_cso,blitter_get_vs_func get_vs,int x1,int y1,int x2,int y2,float depth,unsigned num_instances,enum blitter_attrib_type type,const union blitter_attrib * attrib)645 zink_draw_rectangle(struct blitter_context *blitter, void *vertex_elements_cso,
646                     blitter_get_vs_func get_vs, int x1, int y1, int x2, int y2,
647                     float depth, unsigned num_instances, enum blitter_attrib_type type,
648                     const union blitter_attrib *attrib)
649 {
650    struct zink_context *ctx = zink_context(blitter->pipe);
651 
652    union blitter_attrib new_attrib = *attrib;
653 
654    /* Avoid inconsistencies in rounding between both triangles which can show with
655     * nearest filtering by expanding the rect so only one triangle is effectively drawn.
656     */
657    if (ctx->blit_scissor && ctx->blit_nearest) {
658       int64_t new_x1 = (int64_t)x1 * 2 - x2;
659       int64_t new_y2 = (int64_t)y2 * 2 - y1;
660       if (new_x1 < INT32_MAX && new_x1 > INT32_MIN &&
661           new_y2 < INT32_MAX && new_y2 > INT32_MIN) {
662          x1 = new_x1;
663          y2 = new_y2;
664 
665          if (type == UTIL_BLITTER_ATTRIB_TEXCOORD_XY ||
666              type == UTIL_BLITTER_ATTRIB_TEXCOORD_XYZW) {
667             new_attrib.texcoord.x1 += new_attrib.texcoord.x1 - new_attrib.texcoord.x2;
668             new_attrib.texcoord.y2 += new_attrib.texcoord.y2 - new_attrib.texcoord.y1;
669          }
670       }
671    }
672 
673    util_blitter_draw_rectangle(blitter, vertex_elements_cso, get_vs, x1, y1, x2, y2,
674                                depth, num_instances, type, &new_attrib);
675 }
676