blit_image.cpp 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984
  1. // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <algorithm>
  4. #include "video_core/renderer_vulkan/vk_texture_cache.h"
  5. #include "common/settings.h"
  6. #include "video_core/host_shaders/blit_color_float_frag_spv.h"
  7. #include "video_core/host_shaders/convert_abgr8_to_d24s8_frag_spv.h"
  8. #include "video_core/host_shaders/convert_d24s8_to_abgr8_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/convert_s8d24_to_abgr8_frag_spv.h"
  12. #include "video_core/host_shaders/full_screen_triangle_vert_spv.h"
  13. #include "video_core/host_shaders/vulkan_blit_depth_stencil_frag_spv.h"
  14. #include "video_core/host_shaders/vulkan_color_clear_frag_spv.h"
  15. #include "video_core/host_shaders/vulkan_color_clear_vert_spv.h"
  16. #include "video_core/host_shaders/vulkan_depthstencil_clear_frag_spv.h"
  17. #include "video_core/renderer_vulkan/blit_image.h"
  18. #include "video_core/renderer_vulkan/maxwell_to_vk.h"
  19. #include "video_core/renderer_vulkan/vk_scheduler.h"
  20. #include "video_core/renderer_vulkan/vk_shader_util.h"
  21. #include "video_core/renderer_vulkan/vk_state_tracker.h"
  22. #include "video_core/renderer_vulkan/vk_update_descriptor.h"
  23. #include "video_core/surface.h"
  24. #include "video_core/vulkan_common/vulkan_device.h"
  25. #include "video_core/vulkan_common/vulkan_wrapper.h"
  26. namespace Vulkan {
  27. using VideoCommon::ImageViewType;
  28. namespace {
  29. struct PushConstants {
  30. std::array<float, 2> tex_scale;
  31. std::array<float, 2> tex_offset;
  32. };
  33. template <u32 binding>
  34. inline constexpr VkDescriptorSetLayoutBinding TEXTURE_DESCRIPTOR_SET_LAYOUT_BINDING{
  35. .binding = binding,
  36. .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
  37. .descriptorCount = 1,
  38. .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
  39. .pImmutableSamplers = nullptr,
  40. };
  41. constexpr std::array TWO_TEXTURES_DESCRIPTOR_SET_LAYOUT_BINDINGS{
  42. TEXTURE_DESCRIPTOR_SET_LAYOUT_BINDING<0>,
  43. TEXTURE_DESCRIPTOR_SET_LAYOUT_BINDING<1>,
  44. };
  45. constexpr VkDescriptorSetLayoutCreateInfo ONE_TEXTURE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO{
  46. .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
  47. .pNext = nullptr,
  48. .flags = 0,
  49. .bindingCount = 1,
  50. .pBindings = &TEXTURE_DESCRIPTOR_SET_LAYOUT_BINDING<0>,
  51. };
  52. template <u32 num_textures>
  53. inline constexpr DescriptorBankInfo TEXTURE_DESCRIPTOR_BANK_INFO{
  54. .uniform_buffers = 0,
  55. .storage_buffers = 0,
  56. .texture_buffers = 0,
  57. .image_buffers = 0,
  58. .textures = num_textures,
  59. .images = 0,
  60. .score = 2,
  61. };
  62. constexpr VkDescriptorSetLayoutCreateInfo TWO_TEXTURES_DESCRIPTOR_SET_LAYOUT_CREATE_INFO{
  63. .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
  64. .pNext = nullptr,
  65. .flags = 0,
  66. .bindingCount = static_cast<u32>(TWO_TEXTURES_DESCRIPTOR_SET_LAYOUT_BINDINGS.size()),
  67. .pBindings = TWO_TEXTURES_DESCRIPTOR_SET_LAYOUT_BINDINGS.data(),
  68. };
  69. template <VkShaderStageFlags stageFlags, size_t size>
  70. inline constexpr VkPushConstantRange PUSH_CONSTANT_RANGE{
  71. .stageFlags = stageFlags,
  72. .offset = 0,
  73. .size = static_cast<u32>(size),
  74. };
  75. constexpr VkPipelineVertexInputStateCreateInfo PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO{
  76. .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
  77. .pNext = nullptr,
  78. .flags = 0,
  79. .vertexBindingDescriptionCount = 0,
  80. .pVertexBindingDescriptions = nullptr,
  81. .vertexAttributeDescriptionCount = 0,
  82. .pVertexAttributeDescriptions = nullptr,
  83. };
  84. constexpr VkPipelineInputAssemblyStateCreateInfo PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO{
  85. .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
  86. .pNext = nullptr,
  87. .flags = 0,
  88. .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
  89. .primitiveRestartEnable = VK_FALSE,
  90. };
  91. constexpr VkPipelineViewportStateCreateInfo PIPELINE_VIEWPORT_STATE_CREATE_INFO{
  92. .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
  93. .pNext = nullptr,
  94. .flags = 0,
  95. .viewportCount = 1,
  96. .pViewports = nullptr,
  97. .scissorCount = 1,
  98. .pScissors = nullptr,
  99. };
  100. constexpr VkPipelineRasterizationStateCreateInfo PIPELINE_RASTERIZATION_STATE_CREATE_INFO{
  101. .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
  102. .pNext = nullptr,
  103. .flags = 0,
  104. .depthClampEnable = VK_FALSE,
  105. .rasterizerDiscardEnable = VK_FALSE,
  106. .polygonMode = VK_POLYGON_MODE_FILL,
  107. .cullMode = VK_CULL_MODE_BACK_BIT,
  108. .frontFace = VK_FRONT_FACE_CLOCKWISE,
  109. .depthBiasEnable = VK_FALSE,
  110. .depthBiasConstantFactor = 0.0f,
  111. .depthBiasClamp = 0.0f,
  112. .depthBiasSlopeFactor = 0.0f,
  113. .lineWidth = 1.0f,
  114. };
  115. constexpr VkPipelineMultisampleStateCreateInfo PIPELINE_MULTISAMPLE_STATE_CREATE_INFO{
  116. .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
  117. .pNext = nullptr,
  118. .flags = 0,
  119. .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
  120. .sampleShadingEnable = VK_FALSE,
  121. .minSampleShading = 0.0f,
  122. .pSampleMask = nullptr,
  123. .alphaToCoverageEnable = VK_FALSE,
  124. .alphaToOneEnable = VK_FALSE,
  125. };
  126. constexpr std::array DYNAMIC_STATES{VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR,
  127. VK_DYNAMIC_STATE_BLEND_CONSTANTS};
  128. constexpr VkPipelineDynamicStateCreateInfo PIPELINE_DYNAMIC_STATE_CREATE_INFO{
  129. .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
  130. .pNext = nullptr,
  131. .flags = 0,
  132. .dynamicStateCount = static_cast<u32>(DYNAMIC_STATES.size()),
  133. .pDynamicStates = DYNAMIC_STATES.data(),
  134. };
  135. constexpr VkPipelineColorBlendStateCreateInfo PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO{
  136. .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
  137. .pNext = nullptr,
  138. .flags = 0,
  139. .logicOpEnable = VK_FALSE,
  140. .logicOp = VK_LOGIC_OP_CLEAR,
  141. .attachmentCount = 0,
  142. .pAttachments = nullptr,
  143. .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f},
  144. };
  145. constexpr VkPipelineColorBlendAttachmentState PIPELINE_COLOR_BLEND_ATTACHMENT_STATE{
  146. .blendEnable = VK_FALSE,
  147. .srcColorBlendFactor = VK_BLEND_FACTOR_ZERO,
  148. .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO,
  149. .colorBlendOp = VK_BLEND_OP_ADD,
  150. .srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
  151. .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
  152. .alphaBlendOp = VK_BLEND_OP_ADD,
  153. .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
  154. VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
  155. };
  156. constexpr VkPipelineColorBlendStateCreateInfo PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO{
  157. .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
  158. .pNext = nullptr,
  159. .flags = 0,
  160. .logicOpEnable = VK_FALSE,
  161. .logicOp = VK_LOGIC_OP_CLEAR,
  162. .attachmentCount = 1,
  163. .pAttachments = &PIPELINE_COLOR_BLEND_ATTACHMENT_STATE,
  164. .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f},
  165. };
  166. constexpr VkPipelineDepthStencilStateCreateInfo PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO{
  167. .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
  168. .pNext = nullptr,
  169. .flags = 0,
  170. .depthTestEnable = VK_TRUE,
  171. .depthWriteEnable = VK_TRUE,
  172. .depthCompareOp = VK_COMPARE_OP_ALWAYS,
  173. .depthBoundsTestEnable = VK_FALSE,
  174. .stencilTestEnable = VK_FALSE,
  175. .front = VkStencilOpState{},
  176. .back = VkStencilOpState{},
  177. .minDepthBounds = 0.0f,
  178. .maxDepthBounds = 0.0f,
  179. };
  180. template <VkFilter filter>
  181. inline constexpr VkSamplerCreateInfo SAMPLER_CREATE_INFO{
  182. .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
  183. .pNext = nullptr,
  184. .flags = 0,
  185. .magFilter = filter,
  186. .minFilter = filter,
  187. .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST,
  188. .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
  189. .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
  190. .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
  191. .mipLodBias = 0.0f,
  192. .anisotropyEnable = VK_FALSE,
  193. .maxAnisotropy = 0.0f,
  194. .compareEnable = VK_FALSE,
  195. .compareOp = VK_COMPARE_OP_NEVER,
  196. .minLod = 0.0f,
  197. .maxLod = 0.0f,
  198. .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE,
  199. .unnormalizedCoordinates = VK_TRUE,
  200. };
  201. constexpr VkPipelineLayoutCreateInfo PipelineLayoutCreateInfo(
  202. const VkDescriptorSetLayout* set_layout, vk::Span<VkPushConstantRange> push_constants) {
  203. return VkPipelineLayoutCreateInfo{
  204. .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
  205. .pNext = nullptr,
  206. .flags = 0,
  207. .setLayoutCount = (set_layout != nullptr ? 1u : 0u),
  208. .pSetLayouts = set_layout,
  209. .pushConstantRangeCount = push_constants.size(),
  210. .pPushConstantRanges = push_constants.data(),
  211. };
  212. }
  213. constexpr VkPipelineShaderStageCreateInfo PipelineShaderStageCreateInfo(VkShaderStageFlagBits stage,
  214. VkShaderModule shader) {
  215. return VkPipelineShaderStageCreateInfo{
  216. .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
  217. .pNext = nullptr,
  218. .flags = 0,
  219. .stage = stage,
  220. .module = shader,
  221. .pName = "main",
  222. .pSpecializationInfo = nullptr,
  223. };
  224. }
  225. constexpr std::array<VkPipelineShaderStageCreateInfo, 2> MakeStages(
  226. VkShaderModule vertex_shader, VkShaderModule fragment_shader) {
  227. return std::array{
  228. PipelineShaderStageCreateInfo(VK_SHADER_STAGE_VERTEX_BIT, vertex_shader),
  229. PipelineShaderStageCreateInfo(VK_SHADER_STAGE_FRAGMENT_BIT, fragment_shader),
  230. };
  231. }
  232. void UpdateOneTextureDescriptorSet(const Device& device, VkDescriptorSet descriptor_set,
  233. VkSampler sampler, VkImageView image_view) {
  234. const VkDescriptorImageInfo image_info{
  235. .sampler = sampler,
  236. .imageView = image_view,
  237. .imageLayout = VK_IMAGE_LAYOUT_GENERAL,
  238. };
  239. const VkWriteDescriptorSet write_descriptor_set{
  240. .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
  241. .pNext = nullptr,
  242. .dstSet = descriptor_set,
  243. .dstBinding = 0,
  244. .dstArrayElement = 0,
  245. .descriptorCount = 1,
  246. .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
  247. .pImageInfo = &image_info,
  248. .pBufferInfo = nullptr,
  249. .pTexelBufferView = nullptr,
  250. };
  251. device.GetLogical().UpdateDescriptorSets(write_descriptor_set, nullptr);
  252. }
  253. void UpdateTwoTexturesDescriptorSet(const Device& device, VkDescriptorSet descriptor_set,
  254. VkSampler sampler, VkImageView image_view_0,
  255. VkImageView image_view_1) {
  256. const VkDescriptorImageInfo image_info_0{
  257. .sampler = sampler,
  258. .imageView = image_view_0,
  259. .imageLayout = VK_IMAGE_LAYOUT_GENERAL,
  260. };
  261. const VkDescriptorImageInfo image_info_1{
  262. .sampler = sampler,
  263. .imageView = image_view_1,
  264. .imageLayout = VK_IMAGE_LAYOUT_GENERAL,
  265. };
  266. const std::array write_descriptor_sets{
  267. VkWriteDescriptorSet{
  268. .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
  269. .pNext = nullptr,
  270. .dstSet = descriptor_set,
  271. .dstBinding = 0,
  272. .dstArrayElement = 0,
  273. .descriptorCount = 1,
  274. .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
  275. .pImageInfo = &image_info_0,
  276. .pBufferInfo = nullptr,
  277. .pTexelBufferView = nullptr,
  278. },
  279. VkWriteDescriptorSet{
  280. .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
  281. .pNext = nullptr,
  282. .dstSet = descriptor_set,
  283. .dstBinding = 1,
  284. .dstArrayElement = 0,
  285. .descriptorCount = 1,
  286. .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
  287. .pImageInfo = &image_info_1,
  288. .pBufferInfo = nullptr,
  289. .pTexelBufferView = nullptr,
  290. },
  291. };
  292. device.GetLogical().UpdateDescriptorSets(write_descriptor_sets, nullptr);
  293. }
  294. void BindBlitState(vk::CommandBuffer cmdbuf, const Region2D& dst_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. cmdbuf.SetViewport(0, viewport);
  317. cmdbuf.SetScissor(0, scissor);
  318. }
  319. void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout, const Region2D& dst_region,
  320. const Region2D& src_region, const Extent3D& src_size = {1, 1, 1}) {
  321. BindBlitState(cmdbuf, dst_region);
  322. const float scale_x = static_cast<float>(src_region.end.x - src_region.start.x) /
  323. static_cast<float>(src_size.width);
  324. const float scale_y = static_cast<float>(src_region.end.y - src_region.start.y) /
  325. static_cast<float>(src_size.height);
  326. const PushConstants push_constants{
  327. .tex_scale = {scale_x, scale_y},
  328. .tex_offset = {static_cast<float>(src_region.start.x) / static_cast<float>(src_size.width),
  329. static_cast<float>(src_region.start.y) /
  330. static_cast<float>(src_size.height)},
  331. };
  332. cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants);
  333. }
  334. VkExtent2D GetConversionExtent(const ImageView& src_image_view) {
  335. const auto& resolution = Settings::values.resolution_info;
  336. const bool is_rescaled = src_image_view.IsRescaled();
  337. u32 width = src_image_view.size.width;
  338. u32 height = src_image_view.size.height;
  339. return VkExtent2D{
  340. .width = is_rescaled ? resolution.ScaleUp(width) : width,
  341. .height = is_rescaled ? resolution.ScaleUp(height) : height,
  342. };
  343. }
  344. void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayout target_layout,
  345. VkImageLayout source_layout = VK_IMAGE_LAYOUT_GENERAL) {
  346. constexpr VkFlags flags{VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
  347. VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT};
  348. const VkImageMemoryBarrier barrier{
  349. .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
  350. .pNext = nullptr,
  351. .srcAccessMask = flags,
  352. .dstAccessMask = flags,
  353. .oldLayout = source_layout,
  354. .newLayout = target_layout,
  355. .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
  356. .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
  357. .image = image,
  358. .subresourceRange{
  359. .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
  360. .baseMipLevel = 0,
  361. .levelCount = 1,
  362. .baseArrayLayer = 0,
  363. .layerCount = 1,
  364. },
  365. };
  366. cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
  367. 0, barrier);
  368. }
  369. void BeginRenderPass(vk::CommandBuffer& cmdbuf, const Framebuffer* framebuffer) {
  370. const VkRenderPass render_pass = framebuffer->RenderPass();
  371. const VkFramebuffer framebuffer_handle = framebuffer->Handle();
  372. const VkExtent2D render_area = framebuffer->RenderArea();
  373. const VkRenderPassBeginInfo renderpass_bi{
  374. .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
  375. .pNext = nullptr,
  376. .renderPass = render_pass,
  377. .framebuffer = framebuffer_handle,
  378. .renderArea{
  379. .offset{},
  380. .extent = render_area,
  381. },
  382. .clearValueCount = 0,
  383. .pClearValues = nullptr,
  384. };
  385. cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE);
  386. }
  387. } // Anonymous namespace
  388. BlitImageHelper::BlitImageHelper(const Device& device_, Scheduler& scheduler_,
  389. StateTracker& state_tracker_, DescriptorPool& descriptor_pool)
  390. : device{device_}, scheduler{scheduler_}, state_tracker{state_tracker_},
  391. one_texture_set_layout(device.GetLogical().CreateDescriptorSetLayout(
  392. ONE_TEXTURE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO)),
  393. two_textures_set_layout(device.GetLogical().CreateDescriptorSetLayout(
  394. TWO_TEXTURES_DESCRIPTOR_SET_LAYOUT_CREATE_INFO)),
  395. one_texture_descriptor_allocator{
  396. descriptor_pool.Allocator(*one_texture_set_layout, TEXTURE_DESCRIPTOR_BANK_INFO<1>)},
  397. two_textures_descriptor_allocator{
  398. descriptor_pool.Allocator(*two_textures_set_layout, TEXTURE_DESCRIPTOR_BANK_INFO<2>)},
  399. one_texture_pipeline_layout(device.GetLogical().CreatePipelineLayout(PipelineLayoutCreateInfo(
  400. one_texture_set_layout.address(),
  401. PUSH_CONSTANT_RANGE<VK_SHADER_STAGE_VERTEX_BIT, sizeof(PushConstants)>))),
  402. two_textures_pipeline_layout(
  403. device.GetLogical().CreatePipelineLayout(PipelineLayoutCreateInfo(
  404. two_textures_set_layout.address(),
  405. PUSH_CONSTANT_RANGE<VK_SHADER_STAGE_VERTEX_BIT, sizeof(PushConstants)>))),
  406. clear_color_pipeline_layout(device.GetLogical().CreatePipelineLayout(PipelineLayoutCreateInfo(
  407. nullptr, PUSH_CONSTANT_RANGE<VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(float) * 4>))),
  408. full_screen_vert(BuildShader(device, FULL_SCREEN_TRIANGLE_VERT_SPV)),
  409. blit_color_to_color_frag(BuildShader(device, BLIT_COLOR_FLOAT_FRAG_SPV)),
  410. blit_depth_stencil_frag(BuildShader(device, VULKAN_BLIT_DEPTH_STENCIL_FRAG_SPV)),
  411. clear_color_vert(BuildShader(device, VULKAN_COLOR_CLEAR_VERT_SPV)),
  412. clear_color_frag(BuildShader(device, VULKAN_COLOR_CLEAR_FRAG_SPV)),
  413. clear_stencil_frag(BuildShader(device, VULKAN_DEPTHSTENCIL_CLEAR_FRAG_SPV)),
  414. convert_depth_to_float_frag(BuildShader(device, CONVERT_DEPTH_TO_FLOAT_FRAG_SPV)),
  415. convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)),
  416. convert_abgr8_to_d24s8_frag(BuildShader(device, CONVERT_ABGR8_TO_D24S8_FRAG_SPV)),
  417. convert_d24s8_to_abgr8_frag(BuildShader(device, CONVERT_D24S8_TO_ABGR8_FRAG_SPV)),
  418. convert_s8d24_to_abgr8_frag(BuildShader(device, CONVERT_S8D24_TO_ABGR8_FRAG_SPV)),
  419. linear_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_LINEAR>)),
  420. nearest_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_NEAREST>)) {}
  421. BlitImageHelper::~BlitImageHelper() = default;
  422. void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, VkImageView src_view,
  423. const Region2D& dst_region, const Region2D& src_region,
  424. Tegra::Engines::Fermi2D::Filter filter,
  425. Tegra::Engines::Fermi2D::Operation operation) {
  426. const bool is_linear = filter == Tegra::Engines::Fermi2D::Filter::Bilinear;
  427. const BlitImagePipelineKey key{
  428. .renderpass = dst_framebuffer->RenderPass(),
  429. .operation = operation,
  430. };
  431. const VkPipelineLayout layout = *one_texture_pipeline_layout;
  432. const VkSampler sampler = is_linear ? *linear_sampler : *nearest_sampler;
  433. const VkPipeline pipeline = FindOrEmplaceColorPipeline(key);
  434. scheduler.RequestRenderpass(dst_framebuffer);
  435. scheduler.Record([this, dst_region, src_region, pipeline, layout, sampler,
  436. src_view](vk::CommandBuffer cmdbuf) {
  437. // TODO: Barriers
  438. const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit();
  439. UpdateOneTextureDescriptorSet(device, descriptor_set, sampler, src_view);
  440. cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
  441. cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
  442. nullptr);
  443. BindBlitState(cmdbuf, layout, dst_region, src_region);
  444. cmdbuf.Draw(3, 1, 0, 0);
  445. });
  446. scheduler.InvalidateState();
  447. }
  448. void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, VkImageView src_image_view,
  449. VkImage src_image, VkSampler src_sampler,
  450. const Region2D& dst_region, const Region2D& src_region,
  451. const Extent3D& src_size) {
  452. const BlitImagePipelineKey key{
  453. .renderpass = dst_framebuffer->RenderPass(),
  454. .operation = Tegra::Engines::Fermi2D::Operation::SrcCopy,
  455. };
  456. const VkPipelineLayout layout = *one_texture_pipeline_layout;
  457. const VkPipeline pipeline = FindOrEmplaceColorPipeline(key);
  458. scheduler.RequestOutsideRenderPassOperationContext();
  459. scheduler.Record([this, dst_framebuffer, src_image_view, src_image, src_sampler, dst_region,
  460. src_region, src_size, pipeline, layout](vk::CommandBuffer cmdbuf) {
  461. TransitionImageLayout(cmdbuf, src_image, VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL);
  462. BeginRenderPass(cmdbuf, dst_framebuffer);
  463. const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit();
  464. UpdateOneTextureDescriptorSet(device, descriptor_set, src_sampler, src_image_view);
  465. cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
  466. cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
  467. nullptr);
  468. BindBlitState(cmdbuf, layout, dst_region, src_region, src_size);
  469. cmdbuf.Draw(3, 1, 0, 0);
  470. cmdbuf.EndRenderPass();
  471. });
  472. }
  473. void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer,
  474. VkImageView src_depth_view, VkImageView src_stencil_view,
  475. const Region2D& dst_region, const Region2D& src_region,
  476. Tegra::Engines::Fermi2D::Filter filter,
  477. Tegra::Engines::Fermi2D::Operation operation) {
  478. if (!device.IsExtShaderStencilExportSupported()) {
  479. return;
  480. }
  481. ASSERT(filter == Tegra::Engines::Fermi2D::Filter::Point);
  482. ASSERT(operation == Tegra::Engines::Fermi2D::Operation::SrcCopy);
  483. const BlitImagePipelineKey key{
  484. .renderpass = dst_framebuffer->RenderPass(),
  485. .operation = operation,
  486. };
  487. const VkPipelineLayout layout = *two_textures_pipeline_layout;
  488. const VkSampler sampler = *nearest_sampler;
  489. const VkPipeline pipeline = FindOrEmplaceDepthStencilPipeline(key);
  490. scheduler.RequestRenderpass(dst_framebuffer);
  491. scheduler.Record([dst_region, src_region, pipeline, layout, sampler, src_depth_view,
  492. src_stencil_view, this](vk::CommandBuffer cmdbuf) {
  493. // TODO: Barriers
  494. const VkDescriptorSet descriptor_set = two_textures_descriptor_allocator.Commit();
  495. UpdateTwoTexturesDescriptorSet(device, descriptor_set, sampler, src_depth_view,
  496. src_stencil_view);
  497. cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
  498. cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
  499. nullptr);
  500. BindBlitState(cmdbuf, layout, dst_region, src_region);
  501. cmdbuf.Draw(3, 1, 0, 0);
  502. });
  503. scheduler.InvalidateState();
  504. }
  505. void BlitImageHelper::ConvertD32ToR32(const Framebuffer* dst_framebuffer,
  506. const ImageView& src_image_view) {
  507. ConvertDepthToColorPipeline(convert_d32_to_r32_pipeline, dst_framebuffer->RenderPass());
  508. Convert(*convert_d32_to_r32_pipeline, dst_framebuffer, src_image_view);
  509. }
  510. void BlitImageHelper::ConvertR32ToD32(const Framebuffer* dst_framebuffer,
  511. const ImageView& src_image_view) {
  512. ConvertColorToDepthPipeline(convert_r32_to_d32_pipeline, dst_framebuffer->RenderPass());
  513. Convert(*convert_r32_to_d32_pipeline, dst_framebuffer, src_image_view);
  514. }
  515. void BlitImageHelper::ConvertD16ToR16(const Framebuffer* dst_framebuffer,
  516. const ImageView& src_image_view) {
  517. ConvertDepthToColorPipeline(convert_d16_to_r16_pipeline, dst_framebuffer->RenderPass());
  518. Convert(*convert_d16_to_r16_pipeline, dst_framebuffer, src_image_view);
  519. }
  520. void BlitImageHelper::ConvertR16ToD16(const Framebuffer* dst_framebuffer,
  521. const ImageView& src_image_view) {
  522. ConvertColorToDepthPipeline(convert_r16_to_d16_pipeline, dst_framebuffer->RenderPass());
  523. Convert(*convert_r16_to_d16_pipeline, dst_framebuffer, src_image_view);
  524. }
  525. void BlitImageHelper::ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer,
  526. const ImageView& src_image_view) {
  527. ConvertPipelineDepthTargetEx(convert_abgr8_to_d24s8_pipeline, dst_framebuffer->RenderPass(),
  528. convert_abgr8_to_d24s8_frag);
  529. Convert(*convert_abgr8_to_d24s8_pipeline, dst_framebuffer, src_image_view);
  530. }
  531. void BlitImageHelper::ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer,
  532. ImageView& src_image_view) {
  533. ConvertPipelineColorTargetEx(convert_d24s8_to_abgr8_pipeline, dst_framebuffer->RenderPass(),
  534. convert_d24s8_to_abgr8_frag);
  535. ConvertDepthStencil(*convert_d24s8_to_abgr8_pipeline, dst_framebuffer, src_image_view);
  536. }
  537. void BlitImageHelper::ConvertS8D24ToABGR8(const Framebuffer* dst_framebuffer,
  538. ImageView& src_image_view) {
  539. ConvertPipelineColorTargetEx(convert_s8d24_to_abgr8_pipeline, dst_framebuffer->RenderPass(),
  540. convert_s8d24_to_abgr8_frag);
  541. ConvertDepthStencil(*convert_s8d24_to_abgr8_pipeline, dst_framebuffer, src_image_view);
  542. }
  543. void BlitImageHelper::ClearColor(const Framebuffer* dst_framebuffer, u8 color_mask,
  544. const std::array<f32, 4>& clear_color,
  545. const Region2D& dst_region) {
  546. const BlitImagePipelineKey key{
  547. .renderpass = dst_framebuffer->RenderPass(),
  548. .operation = Tegra::Engines::Fermi2D::Operation::BlendPremult,
  549. };
  550. const VkPipeline pipeline = FindOrEmplaceClearColorPipeline(key);
  551. const VkPipelineLayout layout = *clear_color_pipeline_layout;
  552. scheduler.RequestRenderpass(dst_framebuffer);
  553. scheduler.Record(
  554. [pipeline, layout, color_mask, clear_color, dst_region](vk::CommandBuffer cmdbuf) {
  555. cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
  556. const std::array blend_color = {
  557. (color_mask & 0x1) ? 1.0f : 0.0f, (color_mask & 0x2) ? 1.0f : 0.0f,
  558. (color_mask & 0x4) ? 1.0f : 0.0f, (color_mask & 0x8) ? 1.0f : 0.0f};
  559. cmdbuf.SetBlendConstants(blend_color.data());
  560. BindBlitState(cmdbuf, dst_region);
  561. cmdbuf.PushConstants(layout, VK_SHADER_STAGE_FRAGMENT_BIT, clear_color);
  562. cmdbuf.Draw(3, 1, 0, 0);
  563. });
  564. scheduler.InvalidateState();
  565. }
  566. void BlitImageHelper::ClearDepthStencil(const Framebuffer* dst_framebuffer, bool depth_clear,
  567. f32 clear_depth, u8 stencil_mask, u32 stencil_ref,
  568. u32 stencil_compare_mask, const Region2D& dst_region) {
  569. const BlitDepthStencilPipelineKey key{
  570. .renderpass = dst_framebuffer->RenderPass(),
  571. .depth_clear = depth_clear,
  572. .stencil_mask = stencil_mask,
  573. .stencil_compare_mask = stencil_compare_mask,
  574. .stencil_ref = stencil_ref,
  575. };
  576. const VkPipeline pipeline = FindOrEmplaceClearStencilPipeline(key);
  577. const VkPipelineLayout layout = *clear_color_pipeline_layout;
  578. scheduler.RequestRenderpass(dst_framebuffer);
  579. scheduler.Record([pipeline, layout, clear_depth, dst_region](vk::CommandBuffer cmdbuf) {
  580. constexpr std::array blend_constants{0.0f, 0.0f, 0.0f, 0.0f};
  581. cmdbuf.SetBlendConstants(blend_constants.data());
  582. cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
  583. BindBlitState(cmdbuf, dst_region);
  584. cmdbuf.PushConstants(layout, VK_SHADER_STAGE_FRAGMENT_BIT, clear_depth);
  585. cmdbuf.Draw(3, 1, 0, 0);
  586. });
  587. scheduler.InvalidateState();
  588. }
  589. void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
  590. const ImageView& src_image_view) {
  591. const VkPipelineLayout layout = *one_texture_pipeline_layout;
  592. const VkImageView src_view = src_image_view.Handle(Shader::TextureType::Color2D);
  593. const VkSampler sampler = *nearest_sampler;
  594. const VkExtent2D extent = GetConversionExtent(src_image_view);
  595. scheduler.RequestRenderpass(dst_framebuffer);
  596. scheduler.Record([pipeline, layout, sampler, src_view, extent, this](vk::CommandBuffer cmdbuf) {
  597. const VkOffset2D offset{
  598. .x = 0,
  599. .y = 0,
  600. };
  601. const VkViewport viewport{
  602. .x = 0.0f,
  603. .y = 0.0f,
  604. .width = static_cast<float>(extent.width),
  605. .height = static_cast<float>(extent.height),
  606. .minDepth = 0.0f,
  607. .maxDepth = 0.0f,
  608. };
  609. const VkRect2D scissor{
  610. .offset = offset,
  611. .extent = extent,
  612. };
  613. const PushConstants push_constants{
  614. .tex_scale = {viewport.width, viewport.height},
  615. .tex_offset = {0.0f, 0.0f},
  616. };
  617. const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit();
  618. UpdateOneTextureDescriptorSet(device, descriptor_set, sampler, src_view);
  619. // TODO: Barriers
  620. cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
  621. cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
  622. nullptr);
  623. cmdbuf.SetViewport(0, viewport);
  624. cmdbuf.SetScissor(0, scissor);
  625. cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants);
  626. cmdbuf.Draw(3, 1, 0, 0);
  627. });
  628. scheduler.InvalidateState();
  629. }
  630. void BlitImageHelper::ConvertDepthStencil(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
  631. ImageView& src_image_view) {
  632. const VkPipelineLayout layout = *two_textures_pipeline_layout;
  633. const VkImageView src_depth_view = src_image_view.DepthView();
  634. const VkImageView src_stencil_view = src_image_view.StencilView();
  635. const VkSampler sampler = *nearest_sampler;
  636. const VkExtent2D extent = GetConversionExtent(src_image_view);
  637. scheduler.RequestRenderpass(dst_framebuffer);
  638. scheduler.Record([pipeline, layout, sampler, src_depth_view, src_stencil_view, extent,
  639. this](vk::CommandBuffer cmdbuf) {
  640. const VkOffset2D offset{
  641. .x = 0,
  642. .y = 0,
  643. };
  644. const VkViewport viewport{
  645. .x = 0.0f,
  646. .y = 0.0f,
  647. .width = static_cast<float>(extent.width),
  648. .height = static_cast<float>(extent.height),
  649. .minDepth = 0.0f,
  650. .maxDepth = 0.0f,
  651. };
  652. const VkRect2D scissor{
  653. .offset = offset,
  654. .extent = extent,
  655. };
  656. const PushConstants push_constants{
  657. .tex_scale = {viewport.width, viewport.height},
  658. .tex_offset = {0.0f, 0.0f},
  659. };
  660. const VkDescriptorSet descriptor_set = two_textures_descriptor_allocator.Commit();
  661. UpdateTwoTexturesDescriptorSet(device, descriptor_set, sampler, src_depth_view,
  662. src_stencil_view);
  663. // TODO: Barriers
  664. cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
  665. cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
  666. nullptr);
  667. cmdbuf.SetViewport(0, viewport);
  668. cmdbuf.SetScissor(0, scissor);
  669. cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants);
  670. cmdbuf.Draw(3, 1, 0, 0);
  671. });
  672. scheduler.InvalidateState();
  673. }
  674. VkPipeline BlitImageHelper::FindOrEmplaceColorPipeline(const BlitImagePipelineKey& key) {
  675. const auto it = std::ranges::find(blit_color_keys, key);
  676. if (it != blit_color_keys.end()) {
  677. return *blit_color_pipelines[std::distance(blit_color_keys.begin(), it)];
  678. }
  679. blit_color_keys.push_back(key);
  680. const std::array stages = MakeStages(*full_screen_vert, *blit_color_to_color_frag);
  681. const VkPipelineColorBlendAttachmentState blend_attachment{
  682. .blendEnable = VK_FALSE,
  683. .srcColorBlendFactor = VK_BLEND_FACTOR_ZERO,
  684. .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO,
  685. .colorBlendOp = VK_BLEND_OP_ADD,
  686. .srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
  687. .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
  688. .alphaBlendOp = VK_BLEND_OP_ADD,
  689. .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
  690. VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
  691. };
  692. // TODO: programmable blending
  693. const VkPipelineColorBlendStateCreateInfo color_blend_create_info{
  694. .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
  695. .pNext = nullptr,
  696. .flags = 0,
  697. .logicOpEnable = VK_FALSE,
  698. .logicOp = VK_LOGIC_OP_CLEAR,
  699. .attachmentCount = 1,
  700. .pAttachments = &blend_attachment,
  701. .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f},
  702. };
  703. blit_color_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
  704. .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
  705. .pNext = nullptr,
  706. .flags = 0,
  707. .stageCount = static_cast<u32>(stages.size()),
  708. .pStages = stages.data(),
  709. .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
  710. .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
  711. .pTessellationState = nullptr,
  712. .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
  713. .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
  714. .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
  715. .pDepthStencilState = nullptr,
  716. .pColorBlendState = &color_blend_create_info,
  717. .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
  718. .layout = *one_texture_pipeline_layout,
  719. .renderPass = key.renderpass,
  720. .subpass = 0,
  721. .basePipelineHandle = VK_NULL_HANDLE,
  722. .basePipelineIndex = 0,
  723. }));
  724. return *blit_color_pipelines.back();
  725. }
  726. VkPipeline BlitImageHelper::FindOrEmplaceDepthStencilPipeline(const BlitImagePipelineKey& key) {
  727. const auto it = std::ranges::find(blit_depth_stencil_keys, key);
  728. if (it != blit_depth_stencil_keys.end()) {
  729. return *blit_depth_stencil_pipelines[std::distance(blit_depth_stencil_keys.begin(), it)];
  730. }
  731. blit_depth_stencil_keys.push_back(key);
  732. const std::array stages = MakeStages(*full_screen_vert, *blit_depth_stencil_frag);
  733. blit_depth_stencil_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
  734. .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
  735. .pNext = nullptr,
  736. .flags = 0,
  737. .stageCount = static_cast<u32>(stages.size()),
  738. .pStages = stages.data(),
  739. .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
  740. .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
  741. .pTessellationState = nullptr,
  742. .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
  743. .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
  744. .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
  745. .pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
  746. .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO,
  747. .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
  748. .layout = *two_textures_pipeline_layout,
  749. .renderPass = key.renderpass,
  750. .subpass = 0,
  751. .basePipelineHandle = VK_NULL_HANDLE,
  752. .basePipelineIndex = 0,
  753. }));
  754. return *blit_depth_stencil_pipelines.back();
  755. }
  756. VkPipeline BlitImageHelper::FindOrEmplaceClearColorPipeline(const BlitImagePipelineKey& key) {
  757. const auto it = std::ranges::find(clear_color_keys, key);
  758. if (it != clear_color_keys.end()) {
  759. return *clear_color_pipelines[std::distance(clear_color_keys.begin(), it)];
  760. }
  761. clear_color_keys.push_back(key);
  762. const std::array stages = MakeStages(*clear_color_vert, *clear_color_frag);
  763. const VkPipelineColorBlendAttachmentState color_blend_attachment_state{
  764. .blendEnable = VK_TRUE,
  765. .srcColorBlendFactor = VK_BLEND_FACTOR_CONSTANT_COLOR,
  766. .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR,
  767. .colorBlendOp = VK_BLEND_OP_ADD,
  768. .srcAlphaBlendFactor = VK_BLEND_FACTOR_CONSTANT_ALPHA,
  769. .dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA,
  770. .alphaBlendOp = VK_BLEND_OP_ADD,
  771. .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
  772. VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
  773. };
  774. const VkPipelineColorBlendStateCreateInfo color_blend_state_generic_create_info{
  775. .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
  776. .pNext = nullptr,
  777. .flags = 0,
  778. .logicOpEnable = VK_FALSE,
  779. .logicOp = VK_LOGIC_OP_CLEAR,
  780. .attachmentCount = 1,
  781. .pAttachments = &color_blend_attachment_state,
  782. .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f},
  783. };
  784. clear_color_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
  785. .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
  786. .pNext = nullptr,
  787. .flags = 0,
  788. .stageCount = static_cast<u32>(stages.size()),
  789. .pStages = stages.data(),
  790. .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
  791. .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
  792. .pTessellationState = nullptr,
  793. .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
  794. .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
  795. .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
  796. .pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
  797. .pColorBlendState = &color_blend_state_generic_create_info,
  798. .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
  799. .layout = *clear_color_pipeline_layout,
  800. .renderPass = key.renderpass,
  801. .subpass = 0,
  802. .basePipelineHandle = VK_NULL_HANDLE,
  803. .basePipelineIndex = 0,
  804. }));
  805. return *clear_color_pipelines.back();
  806. }
  807. VkPipeline BlitImageHelper::FindOrEmplaceClearStencilPipeline(
  808. const BlitDepthStencilPipelineKey& key) {
  809. const auto it = std::ranges::find(clear_stencil_keys, key);
  810. if (it != clear_stencil_keys.end()) {
  811. return *clear_stencil_pipelines[std::distance(clear_stencil_keys.begin(), it)];
  812. }
  813. clear_stencil_keys.push_back(key);
  814. const std::array stages = MakeStages(*clear_color_vert, *clear_stencil_frag);
  815. const auto stencil = VkStencilOpState{
  816. .failOp = VK_STENCIL_OP_KEEP,
  817. .passOp = VK_STENCIL_OP_REPLACE,
  818. .depthFailOp = VK_STENCIL_OP_KEEP,
  819. .compareOp = VK_COMPARE_OP_ALWAYS,
  820. .compareMask = key.stencil_compare_mask,
  821. .writeMask = key.stencil_mask,
  822. .reference = key.stencil_ref,
  823. };
  824. const VkPipelineDepthStencilStateCreateInfo depth_stencil_ci{
  825. .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
  826. .pNext = nullptr,
  827. .flags = 0,
  828. .depthTestEnable = key.depth_clear,
  829. .depthWriteEnable = key.depth_clear,
  830. .depthCompareOp = VK_COMPARE_OP_ALWAYS,
  831. .depthBoundsTestEnable = VK_FALSE,
  832. .stencilTestEnable = VK_TRUE,
  833. .front = stencil,
  834. .back = stencil,
  835. .minDepthBounds = 0.0f,
  836. .maxDepthBounds = 0.0f,
  837. };
  838. clear_stencil_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
  839. .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
  840. .pNext = nullptr,
  841. .flags = 0,
  842. .stageCount = static_cast<u32>(stages.size()),
  843. .pStages = stages.data(),
  844. .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
  845. .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
  846. .pTessellationState = nullptr,
  847. .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
  848. .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
  849. .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
  850. .pDepthStencilState = &depth_stencil_ci,
  851. .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO,
  852. .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
  853. .layout = *clear_color_pipeline_layout,
  854. .renderPass = key.renderpass,
  855. .subpass = 0,
  856. .basePipelineHandle = VK_NULL_HANDLE,
  857. .basePipelineIndex = 0,
  858. }));
  859. return *clear_stencil_pipelines.back();
  860. }
  861. void BlitImageHelper::ConvertPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass,
  862. bool is_target_depth) {
  863. if (pipeline) {
  864. return;
  865. }
  866. VkShaderModule frag_shader =
  867. is_target_depth ? *convert_float_to_depth_frag : *convert_depth_to_float_frag;
  868. const std::array stages = MakeStages(*full_screen_vert, frag_shader);
  869. pipeline = device.GetLogical().CreateGraphicsPipeline({
  870. .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
  871. .pNext = nullptr,
  872. .flags = 0,
  873. .stageCount = static_cast<u32>(stages.size()),
  874. .pStages = stages.data(),
  875. .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
  876. .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
  877. .pTessellationState = nullptr,
  878. .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
  879. .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
  880. .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
  881. .pDepthStencilState = is_target_depth ? &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO : nullptr,
  882. .pColorBlendState = is_target_depth ? &PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO
  883. : &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO,
  884. .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
  885. .layout = *one_texture_pipeline_layout,
  886. .renderPass = renderpass,
  887. .subpass = 0,
  888. .basePipelineHandle = VK_NULL_HANDLE,
  889. .basePipelineIndex = 0,
  890. });
  891. }
  892. void BlitImageHelper::ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass) {
  893. ConvertPipeline(pipeline, renderpass, false);
  894. }
  895. void BlitImageHelper::ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass) {
  896. ConvertPipeline(pipeline, renderpass, true);
  897. }
  898. void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
  899. vk::ShaderModule& module, bool single_texture,
  900. bool is_target_depth) {
  901. if (pipeline) {
  902. return;
  903. }
  904. const std::array stages = MakeStages(*full_screen_vert, *module);
  905. pipeline = device.GetLogical().CreateGraphicsPipeline({
  906. .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
  907. .pNext = nullptr,
  908. .flags = 0,
  909. .stageCount = static_cast<u32>(stages.size()),
  910. .pStages = stages.data(),
  911. .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
  912. .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
  913. .pTessellationState = nullptr,
  914. .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
  915. .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
  916. .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
  917. .pDepthStencilState = is_target_depth ? &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO : nullptr,
  918. .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO,
  919. .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
  920. .layout = single_texture ? *one_texture_pipeline_layout : *two_textures_pipeline_layout,
  921. .renderPass = renderpass,
  922. .subpass = 0,
  923. .basePipelineHandle = VK_NULL_HANDLE,
  924. .basePipelineIndex = 0,
  925. });
  926. }
  927. void BlitImageHelper::ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
  928. vk::ShaderModule& module) {
  929. ConvertPipelineEx(pipeline, renderpass, module, false, false);
  930. }
  931. void BlitImageHelper::ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
  932. vk::ShaderModule& module) {
  933. ConvertPipelineEx(pipeline, renderpass, module, true, true);
  934. }
  935. } // namespace Vulkan