summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/video_core/CMakeLists.txt6
-rw-r--r--src/video_core/renderer_vulkan/blit_image.cpp3
-rw-r--r--src/video_core/renderer_vulkan/maxwell_to_vk.cpp20
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp18
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.h5
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.cpp3
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp5
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp7
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp23
-rw-r--r--src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp16
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp4
-rw-r--r--src/video_core/surface.cpp22
-rw-r--r--src/video_core/surface.h2
-rw-r--r--src/video_core/texture_cache/decode_bc.cpp129
-rw-r--r--src/video_core/texture_cache/decode_bc.h (renamed from src/video_core/texture_cache/decode_bc4.h)6
-rw-r--r--src/video_core/texture_cache/decode_bc4.cpp96
-rw-r--r--src/video_core/texture_cache/util.cpp24
-rw-r--r--src/video_core/textures/bcn.cpp1
-rw-r--r--src/video_core/textures/bcn.h9
-rw-r--r--src/video_core/vulkan_common/vulkan_debug_callback.cpp40
-rw-r--r--src/video_core/vulkan_common/vulkan_debug_callback.h4
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp6
-rw-r--r--src/video_core/vulkan_common/vulkan_device.h35
-rw-r--r--src/video_core/vulkan_common/vulkan_instance.cpp58
-rw-r--r--src/video_core/vulkan_common/vulkan_wrapper.cpp14
-rw-r--r--src/video_core/vulkan_common/vulkan_wrapper.h9
26 files changed, 392 insertions, 173 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index e9e6f278d..3b2fe01da 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -220,8 +220,8 @@ add_library(video_core STATIC
220 surface.h 220 surface.h
221 texture_cache/accelerated_swizzle.cpp 221 texture_cache/accelerated_swizzle.cpp
222 texture_cache/accelerated_swizzle.h 222 texture_cache/accelerated_swizzle.h
223 texture_cache/decode_bc4.cpp 223 texture_cache/decode_bc.cpp
224 texture_cache/decode_bc4.h 224 texture_cache/decode_bc.h
225 texture_cache/descriptor_table.h 225 texture_cache/descriptor_table.h
226 texture_cache/formatter.cpp 226 texture_cache/formatter.cpp
227 texture_cache/formatter.h 227 texture_cache/formatter.h
@@ -279,7 +279,7 @@ add_library(video_core STATIC
279create_target_directory_groups(video_core) 279create_target_directory_groups(video_core)
280 280
281target_link_libraries(video_core PUBLIC common core) 281target_link_libraries(video_core PUBLIC common core)
282target_link_libraries(video_core PUBLIC glad shader_recompiler stb) 282target_link_libraries(video_core PUBLIC glad shader_recompiler stb bc_decoder)
283 283
284if (YUZU_USE_BUNDLED_FFMPEG AND NOT (WIN32 OR ANDROID)) 284if (YUZU_USE_BUNDLED_FFMPEG AND NOT (WIN32 OR ANDROID))
285 add_dependencies(video_core ffmpeg-build) 285 add_dependencies(video_core ffmpeg-build)
diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp
index cf2964a3f..28d4b15a0 100644
--- a/src/video_core/renderer_vulkan/blit_image.cpp
+++ b/src/video_core/renderer_vulkan/blit_image.cpp
@@ -495,6 +495,9 @@ void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer,
495 const Region2D& dst_region, const Region2D& src_region, 495 const Region2D& dst_region, const Region2D& src_region,
496 Tegra::Engines::Fermi2D::Filter filter, 496 Tegra::Engines::Fermi2D::Filter filter,
497 Tegra::Engines::Fermi2D::Operation operation) { 497 Tegra::Engines::Fermi2D::Operation operation) {
498 if (!device.IsExtShaderStencilExportSupported()) {
499 return;
500 }
498 ASSERT(filter == Tegra::Engines::Fermi2D::Filter::Point); 501 ASSERT(filter == Tegra::Engines::Fermi2D::Filter::Point);
499 ASSERT(operation == Tegra::Engines::Fermi2D::Operation::SrcCopy); 502 ASSERT(operation == Tegra::Engines::Fermi2D::Operation::SrcCopy);
500 const BlitImagePipelineKey key{ 503 const BlitImagePipelineKey key{
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
index 9a0b10568..a8540339d 100644
--- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
+++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
@@ -259,6 +259,26 @@ FormatInfo SurfaceFormat(const Device& device, FormatType format_type, bool with
259 break; 259 break;
260 } 260 }
261 } 261 }
262 // Transcode on hardware that doesn't support BCn natively
263 if (!device.IsOptimalBcnSupported() && VideoCore::Surface::IsPixelFormatBCn(pixel_format)) {
264 const bool is_srgb = with_srgb && VideoCore::Surface::IsPixelFormatSRGB(pixel_format);
265 if (pixel_format == PixelFormat::BC4_SNORM) {
266 tuple.format = VK_FORMAT_R8_SNORM;
267 } else if (pixel_format == PixelFormat::BC4_UNORM) {
268 tuple.format = VK_FORMAT_R8_UNORM;
269 } else if (pixel_format == PixelFormat::BC5_SNORM) {
270 tuple.format = VK_FORMAT_R8G8_SNORM;
271 } else if (pixel_format == PixelFormat::BC5_UNORM) {
272 tuple.format = VK_FORMAT_R8G8_UNORM;
273 } else if (pixel_format == PixelFormat::BC6H_SFLOAT ||
274 pixel_format == PixelFormat::BC6H_UFLOAT) {
275 tuple.format = VK_FORMAT_R16G16B16A16_SFLOAT;
276 } else if (is_srgb) {
277 tuple.format = VK_FORMAT_A8B8G8R8_SRGB_PACK32;
278 } else {
279 tuple.format = VK_FORMAT_A8B8G8R8_UNORM_PACK32;
280 }
281 }
262 const bool attachable = (tuple.usage & Attachable) != 0; 282 const bool attachable = (tuple.usage & Attachable) != 0;
263 const bool storage = (tuple.usage & Storage) != 0; 283 const bool storage = (tuple.usage & Storage) != 0;
264 284
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index ddf28ca28..454bb66a4 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -12,6 +12,7 @@
12#include <fmt/format.h> 12#include <fmt/format.h>
13 13
14#include "common/logging/log.h" 14#include "common/logging/log.h"
15#include "common/polyfill_ranges.h"
15#include "common/scope_exit.h" 16#include "common/scope_exit.h"
16#include "common/settings.h" 17#include "common/settings.h"
17#include "common/telemetry.h" 18#include "common/telemetry.h"
@@ -65,6 +66,21 @@ std::string BuildCommaSeparatedExtensions(
65 return fmt::format("{}", fmt::join(available_extensions, ",")); 66 return fmt::format("{}", fmt::join(available_extensions, ","));
66} 67}
67 68
69DebugCallback MakeDebugCallback(const vk::Instance& instance, const vk::InstanceDispatch& dld) {
70 if (!Settings::values.renderer_debug) {
71 return DebugCallback{};
72 }
73 const std::optional properties = vk::EnumerateInstanceExtensionProperties(dld);
74 const auto it = std::ranges::find_if(*properties, [](const auto& prop) {
75 return std::strcmp(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, prop.extensionName) == 0;
76 });
77 if (it != properties->end()) {
78 return CreateDebugUtilsCallback(instance);
79 } else {
80 return CreateDebugReportCallback(instance);
81 }
82}
83
68} // Anonymous namespace 84} // Anonymous namespace
69 85
70Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dld, 86Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dld,
@@ -87,7 +103,7 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_,
87 cpu_memory(cpu_memory_), gpu(gpu_), library(OpenLibrary(context.get())), 103 cpu_memory(cpu_memory_), gpu(gpu_), library(OpenLibrary(context.get())),
88 instance(CreateInstance(*library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type, 104 instance(CreateInstance(*library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type,
89 Settings::values.renderer_debug.GetValue())), 105 Settings::values.renderer_debug.GetValue())),
90 debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr), 106 debug_callback(MakeDebugCallback(instance, dld)),
91 surface(CreateSurface(instance, render_window.GetWindowInfo())), 107 surface(CreateSurface(instance, render_window.GetWindowInfo())),
92 device(CreateDevice(instance, dld, *surface)), memory_allocator(device), state_tracker(), 108 device(CreateDevice(instance, dld, *surface)), memory_allocator(device), state_tracker(),
93 scheduler(device, state_tracker), 109 scheduler(device, state_tracker),
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h
index b2e8cbd1b..ca22c0baa 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.h
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.h
@@ -5,6 +5,7 @@
5 5
6#include <memory> 6#include <memory>
7#include <string> 7#include <string>
8#include <variant>
8 9
9#include "common/dynamic_library.h" 10#include "common/dynamic_library.h"
10#include "video_core/renderer_base.h" 11#include "video_core/renderer_base.h"
@@ -33,6 +34,8 @@ class GPU;
33 34
34namespace Vulkan { 35namespace Vulkan {
35 36
37using DebugCallback = std::variant<vk::DebugUtilsMessenger, vk::DebugReportCallback>;
38
36Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dld, 39Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dld,
37 VkSurfaceKHR surface); 40 VkSurfaceKHR surface);
38 41
@@ -71,7 +74,7 @@ private:
71 vk::InstanceDispatch dld; 74 vk::InstanceDispatch dld;
72 75
73 vk::Instance instance; 76 vk::Instance instance;
74 vk::DebugUtilsMessenger debug_callback; 77 DebugCallback debug_callback;
75 vk::SurfaceKHR surface; 78 vk::SurfaceKHR surface;
76 79
77 ScreenInfo screen_info; 80 ScreenInfo screen_info;
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
index 660f7c9ff..b72f95235 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
@@ -590,7 +590,8 @@ void BufferCacheRuntime::ReserveNullBuffer() {
590 .pNext = nullptr, 590 .pNext = nullptr,
591 .flags = 0, 591 .flags = 0,
592 .size = 4, 592 .size = 4,
593 .usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, 593 .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
594 VK_BUFFER_USAGE_TRANSFER_DST_BIT,
594 .sharingMode = VK_SHARING_MODE_EXCLUSIVE, 595 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
595 .queueFamilyIndexCount = 0, 596 .queueFamilyIndexCount = 0,
596 .pQueueFamilyIndices = nullptr, 597 .pQueueFamilyIndices = nullptr,
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
index c1595642e..ad35cacac 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
@@ -652,13 +652,14 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
652 .pNext = nullptr, 652 .pNext = nullptr,
653 .negativeOneToOne = key.state.ndc_minus_one_to_one.Value() != 0 ? VK_TRUE : VK_FALSE, 653 .negativeOneToOne = key.state.ndc_minus_one_to_one.Value() != 0 ? VK_TRUE : VK_FALSE,
654 }; 654 };
655 const u32 num_viewports = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports);
655 VkPipelineViewportStateCreateInfo viewport_ci{ 656 VkPipelineViewportStateCreateInfo viewport_ci{
656 .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, 657 .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
657 .pNext = nullptr, 658 .pNext = nullptr,
658 .flags = 0, 659 .flags = 0,
659 .viewportCount = Maxwell::NumViewports, 660 .viewportCount = num_viewports,
660 .pViewports = nullptr, 661 .pViewports = nullptr,
661 .scissorCount = Maxwell::NumViewports, 662 .scissorCount = num_viewports,
662 .pScissors = nullptr, 663 .pScissors = nullptr,
663 }; 664 };
664 if (device.IsNvViewportSwizzleSupported()) { 665 if (device.IsNvViewportSwizzleSupported()) {
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 9f316113c..d600c4e61 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -309,7 +309,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device
309 .support_int16 = device.IsShaderInt16Supported(), 309 .support_int16 = device.IsShaderInt16Supported(),
310 .support_int64 = device.IsShaderInt64Supported(), 310 .support_int64 = device.IsShaderInt64Supported(),
311 .support_vertex_instance_id = false, 311 .support_vertex_instance_id = false,
312 .support_float_controls = true, 312 .support_float_controls = device.IsKhrShaderFloatControlsSupported(),
313 .support_separate_denorm_behavior = 313 .support_separate_denorm_behavior =
314 float_control.denormBehaviorIndependence == VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL, 314 float_control.denormBehaviorIndependence == VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL,
315 .support_separate_rounding_mode = 315 .support_separate_rounding_mode =
@@ -325,12 +325,13 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device
325 .support_fp64_signed_zero_nan_preserve = 325 .support_fp64_signed_zero_nan_preserve =
326 float_control.shaderSignedZeroInfNanPreserveFloat64 != VK_FALSE, 326 float_control.shaderSignedZeroInfNanPreserveFloat64 != VK_FALSE,
327 .support_explicit_workgroup_layout = device.IsKhrWorkgroupMemoryExplicitLayoutSupported(), 327 .support_explicit_workgroup_layout = device.IsKhrWorkgroupMemoryExplicitLayoutSupported(),
328 .support_vote = true, 328 .support_vote = device.IsSubgroupFeatureSupported(VK_SUBGROUP_FEATURE_VOTE_BIT),
329 .support_viewport_index_layer_non_geometry = 329 .support_viewport_index_layer_non_geometry =
330 device.IsExtShaderViewportIndexLayerSupported(), 330 device.IsExtShaderViewportIndexLayerSupported(),
331 .support_viewport_mask = device.IsNvViewportArray2Supported(), 331 .support_viewport_mask = device.IsNvViewportArray2Supported(),
332 .support_typeless_image_loads = device.IsFormatlessImageLoadSupported(), 332 .support_typeless_image_loads = device.IsFormatlessImageLoadSupported(),
333 .support_demote_to_helper_invocation = true, 333 .support_demote_to_helper_invocation =
334 device.IsExtShaderDemoteToHelperInvocationSupported(),
334 .support_int64_atomics = device.IsExtShaderAtomicInt64Supported(), 335 .support_int64_atomics = device.IsExtShaderAtomicInt64Supported(),
335 .support_derivative_control = true, 336 .support_derivative_control = true,
336 .support_geometry_shader_passthrough = device.IsNvGeometryShaderPassthroughSupported(), 337 .support_geometry_shader_passthrough = device.IsNvGeometryShaderPassthroughSupported(),
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index 84e3a30cc..f7c0d939a 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -315,7 +315,14 @@ void RasterizerVulkan::Clear(u32 layer_count) {
315 FlushWork(); 315 FlushWork();
316 gpu_memory->FlushCaching(); 316 gpu_memory->FlushCaching();
317 317
318#if ANDROID
319 if (Settings::IsGPULevelHigh()) {
320 // This is problematic on Android, disable on GPU Normal.
321 query_cache.UpdateCounters();
322 }
323#else
318 query_cache.UpdateCounters(); 324 query_cache.UpdateCounters();
325#endif
319 326
320 auto& regs = maxwell3d->regs; 327 auto& regs = maxwell3d->regs;
321 const bool use_color = regs.clear_surface.R || regs.clear_surface.G || regs.clear_surface.B || 328 const bool use_color = regs.clear_surface.R || regs.clear_surface.G || regs.clear_surface.B ||
@@ -925,7 +932,7 @@ void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& reg
925 } 932 }
926 const bool is_rescaling{texture_cache.IsRescaling()}; 933 const bool is_rescaling{texture_cache.IsRescaling()};
927 const float scale = is_rescaling ? Settings::values.resolution_info.up_factor : 1.0f; 934 const float scale = is_rescaling ? Settings::values.resolution_info.up_factor : 1.0f;
928 const std::array viewports{ 935 const std::array viewport_list{
929 GetViewportState(device, regs, 0, scale), GetViewportState(device, regs, 1, scale), 936 GetViewportState(device, regs, 0, scale), GetViewportState(device, regs, 1, scale),
930 GetViewportState(device, regs, 2, scale), GetViewportState(device, regs, 3, scale), 937 GetViewportState(device, regs, 2, scale), GetViewportState(device, regs, 3, scale),
931 GetViewportState(device, regs, 4, scale), GetViewportState(device, regs, 5, scale), 938 GetViewportState(device, regs, 4, scale), GetViewportState(device, regs, 5, scale),
@@ -935,7 +942,11 @@ void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& reg
935 GetViewportState(device, regs, 12, scale), GetViewportState(device, regs, 13, scale), 942 GetViewportState(device, regs, 12, scale), GetViewportState(device, regs, 13, scale),
936 GetViewportState(device, regs, 14, scale), GetViewportState(device, regs, 15, scale), 943 GetViewportState(device, regs, 14, scale), GetViewportState(device, regs, 15, scale),
937 }; 944 };
938 scheduler.Record([viewports](vk::CommandBuffer cmdbuf) { cmdbuf.SetViewport(0, viewports); }); 945 scheduler.Record([this, viewport_list](vk::CommandBuffer cmdbuf) {
946 const u32 num_viewports = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports);
947 const vk::Span<VkViewport> viewports(viewport_list.data(), num_viewports);
948 cmdbuf.SetViewport(0, viewports);
949 });
939} 950}
940 951
941void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs) { 952void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs) {
@@ -948,7 +959,7 @@ void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs
948 up_scale = Settings::values.resolution_info.up_scale; 959 up_scale = Settings::values.resolution_info.up_scale;
949 down_shift = Settings::values.resolution_info.down_shift; 960 down_shift = Settings::values.resolution_info.down_shift;
950 } 961 }
951 const std::array scissors{ 962 const std::array scissor_list{
952 GetScissorState(regs, 0, up_scale, down_shift), 963 GetScissorState(regs, 0, up_scale, down_shift),
953 GetScissorState(regs, 1, up_scale, down_shift), 964 GetScissorState(regs, 1, up_scale, down_shift),
954 GetScissorState(regs, 2, up_scale, down_shift), 965 GetScissorState(regs, 2, up_scale, down_shift),
@@ -966,7 +977,11 @@ void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs
966 GetScissorState(regs, 14, up_scale, down_shift), 977 GetScissorState(regs, 14, up_scale, down_shift),
967 GetScissorState(regs, 15, up_scale, down_shift), 978 GetScissorState(regs, 15, up_scale, down_shift),
968 }; 979 };
969 scheduler.Record([scissors](vk::CommandBuffer cmdbuf) { cmdbuf.SetScissor(0, scissors); }); 980 scheduler.Record([this, scissor_list](vk::CommandBuffer cmdbuf) {
981 const u32 num_scissors = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports);
982 const vk::Span<VkRect2D> scissors(scissor_list.data(), num_scissors);
983 cmdbuf.SetScissor(0, scissors);
984 });
970} 985}
971 986
972void RasterizerVulkan::UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs) { 987void RasterizerVulkan::UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs) {
diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp
index 62b251a9b..ce92f66ab 100644
--- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp
+++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp
@@ -38,18 +38,20 @@ size_t Region(size_t iterator) noexcept {
38StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& memory_allocator_, 38StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& memory_allocator_,
39 Scheduler& scheduler_) 39 Scheduler& scheduler_)
40 : device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_} { 40 : device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_} {
41 const VkBufferCreateInfo stream_ci = { 41 VkBufferCreateInfo stream_ci = {
42 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 42 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
43 .pNext = nullptr, 43 .pNext = nullptr,
44 .flags = 0, 44 .flags = 0,
45 .size = STREAM_BUFFER_SIZE, 45 .size = STREAM_BUFFER_SIZE,
46 .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | 46 .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT |
47 VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | 47 VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
48 VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT,
49 .sharingMode = VK_SHARING_MODE_EXCLUSIVE, 48 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
50 .queueFamilyIndexCount = 0, 49 .queueFamilyIndexCount = 0,
51 .pQueueFamilyIndices = nullptr, 50 .pQueueFamilyIndices = nullptr,
52 }; 51 };
52 if (device.IsExtTransformFeedbackSupported()) {
53 stream_ci.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT;
54 }
53 stream_buffer = memory_allocator.CreateBuffer(stream_ci, MemoryUsage::Stream); 55 stream_buffer = memory_allocator.CreateBuffer(stream_ci, MemoryUsage::Stream);
54 if (device.HasDebuggingToolAttached()) { 56 if (device.HasDebuggingToolAttached()) {
55 stream_buffer.SetObjectNameEXT("Stream Buffer"); 57 stream_buffer.SetObjectNameEXT("Stream Buffer");
@@ -164,19 +166,21 @@ std::optional<StagingBufferRef> StagingBufferPool::TryGetReservedBuffer(size_t s
164StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage usage, 166StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage usage,
165 bool deferred) { 167 bool deferred) {
166 const u32 log2 = Common::Log2Ceil64(size); 168 const u32 log2 = Common::Log2Ceil64(size);
167 const VkBufferCreateInfo buffer_ci = { 169 VkBufferCreateInfo buffer_ci = {
168 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 170 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
169 .pNext = nullptr, 171 .pNext = nullptr,
170 .flags = 0, 172 .flags = 0,
171 .size = 1ULL << log2, 173 .size = 1ULL << log2,
172 .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | 174 .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
173 VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | 175 VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
174 VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | 176 VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
175 VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT,
176 .sharingMode = VK_SHARING_MODE_EXCLUSIVE, 177 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
177 .queueFamilyIndexCount = 0, 178 .queueFamilyIndexCount = 0,
178 .pQueueFamilyIndices = nullptr, 179 .pQueueFamilyIndices = nullptr,
179 }; 180 };
181 if (device.IsExtTransformFeedbackSupported()) {
182 buffer_ci.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT;
183 }
180 vk::Buffer buffer = memory_allocator.CreateBuffer(buffer_ci, usage); 184 vk::Buffer buffer = memory_allocator.CreateBuffer(buffer_ci, usage);
181 if (device.HasDebuggingToolAttached()) { 185 if (device.HasDebuggingToolAttached()) {
182 ++buffer_index; 186 ++buffer_index;
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index ce6acc30c..8385b5509 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -1279,6 +1279,10 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu
1279 flags |= VideoCommon::ImageFlagBits::Converted; 1279 flags |= VideoCommon::ImageFlagBits::Converted;
1280 flags |= VideoCommon::ImageFlagBits::CostlyLoad; 1280 flags |= VideoCommon::ImageFlagBits::CostlyLoad;
1281 } 1281 }
1282 if (IsPixelFormatBCn(info.format) && !runtime->device.IsOptimalBcnSupported()) {
1283 flags |= VideoCommon::ImageFlagBits::Converted;
1284 flags |= VideoCommon::ImageFlagBits::CostlyLoad;
1285 }
1282 if (runtime->device.HasDebuggingToolAttached()) { 1286 if (runtime->device.HasDebuggingToolAttached()) {
1283 original_image.SetObjectNameEXT(VideoCommon::Name(*this).c_str()); 1287 original_image.SetObjectNameEXT(VideoCommon::Name(*this).c_str());
1284 } 1288 }
diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp
index cb51529e4..e16cd5e73 100644
--- a/src/video_core/surface.cpp
+++ b/src/video_core/surface.cpp
@@ -269,6 +269,28 @@ bool IsPixelFormatASTC(PixelFormat format) {
269 } 269 }
270} 270}
271 271
272bool IsPixelFormatBCn(PixelFormat format) {
273 switch (format) {
274 case PixelFormat::BC1_RGBA_UNORM:
275 case PixelFormat::BC2_UNORM:
276 case PixelFormat::BC3_UNORM:
277 case PixelFormat::BC4_UNORM:
278 case PixelFormat::BC4_SNORM:
279 case PixelFormat::BC5_UNORM:
280 case PixelFormat::BC5_SNORM:
281 case PixelFormat::BC1_RGBA_SRGB:
282 case PixelFormat::BC2_SRGB:
283 case PixelFormat::BC3_SRGB:
284 case PixelFormat::BC7_UNORM:
285 case PixelFormat::BC6H_UFLOAT:
286 case PixelFormat::BC6H_SFLOAT:
287 case PixelFormat::BC7_SRGB:
288 return true;
289 default:
290 return false;
291 }
292}
293
272bool IsPixelFormatSRGB(PixelFormat format) { 294bool IsPixelFormatSRGB(PixelFormat format) {
273 switch (format) { 295 switch (format) {
274 case PixelFormat::A8B8G8R8_SRGB: 296 case PixelFormat::A8B8G8R8_SRGB:
diff --git a/src/video_core/surface.h b/src/video_core/surface.h
index 0225d3287..9b9c4d9bc 100644
--- a/src/video_core/surface.h
+++ b/src/video_core/surface.h
@@ -501,6 +501,8 @@ SurfaceType GetFormatType(PixelFormat pixel_format);
501 501
502bool IsPixelFormatASTC(PixelFormat format); 502bool IsPixelFormatASTC(PixelFormat format);
503 503
504bool IsPixelFormatBCn(PixelFormat format);
505
504bool IsPixelFormatSRGB(PixelFormat format); 506bool IsPixelFormatSRGB(PixelFormat format);
505 507
506bool IsPixelFormatInteger(PixelFormat format); 508bool IsPixelFormatInteger(PixelFormat format);
diff --git a/src/video_core/texture_cache/decode_bc.cpp b/src/video_core/texture_cache/decode_bc.cpp
new file mode 100644
index 000000000..3e26474a3
--- /dev/null
+++ b/src/video_core/texture_cache/decode_bc.cpp
@@ -0,0 +1,129 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <algorithm>
5#include <array>
6#include <span>
7#include <bc_decoder.h>
8
9#include "common/common_types.h"
10#include "video_core/texture_cache/decode_bc.h"
11
12namespace VideoCommon {
13
14namespace {
15constexpr u32 BLOCK_SIZE = 4;
16
17using VideoCore::Surface::PixelFormat;
18
19constexpr bool IsSigned(PixelFormat pixel_format) {
20 switch (pixel_format) {
21 case PixelFormat::BC4_SNORM:
22 case PixelFormat::BC4_UNORM:
23 case PixelFormat::BC5_SNORM:
24 case PixelFormat::BC5_UNORM:
25 case PixelFormat::BC6H_SFLOAT:
26 case PixelFormat::BC6H_UFLOAT:
27 return true;
28 default:
29 return false;
30 }
31}
32
33constexpr u32 BlockSize(PixelFormat pixel_format) {
34 switch (pixel_format) {
35 case PixelFormat::BC1_RGBA_SRGB:
36 case PixelFormat::BC1_RGBA_UNORM:
37 case PixelFormat::BC4_SNORM:
38 case PixelFormat::BC4_UNORM:
39 return 8;
40 default:
41 return 16;
42 }
43}
44} // Anonymous namespace
45
46u32 ConvertedBytesPerBlock(VideoCore::Surface::PixelFormat pixel_format) {
47 switch (pixel_format) {
48 case PixelFormat::BC4_SNORM:
49 case PixelFormat::BC4_UNORM:
50 return 1;
51 case PixelFormat::BC5_SNORM:
52 case PixelFormat::BC5_UNORM:
53 return 2;
54 case PixelFormat::BC6H_SFLOAT:
55 case PixelFormat::BC6H_UFLOAT:
56 return 8;
57 default:
58 return 4;
59 }
60}
61
62template <auto decompress, PixelFormat pixel_format>
63void DecompressBlocks(std::span<const u8> input, std::span<u8> output, Extent3D extent,
64 bool is_signed = false) {
65 const u32 out_bpp = ConvertedBytesPerBlock(pixel_format);
66 const u32 block_width = std::min(extent.width, BLOCK_SIZE);
67 const u32 block_height = std::min(extent.height, BLOCK_SIZE);
68 const u32 pitch = extent.width * out_bpp;
69 size_t input_offset = 0;
70 size_t output_offset = 0;
71 for (u32 slice = 0; slice < extent.depth; ++slice) {
72 for (u32 y = 0; y < extent.height; y += block_height) {
73 size_t row_offset = 0;
74 for (u32 x = 0; x < extent.width;
75 x += block_width, row_offset += block_width * out_bpp) {
76 const u8* src = input.data() + input_offset;
77 u8* const dst = output.data() + output_offset + row_offset;
78 if constexpr (IsSigned(pixel_format)) {
79 decompress(src, dst, x, y, extent.width, extent.height, is_signed);
80 } else {
81 decompress(src, dst, x, y, extent.width, extent.height);
82 }
83 input_offset += BlockSize(pixel_format);
84 }
85 output_offset += block_height * pitch;
86 }
87 }
88}
89
90void DecompressBCn(std::span<const u8> input, std::span<u8> output, Extent3D extent,
91 VideoCore::Surface::PixelFormat pixel_format) {
92 switch (pixel_format) {
93 case PixelFormat::BC1_RGBA_UNORM:
94 case PixelFormat::BC1_RGBA_SRGB:
95 DecompressBlocks<bcn::DecodeBc1, PixelFormat::BC1_RGBA_UNORM>(input, output, extent);
96 break;
97 case PixelFormat::BC2_UNORM:
98 case PixelFormat::BC2_SRGB:
99 DecompressBlocks<bcn::DecodeBc2, PixelFormat::BC2_UNORM>(input, output, extent);
100 break;
101 case PixelFormat::BC3_UNORM:
102 case PixelFormat::BC3_SRGB:
103 DecompressBlocks<bcn::DecodeBc3, PixelFormat::BC3_UNORM>(input, output, extent);
104 break;
105 case PixelFormat::BC4_SNORM:
106 case PixelFormat::BC4_UNORM:
107 DecompressBlocks<bcn::DecodeBc4, PixelFormat::BC4_UNORM>(
108 input, output, extent, pixel_format == PixelFormat::BC4_SNORM);
109 break;
110 case PixelFormat::BC5_SNORM:
111 case PixelFormat::BC5_UNORM:
112 DecompressBlocks<bcn::DecodeBc5, PixelFormat::BC5_UNORM>(
113 input, output, extent, pixel_format == PixelFormat::BC5_SNORM);
114 break;
115 case PixelFormat::BC6H_SFLOAT:
116 case PixelFormat::BC6H_UFLOAT:
117 DecompressBlocks<bcn::DecodeBc6, PixelFormat::BC6H_UFLOAT>(
118 input, output, extent, pixel_format == PixelFormat::BC6H_SFLOAT);
119 break;
120 case PixelFormat::BC7_SRGB:
121 case PixelFormat::BC7_UNORM:
122 DecompressBlocks<bcn::DecodeBc7, PixelFormat::BC7_UNORM>(input, output, extent);
123 break;
124 default:
125 LOG_WARNING(HW_GPU, "Unimplemented BCn decompression {}", pixel_format);
126 }
127}
128
129} // namespace VideoCommon
diff --git a/src/video_core/texture_cache/decode_bc4.h b/src/video_core/texture_cache/decode_bc.h
index ab2f735be..41d1ec0a3 100644
--- a/src/video_core/texture_cache/decode_bc4.h
+++ b/src/video_core/texture_cache/decode_bc.h
@@ -6,10 +6,14 @@
6#include <span> 6#include <span>
7 7
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "video_core/surface.h"
9#include "video_core/texture_cache/types.h" 10#include "video_core/texture_cache/types.h"
10 11
11namespace VideoCommon { 12namespace VideoCommon {
12 13
13void DecompressBC4(std::span<const u8> data, Extent3D extent, std::span<u8> output); 14[[nodiscard]] u32 ConvertedBytesPerBlock(VideoCore::Surface::PixelFormat pixel_format);
15
16void DecompressBCn(std::span<const u8> input, std::span<u8> output, Extent3D extent,
17 VideoCore::Surface::PixelFormat pixel_format);
14 18
15} // namespace VideoCommon 19} // namespace VideoCommon
diff --git a/src/video_core/texture_cache/decode_bc4.cpp b/src/video_core/texture_cache/decode_bc4.cpp
deleted file mode 100644
index ef98afdca..000000000
--- a/src/video_core/texture_cache/decode_bc4.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <algorithm>
5#include <array>
6#include <span>
7
8#include "common/assert.h"
9#include "common/common_types.h"
10#include "video_core/texture_cache/decode_bc4.h"
11#include "video_core/texture_cache/types.h"
12
13namespace VideoCommon {
14
15// https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_texture_compression_rgtc.txt
16[[nodiscard]] constexpr u32 DecompressBlock(u64 bits, u32 x, u32 y) {
17 const u32 code_offset = 16 + 3 * (4 * y + x);
18 const u32 code = (bits >> code_offset) & 7;
19 const u32 red0 = (bits >> 0) & 0xff;
20 const u32 red1 = (bits >> 8) & 0xff;
21 if (red0 > red1) {
22 switch (code) {
23 case 0:
24 return red0;
25 case 1:
26 return red1;
27 case 2:
28 return (6 * red0 + 1 * red1) / 7;
29 case 3:
30 return (5 * red0 + 2 * red1) / 7;
31 case 4:
32 return (4 * red0 + 3 * red1) / 7;
33 case 5:
34 return (3 * red0 + 4 * red1) / 7;
35 case 6:
36 return (2 * red0 + 5 * red1) / 7;
37 case 7:
38 return (1 * red0 + 6 * red1) / 7;
39 }
40 } else {
41 switch (code) {
42 case 0:
43 return red0;
44 case 1:
45 return red1;
46 case 2:
47 return (4 * red0 + 1 * red1) / 5;
48 case 3:
49 return (3 * red0 + 2 * red1) / 5;
50 case 4:
51 return (2 * red0 + 3 * red1) / 5;
52 case 5:
53 return (1 * red0 + 4 * red1) / 5;
54 case 6:
55 return 0;
56 case 7:
57 return 0xff;
58 }
59 }
60 return 0;
61}
62
63void DecompressBC4(std::span<const u8> input, Extent3D extent, std::span<u8> output) {
64 UNIMPLEMENTED_IF_MSG(extent.width % 4 != 0, "Unaligned width={}", extent.width);
65 UNIMPLEMENTED_IF_MSG(extent.height % 4 != 0, "Unaligned height={}", extent.height);
66 static constexpr u32 BLOCK_SIZE = 4;
67 size_t input_offset = 0;
68 for (u32 slice = 0; slice < extent.depth; ++slice) {
69 for (u32 block_y = 0; block_y < extent.height / 4; ++block_y) {
70 for (u32 block_x = 0; block_x < extent.width / 4; ++block_x) {
71 u64 bits;
72 std::memcpy(&bits, &input[input_offset], sizeof(bits));
73 input_offset += sizeof(bits);
74
75 for (u32 y = 0; y < BLOCK_SIZE; ++y) {
76 for (u32 x = 0; x < BLOCK_SIZE; ++x) {
77 const u32 linear_z = slice;
78 const u32 linear_y = block_y * BLOCK_SIZE + y;
79 const u32 linear_x = block_x * BLOCK_SIZE + x;
80 const u32 offset_z = linear_z * extent.width * extent.height;
81 const u32 offset_y = linear_y * extent.width;
82 const u32 offset_x = linear_x;
83 const u32 output_offset = (offset_z + offset_y + offset_x) * 4ULL;
84 const u32 color = DecompressBlock(bits, x, y);
85 output[output_offset + 0] = static_cast<u8>(color);
86 output[output_offset + 1] = 0;
87 output[output_offset + 2] = 0;
88 output[output_offset + 3] = 0xff;
89 }
90 }
91 }
92 }
93 }
94}
95
96} // namespace VideoCommon
diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp
index f781cb7a0..9a618a57a 100644
--- a/src/video_core/texture_cache/util.cpp
+++ b/src/video_core/texture_cache/util.cpp
@@ -24,7 +24,7 @@
24#include "video_core/engines/maxwell_3d.h" 24#include "video_core/engines/maxwell_3d.h"
25#include "video_core/memory_manager.h" 25#include "video_core/memory_manager.h"
26#include "video_core/surface.h" 26#include "video_core/surface.h"
27#include "video_core/texture_cache/decode_bc4.h" 27#include "video_core/texture_cache/decode_bc.h"
28#include "video_core/texture_cache/format_lookup_table.h" 28#include "video_core/texture_cache/format_lookup_table.h"
29#include "video_core/texture_cache/formatter.h" 29#include "video_core/texture_cache/formatter.h"
30#include "video_core/texture_cache/samples_helper.h" 30#include "video_core/texture_cache/samples_helper.h"
@@ -61,8 +61,6 @@ using VideoCore::Surface::PixelFormatFromDepthFormat;
61using VideoCore::Surface::PixelFormatFromRenderTargetFormat; 61using VideoCore::Surface::PixelFormatFromRenderTargetFormat;
62using VideoCore::Surface::SurfaceType; 62using VideoCore::Surface::SurfaceType;
63 63
64constexpr u32 CONVERTED_BYTES_PER_BLOCK = BytesPerBlock(PixelFormat::A8B8G8R8_UNORM);
65
66struct LevelInfo { 64struct LevelInfo {
67 Extent3D size; 65 Extent3D size;
68 Extent3D block; 66 Extent3D block;
@@ -612,7 +610,8 @@ u32 CalculateConvertedSizeBytes(const ImageInfo& info) noexcept {
612 } 610 }
613 return output_size; 611 return output_size;
614 } 612 }
615 return NumBlocksPerLayer(info, TILE_SIZE) * info.resources.layers * CONVERTED_BYTES_PER_BLOCK; 613 return NumBlocksPerLayer(info, TILE_SIZE) * info.resources.layers *
614 ConvertedBytesPerBlock(info.format);
616} 615}
617 616
618u32 CalculateLayerStride(const ImageInfo& info) noexcept { 617u32 CalculateLayerStride(const ImageInfo& info) noexcept {
@@ -945,7 +944,8 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
945 tile_size.height, output.subspan(output_offset)); 944 tile_size.height, output.subspan(output_offset));
946 945
947 output_offset += copy.image_extent.width * copy.image_extent.height * 946 output_offset += copy.image_extent.width * copy.image_extent.height *
948 copy.image_subresource.num_layers * CONVERTED_BYTES_PER_BLOCK; 947 copy.image_subresource.num_layers *
948 BytesPerBlock(PixelFormat::A8B8G8R8_UNORM);
949 } else if (astc) { 949 } else if (astc) {
950 // BC1 uses 0.5 bytes per texel 950 // BC1 uses 0.5 bytes per texel
951 // BC3 uses 1 byte per texel 951 // BC3 uses 1 byte per texel
@@ -956,7 +956,8 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
956 956
957 const u32 plane_dim = copy.image_extent.width * copy.image_extent.height; 957 const u32 plane_dim = copy.image_extent.width * copy.image_extent.height;
958 const u32 level_size = plane_dim * copy.image_extent.depth * 958 const u32 level_size = plane_dim * copy.image_extent.depth *
959 copy.image_subresource.num_layers * CONVERTED_BYTES_PER_BLOCK; 959 copy.image_subresource.num_layers *
960 BytesPerBlock(PixelFormat::A8B8G8R8_UNORM);
960 decode_scratch.resize_destructive(level_size); 961 decode_scratch.resize_destructive(level_size);
961 962
962 Tegra::Texture::ASTC::Decompress( 963 Tegra::Texture::ASTC::Decompress(
@@ -976,10 +977,15 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
976 bpp_div; 977 bpp_div;
977 output_offset += static_cast<u32>(copy.buffer_size); 978 output_offset += static_cast<u32>(copy.buffer_size);
978 } else { 979 } else {
979 DecompressBC4(input_offset, copy.image_extent, output.subspan(output_offset)); 980 const Extent3D image_extent{
980 981 .width = copy.image_extent.width,
982 .height = copy.image_extent.height * copy.image_subresource.num_layers,
983 .depth = copy.image_extent.depth,
984 };
985 DecompressBCn(input_offset, output.subspan(output_offset), image_extent, info.format);
981 output_offset += copy.image_extent.width * copy.image_extent.height * 986 output_offset += copy.image_extent.width * copy.image_extent.height *
982 copy.image_subresource.num_layers * CONVERTED_BYTES_PER_BLOCK; 987 copy.image_subresource.num_layers *
988 ConvertedBytesPerBlock(info.format);
983 } 989 }
984 } 990 }
985} 991}
diff --git a/src/video_core/textures/bcn.cpp b/src/video_core/textures/bcn.cpp
index 671212a49..16ddbe320 100644
--- a/src/video_core/textures/bcn.cpp
+++ b/src/video_core/textures/bcn.cpp
@@ -3,7 +3,6 @@
3 3
4#include <stb_dxt.h> 4#include <stb_dxt.h>
5#include <string.h> 5#include <string.h>
6
7#include "common/alignment.h" 6#include "common/alignment.h"
8#include "video_core/textures/bcn.h" 7#include "video_core/textures/bcn.h"
9#include "video_core/textures/workers.h" 8#include "video_core/textures/workers.h"
diff --git a/src/video_core/textures/bcn.h b/src/video_core/textures/bcn.h
index 6464af885..d5d2a16c9 100644
--- a/src/video_core/textures/bcn.h
+++ b/src/video_core/textures/bcn.h
@@ -4,14 +4,13 @@
4#pragma once 4#pragma once
5 5
6#include <span> 6#include <span>
7#include <stdint.h> 7
8#include "common/common_types.h"
8 9
9namespace Tegra::Texture::BCN { 10namespace Tegra::Texture::BCN {
10 11
11void CompressBC1(std::span<const uint8_t> data, uint32_t width, uint32_t height, uint32_t depth, 12void CompressBC1(std::span<const u8> data, u32 width, u32 height, u32 depth, std::span<u8> output);
12 std::span<uint8_t> output);
13 13
14void CompressBC3(std::span<const uint8_t> data, uint32_t width, uint32_t height, uint32_t depth, 14void CompressBC3(std::span<const u8> data, u32 width, u32 height, u32 depth, std::span<u8> output);
15 std::span<uint8_t> output);
16 15
17} // namespace Tegra::Texture::BCN 16} // namespace Tegra::Texture::BCN
diff --git a/src/video_core/vulkan_common/vulkan_debug_callback.cpp b/src/video_core/vulkan_common/vulkan_debug_callback.cpp
index 9de484c29..67e8065a4 100644
--- a/src/video_core/vulkan_common/vulkan_debug_callback.cpp
+++ b/src/video_core/vulkan_common/vulkan_debug_callback.cpp
@@ -7,10 +7,10 @@
7 7
8namespace Vulkan { 8namespace Vulkan {
9namespace { 9namespace {
10VkBool32 Callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, 10VkBool32 DebugUtilCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
11 VkDebugUtilsMessageTypeFlagsEXT type, 11 VkDebugUtilsMessageTypeFlagsEXT type,
12 const VkDebugUtilsMessengerCallbackDataEXT* data, 12 const VkDebugUtilsMessengerCallbackDataEXT* data,
13 [[maybe_unused]] void* user_data) { 13 [[maybe_unused]] void* user_data) {
14 // Skip logging known false-positive validation errors 14 // Skip logging known false-positive validation errors
15 switch (static_cast<u32>(data->messageIdNumber)) { 15 switch (static_cast<u32>(data->messageIdNumber)) {
16#ifdef ANDROID 16#ifdef ANDROID
@@ -62,9 +62,26 @@ VkBool32 Callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
62 } 62 }
63 return VK_FALSE; 63 return VK_FALSE;
64} 64}
65
66VkBool32 DebugReportCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType,
67 uint64_t object, size_t location, int32_t messageCode,
68 const char* pLayerPrefix, const char* pMessage, void* pUserData) {
69 const VkDebugReportFlagBitsEXT severity = static_cast<VkDebugReportFlagBitsEXT>(flags);
70 const std::string_view message{pMessage};
71 if (severity & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
72 LOG_CRITICAL(Render_Vulkan, "{}", message);
73 } else if (severity & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
74 LOG_WARNING(Render_Vulkan, "{}", message);
75 } else if (severity & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) {
76 LOG_INFO(Render_Vulkan, "{}", message);
77 } else if (severity & VK_DEBUG_REPORT_DEBUG_BIT_EXT) {
78 LOG_DEBUG(Render_Vulkan, "{}", message);
79 }
80 return VK_FALSE;
81}
65} // Anonymous namespace 82} // Anonymous namespace
66 83
67vk::DebugUtilsMessenger CreateDebugCallback(const vk::Instance& instance) { 84vk::DebugUtilsMessenger CreateDebugUtilsCallback(const vk::Instance& instance) {
68 return instance.CreateDebugUtilsMessenger(VkDebugUtilsMessengerCreateInfoEXT{ 85 return instance.CreateDebugUtilsMessenger(VkDebugUtilsMessengerCreateInfoEXT{
69 .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, 86 .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
70 .pNext = nullptr, 87 .pNext = nullptr,
@@ -76,7 +93,18 @@ vk::DebugUtilsMessenger CreateDebugCallback(const vk::Instance& instance) {
76 .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | 93 .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
77 VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | 94 VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
78 VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, 95 VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
79 .pfnUserCallback = Callback, 96 .pfnUserCallback = DebugUtilCallback,
97 .pUserData = nullptr,
98 });
99}
100
101vk::DebugReportCallback CreateDebugReportCallback(const vk::Instance& instance) {
102 return instance.CreateDebugReportCallback({
103 .sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT,
104 .pNext = nullptr,
105 .flags = VK_DEBUG_REPORT_DEBUG_BIT_EXT | VK_DEBUG_REPORT_INFORMATION_BIT_EXT |
106 VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT,
107 .pfnCallback = DebugReportCallback,
80 .pUserData = nullptr, 108 .pUserData = nullptr,
81 }); 109 });
82} 110}
diff --git a/src/video_core/vulkan_common/vulkan_debug_callback.h b/src/video_core/vulkan_common/vulkan_debug_callback.h
index 71b1f69ec..a8af7b406 100644
--- a/src/video_core/vulkan_common/vulkan_debug_callback.h
+++ b/src/video_core/vulkan_common/vulkan_debug_callback.h
@@ -7,6 +7,8 @@
7 7
8namespace Vulkan { 8namespace Vulkan {
9 9
10vk::DebugUtilsMessenger CreateDebugCallback(const vk::Instance& instance); 10vk::DebugUtilsMessenger CreateDebugUtilsCallback(const vk::Instance& instance);
11
12vk::DebugReportCallback CreateDebugReportCallback(const vk::Instance& instance);
11 13
12} // namespace Vulkan 14} // namespace Vulkan
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index e4ca65b58..70436cf1c 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -349,7 +349,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
349 const bool is_s8gen2 = device_id == 0x43050a01; 349 const bool is_s8gen2 = device_id == 0x43050a01;
350 const bool is_arm = driver_id == VK_DRIVER_ID_ARM_PROPRIETARY; 350 const bool is_arm = driver_id == VK_DRIVER_ID_ARM_PROPRIETARY;
351 351
352 if ((is_mvk || is_qualcomm || is_turnip) && !is_suitable) { 352 if ((is_mvk || is_qualcomm || is_turnip || is_arm) && !is_suitable) {
353 LOG_WARNING(Render_Vulkan, "Unsuitable driver, continuing anyway"); 353 LOG_WARNING(Render_Vulkan, "Unsuitable driver, continuing anyway");
354 } else if (!is_suitable) { 354 } else if (!is_suitable) {
355 throw vk::Exception(VK_ERROR_INCOMPATIBLE_DRIVER); 355 throw vk::Exception(VK_ERROR_INCOMPATIBLE_DRIVER);
@@ -905,6 +905,10 @@ bool Device::GetSuitability(bool requires_swapchain) {
905 properties.driver.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES; 905 properties.driver.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES;
906 SetNext(next, properties.driver); 906 SetNext(next, properties.driver);
907 907
908 // Retrieve subgroup properties.
909 properties.subgroup_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
910 SetNext(next, properties.subgroup_properties);
911
908 // Retrieve relevant extension properties. 912 // Retrieve relevant extension properties.
909 if (extensions.shader_float_controls) { 913 if (extensions.shader_float_controls) {
910 properties.float_controls.sType = 914 properties.float_controls.sType =
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h
index b84af3dfb..1f17265d5 100644
--- a/src/video_core/vulkan_common/vulkan_device.h
+++ b/src/video_core/vulkan_common/vulkan_device.h
@@ -293,6 +293,11 @@ public:
293 return features.features.textureCompressionASTC_LDR; 293 return features.features.textureCompressionASTC_LDR;
294 } 294 }
295 295
296 /// Returns true if BCn is natively supported.
297 bool IsOptimalBcnSupported() const {
298 return features.features.textureCompressionBC;
299 }
300
296 /// Returns true if descriptor aliasing is natively supported. 301 /// Returns true if descriptor aliasing is natively supported.
297 bool IsDescriptorAliasingSupported() const { 302 bool IsDescriptorAliasingSupported() const {
298 return GetDriverID() != VK_DRIVER_ID_QUALCOMM_PROPRIETARY; 303 return GetDriverID() != VK_DRIVER_ID_QUALCOMM_PROPRIETARY;
@@ -323,6 +328,11 @@ public:
323 return properties.subgroup_size_control.requiredSubgroupSizeStages & stage; 328 return properties.subgroup_size_control.requiredSubgroupSizeStages & stage;
324 } 329 }
325 330
331 /// Returns true if the device supports the provided subgroup feature.
332 bool IsSubgroupFeatureSupported(VkSubgroupFeatureFlagBits feature) const {
333 return properties.subgroup_properties.supportedOperations & feature;
334 }
335
326 /// Returns the maximum number of push descriptors. 336 /// Returns the maximum number of push descriptors.
327 u32 MaxPushDescriptors() const { 337 u32 MaxPushDescriptors() const {
328 return properties.push_descriptor.maxPushDescriptors; 338 return properties.push_descriptor.maxPushDescriptors;
@@ -388,6 +398,11 @@ public:
388 return extensions.swapchain_mutable_format; 398 return extensions.swapchain_mutable_format;
389 } 399 }
390 400
401 /// Returns true if VK_KHR_shader_float_controls is enabled.
402 bool IsKhrShaderFloatControlsSupported() const {
403 return extensions.shader_float_controls;
404 }
405
391 /// Returns true if the device supports VK_KHR_workgroup_memory_explicit_layout. 406 /// Returns true if the device supports VK_KHR_workgroup_memory_explicit_layout.
392 bool IsKhrWorkgroupMemoryExplicitLayoutSupported() const { 407 bool IsKhrWorkgroupMemoryExplicitLayoutSupported() const {
393 return extensions.workgroup_memory_explicit_layout; 408 return extensions.workgroup_memory_explicit_layout;
@@ -413,6 +428,11 @@ public:
413 return extensions.sampler_filter_minmax; 428 return extensions.sampler_filter_minmax;
414 } 429 }
415 430
431 /// Returns true if the device supports VK_EXT_shader_stencil_export.
432 bool IsExtShaderStencilExportSupported() const {
433 return extensions.shader_stencil_export;
434 }
435
416 /// Returns true if the device supports VK_EXT_depth_range_unrestricted. 436 /// Returns true if the device supports VK_EXT_depth_range_unrestricted.
417 bool IsExtDepthRangeUnrestrictedSupported() const { 437 bool IsExtDepthRangeUnrestrictedSupported() const {
418 return extensions.depth_range_unrestricted; 438 return extensions.depth_range_unrestricted;
@@ -482,9 +502,9 @@ public:
482 return extensions.vertex_input_dynamic_state; 502 return extensions.vertex_input_dynamic_state;
483 } 503 }
484 504
485 /// Returns true if the device supports VK_EXT_shader_stencil_export. 505 /// Returns true if the device supports VK_EXT_shader_demote_to_helper_invocation
486 bool IsExtShaderStencilExportSupported() const { 506 bool IsExtShaderDemoteToHelperInvocationSupported() const {
487 return extensions.shader_stencil_export; 507 return extensions.shader_demote_to_helper_invocation;
488 } 508 }
489 509
490 /// Returns true if the device supports VK_EXT_conservative_rasterization. 510 /// Returns true if the device supports VK_EXT_conservative_rasterization.
@@ -518,12 +538,12 @@ public:
518 if (extensions.spirv_1_4) { 538 if (extensions.spirv_1_4) {
519 return 0x00010400U; 539 return 0x00010400U;
520 } 540 }
521 return 0x00010000U; 541 return 0x00010300U;
522 } 542 }
523 543
524 /// Returns true when a known debugging tool is attached. 544 /// Returns true when a known debugging tool is attached.
525 bool HasDebuggingToolAttached() const { 545 bool HasDebuggingToolAttached() const {
526 return has_renderdoc || has_nsight_graphics || Settings::values.renderer_debug.GetValue(); 546 return has_renderdoc || has_nsight_graphics;
527 } 547 }
528 548
529 /// @returns True if compute pipelines can cause crashing. 549 /// @returns True if compute pipelines can cause crashing.
@@ -588,6 +608,10 @@ public:
588 return properties.properties.limits.maxVertexInputBindings; 608 return properties.properties.limits.maxVertexInputBindings;
589 } 609 }
590 610
611 u32 GetMaxViewports() const {
612 return properties.properties.limits.maxViewports;
613 }
614
591 bool SupportsConditionalBarriers() const { 615 bool SupportsConditionalBarriers() const {
592 return supports_conditional_barriers; 616 return supports_conditional_barriers;
593 } 617 }
@@ -680,6 +704,7 @@ private:
680 704
681 struct Properties { 705 struct Properties {
682 VkPhysicalDeviceDriverProperties driver{}; 706 VkPhysicalDeviceDriverProperties driver{};
707 VkPhysicalDeviceSubgroupProperties subgroup_properties{};
683 VkPhysicalDeviceFloatControlsProperties float_controls{}; 708 VkPhysicalDeviceFloatControlsProperties float_controls{};
684 VkPhysicalDevicePushDescriptorPropertiesKHR push_descriptor{}; 709 VkPhysicalDevicePushDescriptorPropertiesKHR push_descriptor{};
685 VkPhysicalDeviceSubgroupSizeControlProperties subgroup_size_control{}; 710 VkPhysicalDeviceSubgroupSizeControlProperties subgroup_size_control{};
diff --git a/src/video_core/vulkan_common/vulkan_instance.cpp b/src/video_core/vulkan_common/vulkan_instance.cpp
index b6d83e446..7624a9b32 100644
--- a/src/video_core/vulkan_common/vulkan_instance.cpp
+++ b/src/video_core/vulkan_common/vulkan_instance.cpp
@@ -31,10 +31,34 @@
31 31
32namespace Vulkan { 32namespace Vulkan {
33namespace { 33namespace {
34
35[[nodiscard]] bool AreExtensionsSupported(const vk::InstanceDispatch& dld,
36 std::span<const char* const> extensions) {
37 const std::optional properties = vk::EnumerateInstanceExtensionProperties(dld);
38 if (!properties) {
39 LOG_ERROR(Render_Vulkan, "Failed to query extension properties");
40 return false;
41 }
42 for (const char* extension : extensions) {
43 const auto it = std::ranges::find_if(*properties, [extension](const auto& prop) {
44 return std::strcmp(extension, prop.extensionName) == 0;
45 });
46 if (it == properties->end()) {
47 LOG_ERROR(Render_Vulkan, "Required instance extension {} is not available", extension);
48 return false;
49 }
50 }
51 return true;
52}
53
34[[nodiscard]] std::vector<const char*> RequiredExtensions( 54[[nodiscard]] std::vector<const char*> RequiredExtensions(
35 Core::Frontend::WindowSystemType window_type, bool enable_validation) { 55 const vk::InstanceDispatch& dld, Core::Frontend::WindowSystemType window_type,
56 bool enable_validation) {
36 std::vector<const char*> extensions; 57 std::vector<const char*> extensions;
37 extensions.reserve(6); 58 extensions.reserve(6);
59#ifdef __APPLE__
60 extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
61#endif
38 switch (window_type) { 62 switch (window_type) {
39 case Core::Frontend::WindowSystemType::Headless: 63 case Core::Frontend::WindowSystemType::Headless:
40 break; 64 break;
@@ -66,35 +90,14 @@ namespace {
66 extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME); 90 extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
67 } 91 }
68 if (enable_validation) { 92 if (enable_validation) {
69 extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); 93 const bool debug_utils =
94 AreExtensionsSupported(dld, std::array{VK_EXT_DEBUG_UTILS_EXTENSION_NAME});
95 extensions.push_back(debug_utils ? VK_EXT_DEBUG_UTILS_EXTENSION_NAME
96 : VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
70 } 97 }
71 extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
72
73#ifdef __APPLE__
74 extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
75#endif
76 return extensions; 98 return extensions;
77} 99}
78 100
79[[nodiscard]] bool AreExtensionsSupported(const vk::InstanceDispatch& dld,
80 std::span<const char* const> extensions) {
81 const std::optional properties = vk::EnumerateInstanceExtensionProperties(dld);
82 if (!properties) {
83 LOG_ERROR(Render_Vulkan, "Failed to query extension properties");
84 return false;
85 }
86 for (const char* extension : extensions) {
87 const auto it = std::ranges::find_if(*properties, [extension](const auto& prop) {
88 return std::strcmp(extension, prop.extensionName) == 0;
89 });
90 if (it == properties->end()) {
91 LOG_ERROR(Render_Vulkan, "Required instance extension {} is not available", extension);
92 return false;
93 }
94 }
95 return true;
96}
97
98[[nodiscard]] std::vector<const char*> Layers(bool enable_validation) { 101[[nodiscard]] std::vector<const char*> Layers(bool enable_validation) {
99 std::vector<const char*> layers; 102 std::vector<const char*> layers;
100 if (enable_validation) { 103 if (enable_validation) {
@@ -138,7 +141,8 @@ vk::Instance CreateInstance(const Common::DynamicLibrary& library, vk::InstanceD
138 LOG_ERROR(Render_Vulkan, "Failed to load Vulkan function pointers"); 141 LOG_ERROR(Render_Vulkan, "Failed to load Vulkan function pointers");
139 throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); 142 throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
140 } 143 }
141 const std::vector<const char*> extensions = RequiredExtensions(window_type, enable_validation); 144 const std::vector<const char*> extensions =
145 RequiredExtensions(dld, window_type, enable_validation);
142 if (!AreExtensionsSupported(dld, extensions)) { 146 if (!AreExtensionsSupported(dld, extensions)) {
143 throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT); 147 throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT);
144 } 148 }
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp
index 28fcb21a0..2fa29793a 100644
--- a/src/video_core/vulkan_common/vulkan_wrapper.cpp
+++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp
@@ -259,7 +259,9 @@ bool Load(VkInstance instance, InstanceDispatch& dld) noexcept {
259 // These functions may fail to load depending on the enabled extensions. 259 // These functions may fail to load depending on the enabled extensions.
260 // Don't return a failure on these. 260 // Don't return a failure on these.
261 X(vkCreateDebugUtilsMessengerEXT); 261 X(vkCreateDebugUtilsMessengerEXT);
262 X(vkCreateDebugReportCallbackEXT);
262 X(vkDestroyDebugUtilsMessengerEXT); 263 X(vkDestroyDebugUtilsMessengerEXT);
264 X(vkDestroyDebugReportCallbackEXT);
263 X(vkDestroySurfaceKHR); 265 X(vkDestroySurfaceKHR);
264 X(vkGetPhysicalDeviceFeatures2); 266 X(vkGetPhysicalDeviceFeatures2);
265 X(vkGetPhysicalDeviceProperties2); 267 X(vkGetPhysicalDeviceProperties2);
@@ -481,6 +483,11 @@ void Destroy(VkInstance instance, VkDebugUtilsMessengerEXT handle,
481 dld.vkDestroyDebugUtilsMessengerEXT(instance, handle, nullptr); 483 dld.vkDestroyDebugUtilsMessengerEXT(instance, handle, nullptr);
482} 484}
483 485
486void Destroy(VkInstance instance, VkDebugReportCallbackEXT handle,
487 const InstanceDispatch& dld) noexcept {
488 dld.vkDestroyDebugReportCallbackEXT(instance, handle, nullptr);
489}
490
484void Destroy(VkInstance instance, VkSurfaceKHR handle, const InstanceDispatch& dld) noexcept { 491void Destroy(VkInstance instance, VkSurfaceKHR handle, const InstanceDispatch& dld) noexcept {
485 dld.vkDestroySurfaceKHR(instance, handle, nullptr); 492 dld.vkDestroySurfaceKHR(instance, handle, nullptr);
486} 493}
@@ -549,6 +556,13 @@ DebugUtilsMessenger Instance::CreateDebugUtilsMessenger(
549 return DebugUtilsMessenger(object, handle, *dld); 556 return DebugUtilsMessenger(object, handle, *dld);
550} 557}
551 558
559DebugReportCallback Instance::CreateDebugReportCallback(
560 const VkDebugReportCallbackCreateInfoEXT& create_info) const {
561 VkDebugReportCallbackEXT object;
562 Check(dld->vkCreateDebugReportCallbackEXT(handle, &create_info, nullptr, &object));
563 return DebugReportCallback(object, handle, *dld);
564}
565
552void Image::SetObjectNameEXT(const char* name) const { 566void Image::SetObjectNameEXT(const char* name) const {
553 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_IMAGE, name); 567 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_IMAGE, name);
554} 568}
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h
index 44fce47a5..b5e70fcd4 100644
--- a/src/video_core/vulkan_common/vulkan_wrapper.h
+++ b/src/video_core/vulkan_common/vulkan_wrapper.h
@@ -164,8 +164,10 @@ struct InstanceDispatch {
164 PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties{}; 164 PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties{};
165 165
166 PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT{}; 166 PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT{};
167 PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT{};
167 PFN_vkCreateDevice vkCreateDevice{}; 168 PFN_vkCreateDevice vkCreateDevice{};
168 PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT{}; 169 PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT{};
170 PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT{};
169 PFN_vkDestroyDevice vkDestroyDevice{}; 171 PFN_vkDestroyDevice vkDestroyDevice{};
170 PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR{}; 172 PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR{};
171 PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties{}; 173 PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties{};
@@ -366,6 +368,7 @@ void Destroy(VkDevice, VkSwapchainKHR, const DeviceDispatch&) noexcept;
366void Destroy(VkDevice, VkSemaphore, const DeviceDispatch&) noexcept; 368void Destroy(VkDevice, VkSemaphore, const DeviceDispatch&) noexcept;
367void Destroy(VkDevice, VkShaderModule, const DeviceDispatch&) noexcept; 369void Destroy(VkDevice, VkShaderModule, const DeviceDispatch&) noexcept;
368void Destroy(VkInstance, VkDebugUtilsMessengerEXT, const InstanceDispatch&) noexcept; 370void Destroy(VkInstance, VkDebugUtilsMessengerEXT, const InstanceDispatch&) noexcept;
371void Destroy(VkInstance, VkDebugReportCallbackEXT, const InstanceDispatch&) noexcept;
369void Destroy(VkInstance, VkSurfaceKHR, const InstanceDispatch&) noexcept; 372void Destroy(VkInstance, VkSurfaceKHR, const InstanceDispatch&) noexcept;
370 373
371VkResult Free(VkDevice, VkDescriptorPool, Span<VkDescriptorSet>, const DeviceDispatch&) noexcept; 374VkResult Free(VkDevice, VkDescriptorPool, Span<VkDescriptorSet>, const DeviceDispatch&) noexcept;
@@ -581,6 +584,7 @@ private:
581}; 584};
582 585
583using DebugUtilsMessenger = Handle<VkDebugUtilsMessengerEXT, VkInstance, InstanceDispatch>; 586using DebugUtilsMessenger = Handle<VkDebugUtilsMessengerEXT, VkInstance, InstanceDispatch>;
587using DebugReportCallback = Handle<VkDebugReportCallbackEXT, VkInstance, InstanceDispatch>;
584using DescriptorSetLayout = Handle<VkDescriptorSetLayout, VkDevice, DeviceDispatch>; 588using DescriptorSetLayout = Handle<VkDescriptorSetLayout, VkDevice, DeviceDispatch>;
585using DescriptorUpdateTemplate = Handle<VkDescriptorUpdateTemplate, VkDevice, DeviceDispatch>; 589using DescriptorUpdateTemplate = Handle<VkDescriptorUpdateTemplate, VkDevice, DeviceDispatch>;
586using Pipeline = Handle<VkPipeline, VkDevice, DeviceDispatch>; 590using Pipeline = Handle<VkPipeline, VkDevice, DeviceDispatch>;
@@ -613,6 +617,11 @@ public:
613 DebugUtilsMessenger CreateDebugUtilsMessenger( 617 DebugUtilsMessenger CreateDebugUtilsMessenger(
614 const VkDebugUtilsMessengerCreateInfoEXT& create_info) const; 618 const VkDebugUtilsMessengerCreateInfoEXT& create_info) const;
615 619
620 /// Creates a debug report callback.
621 /// @throw Exception on creation failure.
622 DebugReportCallback CreateDebugReportCallback(
623 const VkDebugReportCallbackCreateInfoEXT& create_info) const;
624
616 /// Returns dispatch table. 625 /// Returns dispatch table.
617 const InstanceDispatch& Dispatch() const noexcept { 626 const InstanceDispatch& Dispatch() const noexcept {
618 return *dld; 627 return *dld;