70dcc30bee637cb191415a7a6d8913ab200f48c9
[mesa.git] / src / amd / vulkan / radv_meta_resolve.c
1 /*
2 * Copyright © 2016 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 #include <assert.h>
25 #include <stdbool.h>
26
27 #include "radv_meta.h"
28 #include "radv_private.h"
29 #include "nir/nir_builder.h"
30 #include "sid.h"
31
32 /* vertex shader that generates vertex data */
33 static nir_shader *
34 build_nir_vs(void)
35 {
36 const struct glsl_type *vec4 = glsl_vec4_type();
37
38 nir_builder b;
39 nir_variable *v_position;
40
41 nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_VERTEX, NULL);
42 b.shader->info->name = ralloc_strdup(b.shader, "meta_resolve_vs");
43
44 nir_ssa_def *outvec = radv_meta_gen_rect_vertices(&b);
45
46 v_position = nir_variable_create(b.shader, nir_var_shader_out, vec4,
47 "gl_Position");
48 v_position->data.location = VARYING_SLOT_POS;
49
50
51 nir_store_var(&b, v_position, outvec, 0xf);
52
53 return b.shader;
54 }
55
56 /* simple passthrough shader */
57 static nir_shader *
58 build_nir_fs(void)
59 {
60 const struct glsl_type *vec4 = glsl_vec4_type();
61 nir_builder b;
62 nir_variable *f_color; /* vec4, fragment output color */
63
64 nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_FRAGMENT, NULL);
65 b.shader->info->name = ralloc_asprintf(b.shader,
66 "meta_resolve_fs");
67
68 f_color = nir_variable_create(b.shader, nir_var_shader_out, vec4,
69 "f_color");
70 f_color->data.location = FRAG_RESULT_DATA0;
71 nir_store_var(&b, f_color, nir_imm_vec4(&b, 0.0, 0.0, 0.0, 1.0), 0xf);
72
73 return b.shader;
74 }
75
76 static VkResult
77 create_pass(struct radv_device *device)
78 {
79 VkResult result;
80 VkDevice device_h = radv_device_to_handle(device);
81 const VkAllocationCallbacks *alloc = &device->meta_state.alloc;
82 VkAttachmentDescription attachments[2];
83 int i;
84
85 for (i = 0; i < 2; i++) {
86 attachments[i].format = VK_FORMAT_UNDEFINED;
87 attachments[i].samples = 1;
88 attachments[i].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
89 attachments[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
90 }
91 attachments[0].initialLayout = VK_IMAGE_LAYOUT_GENERAL;
92 attachments[0].finalLayout = VK_IMAGE_LAYOUT_GENERAL;
93 attachments[1].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
94 attachments[1].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
95
96 result = radv_CreateRenderPass(device_h,
97 &(VkRenderPassCreateInfo) {
98 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
99 .attachmentCount = 2,
100 .pAttachments = attachments,
101 .subpassCount = 1,
102 .pSubpasses = &(VkSubpassDescription) {
103 .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
104 .inputAttachmentCount = 0,
105 .colorAttachmentCount = 2,
106 .pColorAttachments = (VkAttachmentReference[]) {
107 {
108 .attachment = 0,
109 .layout = VK_IMAGE_LAYOUT_GENERAL,
110 },
111 {
112 .attachment = 1,
113 .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
114 },
115 },
116 .pResolveAttachments = NULL,
117 .pDepthStencilAttachment = &(VkAttachmentReference) {
118 .attachment = VK_ATTACHMENT_UNUSED,
119 },
120 .preserveAttachmentCount = 0,
121 .pPreserveAttachments = NULL,
122 },
123 .dependencyCount = 0,
124 },
125 alloc,
126 &device->meta_state.resolve.pass);
127
128 return result;
129 }
130
131 static VkResult
132 create_pipeline(struct radv_device *device,
133 VkShaderModule vs_module_h)
134 {
135 VkResult result;
136 VkDevice device_h = radv_device_to_handle(device);
137
138 struct radv_shader_module fs_module = {
139 .nir = build_nir_fs(),
140 };
141
142 if (!fs_module.nir) {
143 /* XXX: Need more accurate error */
144 result = VK_ERROR_OUT_OF_HOST_MEMORY;
145 goto cleanup;
146 }
147
148 result = radv_graphics_pipeline_create(device_h,
149 radv_pipeline_cache_to_handle(&device->meta_state.cache),
150 &(VkGraphicsPipelineCreateInfo) {
151 .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
152 .stageCount = 2,
153 .pStages = (VkPipelineShaderStageCreateInfo[]) {
154 {
155 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
156 .stage = VK_SHADER_STAGE_VERTEX_BIT,
157 .module = vs_module_h,
158 .pName = "main",
159 },
160 {
161 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
162 .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
163 .module = radv_shader_module_to_handle(&fs_module),
164 .pName = "main",
165 },
166 },
167 .pVertexInputState = &(VkPipelineVertexInputStateCreateInfo) {
168 .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
169 .vertexBindingDescriptionCount = 0,
170 .vertexAttributeDescriptionCount = 0,
171 },
172 .pInputAssemblyState = &(VkPipelineInputAssemblyStateCreateInfo) {
173 .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
174 .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
175 .primitiveRestartEnable = false,
176 },
177 .pViewportState = &(VkPipelineViewportStateCreateInfo) {
178 .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
179 .viewportCount = 1,
180 .scissorCount = 1,
181 },
182 .pRasterizationState = &(VkPipelineRasterizationStateCreateInfo) {
183 .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
184 .depthClampEnable = false,
185 .rasterizerDiscardEnable = false,
186 .polygonMode = VK_POLYGON_MODE_FILL,
187 .cullMode = VK_CULL_MODE_NONE,
188 .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,
189 },
190 .pMultisampleState = &(VkPipelineMultisampleStateCreateInfo) {
191 .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
192 .rasterizationSamples = 1,
193 .sampleShadingEnable = false,
194 .pSampleMask = NULL,
195 .alphaToCoverageEnable = false,
196 .alphaToOneEnable = false,
197 },
198 .pColorBlendState = &(VkPipelineColorBlendStateCreateInfo) {
199 .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
200 .logicOpEnable = false,
201 .attachmentCount = 2,
202 .pAttachments = (VkPipelineColorBlendAttachmentState []) {
203 {
204 .colorWriteMask = VK_COLOR_COMPONENT_R_BIT |
205 VK_COLOR_COMPONENT_G_BIT |
206 VK_COLOR_COMPONENT_B_BIT |
207 VK_COLOR_COMPONENT_A_BIT,
208 },
209 {
210 .colorWriteMask = 0,
211
212 }
213 },
214 },
215 .pDynamicState = &(VkPipelineDynamicStateCreateInfo) {
216 .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
217 .dynamicStateCount = 2,
218 .pDynamicStates = (VkDynamicState[]) {
219 VK_DYNAMIC_STATE_VIEWPORT,
220 VK_DYNAMIC_STATE_SCISSOR,
221 },
222 },
223 .renderPass = device->meta_state.resolve.pass,
224 .subpass = 0,
225 },
226 &(struct radv_graphics_pipeline_create_info) {
227 .use_rectlist = true,
228 .custom_blend_mode = V_028808_CB_RESOLVE,
229 },
230 &device->meta_state.alloc,
231 &device->meta_state.resolve.pipeline);
232 if (result != VK_SUCCESS)
233 goto cleanup;
234
235 goto cleanup;
236
237 cleanup:
238 ralloc_free(fs_module.nir);
239 return result;
240 }
241
242 void
243 radv_device_finish_meta_resolve_state(struct radv_device *device)
244 {
245 struct radv_meta_state *state = &device->meta_state;
246 VkDevice device_h = radv_device_to_handle(device);
247 VkRenderPass pass_h = device->meta_state.resolve.pass;
248 const VkAllocationCallbacks *alloc = &device->meta_state.alloc;
249
250 if (pass_h)
251 radv_DestroyRenderPass(device_h, pass_h,
252 &device->meta_state.alloc);
253
254 VkPipeline pipeline_h = state->resolve.pipeline;
255 if (pipeline_h) {
256 radv_DestroyPipeline(device_h, pipeline_h, alloc);
257 }
258 }
259
260 VkResult
261 radv_device_init_meta_resolve_state(struct radv_device *device)
262 {
263 VkResult res = VK_SUCCESS;
264
265 zero(device->meta_state.resolve);
266
267 struct radv_shader_module vs_module = { .nir = build_nir_vs() };
268 if (!vs_module.nir) {
269 /* XXX: Need more accurate error */
270 res = VK_ERROR_OUT_OF_HOST_MEMORY;
271 goto fail;
272 }
273
274 res = create_pass(device);
275 if (res != VK_SUCCESS)
276 goto fail;
277
278 VkShaderModule vs_module_h = radv_shader_module_to_handle(&vs_module);
279 res = create_pipeline(device, vs_module_h);
280 if (res != VK_SUCCESS)
281 goto fail;
282
283 goto cleanup;
284
285 fail:
286 radv_device_finish_meta_resolve_state(device);
287
288 cleanup:
289 ralloc_free(vs_module.nir);
290
291 return res;
292 }
293
294 static void
295 emit_resolve(struct radv_cmd_buffer *cmd_buffer,
296 const VkOffset2D *dest_offset,
297 const VkExtent2D *resolve_extent)
298 {
299 struct radv_device *device = cmd_buffer->device;
300 VkCommandBuffer cmd_buffer_h = radv_cmd_buffer_to_handle(cmd_buffer);
301
302 cmd_buffer->state.flush_bits |= RADV_CMD_FLAG_FLUSH_AND_INV_CB;
303
304 VkPipeline pipeline_h = device->meta_state.resolve.pipeline;
305 RADV_FROM_HANDLE(radv_pipeline, pipeline, pipeline_h);
306
307 if (cmd_buffer->state.pipeline != pipeline) {
308 radv_CmdBindPipeline(cmd_buffer_h, VK_PIPELINE_BIND_POINT_GRAPHICS,
309 pipeline_h);
310 }
311
312 radv_CmdSetViewport(radv_cmd_buffer_to_handle(cmd_buffer), 0, 1, &(VkViewport) {
313 .x = dest_offset->x,
314 .y = dest_offset->y,
315 .width = resolve_extent->width,
316 .height = resolve_extent->height,
317 .minDepth = 0.0f,
318 .maxDepth = 1.0f
319 });
320
321 radv_CmdSetScissor(radv_cmd_buffer_to_handle(cmd_buffer), 0, 1, &(VkRect2D) {
322 .offset = *dest_offset,
323 .extent = *resolve_extent,
324 });
325
326 radv_CmdDraw(cmd_buffer_h, 3, 1, 0, 0);
327 cmd_buffer->state.flush_bits |= RADV_CMD_FLAG_FLUSH_AND_INV_CB;
328 }
329
330 void radv_CmdResolveImage(
331 VkCommandBuffer cmd_buffer_h,
332 VkImage src_image_h,
333 VkImageLayout src_image_layout,
334 VkImage dest_image_h,
335 VkImageLayout dest_image_layout,
336 uint32_t region_count,
337 const VkImageResolve* regions)
338 {
339 RADV_FROM_HANDLE(radv_cmd_buffer, cmd_buffer, cmd_buffer_h);
340 RADV_FROM_HANDLE(radv_image, src_image, src_image_h);
341 RADV_FROM_HANDLE(radv_image, dest_image, dest_image_h);
342 struct radv_device *device = cmd_buffer->device;
343 struct radv_meta_saved_state saved_state;
344 VkDevice device_h = radv_device_to_handle(device);
345 bool use_compute_resolve = false;
346
347 /* we can use the hw resolve only for single full resolves */
348 if (region_count == 1) {
349 if (regions[0].srcOffset.x ||
350 regions[0].srcOffset.y ||
351 regions[0].srcOffset.z)
352 use_compute_resolve = true;
353 if (regions[0].dstOffset.x ||
354 regions[0].dstOffset.y ||
355 regions[0].dstOffset.z)
356 use_compute_resolve = true;
357
358 if (regions[0].extent.width != src_image->extent.width ||
359 regions[0].extent.height != src_image->extent.height ||
360 regions[0].extent.depth != src_image->extent.depth)
361 use_compute_resolve = true;
362 } else
363 use_compute_resolve = true;
364
365 if (use_compute_resolve) {
366
367 radv_meta_resolve_compute_image(cmd_buffer,
368 src_image,
369 src_image_layout,
370 dest_image,
371 dest_image_layout,
372 region_count, regions);
373 return;
374 }
375
376 radv_meta_save_graphics_reset_vport_scissor_novertex(&saved_state, cmd_buffer);
377
378 assert(src_image->samples > 1);
379 assert(dest_image->samples == 1);
380
381 if (src_image->samples >= 16) {
382 /* See commit aa3f9aaf31e9056a255f9e0472ebdfdaa60abe54 for the
383 * glBlitFramebuffer workaround for samples >= 16.
384 */
385 radv_finishme("vkCmdResolveImage: need interpolation workaround when "
386 "samples >= 16");
387 }
388
389 if (src_image->array_size > 1)
390 radv_finishme("vkCmdResolveImage: multisample array images");
391
392 if (dest_image->surface.dcc_size) {
393 radv_initialize_dcc(cmd_buffer, dest_image, 0xffffffff);
394 }
395 for (uint32_t r = 0; r < region_count; ++r) {
396 const VkImageResolve *region = &regions[r];
397
398 /* From the Vulkan 1.0 spec:
399 *
400 * - The aspectMask member of srcSubresource and dstSubresource must
401 * only contain VK_IMAGE_ASPECT_COLOR_BIT
402 *
403 * - The layerCount member of srcSubresource and dstSubresource must
404 * match
405 */
406 assert(region->srcSubresource.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT);
407 assert(region->dstSubresource.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT);
408 assert(region->srcSubresource.layerCount ==
409 region->dstSubresource.layerCount);
410
411 const uint32_t src_base_layer =
412 radv_meta_get_iview_layer(src_image, &region->srcSubresource,
413 &region->srcOffset);
414
415 const uint32_t dest_base_layer =
416 radv_meta_get_iview_layer(dest_image, &region->dstSubresource,
417 &region->dstOffset);
418
419 /**
420 * From Vulkan 1.0.6 spec: 18.6 Resolving Multisample Images
421 *
422 * extent is the size in texels of the source image to resolve in width,
423 * height and depth. 1D images use only x and width. 2D images use x, y,
424 * width and height. 3D images use x, y, z, width, height and depth.
425 *
426 * srcOffset and dstOffset select the initial x, y, and z offsets in
427 * texels of the sub-regions of the source and destination image data.
428 * extent is the size in texels of the source image to resolve in width,
429 * height and depth. 1D images use only x and width. 2D images use x, y,
430 * width and height. 3D images use x, y, z, width, height and depth.
431 */
432 const struct VkExtent3D extent =
433 radv_sanitize_image_extent(src_image->type, region->extent);
434 const struct VkOffset3D dstOffset =
435 radv_sanitize_image_offset(dest_image->type, region->dstOffset);
436
437
438 for (uint32_t layer = 0; layer < region->srcSubresource.layerCount;
439 ++layer) {
440
441 struct radv_image_view src_iview;
442 radv_image_view_init(&src_iview, cmd_buffer->device,
443 &(VkImageViewCreateInfo) {
444 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
445 .image = src_image_h,
446 .viewType = radv_meta_get_view_type(src_image),
447 .format = src_image->vk_format,
448 .subresourceRange = {
449 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
450 .baseMipLevel = region->srcSubresource.mipLevel,
451 .levelCount = 1,
452 .baseArrayLayer = src_base_layer + layer,
453 .layerCount = 1,
454 },
455 },
456 cmd_buffer, VK_IMAGE_USAGE_SAMPLED_BIT);
457
458 struct radv_image_view dest_iview;
459 radv_image_view_init(&dest_iview, cmd_buffer->device,
460 &(VkImageViewCreateInfo) {
461 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
462 .image = dest_image_h,
463 .viewType = radv_meta_get_view_type(dest_image),
464 .format = dest_image->vk_format,
465 .subresourceRange = {
466 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
467 .baseMipLevel = region->dstSubresource.mipLevel,
468 .levelCount = 1,
469 .baseArrayLayer = dest_base_layer + layer,
470 .layerCount = 1,
471 },
472 },
473 cmd_buffer, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
474
475 VkFramebuffer fb_h;
476 radv_CreateFramebuffer(device_h,
477 &(VkFramebufferCreateInfo) {
478 .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
479 .attachmentCount = 2,
480 .pAttachments = (VkImageView[]) {
481 radv_image_view_to_handle(&src_iview),
482 radv_image_view_to_handle(&dest_iview),
483 },
484 .width = radv_minify(dest_image->extent.width,
485 region->dstSubresource.mipLevel),
486 .height = radv_minify(dest_image->extent.height,
487 region->dstSubresource.mipLevel),
488 .layers = 1
489 },
490 &cmd_buffer->pool->alloc,
491 &fb_h);
492
493 radv_CmdBeginRenderPass(cmd_buffer_h,
494 &(VkRenderPassBeginInfo) {
495 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
496 .renderPass = device->meta_state.resolve.pass,
497 .framebuffer = fb_h,
498 .renderArea = {
499 .offset = {
500 dstOffset.x,
501 dstOffset.y,
502 },
503 .extent = {
504 extent.width,
505 extent.height,
506 }
507 },
508 .clearValueCount = 0,
509 .pClearValues = NULL,
510 },
511 VK_SUBPASS_CONTENTS_INLINE);
512
513 emit_resolve(cmd_buffer,
514 &(VkOffset2D) {
515 .x = dstOffset.x,
516 .y = dstOffset.y,
517 },
518 &(VkExtent2D) {
519 .width = extent.width,
520 .height = extent.height,
521 });
522
523 radv_CmdEndRenderPass(cmd_buffer_h);
524
525 radv_DestroyFramebuffer(device_h, fb_h,
526 &cmd_buffer->pool->alloc);
527 }
528 }
529
530 radv_meta_restore(&saved_state, cmd_buffer);
531 }
532
533 /**
534 * Emit any needed resolves for the current subpass.
535 */
536 void
537 radv_cmd_buffer_resolve_subpass(struct radv_cmd_buffer *cmd_buffer)
538 {
539 struct radv_framebuffer *fb = cmd_buffer->state.framebuffer;
540 const struct radv_subpass *subpass = cmd_buffer->state.subpass;
541 struct radv_meta_saved_state saved_state;
542
543 /* FINISHME(perf): Skip clears for resolve attachments.
544 *
545 * From the Vulkan 1.0 spec:
546 *
547 * If the first use of an attachment in a render pass is as a resolve
548 * attachment, then the loadOp is effectively ignored as the resolve is
549 * guaranteed to overwrite all pixels in the render area.
550 */
551
552 if (!subpass->has_resolve)
553 return;
554
555 radv_meta_save_graphics_reset_vport_scissor(&saved_state, cmd_buffer);
556
557 for (uint32_t i = 0; i < subpass->color_count; ++i) {
558 VkAttachmentReference src_att = subpass->color_attachments[i];
559 VkAttachmentReference dest_att = subpass->resolve_attachments[i];
560 struct radv_image *dst_img = cmd_buffer->state.framebuffer->attachments[dest_att.attachment].attachment->image;
561 if (dest_att.attachment == VK_ATTACHMENT_UNUSED)
562 continue;
563
564 if (dst_img->surface.dcc_size) {
565 radv_initialize_dcc(cmd_buffer, dst_img, 0xffffffff);
566 cmd_buffer->state.attachments[dest_att.attachment].current_layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
567 }
568
569 struct radv_subpass resolve_subpass = {
570 .color_count = 2,
571 .color_attachments = (VkAttachmentReference[]) { src_att, dest_att },
572 .depth_stencil_attachment = { .attachment = VK_ATTACHMENT_UNUSED },
573 };
574
575 radv_cmd_buffer_set_subpass(cmd_buffer, &resolve_subpass, false);
576
577 /* Subpass resolves must respect the render area. We can ignore the
578 * render area here because vkCmdBeginRenderPass set the render area
579 * with 3DSTATE_DRAWING_RECTANGLE.
580 *
581 * XXX(chadv): Does the hardware really respect
582 * 3DSTATE_DRAWING_RECTANGLE when draing a 3DPRIM_RECTLIST?
583 */
584 emit_resolve(cmd_buffer,
585 &(VkOffset2D) { 0, 0 },
586 &(VkExtent2D) { fb->width, fb->height });
587 }
588
589 cmd_buffer->state.subpass = subpass;
590 radv_meta_restore(&saved_state, cmd_buffer);
591 }