blit_image.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  1. // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <algorithm>
  4. #include "common/settings.h"
  5. #include "video_core/host_shaders/convert_abgr8_to_d24s8_frag_spv.h"
  6. #include "video_core/host_shaders/convert_d24s8_to_abgr8_frag_spv.h"
  7. #include "video_core/host_shaders/convert_depth_to_float_frag_spv.h"
  8. #include "video_core/host_shaders/convert_float_to_depth_frag_spv.h"
  9. #include "video_core/host_shaders/convert_s8d24_to_abgr8_frag_spv.h"
  10. #include "video_core/host_shaders/full_screen_triangle_vert_spv.h"
  11. #include "video_core/host_shaders/vulkan_blit_color_float_frag_spv.h"
  12. #include "video_core/host_shaders/vulkan_blit_depth_stencil_frag_spv.h"
  13. #include "video_core/renderer_vulkan/blit_image.h"
  14. #include "video_core/renderer_vulkan/maxwell_to_vk.h"
  15. #include "video_core/renderer_vulkan/vk_scheduler.h"
  16. #include "video_core/renderer_vulkan/vk_shader_util.h"
  17. #include "video_core/renderer_vulkan/vk_state_tracker.h"
  18. #include "video_core/renderer_vulkan/vk_texture_cache.h"
  19. #include "video_core/renderer_vulkan/vk_update_descriptor.h"
  20. #include "video_core/surface.h"
  21. #include "video_core/vulkan_common/vulkan_device.h"
  22. #include "video_core/vulkan_common/vulkan_wrapper.h"
  23. namespace Vulkan {
  24. using VideoCommon::ImageViewType;
  25. namespace {
  26. struct PushConstants {
  27. std::array<float, 2> tex_scale;
  28. std::array<float, 2> tex_offset;
  29. };
  30. template <u32 binding>
  31. inline constexpr VkDescriptorSetLayoutBinding TEXTURE_DESCRIPTOR_SET_LAYOUT_BINDING{
  32. .binding = binding,
  33. .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
  34. .descriptorCount = 1,
  35. .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
  36. .pImmutableSamplers = nullptr,
  37. };
  38. constexpr std::array TWO_TEXTURES_DESCRIPTOR_SET_LAYOUT_BINDINGS{
  39. TEXTURE_DESCRIPTOR_SET_LAYOUT_BINDING<0>,
  40. TEXTURE_DESCRIPTOR_SET_LAYOUT_BINDING<1>,
  41. };
  42. constexpr VkDescriptorSetLayoutCreateInfo ONE_TEXTURE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO{
  43. .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
  44. .pNext = nullptr,
  45. .flags = 0,
  46. .bindingCount = 1,
  47. .pBindings = &TEXTURE_DESCRIPTOR_SET_LAYOUT_BINDING<0>,
  48. };
  49. template <u32 num_textures>
  50. inline constexpr DescriptorBankInfo TEXTURE_DESCRIPTOR_BANK_INFO{
  51. .uniform_buffers = 0,
  52. .storage_buffers = 0,
  53. .texture_buffers = 0,
  54. .image_buffers = 0,
  55. .textures = num_textures,
  56. .images = 0,
  57. .score = 2,
  58. };
  59. constexpr VkDescriptorSetLayoutCreateInfo TWO_TEXTURES_DESCRIPTOR_SET_LAYOUT_CREATE_INFO{
  60. .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
  61. .pNext = nullptr,
  62. .flags = 0,
  63. .bindingCount = static_cast<u32>(TWO_TEXTURES_DESCRIPTOR_SET_LAYOUT_BINDINGS.size()),
  64. .pBindings = TWO_TEXTURES_DESCRIPTOR_SET_LAYOUT_BINDINGS.data(),
  65. };
  66. constexpr VkPushConstantRange PUSH_CONSTANT_RANGE{
  67. .stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
  68. .offset = 0,
  69. .size = sizeof(PushConstants),
  70. };
  71. constexpr VkPipelineVertexInputStateCreateInfo PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO{
  72. .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
  73. .pNext = nullptr,
  74. .flags = 0,
  75. .vertexBindingDescriptionCount = 0,
  76. .pVertexBindingDescriptions = nullptr,
  77. .vertexAttributeDescriptionCount = 0,
  78. .pVertexAttributeDescriptions = nullptr,
  79. };
  80. constexpr VkPipelineInputAssemblyStateCreateInfo PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO{
  81. .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
  82. .pNext = nullptr,
  83. .flags = 0,
  84. .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
  85. .primitiveRestartEnable = VK_FALSE,
  86. };
  87. constexpr VkPipelineViewportStateCreateInfo PIPELINE_VIEWPORT_STATE_CREATE_INFO{
  88. .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
  89. .pNext = nullptr,
  90. .flags = 0,
  91. .viewportCount = 1,
  92. .pViewports = nullptr,
  93. .scissorCount = 1,
  94. .pScissors = nullptr,
  95. };
  96. constexpr VkPipelineRasterizationStateCreateInfo PIPELINE_RASTERIZATION_STATE_CREATE_INFO{
  97. .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
  98. .pNext = nullptr,
  99. .flags = 0,
  100. .depthClampEnable = VK_FALSE,
  101. .rasterizerDiscardEnable = VK_FALSE,
  102. .polygonMode = VK_POLYGON_MODE_FILL,
  103. .cullMode = VK_CULL_MODE_BACK_BIT,
  104. .frontFace = VK_FRONT_FACE_CLOCKWISE,
  105. .depthBiasEnable = VK_FALSE,
  106. .depthBiasConstantFactor = 0.0f,
  107. .depthBiasClamp = 0.0f,
  108. .depthBiasSlopeFactor = 0.0f,
  109. .lineWidth = 1.0f,
  110. };
  111. constexpr VkPipelineMultisampleStateCreateInfo PIPELINE_MULTISAMPLE_STATE_CREATE_INFO{
  112. .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
  113. .pNext = nullptr,
  114. .flags = 0,
  115. .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
  116. .sampleShadingEnable = VK_FALSE,
  117. .minSampleShading = 0.0f,
  118. .pSampleMask = nullptr,
  119. .alphaToCoverageEnable = VK_FALSE,
  120. .alphaToOneEnable = VK_FALSE,
  121. };
  122. constexpr std::array DYNAMIC_STATES{
  123. VK_DYNAMIC_STATE_VIEWPORT,
  124. VK_DYNAMIC_STATE_SCISSOR,
  125. };
  126. constexpr VkPipelineDynamicStateCreateInfo PIPELINE_DYNAMIC_STATE_CREATE_INFO{
  127. .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
  128. .pNext = nullptr,
  129. .flags = 0,
  130. .dynamicStateCount = static_cast<u32>(DYNAMIC_STATES.size()),
  131. .pDynamicStates = DYNAMIC_STATES.data(),
  132. };
  133. constexpr VkPipelineColorBlendStateCreateInfo PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO{
  134. .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
  135. .pNext = nullptr,
  136. .flags = 0,
  137. .logicOpEnable = VK_FALSE,
  138. .logicOp = VK_LOGIC_OP_CLEAR,
  139. .attachmentCount = 0,
  140. .pAttachments = nullptr,
  141. .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f},
  142. };
  143. constexpr VkPipelineColorBlendAttachmentState PIPELINE_COLOR_BLEND_ATTACHMENT_STATE{
  144. .blendEnable = VK_FALSE,
  145. .srcColorBlendFactor = VK_BLEND_FACTOR_ZERO,
  146. .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO,
  147. .colorBlendOp = VK_BLEND_OP_ADD,
  148. .srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
  149. .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
  150. .alphaBlendOp = VK_BLEND_OP_ADD,
  151. .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
  152. VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
  153. };
  154. constexpr VkPipelineColorBlendStateCreateInfo PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO{
  155. .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
  156. .pNext = nullptr,
  157. .flags = 0,
  158. .logicOpEnable = VK_FALSE,
  159. .logicOp = VK_LOGIC_OP_CLEAR,
  160. .attachmentCount = 1,
  161. .pAttachments = &PIPELINE_COLOR_BLEND_ATTACHMENT_STATE,
  162. .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f},
  163. };
  164. constexpr VkPipelineDepthStencilStateCreateInfo PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO{
  165. .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
  166. .pNext = nullptr,
  167. .flags = 0,
  168. .depthTestEnable = VK_TRUE,
  169. .depthWriteEnable = VK_TRUE,
  170. .depthCompareOp = VK_COMPARE_OP_ALWAYS,
  171. .depthBoundsTestEnable = VK_FALSE,
  172. .stencilTestEnable = VK_FALSE,
  173. .front = VkStencilOpState{},
  174. .back = VkStencilOpState{},
  175. .minDepthBounds = 0.0f,
  176. .maxDepthBounds = 0.0f,
  177. };
  178. template <VkFilter filter>
  179. inline constexpr VkSamplerCreateInfo SAMPLER_CREATE_INFO{
  180. .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
  181. .pNext = nullptr,
  182. .flags = 0,
  183. .magFilter = filter,
  184. .minFilter = filter,
  185. .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST,
  186. .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
  187. .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
  188. .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
  189. .mipLodBias = 0.0f,
  190. .anisotropyEnable = VK_FALSE,
  191. .maxAnisotropy = 0.0f,
  192. .compareEnable = VK_FALSE,
  193. .compareOp = VK_COMPARE_OP_NEVER,
  194. .minLod = 0.0f,
  195. .maxLod = 0.0f,
  196. .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE,
  197. .unnormalizedCoordinates = VK_TRUE,
  198. };
  199. constexpr VkPipelineLayoutCreateInfo PipelineLayoutCreateInfo(
  200. const VkDescriptorSetLayout* set_layout) {
  201. return VkPipelineLayoutCreateInfo{
  202. .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
  203. .pNext = nullptr,
  204. .flags = 0,
  205. .setLayoutCount = 1,
  206. .pSetLayouts = set_layout,
  207. .pushConstantRangeCount = 1,
  208. .pPushConstantRanges = &PUSH_CONSTANT_RANGE,
  209. };
  210. }
  211. constexpr VkPipelineShaderStageCreateInfo PipelineShaderStageCreateInfo(VkShaderStageFlagBits stage,
  212. VkShaderModule shader) {
  213. return VkPipelineShaderStageCreateInfo{
  214. .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
  215. .pNext = nullptr,
  216. .flags = 0,
  217. .stage = stage,
  218. .module = shader,
  219. .pName = "main",
  220. .pSpecializationInfo = nullptr,
  221. };
  222. }
  223. constexpr std::array<VkPipelineShaderStageCreateInfo, 2> MakeStages(
  224. VkShaderModule vertex_shader, VkShaderModule fragment_shader) {
  225. return std::array{
  226. PipelineShaderStageCreateInfo(VK_SHADER_STAGE_VERTEX_BIT, vertex_shader),
  227. PipelineShaderStageCreateInfo(VK_SHADER_STAGE_FRAGMENT_BIT, fragment_shader),
  228. };
  229. }
  230. void UpdateOneTextureDescriptorSet(const Device& device, VkDescriptorSet descriptor_set,
  231. VkSampler sampler, VkImageView image_view) {
  232. const VkDescriptorImageInfo image_info{
  233. .sampler = sampler,
  234. .imageView = image_view,
  235. .imageLayout = VK_IMAGE_LAYOUT_GENERAL,
  236. };
  237. const VkWriteDescriptorSet write_descriptor_set{
  238. .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
  239. .pNext = nullptr,
  240. .dstSet = descriptor_set,
  241. .dstBinding = 0,
  242. .dstArrayElement = 0,
  243. .descriptorCount = 1,
  244. .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
  245. .pImageInfo = &image_info,
  246. .pBufferInfo = nullptr,
  247. .pTexelBufferView = nullptr,
  248. };
  249. device.GetLogical().UpdateDescriptorSets(write_descriptor_set, nullptr);
  250. }
  251. void UpdateTwoTexturesDescriptorSet(const Device& device, VkDescriptorSet descriptor_set,
  252. VkSampler sampler, VkImageView image_view_0,
  253. VkImageView image_view_1) {
  254. const VkDescriptorImageInfo image_info_0{
  255. .sampler = sampler,
  256. .imageView = image_view_0,
  257. .imageLayout = VK_IMAGE_LAYOUT_GENERAL,
  258. };
  259. const VkDescriptorImageInfo image_info_1{
  260. .sampler = sampler,
  261. .imageView = image_view_1,
  262. .imageLayout = VK_IMAGE_LAYOUT_GENERAL,
  263. };
  264. const std::array write_descriptor_sets{
  265. VkWriteDescriptorSet{
  266. .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
  267. .pNext = nullptr,
  268. .dstSet = descriptor_set,
  269. .dstBinding = 0,
  270. .dstArrayElement = 0,
  271. .descriptorCount = 1,
  272. .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
  273. .pImageInfo = &image_info_0,
  274. .pBufferInfo = nullptr,
  275. .pTexelBufferView = nullptr,
  276. },
  277. VkWriteDescriptorSet{
  278. .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
  279. .pNext = nullptr,
  280. .dstSet = descriptor_set,
  281. .dstBinding = 1,
  282. .dstArrayElement = 0,
  283. .descriptorCount = 1,
  284. .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
  285. .pImageInfo = &image_info_1,
  286. .pBufferInfo = nullptr,
  287. .pTexelBufferView = nullptr,
  288. },
  289. };
  290. device.GetLogical().UpdateDescriptorSets(write_descriptor_sets, nullptr);
  291. }
  292. void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout, const Region2D& dst_region,
  293. const Region2D& src_region) {
  294. const VkOffset2D offset{
  295. .x = std::min(dst_region.start.x, dst_region.end.x),
  296. .y = std::min(dst_region.start.y, dst_region.end.y),
  297. };
  298. const VkExtent2D extent{
  299. .width = static_cast<u32>(std::abs(dst_region.end.x - dst_region.start.x)),
  300. .height = static_cast<u32>(std::abs(dst_region.end.y - dst_region.start.y)),
  301. };
  302. const VkViewport viewport{
  303. .x = static_cast<float>(offset.x),
  304. .y = static_cast<float>(offset.y),
  305. .width = static_cast<float>(extent.width),
  306. .height = static_cast<float>(extent.height),
  307. .minDepth = 0.0f,
  308. .maxDepth = 1.0f,
  309. };
  310. // TODO: Support scissored blits
  311. const VkRect2D scissor{
  312. .offset = offset,
  313. .extent = extent,
  314. };
  315. const float scale_x = static_cast<float>(src_region.end.x - src_region.start.x);
  316. const float scale_y = static_cast<float>(src_region.end.y - src_region.start.y);
  317. const PushConstants push_constants{
  318. .tex_scale = {scale_x, scale_y},
  319. .tex_offset = {static_cast<float>(src_region.start.x),
  320. static_cast<float>(src_region.start.y)},
  321. };
  322. cmdbuf.SetViewport(0, viewport);
  323. cmdbuf.SetScissor(0, scissor);
  324. cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants);
  325. }
  326. VkExtent2D GetConversionExtent(const ImageView& src_image_view) {
  327. const auto& resolution = Settings::values.resolution_info;
  328. const bool is_rescaled = src_image_view.IsRescaled();
  329. u32 width = src_image_view.size.width;
  330. u32 height = src_image_view.size.height;
  331. return VkExtent2D{
  332. .width = is_rescaled ? resolution.ScaleUp(width) : width,
  333. .height = is_rescaled ? resolution.ScaleUp(height) : height,
  334. };
  335. }
  336. } // Anonymous namespace
  337. BlitImageHelper::BlitImageHelper(const Device& device_, Scheduler& scheduler_,
  338. StateTracker& state_tracker_, DescriptorPool& descriptor_pool)
  339. : device{device_}, scheduler{scheduler_}, state_tracker{state_tracker_},
  340. one_texture_set_layout(device.GetLogical().CreateDescriptorSetLayout(
  341. ONE_TEXTURE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO)),
  342. two_textures_set_layout(device.GetLogical().CreateDescriptorSetLayout(
  343. TWO_TEXTURES_DESCRIPTOR_SET_LAYOUT_CREATE_INFO)),
  344. one_texture_descriptor_allocator{
  345. descriptor_pool.Allocator(*one_texture_set_layout, TEXTURE_DESCRIPTOR_BANK_INFO<1>)},
  346. two_textures_descriptor_allocator{
  347. descriptor_pool.Allocator(*two_textures_set_layout, TEXTURE_DESCRIPTOR_BANK_INFO<2>)},
  348. one_texture_pipeline_layout(device.GetLogical().CreatePipelineLayout(
  349. PipelineLayoutCreateInfo(one_texture_set_layout.address()))),
  350. two_textures_pipeline_layout(device.GetLogical().CreatePipelineLayout(
  351. PipelineLayoutCreateInfo(two_textures_set_layout.address()))),
  352. full_screen_vert(BuildShader(device, FULL_SCREEN_TRIANGLE_VERT_SPV)),
  353. blit_color_to_color_frag(BuildShader(device, VULKAN_BLIT_COLOR_FLOAT_FRAG_SPV)),
  354. blit_depth_stencil_frag(BuildShader(device, VULKAN_BLIT_DEPTH_STENCIL_FRAG_SPV)),
  355. convert_depth_to_float_frag(BuildShader(device, CONVERT_DEPTH_TO_FLOAT_FRAG_SPV)),
  356. convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)),
  357. convert_abgr8_to_d24s8_frag(BuildShader(device, CONVERT_ABGR8_TO_D24S8_FRAG_SPV)),
  358. convert_d24s8_to_abgr8_frag(BuildShader(device, CONVERT_D24S8_TO_ABGR8_FRAG_SPV)),
  359. convert_s8d24_to_abgr8_frag(BuildShader(device, CONVERT_S8D24_TO_ABGR8_FRAG_SPV)),
  360. linear_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_LINEAR>)),
  361. nearest_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_NEAREST>)) {}
  362. BlitImageHelper::~BlitImageHelper() = default;
  363. void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, VkImageView src_view,
  364. const Region2D& dst_region, const Region2D& src_region,
  365. Tegra::Engines::Fermi2D::Filter filter,
  366. Tegra::Engines::Fermi2D::Operation operation) {
  367. const bool is_linear = filter == Tegra::Engines::Fermi2D::Filter::Bilinear;
  368. const BlitImagePipelineKey key{
  369. .renderpass = dst_framebuffer->RenderPass(),
  370. .operation = operation,
  371. };
  372. const VkPipelineLayout layout = *one_texture_pipeline_layout;
  373. const VkSampler sampler = is_linear ? *linear_sampler : *nearest_sampler;
  374. const VkPipeline pipeline = FindOrEmplaceColorPipeline(key);
  375. scheduler.RequestRenderpass(dst_framebuffer);
  376. scheduler.Record([this, dst_region, src_region, pipeline, layout, sampler,
  377. src_view](vk::CommandBuffer cmdbuf) {
  378. // TODO: Barriers
  379. const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit();
  380. UpdateOneTextureDescriptorSet(device, descriptor_set, sampler, src_view);
  381. cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
  382. cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
  383. nullptr);
  384. BindBlitState(cmdbuf, layout, dst_region, src_region);
  385. cmdbuf.Draw(3, 1, 0, 0);
  386. });
  387. scheduler.InvalidateState();
  388. }
  389. void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer,
  390. VkImageView src_depth_view, VkImageView src_stencil_view,
  391. const Region2D& dst_region, const Region2D& src_region,
  392. Tegra::Engines::Fermi2D::Filter filter,
  393. Tegra::Engines::Fermi2D::Operation operation) {
  394. ASSERT(filter == Tegra::Engines::Fermi2D::Filter::Point);
  395. ASSERT(operation == Tegra::Engines::Fermi2D::Operation::SrcCopy);
  396. const BlitImagePipelineKey key{
  397. .renderpass = dst_framebuffer->RenderPass(),
  398. .operation = operation,
  399. };
  400. const VkPipelineLayout layout = *two_textures_pipeline_layout;
  401. const VkSampler sampler = *nearest_sampler;
  402. const VkPipeline pipeline = FindOrEmplaceDepthStencilPipeline(key);
  403. scheduler.RequestRenderpass(dst_framebuffer);
  404. scheduler.Record([dst_region, src_region, pipeline, layout, sampler, src_depth_view,
  405. src_stencil_view, this](vk::CommandBuffer cmdbuf) {
  406. // TODO: Barriers
  407. const VkDescriptorSet descriptor_set = two_textures_descriptor_allocator.Commit();
  408. UpdateTwoTexturesDescriptorSet(device, descriptor_set, sampler, src_depth_view,
  409. src_stencil_view);
  410. cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
  411. cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
  412. nullptr);
  413. BindBlitState(cmdbuf, layout, dst_region, src_region);
  414. cmdbuf.Draw(3, 1, 0, 0);
  415. });
  416. scheduler.InvalidateState();
  417. }
  418. void BlitImageHelper::ConvertD32ToR32(const Framebuffer* dst_framebuffer,
  419. const ImageView& src_image_view) {
  420. ConvertDepthToColorPipeline(convert_d32_to_r32_pipeline, dst_framebuffer->RenderPass());
  421. Convert(*convert_d32_to_r32_pipeline, dst_framebuffer, src_image_view);
  422. }
  423. void BlitImageHelper::ConvertR32ToD32(const Framebuffer* dst_framebuffer,
  424. const ImageView& src_image_view) {
  425. ConvertColorToDepthPipeline(convert_r32_to_d32_pipeline, dst_framebuffer->RenderPass());
  426. Convert(*convert_r32_to_d32_pipeline, dst_framebuffer, src_image_view);
  427. }
  428. void BlitImageHelper::ConvertD16ToR16(const Framebuffer* dst_framebuffer,
  429. const ImageView& src_image_view) {
  430. ConvertDepthToColorPipeline(convert_d16_to_r16_pipeline, dst_framebuffer->RenderPass());
  431. Convert(*convert_d16_to_r16_pipeline, dst_framebuffer, src_image_view);
  432. }
  433. void BlitImageHelper::ConvertR16ToD16(const Framebuffer* dst_framebuffer,
  434. const ImageView& src_image_view) {
  435. ConvertColorToDepthPipeline(convert_r16_to_d16_pipeline, dst_framebuffer->RenderPass());
  436. Convert(*convert_r16_to_d16_pipeline, dst_framebuffer, src_image_view);
  437. }
  438. void BlitImageHelper::ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer,
  439. const ImageView& src_image_view) {
  440. ConvertPipelineDepthTargetEx(convert_abgr8_to_d24s8_pipeline, dst_framebuffer->RenderPass(),
  441. convert_abgr8_to_d24s8_frag);
  442. Convert(*convert_abgr8_to_d24s8_pipeline, dst_framebuffer, src_image_view);
  443. }
  444. void BlitImageHelper::ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer,
  445. ImageView& src_image_view) {
  446. ConvertPipelineColorTargetEx(convert_d24s8_to_abgr8_pipeline, dst_framebuffer->RenderPass(),
  447. convert_d24s8_to_abgr8_frag);
  448. ConvertDepthStencil(*convert_d24s8_to_abgr8_pipeline, dst_framebuffer, src_image_view);
  449. }
  450. void BlitImageHelper::ConvertS8D24ToABGR8(const Framebuffer* dst_framebuffer,
  451. ImageView& src_image_view) {
  452. ConvertPipelineColorTargetEx(convert_s8d24_to_abgr8_pipeline, dst_framebuffer->RenderPass(),
  453. convert_s8d24_to_abgr8_frag);
  454. ConvertDepthStencil(*convert_s8d24_to_abgr8_pipeline, dst_framebuffer, src_image_view);
  455. }
  456. void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
  457. const ImageView& src_image_view) {
  458. const VkPipelineLayout layout = *one_texture_pipeline_layout;
  459. const VkImageView src_view = src_image_view.Handle(Shader::TextureType::Color2D);
  460. const VkSampler sampler = *nearest_sampler;
  461. const VkExtent2D extent = GetConversionExtent(src_image_view);
  462. scheduler.RequestRenderpass(dst_framebuffer);
  463. scheduler.Record([pipeline, layout, sampler, src_view, extent, this](vk::CommandBuffer cmdbuf) {
  464. const VkOffset2D offset{
  465. .x = 0,
  466. .y = 0,
  467. };
  468. const VkViewport viewport{
  469. .x = 0.0f,
  470. .y = 0.0f,
  471. .width = static_cast<float>(extent.width),
  472. .height = static_cast<float>(extent.height),
  473. .minDepth = 0.0f,
  474. .maxDepth = 0.0f,
  475. };
  476. const VkRect2D scissor{
  477. .offset = offset,
  478. .extent = extent,
  479. };
  480. const PushConstants push_constants{
  481. .tex_scale = {viewport.width, viewport.height},
  482. .tex_offset = {0.0f, 0.0f},
  483. };
  484. const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit();
  485. UpdateOneTextureDescriptorSet(device, descriptor_set, sampler, src_view);
  486. // TODO: Barriers
  487. cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
  488. cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
  489. nullptr);
  490. cmdbuf.SetViewport(0, viewport);
  491. cmdbuf.SetScissor(0, scissor);
  492. cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants);
  493. cmdbuf.Draw(3, 1, 0, 0);
  494. });
  495. scheduler.InvalidateState();
  496. }
  497. void BlitImageHelper::ConvertDepthStencil(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
  498. ImageView& src_image_view) {
  499. const VkPipelineLayout layout = *two_textures_pipeline_layout;
  500. const VkImageView src_depth_view = src_image_view.DepthView();
  501. const VkImageView src_stencil_view = src_image_view.StencilView();
  502. const VkSampler sampler = *nearest_sampler;
  503. const VkExtent2D extent = GetConversionExtent(src_image_view);
  504. scheduler.RequestRenderpass(dst_framebuffer);
  505. scheduler.Record([pipeline, layout, sampler, src_depth_view, src_stencil_view, extent,
  506. this](vk::CommandBuffer cmdbuf) {
  507. const VkOffset2D offset{
  508. .x = 0,
  509. .y = 0,
  510. };
  511. const VkViewport viewport{
  512. .x = 0.0f,
  513. .y = 0.0f,
  514. .width = static_cast<float>(extent.width),
  515. .height = static_cast<float>(extent.height),
  516. .minDepth = 0.0f,
  517. .maxDepth = 0.0f,
  518. };
  519. const VkRect2D scissor{
  520. .offset = offset,
  521. .extent = extent,
  522. };
  523. const PushConstants push_constants{
  524. .tex_scale = {viewport.width, viewport.height},
  525. .tex_offset = {0.0f, 0.0f},
  526. };
  527. const VkDescriptorSet descriptor_set = two_textures_descriptor_allocator.Commit();
  528. UpdateTwoTexturesDescriptorSet(device, descriptor_set, sampler, src_depth_view,
  529. src_stencil_view);
  530. // TODO: Barriers
  531. cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
  532. cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
  533. nullptr);
  534. cmdbuf.SetViewport(0, viewport);
  535. cmdbuf.SetScissor(0, scissor);
  536. cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants);
  537. cmdbuf.Draw(3, 1, 0, 0);
  538. });
  539. scheduler.InvalidateState();
  540. }
  541. VkPipeline BlitImageHelper::FindOrEmplaceColorPipeline(const BlitImagePipelineKey& key) {
  542. const auto it = std::ranges::find(blit_color_keys, key);
  543. if (it != blit_color_keys.end()) {
  544. return *blit_color_pipelines[std::distance(blit_color_keys.begin(), it)];
  545. }
  546. blit_color_keys.push_back(key);
  547. const std::array stages = MakeStages(*full_screen_vert, *blit_color_to_color_frag);
  548. const VkPipelineColorBlendAttachmentState blend_attachment{
  549. .blendEnable = VK_FALSE,
  550. .srcColorBlendFactor = VK_BLEND_FACTOR_ZERO,
  551. .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO,
  552. .colorBlendOp = VK_BLEND_OP_ADD,
  553. .srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
  554. .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
  555. .alphaBlendOp = VK_BLEND_OP_ADD,
  556. .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
  557. VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
  558. };
  559. // TODO: programmable blending
  560. const VkPipelineColorBlendStateCreateInfo color_blend_create_info{
  561. .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
  562. .pNext = nullptr,
  563. .flags = 0,
  564. .logicOpEnable = VK_FALSE,
  565. .logicOp = VK_LOGIC_OP_CLEAR,
  566. .attachmentCount = 1,
  567. .pAttachments = &blend_attachment,
  568. .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f},
  569. };
  570. blit_color_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
  571. .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
  572. .pNext = nullptr,
  573. .flags = 0,
  574. .stageCount = static_cast<u32>(stages.size()),
  575. .pStages = stages.data(),
  576. .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
  577. .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
  578. .pTessellationState = nullptr,
  579. .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
  580. .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
  581. .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
  582. .pDepthStencilState = nullptr,
  583. .pColorBlendState = &color_blend_create_info,
  584. .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
  585. .layout = *one_texture_pipeline_layout,
  586. .renderPass = key.renderpass,
  587. .subpass = 0,
  588. .basePipelineHandle = VK_NULL_HANDLE,
  589. .basePipelineIndex = 0,
  590. }));
  591. return *blit_color_pipelines.back();
  592. }
  593. VkPipeline BlitImageHelper::FindOrEmplaceDepthStencilPipeline(const BlitImagePipelineKey& key) {
  594. const auto it = std::ranges::find(blit_depth_stencil_keys, key);
  595. if (it != blit_depth_stencil_keys.end()) {
  596. return *blit_depth_stencil_pipelines[std::distance(blit_depth_stencil_keys.begin(), it)];
  597. }
  598. blit_depth_stencil_keys.push_back(key);
  599. const std::array stages = MakeStages(*full_screen_vert, *blit_depth_stencil_frag);
  600. blit_depth_stencil_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
  601. .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
  602. .pNext = nullptr,
  603. .flags = 0,
  604. .stageCount = static_cast<u32>(stages.size()),
  605. .pStages = stages.data(),
  606. .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
  607. .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
  608. .pTessellationState = nullptr,
  609. .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
  610. .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
  611. .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
  612. .pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
  613. .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO,
  614. .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
  615. .layout = *two_textures_pipeline_layout,
  616. .renderPass = key.renderpass,
  617. .subpass = 0,
  618. .basePipelineHandle = VK_NULL_HANDLE,
  619. .basePipelineIndex = 0,
  620. }));
  621. return *blit_depth_stencil_pipelines.back();
  622. }
  623. void BlitImageHelper::ConvertPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass,
  624. bool is_target_depth) {
  625. if (pipeline) {
  626. return;
  627. }
  628. VkShaderModule frag_shader =
  629. is_target_depth ? *convert_float_to_depth_frag : *convert_depth_to_float_frag;
  630. const std::array stages = MakeStages(*full_screen_vert, frag_shader);
  631. pipeline = device.GetLogical().CreateGraphicsPipeline({
  632. .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
  633. .pNext = nullptr,
  634. .flags = 0,
  635. .stageCount = static_cast<u32>(stages.size()),
  636. .pStages = stages.data(),
  637. .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
  638. .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
  639. .pTessellationState = nullptr,
  640. .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
  641. .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
  642. .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
  643. .pDepthStencilState = is_target_depth ? &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO : nullptr,
  644. .pColorBlendState = is_target_depth ? &PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO
  645. : &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO,
  646. .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
  647. .layout = *one_texture_pipeline_layout,
  648. .renderPass = renderpass,
  649. .subpass = 0,
  650. .basePipelineHandle = VK_NULL_HANDLE,
  651. .basePipelineIndex = 0,
  652. });
  653. }
  654. void BlitImageHelper::ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass) {
  655. ConvertPipeline(pipeline, renderpass, false);
  656. }
  657. void BlitImageHelper::ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass) {
  658. ConvertPipeline(pipeline, renderpass, true);
  659. }
  660. void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
  661. vk::ShaderModule& module, bool single_texture,
  662. bool is_target_depth) {
  663. if (pipeline) {
  664. return;
  665. }
  666. const std::array stages = MakeStages(*full_screen_vert, *module);
  667. pipeline = device.GetLogical().CreateGraphicsPipeline({
  668. .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
  669. .pNext = nullptr,
  670. .flags = 0,
  671. .stageCount = static_cast<u32>(stages.size()),
  672. .pStages = stages.data(),
  673. .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
  674. .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
  675. .pTessellationState = nullptr,
  676. .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
  677. .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
  678. .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
  679. .pDepthStencilState = is_target_depth ? &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO : nullptr,
  680. .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO,
  681. .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
  682. .layout = single_texture ? *one_texture_pipeline_layout : *two_textures_pipeline_layout,
  683. .renderPass = renderpass,
  684. .subpass = 0,
  685. .basePipelineHandle = VK_NULL_HANDLE,
  686. .basePipelineIndex = 0,
  687. });
  688. }
  689. void BlitImageHelper::ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
  690. vk::ShaderModule& module) {
  691. ConvertPipelineEx(pipeline, renderpass, module, false, false);
  692. }
  693. void BlitImageHelper::ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
  694. vk::ShaderModule& module) {
  695. ConvertPipelineEx(pipeline, renderpass, module, true, true);
  696. }
  697. } // namespace Vulkan