blit_image.cpp 27 KB

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