diff --git a/app/src/main/cpp/skyline/common/settings.cpp b/app/src/main/cpp/skyline/common/settings.cpp index 5c6cbd1f..193998c1 100644 --- a/app/src/main/cpp/skyline/common/settings.cpp +++ b/app/src/main/cpp/skyline/common/settings.cpp @@ -19,6 +19,8 @@ namespace skyline { PREF_ELEM("log_level", logLevel, static_cast(element.text().as_uint(static_cast(Logger::LogLevel::Info)))), PREF_ELEM("username_value", username, element.text().as_string()), PREF_ELEM("operation_mode", operationMode, element.attribute("value").as_bool()), + PREF_ELEM("force_triple_buffering", forceTripleBuffering, element.attribute("value").as_bool()), + PREF_ELEM("disable_frame_throttling", disableFrameThrottling, element.attribute("value").as_bool()), }; #undef PREF_ELEM diff --git a/app/src/main/cpp/skyline/common/settings.h b/app/src/main/cpp/skyline/common/settings.h index 682874b7..0c267d72 100644 --- a/app/src/main/cpp/skyline/common/settings.h +++ b/app/src/main/cpp/skyline/common/settings.h @@ -14,7 +14,8 @@ namespace skyline { Logger::LogLevel logLevel; //!< The minimum level that logs need to be for them to be printed std::string username; //!< The name set by the user to be supplied to the guest bool operationMode; //!< If the emulated Switch should be handheld or docked - bool forceTripleBuffering{true}; //!< If the presentation should always triple buffer even if the game double buffers + bool forceTripleBuffering; //!< If the presentation engine should always triple buffer even if the swapchain supports double buffering + bool disableFrameThrottling; //!< Allow the guest to submit frames without any blocking calls /** * @param fd An FD to the preference XML file diff --git a/app/src/main/cpp/skyline/gpu/fence_cycle.h b/app/src/main/cpp/skyline/gpu/fence_cycle.h index a9f04ec6..508d87ed 100644 --- a/app/src/main/cpp/skyline/gpu/fence_cycle.h +++ b/app/src/main/cpp/skyline/gpu/fence_cycle.h @@ -114,35 +114,20 @@ namespace skyline::gpu { */ void AttachObjects(std::initializer_list> dependencies) { if (!signalled.test(std::memory_order_consume)) { - { - auto it{dependencies.begin()}; - while (it != dependencies.end()) { - auto next{std::next(it)}; + auto it{dependencies.begin()}, next{std::next(it)}; + if (it != dependencies.end()) { + while (next != dependencies.end()) { (*it)->next = *next; it = next; + next = std::next(next); } } - - const auto &first{*dependencies.begin()}; - const auto &last{*dependencies.end()}; - std::shared_ptr next{std::atomic_load_explicit(&list, std::memory_order_consume)}; - do { - last->next = next; - if (!next && signalled.test(std::memory_order_consume)) { - std::shared_ptr current{first}; - while (current) { - next.swap(first->next); - current.swap(next); - next.reset(); - } - return; - } - } while (std::atomic_compare_exchange_strong(&list, &next, first)); + AttachObject(*dependencies.begin()); } } template - void AttachObjects(Dependencies... dependencies) { + void AttachObjects(Dependencies &&... dependencies) { AttachObjects(std::initializer_list>{std::forward(dependencies)...}); } }; diff --git a/app/src/main/cpp/skyline/gpu/presentation_engine.cpp b/app/src/main/cpp/skyline/gpu/presentation_engine.cpp index 824034b0..6a9e1543 100644 --- a/app/src/main/cpp/skyline/gpu/presentation_engine.cpp +++ b/app/src/main/cpp/skyline/gpu/presentation_engine.cpp @@ -69,7 +69,7 @@ namespace skyline::gpu { } void PresentationEngine::UpdateSwapchain(texture::Format format, texture::Dimensions extent) { - auto minImageCount{std::max(vkSurfaceCapabilities.minImageCount, state.settings->forceTripleBuffering ? 3U : 0U)}; + auto minImageCount{std::max(vkSurfaceCapabilities.minImageCount, state.settings->forceTripleBuffering ? 3U : 2U)}; if (minImageCount > MaxSwapchainImageCount) throw exception("Requesting swapchain with higher image count ({}) than maximum slot count ({})", minImageCount, MaxSwapchainImageCount); @@ -99,13 +99,14 @@ namespace skyline::gpu { .imageUsage = presentUsage, .imageSharingMode = vk::SharingMode::eExclusive, .compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eInherit, - .presentMode = vk::PresentModeKHR::eMailbox, + .presentMode = state.settings->disableFrameThrottling ? vk::PresentModeKHR::eMailbox : vk::PresentModeKHR::eFifo, .clipped = true, }); auto vkImages{vkSwapchain->getImages()}; if (vkImages.size() > MaxSwapchainImageCount) throw exception("Swapchain has higher image count ({}) than maximum slot count ({})", minImageCount, MaxSwapchainImageCount); + state.logger->Error("Buffer Count: {}", vkImages.size()); for (size_t index{}; index < vkImages.size(); index++) { auto &slot{images[index]}; diff --git a/app/src/main/cpp/skyline/gpu/texture/texture.cpp b/app/src/main/cpp/skyline/gpu/texture/texture.cpp index c9685bfe..5b522efd 100644 --- a/app/src/main/cpp/skyline/gpu/texture/texture.cpp +++ b/app/src/main/cpp/skyline/gpu/texture/texture.cpp @@ -262,8 +262,7 @@ namespace skyline::gpu { }, }); }); - - cycle->AttachObject(stagingBuffer); + cycle->AttachObjects(stagingBuffer, shared_from_this()); } } @@ -376,6 +375,6 @@ namespace skyline::gpu { }, }); }); - cycle->AttachObject(source); + cycle->AttachObjects(source, shared_from_this()); } } diff --git a/app/src/main/cpp/skyline/gpu/texture/texture.h b/app/src/main/cpp/skyline/gpu/texture/texture.h index 296f6827..8ce8dbcc 100644 --- a/app/src/main/cpp/skyline/gpu/texture/texture.h +++ b/app/src/main/cpp/skyline/gpu/texture/texture.h @@ -224,7 +224,7 @@ namespace skyline::gpu { * @brief A texture which is backed by host constructs while being synchronized with the underlying guest texture * @note This class conforms to the Lockable and BasicLockable C++ named requirements */ - class Texture : public FenceCycleDependency { + class Texture : public std::enable_shared_from_this, public FenceCycleDependency { private: GPU &gpu; std::mutex mutex; //!< Synchronizes any mutations to the texture or its backing diff --git a/app/src/main/java/emu/skyline/EmulationActivity.kt b/app/src/main/java/emu/skyline/EmulationActivity.kt index 22c6d645..7490b7a5 100644 --- a/app/src/main/java/emu/skyline/EmulationActivity.kt +++ b/app/src/main/java/emu/skyline/EmulationActivity.kt @@ -212,7 +212,10 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo } @Suppress("DEPRECATION") val display = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) display!! else windowManager.defaultDisplay - display?.supportedModes?.maxByOrNull { it.refreshRate * it.physicalHeight * it.physicalWidth }?.let { window.attributes.preferredDisplayModeId = it.modeId } + if (settings.maxRefreshRate) + display?.supportedModes?.maxByOrNull { it.refreshRate * it.physicalHeight * it.physicalWidth }?.let { window.attributes.preferredDisplayModeId = it.modeId } + else + display?.supportedModes?.minByOrNull { abs(it.refreshRate - 60f) }?.let { window.attributes.preferredDisplayModeId = it.modeId } binding.gameView.setOnTouchListener(this) diff --git a/app/src/main/java/emu/skyline/utils/Settings.kt b/app/src/main/java/emu/skyline/utils/Settings.kt index 8f3b7bf3..1be797dd 100644 --- a/app/src/main/java/emu/skyline/utils/Settings.kt +++ b/app/src/main/java/emu/skyline/utils/Settings.kt @@ -35,4 +35,6 @@ class Settings @Inject constructor(@ApplicationContext private val context : Con var logLevel by sharedPreferences(context, "3") var filter by sharedPreferences(context, 0) + + var maxRefreshRate by sharedPreferences(context, false) } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 993c23b2..24a6172c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -25,7 +25,7 @@ The log file was not found The logs are being uploaded The logs have been cleared - + Emulator Search Location Theme @@ -40,17 +40,30 @@ Compact Logs Logs will be displayed in a compact form factor Logs will be displayed in a verbose form factor + System Use Docked Mode The system will emulate being in handheld mode The system will emulate being in docked mode Username @string/app_name + Keys Production Keys Title Keys Successfully imported keys Failed to import keys + + Display + Force Triple Buffering + Utilize at least 3 swapchain buffers (Higher FPS with higher input lag) + Utilize at least 2 swapchain buffers (Lower FPS with lower input lag) + Disable Frame Throttling + Game is allowed to submit frames as fast as possible (Only for benchmarking) + Only allow the game to submit frames at the display refresh rate + Use Maximum Display Refresh Rate + Sets the display refresh rate as high as possible (Will break most games) + Sets the display refresh rate to 60Hz Input On-Screen Controls diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index afe79085..86d6f35c 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -1,90 +1,105 @@ + xmlns:app="http://schemas.android.com/apk/res-auto"> + android:key="category_emulator" + android:title="@string/emulator"> + app:key="search_location" + app:title="@string/search_location" /> + android:defaultValue="2" + android:entries="@array/app_theme" + android:entryValues="@array/app_theme_val" + app:key="app_theme" + app:title="@string/theme" + app:useSimpleSummaryProvider="true" /> + android:defaultValue="1" + android:entries="@array/layout_type" + android:entryValues="@array/layout_type_val" + app:key="layout_type" + app:title="@string/layout_type" + app:useSimpleSummaryProvider="true" /> + android:defaultValue="false" + android:summaryOff="@string/select_action_desc_off" + android:summaryOn="@string/select_action_desc_on" + app:key="select_action" + app:title="@string/select_action" /> + android:defaultValue="false" + android:summaryOff="@string/perf_stats_desc_off" + android:summaryOn="@string/perf_stats_desc_on" + app:key="perf_stats" + app:title="@string/perf_stats" /> + android:defaultValue="2" + android:entries="@array/log_level" + android:entryValues="@array/log_level_val" + app:key="log_level" + app:title="@string/log_level" + app:useSimpleSummaryProvider="true" /> + android:defaultValue="false" + android:summaryOff="@string/log_compact_desc_off" + android:summaryOn="@string/log_compact_desc_on" + app:key="log_compact" + app:title="@string/log_compact" /> + + + + + + + + android:defaultValue="@string/username_default" + app:key="username_value" + app:limit="31" + app:title="@string/username" /> - - - - + android:key="category_presentation" + android:title="@string/display"> + android:defaultValue="true" + android:summaryOff="@string/triple_buffering_disabled" + android:summaryOn="@string/triple_buffering_enabled" + app:key="force_triple_buffering" + app:title="@string/force_triple_buffering" /> + + - + android:key="category_input" + android:title="@string/input" + app:initialExpandedChildrenCount="4"> @@ -95,73 +110,73 @@ + android:key="category_licenses" + android:title="@string/licenses" + app:initialExpandedChildrenCount="3"> + libraryLicense="@string/mpl2_license" + libraryUrl="https://github.com/skyline-emu/skyline" + app:summary="@string/skyline_license_description" + app:title="@string/app_name" /> + libraryLicense="@string/fmtlib_license" + libraryUrl="https://github.com/fmtlib/fmt" + app:summary="@string/fmtlib_description" + app:title="@string/fmtlib" /> + libraryLicense="@string/apache2_license" + libraryUrl="https://github.com/google/oboe" + app:summary="@string/oboe_description" + app:title="@string/oboe" /> + libraryLicense="@string/apache2_license" + libraryUrl="https://github.com/KhronosGroup/Vulkan-Hpp" + app:summary="@string/vkhpp_description" + app:title="@string/vkhpp" /> + libraryLicense="@string/zlib_license" + libraryUrl="https://github.com/leethomason/tinyxml2" + app:summary="@string/txml2_description" + app:title="@string/txml2" /> + libraryLicense="@string/apache2_license" + libraryUrl="https://github.com/tdebatty/java-string-similarity" + app:summary="@string/jssim_description" + app:title="@string/jssim" /> + libraryLicense="@string/apache2_license" + libraryUrl="https://developer.android.com/jetpack/androidx" + app:summary="@string/andx_description" + app:title="@string/andx" /> + libraryLicense="@string/apache2_license" + libraryUrl="https://github.com/material-components/material-components-android" + app:summary="@string/amat_description" + app:title="@string/amat" /> + libraryLicense="@string/apache2_license" + libraryUrl="https://kotlinlang.org/api/latest/jvm/stdlib" + app:summary="@string/ktstd_description" + app:title="@string/ktstd" /> + libraryLicense="@string/apache2_license" + libraryUrl="https://material.io/resources/icons" + app:summary="@string/mtico_description" + app:title="@string/mtico" /> + libraryLicense="@string/apache2_license" + libraryUrl="https://fonts.google.com/specimen/Open+Sans" + app:summary="@string/open_sans_description" + app:title="@string/open_sans" /> + libraryLicense="@string/apache2_license" + libraryUrl="https://fonts.google.com/specimen/Roboto" + app:summary="@string/roboto_description" + app:title="@string/roboto" /> + libraryLicense="@string/sil_open_font_license" + libraryUrl="https://fonts.google.com/specimen/Source+Sans+Pro" + app:summary="@string/source_sans_pro_description" + app:title="@string/source_sans_pro" />