Skip to content

renderer_vulkan: Implement MSAA#2053

Draft
Wunkolo wants to merge 21 commits intoazahar-emu:masterfrom
Wunkolo:vk-msaa
Draft

renderer_vulkan: Implement MSAA#2053
Wunkolo wants to merge 21 commits intoazahar-emu:masterfrom
Wunkolo:vk-msaa

Conversation

@Wunkolo
Copy link
Copy Markdown
Contributor

@Wunkolo Wunkolo commented Apr 19, 2026


This is a port of the MSAA feature I was implementing for Citra before the "rapture".
Enables Multi-sample anti-aliasing just for Vulkan at the moment.

Addresses #546

Native resolution Native resolution, 4x MSAA
_19 04 26_11 48 07 266 _19 04 26_11 48 15 272
Picross 3D Round 2_19 04 26_11 42 28 042 Picross 3D Round 2_19 04 26_11 42 36 346
Pokémon Omega Ruby_19 04 26_11 27 06 448 Pokémon Omega Ruby_19 04 26_11 27 17 831
Pokémon Omega Ruby_19 04 26_11 33 28 213 Pokémon Omega Ruby_19 04 26_11 38 38 146
Brain Age Concentration Training_19 04 26_11 51 18 091 Brain Age Concentration Training_19 04 26_11 51 27 125

Wunkolo added 13 commits April 26, 2026 14:57
Option is only enabled when the renderer is set to Vulkan, for now.
Helper host-shader for blitting multi-sampled DS24S8 textures to multi-sampled RGBA8
Full multi-sample support is when renderpass-2 and depth-stencil-resolve extensions are available and when sample-rate-shading and msaa-storage-images are supported.
Allows multi-sample render passes and graphics pipelines to be created, using sample-rate shading rather than coverage-based MSAA.
This seems to be enough for simple programs to render with MSAA enabled!
Should address the MultiSampled image directly since the multisampled image is just a transient image and not the leading state of the image.
`sample_count` needs to be move/copied over.

Also reorder the accessor order to match the declaration of variables.
These individual parameters need to be copied as the reference to the surface-object only lasts within the scope of this function.
Derive the framebuffer sample-count from the input color and depth operands. Similar to how `res_scale` is determined.
Try to optimally create the new image handles when a change in res scale or sample-count has actually occured. MSAA images need to be updated too in the case that the resolution scale has changed
Rather than use a big lambda, just rip this out into a proper function for other blit functions to utilize.
Wunkolo added 2 commits April 26, 2026 15:00
Fixes a compilation error on Unix platforms.
Use the specified type rather than defaulting to the surface's current one(implicit `ImageView` argument).
@RedBlackAka
Copy link
Copy Markdown
Contributor

Crashes currently on macOS. Here is a log, though doesn't look very helpful:
azahar_log.old.txt

Might be worth an attempt to test with a newer MoltenVK?

@72374
Copy link
Copy Markdown

72374 commented Apr 27, 2026

When i try to start a game with a build based on this PR, while using a Radeon RX 6750 XT with Mesa 26.0.4 (RADV), and the graphics-API is set to Vulkan, Azahar does quit with what(): boost::container::bad_alloc thrown.

According to testing with printf(), that happens there.

I was able to start games normally, with and without anti-aliasing, after excluding the VK_KHR_fragment_shader_barycentric-extension like this:

Code-change
diff --git a/src/video_core/renderer_vulkan/vk_instance.cpp b/src/video_core/renderer_vulkan/vk_instance.cpp
index e3c90aff4..bde3c0b05 100644
--- a/src/video_core/renderer_vulkan/vk_instance.cpp
+++ b/src/video_core/renderer_vulkan/vk_instance.cpp
@@ -446,6 +446,7 @@ bool Instance::CreateDevice() {
     const bool is_arm = driver_id == vk::DriverIdKHR::eArmProprietary;
     const bool is_qualcomm = driver_id == vk::DriverIdKHR::eQualcommProprietary;
     const bool is_turnip = driver_id == vk::DriverIdKHR::eMesaTurnip;
+    const bool is_radv = driver_id == vk::DriverIdKHR::eMesaRadv;
 
     add_extension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
     image_format_list = add_extension(VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME);
@@ -474,7 +475,7 @@ bool Instance::CreateDevice() {
         add_extension(VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_EXTENSION_NAME, is_nvidia,
                       "it is broken on Nvidia drivers");
     const bool has_fragment_shader_barycentric =
-        add_extension(VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME, is_moltenvk,
+        add_extension(VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME, is_moltenvk || is_radv,
                       "the PerVertexKHR attribute is not supported by MoltenVK");
 
     const auto family_properties = physical_device.getQueueFamilyProperties();

@Wunkolo
Copy link
Copy Markdown
Contributor Author

Wunkolo commented Apr 28, 2026

Oh woah people are already testing it! This is still a draft PR that I am chipping away at. Currently only tested on a Windows+Nvidia machine.

Crashes currently on macOS. Here is a log, though doesn't look very helpful: azahar_log.old.txt

Might be worth an attempt to test with a newer MoltenVK?

Currently untested on MacOS, but previously ran into issues relating to MSAA materials having kinda unstable support in MoltenVK. Was going to look into MacOS proper once the Vulkan implementation proves stable. It's pretty stable for me now actually, outside of some edge cases relating to Depth-Stencil->RGBA blits and such in Pokemon. Open to hearing about more issues that people are facing.

When i try to start a game with a build based on this PR, while using a Radeon RX 6750 XT with Mesa 26.0.4 (RADV), and the graphics-API is set to Vulkan, Azahar does quit with what(): boost::container::bad_alloc thrown.

According to testing with printf(), that happens there.

I was able to start games normally, with and without anti-aliasing, after excluding the VK_KHR_fragment_shader_barycentric-extension like this:

Oh this is interesting. Does this happen on the main branch too? I can imagine there could be an odd interaction with barycentric coordinates and sample-rate shading being on at the same time, as each MSAA sample-position might have different barycentric coordinates.

@72374
Copy link
Copy Markdown

72374 commented Apr 28, 2026

Does this happen on the main branch too?

Nope, on the main branch it works without those changes.

The only other issue, that i noticed so far, is that the solid part of the background of the info-message that appears when one does start Mario Kart 7 without a Mii available, is not there with any sample-count higher than 1:

Images

1x sample-count:
1x sample-count
4x sample-count:
4x sample-count

This happens with a "Radeon RX 6750 XT"-GPU (log) and with an "Intel UHD Graphics 770"-GPU (log).

@Wunkolo
Copy link
Copy Markdown
Contributor Author

Wunkolo commented Apr 29, 2026

Thanks for this. I was seeing a similar issue in other games as well such as Kid Icarus. This should be fixed now. Still seeing some issues with Pokemon and other games that utilize depth-resolves though.

1xScale 1xScale + 4xMSAA
MARIO KART 7_28 04 26_21 45 52 736 MARIO KART 7_28 04 26_21 46 04 882
Kid Icarus Uprising_28 04 26_21 53 47 774 Kid Icarus Uprising_28 04 26_21 54 30 761

Nope, on the main branch it works without those changes.

I'll check this out soon too once I can get access to my AMD GPU again. It's possible that sample-rate-shading and barycentric extensions are unable to both be enabled in such a way.

Wunkolo added 2 commits April 28, 2026 21:48
This should be checking the _new_ value to possibly cull upscaled texture creation rather than the current value of the surface. Fixes broken up render passes when drawing UI in some games.
Ensure that the Multi-Sample texture is used for the destination color image as well. Should the dest image be MSAA too? Or should all the values be resolved into a minimum depth and some combination of stencil-values here?
Wunkolo added 3 commits April 28, 2026 23:32
Ensure that the multisample framebuffer is used rather than the usual one when using a render pass to clear the textures.

That way, a MSAA-render AND resolve is used to clear the textures at the same time.
MSAA renderpasses require the "current" image as the main resolve target, and the MSAA image as the second attachment.
Migrate `ResolveTexture` to `BlitHelper`.
If the conversion was multi-sample, do a final resolve at the end of the conversion to ensure the non-multisample textures are updated as well.

Fixes Pokemon!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants