Implement Display Settings + Attach Texture to FenceCycle

This commit is contained in:
PixelyIon 2021-06-20 03:44:43 +05:30 committed by ◱ Mark
parent b2bb855a02
commit e511e158e3
10 changed files with 178 additions and 157 deletions

View File

@ -19,6 +19,8 @@ namespace skyline {
PREF_ELEM("log_level", logLevel, static_cast<Logger::LogLevel>(element.text().as_uint(static_cast<unsigned int>(Logger::LogLevel::Info)))), PREF_ELEM("log_level", logLevel, static_cast<Logger::LogLevel>(element.text().as_uint(static_cast<unsigned int>(Logger::LogLevel::Info)))),
PREF_ELEM("username_value", username, element.text().as_string()), PREF_ELEM("username_value", username, element.text().as_string()),
PREF_ELEM("operation_mode", operationMode, element.attribute("value").as_bool()), 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 #undef PREF_ELEM

View File

@ -14,7 +14,8 @@ namespace skyline {
Logger::LogLevel logLevel; //!< The minimum level that logs need to be for them to be printed 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 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 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 * @param fd An FD to the preference XML file

View File

@ -114,35 +114,20 @@ namespace skyline::gpu {
*/ */
void AttachObjects(std::initializer_list<std::shared_ptr<FenceCycleDependency>> dependencies) { void AttachObjects(std::initializer_list<std::shared_ptr<FenceCycleDependency>> dependencies) {
if (!signalled.test(std::memory_order_consume)) { if (!signalled.test(std::memory_order_consume)) {
{ auto it{dependencies.begin()}, next{std::next(it)};
auto it{dependencies.begin()}; if (it != dependencies.end()) {
while (it != dependencies.end()) { while (next != dependencies.end()) {
auto next{std::next(it)};
(*it)->next = *next; (*it)->next = *next;
it = next; it = next;
next = std::next(next);
} }
} }
AttachObject(*dependencies.begin());
const auto &first{*dependencies.begin()};
const auto &last{*dependencies.end()};
std::shared_ptr<FenceCycleDependency> 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<FenceCycleDependency> current{first};
while (current) {
next.swap(first->next);
current.swap(next);
next.reset();
}
return;
}
} while (std::atomic_compare_exchange_strong(&list, &next, first));
} }
} }
template<typename... Dependencies> template<typename... Dependencies>
void AttachObjects(Dependencies... dependencies) { void AttachObjects(Dependencies &&... dependencies) {
AttachObjects(std::initializer_list<std::shared_ptr<FenceCycleDependency>>{std::forward<Dependencies>(dependencies)...}); AttachObjects(std::initializer_list<std::shared_ptr<FenceCycleDependency>>{std::forward<Dependencies>(dependencies)...});
} }
}; };

View File

@ -69,7 +69,7 @@ namespace skyline::gpu {
} }
void PresentationEngine::UpdateSwapchain(texture::Format format, texture::Dimensions extent) { 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) if (minImageCount > MaxSwapchainImageCount)
throw exception("Requesting swapchain with higher image count ({}) than maximum slot count ({})", 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, .imageUsage = presentUsage,
.imageSharingMode = vk::SharingMode::eExclusive, .imageSharingMode = vk::SharingMode::eExclusive,
.compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eInherit, .compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eInherit,
.presentMode = vk::PresentModeKHR::eMailbox, .presentMode = state.settings->disableFrameThrottling ? vk::PresentModeKHR::eMailbox : vk::PresentModeKHR::eFifo,
.clipped = true, .clipped = true,
}); });
auto vkImages{vkSwapchain->getImages()}; auto vkImages{vkSwapchain->getImages()};
if (vkImages.size() > MaxSwapchainImageCount) if (vkImages.size() > MaxSwapchainImageCount)
throw exception("Swapchain has higher image count ({}) than maximum slot count ({})", minImageCount, 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++) { for (size_t index{}; index < vkImages.size(); index++) {
auto &slot{images[index]}; auto &slot{images[index]};

View File

@ -262,8 +262,7 @@ namespace skyline::gpu {
}, },
}); });
}); });
cycle->AttachObjects(stagingBuffer, shared_from_this());
cycle->AttachObject(stagingBuffer);
} }
} }
@ -376,6 +375,6 @@ namespace skyline::gpu {
}, },
}); });
}); });
cycle->AttachObject(source); cycle->AttachObjects(source, shared_from_this());
} }
} }

View File

@ -224,7 +224,7 @@ namespace skyline::gpu {
* @brief A texture which is backed by host constructs while being synchronized with the underlying guest texture * @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 * @note This class conforms to the Lockable and BasicLockable C++ named requirements
*/ */
class Texture : public FenceCycleDependency { class Texture : public std::enable_shared_from_this<Texture>, public FenceCycleDependency {
private: private:
GPU &gpu; GPU &gpu;
std::mutex mutex; //!< Synchronizes any mutations to the texture or its backing std::mutex mutex; //!< Synchronizes any mutations to the texture or its backing

View File

@ -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 @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) binding.gameView.setOnTouchListener(this)

View File

@ -35,4 +35,6 @@ class Settings @Inject constructor(@ApplicationContext private val context : Con
var logLevel by sharedPreferences(context, "3") var logLevel by sharedPreferences(context, "3")
var filter by sharedPreferences(context, 0) var filter by sharedPreferences(context, 0)
var maxRefreshRate by sharedPreferences(context, false)
} }

View File

@ -25,7 +25,7 @@
<string name="file_missing">The log file was not found</string> <string name="file_missing">The log file was not found</string>
<string name="upload_logs">The logs are being uploaded</string> <string name="upload_logs">The logs are being uploaded</string>
<string name="cleared">The logs have been cleared</string> <string name="cleared">The logs have been cleared</string>
<!-- Settings --> <!-- Settings - Emulator -->
<string name="emulator">Emulator</string> <string name="emulator">Emulator</string>
<string name="search_location">Search Location</string> <string name="search_location">Search Location</string>
<string name="theme">Theme</string> <string name="theme">Theme</string>
@ -40,17 +40,30 @@
<string name="log_compact">Compact Logs</string> <string name="log_compact">Compact Logs</string>
<string name="log_compact_desc_on">Logs will be displayed in a compact form factor</string> <string name="log_compact_desc_on">Logs will be displayed in a compact form factor</string>
<string name="log_compact_desc_off">Logs will be displayed in a verbose form factor</string> <string name="log_compact_desc_off">Logs will be displayed in a verbose form factor</string>
<!-- Settings - System -->
<string name="system">System</string> <string name="system">System</string>
<string name="use_docked">Use Docked Mode</string> <string name="use_docked">Use Docked Mode</string>
<string name="handheld_enabled">The system will emulate being in handheld mode</string> <string name="handheld_enabled">The system will emulate being in handheld mode</string>
<string name="docked_enabled">The system will emulate being in docked mode</string> <string name="docked_enabled">The system will emulate being in docked mode</string>
<string name="username">Username</string> <string name="username">Username</string>
<string name="username_default">@string/app_name</string> <string name="username_default">@string/app_name</string>
<!-- Settings - Keys -->
<string name="keys">Keys</string> <string name="keys">Keys</string>
<string name="prod_keys">Production Keys</string> <string name="prod_keys">Production Keys</string>
<string name="title_keys">Title Keys</string> <string name="title_keys">Title Keys</string>
<string name="import_keys_success">Successfully imported keys</string> <string name="import_keys_success">Successfully imported keys</string>
<string name="import_keys_failed">Failed to import keys</string> <string name="import_keys_failed">Failed to import keys</string>
<!-- Settings - Display -->
<string name="display">Display</string>
<string name="force_triple_buffering">Force Triple Buffering</string>
<string name="triple_buffering_enabled">Utilize at least 3 swapchain buffers (Higher FPS with higher input lag)</string>
<string name="triple_buffering_disabled">Utilize at least 2 swapchain buffers (Lower FPS with lower input lag)</string>
<string name="disable_frame_throttling">Disable Frame Throttling</string>
<string name="disable_frame_throttling_enabled">Game is allowed to submit frames as fast as possible (Only for benchmarking)</string>
<string name="disable_frame_throttling_disabled">Only allow the game to submit frames at the display refresh rate</string>
<string name="max_refresh_rate">Use Maximum Display Refresh Rate</string>
<string name="max_refresh_rate_enabled">Sets the display refresh rate as high as possible (Will break most games)</string>
<string name="max_refresh_rate_disabled">Sets the display refresh rate to 60Hz</string>
<!-- Input --> <!-- Input -->
<string name="input">Input</string> <string name="input">Input</string>
<string name="osc">On-Screen Controls</string> <string name="osc">On-Screen Controls</string>

View File

@ -1,90 +1,105 @@
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" <androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory <PreferenceCategory
android:key="category_emulator" android:key="category_emulator"
android:title="@string/emulator"> android:title="@string/emulator">
<emu.skyline.preference.FolderPickerPreference <emu.skyline.preference.FolderPickerPreference
app:key="search_location" app:key="search_location"
app:title="@string/search_location" /> app:title="@string/search_location" />
<emu.skyline.preference.ThemePreference <emu.skyline.preference.ThemePreference
android:defaultValue="2" android:defaultValue="2"
android:entries="@array/app_theme" android:entries="@array/app_theme"
android:entryValues="@array/app_theme_val" android:entryValues="@array/app_theme_val"
app:key="app_theme" app:key="app_theme"
app:title="@string/theme" app:title="@string/theme"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<ListPreference <ListPreference
android:defaultValue="1" android:defaultValue="1"
android:entries="@array/layout_type" android:entries="@array/layout_type"
android:entryValues="@array/layout_type_val" android:entryValues="@array/layout_type_val"
app:key="layout_type" app:key="layout_type"
app:title="@string/layout_type" app:title="@string/layout_type"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="false" android:defaultValue="false"
android:summaryOff="@string/select_action_desc_off" android:summaryOff="@string/select_action_desc_off"
android:summaryOn="@string/select_action_desc_on" android:summaryOn="@string/select_action_desc_on"
app:key="select_action" app:key="select_action"
app:title="@string/select_action" /> app:title="@string/select_action" />
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="false" android:defaultValue="false"
android:summaryOff="@string/perf_stats_desc_off" android:summaryOff="@string/perf_stats_desc_off"
android:summaryOn="@string/perf_stats_desc_on" android:summaryOn="@string/perf_stats_desc_on"
app:key="perf_stats" app:key="perf_stats"
app:title="@string/perf_stats" /> app:title="@string/perf_stats" />
<ListPreference <ListPreference
android:defaultValue="2" android:defaultValue="2"
android:entries="@array/log_level" android:entries="@array/log_level"
android:entryValues="@array/log_level_val" android:entryValues="@array/log_level_val"
app:key="log_level" app:key="log_level"
app:title="@string/log_level" app:title="@string/log_level"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="false" android:defaultValue="false"
android:summaryOff="@string/log_compact_desc_off" android:summaryOff="@string/log_compact_desc_off"
android:summaryOn="@string/log_compact_desc_on" android:summaryOn="@string/log_compact_desc_on"
app:key="log_compact" app:key="log_compact"
app:title="@string/log_compact" /> app:title="@string/log_compact" />
</PreferenceCategory>
<PreferenceCategory
android:key="category_keys"
android:title="@string/keys">
<emu.skyline.preference.KeyPickerPreference
app:key="prod_keys"
app:title="@string/prod_keys"
app:useSimpleSummaryProvider="true" />
<emu.skyline.preference.KeyPickerPreference
app:key="title_keys"
app:title="@string/title_keys"
app:useSimpleSummaryProvider="true" />
</PreferenceCategory>
<PreferenceCategory
android:key="category_system"
android:title="@string/system">
<CheckBoxPreference
android:defaultValue="true"
android:summaryOff="@string/handheld_enabled"
android:summaryOn="@string/docked_enabled"
app:key="operation_mode"
app:title="@string/use_docked" />
<emu.skyline.preference.CustomEditTextPreference <emu.skyline.preference.CustomEditTextPreference
android:defaultValue="@string/username_default" android:defaultValue="@string/username_default"
app:key="username_value" app:key="username_value"
app:limit="31" app:limit="31"
app:title="@string/username" /> app:title="@string/username" />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory
android:key="category_keys" android:key="category_presentation"
android:title="@string/keys"> android:title="@string/display">
<emu.skyline.preference.KeyPickerPreference
app:key="prod_keys"
app:title="@string/prod_keys"
app:useSimpleSummaryProvider="true" />
<emu.skyline.preference.KeyPickerPreference
app:key="title_keys"
app:title="@string/title_keys"
app:useSimpleSummaryProvider="true" />
</PreferenceCategory>
<PreferenceCategory
android:key="category_system"
android:title="@string/system">
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="true" android:defaultValue="true"
android:summaryOff="@string/handheld_enabled" android:summaryOff="@string/triple_buffering_disabled"
android:summaryOn="@string/docked_enabled" android:summaryOn="@string/triple_buffering_enabled"
app:key="operation_mode" app:key="force_triple_buffering"
app:title="@string/use_docked" /> app:title="@string/force_triple_buffering" />
<CheckBoxPreference
android:defaultValue="false"
android:dependency="force_triple_buffering"
android:summaryOff="@string/disable_frame_throttling_disabled"
android:summaryOn="@string/disable_frame_throttling_enabled"
app:key="disable_frame_throttling"
app:title="@string/disable_frame_throttling" />
<CheckBoxPreference
android:defaultValue="false"
android:summaryOff="@string/max_refresh_rate_disabled"
android:summaryOn="@string/max_refresh_rate_enabled"
app:key="max_refresh_rate"
app:title="@string/max_refresh_rate" />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory
android:key="category_input" android:key="category_input"
android:title="@string/input" android:title="@string/input"
app:initialExpandedChildrenCount="4"> app:initialExpandedChildrenCount="4">
<!--
<CheckBoxPreference
android:defaultValue="true"
android:summaryOff="@string/osc_not_shown"
android:summaryOn="@string/osc_shown"
app:key="show_osc"
app:title="@string/show_osc" />
-->
<emu.skyline.preference.ControllerPreference index="0" /> <emu.skyline.preference.ControllerPreference index="0" />
<emu.skyline.preference.ControllerPreference index="1" /> <emu.skyline.preference.ControllerPreference index="1" />
<emu.skyline.preference.ControllerPreference index="2" /> <emu.skyline.preference.ControllerPreference index="2" />
@ -95,73 +110,73 @@
<emu.skyline.preference.ControllerPreference index="7" /> <emu.skyline.preference.ControllerPreference index="7" />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory
android:key="category_licenses" android:key="category_licenses"
android:title="@string/licenses" android:title="@string/licenses"
app:initialExpandedChildrenCount="3"> app:initialExpandedChildrenCount="3">
<emu.skyline.preference.LicensePreference <emu.skyline.preference.LicensePreference
libraryLicense="@string/mpl2_license" libraryLicense="@string/mpl2_license"
libraryUrl="https://github.com/skyline-emu/skyline" libraryUrl="https://github.com/skyline-emu/skyline"
app:summary="@string/skyline_license_description" app:summary="@string/skyline_license_description"
app:title="@string/app_name" /> app:title="@string/app_name" />
<emu.skyline.preference.LicensePreference <emu.skyline.preference.LicensePreference
libraryLicense="@string/fmtlib_license" libraryLicense="@string/fmtlib_license"
libraryUrl="https://github.com/fmtlib/fmt" libraryUrl="https://github.com/fmtlib/fmt"
app:summary="@string/fmtlib_description" app:summary="@string/fmtlib_description"
app:title="@string/fmtlib" /> app:title="@string/fmtlib" />
<emu.skyline.preference.LicensePreference <emu.skyline.preference.LicensePreference
libraryLicense="@string/apache2_license" libraryLicense="@string/apache2_license"
libraryUrl="https://github.com/google/oboe" libraryUrl="https://github.com/google/oboe"
app:summary="@string/oboe_description" app:summary="@string/oboe_description"
app:title="@string/oboe" /> app:title="@string/oboe" />
<emu.skyline.preference.LicensePreference <emu.skyline.preference.LicensePreference
libraryLicense="@string/apache2_license" libraryLicense="@string/apache2_license"
libraryUrl="https://github.com/KhronosGroup/Vulkan-Hpp" libraryUrl="https://github.com/KhronosGroup/Vulkan-Hpp"
app:summary="@string/vkhpp_description" app:summary="@string/vkhpp_description"
app:title="@string/vkhpp" /> app:title="@string/vkhpp" />
<emu.skyline.preference.LicensePreference <emu.skyline.preference.LicensePreference
libraryLicense="@string/zlib_license" libraryLicense="@string/zlib_license"
libraryUrl="https://github.com/leethomason/tinyxml2" libraryUrl="https://github.com/leethomason/tinyxml2"
app:summary="@string/txml2_description" app:summary="@string/txml2_description"
app:title="@string/txml2" /> app:title="@string/txml2" />
<emu.skyline.preference.LicensePreference <emu.skyline.preference.LicensePreference
libraryLicense="@string/apache2_license" libraryLicense="@string/apache2_license"
libraryUrl="https://github.com/tdebatty/java-string-similarity" libraryUrl="https://github.com/tdebatty/java-string-similarity"
app:summary="@string/jssim_description" app:summary="@string/jssim_description"
app:title="@string/jssim" /> app:title="@string/jssim" />
<emu.skyline.preference.LicensePreference <emu.skyline.preference.LicensePreference
libraryLicense="@string/apache2_license" libraryLicense="@string/apache2_license"
libraryUrl="https://developer.android.com/jetpack/androidx" libraryUrl="https://developer.android.com/jetpack/androidx"
app:summary="@string/andx_description" app:summary="@string/andx_description"
app:title="@string/andx" /> app:title="@string/andx" />
<emu.skyline.preference.LicensePreference <emu.skyline.preference.LicensePreference
libraryLicense="@string/apache2_license" libraryLicense="@string/apache2_license"
libraryUrl="https://github.com/material-components/material-components-android" libraryUrl="https://github.com/material-components/material-components-android"
app:summary="@string/amat_description" app:summary="@string/amat_description"
app:title="@string/amat" /> app:title="@string/amat" />
<emu.skyline.preference.LicensePreference <emu.skyline.preference.LicensePreference
libraryLicense="@string/apache2_license" libraryLicense="@string/apache2_license"
libraryUrl="https://kotlinlang.org/api/latest/jvm/stdlib" libraryUrl="https://kotlinlang.org/api/latest/jvm/stdlib"
app:summary="@string/ktstd_description" app:summary="@string/ktstd_description"
app:title="@string/ktstd" /> app:title="@string/ktstd" />
<emu.skyline.preference.LicensePreference <emu.skyline.preference.LicensePreference
libraryLicense="@string/apache2_license" libraryLicense="@string/apache2_license"
libraryUrl="https://material.io/resources/icons" libraryUrl="https://material.io/resources/icons"
app:summary="@string/mtico_description" app:summary="@string/mtico_description"
app:title="@string/mtico" /> app:title="@string/mtico" />
<emu.skyline.preference.LicensePreference <emu.skyline.preference.LicensePreference
libraryLicense="@string/apache2_license" libraryLicense="@string/apache2_license"
libraryUrl="https://fonts.google.com/specimen/Open+Sans" libraryUrl="https://fonts.google.com/specimen/Open+Sans"
app:summary="@string/open_sans_description" app:summary="@string/open_sans_description"
app:title="@string/open_sans" /> app:title="@string/open_sans" />
<emu.skyline.preference.LicensePreference <emu.skyline.preference.LicensePreference
libraryLicense="@string/apache2_license" libraryLicense="@string/apache2_license"
libraryUrl="https://fonts.google.com/specimen/Roboto" libraryUrl="https://fonts.google.com/specimen/Roboto"
app:summary="@string/roboto_description" app:summary="@string/roboto_description"
app:title="@string/roboto" /> app:title="@string/roboto" />
<emu.skyline.preference.LicensePreference <emu.skyline.preference.LicensePreference
libraryLicense="@string/sil_open_font_license" libraryLicense="@string/sil_open_font_license"
libraryUrl="https://fonts.google.com/specimen/Source+Sans+Pro" libraryUrl="https://fonts.google.com/specimen/Source+Sans+Pro"
app:summary="@string/source_sans_pro_description" app:summary="@string/source_sans_pro_description"
app:title="@string/source_sans_pro" /> app:title="@string/source_sans_pro" />
</PreferenceCategory> </PreferenceCategory>
</androidx.preference.PreferenceScreen> </androidx.preference.PreferenceScreen>