blit_image.cpp 34 KB

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