diff --git a/assets/config_menu/graphics.rml b/assets/config_menu/graphics.rml index 76b2de4..85ac42a 100644 --- a/assets/config_menu/graphics.rml +++ b/assets/config_menu/graphics.rml @@ -204,6 +204,7 @@ data-event-blur="set_current_gfx_description(-1)" data-event-focus="set_current_gfx_description(5)" name="antialiasing" + data-attrif-disabled="!msaa2x_supported" data-checked="msaa_option" value="MSAA2X" id="msaa_2x" @@ -214,6 +215,7 @@ data-event-blur="set_current_gfx_description(-1)" data-event-focus="set_current_gfx_description(5)" name="antialiasing" + data-attrif-disabled="!msaa4x_supported" data-checked="msaa_option" value="MSAA4X" id="msaa_4x" @@ -222,31 +224,38 @@ +
Not available (missing sample positions support)

- Sets the output resolution of the game. + Sets the output resolution of the game. Original matches the game's original 240p resolution. Original 2x will render at 480p. Auto will scale based on the game window's resolution.

Renders at a higher resolution and scales it down to the output resolution for increased quality. Only available in Original and Original 2x resolution. +
+
+ Note: 4x downsampling quality at Original 2x resolution may cause performance issues on low end devices, as it will cause the game to render at almost 4k internal resolution.

- Sets the horizontal aspect ratio. Original limits the game to 4:3 (N64). Expand will adjust the game to match your display's horizontal resolution. + Sets the horizontal aspect ratio. Original uses the game's original 4:3 aspect ratio. Expand will adjust to match the game window's aspect ratio.

Sets whether the game should display on a Window or Fullscreen. You can also use Alt + Enter to toggle this option.

- Doesn't affect gameplay. If you have issues on Display while using an external frame limiter, use Manual with that frame limit instead. + Sets the game's output framerate. This option does not affect gameplay. +
+
+ Note: If you have issues with Display mode while using an external frame limiter, use Manual mode instead and configure it to that same frame limit.

- Sets the Multisample anti-aliasing (MSAA) quality level. This reduces jagged edges in the final image at the expense of rendering performance. + Sets the multisample anti-aliasing (MSAA) quality level. This reduces jagged edges in the final image at the expense of rendering performance.

- Note: This option won't be available if your GPU does not support MSAA Sample Positions during the time being as it is required to avoid rendering glitches. + Note: This option won't be available if your GPU does not support programmable MSAA sample positions, as it is currently required to avoid rendering glitches.

@@ -269,4 +278,3 @@ - \ No newline at end of file diff --git a/include/recomp_config.h b/include/recomp_config.h index 6cd556f..1dd9a16 100644 --- a/include/recomp_config.h +++ b/include/recomp_config.h @@ -13,7 +13,6 @@ namespace recomp { void save_config(); void reset_input_bindings(); - void reset_graphics_options(); std::filesystem::path get_app_folder_path(); diff --git a/include/recomp_ui.h b/include/recomp_ui.h index e676d39..6c7a958 100644 --- a/include/recomp_ui.h +++ b/include/recomp_ui.h @@ -59,6 +59,8 @@ namespace recomp { void apply_color_hack(); void get_window_size(int& width, int& height); void set_cursor_visible(bool visible); + void update_supported_options(); + void toggle_fullscreen(); } #endif diff --git a/include/rt64_layer.h b/include/rt64_layer.h index b5df376..1b207c7 100644 --- a/include/rt64_layer.h +++ b/include/rt64_layer.h @@ -20,6 +20,7 @@ void RT64UpdateScreen(uint32_t vi_origin); void RT64ChangeWindow(); void RT64Shutdown(); RT64::UserConfiguration::Antialiasing RT64MaxMSAA(); +bool RT64SamplePositionsSupported(); uint32_t RT64GetDisplayFramerate(RT64::Application* application); void set_rt64_hooks(); diff --git a/patches/effect_transform_tagging.c b/patches/effect_transform_tagging.c index e9e1f03..b54c679 100644 --- a/patches/effect_transform_tagging.c +++ b/patches/effect_transform_tagging.c @@ -500,7 +500,7 @@ void EffStk_Draw(Actor* thisx, PlayState* play) { gSPDisplayList(POLY_XLU_DISP++, object_stk2_DL_008920); gSPDisplayList(POLY_XLU_DISP++, object_stk2_DL_008A38); - // @recomp Tag the transform. + // @recomp Pop the transform tag. gEXPopMatrixGroup(POLY_XLU_DISP++, G_MTX_MODELVIEW); CLOSE_DISPS(play->state.gfxCtx); diff --git a/src/game/config.cpp b/src/game/config.cpp index 3642667..cddaf4b 100644 --- a/src/game/config.cpp +++ b/src/game/config.cpp @@ -170,7 +170,7 @@ void recomp::reset_input_bindings() { assign_all_mappings(recomp::InputDevice::Controller, recomp::default_n64_controller_mappings); } -void recomp::reset_graphics_options() { +void reset_graphics_options() { ultramodern::GraphicsConfig new_config{}; new_config.res_option = res_default; new_config.wm_option = wm_default; @@ -314,7 +314,7 @@ void recomp::load_config() { load_graphics_config(graphics_path); } else { - recomp::reset_graphics_options(); + reset_graphics_options(); save_graphics_config(graphics_path); } diff --git a/src/game/input.cpp b/src/game/input.cpp index 2e07c71..f1dd6e0 100644 --- a/src/game/input.cpp +++ b/src/game/input.cpp @@ -83,7 +83,7 @@ bool sdl_event_filter(void* userdata, SDL_Event* event) { SDL_KeyboardEvent* keyevent = &event->key; if (keyevent->keysym.scancode == SDL_Scancode::SDL_SCANCODE_RETURN && (keyevent->keysym.mod & SDL_Keymod::KMOD_ALT)) { - RT64ChangeWindow(); + recomp::toggle_fullscreen(); } if (scanning_device != recomp::InputDevice::COUNT) { if (keyevent->keysym.scancode == SDL_Scancode::SDL_SCANCODE_ESCAPE) { diff --git a/src/recomp/rt64_layer.cpp b/src/recomp/rt64_layer.cpp index ec7d87d..03abece 100644 --- a/src/recomp/rt64_layer.cpp +++ b/src/recomp/rt64_layer.cpp @@ -109,6 +109,7 @@ unsigned int SP_STATUS_REG = 0; unsigned int RDRAM_SIZE = 0x800000; static RT64::UserConfiguration::Antialiasing device_max_msaa = RT64::UserConfiguration::Antialiasing::None; +static bool sample_positions_supported = false; #define GET_FUNC(lib, name) \ name = (decltype(name))GetProcAddress(lib, #name) @@ -184,11 +185,23 @@ RT64::Application* RT64Init(uint8_t* rdram, ultramodern::WindowHandle window_han #endif // Before configuring multisampling, make sure the device actually supports it for the formats we'll use. If it doesn't, turn off antialiasing in the configuration. - RT64::RenderSampleCounts color_sample_counts = ret->device->getSampleCountsSupported(RT64::RenderFormat::R8G8B8A8_UNORM); - RT64::RenderSampleCounts depth_sample_counts = ret->device->getSampleCountsSupported(RT64::RenderFormat::D32_FLOAT); - RT64::RenderSampleCounts common_sample_counts = color_sample_counts & depth_sample_counts; - - device_max_msaa = compute_max_supported_aa(common_sample_counts); + // RT64 requires programmable sample positions for MSAA to function without issues, so check that first. + if (ret->device->getCapabilities().sampleLocations) { + RT64::RenderSampleCounts color_sample_counts = ret->device->getSampleCountsSupported(RT64::RenderFormat::R8G8B8A8_UNORM); + RT64::RenderSampleCounts depth_sample_counts = ret->device->getSampleCountsSupported(RT64::RenderFormat::D32_FLOAT); + RT64::RenderSampleCounts common_sample_counts = color_sample_counts & depth_sample_counts; + device_max_msaa = compute_max_supported_aa(common_sample_counts); + sample_positions_supported = true; + } + else { + device_max_msaa = RT64::UserConfiguration::Antialiasing::None; + sample_positions_supported = false; + } + + // Update the config to account for MSAA support. + ultramodern::GraphicsConfig cur_config = ultramodern::get_graphics_config(); + cur_config.msaa_option = std::min(cur_config.msaa_option, device_max_msaa); + ultramodern::set_graphics_config(cur_config); // Force gbi depth branches to prevent LODs from kicking in. ret->enhancementConfig.f3dex.forceBranch = true; @@ -217,10 +230,6 @@ void RT64UpdateScreen(uint32_t vi_origin) { UpdateScreen(); } -void RT64ChangeWindow() { - ChangeWindow(); -} - void RT64Shutdown() { PluginShutdown(); } @@ -271,6 +280,10 @@ RT64::UserConfiguration::Antialiasing RT64MaxMSAA() { return device_max_msaa; } +bool RT64SamplePositionsSupported() { + return sample_positions_supported; +} + uint32_t RT64GetDisplayFramerate(RT64::Application* application) { return application->presentQueue->ext.sharedResources->swapChainRate; } diff --git a/src/ui/ui_config.cpp b/src/ui/ui_config.cpp index 0315449..ab6079f 100644 --- a/src/ui/ui_config.cpp +++ b/src/ui/ui_config.cpp @@ -7,6 +7,7 @@ #include "../../ultramodern/config.hpp" #include "../../ultramodern/ultramodern.hpp" #include "RmlUi/Core.h" +#include "rt64_layer.h" ultramodern::GraphicsConfig new_options; Rml::DataModelHandle nav_help_model_handle; @@ -71,6 +72,11 @@ static int scanned_input_index = -1; static int focused_input_index = -1; static int focused_gfx_index = -1; +static bool msaa2x_supported = false; +static bool msaa4x_supported = false; +static bool msaa8x_supported = false; +static bool sample_positions_supported = false; + static bool cont_active = true; static recomp::InputDevice cur_device = recomp::InputDevice::Controller; @@ -340,6 +346,7 @@ public: constructor.BindFunc("ds_info", [](Rml::Variant& out) { switch (new_options.res_option) { + default: case ultramodern::Resolution::Auto: out = "Downsampling is not available at auto resolution"; return; @@ -373,6 +380,11 @@ public: }); constructor.Bind("cur_gfx_description", &focused_gfx_index); + constructor.Bind("msaa2x_supported", &msaa2x_supported); + constructor.Bind("msaa4x_supported", &msaa4x_supported); + constructor.Bind("msaa8x_supported", &msaa8x_supported); + constructor.Bind("sample_positions_supported", &sample_positions_supported); + graphics_model_handle = constructor.GetModelHandle(); } @@ -623,3 +635,20 @@ void recomp::set_debug_mode_enabled(bool enabled) { debug_context.model_handle.DirtyVariable("debug_enabled"); } } + +void recomp::update_supported_options() { + msaa2x_supported = RT64MaxMSAA() >= RT64::UserConfiguration::Antialiasing::MSAA2X; + msaa4x_supported = RT64MaxMSAA() >= RT64::UserConfiguration::Antialiasing::MSAA4X; + msaa8x_supported = RT64MaxMSAA() >= RT64::UserConfiguration::Antialiasing::MSAA8X; + sample_positions_supported = RT64SamplePositionsSupported(); + + new_options = ultramodern::get_graphics_config(); + + graphics_model_handle.DirtyAllVariables(); +} + +void recomp::toggle_fullscreen() { + new_options.wm_option = (new_options.wm_option == ultramodern::WindowMode::Windowed) ? ultramodern::WindowMode::Fullscreen : ultramodern::WindowMode::Windowed; + ultramodern::set_graphics_config(new_options); + graphics_model_handle.DirtyVariable("wm_option"); +} diff --git a/ultramodern/events.cpp b/ultramodern/events.cpp index c1a51f2..857bc43 100644 --- a/ultramodern/events.cpp +++ b/ultramodern/events.cpp @@ -294,6 +294,9 @@ void gfx_thread_func(uint8_t* rdram, std::atomic_flag* thread_ready, ultramodern RT64::Application* application = RT64Init(rdram, window_handle, cur_config.load().developer_mode); + // TODO move recomp code out of ultramodern. + recomp::update_supported_options(); + if (application == nullptr) { throw std::runtime_error("Failed to initialize RT64!"); } @@ -342,6 +345,7 @@ void gfx_thread_func(uint8_t* rdram, std::atomic_flag* thread_ready, ultramodern } } } + // TODO move recomp code out of ultramodern. recomp::destroy_ui(); RT64Shutdown(); }