diff options
Diffstat (limited to 'src/video_core')
-rw-r--r-- | src/video_core/engines/maxwell_3d.h | 67 | ||||
-rw-r--r-- | src/video_core/engines/shader_bytecode.h | 57 | ||||
-rw-r--r-- | src/video_core/renderer_vulkan/declarations.h | 2 | ||||
-rw-r--r-- | src/video_core/renderer_vulkan/renderer_vulkan.cpp | 264 | ||||
-rw-r--r-- | src/video_core/renderer_vulkan/renderer_vulkan.h | 19 | ||||
-rw-r--r-- | src/video_core/renderer_vulkan/vk_device.cpp | 92 | ||||
-rw-r--r-- | src/video_core/renderer_vulkan/vk_device.h | 21 | ||||
-rw-r--r-- | src/video_core/shader/decode/video.cpp | 58 | ||||
-rw-r--r-- | src/video_core/shader/shader_ir.h | 3 | ||||
-rw-r--r-- | src/video_core/textures/texture.h | 15 |
10 files changed, 495 insertions, 103 deletions
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index d24c9f657..4637ddabd 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -312,6 +312,35 @@ public: } }; + struct MsaaSampleLocation { + union { + BitField<0, 4, u32> x0; + BitField<4, 4, u32> y0; + BitField<8, 4, u32> x1; + BitField<12, 4, u32> y1; + BitField<16, 4, u32> x2; + BitField<20, 4, u32> y2; + BitField<24, 4, u32> x3; + BitField<28, 4, u32> y3; + }; + + constexpr std::pair<u32, u32> Location(int index) const { + switch (index) { + case 0: + return {x0, y0}; + case 1: + return {x1, y1}; + case 2: + return {x2, y2}; + case 3: + return {x3, y3}; + default: + UNREACHABLE(); + return {0, 0}; + } + } + }; + enum class DepthMode : u32 { MinusOneToOne = 0, ZeroToOne = 1, @@ -793,7 +822,13 @@ public: u32 rt_separate_frag_data; - INSERT_UNION_PADDING_WORDS(0xC); + INSERT_UNION_PADDING_WORDS(0x1); + + u32 multisample_raster_enable; + u32 multisample_raster_samples; + std::array<u32, 4> multisample_sample_mask; + + INSERT_UNION_PADDING_WORDS(0x5); struct { u32 address_high; @@ -830,7 +865,16 @@ public: std::array<VertexAttribute, NumVertexAttributes> vertex_attrib_format; - INSERT_UNION_PADDING_WORDS(0xF); + std::array<MsaaSampleLocation, 4> multisample_sample_locations; + + INSERT_UNION_PADDING_WORDS(0x2); + + union { + BitField<0, 1, u32> enable; + BitField<4, 3, u32> target; + } multisample_coverage_to_color; + + INSERT_UNION_PADDING_WORDS(0x8); struct { union { @@ -943,7 +987,7 @@ public: CounterReset counter_reset; - INSERT_UNION_PADDING_WORDS(0x1); + u32 multisample_enable; u32 zeta_enable; @@ -1007,7 +1051,11 @@ public: float polygon_offset_units; - INSERT_UNION_PADDING_WORDS(0x11); + INSERT_UNION_PADDING_WORDS(0x4); + + Tegra::Texture::MsaaMode multisample_mode; + + INSERT_UNION_PADDING_WORDS(0xC); union { BitField<2, 1, u32> coord_origin; @@ -1507,12 +1555,17 @@ ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5); ASSERT_REG_POSITION(stencil_back_mask, 0x3D6); ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D7); ASSERT_REG_POSITION(color_mask_common, 0x3E4); -ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB); ASSERT_REG_POSITION(depth_bounds, 0x3E7); +ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB); +ASSERT_REG_POSITION(multisample_raster_enable, 0x3ED); +ASSERT_REG_POSITION(multisample_raster_samples, 0x3EE); +ASSERT_REG_POSITION(multisample_sample_mask, 0x3EF); ASSERT_REG_POSITION(zeta, 0x3F8); ASSERT_REG_POSITION(clear_flags, 0x43E); ASSERT_REG_POSITION(fill_rectangle, 0x44F); ASSERT_REG_POSITION(vertex_attrib_format, 0x458); +ASSERT_REG_POSITION(multisample_sample_locations, 0x478); +ASSERT_REG_POSITION(multisample_coverage_to_color, 0x47E); ASSERT_REG_POSITION(rt_control, 0x487); ASSERT_REG_POSITION(zeta_width, 0x48a); ASSERT_REG_POSITION(zeta_height, 0x48b); @@ -1545,11 +1598,12 @@ ASSERT_REG_POSITION(samplecnt_enable, 0x545); ASSERT_REG_POSITION(point_size, 0x546); ASSERT_REG_POSITION(point_sprite_enable, 0x548); ASSERT_REG_POSITION(counter_reset, 0x54C); +ASSERT_REG_POSITION(multisample_enable, 0x54D); ASSERT_REG_POSITION(zeta_enable, 0x54E); ASSERT_REG_POSITION(multisample_control, 0x54F); ASSERT_REG_POSITION(condition, 0x554); ASSERT_REG_POSITION(tsc, 0x557); -ASSERT_REG_POSITION(polygon_offset_factor, 0x55b); +ASSERT_REG_POSITION(polygon_offset_factor, 0x55B); ASSERT_REG_POSITION(tic, 0x55D); ASSERT_REG_POSITION(stencil_two_side_enable, 0x565); ASSERT_REG_POSITION(stencil_back_op_fail, 0x566); @@ -1558,6 +1612,7 @@ ASSERT_REG_POSITION(stencil_back_op_zpass, 0x568); ASSERT_REG_POSITION(stencil_back_func_func, 0x569); ASSERT_REG_POSITION(framebuffer_srgb, 0x56E); ASSERT_REG_POSITION(polygon_offset_units, 0x56F); +ASSERT_REG_POSITION(multisample_mode, 0x574); ASSERT_REG_POSITION(point_coord_replace, 0x581); ASSERT_REG_POSITION(code_address, 0x582); ASSERT_REG_POSITION(draw, 0x585); diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index 498936f0c..c66c66f6c 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h @@ -290,6 +290,23 @@ enum class VmadShr : u64 { Shr15 = 2, }; +enum class VmnmxType : u64 { + Bits8, + Bits16, + Bits32, +}; + +enum class VmnmxOperation : u64 { + Mrg_16H = 0, + Mrg_16L = 1, + Mrg_8B0 = 2, + Mrg_8B2 = 3, + Acc = 4, + Min = 5, + Max = 6, + Nop = 7, +}; + enum class XmadMode : u64 { None = 0, CLo = 1, @@ -1651,6 +1668,42 @@ union Instruction { } vmad; union { + BitField<54, 1, u64> is_dest_signed; + BitField<48, 1, u64> is_src_a_signed; + BitField<49, 1, u64> is_src_b_signed; + BitField<37, 2, u64> src_format_a; + BitField<29, 2, u64> src_format_b; + BitField<56, 1, u64> mx; + BitField<55, 1, u64> sat; + BitField<36, 2, u64> selector_a; + BitField<28, 2, u64> selector_b; + BitField<50, 1, u64> is_op_b_register; + BitField<51, 3, VmnmxOperation> operation; + + VmnmxType SourceFormatA() const { + switch (src_format_a) { + case 0b11: + return VmnmxType::Bits32; + case 0b10: + return VmnmxType::Bits16; + default: + return VmnmxType::Bits8; + } + } + + VmnmxType SourceFormatB() const { + switch (src_format_b) { + case 0b11: + return VmnmxType::Bits32; + case 0b10: + return VmnmxType::Bits16; + default: + return VmnmxType::Bits8; + } + } + } vmnmx; + + union { BitField<20, 16, u64> imm20_16; BitField<35, 1, u64> high_b_rr; // used on RR BitField<36, 1, u64> product_shift_left; @@ -1763,6 +1816,7 @@ public: MEMBAR, VMAD, VSETP, + VMNMX, FFMA_IMM, // Fused Multiply and Add FFMA_CR, FFMA_RC, @@ -2070,6 +2124,7 @@ private: INST("1110111110011---", Id::MEMBAR, Type::Trivial, "MEMBAR"), INST("01011111--------", Id::VMAD, Type::Video, "VMAD"), INST("0101000011110---", Id::VSETP, Type::Video, "VSETP"), + INST("0011101---------", Id::VMNMX, Type::Video, "VMNMX"), INST("0011001-1-------", Id::FFMA_IMM, Type::Ffma, "FFMA_IMM"), INST("010010011-------", Id::FFMA_CR, Type::Ffma, "FFMA_CR"), INST("010100011-------", Id::FFMA_RC, Type::Ffma, "FFMA_RC"), @@ -2170,7 +2225,7 @@ private: INST("0011011-11111---", Id::SHF_LEFT_IMM, Type::Shift, "SHF_LEFT_IMM"), INST("0100110011100---", Id::I2I_C, Type::Conversion, "I2I_C"), INST("0101110011100---", Id::I2I_R, Type::Conversion, "I2I_R"), - INST("0011101-11100---", Id::I2I_IMM, Type::Conversion, "I2I_IMM"), + INST("0011100-11100---", Id::I2I_IMM, Type::Conversion, "I2I_IMM"), INST("0100110010111---", Id::I2F_C, Type::Conversion, "I2F_C"), INST("0101110010111---", Id::I2F_R, Type::Conversion, "I2F_R"), INST("0011100-10111---", Id::I2F_IMM, Type::Conversion, "I2F_IMM"), diff --git a/src/video_core/renderer_vulkan/declarations.h b/src/video_core/renderer_vulkan/declarations.h index 323bf6b39..89a035ca4 100644 --- a/src/video_core/renderer_vulkan/declarations.h +++ b/src/video_core/renderer_vulkan/declarations.h @@ -39,6 +39,7 @@ using UniqueFence = UniqueHandle<vk::Fence>; using UniqueFramebuffer = UniqueHandle<vk::Framebuffer>; using UniqueImage = UniqueHandle<vk::Image>; using UniqueImageView = UniqueHandle<vk::ImageView>; +using UniqueInstance = UniqueHandle<vk::Instance>; using UniqueIndirectCommandsLayoutNVX = UniqueHandle<vk::IndirectCommandsLayoutNVX>; using UniqueObjectTableNVX = UniqueHandle<vk::ObjectTableNVX>; using UniquePipeline = UniqueHandle<vk::Pipeline>; @@ -50,6 +51,7 @@ using UniqueSampler = UniqueHandle<vk::Sampler>; using UniqueSamplerYcbcrConversion = UniqueHandle<vk::SamplerYcbcrConversion>; using UniqueSemaphore = UniqueHandle<vk::Semaphore>; using UniqueShaderModule = UniqueHandle<vk::ShaderModule>; +using UniqueSurfaceKHR = UniqueHandle<vk::SurfaceKHR>; using UniqueSwapchainKHR = UniqueHandle<vk::SwapchainKHR>; using UniqueValidationCacheEXT = UniqueHandle<vk::ValidationCacheEXT>; using UniqueDebugReportCallbackEXT = UniqueHandle<vk::DebugReportCallbackEXT>; diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 6953aaafe..9cdb4b627 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -2,13 +2,18 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <algorithm> +#include <array> +#include <cstring> #include <memory> #include <optional> +#include <string> #include <vector> #include <fmt/format.h> #include "common/assert.h" +#include "common/dynamic_library.h" #include "common/logging/log.h" #include "common/telemetry.h" #include "core/core.h" @@ -30,15 +35,30 @@ #include "video_core/renderer_vulkan/vk_state_tracker.h" #include "video_core/renderer_vulkan/vk_swapchain.h" +// Include these late to avoid changing Vulkan-Hpp's dynamic dispatcher size +#ifdef _WIN32 +#include <windows.h> +// ensure include order +#include <vulkan/vulkan_win32.h> +#endif + +#ifdef __linux__ +#include <X11/Xlib.h> +#include <vulkan/vulkan_wayland.h> +#include <vulkan/vulkan_xlib.h> +#endif + namespace Vulkan { namespace { +using Core::Frontend::WindowSystemType; + VkBool32 DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity_, VkDebugUtilsMessageTypeFlagsEXT type, const VkDebugUtilsMessengerCallbackDataEXT* data, [[maybe_unused]] void* user_data) { - const vk::DebugUtilsMessageSeverityFlagBitsEXT severity{severity_}; + const auto severity{static_cast<vk::DebugUtilsMessageSeverityFlagBitsEXT>(severity_)}; const char* message{data->pMessage}; if (severity & vk::DebugUtilsMessageSeverityFlagBitsEXT::eError) { @@ -53,6 +73,110 @@ VkBool32 DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity_, return VK_FALSE; } +Common::DynamicLibrary OpenVulkanLibrary() { + Common::DynamicLibrary library; +#ifdef __APPLE__ + // Check if a path to a specific Vulkan library has been specified. + char* libvulkan_env = getenv("LIBVULKAN_PATH"); + if (!libvulkan_env || !library.Open(libvulkan_env)) { + // Use the libvulkan.dylib from the application bundle. + std::string filename = File::GetBundleDirectory() + "/Contents/Frameworks/libvulkan.dylib"; + library.Open(filename.c_str()); + } +#else + std::string filename = Common::DynamicLibrary::GetVersionedFilename("vulkan", 1); + if (!library.Open(filename.c_str())) { + // Android devices may not have libvulkan.so.1, only libvulkan.so. + filename = Common::DynamicLibrary::GetVersionedFilename("vulkan"); + library.Open(filename.c_str()); + } +#endif + return library; +} + +UniqueInstance CreateInstance(Common::DynamicLibrary& library, vk::DispatchLoaderDynamic& dld, + WindowSystemType window_type = WindowSystemType::Headless, + bool enable_layers = false) { + if (!library.IsOpen()) { + LOG_ERROR(Render_Vulkan, "Vulkan library not available"); + return UniqueInstance{}; + } + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; + if (!library.GetSymbol("vkGetInstanceProcAddr", &vkGetInstanceProcAddr)) { + LOG_ERROR(Render_Vulkan, "vkGetInstanceProcAddr not present in Vulkan"); + return UniqueInstance{}; + } + dld.init(vkGetInstanceProcAddr); + + std::vector<const char*> extensions; + extensions.reserve(4); + switch (window_type) { + case Core::Frontend::WindowSystemType::Headless: + break; +#ifdef _WIN32 + case Core::Frontend::WindowSystemType::Windows: + extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); + break; +#endif +#ifdef __linux__ + case Core::Frontend::WindowSystemType::X11: + extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); + break; + case Core::Frontend::WindowSystemType::Wayland: + extensions.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME); + break; +#endif + default: + LOG_ERROR(Render_Vulkan, "Presentation not supported on this platform"); + break; + } + if (window_type != Core::Frontend::WindowSystemType::Headless) { + extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME); + } + if (enable_layers) { + extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + } + + u32 num_properties; + if (vk::enumerateInstanceExtensionProperties(nullptr, &num_properties, nullptr, dld) != + vk::Result::eSuccess) { + LOG_ERROR(Render_Vulkan, "Failed to query number of extension properties"); + return UniqueInstance{}; + } + std::vector<vk::ExtensionProperties> properties(num_properties); + if (vk::enumerateInstanceExtensionProperties(nullptr, &num_properties, properties.data(), + dld) != vk::Result::eSuccess) { + LOG_ERROR(Render_Vulkan, "Failed to query extension properties"); + return UniqueInstance{}; + } + + for (const char* extension : extensions) { + const auto it = + std::find_if(properties.begin(), properties.end(), [extension](const auto& prop) { + return !std::strcmp(extension, prop.extensionName); + }); + if (it == properties.end()) { + LOG_ERROR(Render_Vulkan, "Required instance extension {} is not available", extension); + return UniqueInstance{}; + } + } + + const vk::ApplicationInfo application_info("yuzu Emulator", VK_MAKE_VERSION(0, 1, 0), + "yuzu Emulator", VK_MAKE_VERSION(0, 1, 0), + VK_API_VERSION_1_1); + const std::array layers = {"VK_LAYER_LUNARG_standard_validation"}; + const vk::InstanceCreateInfo instance_ci( + {}, &application_info, enable_layers ? static_cast<u32>(layers.size()) : 0, layers.data(), + static_cast<u32>(extensions.size()), extensions.data()); + vk::Instance unsafe_instance; + if (vk::createInstance(&instance_ci, nullptr, &unsafe_instance, dld) != vk::Result::eSuccess) { + LOG_ERROR(Render_Vulkan, "Failed to create Vulkan instance"); + return UniqueInstance{}; + } + dld.init(unsafe_instance); + return UniqueInstance(unsafe_instance, {nullptr, dld}); +} + std::string GetReadableVersion(u32 version) { return fmt::format("{}.{}.{}", VK_VERSION_MAJOR(version), VK_VERSION_MINOR(version), VK_VERSION_PATCH(version)); @@ -147,27 +271,12 @@ bool RendererVulkan::TryPresent(int /*timeout_ms*/) { } bool RendererVulkan::Init() { - PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr{}; - render_window.RetrieveVulkanHandlers(&vkGetInstanceProcAddr, &instance, &surface); - const vk::DispatchLoaderDynamic dldi(instance, vkGetInstanceProcAddr); - - std::optional<vk::DebugUtilsMessengerEXT> callback; - if (Settings::values.renderer_debug && dldi.vkCreateDebugUtilsMessengerEXT) { - callback = CreateDebugCallback(dldi); - if (!callback) { - return false; - } - } - - if (!PickDevices(dldi)) { - if (callback) { - instance.destroy(*callback, nullptr, dldi); - } + library = OpenVulkanLibrary(); + instance = CreateInstance(library, dld, render_window.GetWindowInfo().type, + Settings::values.renderer_debug); + if (!instance || !CreateDebugCallback() || !CreateSurface() || !PickDevices()) { return false; } - debug_callback = UniqueDebugUtilsMessengerEXT( - *callback, vk::ObjectDestroy<vk::Instance, vk::DispatchLoaderDynamic>( - instance, nullptr, device->GetDispatchLoader())); Report(); @@ -176,7 +285,7 @@ bool RendererVulkan::Init() { resource_manager = std::make_unique<VKResourceManager>(*device); const auto& framebuffer = render_window.GetFramebufferLayout(); - swapchain = std::make_unique<VKSwapchain>(surface, *device); + swapchain = std::make_unique<VKSwapchain>(*surface, *device); swapchain->Create(framebuffer.width, framebuffer.height, false); state_tracker = std::make_unique<StateTracker>(system); @@ -213,8 +322,10 @@ void RendererVulkan::ShutDown() { device.reset(); } -std::optional<vk::DebugUtilsMessengerEXT> RendererVulkan::CreateDebugCallback( - const vk::DispatchLoaderDynamic& dldi) { +bool RendererVulkan::CreateDebugCallback() { + if (!Settings::values.renderer_debug) { + return true; + } const vk::DebugUtilsMessengerCreateInfoEXT callback_ci( {}, vk::DebugUtilsMessageSeverityFlagBitsEXT::eError | @@ -225,32 +336,88 @@ std::optional<vk::DebugUtilsMessengerEXT> RendererVulkan::CreateDebugCallback( vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation | vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance, &DebugCallback, nullptr); - vk::DebugUtilsMessengerEXT callback; - if (instance.createDebugUtilsMessengerEXT(&callback_ci, nullptr, &callback, dldi) != + vk::DebugUtilsMessengerEXT unsafe_callback; + if (instance->createDebugUtilsMessengerEXT(&callback_ci, nullptr, &unsafe_callback, dld) != vk::Result::eSuccess) { LOG_ERROR(Render_Vulkan, "Failed to create debug callback"); - return {}; + return false; + } + debug_callback = UniqueDebugUtilsMessengerEXT(unsafe_callback, {*instance, nullptr, dld}); + return true; +} + +bool RendererVulkan::CreateSurface() { + [[maybe_unused]] const auto& window_info = render_window.GetWindowInfo(); + VkSurfaceKHR unsafe_surface = nullptr; + +#ifdef _WIN32 + if (window_info.type == Core::Frontend::WindowSystemType::Windows) { + const HWND hWnd = static_cast<HWND>(window_info.render_surface); + const VkWin32SurfaceCreateInfoKHR win32_ci{VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, + nullptr, 0, nullptr, hWnd}; + const auto vkCreateWin32SurfaceKHR = reinterpret_cast<PFN_vkCreateWin32SurfaceKHR>( + dld.vkGetInstanceProcAddr(*instance, "vkCreateWin32SurfaceKHR")); + if (!vkCreateWin32SurfaceKHR || vkCreateWin32SurfaceKHR(instance.get(), &win32_ci, nullptr, + &unsafe_surface) != VK_SUCCESS) { + LOG_ERROR(Render_Vulkan, "Failed to initialize Win32 surface"); + return false; + } + } +#endif +#ifdef __linux__ + if (window_info.type == Core::Frontend::WindowSystemType::X11) { + const VkXlibSurfaceCreateInfoKHR xlib_ci{ + VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, nullptr, 0, + static_cast<Display*>(window_info.display_connection), + reinterpret_cast<Window>(window_info.render_surface)}; + const auto vkCreateXlibSurfaceKHR = reinterpret_cast<PFN_vkCreateXlibSurfaceKHR>( + dld.vkGetInstanceProcAddr(*instance, "vkCreateXlibSurfaceKHR")); + if (!vkCreateXlibSurfaceKHR || vkCreateXlibSurfaceKHR(instance.get(), &xlib_ci, nullptr, + &unsafe_surface) != VK_SUCCESS) { + LOG_ERROR(Render_Vulkan, "Failed to initialize Xlib surface"); + return false; + } + } + if (window_info.type == Core::Frontend::WindowSystemType::Wayland) { + const VkWaylandSurfaceCreateInfoKHR wayland_ci{ + VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, nullptr, 0, + static_cast<wl_display*>(window_info.display_connection), + static_cast<wl_surface*>(window_info.render_surface)}; + const auto vkCreateWaylandSurfaceKHR = reinterpret_cast<PFN_vkCreateWaylandSurfaceKHR>( + dld.vkGetInstanceProcAddr(*instance, "vkCreateWaylandSurfaceKHR")); + if (!vkCreateWaylandSurfaceKHR || + vkCreateWaylandSurfaceKHR(instance.get(), &wayland_ci, nullptr, &unsafe_surface) != + VK_SUCCESS) { + LOG_ERROR(Render_Vulkan, "Failed to initialize Wayland surface"); + return false; + } + } +#endif + if (!unsafe_surface) { + LOG_ERROR(Render_Vulkan, "Presentation not supported on this platform"); + return false; } - return callback; + + surface = UniqueSurfaceKHR(unsafe_surface, {*instance, nullptr, dld}); + return true; } -bool RendererVulkan::PickDevices(const vk::DispatchLoaderDynamic& dldi) { - const auto devices = instance.enumeratePhysicalDevices(dldi); +bool RendererVulkan::PickDevices() { + const auto devices = instance->enumeratePhysicalDevices(dld); - // TODO(Rodrigo): Choose device from config file const s32 device_index = Settings::values.vulkan_device; if (device_index < 0 || device_index >= static_cast<s32>(devices.size())) { LOG_ERROR(Render_Vulkan, "Invalid device index {}!", device_index); return false; } - const vk::PhysicalDevice physical_device = devices[device_index]; + const vk::PhysicalDevice physical_device = devices[static_cast<std::size_t>(device_index)]; - if (!VKDevice::IsSuitable(dldi, physical_device, surface)) { + if (!VKDevice::IsSuitable(physical_device, *surface, dld)) { return false; } - device = std::make_unique<VKDevice>(dldi, physical_device, surface); - return device->Create(dldi, instance); + device = std::make_unique<VKDevice>(dld, physical_device, *surface); + return device->Create(*instance); } void RendererVulkan::Report() const { @@ -276,4 +443,33 @@ void RendererVulkan::Report() const { telemetry_session.AddField(field, "GPU_Vulkan_Extensions", extensions); } +std::vector<std::string> RendererVulkan::EnumerateDevices() { + // Avoid putting DispatchLoaderDynamic, it's too large + auto dld_memory = std::make_unique<vk::DispatchLoaderDynamic>(); + auto& dld = *dld_memory; + + Common::DynamicLibrary library = OpenVulkanLibrary(); + UniqueInstance instance = CreateInstance(library, dld); + if (!instance) { + return {}; + } + + u32 num_devices; + if (instance->enumeratePhysicalDevices(&num_devices, nullptr, dld) != vk::Result::eSuccess) { + return {}; + } + std::vector<vk::PhysicalDevice> devices(num_devices); + if (instance->enumeratePhysicalDevices(&num_devices, devices.data(), dld) != + vk::Result::eSuccess) { + return {}; + } + + std::vector<std::string> names; + names.reserve(num_devices); + for (auto& device : devices) { + names.push_back(device.getProperties(dld).deviceName); + } + return names; +} + } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index d14384e79..42e253de5 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h @@ -6,8 +6,11 @@ #include <memory> #include <optional> +#include <string> #include <vector> +#include "common/dynamic_library.h" + #include "video_core/renderer_base.h" #include "video_core/renderer_vulkan/declarations.h" @@ -44,18 +47,24 @@ public: void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override; bool TryPresent(int timeout_ms) override; + static std::vector<std::string> EnumerateDevices(); + private: - std::optional<vk::DebugUtilsMessengerEXT> CreateDebugCallback( - const vk::DispatchLoaderDynamic& dldi); + bool CreateDebugCallback(); - bool PickDevices(const vk::DispatchLoaderDynamic& dldi); + bool CreateSurface(); + + bool PickDevices(); void Report() const; Core::System& system; - vk::Instance instance; - vk::SurfaceKHR surface; + Common::DynamicLibrary library; + vk::DispatchLoaderDynamic dld; + + UniqueInstance instance; + UniqueSurfaceKHR surface; VKScreenInfo screen_info; diff --git a/src/video_core/renderer_vulkan/vk_device.cpp b/src/video_core/renderer_vulkan/vk_device.cpp index 7aafb5e59..6f4ae9132 100644 --- a/src/video_core/renderer_vulkan/vk_device.cpp +++ b/src/video_core/renderer_vulkan/vk_device.cpp @@ -10,6 +10,7 @@ #include <string_view> #include <thread> #include <vector> + #include "common/assert.h" #include "core/settings.h" #include "video_core/renderer_vulkan/declarations.h" @@ -35,20 +36,20 @@ void SetNext(void**& next, T& data) { } template <typename T> -T GetFeatures(vk::PhysicalDevice physical, const vk::DispatchLoaderDynamic& dldi) { +T GetFeatures(vk::PhysicalDevice physical, const vk::DispatchLoaderDynamic& dld) { vk::PhysicalDeviceFeatures2 features; T extension_features; features.pNext = &extension_features; - physical.getFeatures2(&features, dldi); + physical.getFeatures2(&features, dld); return extension_features; } template <typename T> -T GetProperties(vk::PhysicalDevice physical, const vk::DispatchLoaderDynamic& dldi) { +T GetProperties(vk::PhysicalDevice physical, const vk::DispatchLoaderDynamic& dld) { vk::PhysicalDeviceProperties2 properties; T extension_properties; properties.pNext = &extension_properties; - physical.getProperties2(&properties, dldi); + physical.getProperties2(&properties, dld); return extension_properties; } @@ -78,19 +79,19 @@ vk::FormatFeatureFlags GetFormatFeatures(vk::FormatProperties properties, Format } // Anonymous namespace -VKDevice::VKDevice(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical, +VKDevice::VKDevice(const vk::DispatchLoaderDynamic& dld, vk::PhysicalDevice physical, vk::SurfaceKHR surface) - : physical{physical}, properties{physical.getProperties(dldi)}, - format_properties{GetFormatProperties(dldi, physical)} { - SetupFamilies(dldi, surface); - SetupFeatures(dldi); + : dld{dld}, physical{physical}, properties{physical.getProperties(dld)}, + format_properties{GetFormatProperties(dld, physical)} { + SetupFamilies(surface); + SetupFeatures(); } VKDevice::~VKDevice() = default; -bool VKDevice::Create(const vk::DispatchLoaderDynamic& dldi, vk::Instance instance) { +bool VKDevice::Create(vk::Instance instance) { const auto queue_cis = GetDeviceQueueCreateInfos(); - const std::vector extensions = LoadExtensions(dldi); + const std::vector extensions = LoadExtensions(); vk::PhysicalDeviceFeatures2 features2; void** next = &features2.pNext; @@ -165,15 +166,13 @@ bool VKDevice::Create(const vk::DispatchLoaderDynamic& dldi, vk::Instance instan nullptr); device_ci.pNext = &features2; - vk::Device dummy_logical; - if (physical.createDevice(&device_ci, nullptr, &dummy_logical, dldi) != vk::Result::eSuccess) { + vk::Device unsafe_logical; + if (physical.createDevice(&device_ci, nullptr, &unsafe_logical, dld) != vk::Result::eSuccess) { LOG_CRITICAL(Render_Vulkan, "Logical device failed to be created!"); return false; } - - dld.init(instance, dldi.vkGetInstanceProcAddr, dummy_logical, dldi.vkGetDeviceProcAddr); - logical = UniqueDevice( - dummy_logical, vk::ObjectDestroy<vk::NoParent, vk::DispatchLoaderDynamic>(nullptr, dld)); + dld.init(instance, dld.vkGetInstanceProcAddr, unsafe_logical); + logical = UniqueDevice(unsafe_logical, {nullptr, dld}); CollectTelemetryParameters(); @@ -235,8 +234,8 @@ void VKDevice::ReportLoss() const { // *(VKGraphicsPipeline*)data[0] } -bool VKDevice::IsOptimalAstcSupported(const vk::PhysicalDeviceFeatures& features, - const vk::DispatchLoaderDynamic& dldi) const { +bool VKDevice::IsOptimalAstcSupported(const vk::PhysicalDeviceFeatures& features) const { + // Disable for now to avoid converting ASTC twice. static constexpr std::array astc_formats = { vk::Format::eAstc4x4UnormBlock, vk::Format::eAstc4x4SrgbBlock, vk::Format::eAstc5x4UnormBlock, vk::Format::eAstc5x4SrgbBlock, @@ -260,7 +259,7 @@ bool VKDevice::IsOptimalAstcSupported(const vk::PhysicalDeviceFeatures& features vk::FormatFeatureFlagBits::eBlitDst | vk::FormatFeatureFlagBits::eTransferSrc | vk::FormatFeatureFlagBits::eTransferDst}; for (const auto format : astc_formats) { - const auto format_properties{physical.getFormatProperties(format, dldi)}; + const auto format_properties{physical.getFormatProperties(format, dld)}; if (!(format_properties.optimalTilingFeatures & format_feature_usage)) { return false; } @@ -279,11 +278,9 @@ bool VKDevice::IsFormatSupported(vk::Format wanted_format, vk::FormatFeatureFlag return (supported_usage & wanted_usage) == wanted_usage; } -bool VKDevice::IsSuitable(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical, - vk::SurfaceKHR surface) { - bool is_suitable = true; - - constexpr std::array required_extensions = { +bool VKDevice::IsSuitable(vk::PhysicalDevice physical, vk::SurfaceKHR surface, + const vk::DispatchLoaderDynamic& dld) { + static constexpr std::array required_extensions = { VK_KHR_SWAPCHAIN_EXTENSION_NAME, VK_KHR_16BIT_STORAGE_EXTENSION_NAME, VK_KHR_8BIT_STORAGE_EXTENSION_NAME, @@ -293,9 +290,10 @@ bool VKDevice::IsSuitable(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDev VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME, VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME, }; + bool is_suitable = true; std::bitset<required_extensions.size()> available_extensions{}; - for (const auto& prop : physical.enumerateDeviceExtensionProperties(nullptr, dldi)) { + for (const auto& prop : physical.enumerateDeviceExtensionProperties(nullptr, dld)) { for (std::size_t i = 0; i < required_extensions.size(); ++i) { if (available_extensions[i]) { continue; @@ -315,7 +313,7 @@ bool VKDevice::IsSuitable(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDev } bool has_graphics{}, has_present{}; - const auto queue_family_properties = physical.getQueueFamilyProperties(dldi); + const auto queue_family_properties = physical.getQueueFamilyProperties(dld); for (u32 i = 0; i < static_cast<u32>(queue_family_properties.size()); ++i) { const auto& family = queue_family_properties[i]; if (family.queueCount == 0) { @@ -323,7 +321,7 @@ bool VKDevice::IsSuitable(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDev } has_graphics |= (family.queueFlags & vk::QueueFlagBits::eGraphics) != static_cast<vk::QueueFlagBits>(0); - has_present |= physical.getSurfaceSupportKHR(i, surface, dldi) != 0; + has_present |= physical.getSurfaceSupportKHR(i, surface, dld) != 0; } if (!has_graphics || !has_present) { LOG_ERROR(Render_Vulkan, "Device lacks a graphics and present queue"); @@ -331,7 +329,7 @@ bool VKDevice::IsSuitable(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDev } // TODO(Rodrigo): Check if the device matches all requeriments. - const auto properties{physical.getProperties(dldi)}; + const auto properties{physical.getProperties(dld)}; const auto& limits{properties.limits}; constexpr u32 required_ubo_size = 65536; @@ -348,7 +346,7 @@ bool VKDevice::IsSuitable(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDev is_suitable = false; } - const auto features{physical.getFeatures(dldi)}; + const auto features{physical.getFeatures(dld)}; const std::array feature_report = { std::make_pair(features.vertexPipelineStoresAndAtomics, "vertexPipelineStoresAndAtomics"), std::make_pair(features.independentBlend, "independentBlend"), @@ -380,7 +378,7 @@ bool VKDevice::IsSuitable(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDev return is_suitable; } -std::vector<const char*> VKDevice::LoadExtensions(const vk::DispatchLoaderDynamic& dldi) { +std::vector<const char*> VKDevice::LoadExtensions() { std::vector<const char*> extensions; const auto Test = [&](const vk::ExtensionProperties& extension, std::optional<std::reference_wrapper<bool>> status, const char* name, @@ -411,7 +409,7 @@ std::vector<const char*> VKDevice::LoadExtensions(const vk::DispatchLoaderDynami bool has_khr_shader_float16_int8{}; bool has_ext_subgroup_size_control{}; bool has_ext_transform_feedback{}; - for (const auto& extension : physical.enumerateDeviceExtensionProperties(nullptr, dldi)) { + for (const auto& extension : physical.enumerateDeviceExtensionProperties(nullptr, dld)) { Test(extension, khr_uniform_buffer_standard_layout, VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_EXTENSION_NAME, true); Test(extension, has_khr_shader_float16_int8, VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, @@ -433,15 +431,15 @@ std::vector<const char*> VKDevice::LoadExtensions(const vk::DispatchLoaderDynami if (has_khr_shader_float16_int8) { is_float16_supported = - GetFeatures<vk::PhysicalDeviceFloat16Int8FeaturesKHR>(physical, dldi).shaderFloat16; + GetFeatures<vk::PhysicalDeviceFloat16Int8FeaturesKHR>(physical, dld).shaderFloat16; extensions.push_back(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME); } if (has_ext_subgroup_size_control) { const auto features = - GetFeatures<vk::PhysicalDeviceSubgroupSizeControlFeaturesEXT>(physical, dldi); + GetFeatures<vk::PhysicalDeviceSubgroupSizeControlFeaturesEXT>(physical, dld); const auto properties = - GetProperties<vk::PhysicalDeviceSubgroupSizeControlPropertiesEXT>(physical, dldi); + GetProperties<vk::PhysicalDeviceSubgroupSizeControlPropertiesEXT>(physical, dld); is_warp_potentially_bigger = properties.maxSubgroupSize > GuestWarpSize; @@ -456,9 +454,9 @@ std::vector<const char*> VKDevice::LoadExtensions(const vk::DispatchLoaderDynami if (has_ext_transform_feedback) { const auto features = - GetFeatures<vk::PhysicalDeviceTransformFeedbackFeaturesEXT>(physical, dldi); + GetFeatures<vk::PhysicalDeviceTransformFeedbackFeaturesEXT>(physical, dld); const auto properties = - GetProperties<vk::PhysicalDeviceTransformFeedbackPropertiesEXT>(physical, dldi); + GetProperties<vk::PhysicalDeviceTransformFeedbackPropertiesEXT>(physical, dld); if (features.transformFeedback && features.geometryStreams && properties.maxTransformFeedbackStreams >= 4 && properties.maxTransformFeedbackBuffers && @@ -471,10 +469,10 @@ std::vector<const char*> VKDevice::LoadExtensions(const vk::DispatchLoaderDynami return extensions; } -void VKDevice::SetupFamilies(const vk::DispatchLoaderDynamic& dldi, vk::SurfaceKHR surface) { +void VKDevice::SetupFamilies(vk::SurfaceKHR surface) { std::optional<u32> graphics_family_, present_family_; - const auto queue_family_properties = physical.getQueueFamilyProperties(dldi); + const auto queue_family_properties = physical.getQueueFamilyProperties(dld); for (u32 i = 0; i < static_cast<u32>(queue_family_properties.size()); ++i) { if (graphics_family_ && present_family_) break; @@ -483,10 +481,12 @@ void VKDevice::SetupFamilies(const vk::DispatchLoaderDynamic& dldi, vk::SurfaceK if (queue_family.queueCount == 0) continue; - if (queue_family.queueFlags & vk::QueueFlagBits::eGraphics) + if (queue_family.queueFlags & vk::QueueFlagBits::eGraphics) { graphics_family_ = i; - if (physical.getSurfaceSupportKHR(i, surface, dldi)) + } + if (physical.getSurfaceSupportKHR(i, surface, dld)) { present_family_ = i; + } } ASSERT(graphics_family_ && present_family_); @@ -494,10 +494,10 @@ void VKDevice::SetupFamilies(const vk::DispatchLoaderDynamic& dldi, vk::SurfaceK present_family = *present_family_; } -void VKDevice::SetupFeatures(const vk::DispatchLoaderDynamic& dldi) { - const auto supported_features{physical.getFeatures(dldi)}; +void VKDevice::SetupFeatures() { + const auto supported_features{physical.getFeatures(dld)}; is_formatless_image_load_supported = supported_features.shaderStorageImageReadWithoutFormat; - is_optimal_astc_supported = IsOptimalAstcSupported(supported_features, dldi); + is_optimal_astc_supported = IsOptimalAstcSupported(supported_features); } void VKDevice::CollectTelemetryParameters() { @@ -525,7 +525,7 @@ std::vector<vk::DeviceQueueCreateInfo> VKDevice::GetDeviceQueueCreateInfos() con } std::unordered_map<vk::Format, vk::FormatProperties> VKDevice::GetFormatProperties( - const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical) { + const vk::DispatchLoaderDynamic& dld, vk::PhysicalDevice physical) { static constexpr std::array formats{vk::Format::eA8B8G8R8UnormPack32, vk::Format::eA8B8G8R8UintPack32, vk::Format::eA8B8G8R8SnormPack32, @@ -606,7 +606,7 @@ std::unordered_map<vk::Format, vk::FormatProperties> VKDevice::GetFormatProperti vk::Format::eE5B9G9R9UfloatPack32}; std::unordered_map<vk::Format, vk::FormatProperties> format_properties; for (const auto format : formats) { - format_properties.emplace(format, physical.getFormatProperties(format, dldi)); + format_properties.emplace(format, physical.getFormatProperties(format, dld)); } return format_properties; } diff --git a/src/video_core/renderer_vulkan/vk_device.h b/src/video_core/renderer_vulkan/vk_device.h index 6e656517f..d9d809852 100644 --- a/src/video_core/renderer_vulkan/vk_device.h +++ b/src/video_core/renderer_vulkan/vk_device.h @@ -22,12 +22,12 @@ const u32 GuestWarpSize = 32; /// Handles data specific to a physical device. class VKDevice final { public: - explicit VKDevice(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical, + explicit VKDevice(const vk::DispatchLoaderDynamic& dld, vk::PhysicalDevice physical, vk::SurfaceKHR surface); ~VKDevice(); /// Initializes the device. Returns true on success. - bool Create(const vk::DispatchLoaderDynamic& dldi, vk::Instance instance); + bool Create(vk::Instance instance); /** * Returns a format supported by the device for the passed requeriments. @@ -188,18 +188,18 @@ public: } /// Checks if the physical device is suitable. - static bool IsSuitable(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical, - vk::SurfaceKHR surface); + static bool IsSuitable(vk::PhysicalDevice physical, vk::SurfaceKHR surface, + const vk::DispatchLoaderDynamic& dld); private: /// Loads extensions into a vector and stores available ones in this object. - std::vector<const char*> LoadExtensions(const vk::DispatchLoaderDynamic& dldi); + std::vector<const char*> LoadExtensions(); /// Sets up queue families. - void SetupFamilies(const vk::DispatchLoaderDynamic& dldi, vk::SurfaceKHR surface); + void SetupFamilies(vk::SurfaceKHR surface); /// Sets up device features. - void SetupFeatures(const vk::DispatchLoaderDynamic& dldi); + void SetupFeatures(); /// Collects telemetry information from the device. void CollectTelemetryParameters(); @@ -208,8 +208,7 @@ private: std::vector<vk::DeviceQueueCreateInfo> GetDeviceQueueCreateInfos() const; /// Returns true if ASTC textures are natively supported. - bool IsOptimalAstcSupported(const vk::PhysicalDeviceFeatures& features, - const vk::DispatchLoaderDynamic& dldi) const; + bool IsOptimalAstcSupported(const vk::PhysicalDeviceFeatures& features) const; /// Returns true if a format is supported. bool IsFormatSupported(vk::Format wanted_format, vk::FormatFeatureFlags wanted_usage, @@ -217,10 +216,10 @@ private: /// Returns the device properties for Vulkan formats. static std::unordered_map<vk::Format, vk::FormatProperties> GetFormatProperties( - const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical); + const vk::DispatchLoaderDynamic& dld, vk::PhysicalDevice physical); - const vk::PhysicalDevice physical; ///< Physical device. vk::DispatchLoaderDynamic dld; ///< Device function pointers. + vk::PhysicalDevice physical; ///< Physical device. vk::PhysicalDeviceProperties properties; ///< Device properties. UniqueDevice logical; ///< Logical device. vk::Queue graphics_queue; ///< Main graphics queue. diff --git a/src/video_core/shader/decode/video.cpp b/src/video_core/shader/decode/video.cpp index b047cf870..64ba60ea2 100644 --- a/src/video_core/shader/decode/video.cpp +++ b/src/video_core/shader/decode/video.cpp @@ -10,16 +10,24 @@ namespace VideoCommon::Shader { +using std::move; using Tegra::Shader::Instruction; using Tegra::Shader::OpCode; using Tegra::Shader::Pred; using Tegra::Shader::VideoType; using Tegra::Shader::VmadShr; +using Tegra::Shader::VmnmxOperation; +using Tegra::Shader::VmnmxType; u32 ShaderIR::DecodeVideo(NodeBlock& bb, u32 pc) { const Instruction instr = {program_code[pc]}; const auto opcode = OpCode::Decode(instr); + if (opcode->get().GetId() == OpCode::Id::VMNMX) { + DecodeVMNMX(bb, instr); + return pc; + } + const Node op_a = GetVideoOperand(GetRegister(instr.gpr8), instr.video.is_byte_chunk_a, instr.video.signed_a, instr.video.type_a, instr.video.byte_height_a); @@ -109,4 +117,54 @@ Node ShaderIR::GetVideoOperand(Node op, bool is_chunk, bool is_signed, } } +void ShaderIR::DecodeVMNMX(NodeBlock& bb, Tegra::Shader::Instruction instr) { + UNIMPLEMENTED_IF(!instr.vmnmx.is_op_b_register); + UNIMPLEMENTED_IF(instr.vmnmx.SourceFormatA() != VmnmxType::Bits32); + UNIMPLEMENTED_IF(instr.vmnmx.SourceFormatB() != VmnmxType::Bits32); + UNIMPLEMENTED_IF(instr.vmnmx.is_src_a_signed != instr.vmnmx.is_src_b_signed); + UNIMPLEMENTED_IF(instr.vmnmx.sat); + UNIMPLEMENTED_IF(instr.generates_cc); + + Node op_a = GetRegister(instr.gpr8); + Node op_b = GetRegister(instr.gpr20); + Node op_c = GetRegister(instr.gpr39); + + const bool is_oper1_signed = instr.vmnmx.is_src_a_signed; // Stubbed + const bool is_oper2_signed = instr.vmnmx.is_dest_signed; + + const auto operation_a = instr.vmnmx.mx ? OperationCode::IMax : OperationCode::IMin; + Node value = SignedOperation(operation_a, is_oper1_signed, move(op_a), move(op_b)); + + switch (instr.vmnmx.operation) { + case VmnmxOperation::Mrg_16H: + value = BitfieldInsert(move(op_c), move(value), 16, 16); + break; + case VmnmxOperation::Mrg_16L: + value = BitfieldInsert(move(op_c), move(value), 0, 16); + break; + case VmnmxOperation::Mrg_8B0: + value = BitfieldInsert(move(op_c), move(value), 0, 8); + break; + case VmnmxOperation::Mrg_8B2: + value = BitfieldInsert(move(op_c), move(value), 16, 8); + break; + case VmnmxOperation::Acc: + value = Operation(OperationCode::IAdd, move(value), move(op_c)); + break; + case VmnmxOperation::Min: + value = SignedOperation(OperationCode::IMin, is_oper2_signed, move(value), move(op_c)); + break; + case VmnmxOperation::Max: + value = SignedOperation(OperationCode::IMax, is_oper2_signed, move(value), move(op_c)); + break; + case VmnmxOperation::Nop: + break; + default: + UNREACHABLE(); + break; + } + + SetRegister(bb, instr.gpr0, move(value)); +} + } // namespace VideoCommon::Shader diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h index ca6c976c9..c6e7bdf50 100644 --- a/src/video_core/shader/shader_ir.h +++ b/src/video_core/shader/shader_ir.h @@ -354,6 +354,9 @@ private: /// Marks the usage of a input or output attribute. void MarkAttributeUsage(Tegra::Shader::Attribute::Index index, u64 element); + /// Decodes VMNMX instruction and inserts its code into the passed basic block. + void DecodeVMNMX(NodeBlock& bb, Tegra::Shader::Instruction instr); + void WriteTexInstructionFloat(NodeBlock& bb, Tegra::Shader::Instruction instr, const Node4& components); diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h index 59b8a5e66..eba05aced 100644 --- a/src/video_core/textures/texture.h +++ b/src/video_core/textures/texture.h @@ -131,6 +131,20 @@ enum class SwizzleSource : u32 { OneFloat = 7, }; +enum class MsaaMode : u32 { + Msaa1x1 = 0, + Msaa2x1 = 1, + Msaa2x2 = 2, + Msaa4x2 = 3, + Msaa4x2_D3D = 4, + Msaa2x1_D3D = 5, + Msaa4x4 = 6, + Msaa2x2_VC4 = 8, + Msaa2x2_VC12 = 9, + Msaa4x2_VC8 = 10, + Msaa4x2_VC24 = 11, +}; + union TextureHandle { TextureHandle(u32 raw) : raw{raw} {} @@ -197,6 +211,7 @@ struct TICEntry { union { BitField<0, 4, u32> res_min_mip_level; BitField<4, 4, u32> res_max_mip_level; + BitField<8, 4, MsaaMode> msaa_mode; BitField<12, 12, u32> min_lod_clamp; }; |