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