diff options
| author | 2021-11-20 16:51:13 -0800 | |
|---|---|---|
| committer | 2021-11-20 16:51:13 -0800 | |
| commit | ea6fa044f3e55de3b542c6c1b7ca581cbf76d77e (patch) | |
| tree | 3eb75c6d43296f2a4cbb41099b4f4e787918b1a1 /src/video_core/renderer_vulkan | |
| parent | Merge pull request #7294 from vonchenplus/fix_image_update_error_when_width_t... (diff) | |
| parent | TextureCache: Refactor and fix linux compiling. (diff) | |
| download | yuzu-ea6fa044f3e55de3b542c6c1b7ca581cbf76d77e.tar.gz yuzu-ea6fa044f3e55de3b542c6c1b7ca581cbf76d77e.tar.xz yuzu-ea6fa044f3e55de3b542c6c1b7ca581cbf76d77e.zip | |
Merge pull request #7368 from FernandoS27/vulkan-conv
Fix ART Blit detection regression and add D24S8 <-> RGBA8 conv to Vulkan
Diffstat (limited to 'src/video_core/renderer_vulkan')
| -rw-r--r-- | src/video_core/renderer_vulkan/blit_image.cpp | 171 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/blit_image.h | 39 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_texture_cache.cpp | 199 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_texture_cache.h | 11 |
4 files changed, 419 insertions, 1 deletions
diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp index b3884a4f5..28b631f73 100644 --- a/src/video_core/renderer_vulkan/blit_image.cpp +++ b/src/video_core/renderer_vulkan/blit_image.cpp | |||
| @@ -4,8 +4,14 @@ | |||
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | 6 | ||
| 7 | #include "video_core/host_shaders/convert_abgr8_to_d24s8_frag_spv.h" | ||
| 8 | #include "video_core/host_shaders/convert_b10g11r11_to_d24s8_frag_spv.h" | ||
| 9 | #include "video_core/host_shaders/convert_d24s8_to_abgr8_frag_spv.h" | ||
| 10 | #include "video_core/host_shaders/convert_d24s8_to_b10g11r11_frag_spv.h" | ||
| 11 | #include "video_core/host_shaders/convert_d24s8_to_r16g16_frag_spv.h" | ||
| 7 | #include "video_core/host_shaders/convert_depth_to_float_frag_spv.h" | 12 | #include "video_core/host_shaders/convert_depth_to_float_frag_spv.h" |
| 8 | #include "video_core/host_shaders/convert_float_to_depth_frag_spv.h" | 13 | #include "video_core/host_shaders/convert_float_to_depth_frag_spv.h" |
| 14 | #include "video_core/host_shaders/convert_r16g16_to_d24s8_frag_spv.h" | ||
| 9 | #include "video_core/host_shaders/full_screen_triangle_vert_spv.h" | 15 | #include "video_core/host_shaders/full_screen_triangle_vert_spv.h" |
| 10 | #include "video_core/host_shaders/vulkan_blit_color_float_frag_spv.h" | 16 | #include "video_core/host_shaders/vulkan_blit_color_float_frag_spv.h" |
| 11 | #include "video_core/host_shaders/vulkan_blit_depth_stencil_frag_spv.h" | 17 | #include "video_core/host_shaders/vulkan_blit_depth_stencil_frag_spv.h" |
| @@ -354,6 +360,12 @@ BlitImageHelper::BlitImageHelper(const Device& device_, VKScheduler& scheduler_, | |||
| 354 | blit_color_to_color_frag(BuildShader(device, VULKAN_BLIT_COLOR_FLOAT_FRAG_SPV)), | 360 | blit_color_to_color_frag(BuildShader(device, VULKAN_BLIT_COLOR_FLOAT_FRAG_SPV)), |
| 355 | convert_depth_to_float_frag(BuildShader(device, CONVERT_DEPTH_TO_FLOAT_FRAG_SPV)), | 361 | convert_depth_to_float_frag(BuildShader(device, CONVERT_DEPTH_TO_FLOAT_FRAG_SPV)), |
| 356 | convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)), | 362 | convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)), |
| 363 | convert_abgr8_to_d24s8_frag(BuildShader(device, CONVERT_ABGR8_TO_D24S8_FRAG_SPV)), | ||
| 364 | convert_b10g11r11_to_d24s8_frag(BuildShader(device, CONVERT_B10G11R11_TO_D24S8_FRAG_SPV)), | ||
| 365 | convert_r16g16_to_d24s8_frag(BuildShader(device, CONVERT_R16G16_TO_D24S8_FRAG_SPV)), | ||
| 366 | convert_d24s8_to_abgr8_frag(BuildShader(device, CONVERT_D24S8_TO_ABGR8_FRAG_SPV)), | ||
| 367 | convert_d24s8_to_b10g11r11_frag(BuildShader(device, CONVERT_D24S8_TO_B10G11R11_FRAG_SPV)), | ||
| 368 | convert_d24s8_to_r16g16_frag(BuildShader(device, CONVERT_D24S8_TO_R16G16_FRAG_SPV)), | ||
| 357 | linear_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_LINEAR>)), | 369 | linear_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_LINEAR>)), |
| 358 | nearest_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_NEAREST>)) { | 370 | nearest_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_NEAREST>)) { |
| 359 | if (device.IsExtShaderStencilExportSupported()) { | 371 | if (device.IsExtShaderStencilExportSupported()) { |
| @@ -448,6 +460,59 @@ void BlitImageHelper::ConvertR16ToD16(const Framebuffer* dst_framebuffer, | |||
| 448 | Convert(*convert_r16_to_d16_pipeline, dst_framebuffer, src_image_view, up_scale, down_shift); | 460 | Convert(*convert_r16_to_d16_pipeline, dst_framebuffer, src_image_view, up_scale, down_shift); |
| 449 | } | 461 | } |
| 450 | 462 | ||
| 463 | void BlitImageHelper::ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer, | ||
| 464 | const ImageView& src_image_view, u32 up_scale, | ||
| 465 | u32 down_shift) { | ||
| 466 | ConvertPipelineDepthTargetEx(convert_abgr8_to_d24s8_pipeline, dst_framebuffer->RenderPass(), | ||
| 467 | convert_abgr8_to_d24s8_frag, true); | ||
| 468 | Convert(*convert_abgr8_to_d24s8_pipeline, dst_framebuffer, src_image_view, up_scale, | ||
| 469 | down_shift); | ||
| 470 | } | ||
| 471 | |||
| 472 | void BlitImageHelper::ConvertB10G11R11ToD24S8(const Framebuffer* dst_framebuffer, | ||
| 473 | const ImageView& src_image_view, u32 up_scale, | ||
| 474 | u32 down_shift) { | ||
| 475 | ConvertPipelineDepthTargetEx(convert_b10g11r11_to_d24s8_pipeline, dst_framebuffer->RenderPass(), | ||
| 476 | convert_b10g11r11_to_d24s8_frag, true); | ||
| 477 | Convert(*convert_b10g11r11_to_d24s8_pipeline, dst_framebuffer, src_image_view, up_scale, | ||
| 478 | down_shift); | ||
| 479 | } | ||
| 480 | |||
| 481 | void BlitImageHelper::ConvertR16G16ToD24S8(const Framebuffer* dst_framebuffer, | ||
| 482 | const ImageView& src_image_view, u32 up_scale, | ||
| 483 | u32 down_shift) { | ||
| 484 | ConvertPipelineDepthTargetEx(convert_r16g16_to_d24s8_pipeline, dst_framebuffer->RenderPass(), | ||
| 485 | convert_r16g16_to_d24s8_frag, true); | ||
| 486 | Convert(*convert_r16g16_to_d24s8_pipeline, dst_framebuffer, src_image_view, up_scale, | ||
| 487 | down_shift); | ||
| 488 | } | ||
| 489 | |||
| 490 | void BlitImageHelper::ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, | ||
| 491 | ImageView& src_image_view, u32 up_scale, u32 down_shift) { | ||
| 492 | ConvertPipelineColorTargetEx(convert_d24s8_to_abgr8_pipeline, dst_framebuffer->RenderPass(), | ||
| 493 | convert_d24s8_to_abgr8_frag, false); | ||
| 494 | ConvertDepthStencil(*convert_d24s8_to_abgr8_pipeline, dst_framebuffer, src_image_view, up_scale, | ||
| 495 | down_shift); | ||
| 496 | } | ||
| 497 | |||
| 498 | void BlitImageHelper::ConvertD24S8ToB10G11R11(const Framebuffer* dst_framebuffer, | ||
| 499 | ImageView& src_image_view, u32 up_scale, | ||
| 500 | u32 down_shift) { | ||
| 501 | ConvertPipelineColorTargetEx(convert_d24s8_to_b10g11r11_pipeline, dst_framebuffer->RenderPass(), | ||
| 502 | convert_d24s8_to_b10g11r11_frag, false); | ||
| 503 | ConvertDepthStencil(*convert_d24s8_to_b10g11r11_pipeline, dst_framebuffer, src_image_view, | ||
| 504 | up_scale, down_shift); | ||
| 505 | } | ||
| 506 | |||
| 507 | void BlitImageHelper::ConvertD24S8ToR16G16(const Framebuffer* dst_framebuffer, | ||
| 508 | ImageView& src_image_view, u32 up_scale, | ||
| 509 | u32 down_shift) { | ||
| 510 | ConvertPipelineColorTargetEx(convert_d24s8_to_r16g16_pipeline, dst_framebuffer->RenderPass(), | ||
| 511 | convert_d24s8_to_r16g16_frag, false); | ||
| 512 | ConvertDepthStencil(*convert_d24s8_to_r16g16_pipeline, dst_framebuffer, src_image_view, | ||
| 513 | up_scale, down_shift); | ||
| 514 | } | ||
| 515 | |||
| 451 | void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer, | 516 | void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer, |
| 452 | const ImageView& src_image_view, u32 up_scale, u32 down_shift) { | 517 | const ImageView& src_image_view, u32 up_scale, u32 down_shift) { |
| 453 | const VkPipelineLayout layout = *one_texture_pipeline_layout; | 518 | const VkPipelineLayout layout = *one_texture_pipeline_layout; |
| @@ -495,6 +560,54 @@ void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_frameb | |||
| 495 | scheduler.InvalidateState(); | 560 | scheduler.InvalidateState(); |
| 496 | } | 561 | } |
| 497 | 562 | ||
| 563 | void BlitImageHelper::ConvertDepthStencil(VkPipeline pipeline, const Framebuffer* dst_framebuffer, | ||
| 564 | ImageView& src_image_view, u32 up_scale, u32 down_shift) { | ||
| 565 | const VkPipelineLayout layout = *two_textures_pipeline_layout; | ||
| 566 | const VkImageView src_depth_view = src_image_view.DepthView(); | ||
| 567 | const VkImageView src_stencil_view = src_image_view.StencilView(); | ||
| 568 | const VkSampler sampler = *nearest_sampler; | ||
| 569 | const VkExtent2D extent{ | ||
| 570 | .width = std::max((src_image_view.size.width * up_scale) >> down_shift, 1U), | ||
| 571 | .height = std::max((src_image_view.size.height * up_scale) >> down_shift, 1U), | ||
| 572 | }; | ||
| 573 | scheduler.RequestRenderpass(dst_framebuffer); | ||
| 574 | scheduler.Record([pipeline, layout, sampler, src_depth_view, src_stencil_view, extent, up_scale, | ||
| 575 | down_shift, this](vk::CommandBuffer cmdbuf) { | ||
| 576 | const VkOffset2D offset{ | ||
| 577 | .x = 0, | ||
| 578 | .y = 0, | ||
| 579 | }; | ||
| 580 | const VkViewport viewport{ | ||
| 581 | .x = 0.0f, | ||
| 582 | .y = 0.0f, | ||
| 583 | .width = static_cast<float>(extent.width), | ||
| 584 | .height = static_cast<float>(extent.height), | ||
| 585 | .minDepth = 0.0f, | ||
| 586 | .maxDepth = 0.0f, | ||
| 587 | }; | ||
| 588 | const VkRect2D scissor{ | ||
| 589 | .offset = offset, | ||
| 590 | .extent = extent, | ||
| 591 | }; | ||
| 592 | const PushConstants push_constants{ | ||
| 593 | .tex_scale = {viewport.width, viewport.height}, | ||
| 594 | .tex_offset = {0.0f, 0.0f}, | ||
| 595 | }; | ||
| 596 | const VkDescriptorSet descriptor_set = two_textures_descriptor_allocator.Commit(); | ||
| 597 | UpdateTwoTexturesDescriptorSet(device, descriptor_set, sampler, src_depth_view, | ||
| 598 | src_stencil_view); | ||
| 599 | // TODO: Barriers | ||
| 600 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); | ||
| 601 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set, | ||
| 602 | nullptr); | ||
| 603 | cmdbuf.SetViewport(0, viewport); | ||
| 604 | cmdbuf.SetScissor(0, scissor); | ||
| 605 | cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants); | ||
| 606 | cmdbuf.Draw(3, 1, 0, 0); | ||
| 607 | }); | ||
| 608 | scheduler.InvalidateState(); | ||
| 609 | } | ||
| 610 | |||
| 498 | VkPipeline BlitImageHelper::FindOrEmplaceColorPipeline(const BlitImagePipelineKey& key) { | 611 | VkPipeline BlitImageHelper::FindOrEmplaceColorPipeline(const BlitImagePipelineKey& key) { |
| 499 | const auto it = std::ranges::find(blit_color_keys, key); | 612 | const auto it = std::ranges::find(blit_color_keys, key); |
| 500 | if (it != blit_color_keys.end()) { | 613 | if (it != blit_color_keys.end()) { |
| @@ -636,4 +749,62 @@ void BlitImageHelper::ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRend | |||
| 636 | }); | 749 | }); |
| 637 | } | 750 | } |
| 638 | 751 | ||
| 752 | void BlitImageHelper::ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass, | ||
| 753 | vk::ShaderModule& module, bool single_texture) { | ||
| 754 | if (pipeline) { | ||
| 755 | return; | ||
| 756 | } | ||
| 757 | const std::array stages = MakeStages(*full_screen_vert, *module); | ||
| 758 | pipeline = device.GetLogical().CreateGraphicsPipeline({ | ||
| 759 | .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, | ||
| 760 | .pNext = nullptr, | ||
| 761 | .flags = 0, | ||
| 762 | .stageCount = static_cast<u32>(stages.size()), | ||
| 763 | .pStages = stages.data(), | ||
| 764 | .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, | ||
| 765 | .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, | ||
| 766 | .pTessellationState = nullptr, | ||
| 767 | .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, | ||
| 768 | .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, | ||
| 769 | .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, | ||
| 770 | .pDepthStencilState = nullptr, | ||
| 771 | .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO, | ||
| 772 | .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO, | ||
| 773 | .layout = single_texture ? *one_texture_pipeline_layout : *two_textures_pipeline_layout, | ||
| 774 | .renderPass = renderpass, | ||
| 775 | .subpass = 0, | ||
| 776 | .basePipelineHandle = VK_NULL_HANDLE, | ||
| 777 | .basePipelineIndex = 0, | ||
| 778 | }); | ||
| 779 | } | ||
| 780 | |||
| 781 | void BlitImageHelper::ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass, | ||
| 782 | vk::ShaderModule& module, bool single_texture) { | ||
| 783 | if (pipeline) { | ||
| 784 | return; | ||
| 785 | } | ||
| 786 | const std::array stages = MakeStages(*full_screen_vert, *module); | ||
| 787 | pipeline = device.GetLogical().CreateGraphicsPipeline({ | ||
| 788 | .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, | ||
| 789 | .pNext = nullptr, | ||
| 790 | .flags = 0, | ||
| 791 | .stageCount = static_cast<u32>(stages.size()), | ||
| 792 | .pStages = stages.data(), | ||
| 793 | .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, | ||
| 794 | .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, | ||
| 795 | .pTessellationState = nullptr, | ||
| 796 | .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, | ||
| 797 | .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, | ||
| 798 | .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, | ||
| 799 | .pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, | ||
| 800 | .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO, | ||
| 801 | .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO, | ||
| 802 | .layout = single_texture ? *one_texture_pipeline_layout : *two_textures_pipeline_layout, | ||
| 803 | .renderPass = renderpass, | ||
| 804 | .subpass = 0, | ||
| 805 | .basePipelineHandle = VK_NULL_HANDLE, | ||
| 806 | .basePipelineIndex = 0, | ||
| 807 | }); | ||
| 808 | } | ||
| 809 | |||
| 639 | } // namespace Vulkan | 810 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h index d77f76678..cec095341 100644 --- a/src/video_core/renderer_vulkan/blit_image.h +++ b/src/video_core/renderer_vulkan/blit_image.h | |||
| @@ -56,10 +56,31 @@ public: | |||
| 56 | void ConvertR16ToD16(const Framebuffer* dst_framebuffer, const ImageView& src_image_view, | 56 | void ConvertR16ToD16(const Framebuffer* dst_framebuffer, const ImageView& src_image_view, |
| 57 | u32 up_scale, u32 down_shift); | 57 | u32 up_scale, u32 down_shift); |
| 58 | 58 | ||
| 59 | void ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer, const ImageView& src_image_view, | ||
| 60 | u32 up_scale, u32 down_shift); | ||
| 61 | |||
| 62 | void ConvertB10G11R11ToD24S8(const Framebuffer* dst_framebuffer, | ||
| 63 | const ImageView& src_image_view, u32 up_scale, u32 down_shift); | ||
| 64 | |||
| 65 | void ConvertR16G16ToD24S8(const Framebuffer* dst_framebuffer, const ImageView& src_image_view, | ||
| 66 | u32 up_scale, u32 down_shift); | ||
| 67 | |||
| 68 | void ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view, | ||
| 69 | u32 up_scale, u32 down_shift); | ||
| 70 | |||
| 71 | void ConvertD24S8ToB10G11R11(const Framebuffer* dst_framebuffer, ImageView& src_image_view, | ||
| 72 | u32 up_scale, u32 down_shift); | ||
| 73 | |||
| 74 | void ConvertD24S8ToR16G16(const Framebuffer* dst_framebuffer, ImageView& src_image_view, | ||
| 75 | u32 up_scale, u32 down_shift); | ||
| 76 | |||
| 59 | private: | 77 | private: |
| 60 | void Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer, | 78 | void Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer, |
| 61 | const ImageView& src_image_view, u32 up_scale, u32 down_shift); | 79 | const ImageView& src_image_view, u32 up_scale, u32 down_shift); |
| 62 | 80 | ||
| 81 | void ConvertDepthStencil(VkPipeline pipeline, const Framebuffer* dst_framebuffer, | ||
| 82 | ImageView& src_image_view, u32 up_scale, u32 down_shift); | ||
| 83 | |||
| 63 | [[nodiscard]] VkPipeline FindOrEmplaceColorPipeline(const BlitImagePipelineKey& key); | 84 | [[nodiscard]] VkPipeline FindOrEmplaceColorPipeline(const BlitImagePipelineKey& key); |
| 64 | 85 | ||
| 65 | [[nodiscard]] VkPipeline FindOrEmplaceDepthStencilPipeline(const BlitImagePipelineKey& key); | 86 | [[nodiscard]] VkPipeline FindOrEmplaceDepthStencilPipeline(const BlitImagePipelineKey& key); |
| @@ -68,6 +89,12 @@ private: | |||
| 68 | 89 | ||
| 69 | void ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass); | 90 | void ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass); |
| 70 | 91 | ||
| 92 | void ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass, | ||
| 93 | vk::ShaderModule& module, bool single_texture); | ||
| 94 | |||
| 95 | void ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass, | ||
| 96 | vk::ShaderModule& module, bool single_texture); | ||
| 97 | |||
| 71 | const Device& device; | 98 | const Device& device; |
| 72 | VKScheduler& scheduler; | 99 | VKScheduler& scheduler; |
| 73 | StateTracker& state_tracker; | 100 | StateTracker& state_tracker; |
| @@ -83,6 +110,12 @@ private: | |||
| 83 | vk::ShaderModule blit_depth_stencil_frag; | 110 | vk::ShaderModule blit_depth_stencil_frag; |
| 84 | vk::ShaderModule convert_depth_to_float_frag; | 111 | vk::ShaderModule convert_depth_to_float_frag; |
| 85 | vk::ShaderModule convert_float_to_depth_frag; | 112 | vk::ShaderModule convert_float_to_depth_frag; |
| 113 | vk::ShaderModule convert_abgr8_to_d24s8_frag; | ||
| 114 | vk::ShaderModule convert_b10g11r11_to_d24s8_frag; | ||
| 115 | vk::ShaderModule convert_r16g16_to_d24s8_frag; | ||
| 116 | vk::ShaderModule convert_d24s8_to_abgr8_frag; | ||
| 117 | vk::ShaderModule convert_d24s8_to_b10g11r11_frag; | ||
| 118 | vk::ShaderModule convert_d24s8_to_r16g16_frag; | ||
| 86 | vk::Sampler linear_sampler; | 119 | vk::Sampler linear_sampler; |
| 87 | vk::Sampler nearest_sampler; | 120 | vk::Sampler nearest_sampler; |
| 88 | 121 | ||
| @@ -94,6 +127,12 @@ private: | |||
| 94 | vk::Pipeline convert_r32_to_d32_pipeline; | 127 | vk::Pipeline convert_r32_to_d32_pipeline; |
| 95 | vk::Pipeline convert_d16_to_r16_pipeline; | 128 | vk::Pipeline convert_d16_to_r16_pipeline; |
| 96 | vk::Pipeline convert_r16_to_d16_pipeline; | 129 | vk::Pipeline convert_r16_to_d16_pipeline; |
| 130 | vk::Pipeline convert_abgr8_to_d24s8_pipeline; | ||
| 131 | vk::Pipeline convert_b10g11r11_to_d24s8_pipeline; | ||
| 132 | vk::Pipeline convert_r16g16_to_d24s8_pipeline; | ||
| 133 | vk::Pipeline convert_d24s8_to_abgr8_pipeline; | ||
| 134 | vk::Pipeline convert_d24s8_to_b10g11r11_pipeline; | ||
| 135 | vk::Pipeline convert_d24s8_to_r16g16_pipeline; | ||
| 97 | }; | 136 | }; |
| 98 | 137 | ||
| 99 | } // namespace Vulkan | 138 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 9bc846b94..3964424af 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include <vector> | 8 | #include <vector> |
| 9 | 9 | ||
| 10 | #include "common/bit_cast.h" | 10 | #include "common/bit_cast.h" |
| 11 | #include "common/bit_util.h" | ||
| 11 | #include "common/settings.h" | 12 | #include "common/settings.h" |
| 12 | 13 | ||
| 13 | #include "video_core/engines/fermi_2d.h" | 14 | #include "video_core/engines/fermi_2d.h" |
| @@ -313,6 +314,19 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { | |||
| 313 | }; | 314 | }; |
| 314 | } | 315 | } |
| 315 | 316 | ||
| 317 | [[nodiscard]] VkBufferImageCopy MakeBufferImageCopy(const VideoCommon::ImageCopy& copy, bool is_src, | ||
| 318 | VkImageAspectFlags aspect_mask) noexcept { | ||
| 319 | return VkBufferImageCopy{ | ||
| 320 | .bufferOffset = 0, | ||
| 321 | .bufferRowLength = 0, | ||
| 322 | .bufferImageHeight = 0, | ||
| 323 | .imageSubresource = MakeImageSubresourceLayers( | ||
| 324 | is_src ? copy.src_subresource : copy.dst_subresource, aspect_mask), | ||
| 325 | .imageOffset = MakeOffset3D(is_src ? copy.src_offset : copy.dst_offset), | ||
| 326 | .imageExtent = MakeExtent3D(copy.extent), | ||
| 327 | }; | ||
| 328 | } | ||
| 329 | |||
| 316 | [[maybe_unused]] [[nodiscard]] std::vector<VkBufferCopy> TransformBufferCopies( | 330 | [[maybe_unused]] [[nodiscard]] std::vector<VkBufferCopy> TransformBufferCopies( |
| 317 | std::span<const VideoCommon::BufferCopy> copies, size_t buffer_offset) { | 331 | std::span<const VideoCommon::BufferCopy> copies, size_t buffer_offset) { |
| 318 | std::vector<VkBufferCopy> result(copies.size()); | 332 | std::vector<VkBufferCopy> result(copies.size()); |
| @@ -759,6 +773,163 @@ StagingBufferRef TextureCacheRuntime::DownloadStagingBuffer(size_t size) { | |||
| 759 | return staging_buffer_pool.Request(size, MemoryUsage::Download); | 773 | return staging_buffer_pool.Request(size, MemoryUsage::Download); |
| 760 | } | 774 | } |
| 761 | 775 | ||
| 776 | bool TextureCacheRuntime::ShouldReinterpret(Image& dst, Image& src) { | ||
| 777 | if (VideoCore::Surface::GetFormatType(dst.info.format) == | ||
| 778 | VideoCore::Surface::SurfaceType::DepthStencil) { | ||
| 779 | return !device.IsExtShaderStencilExportSupported(); | ||
| 780 | } | ||
| 781 | return false; | ||
| 782 | } | ||
| 783 | |||
| 784 | VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) { | ||
| 785 | const auto level = (8 * sizeof(size_t)) - std::countl_zero(needed_size - 1ULL); | ||
| 786 | if (buffer_commits[level]) { | ||
| 787 | return *buffers[level]; | ||
| 788 | } | ||
| 789 | const auto new_size = Common::NextPow2(needed_size); | ||
| 790 | VkBufferUsageFlags flags = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | | ||
| 791 | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | | ||
| 792 | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT; | ||
| 793 | buffers[level] = device.GetLogical().CreateBuffer({ | ||
| 794 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | ||
| 795 | .pNext = nullptr, | ||
| 796 | .flags = 0, | ||
| 797 | .size = new_size, | ||
| 798 | .usage = flags, | ||
| 799 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | ||
| 800 | .queueFamilyIndexCount = 0, | ||
| 801 | .pQueueFamilyIndices = nullptr, | ||
| 802 | }); | ||
| 803 | buffer_commits[level] = std::make_unique<MemoryCommit>( | ||
| 804 | memory_allocator.Commit(buffers[level], MemoryUsage::DeviceLocal)); | ||
| 805 | return *buffers[level]; | ||
| 806 | } | ||
| 807 | |||
| 808 | void TextureCacheRuntime::ReinterpretImage(Image& dst, Image& src, | ||
| 809 | std::span<const VideoCommon::ImageCopy> copies) { | ||
| 810 | std::vector<VkBufferImageCopy> vk_in_copies(copies.size()); | ||
| 811 | std::vector<VkBufferImageCopy> vk_out_copies(copies.size()); | ||
| 812 | const VkImageAspectFlags src_aspect_mask = src.AspectMask(); | ||
| 813 | const VkImageAspectFlags dst_aspect_mask = dst.AspectMask(); | ||
| 814 | |||
| 815 | std::ranges::transform(copies, vk_in_copies.begin(), [src_aspect_mask](const auto& copy) { | ||
| 816 | return MakeBufferImageCopy(copy, true, src_aspect_mask); | ||
| 817 | }); | ||
| 818 | std::ranges::transform(copies, vk_out_copies.begin(), [dst_aspect_mask](const auto& copy) { | ||
| 819 | return MakeBufferImageCopy(copy, false, dst_aspect_mask); | ||
| 820 | }); | ||
| 821 | const u32 img_bpp = BytesPerBlock(src.info.format); | ||
| 822 | size_t total_size = 0; | ||
| 823 | for (const auto& copy : copies) { | ||
| 824 | total_size += copy.extent.width * copy.extent.height * copy.extent.depth * img_bpp; | ||
| 825 | } | ||
| 826 | const VkBuffer copy_buffer = GetTemporaryBuffer(total_size); | ||
| 827 | const VkImage dst_image = dst.Handle(); | ||
| 828 | const VkImage src_image = src.Handle(); | ||
| 829 | scheduler.RequestOutsideRenderPassOperationContext(); | ||
| 830 | scheduler.Record([dst_image, src_image, copy_buffer, src_aspect_mask, dst_aspect_mask, | ||
| 831 | vk_in_copies, vk_out_copies](vk::CommandBuffer cmdbuf) { | ||
| 832 | RangedBarrierRange dst_range; | ||
| 833 | RangedBarrierRange src_range; | ||
| 834 | for (const VkBufferImageCopy& copy : vk_in_copies) { | ||
| 835 | src_range.AddLayers(copy.imageSubresource); | ||
| 836 | } | ||
| 837 | for (const VkBufferImageCopy& copy : vk_out_copies) { | ||
| 838 | dst_range.AddLayers(copy.imageSubresource); | ||
| 839 | } | ||
| 840 | static constexpr VkMemoryBarrier READ_BARRIER{ | ||
| 841 | .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER, | ||
| 842 | .pNext = nullptr, | ||
| 843 | .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT, | ||
| 844 | .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT, | ||
| 845 | }; | ||
| 846 | static constexpr VkMemoryBarrier WRITE_BARRIER{ | ||
| 847 | .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER, | ||
| 848 | .pNext = nullptr, | ||
| 849 | .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, | ||
| 850 | .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, | ||
| 851 | }; | ||
| 852 | const std::array pre_barriers{ | ||
| 853 | VkImageMemoryBarrier{ | ||
| 854 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | ||
| 855 | .pNext = nullptr, | ||
| 856 | .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | | ||
| 857 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | | ||
| 858 | VK_ACCESS_TRANSFER_WRITE_BIT, | ||
| 859 | .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, | ||
| 860 | .oldLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 861 | .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, | ||
| 862 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 863 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 864 | .image = src_image, | ||
| 865 | .subresourceRange = src_range.SubresourceRange(src_aspect_mask), | ||
| 866 | }, | ||
| 867 | }; | ||
| 868 | const std::array middle_in_barrier{ | ||
| 869 | VkImageMemoryBarrier{ | ||
| 870 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | ||
| 871 | .pNext = nullptr, | ||
| 872 | .srcAccessMask = 0, | ||
| 873 | .dstAccessMask = 0, | ||
| 874 | .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, | ||
| 875 | .newLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 876 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 877 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 878 | .image = src_image, | ||
| 879 | .subresourceRange = src_range.SubresourceRange(src_aspect_mask), | ||
| 880 | }, | ||
| 881 | }; | ||
| 882 | const std::array middle_out_barrier{ | ||
| 883 | VkImageMemoryBarrier{ | ||
| 884 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | ||
| 885 | .pNext = nullptr, | ||
| 886 | .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | | ||
| 887 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | | ||
| 888 | VK_ACCESS_TRANSFER_WRITE_BIT, | ||
| 889 | .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, | ||
| 890 | .oldLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 891 | .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, | ||
| 892 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 893 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 894 | .image = dst_image, | ||
| 895 | .subresourceRange = dst_range.SubresourceRange(dst_aspect_mask), | ||
| 896 | }, | ||
| 897 | }; | ||
| 898 | const std::array post_barriers{ | ||
| 899 | VkImageMemoryBarrier{ | ||
| 900 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | ||
| 901 | .pNext = nullptr, | ||
| 902 | .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, | ||
| 903 | .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | | ||
| 904 | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | | ||
| 905 | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | | ||
| 906 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | | ||
| 907 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | | ||
| 908 | VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT, | ||
| 909 | .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, | ||
| 910 | .newLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 911 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 912 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 913 | .image = dst_image, | ||
| 914 | .subresourceRange = dst_range.SubresourceRange(dst_aspect_mask), | ||
| 915 | }, | ||
| 916 | }; | ||
| 917 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, | ||
| 918 | 0, {}, {}, pre_barriers); | ||
| 919 | |||
| 920 | cmdbuf.CopyImageToBuffer(src_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, copy_buffer, | ||
| 921 | vk_in_copies); | ||
| 922 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, | ||
| 923 | 0, WRITE_BARRIER, nullptr, middle_in_barrier); | ||
| 924 | |||
| 925 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, | ||
| 926 | 0, READ_BARRIER, {}, middle_out_barrier); | ||
| 927 | cmdbuf.CopyBufferToImage(copy_buffer, dst_image, VK_IMAGE_LAYOUT_GENERAL, vk_out_copies); | ||
| 928 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, | ||
| 929 | 0, {}, {}, post_barriers); | ||
| 930 | }); | ||
| 931 | } | ||
| 932 | |||
| 762 | void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src, | 933 | void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src, |
| 763 | const Region2D& dst_region, const Region2D& src_region, | 934 | const Region2D& dst_region, const Region2D& src_region, |
| 764 | Tegra::Engines::Fermi2D::Filter filter, | 935 | Tegra::Engines::Fermi2D::Filter filter, |
| @@ -886,6 +1057,22 @@ void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, Im | |||
| 886 | return blit_image_helper.ConvertD16ToR16(dst, src_view, up_scale, down_shift); | 1057 | return blit_image_helper.ConvertD16ToR16(dst, src_view, up_scale, down_shift); |
| 887 | } | 1058 | } |
| 888 | break; | 1059 | break; |
| 1060 | case PixelFormat::A8B8G8R8_UNORM: | ||
| 1061 | case PixelFormat::B8G8R8A8_UNORM: | ||
| 1062 | if (src_view.format == PixelFormat::S8_UINT_D24_UNORM) { | ||
| 1063 | return blit_image_helper.ConvertD24S8ToABGR8(dst, src_view, up_scale, down_shift); | ||
| 1064 | } | ||
| 1065 | break; | ||
| 1066 | case PixelFormat::B10G11R11_FLOAT: | ||
| 1067 | if (src_view.format == PixelFormat::S8_UINT_D24_UNORM) { | ||
| 1068 | return blit_image_helper.ConvertD24S8ToB10G11R11(dst, src_view, up_scale, down_shift); | ||
| 1069 | } | ||
| 1070 | break; | ||
| 1071 | case PixelFormat::R16G16_UNORM: | ||
| 1072 | if (src_view.format == PixelFormat::S8_UINT_D24_UNORM) { | ||
| 1073 | return blit_image_helper.ConvertD24S8ToR16G16(dst, src_view, up_scale, down_shift); | ||
| 1074 | } | ||
| 1075 | break; | ||
| 889 | case PixelFormat::R32_FLOAT: | 1076 | case PixelFormat::R32_FLOAT: |
| 890 | if (src_view.format == PixelFormat::D32_FLOAT) { | 1077 | if (src_view.format == PixelFormat::D32_FLOAT) { |
| 891 | return blit_image_helper.ConvertD32ToR32(dst, src_view, up_scale, down_shift); | 1078 | return blit_image_helper.ConvertD32ToR32(dst, src_view, up_scale, down_shift); |
| @@ -896,6 +1083,18 @@ void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, Im | |||
| 896 | return blit_image_helper.ConvertR16ToD16(dst, src_view, up_scale, down_shift); | 1083 | return blit_image_helper.ConvertR16ToD16(dst, src_view, up_scale, down_shift); |
| 897 | } | 1084 | } |
| 898 | break; | 1085 | break; |
| 1086 | case PixelFormat::S8_UINT_D24_UNORM: | ||
| 1087 | if (src_view.format == PixelFormat::A8B8G8R8_UNORM || | ||
| 1088 | src_view.format == PixelFormat::B8G8R8A8_UNORM) { | ||
| 1089 | return blit_image_helper.ConvertABGR8ToD24S8(dst, src_view, up_scale, down_shift); | ||
| 1090 | } | ||
| 1091 | if (src_view.format == PixelFormat::B10G11R11_FLOAT) { | ||
| 1092 | return blit_image_helper.ConvertB10G11R11ToD24S8(dst, src_view, up_scale, down_shift); | ||
| 1093 | } | ||
| 1094 | if (src_view.format == PixelFormat::R16G16_UNORM) { | ||
| 1095 | return blit_image_helper.ConvertR16G16ToD24S8(dst, src_view, up_scale, down_shift); | ||
| 1096 | } | ||
| 1097 | break; | ||
| 899 | case PixelFormat::D32_FLOAT: | 1098 | case PixelFormat::D32_FLOAT: |
| 900 | if (src_view.format == PixelFormat::R32_FLOAT) { | 1099 | if (src_view.format == PixelFormat::R32_FLOAT) { |
| 901 | return blit_image_helper.ConvertR32ToD32(dst, src_view, up_scale, down_shift); | 1100 | return blit_image_helper.ConvertR32ToD32(dst, src_view, up_scale, down_shift); |
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index f5f8f9a74..44e9dcee4 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h | |||
| @@ -61,6 +61,10 @@ public: | |||
| 61 | 61 | ||
| 62 | void CopyImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies); | 62 | void CopyImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies); |
| 63 | 63 | ||
| 64 | bool ShouldReinterpret(Image& dst, Image& src); | ||
| 65 | |||
| 66 | void ReinterpretImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies); | ||
| 67 | |||
| 64 | void ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view, bool rescaled); | 68 | void ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view, bool rescaled); |
| 65 | 69 | ||
| 66 | bool CanAccelerateImageUpload(Image&) const noexcept { | 70 | bool CanAccelerateImageUpload(Image&) const noexcept { |
| @@ -82,6 +86,8 @@ public: | |||
| 82 | return true; | 86 | return true; |
| 83 | } | 87 | } |
| 84 | 88 | ||
| 89 | [[nodiscard]] VkBuffer GetTemporaryBuffer(size_t needed_size); | ||
| 90 | |||
| 85 | const Device& device; | 91 | const Device& device; |
| 86 | VKScheduler& scheduler; | 92 | VKScheduler& scheduler; |
| 87 | MemoryAllocator& memory_allocator; | 93 | MemoryAllocator& memory_allocator; |
| @@ -90,6 +96,10 @@ public: | |||
| 90 | ASTCDecoderPass& astc_decoder_pass; | 96 | ASTCDecoderPass& astc_decoder_pass; |
| 91 | RenderPassCache& render_pass_cache; | 97 | RenderPassCache& render_pass_cache; |
| 92 | const Settings::ResolutionScalingInfo& resolution; | 98 | const Settings::ResolutionScalingInfo& resolution; |
| 99 | |||
| 100 | constexpr static size_t indexing_slots = 8 * sizeof(size_t); | ||
| 101 | std::array<vk::Buffer, indexing_slots> buffers{}; | ||
| 102 | std::array<std::unique_ptr<MemoryCommit>, indexing_slots> buffer_commits{}; | ||
| 93 | }; | 103 | }; |
| 94 | 104 | ||
| 95 | class Image : public VideoCommon::ImageBase { | 105 | class Image : public VideoCommon::ImageBase { |
| @@ -316,7 +326,6 @@ struct TextureCacheParams { | |||
| 316 | static constexpr bool FRAMEBUFFER_BLITS = false; | 326 | static constexpr bool FRAMEBUFFER_BLITS = false; |
| 317 | static constexpr bool HAS_EMULATED_COPIES = false; | 327 | static constexpr bool HAS_EMULATED_COPIES = false; |
| 318 | static constexpr bool HAS_DEVICE_MEMORY_INFO = true; | 328 | static constexpr bool HAS_DEVICE_MEMORY_INFO = true; |
| 319 | static constexpr bool HAS_PIXEL_FORMAT_CONVERSIONS = false; | ||
| 320 | 329 | ||
| 321 | using Runtime = Vulkan::TextureCacheRuntime; | 330 | using Runtime = Vulkan::TextureCacheRuntime; |
| 322 | using Image = Vulkan::Image; | 331 | using Image = Vulkan::Image; |