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