Compare commits
16 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
02ca46d394 | ||
|
|
664d8c8732 | ||
|
|
da46d924e9 | ||
|
|
a2d7b2f905 | ||
|
|
7a9d9e575b | ||
|
|
ab6a5784fa | ||
|
|
0608336c60 | ||
|
|
d108c2873d | ||
|
|
9872d4bc4f | ||
|
|
9edbbf2af4 | ||
|
|
5e982a7812 | ||
|
|
ecb3342145 | ||
|
|
67159e3be7 | ||
|
|
f10d40a0a2 | ||
|
|
e6f200b960 | ||
|
|
e7c1e6fc27 |
7
externals/CMakeLists.txt
vendored
7
externals/CMakeLists.txt
vendored
@@ -69,7 +69,12 @@ if (YUZU_USE_EXTERNAL_SDL2)
|
||||
endif()
|
||||
|
||||
# SoundTouch
|
||||
add_subdirectory(soundtouch)
|
||||
find_package(SoundTouch MODULE)
|
||||
if (NOT SoundTouch_FOUND)
|
||||
message(STATUS "SoundTouch not found, falling back to externals")
|
||||
add_subdirectory(soundtouch)
|
||||
add_library(SoundTouch::SoundTouch ALIAS SoundTouch)
|
||||
endif()
|
||||
|
||||
# Cubeb
|
||||
if(ENABLE_CUBEB)
|
||||
|
||||
63
externals/find-modules/FindSoundTouch.cmake
vendored
Normal file
63
externals/find-modules/FindSoundTouch.cmake
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
# SPDX-FileCopyrightText: 2022 Andrea Pappacoda <andrea@pappacoda.it>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
# This find module looks for SoundTouch with both a CMake Config file and a
|
||||
# pkg-config. If the library is found, it checks if it enforces 32 bit
|
||||
# floating point samples, and if not it defines SOUNDTOUCH_INTEGER_SAMPLES,
|
||||
# just like in the bundled library.
|
||||
|
||||
find_package(SoundTouch CONFIG)
|
||||
if (SoundTouch_FOUND)
|
||||
set(_st_real_name "SoundTouch::SoundTouch")
|
||||
else()
|
||||
find_package(PkgConfig QUIET)
|
||||
if (PKG_CONFIG_FOUND)
|
||||
pkg_search_module(SoundTouch IMPORTED_TARGET soundtouch)
|
||||
if (SoundTouch_FOUND)
|
||||
set_target_properties(PkgConfig::SoundTouch PROPERTIES IMPORTED_GLOBAL True)
|
||||
add_library(SoundTouch::SoundTouch ALIAS PkgConfig::SoundTouch)
|
||||
# Need to set this variable because CMake doesn't allow to add
|
||||
# compile definitions to ALIAS targets
|
||||
set(_st_real_name "PkgConfig::SoundTouch")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (SoundTouch_FOUND)
|
||||
find_path(_st_include_dir "soundtouch/soundtouch_config.h")
|
||||
file(READ "${_st_include_dir}/soundtouch/soundtouch_config.h" _st_config_file)
|
||||
|
||||
# Check if the config file defines SOUNDTOUCH_FLOAT_SAMPLES
|
||||
string(REGEX MATCH "#define[ ]+SOUNDTOUCH_FLOAT_SAMPLES[ ]+1" SoundTouch_FLOAT_SAMPLES ${_st_config_file})
|
||||
|
||||
if (NOT SoundTouch_FLOAT_SAMPLES)
|
||||
target_compile_definitions(${_st_real_name} INTERFACE "SOUNDTOUCH_INTEGER_SAMPLES=1")
|
||||
set(SoundTouch_INTEGER_SAMPLES True)
|
||||
else()
|
||||
# Check if SoundTouch supports SOUNDTOUCH_NO_CONFIG
|
||||
file(READ "${_st_include_dir}/soundtouch/STTypes.h" _st_types_file)
|
||||
|
||||
string(FIND "${_st_types_file}" "SOUNDTOUCH_NO_CONFIG" SoundTouch_NO_CONFIG)
|
||||
|
||||
# if found
|
||||
if (NOT SoundTouch_NO_CONFIG EQUAL "-1")
|
||||
target_compile_definitions(${_st_real_name} INTERFACE "SOUNDTOUCH_NO_CONFIG" "SOUNDTOUCH_INTEGER_SAMPLES=1")
|
||||
set(SoundTouch_INTEGER_SAMPLES True)
|
||||
endif()
|
||||
|
||||
unset(_st_types_file)
|
||||
endif()
|
||||
|
||||
unset(_st_real_name)
|
||||
unset(_st_include_dir)
|
||||
unset(_st_config_file)
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(SoundTouch
|
||||
REQUIRED_VARS
|
||||
SoundTouch_FOUND
|
||||
SoundTouch_INTEGER_SAMPLES
|
||||
VERSION_VAR SoundTouch_VERSION
|
||||
)
|
||||
@@ -63,7 +63,7 @@ if (NOT MSVC)
|
||||
endif()
|
||||
|
||||
target_link_libraries(audio_core PUBLIC common core)
|
||||
target_link_libraries(audio_core PRIVATE SoundTouch)
|
||||
target_link_libraries(audio_core PRIVATE SoundTouch::SoundTouch)
|
||||
|
||||
if(ENABLE_CUBEB)
|
||||
target_link_libraries(audio_core PRIVATE cubeb)
|
||||
|
||||
@@ -226,7 +226,7 @@ void SoftwareKeyboard::InitializeForeground() {
|
||||
ASSERT(work_buffer_storage != nullptr);
|
||||
|
||||
if (swkbd_config_common.initial_string_length == 0) {
|
||||
InitializeFrontendKeyboard();
|
||||
InitializeFrontendNormalKeyboard();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -243,7 +243,7 @@ void SoftwareKeyboard::InitializeForeground() {
|
||||
|
||||
LOG_DEBUG(Service_AM, "\nInitial Text: {}", Common::UTF16ToUTF8(initial_text));
|
||||
|
||||
InitializeFrontendKeyboard();
|
||||
InitializeFrontendNormalKeyboard();
|
||||
}
|
||||
|
||||
void SoftwareKeyboard::InitializeBackground(LibraryAppletMode library_applet_mode) {
|
||||
@@ -480,129 +480,173 @@ void SoftwareKeyboard::ChangeState(SwkbdState state) {
|
||||
ReplyDefault();
|
||||
}
|
||||
|
||||
void SoftwareKeyboard::InitializeFrontendKeyboard() {
|
||||
if (is_background) {
|
||||
const auto& appear_arg = swkbd_calc_arg.appear_arg;
|
||||
void SoftwareKeyboard::InitializeFrontendNormalKeyboard() {
|
||||
std::u16string ok_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
|
||||
swkbd_config_common.ok_text.data(), swkbd_config_common.ok_text.size());
|
||||
|
||||
std::u16string ok_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
|
||||
appear_arg.ok_text.data(), appear_arg.ok_text.size());
|
||||
std::u16string header_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
|
||||
swkbd_config_common.header_text.data(), swkbd_config_common.header_text.size());
|
||||
|
||||
const u32 max_text_length =
|
||||
appear_arg.max_text_length > 0 && appear_arg.max_text_length <= DEFAULT_MAX_TEXT_LENGTH
|
||||
? appear_arg.max_text_length
|
||||
: DEFAULT_MAX_TEXT_LENGTH;
|
||||
std::u16string sub_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
|
||||
swkbd_config_common.sub_text.data(), swkbd_config_common.sub_text.size());
|
||||
|
||||
const u32 min_text_length =
|
||||
appear_arg.min_text_length <= max_text_length ? appear_arg.min_text_length : 0;
|
||||
std::u16string guide_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
|
||||
swkbd_config_common.guide_text.data(), swkbd_config_common.guide_text.size());
|
||||
|
||||
const s32 initial_cursor_position =
|
||||
current_cursor_position > 0 ? current_cursor_position : 0;
|
||||
const u32 max_text_length =
|
||||
swkbd_config_common.max_text_length > 0 &&
|
||||
swkbd_config_common.max_text_length <= DEFAULT_MAX_TEXT_LENGTH
|
||||
? swkbd_config_common.max_text_length
|
||||
: DEFAULT_MAX_TEXT_LENGTH;
|
||||
|
||||
const auto text_draw_type =
|
||||
max_text_length <= 32 ? SwkbdTextDrawType::Line : SwkbdTextDrawType::Box;
|
||||
const u32 min_text_length = swkbd_config_common.min_text_length <= max_text_length
|
||||
? swkbd_config_common.min_text_length
|
||||
: 0;
|
||||
|
||||
Core::Frontend::KeyboardInitializeParameters initialize_parameters{
|
||||
.ok_text{std::move(ok_text)},
|
||||
.header_text{},
|
||||
.sub_text{},
|
||||
.guide_text{},
|
||||
.initial_text{current_text},
|
||||
.max_text_length{max_text_length},
|
||||
.min_text_length{min_text_length},
|
||||
.initial_cursor_position{initial_cursor_position},
|
||||
.type{appear_arg.type},
|
||||
.password_mode{SwkbdPasswordMode::Disabled},
|
||||
.text_draw_type{text_draw_type},
|
||||
.key_disable_flags{appear_arg.key_disable_flags},
|
||||
.use_blur_background{false},
|
||||
.enable_backspace_button{swkbd_calc_arg.enable_backspace_button},
|
||||
.enable_return_button{appear_arg.enable_return_button},
|
||||
.disable_cancel_button{appear_arg.disable_cancel_button},
|
||||
};
|
||||
const s32 initial_cursor_position = [this] {
|
||||
switch (swkbd_config_common.initial_cursor_position) {
|
||||
case SwkbdInitialCursorPosition::Start:
|
||||
default:
|
||||
return 0;
|
||||
case SwkbdInitialCursorPosition::End:
|
||||
return static_cast<s32>(initial_text.size());
|
||||
}
|
||||
}();
|
||||
|
||||
frontend.InitializeKeyboard(
|
||||
true, std::move(initialize_parameters), {},
|
||||
[this](SwkbdReplyType reply_type, std::u16string submitted_text, s32 cursor_position) {
|
||||
SubmitTextInline(reply_type, submitted_text, cursor_position);
|
||||
});
|
||||
} else {
|
||||
std::u16string ok_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
|
||||
swkbd_config_common.ok_text.data(), swkbd_config_common.ok_text.size());
|
||||
const auto text_draw_type = [this, max_text_length] {
|
||||
switch (swkbd_config_common.text_draw_type) {
|
||||
case SwkbdTextDrawType::Line:
|
||||
default:
|
||||
return max_text_length <= 32 ? SwkbdTextDrawType::Line : SwkbdTextDrawType::Box;
|
||||
case SwkbdTextDrawType::Box:
|
||||
case SwkbdTextDrawType::DownloadCode:
|
||||
return swkbd_config_common.text_draw_type;
|
||||
}
|
||||
}();
|
||||
|
||||
std::u16string header_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
|
||||
swkbd_config_common.header_text.data(), swkbd_config_common.header_text.size());
|
||||
const auto enable_return_button =
|
||||
text_draw_type == SwkbdTextDrawType::Box ? swkbd_config_common.enable_return_button : false;
|
||||
|
||||
std::u16string sub_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
|
||||
swkbd_config_common.sub_text.data(), swkbd_config_common.sub_text.size());
|
||||
const auto disable_cancel_button = swkbd_applet_version >= SwkbdAppletVersion::Version393227
|
||||
? swkbd_config_new.disable_cancel_button
|
||||
: false;
|
||||
|
||||
std::u16string guide_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
|
||||
swkbd_config_common.guide_text.data(), swkbd_config_common.guide_text.size());
|
||||
Core::Frontend::KeyboardInitializeParameters initialize_parameters{
|
||||
.ok_text{std::move(ok_text)},
|
||||
.header_text{std::move(header_text)},
|
||||
.sub_text{std::move(sub_text)},
|
||||
.guide_text{std::move(guide_text)},
|
||||
.initial_text{initial_text},
|
||||
.max_text_length{max_text_length},
|
||||
.min_text_length{min_text_length},
|
||||
.initial_cursor_position{initial_cursor_position},
|
||||
.type{swkbd_config_common.type},
|
||||
.password_mode{swkbd_config_common.password_mode},
|
||||
.text_draw_type{text_draw_type},
|
||||
.key_disable_flags{swkbd_config_common.key_disable_flags},
|
||||
.use_blur_background{swkbd_config_common.use_blur_background},
|
||||
.enable_backspace_button{true},
|
||||
.enable_return_button{enable_return_button},
|
||||
.disable_cancel_button{disable_cancel_button},
|
||||
};
|
||||
|
||||
const u32 max_text_length =
|
||||
swkbd_config_common.max_text_length > 0 &&
|
||||
swkbd_config_common.max_text_length <= DEFAULT_MAX_TEXT_LENGTH
|
||||
? swkbd_config_common.max_text_length
|
||||
: DEFAULT_MAX_TEXT_LENGTH;
|
||||
frontend.InitializeKeyboard(
|
||||
false, std::move(initialize_parameters),
|
||||
[this](SwkbdResult result, std::u16string submitted_text, bool confirmed) {
|
||||
SubmitTextNormal(result, submitted_text, confirmed);
|
||||
},
|
||||
{});
|
||||
}
|
||||
|
||||
const u32 min_text_length = swkbd_config_common.min_text_length <= max_text_length
|
||||
? swkbd_config_common.min_text_length
|
||||
: 0;
|
||||
void SoftwareKeyboard::InitializeFrontendInlineKeyboard(
|
||||
Core::Frontend::KeyboardInitializeParameters initialize_parameters) {
|
||||
frontend.InitializeKeyboard(
|
||||
true, std::move(initialize_parameters), {},
|
||||
[this](SwkbdReplyType reply_type, std::u16string submitted_text, s32 cursor_position) {
|
||||
SubmitTextInline(reply_type, submitted_text, cursor_position);
|
||||
});
|
||||
}
|
||||
|
||||
const s32 initial_cursor_position = [this] {
|
||||
switch (swkbd_config_common.initial_cursor_position) {
|
||||
case SwkbdInitialCursorPosition::Start:
|
||||
default:
|
||||
return 0;
|
||||
case SwkbdInitialCursorPosition::End:
|
||||
return static_cast<s32>(initial_text.size());
|
||||
}
|
||||
}();
|
||||
void SoftwareKeyboard::InitializeFrontendInlineKeyboardOld() {
|
||||
const auto& appear_arg = swkbd_calc_arg_old.appear_arg;
|
||||
|
||||
const auto text_draw_type = [this, max_text_length] {
|
||||
switch (swkbd_config_common.text_draw_type) {
|
||||
case SwkbdTextDrawType::Line:
|
||||
default:
|
||||
return max_text_length <= 32 ? SwkbdTextDrawType::Line : SwkbdTextDrawType::Box;
|
||||
case SwkbdTextDrawType::Box:
|
||||
case SwkbdTextDrawType::DownloadCode:
|
||||
return swkbd_config_common.text_draw_type;
|
||||
}
|
||||
}();
|
||||
std::u16string ok_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
|
||||
appear_arg.ok_text.data(), appear_arg.ok_text.size());
|
||||
|
||||
const auto enable_return_button = text_draw_type == SwkbdTextDrawType::Box
|
||||
? swkbd_config_common.enable_return_button
|
||||
: false;
|
||||
const u32 max_text_length =
|
||||
appear_arg.max_text_length > 0 && appear_arg.max_text_length <= DEFAULT_MAX_TEXT_LENGTH
|
||||
? appear_arg.max_text_length
|
||||
: DEFAULT_MAX_TEXT_LENGTH;
|
||||
|
||||
const auto disable_cancel_button = swkbd_applet_version >= SwkbdAppletVersion::Version393227
|
||||
? swkbd_config_new.disable_cancel_button
|
||||
: false;
|
||||
const u32 min_text_length =
|
||||
appear_arg.min_text_length <= max_text_length ? appear_arg.min_text_length : 0;
|
||||
|
||||
Core::Frontend::KeyboardInitializeParameters initialize_parameters{
|
||||
.ok_text{std::move(ok_text)},
|
||||
.header_text{std::move(header_text)},
|
||||
.sub_text{std::move(sub_text)},
|
||||
.guide_text{std::move(guide_text)},
|
||||
.initial_text{initial_text},
|
||||
.max_text_length{max_text_length},
|
||||
.min_text_length{min_text_length},
|
||||
.initial_cursor_position{initial_cursor_position},
|
||||
.type{swkbd_config_common.type},
|
||||
.password_mode{swkbd_config_common.password_mode},
|
||||
.text_draw_type{text_draw_type},
|
||||
.key_disable_flags{swkbd_config_common.key_disable_flags},
|
||||
.use_blur_background{swkbd_config_common.use_blur_background},
|
||||
.enable_backspace_button{true},
|
||||
.enable_return_button{enable_return_button},
|
||||
.disable_cancel_button{disable_cancel_button},
|
||||
};
|
||||
const s32 initial_cursor_position = current_cursor_position > 0 ? current_cursor_position : 0;
|
||||
|
||||
frontend.InitializeKeyboard(
|
||||
false, std::move(initialize_parameters),
|
||||
[this](SwkbdResult result, std::u16string submitted_text, bool confirmed) {
|
||||
SubmitTextNormal(result, submitted_text, confirmed);
|
||||
},
|
||||
{});
|
||||
}
|
||||
const auto text_draw_type =
|
||||
max_text_length <= 32 ? SwkbdTextDrawType::Line : SwkbdTextDrawType::Box;
|
||||
|
||||
Core::Frontend::KeyboardInitializeParameters initialize_parameters{
|
||||
.ok_text{std::move(ok_text)},
|
||||
.header_text{},
|
||||
.sub_text{},
|
||||
.guide_text{},
|
||||
.initial_text{current_text},
|
||||
.max_text_length{max_text_length},
|
||||
.min_text_length{min_text_length},
|
||||
.initial_cursor_position{initial_cursor_position},
|
||||
.type{appear_arg.type},
|
||||
.password_mode{SwkbdPasswordMode::Disabled},
|
||||
.text_draw_type{text_draw_type},
|
||||
.key_disable_flags{appear_arg.key_disable_flags},
|
||||
.use_blur_background{false},
|
||||
.enable_backspace_button{swkbd_calc_arg_old.enable_backspace_button},
|
||||
.enable_return_button{appear_arg.enable_return_button},
|
||||
.disable_cancel_button{appear_arg.disable_cancel_button},
|
||||
};
|
||||
|
||||
InitializeFrontendInlineKeyboard(std::move(initialize_parameters));
|
||||
}
|
||||
|
||||
void SoftwareKeyboard::InitializeFrontendInlineKeyboardNew() {
|
||||
const auto& appear_arg = swkbd_calc_arg_new.appear_arg;
|
||||
|
||||
std::u16string ok_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
|
||||
appear_arg.ok_text.data(), appear_arg.ok_text.size());
|
||||
|
||||
const u32 max_text_length =
|
||||
appear_arg.max_text_length > 0 && appear_arg.max_text_length <= DEFAULT_MAX_TEXT_LENGTH
|
||||
? appear_arg.max_text_length
|
||||
: DEFAULT_MAX_TEXT_LENGTH;
|
||||
|
||||
const u32 min_text_length =
|
||||
appear_arg.min_text_length <= max_text_length ? appear_arg.min_text_length : 0;
|
||||
|
||||
const s32 initial_cursor_position = current_cursor_position > 0 ? current_cursor_position : 0;
|
||||
|
||||
const auto text_draw_type =
|
||||
max_text_length <= 32 ? SwkbdTextDrawType::Line : SwkbdTextDrawType::Box;
|
||||
|
||||
Core::Frontend::KeyboardInitializeParameters initialize_parameters{
|
||||
.ok_text{std::move(ok_text)},
|
||||
.header_text{},
|
||||
.sub_text{},
|
||||
.guide_text{},
|
||||
.initial_text{current_text},
|
||||
.max_text_length{max_text_length},
|
||||
.min_text_length{min_text_length},
|
||||
.initial_cursor_position{initial_cursor_position},
|
||||
.type{appear_arg.type},
|
||||
.password_mode{SwkbdPasswordMode::Disabled},
|
||||
.text_draw_type{text_draw_type},
|
||||
.key_disable_flags{appear_arg.key_disable_flags},
|
||||
.use_blur_background{false},
|
||||
.enable_backspace_button{swkbd_calc_arg_new.enable_backspace_button},
|
||||
.enable_return_button{appear_arg.enable_return_button},
|
||||
.disable_cancel_button{appear_arg.disable_cancel_button},
|
||||
};
|
||||
|
||||
InitializeFrontendInlineKeyboard(std::move(initialize_parameters));
|
||||
}
|
||||
|
||||
void SoftwareKeyboard::ShowNormalKeyboard() {
|
||||
@@ -614,14 +658,21 @@ void SoftwareKeyboard::ShowTextCheckDialog(SwkbdTextCheckResult text_check_resul
|
||||
frontend.ShowTextCheckDialog(text_check_result, std::move(text_check_message));
|
||||
}
|
||||
|
||||
void SoftwareKeyboard::ShowInlineKeyboard() {
|
||||
void SoftwareKeyboard::ShowInlineKeyboard(
|
||||
Core::Frontend::InlineAppearParameters appear_parameters) {
|
||||
frontend.ShowInlineKeyboard(std::move(appear_parameters));
|
||||
|
||||
ChangeState(SwkbdState::InitializedIsShown);
|
||||
}
|
||||
|
||||
void SoftwareKeyboard::ShowInlineKeyboardOld() {
|
||||
if (swkbd_state != SwkbdState::InitializedIsHidden) {
|
||||
return;
|
||||
}
|
||||
|
||||
ChangeState(SwkbdState::InitializedIsAppearing);
|
||||
|
||||
const auto& appear_arg = swkbd_calc_arg.appear_arg;
|
||||
const auto& appear_arg = swkbd_calc_arg_old.appear_arg;
|
||||
|
||||
const u32 max_text_length =
|
||||
appear_arg.max_text_length > 0 && appear_arg.max_text_length <= DEFAULT_MAX_TEXT_LENGTH
|
||||
@@ -634,21 +685,54 @@ void SoftwareKeyboard::ShowInlineKeyboard() {
|
||||
Core::Frontend::InlineAppearParameters appear_parameters{
|
||||
.max_text_length{max_text_length},
|
||||
.min_text_length{min_text_length},
|
||||
.key_top_scale_x{swkbd_calc_arg.key_top_scale_x},
|
||||
.key_top_scale_y{swkbd_calc_arg.key_top_scale_y},
|
||||
.key_top_translate_x{swkbd_calc_arg.key_top_translate_x},
|
||||
.key_top_translate_y{swkbd_calc_arg.key_top_translate_y},
|
||||
.key_top_scale_x{swkbd_calc_arg_old.key_top_scale_x},
|
||||
.key_top_scale_y{swkbd_calc_arg_old.key_top_scale_y},
|
||||
.key_top_translate_x{swkbd_calc_arg_old.key_top_translate_x},
|
||||
.key_top_translate_y{swkbd_calc_arg_old.key_top_translate_y},
|
||||
.type{appear_arg.type},
|
||||
.key_disable_flags{appear_arg.key_disable_flags},
|
||||
.key_top_as_floating{swkbd_calc_arg.key_top_as_floating},
|
||||
.enable_backspace_button{swkbd_calc_arg.enable_backspace_button},
|
||||
.key_top_as_floating{swkbd_calc_arg_old.key_top_as_floating},
|
||||
.enable_backspace_button{swkbd_calc_arg_old.enable_backspace_button},
|
||||
.enable_return_button{appear_arg.enable_return_button},
|
||||
.disable_cancel_button{appear_arg.disable_cancel_button},
|
||||
};
|
||||
|
||||
frontend.ShowInlineKeyboard(std::move(appear_parameters));
|
||||
ShowInlineKeyboard(std::move(appear_parameters));
|
||||
}
|
||||
|
||||
ChangeState(SwkbdState::InitializedIsShown);
|
||||
void SoftwareKeyboard::ShowInlineKeyboardNew() {
|
||||
if (swkbd_state != SwkbdState::InitializedIsHidden) {
|
||||
return;
|
||||
}
|
||||
|
||||
ChangeState(SwkbdState::InitializedIsAppearing);
|
||||
|
||||
const auto& appear_arg = swkbd_calc_arg_new.appear_arg;
|
||||
|
||||
const u32 max_text_length =
|
||||
appear_arg.max_text_length > 0 && appear_arg.max_text_length <= DEFAULT_MAX_TEXT_LENGTH
|
||||
? appear_arg.max_text_length
|
||||
: DEFAULT_MAX_TEXT_LENGTH;
|
||||
|
||||
const u32 min_text_length =
|
||||
appear_arg.min_text_length <= max_text_length ? appear_arg.min_text_length : 0;
|
||||
|
||||
Core::Frontend::InlineAppearParameters appear_parameters{
|
||||
.max_text_length{max_text_length},
|
||||
.min_text_length{min_text_length},
|
||||
.key_top_scale_x{swkbd_calc_arg_new.key_top_scale_x},
|
||||
.key_top_scale_y{swkbd_calc_arg_new.key_top_scale_y},
|
||||
.key_top_translate_x{swkbd_calc_arg_new.key_top_translate_x},
|
||||
.key_top_translate_y{swkbd_calc_arg_new.key_top_translate_y},
|
||||
.type{appear_arg.type},
|
||||
.key_disable_flags{appear_arg.key_disable_flags},
|
||||
.key_top_as_floating{swkbd_calc_arg_new.key_top_as_floating},
|
||||
.enable_backspace_button{swkbd_calc_arg_new.enable_backspace_button},
|
||||
.enable_return_button{appear_arg.enable_return_button},
|
||||
.disable_cancel_button{appear_arg.disable_cancel_button},
|
||||
};
|
||||
|
||||
ShowInlineKeyboard(std::move(appear_parameters));
|
||||
}
|
||||
|
||||
void SoftwareKeyboard::HideInlineKeyboard() {
|
||||
@@ -693,6 +777,8 @@ void SoftwareKeyboard::RequestFinalize(const std::vector<u8>& request_data) {
|
||||
|
||||
void SoftwareKeyboard::RequestSetUserWordInfo(const std::vector<u8>& request_data) {
|
||||
LOG_WARNING(Service_AM, "SetUserWordInfo is not implemented.");
|
||||
|
||||
ReplyReleasedUserWordInfo();
|
||||
}
|
||||
|
||||
void SoftwareKeyboard::RequestSetCustomizeDic(const std::vector<u8>& request_data) {
|
||||
@@ -702,53 +788,135 @@ void SoftwareKeyboard::RequestSetCustomizeDic(const std::vector<u8>& request_dat
|
||||
void SoftwareKeyboard::RequestCalc(const std::vector<u8>& request_data) {
|
||||
LOG_DEBUG(Service_AM, "Processing Request: Calc");
|
||||
|
||||
ASSERT(request_data.size() == sizeof(SwkbdRequestCommand) + sizeof(SwkbdCalcArg));
|
||||
ASSERT(request_data.size() >= sizeof(SwkbdRequestCommand) + sizeof(SwkbdCalcArgCommon));
|
||||
|
||||
std::memcpy(&swkbd_calc_arg, request_data.data() + sizeof(SwkbdRequestCommand),
|
||||
sizeof(SwkbdCalcArg));
|
||||
std::memcpy(&swkbd_calc_arg_common, request_data.data() + sizeof(SwkbdRequestCommand),
|
||||
sizeof(SwkbdCalcArgCommon));
|
||||
|
||||
if (swkbd_calc_arg.flags.set_input_text) {
|
||||
switch (swkbd_calc_arg_common.calc_arg_size) {
|
||||
case sizeof(SwkbdCalcArgCommon) + sizeof(SwkbdCalcArgOld):
|
||||
ASSERT(request_data.size() ==
|
||||
sizeof(SwkbdRequestCommand) + sizeof(SwkbdCalcArgCommon) + sizeof(SwkbdCalcArgOld));
|
||||
std::memcpy(&swkbd_calc_arg_old,
|
||||
request_data.data() + sizeof(SwkbdRequestCommand) + sizeof(SwkbdCalcArgCommon),
|
||||
sizeof(SwkbdCalcArgOld));
|
||||
RequestCalcOld();
|
||||
break;
|
||||
case sizeof(SwkbdCalcArgCommon) + sizeof(SwkbdCalcArgNew):
|
||||
ASSERT(request_data.size() ==
|
||||
sizeof(SwkbdRequestCommand) + sizeof(SwkbdCalcArgCommon) + sizeof(SwkbdCalcArgNew));
|
||||
std::memcpy(&swkbd_calc_arg_new,
|
||||
request_data.data() + sizeof(SwkbdRequestCommand) + sizeof(SwkbdCalcArgCommon),
|
||||
sizeof(SwkbdCalcArgNew));
|
||||
RequestCalcNew();
|
||||
break;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unknown SwkbdCalcArg size={}", swkbd_calc_arg_common.calc_arg_size);
|
||||
ASSERT(request_data.size() >=
|
||||
sizeof(SwkbdRequestCommand) + sizeof(SwkbdCalcArgCommon) + sizeof(SwkbdCalcArgNew));
|
||||
std::memcpy(&swkbd_calc_arg_new,
|
||||
request_data.data() + sizeof(SwkbdRequestCommand) + sizeof(SwkbdCalcArgCommon),
|
||||
sizeof(SwkbdCalcArgNew));
|
||||
RequestCalcNew();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SoftwareKeyboard::RequestCalcOld() {
|
||||
if (swkbd_calc_arg_common.flags.set_input_text) {
|
||||
current_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
|
||||
swkbd_calc_arg.input_text.data(), swkbd_calc_arg.input_text.size());
|
||||
swkbd_calc_arg_old.input_text.data(), swkbd_calc_arg_old.input_text.size());
|
||||
}
|
||||
|
||||
if (swkbd_calc_arg.flags.set_cursor_position) {
|
||||
current_cursor_position = swkbd_calc_arg.cursor_position;
|
||||
if (swkbd_calc_arg_common.flags.set_cursor_position) {
|
||||
current_cursor_position = swkbd_calc_arg_old.cursor_position;
|
||||
}
|
||||
|
||||
if (swkbd_calc_arg.flags.set_utf8_mode) {
|
||||
inline_use_utf8 = swkbd_calc_arg.utf8_mode;
|
||||
if (swkbd_calc_arg_common.flags.set_utf8_mode) {
|
||||
inline_use_utf8 = swkbd_calc_arg_old.utf8_mode;
|
||||
}
|
||||
|
||||
if (swkbd_state <= SwkbdState::InitializedIsHidden &&
|
||||
swkbd_calc_arg.flags.unset_customize_dic) {
|
||||
swkbd_calc_arg_common.flags.unset_customize_dic) {
|
||||
ReplyUnsetCustomizeDic();
|
||||
}
|
||||
|
||||
if (swkbd_state <= SwkbdState::InitializedIsHidden &&
|
||||
swkbd_calc_arg.flags.unset_user_word_info) {
|
||||
swkbd_calc_arg_common.flags.unset_user_word_info) {
|
||||
ReplyReleasedUserWordInfo();
|
||||
}
|
||||
|
||||
if (swkbd_state == SwkbdState::NotInitialized && swkbd_calc_arg.flags.set_initialize_arg) {
|
||||
InitializeFrontendKeyboard();
|
||||
if (swkbd_state == SwkbdState::NotInitialized &&
|
||||
swkbd_calc_arg_common.flags.set_initialize_arg) {
|
||||
InitializeFrontendInlineKeyboardOld();
|
||||
|
||||
ChangeState(SwkbdState::InitializedIsHidden);
|
||||
|
||||
ReplyFinishedInitialize();
|
||||
}
|
||||
|
||||
if (!swkbd_calc_arg.flags.set_initialize_arg &&
|
||||
(swkbd_calc_arg.flags.set_input_text || swkbd_calc_arg.flags.set_cursor_position)) {
|
||||
if (!swkbd_calc_arg_common.flags.set_initialize_arg &&
|
||||
(swkbd_calc_arg_common.flags.set_input_text ||
|
||||
swkbd_calc_arg_common.flags.set_cursor_position)) {
|
||||
InlineTextChanged();
|
||||
}
|
||||
|
||||
if (swkbd_state == SwkbdState::InitializedIsHidden && swkbd_calc_arg.flags.appear) {
|
||||
ShowInlineKeyboard();
|
||||
if (swkbd_state == SwkbdState::InitializedIsHidden && swkbd_calc_arg_common.flags.appear) {
|
||||
ShowInlineKeyboardOld();
|
||||
return;
|
||||
}
|
||||
|
||||
if (swkbd_state == SwkbdState::InitializedIsShown && swkbd_calc_arg.flags.disappear) {
|
||||
if (swkbd_state == SwkbdState::InitializedIsShown && swkbd_calc_arg_common.flags.disappear) {
|
||||
HideInlineKeyboard();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void SoftwareKeyboard::RequestCalcNew() {
|
||||
if (swkbd_calc_arg_common.flags.set_input_text) {
|
||||
current_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
|
||||
swkbd_calc_arg_new.input_text.data(), swkbd_calc_arg_new.input_text.size());
|
||||
}
|
||||
|
||||
if (swkbd_calc_arg_common.flags.set_cursor_position) {
|
||||
current_cursor_position = swkbd_calc_arg_new.cursor_position;
|
||||
}
|
||||
|
||||
if (swkbd_calc_arg_common.flags.set_utf8_mode) {
|
||||
inline_use_utf8 = swkbd_calc_arg_new.utf8_mode;
|
||||
}
|
||||
|
||||
if (swkbd_state <= SwkbdState::InitializedIsHidden &&
|
||||
swkbd_calc_arg_common.flags.unset_customize_dic) {
|
||||
ReplyUnsetCustomizeDic();
|
||||
}
|
||||
|
||||
if (swkbd_state <= SwkbdState::InitializedIsHidden &&
|
||||
swkbd_calc_arg_common.flags.unset_user_word_info) {
|
||||
ReplyReleasedUserWordInfo();
|
||||
}
|
||||
|
||||
if (swkbd_state == SwkbdState::NotInitialized &&
|
||||
swkbd_calc_arg_common.flags.set_initialize_arg) {
|
||||
InitializeFrontendInlineKeyboardNew();
|
||||
|
||||
ChangeState(SwkbdState::InitializedIsHidden);
|
||||
|
||||
ReplyFinishedInitialize();
|
||||
}
|
||||
|
||||
if (!swkbd_calc_arg_common.flags.set_initialize_arg &&
|
||||
(swkbd_calc_arg_common.flags.set_input_text ||
|
||||
swkbd_calc_arg_common.flags.set_cursor_position)) {
|
||||
InlineTextChanged();
|
||||
}
|
||||
|
||||
if (swkbd_state == SwkbdState::InitializedIsHidden && swkbd_calc_arg_common.flags.appear) {
|
||||
ShowInlineKeyboardNew();
|
||||
return;
|
||||
}
|
||||
|
||||
if (swkbd_state == SwkbdState::InitializedIsShown && swkbd_calc_arg_common.flags.disappear) {
|
||||
HideInlineKeyboard();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,11 @@ namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Core::Frontend {
|
||||
struct KeyboardInitializeParameters;
|
||||
struct InlineAppearParameters;
|
||||
} // namespace Core::Frontend
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
|
||||
class SoftwareKeyboard final : public Applet {
|
||||
@@ -78,13 +83,22 @@ private:
|
||||
void ChangeState(SwkbdState state);
|
||||
|
||||
/**
|
||||
* Signals the frontend to initialize the software keyboard with common parameters.
|
||||
* This initializes either the normal software keyboard or the inline software keyboard
|
||||
* depending on the state of is_background.
|
||||
* Signals the frontend to initialize the normal software keyboard with common parameters.
|
||||
* Note that this does not cause the keyboard to appear.
|
||||
* Use the respective Show*Keyboard() functions to cause the respective keyboards to appear.
|
||||
* Use the ShowNormalKeyboard() functions to cause the keyboard to appear.
|
||||
*/
|
||||
void InitializeFrontendKeyboard();
|
||||
void InitializeFrontendNormalKeyboard();
|
||||
|
||||
/**
|
||||
* Signals the frontend to initialize the inline software keyboard with common parameters.
|
||||
* Note that this does not cause the keyboard to appear.
|
||||
* Use the ShowInlineKeyboard() to cause the keyboard to appear.
|
||||
*/
|
||||
void InitializeFrontendInlineKeyboard(
|
||||
Core::Frontend::KeyboardInitializeParameters initialize_parameters);
|
||||
|
||||
void InitializeFrontendInlineKeyboardOld();
|
||||
void InitializeFrontendInlineKeyboardNew();
|
||||
|
||||
/// Signals the frontend to show the normal software keyboard.
|
||||
void ShowNormalKeyboard();
|
||||
@@ -94,7 +108,10 @@ private:
|
||||
std::u16string text_check_message);
|
||||
|
||||
/// Signals the frontend to show the inline software keyboard.
|
||||
void ShowInlineKeyboard();
|
||||
void ShowInlineKeyboard(Core::Frontend::InlineAppearParameters appear_parameters);
|
||||
|
||||
void ShowInlineKeyboardOld();
|
||||
void ShowInlineKeyboardNew();
|
||||
|
||||
/// Signals the frontend to hide the inline software keyboard.
|
||||
void HideInlineKeyboard();
|
||||
@@ -111,6 +128,8 @@ private:
|
||||
void RequestSetUserWordInfo(const std::vector<u8>& request_data);
|
||||
void RequestSetCustomizeDic(const std::vector<u8>& request_data);
|
||||
void RequestCalc(const std::vector<u8>& request_data);
|
||||
void RequestCalcOld();
|
||||
void RequestCalcNew();
|
||||
void RequestSetCustomizedDictionaries(const std::vector<u8>& request_data);
|
||||
void RequestUnsetCustomizedDictionaries(const std::vector<u8>& request_data);
|
||||
void RequestSetChangedStringV2Flag(const std::vector<u8>& request_data);
|
||||
@@ -149,7 +168,9 @@ private:
|
||||
|
||||
SwkbdState swkbd_state{SwkbdState::NotInitialized};
|
||||
SwkbdInitializeArg swkbd_initialize_arg;
|
||||
SwkbdCalcArg swkbd_calc_arg;
|
||||
SwkbdCalcArgCommon swkbd_calc_arg_common;
|
||||
SwkbdCalcArgOld swkbd_calc_arg_old;
|
||||
SwkbdCalcArgNew swkbd_calc_arg_new;
|
||||
bool use_changed_string_v2{false};
|
||||
bool use_moved_cursor_v2{false};
|
||||
bool inline_use_utf8{false};
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/swap.h"
|
||||
#include "common/uuid.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
|
||||
@@ -216,7 +217,7 @@ struct SwkbdInitializeArg {
|
||||
};
|
||||
static_assert(sizeof(SwkbdInitializeArg) == 0x8, "SwkbdInitializeArg has incorrect size.");
|
||||
|
||||
struct SwkbdAppearArg {
|
||||
struct SwkbdAppearArgOld {
|
||||
SwkbdType type{};
|
||||
std::array<char16_t, MAX_OK_TEXT_LENGTH + 1> ok_text{};
|
||||
char16_t left_optional_symbol_key{};
|
||||
@@ -229,19 +230,46 @@ struct SwkbdAppearArg {
|
||||
bool enable_return_button{};
|
||||
INSERT_PADDING_BYTES(3);
|
||||
u32 flags{};
|
||||
INSERT_PADDING_WORDS(6);
|
||||
bool is_use_save_data{};
|
||||
INSERT_PADDING_BYTES(7);
|
||||
Common::UUID user_id{};
|
||||
};
|
||||
static_assert(sizeof(SwkbdAppearArg) == 0x48, "SwkbdAppearArg has incorrect size.");
|
||||
static_assert(sizeof(SwkbdAppearArgOld) == 0x48, "SwkbdAppearArg has incorrect size.");
|
||||
|
||||
struct SwkbdCalcArg {
|
||||
struct SwkbdAppearArgNew {
|
||||
SwkbdType type{};
|
||||
std::array<char16_t, MAX_OK_TEXT_LENGTH + 1> ok_text{};
|
||||
char16_t left_optional_symbol_key{};
|
||||
char16_t right_optional_symbol_key{};
|
||||
bool use_prediction{};
|
||||
bool disable_cancel_button{};
|
||||
SwkbdKeyDisableFlags key_disable_flags{};
|
||||
u32 max_text_length{};
|
||||
u32 min_text_length{};
|
||||
bool enable_return_button{};
|
||||
INSERT_PADDING_BYTES(3);
|
||||
u32 flags{};
|
||||
bool is_use_save_data{};
|
||||
INSERT_PADDING_BYTES(7);
|
||||
Common::UUID user_id{};
|
||||
u64 start_sampling_number{};
|
||||
INSERT_PADDING_WORDS(8);
|
||||
};
|
||||
static_assert(sizeof(SwkbdAppearArgNew) == 0x70, "SwkbdAppearArg has incorrect size.");
|
||||
|
||||
struct SwkbdCalcArgCommon {
|
||||
u32 unknown{};
|
||||
u16 calc_arg_size{};
|
||||
INSERT_PADDING_BYTES(2);
|
||||
SwkbdCalcArgFlags flags{};
|
||||
SwkbdInitializeArg initialize_arg{};
|
||||
};
|
||||
static_assert(sizeof(SwkbdCalcArgCommon) == 0x18, "SwkbdCalcArgCommon has incorrect size.");
|
||||
|
||||
struct SwkbdCalcArgOld {
|
||||
f32 volume{};
|
||||
s32 cursor_position{};
|
||||
SwkbdAppearArg appear_arg{};
|
||||
SwkbdAppearArgOld appear_arg{};
|
||||
std::array<char16_t, 0x1FA> input_text{};
|
||||
bool utf8_mode{};
|
||||
INSERT_PADDING_BYTES(1);
|
||||
@@ -265,7 +293,39 @@ struct SwkbdCalcArg {
|
||||
u8 se_group{};
|
||||
INSERT_PADDING_BYTES(3);
|
||||
};
|
||||
static_assert(sizeof(SwkbdCalcArg) == 0x4A0, "SwkbdCalcArg has incorrect size.");
|
||||
static_assert(sizeof(SwkbdCalcArgOld) == 0x4A0 - sizeof(SwkbdCalcArgCommon),
|
||||
"SwkbdCalcArgOld has incorrect size.");
|
||||
|
||||
struct SwkbdCalcArgNew {
|
||||
SwkbdAppearArgNew appear_arg{};
|
||||
f32 volume{};
|
||||
s32 cursor_position{};
|
||||
std::array<char16_t, 0x1FA> input_text{};
|
||||
bool utf8_mode{};
|
||||
INSERT_PADDING_BYTES(1);
|
||||
bool enable_backspace_button{};
|
||||
INSERT_PADDING_BYTES(3);
|
||||
bool key_top_as_floating{};
|
||||
bool footer_scalable{};
|
||||
bool alpha_enabled_in_input_mode{};
|
||||
u8 input_mode_fade_type{};
|
||||
bool disable_touch{};
|
||||
bool disable_hardware_keyboard{};
|
||||
INSERT_PADDING_BYTES(8);
|
||||
f32 key_top_scale_x{};
|
||||
f32 key_top_scale_y{};
|
||||
f32 key_top_translate_x{};
|
||||
f32 key_top_translate_y{};
|
||||
f32 key_top_bg_alpha{};
|
||||
f32 footer_bg_alpha{};
|
||||
f32 balloon_scale{};
|
||||
INSERT_PADDING_WORDS(4);
|
||||
u8 se_group{};
|
||||
INSERT_PADDING_BYTES(3);
|
||||
INSERT_PADDING_WORDS(8);
|
||||
};
|
||||
static_assert(sizeof(SwkbdCalcArgNew) == 0x4E8 - sizeof(SwkbdCalcArgCommon),
|
||||
"SwkbdCalcArgNew has incorrect size.");
|
||||
|
||||
struct SwkbdChangedStringArg {
|
||||
u32 text_length{};
|
||||
|
||||
@@ -322,7 +322,7 @@ struct Memory::Impl {
|
||||
}
|
||||
|
||||
if (Settings::IsFastmemEnabled()) {
|
||||
const bool is_read_enable = Settings::IsGPULevelHigh() || !cached;
|
||||
const bool is_read_enable = !Settings::IsGPULevelExtreme() || !cached;
|
||||
system.DeviceMemory().buffer.Protect(vaddr, size, is_read_enable, !cached);
|
||||
}
|
||||
|
||||
|
||||
@@ -326,6 +326,11 @@ void Inst::AddPhiOperand(Block* predecessor, const Value& value) {
|
||||
phi_args.emplace_back(predecessor, value);
|
||||
}
|
||||
|
||||
void Inst::ErasePhiOperand(size_t index) {
|
||||
const auto operand_it{phi_args.begin() + static_cast<ptrdiff_t>(index)};
|
||||
phi_args.erase(operand_it);
|
||||
}
|
||||
|
||||
void Inst::OrderPhiArgs() {
|
||||
if (op != Opcode::Phi) {
|
||||
throw LogicError("{} is not a Phi instruction", op);
|
||||
|
||||
@@ -179,9 +179,13 @@ public:
|
||||
|
||||
/// Get a pointer to the block of a phi argument.
|
||||
[[nodiscard]] Block* PhiBlock(size_t index) const;
|
||||
|
||||
/// Add phi operand to a phi instruction.
|
||||
void AddPhiOperand(Block* predecessor, const Value& value);
|
||||
|
||||
// Erase the phi operand at the given index.
|
||||
void ErasePhiOperand(size_t index);
|
||||
|
||||
/// Orders the Phi arguments from farthest away to nearest.
|
||||
void OrderPhiArgs();
|
||||
|
||||
|
||||
@@ -2,25 +2,105 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <boost/container/small_vector.hpp>
|
||||
|
||||
#include "shader_recompiler/frontend/ir/basic_block.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
#include "shader_recompiler/ir_opt/passes.h"
|
||||
|
||||
namespace Shader::Optimization {
|
||||
|
||||
void DeadCodeEliminationPass(IR::Program& program) {
|
||||
namespace {
|
||||
template <bool TEST_USES>
|
||||
void DeadInstElimination(IR::Block* const block) {
|
||||
// We iterate over the instructions in reverse order.
|
||||
// This is because removing an instruction reduces the number of uses for earlier instructions.
|
||||
for (IR::Block* const block : program.post_order_blocks) {
|
||||
auto it{block->end()};
|
||||
while (it != block->begin()) {
|
||||
--it;
|
||||
if (!it->HasUses() && !it->MayHaveSideEffects()) {
|
||||
it->Invalidate();
|
||||
it = block->Instructions().erase(it);
|
||||
auto it{block->end()};
|
||||
while (it != block->begin()) {
|
||||
--it;
|
||||
if constexpr (TEST_USES) {
|
||||
if (it->HasUses() || it->MayHaveSideEffects()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
it->Invalidate();
|
||||
it = block->Instructions().erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void DeletedPhiArgElimination(IR::Program& program, std::span<const IR::Block*> dead_blocks) {
|
||||
for (IR::Block* const block : program.blocks) {
|
||||
for (IR::Inst& phi : *block) {
|
||||
if (!IR::IsPhi(phi)) {
|
||||
continue;
|
||||
}
|
||||
for (size_t i = 0; i < phi.NumArgs(); ++i) {
|
||||
if (std::ranges::find(dead_blocks, phi.PhiBlock(i)) == dead_blocks.end()) {
|
||||
continue;
|
||||
}
|
||||
// Phi operand at this index is an unreachable block
|
||||
phi.ErasePhiOperand(i);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DeadBranchElimination(IR::Program& program) {
|
||||
boost::container::small_vector<const IR::Block*, 3> dead_blocks;
|
||||
const auto begin_it{program.syntax_list.begin()};
|
||||
for (auto node_it = begin_it; node_it != program.syntax_list.end(); ++node_it) {
|
||||
if (node_it->type != IR::AbstractSyntaxNode::Type::If) {
|
||||
continue;
|
||||
}
|
||||
IR::Inst* const cond_ref{node_it->data.if_node.cond.Inst()};
|
||||
const IR::U1 cond{cond_ref->Arg(0)};
|
||||
if (!cond.IsImmediate()) {
|
||||
continue;
|
||||
}
|
||||
if (cond.U1()) {
|
||||
continue;
|
||||
}
|
||||
// False immediate condition. Remove condition ref, erase the entire branch.
|
||||
cond_ref->Invalidate();
|
||||
// Account for nested if-statements within the if(false) branch
|
||||
u32 nested_ifs{1u};
|
||||
while (node_it->type != IR::AbstractSyntaxNode::Type::EndIf || nested_ifs > 0) {
|
||||
node_it = program.syntax_list.erase(node_it);
|
||||
switch (node_it->type) {
|
||||
case IR::AbstractSyntaxNode::Type::If:
|
||||
++nested_ifs;
|
||||
break;
|
||||
case IR::AbstractSyntaxNode::Type::EndIf:
|
||||
--nested_ifs;
|
||||
break;
|
||||
case IR::AbstractSyntaxNode::Type::Block: {
|
||||
IR::Block* const block{node_it->data.block};
|
||||
DeadInstElimination<false>(block);
|
||||
dead_blocks.push_back(block);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Erase EndIf node of the if(false) branch
|
||||
node_it = program.syntax_list.erase(node_it);
|
||||
// Account for loop increment
|
||||
--node_it;
|
||||
}
|
||||
if (!dead_blocks.empty()) {
|
||||
DeletedPhiArgElimination(program, std::span(dead_blocks.data(), dead_blocks.size()));
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void DeadCodeEliminationPass(IR::Program& program) {
|
||||
DeadBranchElimination(program);
|
||||
for (IR::Block* const block : program.post_order_blocks) {
|
||||
DeadInstElimination<true>(block);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Shader::Optimization
|
||||
|
||||
@@ -76,8 +76,9 @@ class BufferCache {
|
||||
|
||||
static constexpr BufferId NULL_BUFFER_ID{0};
|
||||
|
||||
static constexpr u64 EXPECTED_MEMORY = 512_MiB;
|
||||
static constexpr u64 CRITICAL_MEMORY = 1_GiB;
|
||||
static constexpr s64 DEFAULT_EXPECTED_MEMORY = 512_MiB;
|
||||
static constexpr s64 DEFAULT_CRITICAL_MEMORY = 1_GiB;
|
||||
static constexpr s64 TARGET_THRESHOLD = 4_GiB;
|
||||
|
||||
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
|
||||
|
||||
@@ -436,6 +437,8 @@ private:
|
||||
Common::LeastRecentlyUsedCache<LRUItemParams> lru_cache;
|
||||
u64 frame_tick = 0;
|
||||
u64 total_used_memory = 0;
|
||||
u64 minimum_memory = 0;
|
||||
u64 critical_memory = 0;
|
||||
|
||||
std::array<BufferId, ((1ULL << 39) >> PAGE_BITS)> page_table;
|
||||
};
|
||||
@@ -451,11 +454,30 @@ BufferCache<P>::BufferCache(VideoCore::RasterizerInterface& rasterizer_,
|
||||
// Ensure the first slot is used for the null buffer
|
||||
void(slot_buffers.insert(runtime, NullBufferParams{}));
|
||||
common_ranges.clear();
|
||||
|
||||
if (!runtime.CanReportMemoryUsage()) {
|
||||
minimum_memory = DEFAULT_EXPECTED_MEMORY;
|
||||
critical_memory = DEFAULT_CRITICAL_MEMORY;
|
||||
return;
|
||||
}
|
||||
|
||||
const s64 device_memory = static_cast<s64>(runtime.GetDeviceLocalMemory());
|
||||
const s64 min_spacing_expected = device_memory - 1_GiB - 512_MiB;
|
||||
const s64 min_spacing_critical = device_memory - 1_GiB;
|
||||
const s64 mem_threshold = std::min(device_memory, TARGET_THRESHOLD);
|
||||
const s64 min_vacancy_expected = (6 * mem_threshold) / 10;
|
||||
const s64 min_vacancy_critical = (3 * mem_threshold) / 10;
|
||||
minimum_memory = static_cast<u64>(
|
||||
std::max(std::min(device_memory - min_vacancy_expected, min_spacing_expected),
|
||||
DEFAULT_EXPECTED_MEMORY));
|
||||
critical_memory = static_cast<u64>(
|
||||
std::max(std::min(device_memory - min_vacancy_critical, min_spacing_critical),
|
||||
DEFAULT_CRITICAL_MEMORY));
|
||||
}
|
||||
|
||||
template <class P>
|
||||
void BufferCache<P>::RunGarbageCollector() {
|
||||
const bool aggressive_gc = total_used_memory >= CRITICAL_MEMORY;
|
||||
const bool aggressive_gc = total_used_memory >= critical_memory;
|
||||
const u64 ticks_to_destroy = aggressive_gc ? 60 : 120;
|
||||
int num_iterations = aggressive_gc ? 64 : 32;
|
||||
const auto clean_up = [this, &num_iterations](BufferId buffer_id) {
|
||||
@@ -486,7 +508,11 @@ void BufferCache<P>::TickFrame() {
|
||||
const bool skip_preferred = hits * 256 < shots * 251;
|
||||
uniform_buffer_skip_cache_size = skip_preferred ? DEFAULT_SKIP_CACHE_SIZE : 0;
|
||||
|
||||
if (total_used_memory >= EXPECTED_MEMORY) {
|
||||
// If we can obtain the memory info, use it instead of the estimate.
|
||||
if (runtime.CanReportMemoryUsage()) {
|
||||
total_used_memory = runtime.GetDeviceMemoryUsage();
|
||||
}
|
||||
if (total_used_memory >= minimum_memory) {
|
||||
RunGarbageCollector();
|
||||
}
|
||||
++frame_tick;
|
||||
|
||||
@@ -135,6 +135,20 @@ BufferCacheRuntime::BufferCacheRuntime(const Device& device_)
|
||||
buffer.Create();
|
||||
glNamedBufferData(buffer.handle, 0x10'000, nullptr, GL_STREAM_COPY);
|
||||
}
|
||||
|
||||
device_access_memory = [this]() -> u64 {
|
||||
if (device.CanReportMemoryUsage()) {
|
||||
return device.GetCurrentDedicatedVideoMemory() + 512_MiB;
|
||||
}
|
||||
return 2_GiB; // Return minimum requirements
|
||||
}();
|
||||
}
|
||||
|
||||
u64 BufferCacheRuntime::GetDeviceMemoryUsage() const {
|
||||
if (device.CanReportMemoryUsage()) {
|
||||
return device_access_memory - device.GetCurrentDedicatedVideoMemory();
|
||||
}
|
||||
return 2_GiB;
|
||||
}
|
||||
|
||||
void BufferCacheRuntime::CopyBuffer(Buffer& dst_buffer, Buffer& src_buffer,
|
||||
|
||||
@@ -89,6 +89,8 @@ public:
|
||||
void BindImageBuffer(Buffer& buffer, u32 offset, u32 size,
|
||||
VideoCore::Surface::PixelFormat format);
|
||||
|
||||
u64 GetDeviceMemoryUsage() const;
|
||||
|
||||
void BindFastUniformBuffer(size_t stage, u32 binding_index, u32 size) {
|
||||
const GLuint handle = fast_uniforms[stage][binding_index].handle;
|
||||
const GLsizeiptr gl_size = static_cast<GLsizeiptr>(size);
|
||||
@@ -151,6 +153,14 @@ public:
|
||||
use_storage_buffers = use_storage_buffers_;
|
||||
}
|
||||
|
||||
u64 GetDeviceLocalMemory() const {
|
||||
return device_access_memory;
|
||||
}
|
||||
|
||||
bool CanReportMemoryUsage() const {
|
||||
return device.CanReportMemoryUsage();
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr std::array PABO_LUT{
|
||||
GL_VERTEX_PROGRAM_PARAMETER_BUFFER_NV, GL_TESS_CONTROL_PROGRAM_PARAMETER_BUFFER_NV,
|
||||
@@ -184,6 +194,8 @@ private:
|
||||
std::array<OGLBuffer, VideoCommon::NUM_COMPUTE_UNIFORM_BUFFERS> copy_compute_uniforms;
|
||||
|
||||
u32 index_buffer_offset = 0;
|
||||
|
||||
u64 device_access_memory;
|
||||
};
|
||||
|
||||
struct BufferCacheParams {
|
||||
|
||||
@@ -13,12 +13,15 @@
|
||||
|
||||
#include <glad/glad.h>
|
||||
|
||||
#include "common/literals.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/settings.h"
|
||||
#include "shader_recompiler/stage.h"
|
||||
#include "video_core/renderer_opengl/gl_device.h"
|
||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
||||
|
||||
using namespace Common::Literals;
|
||||
|
||||
namespace OpenGL {
|
||||
namespace {
|
||||
constexpr std::array LIMIT_UBOS = {
|
||||
@@ -165,6 +168,7 @@ Device::Device() {
|
||||
has_sparse_texture_2 = GLAD_GL_ARB_sparse_texture2;
|
||||
warp_size_potentially_larger_than_guest = !is_nvidia && !is_intel;
|
||||
need_fastmath_off = is_nvidia;
|
||||
can_report_memory = GLAD_GL_NVX_gpu_memory_info;
|
||||
|
||||
// At the moment of writing this, only Nvidia's driver optimizes BufferSubData on exclusive
|
||||
// uniform buffers as "push constants"
|
||||
@@ -276,4 +280,10 @@ void main() {
|
||||
})");
|
||||
}
|
||||
|
||||
u64 Device::GetCurrentDedicatedVideoMemory() const {
|
||||
GLint cur_avail_mem_kb = 0;
|
||||
glGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &cur_avail_mem_kb);
|
||||
return static_cast<u64>(cur_avail_mem_kb) * 1_KiB;
|
||||
}
|
||||
|
||||
} // namespace OpenGL
|
||||
|
||||
@@ -20,6 +20,8 @@ public:
|
||||
|
||||
[[nodiscard]] std::string GetVendorName() const;
|
||||
|
||||
u64 GetCurrentDedicatedVideoMemory() const;
|
||||
|
||||
u32 GetMaxUniformBuffers(Shader::Stage stage) const noexcept {
|
||||
return max_uniform_buffers[static_cast<size_t>(stage)];
|
||||
}
|
||||
@@ -168,6 +170,10 @@ public:
|
||||
return vendor_name == "ATI Technologies Inc.";
|
||||
}
|
||||
|
||||
bool CanReportMemoryUsage() const {
|
||||
return can_report_memory;
|
||||
}
|
||||
|
||||
private:
|
||||
static bool TestVariableAoffi();
|
||||
static bool TestPreciseBug();
|
||||
@@ -210,6 +216,7 @@ private:
|
||||
bool need_fastmath_off{};
|
||||
bool has_cbuf_ftou_bug{};
|
||||
bool has_bool_ref_bug{};
|
||||
bool can_report_memory{};
|
||||
|
||||
std::string vendor_name;
|
||||
};
|
||||
|
||||
@@ -352,7 +352,7 @@ void RasterizerOpenGL::OnCPUWrite(VAddr addr, u64 size) {
|
||||
shader_cache.OnCPUWrite(addr, size);
|
||||
{
|
||||
std::scoped_lock lock{texture_cache.mutex};
|
||||
texture_cache.WriteMemory(addr, size);
|
||||
texture_cache.CachedWriteMemory(addr, size);
|
||||
}
|
||||
{
|
||||
std::scoped_lock lock{buffer_cache.mutex};
|
||||
@@ -363,6 +363,10 @@ void RasterizerOpenGL::OnCPUWrite(VAddr addr, u64 size) {
|
||||
void RasterizerOpenGL::SyncGuestHost() {
|
||||
MICROPROFILE_SCOPE(OpenGL_CacheManagement);
|
||||
shader_cache.SyncGuestHost();
|
||||
{
|
||||
std::scoped_lock lock{texture_cache.mutex};
|
||||
texture_cache.FlushCachedWrites();
|
||||
}
|
||||
{
|
||||
std::scoped_lock lock{buffer_cache.mutex};
|
||||
buffer_cache.FlushCachedWrites();
|
||||
|
||||
@@ -484,6 +484,13 @@ TextureCacheRuntime::TextureCacheRuntime(const Device& device_, ProgramManager&
|
||||
rescale_read_fbos[i].Create();
|
||||
}
|
||||
}
|
||||
|
||||
device_access_memory = [this]() -> u64 {
|
||||
if (device.CanReportMemoryUsage()) {
|
||||
return device.GetCurrentDedicatedVideoMemory() + 512_MiB;
|
||||
}
|
||||
return 2_GiB; // Return minimum requirements
|
||||
}();
|
||||
}
|
||||
|
||||
TextureCacheRuntime::~TextureCacheRuntime() = default;
|
||||
@@ -500,13 +507,11 @@ ImageBufferMap TextureCacheRuntime::DownloadStagingBuffer(size_t size) {
|
||||
return download_buffers.RequestMap(size, false);
|
||||
}
|
||||
|
||||
u64 TextureCacheRuntime::GetDeviceLocalMemory() const {
|
||||
if (GLAD_GL_NVX_gpu_memory_info) {
|
||||
GLint cur_avail_mem_kb = 0;
|
||||
glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &cur_avail_mem_kb);
|
||||
return static_cast<u64>(cur_avail_mem_kb) * 1_KiB;
|
||||
u64 TextureCacheRuntime::GetDeviceMemoryUsage() const {
|
||||
if (device.CanReportMemoryUsage()) {
|
||||
return device_access_memory - device.GetCurrentDedicatedVideoMemory();
|
||||
}
|
||||
return 2_GiB; // Return minimum requirements
|
||||
return 2_GiB;
|
||||
}
|
||||
|
||||
void TextureCacheRuntime::CopyImage(Image& dst_image, Image& src_image,
|
||||
@@ -686,6 +691,7 @@ Image::Image(TextureCacheRuntime& runtime_, const VideoCommon::ImageInfo& info_,
|
||||
}
|
||||
if (IsConverted(runtime->device, info.format, info.type)) {
|
||||
flags |= ImageFlagBits::Converted;
|
||||
flags |= ImageFlagBits::CostlyLoad;
|
||||
gl_internal_format = IsPixelFormatSRGB(info.format) ? GL_SRGB8_ALPHA8 : GL_RGBA8;
|
||||
gl_format = GL_RGBA;
|
||||
gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <glad/glad.h>
|
||||
|
||||
#include "shader_recompiler/shader_info.h"
|
||||
#include "video_core/renderer_opengl/gl_device.h"
|
||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
||||
#include "video_core/renderer_opengl/util_shaders.h"
|
||||
#include "video_core/texture_cache/image_view_base.h"
|
||||
@@ -21,7 +22,6 @@ struct ResolutionScalingInfo;
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
class Device;
|
||||
class ProgramManager;
|
||||
class StateTracker;
|
||||
|
||||
@@ -83,7 +83,15 @@ public:
|
||||
|
||||
ImageBufferMap DownloadStagingBuffer(size_t size);
|
||||
|
||||
u64 GetDeviceLocalMemory() const;
|
||||
u64 GetDeviceLocalMemory() const {
|
||||
return device_access_memory;
|
||||
}
|
||||
|
||||
u64 GetDeviceMemoryUsage() const;
|
||||
|
||||
bool CanReportMemoryUsage() const {
|
||||
return device.CanReportMemoryUsage();
|
||||
}
|
||||
|
||||
bool ShouldReinterpret([[maybe_unused]] Image& dst, [[maybe_unused]] Image& src) {
|
||||
return true;
|
||||
@@ -172,6 +180,7 @@ private:
|
||||
std::array<OGLFramebuffer, 4> rescale_draw_fbos;
|
||||
std::array<OGLFramebuffer, 4> rescale_read_fbos;
|
||||
const Settings::ResolutionScalingInfo& resolution;
|
||||
u64 device_access_memory;
|
||||
};
|
||||
|
||||
class Image : public VideoCommon::ImageBase {
|
||||
|
||||
@@ -141,6 +141,18 @@ StagingBufferRef BufferCacheRuntime::DownloadStagingBuffer(size_t size) {
|
||||
return staging_pool.Request(size, MemoryUsage::Download);
|
||||
}
|
||||
|
||||
u64 BufferCacheRuntime::GetDeviceLocalMemory() const {
|
||||
return device.GetDeviceLocalMemory();
|
||||
}
|
||||
|
||||
u64 BufferCacheRuntime::GetDeviceMemoryUsage() const {
|
||||
return device.GetDeviceMemoryUsage();
|
||||
}
|
||||
|
||||
bool BufferCacheRuntime::CanReportMemoryUsage() const {
|
||||
return device.CanReportMemoryUsage();
|
||||
}
|
||||
|
||||
void BufferCacheRuntime::Finish() {
|
||||
scheduler.Finish();
|
||||
}
|
||||
|
||||
@@ -65,6 +65,12 @@ public:
|
||||
|
||||
void Finish();
|
||||
|
||||
u64 GetDeviceLocalMemory() const;
|
||||
|
||||
u64 GetDeviceMemoryUsage() const;
|
||||
|
||||
bool CanReportMemoryUsage() const;
|
||||
|
||||
[[nodiscard]] StagingBufferRef UploadStagingBuffer(size_t size);
|
||||
|
||||
[[nodiscard]] StagingBufferRef DownloadStagingBuffer(size_t size);
|
||||
|
||||
@@ -408,7 +408,7 @@ void RasterizerVulkan::OnCPUWrite(VAddr addr, u64 size) {
|
||||
pipeline_cache.OnCPUWrite(addr, size);
|
||||
{
|
||||
std::scoped_lock lock{texture_cache.mutex};
|
||||
texture_cache.WriteMemory(addr, size);
|
||||
texture_cache.CachedWriteMemory(addr, size);
|
||||
}
|
||||
{
|
||||
std::scoped_lock lock{buffer_cache.mutex};
|
||||
@@ -418,6 +418,10 @@ void RasterizerVulkan::OnCPUWrite(VAddr addr, u64 size) {
|
||||
|
||||
void RasterizerVulkan::SyncGuestHost() {
|
||||
pipeline_cache.SyncGuestHost();
|
||||
{
|
||||
std::scoped_lock lock{texture_cache.mutex};
|
||||
texture_cache.FlushCachedWrites();
|
||||
}
|
||||
{
|
||||
std::scoped_lock lock{buffer_cache.mutex};
|
||||
buffer_cache.FlushCachedWrites();
|
||||
|
||||
@@ -118,7 +118,7 @@ StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& mem
|
||||
.image = nullptr,
|
||||
.buffer = *stream_buffer,
|
||||
};
|
||||
const auto memory_properties = device.GetPhysical().GetMemoryProperties();
|
||||
const auto memory_properties = device.GetPhysical().GetMemoryProperties().memoryProperties;
|
||||
VkMemoryAllocateInfo stream_memory_info{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
.pNext = make_dedicated ? &dedicated_info : nullptr,
|
||||
|
||||
@@ -1189,6 +1189,14 @@ u64 TextureCacheRuntime::GetDeviceLocalMemory() const {
|
||||
return device.GetDeviceLocalMemory();
|
||||
}
|
||||
|
||||
u64 TextureCacheRuntime::GetDeviceMemoryUsage() const {
|
||||
return device.GetDeviceMemoryUsage();
|
||||
}
|
||||
|
||||
bool TextureCacheRuntime::CanReportMemoryUsage() const {
|
||||
return device.CanReportMemoryUsage();
|
||||
}
|
||||
|
||||
void TextureCacheRuntime::TickFrame() {}
|
||||
|
||||
Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu_addr_,
|
||||
@@ -1203,6 +1211,7 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu
|
||||
} else {
|
||||
flags |= VideoCommon::ImageFlagBits::Converted;
|
||||
}
|
||||
flags |= VideoCommon::ImageFlagBits::CostlyLoad;
|
||||
}
|
||||
if (runtime->device.HasDebuggingToolAttached()) {
|
||||
original_image.SetObjectNameEXT(VideoCommon::Name(*this).c_str());
|
||||
|
||||
@@ -55,6 +55,10 @@ public:
|
||||
|
||||
u64 GetDeviceLocalMemory() const;
|
||||
|
||||
u64 GetDeviceMemoryUsage() const;
|
||||
|
||||
bool CanReportMemoryUsage() const;
|
||||
|
||||
void BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src,
|
||||
const Region2D& dst_region, const Region2D& src_region,
|
||||
Tegra::Engines::Fermi2D::Filter filter,
|
||||
|
||||
@@ -33,11 +33,15 @@ enum class ImageFlagBits : u32 {
|
||||
///< garbage collection priority
|
||||
Alias = 1 << 11, ///< This image has aliases and has priority on garbage
|
||||
///< collection
|
||||
CostlyLoad = 1 << 12, ///< Protected from low-tier GC as it is costly to load back.
|
||||
|
||||
// Rescaler
|
||||
Rescaled = 1 << 12,
|
||||
CheckingRescalable = 1 << 13,
|
||||
IsRescalable = 1 << 14,
|
||||
Rescaled = 1 << 13,
|
||||
CheckingRescalable = 1 << 14,
|
||||
IsRescalable = 1 << 15,
|
||||
|
||||
// Cached CPU
|
||||
CachedCpuModified = 1 << 16, ///< Contents have been modified from the CPU
|
||||
};
|
||||
DECLARE_ENUM_FLAG_OPERATORS(ImageFlagBits)
|
||||
|
||||
|
||||
@@ -50,14 +50,20 @@ TextureCache<P>::TextureCache(Runtime& runtime_, VideoCore::RasterizerInterface&
|
||||
void(slot_samplers.insert(runtime, sampler_descriptor));
|
||||
|
||||
if constexpr (HAS_DEVICE_MEMORY_INFO) {
|
||||
const auto device_memory = runtime.GetDeviceLocalMemory();
|
||||
const u64 possible_expected_memory = (device_memory * 4) / 10;
|
||||
const u64 possible_critical_memory = (device_memory * 7) / 10;
|
||||
expected_memory = std::max(possible_expected_memory, DEFAULT_EXPECTED_MEMORY - 256_MiB);
|
||||
critical_memory = std::max(possible_critical_memory, DEFAULT_CRITICAL_MEMORY - 512_MiB);
|
||||
minimum_memory = 0;
|
||||
const s64 device_memory = static_cast<s64>(runtime.GetDeviceLocalMemory());
|
||||
const s64 min_spacing_expected = device_memory - 1_GiB - 512_MiB;
|
||||
const s64 min_spacing_critical = device_memory - 1_GiB;
|
||||
const s64 mem_threshold = std::min(device_memory, TARGET_THRESHOLD);
|
||||
const s64 min_vacancy_expected = (6 * mem_threshold) / 10;
|
||||
const s64 min_vacancy_critical = (3 * mem_threshold) / 10;
|
||||
expected_memory = static_cast<u64>(
|
||||
std::max(std::min(device_memory - min_vacancy_expected, min_spacing_expected),
|
||||
DEFAULT_EXPECTED_MEMORY));
|
||||
critical_memory = static_cast<u64>(
|
||||
std::max(std::min(device_memory - min_vacancy_critical, min_spacing_critical),
|
||||
DEFAULT_CRITICAL_MEMORY));
|
||||
minimum_memory = static_cast<u64>((device_memory - mem_threshold) / 2);
|
||||
} else {
|
||||
// On OpenGL we can be more conservatives as the driver takes care.
|
||||
expected_memory = DEFAULT_EXPECTED_MEMORY + 512_MiB;
|
||||
critical_memory = DEFAULT_CRITICAL_MEMORY + 1_GiB;
|
||||
minimum_memory = 0;
|
||||
@@ -66,18 +72,21 @@ TextureCache<P>::TextureCache(Runtime& runtime_, VideoCore::RasterizerInterface&
|
||||
|
||||
template <class P>
|
||||
void TextureCache<P>::RunGarbageCollector() {
|
||||
const bool high_priority_mode = total_used_memory >= expected_memory;
|
||||
const bool aggressive_mode = total_used_memory >= critical_memory;
|
||||
const u64 ticks_to_destroy = aggressive_mode ? 10ULL : high_priority_mode ? 25ULL : 100ULL;
|
||||
size_t num_iterations = aggressive_mode ? 300 : (high_priority_mode ? 50 : 10);
|
||||
const auto clean_up = [this, &num_iterations, high_priority_mode](ImageId image_id) {
|
||||
bool high_priority_mode = total_used_memory >= expected_memory;
|
||||
bool aggressive_mode = total_used_memory >= critical_memory;
|
||||
const u64 ticks_to_destroy = aggressive_mode ? 10ULL : high_priority_mode ? 25ULL : 50ULL;
|
||||
size_t num_iterations = aggressive_mode ? 40 : (high_priority_mode ? 20 : 10);
|
||||
const auto clean_up = [this, &num_iterations, &high_priority_mode,
|
||||
&aggressive_mode](ImageId image_id) {
|
||||
if (num_iterations == 0) {
|
||||
return true;
|
||||
}
|
||||
--num_iterations;
|
||||
auto& image = slot_images[image_id];
|
||||
const bool must_download = image.IsSafeDownload();
|
||||
if (!high_priority_mode && must_download) {
|
||||
const bool must_download =
|
||||
image.IsSafeDownload() && False(image.flags & ImageFlagBits::BadOverlap);
|
||||
if (!high_priority_mode &&
|
||||
(must_download || True(image.flags & ImageFlagBits::CostlyLoad))) {
|
||||
return false;
|
||||
}
|
||||
if (must_download) {
|
||||
@@ -92,6 +101,18 @@ void TextureCache<P>::RunGarbageCollector() {
|
||||
}
|
||||
UnregisterImage(image_id);
|
||||
DeleteImage(image_id, image.scale_tick > frame_tick + 5);
|
||||
if (total_used_memory < critical_memory) {
|
||||
if (aggressive_mode) {
|
||||
// Sink the aggresiveness.
|
||||
num_iterations >>= 2;
|
||||
aggressive_mode = false;
|
||||
return false;
|
||||
}
|
||||
if (high_priority_mode && total_used_memory < expected_memory) {
|
||||
num_iterations >>= 1;
|
||||
high_priority_mode = false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
lru_cache.ForEachItemBelow(frame_tick - ticks_to_destroy, clean_up);
|
||||
@@ -99,6 +120,10 @@ void TextureCache<P>::RunGarbageCollector() {
|
||||
|
||||
template <class P>
|
||||
void TextureCache<P>::TickFrame() {
|
||||
// If we can obtain the memory info, use it instead of the estimate.
|
||||
if (runtime.CanReportMemoryUsage()) {
|
||||
total_used_memory = runtime.GetDeviceMemoryUsage();
|
||||
}
|
||||
if (total_used_memory > minimum_memory) {
|
||||
RunGarbageCollector();
|
||||
}
|
||||
@@ -106,6 +131,7 @@ void TextureCache<P>::TickFrame() {
|
||||
sentenced_framebuffers.Tick();
|
||||
sentenced_image_view.Tick();
|
||||
runtime.TickFrame();
|
||||
critical_gc = 0;
|
||||
++frame_tick;
|
||||
}
|
||||
|
||||
@@ -411,6 +437,23 @@ void TextureCache<P>::WriteMemory(VAddr cpu_addr, size_t size) {
|
||||
});
|
||||
}
|
||||
|
||||
template <class P>
|
||||
void TextureCache<P>::CachedWriteMemory(VAddr cpu_addr, size_t size) {
|
||||
const VAddr new_cpu_addr = Common::AlignDown(cpu_addr, CPU_PAGE_SIZE);
|
||||
const size_t new_size = Common::AlignUp(size + cpu_addr - new_cpu_addr, CPU_PAGE_SIZE);
|
||||
ForEachImageInRegion(new_cpu_addr, new_size, [this](ImageId image_id, Image& image) {
|
||||
if (True(image.flags & ImageFlagBits::CachedCpuModified)) {
|
||||
return;
|
||||
}
|
||||
image.flags |= ImageFlagBits::CachedCpuModified;
|
||||
cached_cpu_invalidate.insert(image_id);
|
||||
|
||||
if (True(image.flags & ImageFlagBits::Tracked)) {
|
||||
UntrackImage(image, image_id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template <class P>
|
||||
void TextureCache<P>::DownloadMemory(VAddr cpu_addr, size_t size) {
|
||||
std::vector<ImageId> images;
|
||||
@@ -468,6 +511,18 @@ void TextureCache<P>::UnmapGPUMemory(GPUVAddr gpu_addr, size_t size) {
|
||||
}
|
||||
}
|
||||
|
||||
template <class P>
|
||||
void TextureCache<P>::FlushCachedWrites() {
|
||||
for (ImageId image_id : cached_cpu_invalidate) {
|
||||
Image& image = slot_images[image_id];
|
||||
if (True(image.flags & ImageFlagBits::CachedCpuModified)) {
|
||||
image.flags &= ~ImageFlagBits::CachedCpuModified;
|
||||
image.flags |= ImageFlagBits::CpuModified;
|
||||
}
|
||||
}
|
||||
cached_cpu_invalidate.clear();
|
||||
}
|
||||
|
||||
template <class P>
|
||||
void TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
|
||||
const Tegra::Engines::Fermi2D::Surface& src,
|
||||
@@ -1052,6 +1107,11 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VA
|
||||
|
||||
for (const ImageId overlap_id : overlap_ids) {
|
||||
Image& overlap = slot_images[overlap_id];
|
||||
if (True(overlap.flags & ImageFlagBits::GpuModified)) {
|
||||
new_image.flags |= ImageFlagBits::GpuModified;
|
||||
new_image.modification_tick =
|
||||
std::max(overlap.modification_tick, new_image.modification_tick);
|
||||
}
|
||||
if (overlap.info.num_samples != new_image.info.num_samples) {
|
||||
LOG_WARNING(HW_GPU, "Copying between images with different samples is not implemented");
|
||||
} else {
|
||||
@@ -1414,6 +1474,10 @@ void TextureCache<P>::RegisterImage(ImageId image_id) {
|
||||
tentative_size = EstimatedDecompressedSize(tentative_size, image.info.format);
|
||||
}
|
||||
total_used_memory += Common::AlignUp(tentative_size, 1024);
|
||||
if (total_used_memory > critical_memory && critical_gc < GC_EMERGENCY_COUNTS) {
|
||||
RunGarbageCollector();
|
||||
critical_gc++;
|
||||
}
|
||||
image.lru_index = lru_cache.Insert(image_id, frame_tick);
|
||||
|
||||
ForEachGPUPage(image.gpu_addr, image.guest_size_bytes,
|
||||
@@ -1525,6 +1589,9 @@ void TextureCache<P>::UnregisterImage(ImageId image_id) {
|
||||
template <class P>
|
||||
void TextureCache<P>::TrackImage(ImageBase& image, ImageId image_id) {
|
||||
ASSERT(False(image.flags & ImageFlagBits::Tracked));
|
||||
if (True(image.flags & ImageFlagBits::CachedCpuModified)) {
|
||||
return;
|
||||
}
|
||||
image.flags |= ImageFlagBits::Tracked;
|
||||
if (False(image.flags & ImageFlagBits::Sparse)) {
|
||||
rasterizer.UpdatePagesCachedCount(image.cpu_addr, image.guest_size_bytes, 1);
|
||||
@@ -1581,6 +1648,9 @@ void TextureCache<P>::DeleteImage(ImageId image_id, bool immediate_delete) {
|
||||
tentative_size = EstimatedDecompressedSize(tentative_size, image.info.format);
|
||||
}
|
||||
total_used_memory -= Common::AlignUp(tentative_size, 1024);
|
||||
if (True(image.flags & ImageFlagBits::CachedCpuModified)) {
|
||||
cached_cpu_invalidate.erase(image_id);
|
||||
}
|
||||
const GPUVAddr gpu_addr = image.gpu_addr;
|
||||
const auto alloc_it = image_allocs_table.find(gpu_addr);
|
||||
if (alloc_it == image_allocs_table.end()) {
|
||||
@@ -1704,6 +1774,9 @@ void TextureCache<P>::SynchronizeAliases(ImageId image_id) {
|
||||
most_recent_tick = std::max(most_recent_tick, aliased_image.modification_tick);
|
||||
aliased_images.push_back(&aliased);
|
||||
any_rescaled |= True(aliased_image.flags & ImageFlagBits::Rescaled);
|
||||
if (True(aliased_image.flags & ImageFlagBits::GpuModified)) {
|
||||
image.flags |= ImageFlagBits::GpuModified;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (aliased_images.empty()) {
|
||||
@@ -1744,7 +1817,11 @@ template <class P>
|
||||
void TextureCache<P>::PrepareImage(ImageId image_id, bool is_modification, bool invalidate) {
|
||||
Image& image = slot_images[image_id];
|
||||
if (invalidate) {
|
||||
image.flags &= ~(ImageFlagBits::CpuModified | ImageFlagBits::GpuModified);
|
||||
if (True(image.flags & ImageFlagBits::CachedCpuModified)) {
|
||||
cached_cpu_invalidate.erase(image_id);
|
||||
}
|
||||
image.flags &= ~(ImageFlagBits::CpuModified | ImageFlagBits::GpuModified |
|
||||
ImageFlagBits::CachedCpuModified);
|
||||
if (False(image.flags & ImageFlagBits::Tracked)) {
|
||||
TrackImage(image, image_id);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <span>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
|
||||
@@ -50,6 +51,9 @@ class TextureCache {
|
||||
/// Address shift for caching images into a hash table
|
||||
static constexpr u64 PAGE_BITS = 20;
|
||||
|
||||
static constexpr u64 CPU_PAGE_BITS = 12;
|
||||
static constexpr u64 CPU_PAGE_SIZE = 1ULL << CPU_PAGE_BITS;
|
||||
|
||||
/// Enables debugging features to the texture cache
|
||||
static constexpr bool ENABLE_VALIDATION = P::ENABLE_VALIDATION;
|
||||
/// Implement blits as copies between framebuffers
|
||||
@@ -59,8 +63,10 @@ class TextureCache {
|
||||
/// True when the API can provide info about the memory of the device.
|
||||
static constexpr bool HAS_DEVICE_MEMORY_INFO = P::HAS_DEVICE_MEMORY_INFO;
|
||||
|
||||
static constexpr u64 DEFAULT_EXPECTED_MEMORY = 1_GiB;
|
||||
static constexpr u64 DEFAULT_CRITICAL_MEMORY = 2_GiB;
|
||||
static constexpr s64 TARGET_THRESHOLD = 4_GiB;
|
||||
static constexpr s64 DEFAULT_EXPECTED_MEMORY = 1_GiB + 125_MiB;
|
||||
static constexpr s64 DEFAULT_CRITICAL_MEMORY = 1_GiB + 625_MiB;
|
||||
static constexpr size_t GC_EMERGENCY_COUNTS = 2;
|
||||
|
||||
using Runtime = typename P::Runtime;
|
||||
using Image = typename P::Image;
|
||||
@@ -134,6 +140,9 @@ public:
|
||||
/// Mark images in a range as modified from the CPU
|
||||
void WriteMemory(VAddr cpu_addr, size_t size);
|
||||
|
||||
/// Mark images in a range as modified from the CPU
|
||||
void CachedWriteMemory(VAddr cpu_addr, size_t size);
|
||||
|
||||
/// Download contents of host images to guest memory in a region
|
||||
void DownloadMemory(VAddr cpu_addr, size_t size);
|
||||
|
||||
@@ -143,6 +152,8 @@ public:
|
||||
/// Remove images in a region
|
||||
void UnmapGPUMemory(GPUVAddr gpu_addr, size_t size);
|
||||
|
||||
void FlushCachedWrites();
|
||||
|
||||
/// Blit an image with the given parameters
|
||||
void BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
|
||||
const Tegra::Engines::Fermi2D::Surface& src,
|
||||
@@ -364,6 +375,8 @@ private:
|
||||
|
||||
std::unordered_map<ImageId, std::vector<ImageViewId>> sparse_views;
|
||||
|
||||
std::unordered_set<ImageId> cached_cpu_invalidate;
|
||||
|
||||
VAddr virtual_invalid_space{};
|
||||
|
||||
bool has_deleted_images = false;
|
||||
@@ -372,6 +385,7 @@ private:
|
||||
u64 minimum_memory;
|
||||
u64 expected_memory;
|
||||
u64 critical_memory;
|
||||
size_t critical_gc;
|
||||
|
||||
SlotVector<Image> slot_images;
|
||||
SlotVector<ImageMapView> slot_map_views;
|
||||
|
||||
@@ -12,12 +12,14 @@
|
||||
#include <vector>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/literals.h"
|
||||
#include "common/settings.h"
|
||||
#include "video_core/vulkan_common/nsight_aftermath_tracker.h"
|
||||
#include "video_core/vulkan_common/vulkan_device.h"
|
||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||
|
||||
namespace Vulkan {
|
||||
using namespace Common::Literals;
|
||||
namespace {
|
||||
namespace Alternatives {
|
||||
constexpr std::array STENCIL8_UINT{
|
||||
@@ -596,6 +598,11 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
||||
}
|
||||
logical = vk::Device::Create(physical, queue_cis, extensions, first_next, dld);
|
||||
|
||||
is_integrated = properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU;
|
||||
is_virtual = properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU;
|
||||
is_non_gpu = properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_OTHER ||
|
||||
properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU;
|
||||
|
||||
CollectPhysicalMemoryInfo();
|
||||
CollectTelemetryParameters();
|
||||
CollectToolingInfo();
|
||||
@@ -985,6 +992,7 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {
|
||||
test(has_khr_swapchain_mutable_format, VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME,
|
||||
false);
|
||||
test(has_ext_line_rasterization, VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME, false);
|
||||
test(ext_memory_budget, VK_EXT_MEMORY_BUDGET_EXTENSION_NAME, true);
|
||||
if (Settings::values.enable_nsight_aftermath) {
|
||||
test(nv_device_diagnostics_config, VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME,
|
||||
true);
|
||||
@@ -997,7 +1005,7 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {
|
||||
VkPhysicalDeviceFeatures2KHR features{};
|
||||
features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR;
|
||||
|
||||
VkPhysicalDeviceProperties2KHR physical_properties;
|
||||
VkPhysicalDeviceProperties2KHR physical_properties{};
|
||||
physical_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR;
|
||||
|
||||
if (has_khr_shader_float16_int8) {
|
||||
@@ -1267,15 +1275,50 @@ void Device::CollectTelemetryParameters() {
|
||||
vendor_name = driver.driverName;
|
||||
}
|
||||
|
||||
u64 Device::GetDeviceMemoryUsage() const {
|
||||
VkPhysicalDeviceMemoryBudgetPropertiesEXT budget;
|
||||
budget.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT;
|
||||
budget.pNext = nullptr;
|
||||
physical.GetMemoryProperties(&budget);
|
||||
u64 result{};
|
||||
for (const size_t heap : valid_heap_memory) {
|
||||
result += budget.heapUsage[heap];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void Device::CollectPhysicalMemoryInfo() {
|
||||
const auto mem_properties = physical.GetMemoryProperties();
|
||||
VkPhysicalDeviceMemoryBudgetPropertiesEXT budget{};
|
||||
budget.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT;
|
||||
const auto mem_info = physical.GetMemoryProperties(ext_memory_budget ? &budget : nullptr);
|
||||
const auto& mem_properties = mem_info.memoryProperties;
|
||||
const size_t num_properties = mem_properties.memoryHeapCount;
|
||||
device_access_memory = 0;
|
||||
u64 device_initial_usage = 0;
|
||||
u64 local_memory = 0;
|
||||
for (size_t element = 0; element < num_properties; ++element) {
|
||||
if ((mem_properties.memoryHeaps[element].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0) {
|
||||
device_access_memory += mem_properties.memoryHeaps[element].size;
|
||||
const bool is_heap_local =
|
||||
(mem_properties.memoryHeaps[element].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0;
|
||||
if (!is_integrated && !is_heap_local) {
|
||||
continue;
|
||||
}
|
||||
valid_heap_memory.push_back(element);
|
||||
if (is_heap_local) {
|
||||
local_memory += mem_properties.memoryHeaps[element].size;
|
||||
}
|
||||
if (ext_memory_budget) {
|
||||
device_initial_usage += budget.heapUsage[element];
|
||||
device_access_memory += budget.heapBudget[element];
|
||||
continue;
|
||||
}
|
||||
device_access_memory += mem_properties.memoryHeaps[element].size;
|
||||
}
|
||||
if (!is_integrated) {
|
||||
return;
|
||||
}
|
||||
const s64 available_memory = static_cast<s64>(device_access_memory - device_initial_usage);
|
||||
device_access_memory = static_cast<u64>(std::max<s64>(
|
||||
std::min<s64>(available_memory - 8_GiB, 4_GiB), static_cast<s64>(local_memory)));
|
||||
}
|
||||
|
||||
void Device::CollectToolingInfo() {
|
||||
|
||||
@@ -341,6 +341,12 @@ public:
|
||||
return device_access_memory;
|
||||
}
|
||||
|
||||
bool CanReportMemoryUsage() const {
|
||||
return ext_memory_budget;
|
||||
}
|
||||
|
||||
u64 GetDeviceMemoryUsage() const;
|
||||
|
||||
u32 GetSetsPerPool() const {
|
||||
return sets_per_pool;
|
||||
}
|
||||
@@ -421,6 +427,9 @@ private:
|
||||
bool is_topology_list_restart_supported{}; ///< Support for primitive restart with list
|
||||
///< topologies.
|
||||
bool is_patch_list_restart_supported{}; ///< Support for primitive restart with list patch.
|
||||
bool is_integrated{}; ///< Is GPU an iGPU.
|
||||
bool is_virtual{}; ///< Is GPU a virtual GPU.
|
||||
bool is_non_gpu{}; ///< Is SoftwareRasterizer, FPGA, non-GPU device.
|
||||
bool nv_viewport_swizzle{}; ///< Support for VK_NV_viewport_swizzle.
|
||||
bool nv_viewport_array2{}; ///< Support for VK_NV_viewport_array2.
|
||||
bool nv_geometry_shader_passthrough{}; ///< Support for VK_NV_geometry_shader_passthrough.
|
||||
@@ -445,6 +454,7 @@ private:
|
||||
bool ext_shader_atomic_int64{}; ///< Support for VK_KHR_shader_atomic_int64.
|
||||
bool ext_conservative_rasterization{}; ///< Support for VK_EXT_conservative_rasterization.
|
||||
bool ext_provoking_vertex{}; ///< Support for VK_EXT_provoking_vertex.
|
||||
bool ext_memory_budget{}; ///< Support for VK_EXT_memory_budget.
|
||||
bool nv_device_diagnostics_config{}; ///< Support for VK_NV_device_diagnostics_config.
|
||||
bool has_broken_cube_compatibility{}; ///< Has broken cube compatiblity bit
|
||||
bool has_renderdoc{}; ///< Has RenderDoc attached
|
||||
@@ -456,6 +466,7 @@ private:
|
||||
// Telemetry parameters
|
||||
std::string vendor_name; ///< Device's driver name.
|
||||
std::vector<std::string> supported_extensions; ///< Reported Vulkan extensions.
|
||||
std::vector<size_t> valid_heap_memory; ///< Heaps used.
|
||||
|
||||
/// Format properties dictionary.
|
||||
std::unordered_map<VkFormat, VkFormatProperties> format_properties;
|
||||
|
||||
@@ -227,7 +227,7 @@ void MemoryCommit::Release() {
|
||||
}
|
||||
|
||||
MemoryAllocator::MemoryAllocator(const Device& device_, bool export_allocations_)
|
||||
: device{device_}, properties{device_.GetPhysical().GetMemoryProperties()},
|
||||
: device{device_}, properties{device_.GetPhysical().GetMemoryProperties().memoryProperties},
|
||||
export_allocations{export_allocations_},
|
||||
buffer_image_granularity{
|
||||
device_.GetPhysical().GetProperties().limits.bufferImageGranularity} {}
|
||||
|
||||
@@ -237,8 +237,8 @@ bool Load(VkInstance instance, InstanceDispatch& dld) noexcept {
|
||||
return X(vkCreateDevice) && X(vkDestroyDevice) && X(vkDestroyDevice) &&
|
||||
X(vkEnumerateDeviceExtensionProperties) && X(vkEnumeratePhysicalDevices) &&
|
||||
X(vkGetDeviceProcAddr) && X(vkGetPhysicalDeviceFormatProperties) &&
|
||||
X(vkGetPhysicalDeviceMemoryProperties) && X(vkGetPhysicalDeviceProperties) &&
|
||||
X(vkGetPhysicalDeviceQueueFamilyProperties);
|
||||
X(vkGetPhysicalDeviceMemoryProperties) && X(vkGetPhysicalDeviceMemoryProperties2) &&
|
||||
X(vkGetPhysicalDeviceProperties) && X(vkGetPhysicalDeviceQueueFamilyProperties);
|
||||
#undef X
|
||||
}
|
||||
|
||||
@@ -926,9 +926,12 @@ std::vector<VkPresentModeKHR> PhysicalDevice::GetSurfacePresentModesKHR(
|
||||
return modes;
|
||||
}
|
||||
|
||||
VkPhysicalDeviceMemoryProperties PhysicalDevice::GetMemoryProperties() const noexcept {
|
||||
VkPhysicalDeviceMemoryProperties properties;
|
||||
dld->vkGetPhysicalDeviceMemoryProperties(physical_device, &properties);
|
||||
VkPhysicalDeviceMemoryProperties2 PhysicalDevice::GetMemoryProperties(
|
||||
void* next_structures) const noexcept {
|
||||
VkPhysicalDeviceMemoryProperties2 properties{};
|
||||
properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2;
|
||||
properties.pNext = next_structures;
|
||||
dld->vkGetPhysicalDeviceMemoryProperties2(physical_device, &properties);
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
||||
@@ -172,6 +172,7 @@ struct InstanceDispatch {
|
||||
PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR{};
|
||||
PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties{};
|
||||
PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties{};
|
||||
PFN_vkGetPhysicalDeviceMemoryProperties2 vkGetPhysicalDeviceMemoryProperties2{};
|
||||
PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties{};
|
||||
PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR{};
|
||||
PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties{};
|
||||
@@ -950,7 +951,8 @@ public:
|
||||
|
||||
std::vector<VkPresentModeKHR> GetSurfacePresentModesKHR(VkSurfaceKHR) const;
|
||||
|
||||
VkPhysicalDeviceMemoryProperties GetMemoryProperties() const noexcept;
|
||||
VkPhysicalDeviceMemoryProperties2 GetMemoryProperties(
|
||||
void* next_structures = nullptr) const noexcept;
|
||||
|
||||
private:
|
||||
VkPhysicalDevice physical_device = nullptr;
|
||||
|
||||
Reference in New Issue
Block a user