blit_image.cpp 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779
  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 "common/settings.h"
  6. #include "video_core/host_shaders/convert_abgr8_to_d24s8_frag_spv.h"
  7. #include "video_core/host_shaders/convert_d24s8_to_abgr8_frag_spv.h"
  8. #include "video_core/host_shaders/convert_depth_to_float_frag_spv.h"
  9. #include "video_core/host_shaders/convert_float_to_depth_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_, VKScheduler& 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. convert_depth_to_float_frag(BuildShader(device, CONVERT_DEPTH_TO_FLOAT_FRAG_SPV)),
  355. convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)),
  356. convert_abgr8_to_d24s8_frag(BuildShader(device, CONVERT_ABGR8_TO_D24S8_FRAG_SPV)),
  357. convert_d24s8_to_abgr8_frag(BuildShader(device, CONVERT_D24S8_TO_ABGR8_FRAG_SPV)),
  358. linear_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_LINEAR>)),
  359. nearest_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_NEAREST>)) {
  360. if (device.IsExtShaderStencilExportSupported()) {
  361. blit_depth_stencil_frag = BuildShader(device, VULKAN_BLIT_DEPTH_STENCIL_FRAG_SPV);
  362. }
  363. }
  364. BlitImageHelper::~BlitImageHelper() = default;
  365. void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, VkImageView src_view,
  366. const Region2D& dst_region, const Region2D& src_region,
  367. Tegra::Engines::Fermi2D::Filter filter,
  368. Tegra::Engines::Fermi2D::Operation operation) {
  369. const bool is_linear = filter == Tegra::Engines::Fermi2D::Filter::Bilinear;
  370. const BlitImagePipelineKey key{
  371. .renderpass = dst_framebuffer->RenderPass(),
  372. .operation = operation,
  373. };
  374. const VkPipelineLayout layout = *one_texture_pipeline_layout;
  375. const VkSampler sampler = is_linear ? *linear_sampler : *nearest_sampler;
  376. const VkPipeline pipeline = FindOrEmplaceColorPipeline(key);
  377. scheduler.RequestRenderpass(dst_framebuffer);
  378. scheduler.Record([this, dst_region, src_region, pipeline, layout, sampler,
  379. src_view](vk::CommandBuffer cmdbuf) {
  380. // TODO: Barriers
  381. const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit();
  382. UpdateOneTextureDescriptorSet(device, descriptor_set, sampler, src_view);
  383. cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
  384. cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
  385. nullptr);
  386. BindBlitState(cmdbuf, layout, dst_region, src_region);
  387. cmdbuf.Draw(3, 1, 0, 0);
  388. });
  389. scheduler.InvalidateState();
  390. }
  391. void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer,
  392. VkImageView src_depth_view, VkImageView src_stencil_view,
  393. const Region2D& dst_region, const Region2D& src_region,
  394. Tegra::Engines::Fermi2D::Filter filter,
  395. Tegra::Engines::Fermi2D::Operation operation) {
  396. ASSERT(filter == Tegra::Engines::Fermi2D::Filter::Point);
  397. ASSERT(operation == Tegra::Engines::Fermi2D::Operation::SrcCopy);
  398. const BlitImagePipelineKey key{
  399. .renderpass = dst_framebuffer->RenderPass(),
  400. .operation = operation,
  401. };
  402. const VkPipelineLayout layout = *two_textures_pipeline_layout;
  403. const VkSampler sampler = *nearest_sampler;
  404. const VkPipeline pipeline = FindOrEmplaceDepthStencilPipeline(key);
  405. scheduler.RequestRenderpass(dst_framebuffer);
  406. scheduler.Record([dst_region, src_region, pipeline, layout, sampler, src_depth_view,
  407. src_stencil_view, this](vk::CommandBuffer cmdbuf) {
  408. // TODO: Barriers
  409. const VkDescriptorSet descriptor_set = two_textures_descriptor_allocator.Commit();
  410. UpdateTwoTexturesDescriptorSet(device, descriptor_set, sampler, src_depth_view,
  411. src_stencil_view);
  412. cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
  413. cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
  414. nullptr);
  415. BindBlitState(cmdbuf, layout, dst_region, src_region);
  416. cmdbuf.Draw(3, 1, 0, 0);
  417. });
  418. scheduler.InvalidateState();
  419. }
  420. void BlitImageHelper::ConvertD32ToR32(const Framebuffer* dst_framebuffer,
  421. const ImageView& src_image_view) {
  422. ConvertDepthToColorPipeline(convert_d32_to_r32_pipeline, dst_framebuffer->RenderPass());
  423. Convert(*convert_d32_to_r32_pipeline, dst_framebuffer, src_image_view);
  424. }
  425. void BlitImageHelper::ConvertR32ToD32(const Framebuffer* dst_framebuffer,
  426. const ImageView& src_image_view) {
  427. ConvertColorToDepthPipeline(convert_r32_to_d32_pipeline, dst_framebuffer->RenderPass());
  428. Convert(*convert_r32_to_d32_pipeline, dst_framebuffer, src_image_view);
  429. }
  430. void BlitImageHelper::ConvertD16ToR16(const Framebuffer* dst_framebuffer,
  431. const ImageView& src_image_view) {
  432. ConvertDepthToColorPipeline(convert_d16_to_r16_pipeline, dst_framebuffer->RenderPass());
  433. Convert(*convert_d16_to_r16_pipeline, dst_framebuffer, src_image_view);
  434. }
  435. void BlitImageHelper::ConvertR16ToD16(const Framebuffer* dst_framebuffer,
  436. const ImageView& src_image_view) {
  437. ConvertColorToDepthPipeline(convert_r16_to_d16_pipeline, dst_framebuffer->RenderPass());
  438. Convert(*convert_r16_to_d16_pipeline, dst_framebuffer, src_image_view);
  439. }
  440. void BlitImageHelper::ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer,
  441. const ImageView& src_image_view) {
  442. ConvertPipelineDepthTargetEx(convert_abgr8_to_d24s8_pipeline, dst_framebuffer->RenderPass(),
  443. convert_abgr8_to_d24s8_frag);
  444. Convert(*convert_abgr8_to_d24s8_pipeline, dst_framebuffer, src_image_view);
  445. }
  446. void BlitImageHelper::ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer,
  447. ImageView& src_image_view) {
  448. ConvertPipelineColorTargetEx(convert_d24s8_to_abgr8_pipeline, dst_framebuffer->RenderPass(),
  449. convert_d24s8_to_abgr8_frag);
  450. ConvertDepthStencil(*convert_d24s8_to_abgr8_pipeline, dst_framebuffer, src_image_view);
  451. }
  452. void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
  453. const ImageView& src_image_view) {
  454. const VkPipelineLayout layout = *one_texture_pipeline_layout;
  455. const VkImageView src_view = src_image_view.Handle(Shader::TextureType::Color2D);
  456. const VkSampler sampler = *nearest_sampler;
  457. const VkExtent2D extent = GetConversionExtent(src_image_view);
  458. scheduler.RequestRenderpass(dst_framebuffer);
  459. scheduler.Record([pipeline, layout, sampler, src_view, extent, this](vk::CommandBuffer cmdbuf) {
  460. const VkOffset2D offset{
  461. .x = 0,
  462. .y = 0,
  463. };
  464. const VkViewport viewport{
  465. .x = 0.0f,
  466. .y = 0.0f,
  467. .width = static_cast<float>(extent.width),
  468. .height = static_cast<float>(extent.height),
  469. .minDepth = 0.0f,
  470. .maxDepth = 0.0f,
  471. };
  472. const VkRect2D scissor{
  473. .offset = offset,
  474. .extent = extent,
  475. };
  476. const PushConstants push_constants{
  477. .tex_scale = {viewport.width, viewport.height},
  478. .tex_offset = {0.0f, 0.0f},
  479. };
  480. const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit();
  481. UpdateOneTextureDescriptorSet(device, descriptor_set, sampler, src_view);
  482. // TODO: Barriers
  483. cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
  484. cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
  485. nullptr);
  486. cmdbuf.SetViewport(0, viewport);
  487. cmdbuf.SetScissor(0, scissor);
  488. cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants);
  489. cmdbuf.Draw(3, 1, 0, 0);
  490. });
  491. scheduler.InvalidateState();
  492. }
  493. void BlitImageHelper::ConvertColor(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
  494. ImageView& src_image_view, u32 up_scale, u32 down_shift) {
  495. const VkPipelineLayout layout = *one_texture_pipeline_layout;
  496. const VkImageView src_view = src_image_view.ColorView();
  497. const VkSampler sampler = *nearest_sampler;
  498. const VkExtent2D extent{
  499. .width = std::max((src_image_view.size.width * up_scale) >> down_shift, 1U),
  500. .height = std::max((src_image_view.size.height * up_scale) >> down_shift, 1U),
  501. };
  502. scheduler.RequestRenderpass(dst_framebuffer);
  503. scheduler.Record([pipeline, layout, sampler, src_view, extent, up_scale, down_shift,
  504. this](vk::CommandBuffer cmdbuf) {
  505. const VkOffset2D offset{
  506. .x = 0,
  507. .y = 0,
  508. };
  509. const VkViewport viewport{
  510. .x = 0.0f,
  511. .y = 0.0f,
  512. .width = static_cast<float>(extent.width),
  513. .height = static_cast<float>(extent.height),
  514. .minDepth = 0.0f,
  515. .maxDepth = 0.0f,
  516. };
  517. const VkRect2D scissor{
  518. .offset = offset,
  519. .extent = extent,
  520. };
  521. const PushConstants push_constants{
  522. .tex_scale = {viewport.width, viewport.height},
  523. .tex_offset = {0.0f, 0.0f},
  524. };
  525. const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit();
  526. UpdateOneTextureDescriptorSet(device, descriptor_set, sampler, src_view);
  527. // TODO: Barriers
  528. cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
  529. cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
  530. nullptr);
  531. cmdbuf.SetViewport(0, viewport);
  532. cmdbuf.SetScissor(0, scissor);
  533. cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants);
  534. cmdbuf.Draw(3, 1, 0, 0);
  535. });
  536. scheduler.InvalidateState();
  537. }
  538. void BlitImageHelper::ConvertDepthStencil(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
  539. ImageView& src_image_view) {
  540. const VkPipelineLayout layout = *two_textures_pipeline_layout;
  541. const VkImageView src_depth_view = src_image_view.DepthView();
  542. const VkImageView src_stencil_view = src_image_view.StencilView();
  543. const VkSampler sampler = *nearest_sampler;
  544. const VkExtent2D extent = GetConversionExtent(src_image_view);
  545. scheduler.RequestRenderpass(dst_framebuffer);
  546. scheduler.Record([pipeline, layout, sampler, src_depth_view, src_stencil_view, extent,
  547. this](vk::CommandBuffer cmdbuf) {
  548. const VkOffset2D offset{
  549. .x = 0,
  550. .y = 0,
  551. };
  552. const VkViewport viewport{
  553. .x = 0.0f,
  554. .y = 0.0f,
  555. .width = static_cast<float>(extent.width),
  556. .height = static_cast<float>(extent.height),
  557. .minDepth = 0.0f,
  558. .maxDepth = 0.0f,
  559. };
  560. const VkRect2D scissor{
  561. .offset = offset,
  562. .extent = extent,
  563. };
  564. const PushConstants push_constants{
  565. .tex_scale = {viewport.width, viewport.height},
  566. .tex_offset = {0.0f, 0.0f},
  567. };
  568. const VkDescriptorSet descriptor_set = two_textures_descriptor_allocator.Commit();
  569. UpdateTwoTexturesDescriptorSet(device, descriptor_set, sampler, src_depth_view,
  570. src_stencil_view);
  571. // TODO: Barriers
  572. cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
  573. cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
  574. nullptr);
  575. cmdbuf.SetViewport(0, viewport);
  576. cmdbuf.SetScissor(0, scissor);
  577. cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants);
  578. cmdbuf.Draw(3, 1, 0, 0);
  579. });
  580. scheduler.InvalidateState();
  581. }
  582. VkPipeline BlitImageHelper::FindOrEmplaceColorPipeline(const BlitImagePipelineKey& key) {
  583. const auto it = std::ranges::find(blit_color_keys, key);
  584. if (it != blit_color_keys.end()) {
  585. return *blit_color_pipelines[std::distance(blit_color_keys.begin(), it)];
  586. }
  587. blit_color_keys.push_back(key);
  588. const std::array stages = MakeStages(*full_screen_vert, *blit_color_to_color_frag);
  589. const VkPipelineColorBlendAttachmentState blend_attachment{
  590. .blendEnable = VK_FALSE,
  591. .srcColorBlendFactor = VK_BLEND_FACTOR_ZERO,
  592. .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO,
  593. .colorBlendOp = VK_BLEND_OP_ADD,
  594. .srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
  595. .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
  596. .alphaBlendOp = VK_BLEND_OP_ADD,
  597. .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
  598. VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
  599. };
  600. // TODO: programmable blending
  601. const VkPipelineColorBlendStateCreateInfo color_blend_create_info{
  602. .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
  603. .pNext = nullptr,
  604. .flags = 0,
  605. .logicOpEnable = VK_FALSE,
  606. .logicOp = VK_LOGIC_OP_CLEAR,
  607. .attachmentCount = 1,
  608. .pAttachments = &blend_attachment,
  609. .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f},
  610. };
  611. blit_color_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
  612. .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
  613. .pNext = nullptr,
  614. .flags = 0,
  615. .stageCount = static_cast<u32>(stages.size()),
  616. .pStages = stages.data(),
  617. .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
  618. .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
  619. .pTessellationState = nullptr,
  620. .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
  621. .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
  622. .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
  623. .pDepthStencilState = nullptr,
  624. .pColorBlendState = &color_blend_create_info,
  625. .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
  626. .layout = *one_texture_pipeline_layout,
  627. .renderPass = key.renderpass,
  628. .subpass = 0,
  629. .basePipelineHandle = VK_NULL_HANDLE,
  630. .basePipelineIndex = 0,
  631. }));
  632. return *blit_color_pipelines.back();
  633. }
  634. VkPipeline BlitImageHelper::FindOrEmplaceDepthStencilPipeline(const BlitImagePipelineKey& key) {
  635. const auto it = std::ranges::find(blit_depth_stencil_keys, key);
  636. if (it != blit_depth_stencil_keys.end()) {
  637. return *blit_depth_stencil_pipelines[std::distance(blit_depth_stencil_keys.begin(), it)];
  638. }
  639. blit_depth_stencil_keys.push_back(key);
  640. const std::array stages = MakeStages(*full_screen_vert, *blit_depth_stencil_frag);
  641. blit_depth_stencil_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
  642. .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
  643. .pNext = nullptr,
  644. .flags = 0,
  645. .stageCount = static_cast<u32>(stages.size()),
  646. .pStages = stages.data(),
  647. .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
  648. .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
  649. .pTessellationState = nullptr,
  650. .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
  651. .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
  652. .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
  653. .pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
  654. .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO,
  655. .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
  656. .layout = *two_textures_pipeline_layout,
  657. .renderPass = key.renderpass,
  658. .subpass = 0,
  659. .basePipelineHandle = VK_NULL_HANDLE,
  660. .basePipelineIndex = 0,
  661. }));
  662. return *blit_depth_stencil_pipelines.back();
  663. }
  664. void BlitImageHelper::ConvertPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass,
  665. bool is_target_depth) {
  666. if (pipeline) {
  667. return;
  668. }
  669. VkShaderModule frag_shader =
  670. is_target_depth ? *convert_float_to_depth_frag : *convert_depth_to_float_frag;
  671. const std::array stages = MakeStages(*full_screen_vert, frag_shader);
  672. pipeline = device.GetLogical().CreateGraphicsPipeline({
  673. .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
  674. .pNext = nullptr,
  675. .flags = 0,
  676. .stageCount = static_cast<u32>(stages.size()),
  677. .pStages = stages.data(),
  678. .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
  679. .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
  680. .pTessellationState = nullptr,
  681. .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
  682. .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
  683. .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
  684. .pDepthStencilState = is_target_depth ? &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO : nullptr,
  685. .pColorBlendState = is_target_depth ? &PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO
  686. : &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO,
  687. .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
  688. .layout = *one_texture_pipeline_layout,
  689. .renderPass = renderpass,
  690. .subpass = 0,
  691. .basePipelineHandle = VK_NULL_HANDLE,
  692. .basePipelineIndex = 0,
  693. });
  694. }
  695. void BlitImageHelper::ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass) {
  696. ConvertPipeline(pipeline, renderpass, false);
  697. }
  698. void BlitImageHelper::ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass) {
  699. ConvertPipeline(pipeline, renderpass, true);
  700. }
  701. void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
  702. vk::ShaderModule& module, bool single_texture,
  703. bool is_target_depth) {
  704. if (pipeline) {
  705. return;
  706. }
  707. const std::array stages = MakeStages(*full_screen_vert, *module);
  708. pipeline = device.GetLogical().CreateGraphicsPipeline({
  709. .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
  710. .pNext = nullptr,
  711. .flags = 0,
  712. .stageCount = static_cast<u32>(stages.size()),
  713. .pStages = stages.data(),
  714. .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
  715. .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
  716. .pTessellationState = nullptr,
  717. .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
  718. .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
  719. .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
  720. .pDepthStencilState = is_target_depth ? &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO : nullptr,
  721. .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO,
  722. .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
  723. .layout = single_texture ? *one_texture_pipeline_layout : *two_textures_pipeline_layout,
  724. .renderPass = renderpass,
  725. .subpass = 0,
  726. .basePipelineHandle = VK_NULL_HANDLE,
  727. .basePipelineIndex = 0,
  728. });
  729. }
  730. void BlitImageHelper::ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
  731. vk::ShaderModule& module) {
  732. ConvertPipelineEx(pipeline, renderpass, module, false, false);
  733. }
  734. void BlitImageHelper::ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
  735. vk::ShaderModule& module) {
  736. ConvertPipelineEx(pipeline, renderpass, module, true, true);
  737. }
  738. } // namespace Vulkan