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