zink: use general-layout when blitting to/from same resource
[mesa.git] / src / gallium / drivers / zink / zink_blit.c
1 #include "zink_context.h"
2 #include "zink_helpers.h"
3 #include "zink_resource.h"
4 #include "zink_screen.h"
5
6 #include "util/u_blitter.h"
7 #include "util/format/u_format.h"
8
9 static bool
10 blit_resolve(struct zink_context *ctx, const struct pipe_blit_info *info)
11 {
12 if (util_format_get_mask(info->dst.format) != info->mask ||
13 util_format_get_mask(info->src.format) != info->mask ||
14 info->scissor_enable ||
15 info->alpha_blend ||
16 info->render_condition_enable)
17 return false;
18
19 struct zink_resource *src = zink_resource(info->src.resource);
20 struct zink_resource *dst = zink_resource(info->dst.resource);
21
22 struct zink_screen *screen = zink_screen(ctx->base.screen);
23 if (src->format != zink_get_format(screen, info->src.format) ||
24 dst->format != zink_get_format(screen, info->dst.format))
25 return false;
26
27 struct zink_batch *batch = zink_batch_no_rp(ctx);
28
29 zink_batch_reference_resoure(batch, src);
30 zink_batch_reference_resoure(batch, dst);
31
32 if (src->layout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)
33 zink_resource_barrier(batch->cmdbuf, src, src->aspect,
34 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
35
36 if (dst->layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
37 zink_resource_barrier(batch->cmdbuf, dst, dst->aspect,
38 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
39
40 VkImageResolve region = {};
41
42 region.srcSubresource.aspectMask = src->aspect;
43 region.srcSubresource.mipLevel = info->src.level;
44 region.srcSubresource.baseArrayLayer = 0; // no clue
45 region.srcSubresource.layerCount = 1; // no clue
46 region.srcOffset.x = info->src.box.x;
47 region.srcOffset.y = info->src.box.y;
48 region.srcOffset.z = info->src.box.z;
49
50 region.dstSubresource.aspectMask = dst->aspect;
51 region.dstSubresource.mipLevel = info->dst.level;
52 region.dstSubresource.baseArrayLayer = 0; // no clue
53 region.dstSubresource.layerCount = 1; // no clue
54 region.dstOffset.x = info->dst.box.x;
55 region.dstOffset.y = info->dst.box.y;
56 region.dstOffset.z = info->dst.box.z;
57
58 region.extent.width = info->dst.box.width;
59 region.extent.height = info->dst.box.height;
60 region.extent.depth = info->dst.box.depth;
61 vkCmdResolveImage(batch->cmdbuf, src->image, src->layout,
62 dst->image, dst->layout,
63 1, &region);
64
65 return true;
66 }
67
68 static bool
69 blit_native(struct zink_context *ctx, const struct pipe_blit_info *info)
70 {
71 if (util_format_get_mask(info->dst.format) != info->mask ||
72 util_format_get_mask(info->src.format) != info->mask ||
73 info->scissor_enable ||
74 info->alpha_blend ||
75 info->render_condition_enable)
76 return false;
77
78 if (util_format_is_depth_or_stencil(info->dst.format) &&
79 info->dst.format != info->src.format)
80 return false;
81
82 struct zink_resource *src = zink_resource(info->src.resource);
83 struct zink_resource *dst = zink_resource(info->dst.resource);
84
85 struct zink_screen *screen = zink_screen(ctx->base.screen);
86 if (src->format != zink_get_format(screen, info->src.format) ||
87 dst->format != zink_get_format(screen, info->dst.format))
88 return false;
89
90 struct zink_batch *batch = zink_batch_no_rp(ctx);
91 zink_batch_reference_resoure(batch, src);
92 zink_batch_reference_resoure(batch, dst);
93
94 if (src == dst) {
95 /* The Vulkan 1.1 specification says the following about valid usage
96 * of vkCmdBlitImage:
97 *
98 * "srcImageLayout must be VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR,
99 * VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL"
100 *
101 * and:
102 *
103 * "dstImageLayout must be VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR,
104 * VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL"
105 *
106 * Since we cant have the same image in two states at the same time,
107 * we're effectively left with VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR or
108 * VK_IMAGE_LAYOUT_GENERAL. And since this isn't a present-related
109 * operation, VK_IMAGE_LAYOUT_GENERAL seems most appropriate.
110 */
111 if (src->layout != VK_IMAGE_LAYOUT_GENERAL)
112 zink_resource_barrier(batch->cmdbuf, src, src->aspect,
113 VK_IMAGE_LAYOUT_GENERAL);
114 } else {
115 if (src->layout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)
116 zink_resource_barrier(batch->cmdbuf, src, src->aspect,
117 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
118
119 if (dst->layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
120 zink_resource_barrier(batch->cmdbuf, dst, dst->aspect,
121 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
122 }
123
124 VkImageBlit region = {};
125 region.srcSubresource.aspectMask = src->aspect;
126 region.srcSubresource.mipLevel = info->src.level;
127 region.srcOffsets[0].x = info->src.box.x;
128 region.srcOffsets[0].y = info->src.box.y;
129 region.srcOffsets[1].x = info->src.box.x + info->src.box.width;
130 region.srcOffsets[1].y = info->src.box.y + info->src.box.height;
131
132 if (src->base.array_size > 1) {
133 region.srcOffsets[0].z = 0;
134 region.srcOffsets[1].z = 1;
135 region.srcSubresource.baseArrayLayer = info->src.box.z;
136 region.srcSubresource.layerCount = info->src.box.depth;
137 } else {
138 region.srcOffsets[0].z = info->src.box.z;
139 region.srcOffsets[1].z = info->src.box.z + info->src.box.depth;
140 region.srcSubresource.baseArrayLayer = 0;
141 region.srcSubresource.layerCount = 1;
142 }
143
144 region.dstSubresource.aspectMask = dst->aspect;
145 region.dstSubresource.mipLevel = info->dst.level;
146 region.dstOffsets[0].x = info->dst.box.x;
147 region.dstOffsets[0].y = info->dst.box.y;
148 region.dstOffsets[1].x = info->dst.box.x + info->dst.box.width;
149 region.dstOffsets[1].y = info->dst.box.y + info->dst.box.height;
150
151 if (dst->base.array_size > 1) {
152 region.dstOffsets[0].z = 0;
153 region.dstOffsets[1].z = 1;
154 region.dstSubresource.baseArrayLayer = info->dst.box.z;
155 region.dstSubresource.layerCount = info->dst.box.depth;
156 } else {
157 region.dstOffsets[0].z = info->dst.box.z;
158 region.dstOffsets[1].z = info->dst.box.z + info->dst.box.depth;
159 region.dstSubresource.baseArrayLayer = 0;
160 region.dstSubresource.layerCount = 1;
161 }
162
163 vkCmdBlitImage(batch->cmdbuf, src->image, src->layout,
164 dst->image, dst->layout,
165 1, &region,
166 zink_filter(info->filter));
167
168 return true;
169 }
170
171 void
172 zink_blit(struct pipe_context *pctx,
173 const struct pipe_blit_info *info)
174 {
175 struct zink_context *ctx = zink_context(pctx);
176 if (info->src.resource->nr_samples > 1 &&
177 info->dst.resource->nr_samples <= 1) {
178 if (blit_resolve(ctx, info))
179 return;
180 } else {
181 if (blit_native(ctx, info))
182 return;
183 }
184
185 if (!util_blitter_is_blit_supported(ctx->blitter, info)) {
186 debug_printf("blit unsupported %s -> %s\n",
187 util_format_short_name(info->src.resource->format),
188 util_format_short_name(info->dst.resource->format));
189 return;
190 }
191
192 util_blitter_save_blend(ctx->blitter, ctx->gfx_pipeline_state.blend_state);
193 util_blitter_save_depth_stencil_alpha(ctx->blitter, ctx->gfx_pipeline_state.depth_stencil_alpha_state);
194 util_blitter_save_vertex_elements(ctx->blitter, ctx->element_state);
195 util_blitter_save_stencil_ref(ctx->blitter, &ctx->stencil_ref);
196 util_blitter_save_rasterizer(ctx->blitter, ctx->rast_state);
197 util_blitter_save_fragment_shader(ctx->blitter, ctx->gfx_stages[PIPE_SHADER_FRAGMENT]);
198 util_blitter_save_vertex_shader(ctx->blitter, ctx->gfx_stages[PIPE_SHADER_VERTEX]);
199 util_blitter_save_framebuffer(ctx->blitter, &ctx->fb_state);
200 util_blitter_save_viewport(ctx->blitter, ctx->viewport_states);
201 util_blitter_save_scissor(ctx->blitter, ctx->scissor_states);
202 util_blitter_save_fragment_sampler_states(ctx->blitter,
203 ctx->num_samplers[PIPE_SHADER_FRAGMENT],
204 ctx->sampler_states[PIPE_SHADER_FRAGMENT]);
205 util_blitter_save_fragment_sampler_views(ctx->blitter,
206 ctx->num_image_views[PIPE_SHADER_FRAGMENT],
207 ctx->image_views[PIPE_SHADER_FRAGMENT]);
208 util_blitter_save_fragment_constant_buffer_slot(ctx->blitter, ctx->ubos[PIPE_SHADER_FRAGMENT]);
209 util_blitter_save_vertex_buffer_slot(ctx->blitter, ctx->buffers);
210 util_blitter_save_sample_mask(ctx->blitter, ctx->gfx_pipeline_state.sample_mask);
211
212 util_blitter_blit(ctx->blitter, info);
213 }