• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
13 static void
apply_dst_clears(struct zink_context * ctx,const struct pipe_blit_info * info,bool discard_only)14 apply_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 
24 static bool
blit_resolve(struct zink_context * ctx,const struct pipe_blit_info * info,bool * needs_present_readback)25 blit_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, &region);
111 
112    return true;
113 }
114 
115 static VkFormatFeatureFlags
get_resource_features(struct zink_screen * screen,struct zink_resource * res)116 get_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 
123 static bool
blit_native(struct zink_context * ctx,const struct pipe_blit_info * info,bool * needs_present_readback)124 blit_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, &region,
260                   zink_filter(info->filter));
261 
262    return true;
263 }
264 
265 static bool
try_copy_region(struct pipe_context * pctx,const struct pipe_blit_info * info)266 try_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 
284 void
zink_blit(struct pipe_context * pctx,const struct pipe_blit_info * info)285 zink_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    }
380 end:
381    if (needs_present_readback)
382       zink_kopper_present_readback(ctx, src);
383 }
384 
385 /* similar to radeonsi */
386 void
zink_blit_begin(struct zink_context * ctx,enum zink_blit_flags flags)387 zink_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 
429 bool
zink_blit_region_fills(struct u_rect region,unsigned width,unsigned height)430 zink_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 
452 bool
zink_blit_region_covers(struct u_rect region,struct u_rect covers)453 zink_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