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 attributes used by all pipelines. 33 */ 34struct vertex_attrs { 35 float position[2]; /**< 3DPRIM_RECTLIST */ 36}; 37 38/* passthrough vertex shader */ 39static nir_shader * 40build_nir_vs(void) 41{ 42 const struct glsl_type *vec4 = glsl_vec4_type(); 43 44 nir_builder b; 45 nir_variable *a_position; 46 nir_variable *v_position; 47 48 nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_VERTEX, NULL); 49 b.shader->info->name = ralloc_strdup(b.shader, "meta_resolve_vs"); 50 51 a_position = nir_variable_create(b.shader, nir_var_shader_in, vec4, 52 "a_position"); 53 a_position->data.location = VERT_ATTRIB_GENERIC0; 54 55 v_position = nir_variable_create(b.shader, nir_var_shader_out, vec4, 56 "gl_Position"); 57 v_position->data.location = VARYING_SLOT_POS; 58 59 nir_copy_var(&b, v_position, a_position); 60 61 return b.shader; 62} 63 64/* simple passthrough shader */ 65static nir_shader * 66build_nir_fs(void) 67{ 68 const struct glsl_type *vec4 = glsl_vec4_type(); 69 nir_builder b; 70 nir_variable *f_color; /* vec4, fragment output color */ 71 72 nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_FRAGMENT, NULL); 73 b.shader->info->name = ralloc_asprintf(b.shader, 74 "meta_resolve_fs"); 75 76 f_color = nir_variable_create(b.shader, nir_var_shader_out, vec4, 77 "f_color"); 78 f_color->data.location = FRAG_RESULT_DATA0; 79 nir_store_var(&b, f_color, nir_imm_vec4(&b, 0.0, 0.0, 0.0, 1.0), 0xf); 80 81 return b.shader; 82} 83 84static VkResult 85create_pass(struct radv_device *device) 86{ 87 VkResult result; 88 VkDevice device_h = radv_device_to_handle(device); 89 const VkAllocationCallbacks *alloc = &device->meta_state.alloc; 90 VkAttachmentDescription attachments[2]; 91 int i; 92 93 for (i = 0; i < 2; i++) { 94 attachments[i].format = VK_FORMAT_UNDEFINED; 95 attachments[i].samples = 1; 96 attachments[i].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; 97 attachments[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE; 98 attachments[i].initialLayout = VK_IMAGE_LAYOUT_GENERAL; 99 attachments[i].finalLayout = VK_IMAGE_LAYOUT_GENERAL; 100 } 101 102 result = radv_CreateRenderPass(device_h, 103 &(VkRenderPassCreateInfo) { 104 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, 105 .attachmentCount = 2, 106 .pAttachments = attachments, 107 .subpassCount = 1, 108 .pSubpasses = &(VkSubpassDescription) { 109 .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, 110 .inputAttachmentCount = 0, 111 .colorAttachmentCount = 2, 112 .pColorAttachments = (VkAttachmentReference[]) { 113 { 114 .attachment = 0, 115 .layout = VK_IMAGE_LAYOUT_GENERAL, 116 }, 117 { 118 .attachment = 1, 119 .layout = VK_IMAGE_LAYOUT_GENERAL, 120 }, 121 }, 122 .pResolveAttachments = NULL, 123 .pDepthStencilAttachment = &(VkAttachmentReference) { 124 .attachment = VK_ATTACHMENT_UNUSED, 125 }, 126 .preserveAttachmentCount = 0, 127 .pPreserveAttachments = NULL, 128 }, 129 .dependencyCount = 0, 130 }, 131 alloc, 132 &device->meta_state.resolve.pass); 133 134 return result; 135} 136 137static VkResult 138create_pipeline(struct radv_device *device, 139 VkShaderModule vs_module_h) 140{ 141 VkResult result; 142 VkDevice device_h = radv_device_to_handle(device); 143 144 struct radv_shader_module fs_module = { 145 .nir = build_nir_fs(), 146 }; 147 148 if (!fs_module.nir) { 149 /* XXX: Need more accurate error */ 150 result = VK_ERROR_OUT_OF_HOST_MEMORY; 151 goto cleanup; 152 } 153 154 result = radv_graphics_pipeline_create(device_h, 155 radv_pipeline_cache_to_handle(&device->meta_state.cache), 156 &(VkGraphicsPipelineCreateInfo) { 157 .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, 158 .stageCount = 2, 159 .pStages = (VkPipelineShaderStageCreateInfo[]) { 160 { 161 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, 162 .stage = VK_SHADER_STAGE_VERTEX_BIT, 163 .module = vs_module_h, 164 .pName = "main", 165 }, 166 { 167 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, 168 .stage = VK_SHADER_STAGE_FRAGMENT_BIT, 169 .module = radv_shader_module_to_handle(&fs_module), 170 .pName = "main", 171 }, 172 }, 173 .pVertexInputState = &(VkPipelineVertexInputStateCreateInfo) { 174 .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, 175 .vertexBindingDescriptionCount = 1, 176 .pVertexBindingDescriptions = (VkVertexInputBindingDescription[]) { 177 { 178 .binding = 0, 179 .stride = sizeof(struct vertex_attrs), 180 .inputRate = VK_VERTEX_INPUT_RATE_VERTEX 181 }, 182 }, 183 .vertexAttributeDescriptionCount = 1, 184 .pVertexAttributeDescriptions = (VkVertexInputAttributeDescription[]) { 185 { 186 /* Position */ 187 .location = 0, 188 .binding = 0, 189 .format = VK_FORMAT_R32G32_SFLOAT, 190 .offset = offsetof(struct vertex_attrs, position), 191 }, 192 }, 193 }, 194 .pInputAssemblyState = &(VkPipelineInputAssemblyStateCreateInfo) { 195 .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, 196 .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 197 .primitiveRestartEnable = false, 198 }, 199 .pViewportState = &(VkPipelineViewportStateCreateInfo) { 200 .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, 201 .viewportCount = 0, 202 .scissorCount = 0, 203 }, 204 .pRasterizationState = &(VkPipelineRasterizationStateCreateInfo) { 205 .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, 206 .depthClampEnable = false, 207 .rasterizerDiscardEnable = false, 208 .polygonMode = VK_POLYGON_MODE_FILL, 209 .cullMode = VK_CULL_MODE_NONE, 210 .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE, 211 }, 212 .pMultisampleState = &(VkPipelineMultisampleStateCreateInfo) { 213 .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, 214 .rasterizationSamples = 1, 215 .sampleShadingEnable = false, 216 .pSampleMask = NULL, 217 .alphaToCoverageEnable = false, 218 .alphaToOneEnable = false, 219 }, 220 .pColorBlendState = &(VkPipelineColorBlendStateCreateInfo) { 221 .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, 222 .logicOpEnable = false, 223 .attachmentCount = 2, 224 .pAttachments = (VkPipelineColorBlendAttachmentState []) { 225 { 226 .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | 227 VK_COLOR_COMPONENT_G_BIT | 228 VK_COLOR_COMPONENT_B_BIT | 229 VK_COLOR_COMPONENT_A_BIT, 230 }, 231 { 232 .colorWriteMask = 0, 233 234 } 235 }, 236 }, 237 .pDynamicState = NULL, 238 .renderPass = device->meta_state.resolve.pass, 239 .subpass = 0, 240 }, 241 &(struct radv_graphics_pipeline_create_info) { 242 .use_rectlist = true, 243 .custom_blend_mode = V_028808_CB_RESOLVE, 244 }, 245 &device->meta_state.alloc, 246 &device->meta_state.resolve.pipeline); 247 if (result != VK_SUCCESS) 248 goto cleanup; 249 250 goto cleanup; 251 252cleanup: 253 ralloc_free(fs_module.nir); 254 return result; 255} 256 257void 258radv_device_finish_meta_resolve_state(struct radv_device *device) 259{ 260 struct radv_meta_state *state = &device->meta_state; 261 VkDevice device_h = radv_device_to_handle(device); 262 VkRenderPass pass_h = device->meta_state.resolve.pass; 263 const VkAllocationCallbacks *alloc = &device->meta_state.alloc; 264 265 if (pass_h) 266 radv_DestroyRenderPass(device_h, pass_h, 267 &device->meta_state.alloc); 268 269 VkPipeline pipeline_h = state->resolve.pipeline; 270 if (pipeline_h) { 271 radv_DestroyPipeline(device_h, pipeline_h, alloc); 272 } 273} 274 275VkResult 276radv_device_init_meta_resolve_state(struct radv_device *device) 277{ 278 VkResult res = VK_SUCCESS; 279 280 zero(device->meta_state.resolve); 281 282 struct radv_shader_module vs_module = { .nir = build_nir_vs() }; 283 if (!vs_module.nir) { 284 /* XXX: Need more accurate error */ 285 res = VK_ERROR_OUT_OF_HOST_MEMORY; 286 goto fail; 287 } 288 289 res = create_pass(device); 290 if (res != VK_SUCCESS) 291 goto fail; 292 293 VkShaderModule vs_module_h = radv_shader_module_to_handle(&vs_module); 294 res = create_pipeline(device, vs_module_h); 295 if (res != VK_SUCCESS) 296 goto fail; 297 298 goto cleanup; 299 300fail: 301 radv_device_finish_meta_resolve_state(device); 302 303cleanup: 304 ralloc_free(vs_module.nir); 305 306 return res; 307} 308 309static void 310emit_resolve(struct radv_cmd_buffer *cmd_buffer, 311 const VkOffset2D *dest_offset, 312 const VkExtent2D *resolve_extent) 313{ 314 struct radv_device *device = cmd_buffer->device; 315 VkCommandBuffer cmd_buffer_h = radv_cmd_buffer_to_handle(cmd_buffer); 316 uint32_t offset; 317 const struct vertex_attrs vertex_data[3] = { 318 { 319 .position = { 320 dest_offset->x, 321 dest_offset->y, 322 }, 323 }, 324 { 325 .position = { 326 dest_offset->x, 327 dest_offset->y + resolve_extent->height, 328 }, 329 }, 330 { 331 .position = { 332 dest_offset->x + resolve_extent->width, 333 dest_offset->y, 334 }, 335 }, 336 }; 337 338 cmd_buffer->state.flush_bits |= RADV_CMD_FLAG_FLUSH_AND_INV_CB; 339 radv_cmd_buffer_upload_data(cmd_buffer, sizeof(vertex_data), 16, vertex_data, &offset); 340 struct radv_buffer vertex_buffer = { 341 .device = device, 342 .size = sizeof(vertex_data), 343 .bo = cmd_buffer->upload.upload_bo, 344 .offset = offset, 345 }; 346 347 VkBuffer vertex_buffer_h = radv_buffer_to_handle(&vertex_buffer); 348 349 radv_CmdBindVertexBuffers(cmd_buffer_h, 350 /*firstBinding*/ 0, 351 /*bindingCount*/ 1, 352 (VkBuffer[]) { vertex_buffer_h }, 353 (VkDeviceSize[]) { 0 }); 354 355 VkPipeline pipeline_h = device->meta_state.resolve.pipeline; 356 RADV_FROM_HANDLE(radv_pipeline, pipeline, pipeline_h); 357 358 if (cmd_buffer->state.pipeline != pipeline) { 359 radv_CmdBindPipeline(cmd_buffer_h, VK_PIPELINE_BIND_POINT_GRAPHICS, 360 pipeline_h); 361 } 362 363 radv_CmdDraw(cmd_buffer_h, 3, 1, 0, 0); 364 cmd_buffer->state.flush_bits |= RADV_CMD_FLAG_FLUSH_AND_INV_CB; 365 si_emit_cache_flush(cmd_buffer); 366} 367 368void radv_CmdResolveImage( 369 VkCommandBuffer cmd_buffer_h, 370 VkImage src_image_h, 371 VkImageLayout src_image_layout, 372 VkImage dest_image_h, 373 VkImageLayout dest_image_layout, 374 uint32_t region_count, 375 const VkImageResolve* regions) 376{ 377 RADV_FROM_HANDLE(radv_cmd_buffer, cmd_buffer, cmd_buffer_h); 378 RADV_FROM_HANDLE(radv_image, src_image, src_image_h); 379 RADV_FROM_HANDLE(radv_image, dest_image, dest_image_h); 380 struct radv_device *device = cmd_buffer->device; 381 struct radv_meta_saved_state saved_state; 382 VkDevice device_h = radv_device_to_handle(device); 383 bool use_compute_resolve = false; 384 385 /* we can use the hw resolve only for single full resolves */ 386 if (region_count == 1) { 387 if (regions[0].srcOffset.x || 388 regions[0].srcOffset.y || 389 regions[0].srcOffset.z) 390 use_compute_resolve = true; 391 if (regions[0].dstOffset.x || 392 regions[0].dstOffset.y || 393 regions[0].dstOffset.z) 394 use_compute_resolve = true; 395 396 if (regions[0].extent.width != src_image->extent.width || 397 regions[0].extent.height != src_image->extent.height || 398 regions[0].extent.depth != src_image->extent.depth) 399 use_compute_resolve = true; 400 } else 401 use_compute_resolve = true; 402 403 if (use_compute_resolve) { 404 405 radv_fast_clear_flush_image_inplace(cmd_buffer, src_image); 406 radv_meta_resolve_compute_image(cmd_buffer, 407 src_image, 408 src_image_layout, 409 dest_image, 410 dest_image_layout, 411 region_count, regions); 412 return; 413 } 414 415 radv_meta_save_graphics_reset_vport_scissor(&saved_state, cmd_buffer); 416 417 assert(src_image->samples > 1); 418 assert(dest_image->samples == 1); 419 420 if (src_image->samples >= 16) { 421 /* See commit aa3f9aaf31e9056a255f9e0472ebdfdaa60abe54 for the 422 * glBlitFramebuffer workaround for samples >= 16. 423 */ 424 radv_finishme("vkCmdResolveImage: need interpolation workaround when " 425 "samples >= 16"); 426 } 427 428 if (src_image->array_size > 1) 429 radv_finishme("vkCmdResolveImage: multisample array images"); 430 431 for (uint32_t r = 0; r < region_count; ++r) { 432 const VkImageResolve *region = ®ions[r]; 433 434 /* From the Vulkan 1.0 spec: 435 * 436 * - The aspectMask member of srcSubresource and dstSubresource must 437 * only contain VK_IMAGE_ASPECT_COLOR_BIT 438 * 439 * - The layerCount member of srcSubresource and dstSubresource must 440 * match 441 */ 442 assert(region->srcSubresource.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT); 443 assert(region->dstSubresource.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT); 444 assert(region->srcSubresource.layerCount == 445 region->dstSubresource.layerCount); 446 447 const uint32_t src_base_layer = 448 radv_meta_get_iview_layer(src_image, ®ion->srcSubresource, 449 ®ion->srcOffset); 450 451 const uint32_t dest_base_layer = 452 radv_meta_get_iview_layer(dest_image, ®ion->dstSubresource, 453 ®ion->dstOffset); 454 455 /** 456 * From Vulkan 1.0.6 spec: 18.6 Resolving Multisample Images 457 * 458 * extent is the size in texels of the source image to resolve in width, 459 * height and depth. 1D images use only x and width. 2D images use x, y, 460 * width and height. 3D images use x, y, z, width, height and depth. 461 * 462 * srcOffset and dstOffset select the initial x, y, and z offsets in 463 * texels of the sub-regions of the source and destination image data. 464 * extent is the size in texels of the source image to resolve in width, 465 * height and depth. 1D images use only x and width. 2D images use x, y, 466 * width and height. 3D images use x, y, z, width, height and depth. 467 */ 468 const struct VkExtent3D extent = 469 radv_sanitize_image_extent(src_image->type, region->extent); 470 const struct VkOffset3D dstOffset = 471 radv_sanitize_image_offset(dest_image->type, region->dstOffset); 472 473 474 for (uint32_t layer = 0; layer < region->srcSubresource.layerCount; 475 ++layer) { 476 477 struct radv_image_view src_iview; 478 radv_image_view_init(&src_iview, cmd_buffer->device, 479 &(VkImageViewCreateInfo) { 480 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 481 .image = src_image_h, 482 .viewType = radv_meta_get_view_type(src_image), 483 .format = src_image->vk_format, 484 .subresourceRange = { 485 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, 486 .baseMipLevel = region->srcSubresource.mipLevel, 487 .levelCount = 1, 488 .baseArrayLayer = src_base_layer + layer, 489 .layerCount = 1, 490 }, 491 }, 492 cmd_buffer, VK_IMAGE_USAGE_SAMPLED_BIT); 493 494 struct radv_image_view dest_iview; 495 radv_image_view_init(&dest_iview, cmd_buffer->device, 496 &(VkImageViewCreateInfo) { 497 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 498 .image = dest_image_h, 499 .viewType = radv_meta_get_view_type(dest_image), 500 .format = dest_image->vk_format, 501 .subresourceRange = { 502 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, 503 .baseMipLevel = region->dstSubresource.mipLevel, 504 .levelCount = 1, 505 .baseArrayLayer = dest_base_layer + layer, 506 .layerCount = 1, 507 }, 508 }, 509 cmd_buffer, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); 510 511 VkFramebuffer fb_h; 512 radv_CreateFramebuffer(device_h, 513 &(VkFramebufferCreateInfo) { 514 .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, 515 .attachmentCount = 2, 516 .pAttachments = (VkImageView[]) { 517 radv_image_view_to_handle(&src_iview), 518 radv_image_view_to_handle(&dest_iview), 519 }, 520 .width = radv_minify(dest_image->extent.width, 521 region->dstSubresource.mipLevel), 522 .height = radv_minify(dest_image->extent.height, 523 region->dstSubresource.mipLevel), 524 .layers = 1 525 }, 526 &cmd_buffer->pool->alloc, 527 &fb_h); 528 529 radv_CmdBeginRenderPass(cmd_buffer_h, 530 &(VkRenderPassBeginInfo) { 531 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, 532 .renderPass = device->meta_state.resolve.pass, 533 .framebuffer = fb_h, 534 .renderArea = { 535 .offset = { 536 dstOffset.x, 537 dstOffset.y, 538 }, 539 .extent = { 540 extent.width, 541 extent.height, 542 } 543 }, 544 .clearValueCount = 0, 545 .pClearValues = NULL, 546 }, 547 VK_SUBPASS_CONTENTS_INLINE); 548 549 emit_resolve(cmd_buffer, 550 &(VkOffset2D) { 551 .x = dstOffset.x, 552 .y = dstOffset.y, 553 }, 554 &(VkExtent2D) { 555 .width = extent.width, 556 .height = extent.height, 557 }); 558 559 radv_CmdEndRenderPass(cmd_buffer_h); 560 561 radv_DestroyFramebuffer(device_h, fb_h, 562 &cmd_buffer->pool->alloc); 563 } 564 } 565 566 radv_meta_restore(&saved_state, cmd_buffer); 567} 568 569/** 570 * Emit any needed resolves for the current subpass. 571 */ 572void 573radv_cmd_buffer_resolve_subpass(struct radv_cmd_buffer *cmd_buffer) 574{ 575 struct radv_framebuffer *fb = cmd_buffer->state.framebuffer; 576 const struct radv_subpass *subpass = cmd_buffer->state.subpass; 577 struct radv_meta_saved_state saved_state; 578 579 /* FINISHME(perf): Skip clears for resolve attachments. 580 * 581 * From the Vulkan 1.0 spec: 582 * 583 * If the first use of an attachment in a render pass is as a resolve 584 * attachment, then the loadOp is effectively ignored as the resolve is 585 * guaranteed to overwrite all pixels in the render area. 586 */ 587 588 if (!subpass->has_resolve) 589 return; 590 591 radv_meta_save_graphics_reset_vport_scissor(&saved_state, cmd_buffer); 592 593 for (uint32_t i = 0; i < subpass->color_count; ++i) { 594 VkAttachmentReference src_att = subpass->color_attachments[i]; 595 VkAttachmentReference dest_att = subpass->resolve_attachments[i]; 596 struct radv_image *dst_img = cmd_buffer->state.framebuffer->attachments[dest_att.attachment].attachment->image; 597 if (dest_att.attachment == VK_ATTACHMENT_UNUSED) 598 continue; 599 600 if (dst_img->surface.dcc_size) { 601 radv_initialize_dcc(cmd_buffer, dst_img, 0xffffffff); 602 cmd_buffer->state.attachments[dest_att.attachment].current_layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 603 } 604 605 struct radv_subpass resolve_subpass = { 606 .color_count = 2, 607 .color_attachments = (VkAttachmentReference[]) { src_att, dest_att }, 608 .depth_stencil_attachment = { .attachment = VK_ATTACHMENT_UNUSED }, 609 }; 610 611 radv_cmd_buffer_set_subpass(cmd_buffer, &resolve_subpass, false); 612 613 /* Subpass resolves must respect the render area. We can ignore the 614 * render area here because vkCmdBeginRenderPass set the render area 615 * with 3DSTATE_DRAWING_RECTANGLE. 616 * 617 * XXX(chadv): Does the hardware really respect 618 * 3DSTATE_DRAWING_RECTANGLE when draing a 3DPRIM_RECTLIST? 619 */ 620 emit_resolve(cmd_buffer, 621 &(VkOffset2D) { 0, 0 }, 622 &(VkExtent2D) { fb->width, fb->height }); 623 } 624 625 cmd_buffer->state.subpass = subpass; 626 radv_meta_restore(&saved_state, cmd_buffer); 627} 628