vk_blit_helper.cpp
1 // Copyright 2022 Citra Emulator Project 2 // Licensed under GPLv2 or any later version 3 // Refer to the license.txt file included. 4 5 #include "common/vector_math.h" 6 #include "video_core/renderer_vulkan/vk_blit_helper.h" 7 #include "video_core/renderer_vulkan/vk_instance.h" 8 #include "video_core/renderer_vulkan/vk_renderpass_cache.h" 9 #include "video_core/renderer_vulkan/vk_scheduler.h" 10 #include "video_core/renderer_vulkan/vk_shader_util.h" 11 #include "video_core/renderer_vulkan/vk_texture_runtime.h" 12 13 #include "video_core/host_shaders/format_reinterpreter/vulkan_d24s8_to_rgba8_comp.h" 14 #include "video_core/host_shaders/full_screen_triangle_vert.h" 15 #include "video_core/host_shaders/vulkan_blit_depth_stencil_frag.h" 16 #include "video_core/host_shaders/vulkan_depth_to_buffer_comp.h" 17 18 namespace Vulkan { 19 20 using VideoCore::PixelFormat; 21 22 namespace { 23 struct PushConstants { 24 std::array<float, 2> tex_scale; 25 std::array<float, 2> tex_offset; 26 }; 27 28 struct ComputeInfo { 29 Common::Vec2i src_offset; 30 Common::Vec2i dst_offset; 31 Common::Vec2i src_extent; 32 }; 33 34 inline constexpr vk::PushConstantRange COMPUTE_PUSH_CONSTANT_RANGE{ 35 .stageFlags = vk::ShaderStageFlagBits::eCompute, 36 .offset = 0, 37 .size = sizeof(ComputeInfo), 38 }; 39 40 constexpr std::array<vk::DescriptorSetLayoutBinding, 3> COMPUTE_BINDINGS = {{ 41 {0, vk::DescriptorType::eSampledImage, 1, vk::ShaderStageFlagBits::eCompute}, 42 {1, vk::DescriptorType::eSampledImage, 1, vk::ShaderStageFlagBits::eCompute}, 43 {2, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eCompute}, 44 }}; 45 46 constexpr std::array<vk::DescriptorSetLayoutBinding, 3> COMPUTE_BUFFER_BINDINGS = {{ 47 {0, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eCompute}, 48 {1, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eCompute}, 49 {2, vk::DescriptorType::eStorageBuffer, 1, vk::ShaderStageFlagBits::eCompute}, 50 }}; 51 52 constexpr std::array<vk::DescriptorSetLayoutBinding, 2> TWO_TEXTURES_BINDINGS = {{ 53 {0, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment}, 54 {1, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment}, 55 }}; 56 57 inline constexpr vk::PushConstantRange PUSH_CONSTANT_RANGE{ 58 .stageFlags = vk::ShaderStageFlagBits::eVertex, 59 .offset = 0, 60 .size = sizeof(PushConstants), 61 }; 62 constexpr vk::PipelineVertexInputStateCreateInfo PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO{ 63 .vertexBindingDescriptionCount = 0, 64 .pVertexBindingDescriptions = nullptr, 65 .vertexAttributeDescriptionCount = 0, 66 .pVertexAttributeDescriptions = nullptr, 67 }; 68 constexpr vk::PipelineInputAssemblyStateCreateInfo PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO{ 69 .topology = vk::PrimitiveTopology::eTriangleList, 70 .primitiveRestartEnable = VK_FALSE, 71 }; 72 constexpr vk::PipelineViewportStateCreateInfo PIPELINE_VIEWPORT_STATE_CREATE_INFO{ 73 .viewportCount = 1, 74 .pViewports = nullptr, 75 .scissorCount = 1, 76 .pScissors = nullptr, 77 }; 78 constexpr vk::PipelineRasterizationStateCreateInfo PIPELINE_RASTERIZATION_STATE_CREATE_INFO{ 79 .depthClampEnable = VK_FALSE, 80 .rasterizerDiscardEnable = VK_FALSE, 81 .polygonMode = vk::PolygonMode::eFill, 82 .cullMode = vk::CullModeFlagBits::eBack, 83 .frontFace = vk::FrontFace::eClockwise, 84 .depthBiasEnable = VK_FALSE, 85 .depthBiasConstantFactor = 0.0f, 86 .depthBiasClamp = 0.0f, 87 .depthBiasSlopeFactor = 0.0f, 88 .lineWidth = 1.0f, 89 }; 90 constexpr vk::PipelineMultisampleStateCreateInfo PIPELINE_MULTISAMPLE_STATE_CREATE_INFO{ 91 .rasterizationSamples = vk::SampleCountFlagBits::e1, 92 .sampleShadingEnable = VK_FALSE, 93 .minSampleShading = 0.0f, 94 .pSampleMask = nullptr, 95 .alphaToCoverageEnable = VK_FALSE, 96 .alphaToOneEnable = VK_FALSE, 97 }; 98 constexpr std::array DYNAMIC_STATES{ 99 vk::DynamicState::eViewport, 100 vk::DynamicState::eScissor, 101 }; 102 constexpr vk::PipelineDynamicStateCreateInfo PIPELINE_DYNAMIC_STATE_CREATE_INFO{ 103 .dynamicStateCount = static_cast<u32>(DYNAMIC_STATES.size()), 104 .pDynamicStates = DYNAMIC_STATES.data(), 105 }; 106 constexpr vk::PipelineColorBlendStateCreateInfo PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO{ 107 .logicOpEnable = VK_FALSE, 108 .logicOp = vk::LogicOp::eClear, 109 .attachmentCount = 0, 110 .pAttachments = nullptr, 111 .blendConstants = std::array{0.0f, 0.0f, 0.0f, 0.0f}, 112 }; 113 constexpr vk::PipelineDepthStencilStateCreateInfo PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO{ 114 .depthTestEnable = VK_TRUE, 115 .depthWriteEnable = VK_TRUE, 116 .depthCompareOp = vk::CompareOp::eAlways, 117 .depthBoundsTestEnable = VK_FALSE, 118 .stencilTestEnable = VK_FALSE, 119 .front = vk::StencilOpState{}, 120 .back = vk::StencilOpState{}, 121 .minDepthBounds = 0.0f, 122 .maxDepthBounds = 0.0f, 123 }; 124 125 template <vk::Filter filter> 126 inline constexpr vk::SamplerCreateInfo SAMPLER_CREATE_INFO{ 127 .magFilter = filter, 128 .minFilter = filter, 129 .mipmapMode = vk::SamplerMipmapMode::eNearest, 130 .addressModeU = vk::SamplerAddressMode::eClampToBorder, 131 .addressModeV = vk::SamplerAddressMode::eClampToBorder, 132 .addressModeW = vk::SamplerAddressMode::eClampToBorder, 133 .mipLodBias = 0.0f, 134 .anisotropyEnable = VK_FALSE, 135 .maxAnisotropy = 0.0f, 136 .compareEnable = VK_FALSE, 137 .compareOp = vk::CompareOp::eNever, 138 .minLod = 0.0f, 139 .maxLod = 0.0f, 140 .borderColor = vk::BorderColor::eFloatOpaqueWhite, 141 .unnormalizedCoordinates = VK_FALSE, 142 }; 143 144 constexpr vk::PipelineLayoutCreateInfo PipelineLayoutCreateInfo( 145 const vk::DescriptorSetLayout* set_layout, bool compute = false) { 146 return vk::PipelineLayoutCreateInfo{ 147 .setLayoutCount = 1, 148 .pSetLayouts = set_layout, 149 .pushConstantRangeCount = 1, 150 .pPushConstantRanges = (compute ? &COMPUTE_PUSH_CONSTANT_RANGE : &PUSH_CONSTANT_RANGE), 151 }; 152 } 153 154 constexpr std::array<vk::PipelineShaderStageCreateInfo, 2> MakeStages( 155 vk::ShaderModule vertex_shader, vk::ShaderModule fragment_shader) { 156 return std::array{ 157 vk::PipelineShaderStageCreateInfo{ 158 .stage = vk::ShaderStageFlagBits::eVertex, 159 .module = vertex_shader, 160 .pName = "main", 161 }, 162 vk::PipelineShaderStageCreateInfo{ 163 .stage = vk::ShaderStageFlagBits::eFragment, 164 .module = fragment_shader, 165 .pName = "main", 166 }, 167 }; 168 } 169 170 constexpr vk::PipelineShaderStageCreateInfo MakeStages(vk::ShaderModule compute_shader) { 171 return vk::PipelineShaderStageCreateInfo{ 172 .stage = vk::ShaderStageFlagBits::eCompute, 173 .module = compute_shader, 174 .pName = "main", 175 }; 176 } 177 178 } // Anonymous namespace 179 180 BlitHelper::BlitHelper(const Instance& instance_, Scheduler& scheduler_, DescriptorPool& pool, 181 RenderpassCache& renderpass_cache_) 182 : instance{instance_}, scheduler{scheduler_}, renderpass_cache{renderpass_cache_}, 183 device{instance.GetDevice()}, compute_provider{instance, pool, COMPUTE_BINDINGS}, 184 compute_buffer_provider{instance, pool, COMPUTE_BUFFER_BINDINGS}, 185 two_textures_provider{instance, pool, TWO_TEXTURES_BINDINGS}, 186 compute_pipeline_layout{ 187 device.createPipelineLayout(PipelineLayoutCreateInfo(&compute_provider.Layout(), true))}, 188 compute_buffer_pipeline_layout{device.createPipelineLayout( 189 PipelineLayoutCreateInfo(&compute_buffer_provider.Layout(), true))}, 190 two_textures_pipeline_layout{ 191 device.createPipelineLayout(PipelineLayoutCreateInfo(&two_textures_provider.Layout()))}, 192 full_screen_vert{Compile(HostShaders::FULL_SCREEN_TRIANGLE_VERT, 193 vk::ShaderStageFlagBits::eVertex, device)}, 194 d24s8_to_rgba8_comp{Compile(HostShaders::VULKAN_D24S8_TO_RGBA8_COMP, 195 vk::ShaderStageFlagBits::eCompute, device)}, 196 depth_to_buffer_comp{Compile(HostShaders::VULKAN_DEPTH_TO_BUFFER_COMP, 197 vk::ShaderStageFlagBits::eCompute, device)}, 198 blit_depth_stencil_frag{Compile(HostShaders::VULKAN_BLIT_DEPTH_STENCIL_FRAG, 199 vk::ShaderStageFlagBits::eFragment, device)}, 200 d24s8_to_rgba8_pipeline{MakeComputePipeline(d24s8_to_rgba8_comp, compute_pipeline_layout)}, 201 depth_to_buffer_pipeline{ 202 MakeComputePipeline(depth_to_buffer_comp, compute_buffer_pipeline_layout)}, 203 depth_blit_pipeline{MakeDepthStencilBlitPipeline()}, 204 linear_sampler{device.createSampler(SAMPLER_CREATE_INFO<vk::Filter::eLinear>)}, 205 nearest_sampler{device.createSampler(SAMPLER_CREATE_INFO<vk::Filter::eNearest>)} { 206 207 if (instance.HasDebuggingToolAttached()) { 208 SetObjectName(device, compute_pipeline_layout, "BlitHelper: compute_pipeline_layout"); 209 SetObjectName(device, compute_buffer_pipeline_layout, 210 "BlitHelper: compute_buffer_pipeline_layout"); 211 SetObjectName(device, two_textures_pipeline_layout, 212 "BlitHelper: two_textures_pipeline_layout"); 213 SetObjectName(device, full_screen_vert, "BlitHelper: full_screen_vert"); 214 SetObjectName(device, d24s8_to_rgba8_comp, "BlitHelper: d24s8_to_rgba8_comp"); 215 SetObjectName(device, depth_to_buffer_comp, "BlitHelper: depth_to_buffer_comp"); 216 SetObjectName(device, blit_depth_stencil_frag, "BlitHelper: blit_depth_stencil_frag"); 217 SetObjectName(device, d24s8_to_rgba8_pipeline, "BlitHelper: d24s8_to_rgba8_pipeline"); 218 SetObjectName(device, depth_to_buffer_pipeline, "BlitHelper: depth_to_buffer_pipeline"); 219 if (depth_blit_pipeline) { 220 SetObjectName(device, depth_blit_pipeline, "BlitHelper: depth_blit_pipeline"); 221 } 222 SetObjectName(device, linear_sampler, "BlitHelper: linear_sampler"); 223 SetObjectName(device, nearest_sampler, "BlitHelper: nearest_sampler"); 224 } 225 } 226 227 BlitHelper::~BlitHelper() { 228 device.destroyPipelineLayout(compute_pipeline_layout); 229 device.destroyPipelineLayout(compute_buffer_pipeline_layout); 230 device.destroyPipelineLayout(two_textures_pipeline_layout); 231 device.destroyShaderModule(full_screen_vert); 232 device.destroyShaderModule(d24s8_to_rgba8_comp); 233 device.destroyShaderModule(depth_to_buffer_comp); 234 device.destroyShaderModule(blit_depth_stencil_frag); 235 device.destroyPipeline(depth_to_buffer_pipeline); 236 device.destroyPipeline(d24s8_to_rgba8_pipeline); 237 device.destroyPipeline(depth_blit_pipeline); 238 device.destroySampler(linear_sampler); 239 device.destroySampler(nearest_sampler); 240 } 241 242 void BindBlitState(vk::CommandBuffer cmdbuf, vk::PipelineLayout layout, 243 const VideoCore::TextureBlit& blit) { 244 const vk::Offset2D offset{ 245 .x = std::min<s32>(blit.dst_rect.left, blit.dst_rect.right), 246 .y = std::min<s32>(blit.dst_rect.bottom, blit.dst_rect.top), 247 }; 248 const vk::Extent2D extent{ 249 .width = blit.dst_rect.GetWidth(), 250 .height = blit.dst_rect.GetHeight(), 251 }; 252 const vk::Viewport viewport{ 253 .x = static_cast<float>(offset.x), 254 .y = static_cast<float>(offset.y), 255 .width = static_cast<float>(extent.width), 256 .height = static_cast<float>(extent.height), 257 .minDepth = 0.0f, 258 .maxDepth = 1.0f, 259 }; 260 const vk::Rect2D scissor{ 261 .offset = offset, 262 .extent = extent, 263 }; 264 const float scale_x = static_cast<float>(blit.src_rect.GetWidth()); 265 const float scale_y = static_cast<float>(blit.src_rect.GetHeight()); 266 const PushConstants push_constants{ 267 .tex_scale = {scale_x, scale_y}, 268 .tex_offset = {static_cast<float>(blit.src_rect.left), 269 static_cast<float>(blit.src_rect.bottom)}, 270 }; 271 cmdbuf.setViewport(0, viewport); 272 cmdbuf.setScissor(0, scissor); 273 cmdbuf.pushConstants(layout, vk::ShaderStageFlagBits::eVertex, 0, sizeof(push_constants), 274 &push_constants); 275 } 276 277 bool BlitHelper::BlitDepthStencil(Surface& source, Surface& dest, 278 const VideoCore::TextureBlit& blit) { 279 if (!instance.IsShaderStencilExportSupported()) { 280 LOG_ERROR(Render_Vulkan, "Unable to emulate depth stencil images"); 281 return false; 282 } 283 284 const vk::Rect2D dst_render_area = { 285 .offset = {0, 0}, 286 .extent = {dest.GetScaledWidth(), dest.GetScaledHeight()}, 287 }; 288 289 std::array<DescriptorData, 2> textures{}; 290 textures[0].image_info = vk::DescriptorImageInfo{ 291 .sampler = nearest_sampler, 292 .imageView = source.DepthView(), 293 .imageLayout = vk::ImageLayout::eGeneral, 294 }; 295 textures[1].image_info = vk::DescriptorImageInfo{ 296 .sampler = nearest_sampler, 297 .imageView = source.StencilView(), 298 .imageLayout = vk::ImageLayout::eGeneral, 299 }; 300 301 const auto descriptor_set = two_textures_provider.Acquire(textures); 302 303 const RenderPass depth_pass = { 304 .framebuffer = dest.Framebuffer(), 305 .render_pass = 306 renderpass_cache.GetRenderpass(PixelFormat::Invalid, dest.pixel_format, false), 307 .render_area = dst_render_area, 308 }; 309 renderpass_cache.BeginRendering(depth_pass); 310 311 scheduler.Record([blit, descriptor_set, this](vk::CommandBuffer cmdbuf) { 312 const vk::PipelineLayout layout = two_textures_pipeline_layout; 313 314 cmdbuf.bindPipeline(vk::PipelineBindPoint::eGraphics, depth_blit_pipeline); 315 cmdbuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, layout, 0, descriptor_set, {}); 316 BindBlitState(cmdbuf, layout, blit); 317 cmdbuf.draw(3, 1, 0, 0); 318 }); 319 scheduler.MakeDirty(StateFlags::Pipeline); 320 return true; 321 } 322 323 bool BlitHelper::ConvertDS24S8ToRGBA8(Surface& source, Surface& dest, 324 const VideoCore::TextureCopy& copy) { 325 std::array<DescriptorData, 3> textures{}; 326 textures[0].image_info = vk::DescriptorImageInfo{ 327 .imageView = source.DepthView(), 328 .imageLayout = vk::ImageLayout::eDepthStencilReadOnlyOptimal, 329 }; 330 textures[1].image_info = vk::DescriptorImageInfo{ 331 .imageView = source.StencilView(), 332 .imageLayout = vk::ImageLayout::eDepthStencilReadOnlyOptimal, 333 }; 334 textures[2].image_info = vk::DescriptorImageInfo{ 335 .imageView = dest.ImageView(), 336 .imageLayout = vk::ImageLayout::eGeneral, 337 }; 338 339 const auto descriptor_set = compute_provider.Acquire(textures); 340 341 renderpass_cache.EndRendering(); 342 scheduler.Record([this, descriptor_set, copy, src_image = source.Image(), 343 dst_image = dest.Image()](vk::CommandBuffer cmdbuf) { 344 const std::array pre_barriers = { 345 vk::ImageMemoryBarrier{ 346 .srcAccessMask = vk::AccessFlagBits::eDepthStencilAttachmentWrite, 347 .dstAccessMask = vk::AccessFlagBits::eShaderRead, 348 .oldLayout = vk::ImageLayout::eGeneral, 349 .newLayout = vk::ImageLayout::eDepthStencilReadOnlyOptimal, 350 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 351 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 352 .image = src_image, 353 .subresourceRange{ 354 .aspectMask = 355 vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil, 356 .baseMipLevel = 0, 357 .levelCount = VK_REMAINING_MIP_LEVELS, 358 .baseArrayLayer = 0, 359 .layerCount = VK_REMAINING_ARRAY_LAYERS, 360 }, 361 }, 362 vk::ImageMemoryBarrier{ 363 .srcAccessMask = vk::AccessFlagBits::eNone, 364 .dstAccessMask = vk::AccessFlagBits::eShaderWrite, 365 .oldLayout = vk::ImageLayout::eUndefined, 366 .newLayout = vk::ImageLayout::eGeneral, 367 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 368 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 369 .image = dst_image, 370 .subresourceRange{ 371 .aspectMask = vk::ImageAspectFlagBits::eColor, 372 .baseMipLevel = 0, 373 .levelCount = VK_REMAINING_MIP_LEVELS, 374 .baseArrayLayer = 0, 375 .layerCount = VK_REMAINING_ARRAY_LAYERS, 376 }, 377 }, 378 }; 379 const std::array post_barriers = { 380 vk::ImageMemoryBarrier{ 381 .srcAccessMask = vk::AccessFlagBits::eShaderRead, 382 .dstAccessMask = vk::AccessFlagBits::eDepthStencilAttachmentWrite | 383 vk::AccessFlagBits::eDepthStencilAttachmentRead, 384 .oldLayout = vk::ImageLayout::eDepthStencilReadOnlyOptimal, 385 .newLayout = vk::ImageLayout::eGeneral, 386 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 387 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 388 .image = src_image, 389 .subresourceRange{ 390 .aspectMask = 391 vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil, 392 .baseMipLevel = 0, 393 .levelCount = VK_REMAINING_MIP_LEVELS, 394 .baseArrayLayer = 0, 395 .layerCount = VK_REMAINING_ARRAY_LAYERS, 396 }, 397 }, 398 vk::ImageMemoryBarrier{ 399 .srcAccessMask = vk::AccessFlagBits::eShaderWrite, 400 .dstAccessMask = vk::AccessFlagBits::eTransferRead, 401 .oldLayout = vk::ImageLayout::eGeneral, 402 .newLayout = vk::ImageLayout::eGeneral, 403 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 404 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 405 .image = dst_image, 406 .subresourceRange{ 407 .aspectMask = vk::ImageAspectFlagBits::eColor, 408 .baseMipLevel = 0, 409 .levelCount = VK_REMAINING_MIP_LEVELS, 410 .baseArrayLayer = 0, 411 .layerCount = VK_REMAINING_ARRAY_LAYERS, 412 }, 413 }}; 414 cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eEarlyFragmentTests | 415 vk::PipelineStageFlagBits::eLateFragmentTests, 416 vk::PipelineStageFlagBits::eComputeShader, 417 vk::DependencyFlagBits::eByRegion, {}, {}, pre_barriers); 418 419 cmdbuf.bindDescriptorSets(vk::PipelineBindPoint::eCompute, compute_pipeline_layout, 0, 420 descriptor_set, {}); 421 cmdbuf.bindPipeline(vk::PipelineBindPoint::eCompute, d24s8_to_rgba8_pipeline); 422 423 const ComputeInfo info = { 424 .src_offset = Common::Vec2i{static_cast<int>(copy.src_offset.x), 425 static_cast<int>(copy.src_offset.y)}, 426 .dst_offset = Common::Vec2i{static_cast<int>(copy.dst_offset.x), 427 static_cast<int>(copy.dst_offset.y)}, 428 }; 429 cmdbuf.pushConstants(compute_pipeline_layout, vk::ShaderStageFlagBits::eCompute, 0, 430 sizeof(info), &info); 431 432 cmdbuf.dispatch(copy.extent.width / 8, copy.extent.height / 8, 1); 433 434 cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, 435 vk::PipelineStageFlagBits::eEarlyFragmentTests | 436 vk::PipelineStageFlagBits::eLateFragmentTests | 437 vk::PipelineStageFlagBits::eTransfer, 438 vk::DependencyFlagBits::eByRegion, {}, {}, post_barriers); 439 }); 440 return true; 441 } 442 443 bool BlitHelper::DepthToBuffer(Surface& source, vk::Buffer buffer, 444 const VideoCore::BufferTextureCopy& copy) { 445 std::array<DescriptorData, 3> textures{}; 446 textures[0].image_info = vk::DescriptorImageInfo{ 447 .sampler = nearest_sampler, 448 .imageView = source.DepthView(), 449 .imageLayout = vk::ImageLayout::eDepthStencilReadOnlyOptimal, 450 }; 451 textures[1].image_info = vk::DescriptorImageInfo{ 452 .sampler = nearest_sampler, 453 .imageView = source.StencilView(), 454 .imageLayout = vk::ImageLayout::eDepthStencilReadOnlyOptimal, 455 }; 456 textures[2].buffer_info = vk::DescriptorBufferInfo{ 457 .buffer = buffer, 458 .offset = copy.buffer_offset, 459 .range = copy.buffer_size, 460 }; 461 462 const auto descriptor_set = compute_buffer_provider.Acquire(textures); 463 464 renderpass_cache.EndRendering(); 465 scheduler.Record([this, descriptor_set, copy, src_image = source.Image(), 466 extent = source.RealExtent(false)](vk::CommandBuffer cmdbuf) { 467 const vk::ImageMemoryBarrier pre_barrier = { 468 .srcAccessMask = vk::AccessFlagBits::eDepthStencilAttachmentWrite, 469 .dstAccessMask = vk::AccessFlagBits::eShaderRead, 470 .oldLayout = vk::ImageLayout::eGeneral, 471 .newLayout = vk::ImageLayout::eDepthStencilReadOnlyOptimal, 472 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 473 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 474 .image = src_image, 475 .subresourceRange{ 476 .aspectMask = vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil, 477 .baseMipLevel = 0, 478 .levelCount = VK_REMAINING_MIP_LEVELS, 479 .baseArrayLayer = 0, 480 .layerCount = VK_REMAINING_ARRAY_LAYERS, 481 }, 482 }; 483 const vk::ImageMemoryBarrier post_barrier = { 484 .srcAccessMask = vk::AccessFlagBits::eShaderRead, 485 .dstAccessMask = vk::AccessFlagBits::eDepthStencilAttachmentWrite | 486 vk::AccessFlagBits::eDepthStencilAttachmentRead, 487 .oldLayout = vk::ImageLayout::eDepthStencilReadOnlyOptimal, 488 .newLayout = vk::ImageLayout::eGeneral, 489 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 490 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 491 .image = src_image, 492 .subresourceRange{ 493 .aspectMask = vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil, 494 .baseMipLevel = 0, 495 .levelCount = VK_REMAINING_MIP_LEVELS, 496 .baseArrayLayer = 0, 497 .layerCount = VK_REMAINING_ARRAY_LAYERS, 498 }, 499 }; 500 cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eEarlyFragmentTests | 501 vk::PipelineStageFlagBits::eLateFragmentTests, 502 vk::PipelineStageFlagBits::eComputeShader, 503 vk::DependencyFlagBits::eByRegion, {}, {}, pre_barrier); 504 505 cmdbuf.bindDescriptorSets(vk::PipelineBindPoint::eCompute, compute_buffer_pipeline_layout, 506 0, descriptor_set, {}); 507 cmdbuf.bindPipeline(vk::PipelineBindPoint::eCompute, depth_to_buffer_pipeline); 508 509 const ComputeInfo info = { 510 .src_offset = Common::Vec2i{static_cast<int>(copy.texture_rect.left), 511 static_cast<int>(copy.texture_rect.bottom)}, 512 .src_extent = 513 Common::Vec2i{static_cast<int>(extent.width), static_cast<int>(extent.height)}, 514 }; 515 cmdbuf.pushConstants(compute_buffer_pipeline_layout, vk::ShaderStageFlagBits::eCompute, 0, 516 sizeof(ComputeInfo), &info); 517 518 cmdbuf.dispatch(copy.texture_rect.GetWidth() / 8, copy.texture_rect.GetHeight() / 8, 1); 519 520 cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, 521 vk::PipelineStageFlagBits::eEarlyFragmentTests | 522 vk::PipelineStageFlagBits::eLateFragmentTests | 523 vk::PipelineStageFlagBits::eTransfer, 524 vk::DependencyFlagBits::eByRegion, {}, {}, post_barrier); 525 }); 526 return true; 527 } 528 529 vk::Pipeline BlitHelper::MakeComputePipeline(vk::ShaderModule shader, vk::PipelineLayout layout) { 530 const vk::ComputePipelineCreateInfo compute_info = { 531 .stage = MakeStages(shader), 532 .layout = layout, 533 }; 534 535 if (const auto result = device.createComputePipeline({}, compute_info); 536 result.result == vk::Result::eSuccess) { 537 return result.value; 538 } else { 539 LOG_CRITICAL(Render_Vulkan, "Compute pipeline creation failed!"); 540 UNREACHABLE(); 541 } 542 } 543 544 vk::Pipeline BlitHelper::MakeDepthStencilBlitPipeline() { 545 if (!instance.IsShaderStencilExportSupported()) { 546 return VK_NULL_HANDLE; 547 } 548 549 const std::array stages = MakeStages(full_screen_vert, blit_depth_stencil_frag); 550 const auto renderpass = renderpass_cache.GetRenderpass(VideoCore::PixelFormat::Invalid, 551 VideoCore::PixelFormat::D24S8, false); 552 vk::GraphicsPipelineCreateInfo depth_stencil_info = { 553 .stageCount = static_cast<u32>(stages.size()), 554 .pStages = stages.data(), 555 .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, 556 .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, 557 .pTessellationState = nullptr, 558 .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, 559 .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, 560 .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, 561 .pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, 562 .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO, 563 .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO, 564 .layout = two_textures_pipeline_layout, 565 .renderPass = renderpass, 566 }; 567 568 if (const auto result = device.createGraphicsPipeline({}, depth_stencil_info); 569 result.result == vk::Result::eSuccess) { 570 return result.value; 571 } else { 572 LOG_CRITICAL(Render_Vulkan, "Depth stencil blit pipeline creation failed!"); 573 UNREACHABLE(); 574 } 575 return VK_NULL_HANDLE; 576 } 577 578 } // namespace Vulkan