Compare commits

..

1 Commits

Author SHA1 Message Date
6e7d1597af Android #1 2023-07-09 06:55:26 +00:00
36 changed files with 342 additions and 1347 deletions

View File

@ -56,6 +56,7 @@ for i in package/*.exe; do
x86_64-w64-mingw32-strip "${i}" x86_64-w64-mingw32-strip "${i}"
done done
pip3 install pefile
python3 .ci/scripts/windows/scan_dll.py package/*.exe package/imageformats/*.dll "package/" python3 .ci/scripts/windows/scan_dll.py package/*.exe package/imageformats/*.dll "package/"
# copy FFmpeg libraries # copy FFmpeg libraries

View File

@ -22,7 +22,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
android:label="@string/app_name_suffixed" android:label="@string/app_name_suffixed"
android:icon="@drawable/ic_launcher" android:icon="@drawable/ic_launcher"
android:allowBackup="true" android:allowBackup="true"
android:hasFragileUserData="false" android:hasFragileUserData="true"
android:supportsRtl="true" android:supportsRtl="true"
android:isGame="true" android:isGame="true"
android:localeConfig="@xml/locales_config" android:localeConfig="@xml/locales_config"

View File

@ -12,7 +12,6 @@ import androidx.core.content.res.ResourcesCompat
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.CardHomeOptionBinding import org.yuzu.yuzu_emu.databinding.CardHomeOptionBinding
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
import org.yuzu.yuzu_emu.model.HomeSetting import org.yuzu.yuzu_emu.model.HomeSetting
class HomeSettingAdapter(private val activity: AppCompatActivity, var options: List<HomeSetting>) : class HomeSettingAdapter(private val activity: AppCompatActivity, var options: List<HomeSetting>) :
@ -35,14 +34,7 @@ class HomeSettingAdapter(private val activity: AppCompatActivity, var options: L
override fun onClick(view: View) { override fun onClick(view: View) {
val holder = view.tag as HomeOptionViewHolder val holder = view.tag as HomeOptionViewHolder
if (holder.option.isEnabled.invoke()) { holder.option.onClick.invoke()
holder.option.onClick.invoke()
} else {
MessageDialogFragment.newInstance(
holder.option.disabledTitleId,
holder.option.disabledMessageId
).show(activity.supportFragmentManager, MessageDialogFragment.TAG)
}
} }
inner class HomeOptionViewHolder(val binding: CardHomeOptionBinding) : inner class HomeOptionViewHolder(val binding: CardHomeOptionBinding) :
@ -73,12 +65,6 @@ class HomeSettingAdapter(private val activity: AppCompatActivity, var options: L
R.drawable.premium_background R.drawable.premium_background
) )
} }
if (!option.isEnabled.invoke()) {
binding.optionTitle.alpha = 0.5f
binding.optionDescription.alpha = 0.5f
binding.optionIcon.alpha = 0.5f
}
} }
} }
} }

View File

@ -73,113 +73,102 @@ class HomeSettingsFragment : Fragment() {
HomeSetting( HomeSetting(
R.string.advanced_settings, R.string.advanced_settings,
R.string.settings_description, R.string.settings_description,
R.drawable.ic_settings, R.drawable.ic_settings
{ SettingsActivity.launch(requireContext(), SettingsFile.FILE_NAME_CONFIG, "") } ) { SettingsActivity.launch(requireContext(), SettingsFile.FILE_NAME_CONFIG, "") }
)
) )
add( add(
HomeSetting( HomeSetting(
R.string.open_user_folder, R.string.open_user_folder,
R.string.open_user_folder_description, R.string.open_user_folder_description,
R.drawable.ic_folder_open, R.drawable.ic_folder_open
{ openFileManager() } ) { openFileManager() }
)
) )
add( add(
HomeSetting( HomeSetting(
R.string.preferences_theme, R.string.preferences_theme,
R.string.theme_and_color_description, R.string.theme_and_color_description,
R.drawable.ic_palette, R.drawable.ic_palette
{ SettingsActivity.launch(requireContext(), Settings.SECTION_THEME, "") } ) { SettingsActivity.launch(requireContext(), Settings.SECTION_THEME, "") }
)
) )
add(
HomeSetting( if (GpuDriverHelper.supportsCustomDriverLoading()) {
R.string.install_gpu_driver, add(
R.string.install_gpu_driver_description, HomeSetting(
R.drawable.ic_exit, R.string.install_gpu_driver,
{ driverInstaller() }, R.string.install_gpu_driver_description,
{ GpuDriverHelper.supportsCustomDriverLoading() }, R.drawable.ic_exit
R.string.custom_driver_not_supported, ) { driverInstaller() }
R.string.custom_driver_not_supported_description
) )
) }
add( add(
HomeSetting( HomeSetting(
R.string.install_amiibo_keys, R.string.install_amiibo_keys,
R.string.install_amiibo_keys_description, R.string.install_amiibo_keys_description,
R.drawable.ic_nfc, R.drawable.ic_nfc
{ mainActivity.getAmiiboKey.launch(arrayOf("*/*")) } ) { mainActivity.getAmiiboKey.launch(arrayOf("*/*")) }
)
) )
add( add(
HomeSetting( HomeSetting(
R.string.install_game_content, R.string.install_game_content,
R.string.install_game_content_description, R.string.install_game_content_description,
R.drawable.ic_system_update_alt, R.drawable.ic_system_update_alt
{ mainActivity.installGameUpdate.launch(arrayOf("*/*")) } ) { mainActivity.installGameUpdate.launch(arrayOf("*/*")) }
)
) )
add( add(
HomeSetting( HomeSetting(
R.string.select_games_folder, R.string.select_games_folder,
R.string.select_games_folder_description, R.string.select_games_folder_description,
R.drawable.ic_add, R.drawable.ic_add
{ ) {
mainActivity.getGamesDirectory.launch( mainActivity.getGamesDirectory.launch(
Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data
) )
} }
)
) )
add( add(
HomeSetting( HomeSetting(
R.string.manage_save_data, R.string.manage_save_data,
R.string.import_export_saves_description, R.string.import_export_saves_description,
R.drawable.ic_save, R.drawable.ic_save
{ ) {
ImportExportSavesFragment().show( ImportExportSavesFragment().show(
parentFragmentManager, parentFragmentManager,
ImportExportSavesFragment.TAG ImportExportSavesFragment.TAG
) )
} }
)
) )
add( add(
HomeSetting( HomeSetting(
R.string.install_prod_keys, R.string.install_prod_keys,
R.string.install_prod_keys_description, R.string.install_prod_keys_description,
R.drawable.ic_unlock, R.drawable.ic_unlock
{ mainActivity.getProdKey.launch(arrayOf("*/*")) } ) { mainActivity.getProdKey.launch(arrayOf("*/*")) }
)
) )
add( add(
HomeSetting( HomeSetting(
R.string.install_firmware, R.string.install_firmware,
R.string.install_firmware_description, R.string.install_firmware_description,
R.drawable.ic_firmware, R.drawable.ic_firmware
{ mainActivity.getFirmware.launch(arrayOf("application/zip")) } ) { mainActivity.getFirmware.launch(arrayOf("application/zip")) }
)
) )
add( add(
HomeSetting( HomeSetting(
R.string.share_log, R.string.share_log,
R.string.share_log_description, R.string.share_log_description,
R.drawable.ic_log, R.drawable.ic_log
{ shareLog() } ) { shareLog() }
)
) )
add( add(
HomeSetting( HomeSetting(
R.string.about, R.string.about,
R.string.about_description, R.string.about_description,
R.drawable.ic_info_outline, R.drawable.ic_info_outline
{ ) {
exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true) exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
parentFragmentManager.primaryNavigationFragment?.findNavController() parentFragmentManager.primaryNavigationFragment?.findNavController()
?.navigate(R.id.action_homeSettingsFragment_to_aboutFragment) ?.navigate(R.id.action_homeSettingsFragment_to_aboutFragment)
} }
)
) )
} }
@ -189,13 +178,12 @@ class HomeSettingsFragment : Fragment() {
HomeSetting( HomeSetting(
R.string.get_early_access, R.string.get_early_access,
R.string.get_early_access_description, R.string.get_early_access_description,
R.drawable.ic_diamond, R.drawable.ic_diamond
{ ) {
exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true) exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
parentFragmentManager.primaryNavigationFragment?.findNavController() parentFragmentManager.primaryNavigationFragment?.findNavController()
?.navigate(R.id.action_homeSettingsFragment_to_earlyAccessFragment) ?.navigate(R.id.action_homeSettingsFragment_to_earlyAccessFragment)
} }
)
) )
} }

View File

@ -7,8 +7,5 @@ data class HomeSetting(
val titleId: Int, val titleId: Int,
val descriptionId: Int, val descriptionId: Int,
val iconId: Int, val iconId: Int,
val onClick: () -> Unit, val onClick: () -> Unit
val isEnabled: () -> Boolean = { true },
val disabledTitleId: Int = 0,
val disabledMessageId: Int = 0
) )

View File

@ -113,8 +113,6 @@
<string name="install_game_content_success_install">%1$d installed successfully</string> <string name="install_game_content_success_install">%1$d installed successfully</string>
<string name="install_game_content_success_overwrite">%1$d overwritten successfully</string> <string name="install_game_content_success_overwrite">%1$d overwritten successfully</string>
<string name="install_game_content_help_link">https://yuzu-emu.org/help/quickstart/#dumping-installed-updates</string> <string name="install_game_content_help_link">https://yuzu-emu.org/help/quickstart/#dumping-installed-updates</string>
<string name="custom_driver_not_supported">Custom drivers not supported</string>
<string name="custom_driver_not_supported_description">Custom driver loading isn\'t currently supported for this device.\nCheck this option again in the future to see if support was added!</string>
<!-- About screen strings --> <!-- About screen strings -->
<string name="gaia_is_not_real">Gaia isn\'t real</string> <string name="gaia_is_not_real">Gaia isn\'t real</string>

View File

@ -92,9 +92,9 @@ void DeviceSession::AppendBuffers(std::span<const AudioBuffer> buffers) {
if (type == Sink::StreamType::In) { if (type == Sink::StreamType::In) {
stream->AppendBuffer(new_buffer, tmp_samples); stream->AppendBuffer(new_buffer, tmp_samples);
} else { } else {
Core::Memory::CpuGuestMemory<s16, Core::Memory::GuestMemoryFlags::UnsafeRead> samples( system.ApplicationMemory().ReadBlockUnsafe(buffer.samples, tmp_samples.data(),
system.ApplicationMemory(), buffer.samples, buffer.size / sizeof(s16)); buffer.size);
stream->AppendBuffer(new_buffer, samples); stream->AppendBuffer(new_buffer, tmp_samples);
} }
} }
} }

View File

@ -28,6 +28,7 @@ constexpr std::array<u8, 3> PitchBySrcQuality = {4, 8, 4};
template <typename T> template <typename T>
static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer, static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
const DecodeArg& req) { const DecodeArg& req) {
std::array<T, TempBufferSize> tmp_samples{};
constexpr s32 min{std::numeric_limits<s16>::min()}; constexpr s32 min{std::numeric_limits<s16>::min()};
constexpr s32 max{std::numeric_limits<s16>::max()}; constexpr s32 max{std::numeric_limits<s16>::max()};
@ -48,18 +49,19 @@ static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
const VAddr source{req.buffer + const VAddr source{req.buffer +
(((req.start_offset + req.offset) * channel_count) * sizeof(T))}; (((req.start_offset + req.offset) * channel_count) * sizeof(T))};
const u64 size{channel_count * samples_to_decode}; const u64 size{channel_count * samples_to_decode};
const u64 size_bytes{size * sizeof(T)};
memory.ReadBlockUnsafe(source, tmp_samples.data(), size_bytes);
Core::Memory::CpuGuestMemory<T, Core::Memory::GuestMemoryFlags::UnsafeRead> samples(
memory, source, size);
if constexpr (std::is_floating_point_v<T>) { if constexpr (std::is_floating_point_v<T>) {
for (u32 i = 0; i < samples_to_decode; i++) { for (u32 i = 0; i < samples_to_decode; i++) {
auto sample{static_cast<s32>(samples[i * channel_count + req.target_channel] * auto sample{static_cast<s32>(tmp_samples[i * channel_count + req.target_channel] *
std::numeric_limits<s16>::max())}; std::numeric_limits<s16>::max())};
out_buffer[i] = static_cast<s16>(std::clamp(sample, min, max)); out_buffer[i] = static_cast<s16>(std::clamp(sample, min, max));
} }
} else { } else {
for (u32 i = 0; i < samples_to_decode; i++) { for (u32 i = 0; i < samples_to_decode; i++) {
out_buffer[i] = samples[i * channel_count + req.target_channel]; out_buffer[i] = tmp_samples[i * channel_count + req.target_channel];
} }
} }
} break; } break;
@ -72,17 +74,16 @@ static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
} }
const VAddr source{req.buffer + ((req.start_offset + req.offset) * sizeof(T))}; const VAddr source{req.buffer + ((req.start_offset + req.offset) * sizeof(T))};
Core::Memory::CpuGuestMemory<T, Core::Memory::GuestMemoryFlags::UnsafeRead> samples( memory.ReadBlockUnsafe(source, tmp_samples.data(), samples_to_decode * sizeof(T));
memory, source, samples_to_decode);
if constexpr (std::is_floating_point_v<T>) { if constexpr (std::is_floating_point_v<T>) {
for (u32 i = 0; i < samples_to_decode; i++) { for (u32 i = 0; i < samples_to_decode; i++) {
auto sample{static_cast<s32>(samples[i * channel_count + req.target_channel] * auto sample{static_cast<s32>(tmp_samples[i * channel_count + req.target_channel] *
std::numeric_limits<s16>::max())}; std::numeric_limits<s16>::max())};
out_buffer[i] = static_cast<s16>(std::clamp(sample, min, max)); out_buffer[i] = static_cast<s16>(std::clamp(sample, min, max));
} }
} else { } else {
std::memcpy(out_buffer.data(), samples.data(), samples_to_decode * sizeof(s16)); std::memcpy(out_buffer.data(), tmp_samples.data(), samples_to_decode * sizeof(s16));
} }
break; break;
} }
@ -100,6 +101,7 @@ static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
*/ */
static u32 DecodeAdpcm(Core::Memory::Memory& memory, std::span<s16> out_buffer, static u32 DecodeAdpcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
const DecodeArg& req) { const DecodeArg& req) {
std::array<u8, TempBufferSize> wavebuffer{};
constexpr u32 SamplesPerFrame{14}; constexpr u32 SamplesPerFrame{14};
constexpr u32 NibblesPerFrame{16}; constexpr u32 NibblesPerFrame{16};
@ -137,8 +139,7 @@ static u32 DecodeAdpcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
} }
const auto size{std::max((samples_to_process / 8U) * SamplesPerFrame, 8U)}; const auto size{std::max((samples_to_process / 8U) * SamplesPerFrame, 8U)};
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::UnsafeRead> wavebuffer( memory.ReadBlockUnsafe(req.buffer + position_in_frame / 2, wavebuffer.data(), size);
memory, req.buffer + position_in_frame / 2, size);
auto context{req.adpcm_context}; auto context{req.adpcm_context};
auto header{context->header}; auto header{context->header};

View File

@ -21,13 +21,23 @@ static void ResetAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr aux_in
} }
AuxInfo::AuxInfoDsp info{}; AuxInfo::AuxInfoDsp info{};
memory.ReadBlockUnsafe(aux_info, &info, sizeof(AuxInfo::AuxInfoDsp)); auto info_ptr{&info};
bool host_safe{(aux_info & Core::Memory::YUZU_PAGEMASK) <=
(Core::Memory::YUZU_PAGESIZE - sizeof(AuxInfo::AuxInfoDsp))};
info.read_offset = 0; if (host_safe) [[likely]] {
info.write_offset = 0; info_ptr = memory.GetPointer<AuxInfo::AuxInfoDsp>(aux_info);
info.total_sample_count = 0; } else {
memory.ReadBlockUnsafe(aux_info, info_ptr, sizeof(AuxInfo::AuxInfoDsp));
}
memory.WriteBlockUnsafe(aux_info, &info, sizeof(AuxInfo::AuxInfoDsp)); info_ptr->read_offset = 0;
info_ptr->write_offset = 0;
info_ptr->total_sample_count = 0;
if (!host_safe) [[unlikely]] {
memory.WriteBlockUnsafe(aux_info, info_ptr, sizeof(AuxInfo::AuxInfoDsp));
}
} }
/** /**
@ -76,9 +86,17 @@ static u32 WriteAuxBufferDsp(Core::Memory::Memory& memory, CpuAddr send_info_,
} }
AuxInfo::AuxInfoDsp send_info{}; AuxInfo::AuxInfoDsp send_info{};
memory.ReadBlockUnsafe(send_info_, &send_info, sizeof(AuxInfo::AuxInfoDsp)); auto send_ptr = &send_info;
bool host_safe = (send_info_ & Core::Memory::YUZU_PAGEMASK) <=
(Core::Memory::YUZU_PAGESIZE - sizeof(AuxInfo::AuxInfoDsp));
u32 target_write_offset{send_info.write_offset + write_offset}; if (host_safe) [[likely]] {
send_ptr = memory.GetPointer<AuxInfo::AuxInfoDsp>(send_info_);
} else {
memory.ReadBlockUnsafe(send_info_, send_ptr, sizeof(AuxInfo::AuxInfoDsp));
}
u32 target_write_offset{send_ptr->write_offset + write_offset};
if (target_write_offset > count_max) { if (target_write_offset > count_max) {
return 0; return 0;
} }
@ -87,9 +105,15 @@ static u32 WriteAuxBufferDsp(Core::Memory::Memory& memory, CpuAddr send_info_,
u32 read_pos{0}; u32 read_pos{0};
while (write_count > 0) { while (write_count > 0) {
u32 to_write{std::min(count_max - target_write_offset, write_count)}; u32 to_write{std::min(count_max - target_write_offset, write_count)};
if (to_write > 0) { const auto write_addr = send_buffer + target_write_offset * sizeof(s32);
const auto write_addr = send_buffer + target_write_offset * sizeof(s32); bool write_safe{(write_addr & Core::Memory::YUZU_PAGEMASK) <=
memory.WriteBlockUnsafe(write_addr, &input[read_pos], to_write * sizeof(s32)); (Core::Memory::YUZU_PAGESIZE - (write_addr + to_write * sizeof(s32)))};
if (write_safe) [[likely]] {
auto ptr = memory.GetPointer(write_addr);
std::memcpy(ptr, &input[read_pos], to_write * sizeof(s32));
} else {
memory.WriteBlockUnsafe(send_buffer + target_write_offset * sizeof(s32),
&input[read_pos], to_write * sizeof(s32));
} }
target_write_offset = (target_write_offset + to_write) % count_max; target_write_offset = (target_write_offset + to_write) % count_max;
write_count -= to_write; write_count -= to_write;
@ -97,10 +121,13 @@ static u32 WriteAuxBufferDsp(Core::Memory::Memory& memory, CpuAddr send_info_,
} }
if (update_count) { if (update_count) {
send_info.write_offset = (send_info.write_offset + update_count) % count_max; send_ptr->write_offset = (send_ptr->write_offset + update_count) % count_max;
}
if (!host_safe) [[unlikely]] {
memory.WriteBlockUnsafe(send_info_, send_ptr, sizeof(AuxInfo::AuxInfoDsp));
} }
memory.WriteBlockUnsafe(send_info_, &send_info, sizeof(AuxInfo::AuxInfoDsp));
return write_count_; return write_count_;
} }
@ -147,9 +174,17 @@ static u32 ReadAuxBufferDsp(Core::Memory::Memory& memory, CpuAddr return_info_,
} }
AuxInfo::AuxInfoDsp return_info{}; AuxInfo::AuxInfoDsp return_info{};
memory.ReadBlockUnsafe(return_info_, &return_info, sizeof(AuxInfo::AuxInfoDsp)); auto return_ptr = &return_info;
bool host_safe = (return_info_ & Core::Memory::YUZU_PAGEMASK) <=
(Core::Memory::YUZU_PAGESIZE - sizeof(AuxInfo::AuxInfoDsp));
u32 target_read_offset{return_info.read_offset + read_offset}; if (host_safe) [[likely]] {
return_ptr = memory.GetPointer<AuxInfo::AuxInfoDsp>(return_info_);
} else {
memory.ReadBlockUnsafe(return_info_, return_ptr, sizeof(AuxInfo::AuxInfoDsp));
}
u32 target_read_offset{return_ptr->read_offset + read_offset};
if (target_read_offset > count_max) { if (target_read_offset > count_max) {
return 0; return 0;
} }
@ -158,9 +193,15 @@ static u32 ReadAuxBufferDsp(Core::Memory::Memory& memory, CpuAddr return_info_,
u32 write_pos{0}; u32 write_pos{0};
while (read_count > 0) { while (read_count > 0) {
u32 to_read{std::min(count_max - target_read_offset, read_count)}; u32 to_read{std::min(count_max - target_read_offset, read_count)};
if (to_read > 0) { const auto read_addr = return_buffer + target_read_offset * sizeof(s32);
const auto read_addr = return_buffer + target_read_offset * sizeof(s32); bool read_safe{(read_addr & Core::Memory::YUZU_PAGEMASK) <=
memory.ReadBlockUnsafe(read_addr, &output[write_pos], to_read * sizeof(s32)); (Core::Memory::YUZU_PAGESIZE - (read_addr + to_read * sizeof(s32)))};
if (read_safe) [[likely]] {
auto ptr = memory.GetPointer(read_addr);
std::memcpy(&output[write_pos], ptr, to_read * sizeof(s32));
} else {
memory.ReadBlockUnsafe(return_buffer + target_read_offset * sizeof(s32),
&output[write_pos], to_read * sizeof(s32));
} }
target_read_offset = (target_read_offset + to_read) % count_max; target_read_offset = (target_read_offset + to_read) % count_max;
read_count -= to_read; read_count -= to_read;
@ -168,10 +209,13 @@ static u32 ReadAuxBufferDsp(Core::Memory::Memory& memory, CpuAddr return_info_,
} }
if (update_count) { if (update_count) {
return_info.read_offset = (return_info.read_offset + update_count) % count_max; return_ptr->read_offset = (return_ptr->read_offset + update_count) % count_max;
}
if (!host_safe) [[unlikely]] {
memory.WriteBlockUnsafe(return_info_, return_ptr, sizeof(AuxInfo::AuxInfoDsp));
} }
memory.WriteBlockUnsafe(return_info_, &return_info, sizeof(AuxInfo::AuxInfoDsp));
return read_count_; return read_count_;
} }

View File

@ -66,7 +66,6 @@ void PageTable::Resize(std::size_t address_space_width_in_bits, std::size_t page
<< (address_space_width_in_bits - page_size_in_bits)}; << (address_space_width_in_bits - page_size_in_bits)};
pointers.resize(num_page_table_entries); pointers.resize(num_page_table_entries);
backing_addr.resize(num_page_table_entries); backing_addr.resize(num_page_table_entries);
blocks.resize(num_page_table_entries);
current_address_space_width_in_bits = address_space_width_in_bits; current_address_space_width_in_bits = address_space_width_in_bits;
page_size = 1ULL << page_size_in_bits; page_size = 1ULL << page_size_in_bits;
} }

View File

@ -122,7 +122,6 @@ struct PageTable {
* corresponding attribute element is of type `Memory`. * corresponding attribute element is of type `Memory`.
*/ */
VirtualBuffer<PageInfo> pointers; VirtualBuffer<PageInfo> pointers;
VirtualBuffer<u64> blocks;
VirtualBuffer<u64> backing_addr; VirtualBuffer<u64> backing_addr;

View File

@ -40,21 +40,8 @@ public:
~ScratchBuffer() = default; ~ScratchBuffer() = default;
ScratchBuffer(const ScratchBuffer&) = delete; ScratchBuffer(const ScratchBuffer&) = delete;
ScratchBuffer& operator=(const ScratchBuffer&) = delete; ScratchBuffer& operator=(const ScratchBuffer&) = delete;
ScratchBuffer(ScratchBuffer&&) = default;
ScratchBuffer(ScratchBuffer&& other) noexcept { ScratchBuffer& operator=(ScratchBuffer&&) = default;
swap(other);
other.last_requested_size = 0;
other.buffer_capacity = 0;
other.buffer.reset();
}
ScratchBuffer& operator=(ScratchBuffer&& other) noexcept {
swap(other);
other.last_requested_size = 0;
other.buffer_capacity = 0;
other.buffer.reset();
return *this;
}
/// This will only grow the buffer's capacity if size is greater than the current capacity. /// This will only grow the buffer's capacity if size is greater than the current capacity.
/// The previously held data will remain intact. /// The previously held data will remain intact.

View File

@ -27,8 +27,8 @@ std::string GetTimeZoneString() {
std::string location_name; std::string location_name;
if (time_zone_index == 0) { // Auto if (time_zone_index == 0) { // Auto
#if __cpp_lib_chrono >= 201907L #if __cpp_lib_chrono >= 201907L
const struct std::chrono::tzdb& time_zone_data = std::chrono::get_tzdb();
try { try {
const struct std::chrono::tzdb& time_zone_data = std::chrono::get_tzdb();
const std::chrono::time_zone* current_zone = time_zone_data.current_zone(); const std::chrono::time_zone* current_zone = time_zone_data.current_zone();
std::string_view current_zone_name = current_zone->name(); std::string_view current_zone_name = current_zone->name();
location_name = current_zone_name; location_name = current_zone_name;

View File

@ -285,7 +285,6 @@ add_library(core STATIC
hle/kernel/kernel.cpp hle/kernel/kernel.cpp
hle/kernel/kernel.h hle/kernel/kernel.h
hle/kernel/memory_types.h hle/kernel/memory_types.h
hle/kernel/message_buffer.h
hle/kernel/physical_core.cpp hle/kernel/physical_core.cpp
hle/kernel/physical_core.h hle/kernel/physical_core.h
hle/kernel/physical_memory.h hle/kernel/physical_memory.h

View File

@ -185,7 +185,7 @@ void ARM_Interface::Run() {
// Notify the debugger and go to sleep if a breakpoint was hit, // Notify the debugger and go to sleep if a breakpoint was hit,
// or if the thread is unable to continue for any reason. // or if the thread is unable to continue for any reason.
if (True(hr & HaltReason::InstructionBreakpoint) || True(hr & HaltReason::PrefetchAbort)) { if (True(hr & HaltReason::InstructionBreakpoint) || True(hr & HaltReason::PrefetchAbort)) {
if (!True(hr & HaltReason::PrefetchAbort)) { if (!True(hr & HaltReason::InstructionBreakpoint)) {
RewindBreakpointInstruction(); RewindBreakpointInstruction();
} }
if (system.DebuggerEnabled()) { if (system.DebuggerEnabled()) {

View File

@ -70,7 +70,7 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) {
-> std::optional<std::chrono::nanoseconds> { return std::nullopt; }; -> std::optional<std::chrono::nanoseconds> { return std::nullopt; };
ev_lost = CreateEvent("_lost_event", empty_timed_callback); ev_lost = CreateEvent("_lost_event", empty_timed_callback);
if (is_multicore) { if (is_multicore) {
timer_thread = std::make_unique<std::jthread>(ThreadEntry, std::ref(*this)); timer_thread = std::make_unique<std::thread>(ThreadEntry, std::ref(*this));
} }
} }
@ -255,6 +255,7 @@ void CoreTiming::ThreadLoop() {
#ifdef _WIN32 #ifdef _WIN32
while (!paused && !event.IsSet() && wait_time > 0) { while (!paused && !event.IsSet() && wait_time > 0) {
wait_time = *next_time - GetGlobalTimeNs().count(); wait_time = *next_time - GetGlobalTimeNs().count();
if (wait_time >= timer_resolution_ns) { if (wait_time >= timer_resolution_ns) {
Common::Windows::SleepForOneTick(); Common::Windows::SleepForOneTick();
} else { } else {

View File

@ -163,7 +163,7 @@ private:
Common::Event pause_event{}; Common::Event pause_event{};
std::mutex basic_lock; std::mutex basic_lock;
std::mutex advance_lock; std::mutex advance_lock;
std::unique_ptr<std::jthread> timer_thread; std::unique_ptr<std::thread> timer_thread;
std::atomic<bool> paused{}; std::atomic<bool> paused{};
std::atomic<bool> paused_set{}; std::atomic<bool> paused_set{};
std::atomic<bool> wait_set{}; std::atomic<bool> wait_set{};

View File

@ -20,132 +20,12 @@
#include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/k_thread_queue.h" #include "core/hle/kernel/k_thread_queue.h"
#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/message_buffer.h"
#include "core/hle/service/hle_ipc.h" #include "core/hle/service/hle_ipc.h"
#include "core/hle/service/ipc_helpers.h" #include "core/hle/service/ipc_helpers.h"
#include "core/memory.h" #include "core/memory.h"
namespace Kernel { namespace Kernel {
namespace {
template <bool MoveHandleAllowed>
Result ProcessMessageSpecialData(KProcess& dst_process, KProcess& src_process, KThread& src_thread,
MessageBuffer& dst_msg, const MessageBuffer& src_msg,
MessageBuffer::SpecialHeader& src_special_header) {
// Copy the special header to the destination.
s32 offset = dst_msg.Set(src_special_header);
// Copy the process ID.
if (src_special_header.GetHasProcessId()) {
offset = dst_msg.SetProcessId(offset, src_process.GetProcessId());
}
// Prepare to process handles.
auto& dst_handle_table = dst_process.GetHandleTable();
auto& src_handle_table = src_process.GetHandleTable();
Result result = ResultSuccess;
// Process copy handles.
for (auto i = 0; i < src_special_header.GetCopyHandleCount(); ++i) {
// Get the handles.
const Handle src_handle = src_msg.GetHandle(offset);
Handle dst_handle = Svc::InvalidHandle;
// If we're in a success state, try to move the handle to the new table.
if (R_SUCCEEDED(result) && src_handle != Svc::InvalidHandle) {
KScopedAutoObject obj =
src_handle_table.GetObjectForIpc(src_handle, std::addressof(src_thread));
if (obj.IsNotNull()) {
Result add_result =
dst_handle_table.Add(std::addressof(dst_handle), obj.GetPointerUnsafe());
if (R_FAILED(add_result)) {
result = add_result;
dst_handle = Svc::InvalidHandle;
}
} else {
result = ResultInvalidHandle;
}
}
// Set the handle.
offset = dst_msg.SetHandle(offset, dst_handle);
}
// Process move handles.
if constexpr (MoveHandleAllowed) {
for (auto i = 0; i < src_special_header.GetMoveHandleCount(); ++i) {
// Get the handles.
const Handle src_handle = src_msg.GetHandle(offset);
Handle dst_handle = Svc::InvalidHandle;
// Whether or not we've succeeded, we need to remove the handles from the source table.
if (src_handle != Svc::InvalidHandle) {
if (R_SUCCEEDED(result)) {
KScopedAutoObject obj =
src_handle_table.GetObjectForIpcWithoutPseudoHandle(src_handle);
if (obj.IsNotNull()) {
Result add_result = dst_handle_table.Add(std::addressof(dst_handle),
obj.GetPointerUnsafe());
src_handle_table.Remove(src_handle);
if (R_FAILED(add_result)) {
result = add_result;
dst_handle = Svc::InvalidHandle;
}
} else {
result = ResultInvalidHandle;
}
} else {
src_handle_table.Remove(src_handle);
}
}
// Set the handle.
offset = dst_msg.SetHandle(offset, dst_handle);
}
}
R_RETURN(result);
}
void CleanupSpecialData(KProcess& dst_process, u32* dst_msg_ptr, size_t dst_buffer_size) {
// Parse the message.
const MessageBuffer dst_msg(dst_msg_ptr, dst_buffer_size);
const MessageBuffer::MessageHeader dst_header(dst_msg);
const MessageBuffer::SpecialHeader dst_special_header(dst_msg, dst_header);
// Check that the size is big enough.
if (MessageBuffer::GetMessageBufferSize(dst_header, dst_special_header) > dst_buffer_size) {
return;
}
// Set the special header.
int offset = dst_msg.Set(dst_special_header);
// Clear the process id, if needed.
if (dst_special_header.GetHasProcessId()) {
offset = dst_msg.SetProcessId(offset, 0);
}
// Clear handles, as relevant.
auto& dst_handle_table = dst_process.GetHandleTable();
for (auto i = 0;
i < (dst_special_header.GetCopyHandleCount() + dst_special_header.GetMoveHandleCount());
++i) {
const Handle handle = dst_msg.GetHandle(offset);
if (handle != Svc::InvalidHandle) {
dst_handle_table.Remove(handle);
}
offset = dst_msg.SetHandle(offset, Svc::InvalidHandle);
}
}
} // namespace
using ThreadQueueImplForKServerSessionRequest = KThreadQueue; using ThreadQueueImplForKServerSessionRequest = KThreadQueue;
KServerSession::KServerSession(KernelCore& kernel) KServerSession::KServerSession(KernelCore& kernel)
@ -343,27 +223,12 @@ Result KServerSession::SendReply(bool is_hle) {
// the reply has already been written in this case. // the reply has already been written in this case.
} else { } else {
Core::Memory::Memory& memory{client_thread->GetOwnerProcess()->GetMemory()}; Core::Memory::Memory& memory{client_thread->GetOwnerProcess()->GetMemory()};
KThread* server_thread = GetCurrentThreadPointer(m_kernel); KThread* server_thread{GetCurrentThreadPointer(m_kernel)};
KProcess& src_process = *client_thread->GetOwnerProcess();
KProcess& dst_process = *server_thread->GetOwnerProcess();
UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess()); UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
auto* src_msg_buffer = memory.GetPointer<u32>(server_thread->GetTlsAddress()); auto* src_msg_buffer = memory.GetPointer(server_thread->GetTlsAddress());
auto* dst_msg_buffer = memory.GetPointer<u32>(client_message); auto* dst_msg_buffer = memory.GetPointer(client_message);
std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size); std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
// Translate special header ad-hoc.
MessageBuffer src_msg(src_msg_buffer, client_buffer_size);
MessageBuffer::MessageHeader src_header(src_msg);
MessageBuffer::SpecialHeader src_special_header(src_msg, src_header);
if (src_header.GetHasSpecialHeader()) {
MessageBuffer dst_msg(dst_msg_buffer, client_buffer_size);
result = ProcessMessageSpecialData<true>(dst_process, src_process, *server_thread,
dst_msg, src_msg, src_special_header);
if (R_FAILED(result)) {
CleanupSpecialData(dst_process, dst_msg_buffer, client_buffer_size);
}
}
} }
} else { } else {
result = ResultSessionClosed; result = ResultSessionClosed;
@ -465,28 +330,12 @@ Result KServerSession::ReceiveRequest(std::shared_ptr<Service::HLERequestContext
->PopulateFromIncomingCommandBuffer(client_thread->GetOwnerProcess()->GetHandleTable(), ->PopulateFromIncomingCommandBuffer(client_thread->GetOwnerProcess()->GetHandleTable(),
cmd_buf); cmd_buf);
} else { } else {
KThread* server_thread = GetCurrentThreadPointer(m_kernel); KThread* server_thread{GetCurrentThreadPointer(m_kernel)};
KProcess& src_process = *client_thread->GetOwnerProcess(); UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
KProcess& dst_process = *server_thread->GetOwnerProcess();
UNIMPLEMENTED_IF(client_thread->GetOwnerProcess() != server_thread->GetOwnerProcess());
auto* src_msg_buffer = memory.GetPointer<u32>(client_message); auto* src_msg_buffer = memory.GetPointer(client_message);
auto* dst_msg_buffer = memory.GetPointer<u32>(server_thread->GetTlsAddress()); auto* dst_msg_buffer = memory.GetPointer(server_thread->GetTlsAddress());
std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size); std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
// Translate special header ad-hoc.
// TODO: fix this mess
MessageBuffer src_msg(src_msg_buffer, client_buffer_size);
MessageBuffer::MessageHeader src_header(src_msg);
MessageBuffer::SpecialHeader src_special_header(src_msg, src_header);
if (src_header.GetHasSpecialHeader()) {
MessageBuffer dst_msg(dst_msg_buffer, client_buffer_size);
Result res = ProcessMessageSpecialData<false>(dst_process, src_process, *client_thread,
dst_msg, src_msg, src_special_header);
if (R_FAILED(res)) {
CleanupSpecialData(dst_process, dst_msg_buffer, client_buffer_size);
}
}
} }
// We succeeded. // We succeeded.

View File

@ -1,612 +0,0 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/alignment.h"
#include "common/bit_field.h"
#include "core/hle/kernel/k_thread.h"
namespace Kernel {
constexpr inline size_t MessageBufferSize = 0x100;
class MessageBuffer {
public:
class MessageHeader {
private:
static constexpr inline u64 NullTag = 0;
public:
enum class ReceiveListCountType : u32 {
None = 0,
ToMessageBuffer = 1,
ToSingleBuffer = 2,
CountOffset = 2,
CountMax = 13,
};
private:
union {
std::array<u32, 2> raw;
struct {
// Define fields for the first header word.
union {
BitField<0, 16, u16> tag;
BitField<16, 4, u32> pointer_count;
BitField<20, 4, u32> send_count;
BitField<24, 4, u32> receive_count;
BitField<28, 4, u32> exchange_count;
};
// Define fields for the second header word.
union {
BitField<0, 10, u32> raw_count;
BitField<10, 4, ReceiveListCountType> receive_list_count;
BitField<14, 6, u32> reserved0;
BitField<20, 11, u32> receive_list_offset;
BitField<31, 1, u32> has_special_header;
};
};
} m_header;
public:
constexpr MessageHeader() : m_header{} {}
constexpr MessageHeader(u16 tag, bool special, s32 ptr, s32 send, s32 recv, s32 exch,
s32 raw, ReceiveListCountType recv_list)
: m_header{} {
m_header.raw[0] = 0;
m_header.raw[1] = 0;
m_header.tag.Assign(tag);
m_header.pointer_count.Assign(ptr);
m_header.send_count.Assign(send);
m_header.receive_count.Assign(recv);
m_header.exchange_count.Assign(exch);
m_header.raw_count.Assign(raw);
m_header.receive_list_count.Assign(recv_list);
m_header.has_special_header.Assign(special);
}
explicit MessageHeader(const MessageBuffer& buf) : m_header{} {
buf.Get(0, m_header.raw.data(), 2);
}
explicit MessageHeader(const u32* msg) : m_header{{msg[0], msg[1]}} {}
constexpr u16 GetTag() const {
return m_header.tag;
}
constexpr s32 GetPointerCount() const {
return m_header.pointer_count;
}
constexpr s32 GetSendCount() const {
return m_header.send_count;
}
constexpr s32 GetReceiveCount() const {
return m_header.receive_count;
}
constexpr s32 GetExchangeCount() const {
return m_header.exchange_count;
}
constexpr s32 GetMapAliasCount() const {
return this->GetSendCount() + this->GetReceiveCount() + this->GetExchangeCount();
}
constexpr s32 GetRawCount() const {
return m_header.raw_count;
}
constexpr ReceiveListCountType GetReceiveListCount() const {
return m_header.receive_list_count;
}
constexpr s32 GetReceiveListOffset() const {
return m_header.receive_list_offset;
}
constexpr bool GetHasSpecialHeader() const {
return m_header.has_special_header.Value() != 0;
}
constexpr void SetReceiveListCount(ReceiveListCountType recv_list) {
m_header.receive_list_count.Assign(recv_list);
}
constexpr const u32* GetData() const {
return m_header.raw.data();
}
static constexpr size_t GetDataSize() {
return sizeof(m_header);
}
};
class SpecialHeader {
private:
union {
std::array<u32, 1> raw;
// Define fields for the header word.
BitField<0, 1, u32> has_process_id;
BitField<1, 4, u32> copy_handle_count;
BitField<5, 4, u32> move_handle_count;
} m_header;
bool m_has_header;
public:
constexpr explicit SpecialHeader(bool pid, s32 copy, s32 move)
: m_header{}, m_has_header(true) {
m_header.has_process_id.Assign(pid);
m_header.copy_handle_count.Assign(copy);
m_header.move_handle_count.Assign(move);
}
constexpr explicit SpecialHeader(bool pid, s32 copy, s32 move, bool _has_header)
: m_header{}, m_has_header(_has_header) {
m_header.has_process_id.Assign(pid);
m_header.copy_handle_count.Assign(copy);
m_header.move_handle_count.Assign(move);
}
explicit SpecialHeader(const MessageBuffer& buf, const MessageHeader& hdr)
: m_header{}, m_has_header(hdr.GetHasSpecialHeader()) {
if (m_has_header) {
buf.Get(static_cast<s32>(MessageHeader::GetDataSize() / sizeof(u32)),
m_header.raw.data(), sizeof(m_header) / sizeof(u32));
}
}
constexpr bool GetHasProcessId() const {
return m_header.has_process_id.Value() != 0;
}
constexpr s32 GetCopyHandleCount() const {
return m_header.copy_handle_count;
}
constexpr s32 GetMoveHandleCount() const {
return m_header.move_handle_count;
}
constexpr const u32* GetHeader() const {
return m_header.raw.data();
}
constexpr size_t GetHeaderSize() const {
if (m_has_header) {
return sizeof(m_header);
} else {
return 0;
}
}
constexpr size_t GetDataSize() const {
if (m_has_header) {
return (this->GetHasProcessId() ? sizeof(u64) : 0) +
(this->GetCopyHandleCount() * sizeof(Handle)) +
(this->GetMoveHandleCount() * sizeof(Handle));
} else {
return 0;
}
}
};
class MapAliasDescriptor {
public:
enum class Attribute : u32 {
Ipc = 0,
NonSecureIpc = 1,
NonDeviceIpc = 3,
};
private:
static constexpr u32 SizeLowCount = 32;
static constexpr u32 SizeHighCount = 4;
static constexpr u32 AddressLowCount = 32;
static constexpr u32 AddressMidCount = 4;
constexpr u32 GetAddressMid(u64 address) {
return static_cast<u32>(address >> AddressLowCount) & ((1U << AddressMidCount) - 1);
}
constexpr u32 GetAddressHigh(u64 address) {
return static_cast<u32>(address >> (AddressLowCount + AddressMidCount));
}
private:
union {
std::array<u32, 3> raw;
struct {
// Define fields for the first two words.
u32 size_low;
u32 address_low;
// Define fields for the packed descriptor word.
union {
BitField<0, 2, Attribute> attributes;
BitField<2, 3, u32> address_high;
BitField<5, 19, u32> reserved;
BitField<24, 4, u32> size_high;
BitField<28, 4, u32> address_mid;
};
};
} m_data;
public:
constexpr MapAliasDescriptor() : m_data{} {}
MapAliasDescriptor(const void* buffer, size_t _size, Attribute attr = Attribute::Ipc)
: m_data{} {
const u64 address = reinterpret_cast<u64>(buffer);
const u64 size = static_cast<u64>(_size);
m_data.size_low = static_cast<u32>(size);
m_data.address_low = static_cast<u32>(address);
m_data.attributes.Assign(attr);
m_data.address_mid.Assign(GetAddressMid(address));
m_data.size_high.Assign(static_cast<u32>(size >> SizeLowCount));
m_data.address_high.Assign(GetAddressHigh(address));
}
MapAliasDescriptor(const MessageBuffer& buf, s32 index) : m_data{} {
buf.Get(index, m_data.raw.data(), 3);
}
constexpr uintptr_t GetAddress() const {
return (static_cast<u64>((m_data.address_high << AddressMidCount) | m_data.address_mid)
<< AddressLowCount) |
m_data.address_low;
}
constexpr uintptr_t GetSize() const {
return (static_cast<u64>(m_data.size_high) << SizeLowCount) | m_data.size_low;
}
constexpr Attribute GetAttribute() const {
return m_data.attributes;
}
constexpr const u32* GetData() const {
return m_data.raw.data();
}
static constexpr size_t GetDataSize() {
return sizeof(m_data);
}
};
class PointerDescriptor {
private:
static constexpr u32 AddressLowCount = 32;
static constexpr u32 AddressMidCount = 4;
constexpr u32 GetAddressMid(u64 address) {
return static_cast<u32>(address >> AddressLowCount) & ((1u << AddressMidCount) - 1);
}
constexpr u32 GetAddressHigh(u64 address) {
return static_cast<u32>(address >> (AddressLowCount + AddressMidCount));
}
private:
union {
std::array<u32, 2> raw;
struct {
// Define fields for the packed descriptor word.
union {
BitField<0, 4, u32> index;
BitField<4, 2, u32> reserved0;
BitField<6, 3, u32> address_high;
BitField<9, 3, u32> reserved1;
BitField<12, 4, u32> address_mid;
BitField<16, 16, u32> size;
};
// Define fields for the second word.
u32 address_low;
};
} m_data;
public:
constexpr PointerDescriptor() : m_data{} {}
PointerDescriptor(const void* buffer, size_t size, s32 index) : m_data{} {
const u64 address = reinterpret_cast<u64>(buffer);
m_data.index.Assign(index);
m_data.address_high.Assign(GetAddressHigh(address));
m_data.address_mid.Assign(GetAddressMid(address));
m_data.size.Assign(static_cast<u32>(size));
m_data.address_low = static_cast<u32>(address);
}
PointerDescriptor(const MessageBuffer& buf, s32 index) : m_data{} {
buf.Get(index, m_data.raw.data(), 2);
}
constexpr s32 GetIndex() const {
return m_data.index;
}
constexpr uintptr_t GetAddress() const {
return (static_cast<u64>((m_data.address_high << AddressMidCount) | m_data.address_mid)
<< AddressLowCount) |
m_data.address_low;
}
constexpr size_t GetSize() const {
return m_data.size;
}
constexpr const u32* GetData() const {
return m_data.raw.data();
}
static constexpr size_t GetDataSize() {
return sizeof(m_data);
}
};
class ReceiveListEntry {
private:
static constexpr u32 AddressLowCount = 32;
constexpr u32 GetAddressHigh(u64 address) {
return static_cast<u32>(address >> (AddressLowCount));
}
private:
union {
std::array<u32, 2> raw;
struct {
// Define fields for the first word.
u32 address_low;
// Define fields for the packed descriptor word.
union {
BitField<0, 7, u32> address_high;
BitField<7, 9, u32> reserved;
BitField<16, 16, u32> size;
};
};
} m_data;
public:
constexpr ReceiveListEntry() : m_data{} {}
ReceiveListEntry(const void* buffer, size_t size) : m_data{} {
const u64 address = reinterpret_cast<u64>(buffer);
m_data.address_low = static_cast<u32>(address);
m_data.address_high.Assign(GetAddressHigh(address));
m_data.size.Assign(static_cast<u32>(size));
}
ReceiveListEntry(u32 a, u32 b) : m_data{{a, b}} {}
constexpr uintptr_t GetAddress() const {
return (static_cast<u64>(m_data.address_high) << AddressLowCount) | m_data.address_low;
}
constexpr size_t GetSize() const {
return m_data.size;
}
constexpr const u32* GetData() const {
return m_data.raw.data();
}
static constexpr size_t GetDataSize() {
return sizeof(m_data);
}
};
private:
u32* m_buffer;
size_t m_size;
public:
constexpr MessageBuffer(u32* b, size_t sz) : m_buffer(b), m_size(sz) {}
constexpr explicit MessageBuffer(u32* b) : m_buffer(b), m_size(MessageBufferSize) {}
constexpr void* GetBufferForDebug() const {
return m_buffer;
}
constexpr size_t GetBufferSize() const {
return m_size;
}
void Get(s32 index, u32* dst, size_t count) const {
// Ensure that this doesn't get re-ordered.
std::atomic_thread_fence(std::memory_order_seq_cst);
// Get the words.
static_assert(sizeof(*dst) == sizeof(*m_buffer));
memcpy(dst, m_buffer + index, count * sizeof(*dst));
}
s32 Set(s32 index, u32* src, size_t count) const {
// Ensure that this doesn't get re-ordered.
std::atomic_thread_fence(std::memory_order_seq_cst);
// Set the words.
memcpy(m_buffer + index, src, count * sizeof(*src));
// Ensure that this doesn't get re-ordered.
std::atomic_thread_fence(std::memory_order_seq_cst);
return static_cast<s32>(index + count);
}
template <typename T>
const T& GetRaw(s32 index) const {
return *reinterpret_cast<const T*>(m_buffer + index);
}
template <typename T>
s32 SetRaw(s32 index, const T& val) const {
*reinterpret_cast<const T*>(m_buffer + index) = val;
return index + (Common::AlignUp(sizeof(val), sizeof(*m_buffer)) / sizeof(*m_buffer));
}
void GetRawArray(s32 index, void* dst, size_t len) const {
memcpy(dst, m_buffer + index, len);
}
void SetRawArray(s32 index, const void* src, size_t len) const {
memcpy(m_buffer + index, src, len);
}
void SetNull() const {
this->Set(MessageHeader());
}
s32 Set(const MessageHeader& hdr) const {
memcpy(m_buffer, hdr.GetData(), hdr.GetDataSize());
return static_cast<s32>(hdr.GetDataSize() / sizeof(*m_buffer));
}
s32 Set(const SpecialHeader& spc) const {
const s32 index = static_cast<s32>(MessageHeader::GetDataSize() / sizeof(*m_buffer));
memcpy(m_buffer + index, spc.GetHeader(), spc.GetHeaderSize());
return static_cast<s32>(index + (spc.GetHeaderSize() / sizeof(*m_buffer)));
}
s32 SetHandle(s32 index, const Handle& hnd) const {
memcpy(m_buffer + index, std::addressof(hnd), sizeof(hnd));
return static_cast<s32>(index + (sizeof(hnd) / sizeof(*m_buffer)));
}
s32 SetProcessId(s32 index, const u64 pid) const {
memcpy(m_buffer + index, std::addressof(pid), sizeof(pid));
return static_cast<s32>(index + (sizeof(pid) / sizeof(*m_buffer)));
}
s32 Set(s32 index, const MapAliasDescriptor& desc) const {
memcpy(m_buffer + index, desc.GetData(), desc.GetDataSize());
return static_cast<s32>(index + (desc.GetDataSize() / sizeof(*m_buffer)));
}
s32 Set(s32 index, const PointerDescriptor& desc) const {
memcpy(m_buffer + index, desc.GetData(), desc.GetDataSize());
return static_cast<s32>(index + (desc.GetDataSize() / sizeof(*m_buffer)));
}
s32 Set(s32 index, const ReceiveListEntry& desc) const {
memcpy(m_buffer + index, desc.GetData(), desc.GetDataSize());
return static_cast<s32>(index + (desc.GetDataSize() / sizeof(*m_buffer)));
}
s32 Set(s32 index, const u32 val) const {
memcpy(m_buffer + index, std::addressof(val), sizeof(val));
return static_cast<s32>(index + (sizeof(val) / sizeof(*m_buffer)));
}
Result GetAsyncResult() const {
MessageHeader hdr(m_buffer);
MessageHeader null{};
if (memcmp(hdr.GetData(), null.GetData(), MessageHeader::GetDataSize()) != 0) [[unlikely]] {
R_SUCCEED();
}
return Result(m_buffer[MessageHeader::GetDataSize() / sizeof(*m_buffer)]);
}
void SetAsyncResult(Result res) const {
const s32 index = this->Set(MessageHeader());
const auto value = res.raw;
memcpy(m_buffer + index, std::addressof(value), sizeof(value));
}
u32 Get32(s32 index) const {
return m_buffer[index];
}
u64 Get64(s32 index) const {
u64 value;
memcpy(std::addressof(value), m_buffer + index, sizeof(value));
return value;
}
u64 GetProcessId(s32 index) const {
return this->Get64(index);
}
Handle GetHandle(s32 index) const {
static_assert(sizeof(Handle) == sizeof(*m_buffer));
return Handle(m_buffer[index]);
}
static constexpr s32 GetSpecialDataIndex(const MessageHeader& hdr, const SpecialHeader& spc) {
return static_cast<s32>((MessageHeader::GetDataSize() / sizeof(u32)) +
(spc.GetHeaderSize() / sizeof(u32)));
}
static constexpr s32 GetPointerDescriptorIndex(const MessageHeader& hdr,
const SpecialHeader& spc) {
return static_cast<s32>(GetSpecialDataIndex(hdr, spc) + (spc.GetDataSize() / sizeof(u32)));
}
static constexpr s32 GetMapAliasDescriptorIndex(const MessageHeader& hdr,
const SpecialHeader& spc) {
return GetPointerDescriptorIndex(hdr, spc) +
static_cast<s32>(hdr.GetPointerCount() * PointerDescriptor::GetDataSize() /
sizeof(u32));
}
static constexpr s32 GetRawDataIndex(const MessageHeader& hdr, const SpecialHeader& spc) {
return GetMapAliasDescriptorIndex(hdr, spc) +
static_cast<s32>(hdr.GetMapAliasCount() * MapAliasDescriptor::GetDataSize() /
sizeof(u32));
}
static constexpr s32 GetReceiveListIndex(const MessageHeader& hdr, const SpecialHeader& spc) {
if (const s32 recv_list_index = hdr.GetReceiveListOffset()) {
return recv_list_index;
} else {
return GetRawDataIndex(hdr, spc) + hdr.GetRawCount();
}
}
static constexpr size_t GetMessageBufferSize(const MessageHeader& hdr,
const SpecialHeader& spc) {
// Get the size of the plain message.
size_t msg_size = GetReceiveListIndex(hdr, spc) * sizeof(u32);
// Add the size of the receive list.
const auto count = hdr.GetReceiveListCount();
switch (count) {
case MessageHeader::ReceiveListCountType::None:
break;
case MessageHeader::ReceiveListCountType::ToMessageBuffer:
break;
case MessageHeader::ReceiveListCountType::ToSingleBuffer:
msg_size += ReceiveListEntry::GetDataSize();
break;
default:
msg_size += (static_cast<s32>(count) -
static_cast<s32>(MessageHeader::ReceiveListCountType::CountOffset)) *
ReceiveListEntry::GetDataSize();
break;
}
return msg_size;
}
};
} // namespace Kernel

View File

@ -329,22 +329,8 @@ std::vector<u8> HLERequestContext::ReadBufferCopy(std::size_t buffer_index) cons
} }
std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const { std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const {
static thread_local std::array read_buffer_a{ static thread_local std::array<Common::ScratchBuffer<u8>, 2> read_buffer_a;
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), static thread_local std::array<Common::ScratchBuffer<u8>, 2> read_buffer_x;
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
};
static thread_local std::array read_buffer_data_a{
Common::ScratchBuffer<u8>(),
Common::ScratchBuffer<u8>(),
};
static thread_local std::array read_buffer_x{
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
};
static thread_local std::array read_buffer_data_x{
Common::ScratchBuffer<u8>(),
Common::ScratchBuffer<u8>(),
};
const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && const bool is_buffer_a{BufferDescriptorA().size() > buffer_index &&
BufferDescriptorA()[buffer_index].Size()}; BufferDescriptorA()[buffer_index].Size()};
@ -353,17 +339,19 @@ std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) cons
BufferDescriptorA().size() > buffer_index, { return {}; }, BufferDescriptorA().size() > buffer_index, { return {}; },
"BufferDescriptorA invalid buffer_index {}", buffer_index); "BufferDescriptorA invalid buffer_index {}", buffer_index);
auto& read_buffer = read_buffer_a[buffer_index]; auto& read_buffer = read_buffer_a[buffer_index];
return read_buffer.Read(BufferDescriptorA()[buffer_index].Address(), read_buffer.resize_destructive(BufferDescriptorA()[buffer_index].Size());
BufferDescriptorA()[buffer_index].Size(), memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), read_buffer.data(),
&read_buffer_data_a[buffer_index]); read_buffer.size());
return read_buffer;
} else { } else {
ASSERT_OR_EXECUTE_MSG( ASSERT_OR_EXECUTE_MSG(
BufferDescriptorX().size() > buffer_index, { return {}; }, BufferDescriptorX().size() > buffer_index, { return {}; },
"BufferDescriptorX invalid buffer_index {}", buffer_index); "BufferDescriptorX invalid buffer_index {}", buffer_index);
auto& read_buffer = read_buffer_x[buffer_index]; auto& read_buffer = read_buffer_x[buffer_index];
return read_buffer.Read(BufferDescriptorX()[buffer_index].Address(), read_buffer.resize_destructive(BufferDescriptorX()[buffer_index].Size());
BufferDescriptorX()[buffer_index].Size(), memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), read_buffer.data(),
&read_buffer_data_x[buffer_index]); read_buffer.size());
return read_buffer;
} }
} }

View File

@ -266,22 +266,6 @@ struct Memory::Impl {
ReadBlockImpl<true>(*system.ApplicationProcess(), src_addr, dest_buffer, size); ReadBlockImpl<true>(*system.ApplicationProcess(), src_addr, dest_buffer, size);
} }
const u8* GetSpan(const VAddr src_addr, const std::size_t size) const {
if (current_page_table->blocks[src_addr >> YUZU_PAGEBITS] ==
current_page_table->blocks[(src_addr + size) >> YUZU_PAGEBITS]) {
return GetPointerSilent(src_addr);
}
return nullptr;
}
u8* GetSpan(const VAddr src_addr, const std::size_t size) {
if (current_page_table->blocks[src_addr >> YUZU_PAGEBITS] ==
current_page_table->blocks[(src_addr + size) >> YUZU_PAGEBITS]) {
return GetPointerSilent(src_addr);
}
return nullptr;
}
template <bool UNSAFE> template <bool UNSAFE>
void WriteBlockImpl(const Kernel::KProcess& process, const Common::ProcessAddress dest_addr, void WriteBlockImpl(const Kernel::KProcess& process, const Common::ProcessAddress dest_addr,
const void* src_buffer, const std::size_t size) { const void* src_buffer, const std::size_t size) {
@ -575,7 +559,7 @@ struct Memory::Impl {
} }
} }
const auto end = base + size; const Common::ProcessAddress end = base + size;
ASSERT_MSG(end <= page_table.pointers.size(), "out of range mapping at {:016X}", ASSERT_MSG(end <= page_table.pointers.size(), "out of range mapping at {:016X}",
base + page_table.pointers.size()); base + page_table.pointers.size());
@ -586,18 +570,14 @@ struct Memory::Impl {
while (base != end) { while (base != end) {
page_table.pointers[base].Store(nullptr, type); page_table.pointers[base].Store(nullptr, type);
page_table.backing_addr[base] = 0; page_table.backing_addr[base] = 0;
page_table.blocks[base] = 0;
base += 1; base += 1;
} }
} else { } else {
auto orig_base = base;
while (base != end) { while (base != end) {
auto host_ptr = page_table.pointers[base].Store(
system.DeviceMemory().GetPointer<u8>(target) - (base << YUZU_PAGEBITS); system.DeviceMemory().GetPointer<u8>(target) - (base << YUZU_PAGEBITS), type);
auto backing = GetInteger(target) - (base << YUZU_PAGEBITS); page_table.backing_addr[base] = GetInteger(target) - (base << YUZU_PAGEBITS);
page_table.pointers[base].Store(host_ptr, type);
page_table.backing_addr[base] = backing;
page_table.blocks[base] = orig_base << YUZU_PAGEBITS;
ASSERT_MSG(page_table.pointers[base].Pointer(), ASSERT_MSG(page_table.pointers[base].Pointer(),
"memory mapping base yield a nullptr within the table"); "memory mapping base yield a nullptr within the table");
@ -767,14 +747,6 @@ struct Memory::Impl {
VAddr last_address; VAddr last_address;
}; };
void InvalidateRegion(Common::ProcessAddress dest_addr, size_t size) {
system.GPU().InvalidateRegion(GetInteger(dest_addr), size);
}
void FlushRegion(Common::ProcessAddress dest_addr, size_t size) {
system.GPU().FlushRegion(GetInteger(dest_addr), size);
}
Core::System& system; Core::System& system;
Common::PageTable* current_page_table = nullptr; Common::PageTable* current_page_table = nullptr;
std::array<VideoCore::RasterizerDownloadArea, Core::Hardware::NUM_CPU_CORES> std::array<VideoCore::RasterizerDownloadArea, Core::Hardware::NUM_CPU_CORES>
@ -909,14 +881,6 @@ void Memory::ReadBlockUnsafe(const Common::ProcessAddress src_addr, void* dest_b
impl->ReadBlockUnsafe(src_addr, dest_buffer, size); impl->ReadBlockUnsafe(src_addr, dest_buffer, size);
} }
const u8* Memory::GetSpan(const VAddr src_addr, const std::size_t size) const {
return impl->GetSpan(src_addr, size);
}
u8* Memory::GetSpan(const VAddr src_addr, const std::size_t size) {
return impl->GetSpan(src_addr, size);
}
void Memory::WriteBlock(const Common::ProcessAddress dest_addr, const void* src_buffer, void Memory::WriteBlock(const Common::ProcessAddress dest_addr, const void* src_buffer,
const std::size_t size) { const std::size_t size) {
impl->WriteBlock(dest_addr, src_buffer, size); impl->WriteBlock(dest_addr, src_buffer, size);
@ -960,12 +924,4 @@ void Memory::MarkRegionDebug(Common::ProcessAddress vaddr, u64 size, bool debug)
impl->MarkRegionDebug(GetInteger(vaddr), size, debug); impl->MarkRegionDebug(GetInteger(vaddr), size, debug);
} }
void Memory::InvalidateRegion(Common::ProcessAddress dest_addr, size_t size) {
impl->InvalidateRegion(dest_addr, size);
}
void Memory::FlushRegion(Common::ProcessAddress dest_addr, size_t size) {
impl->FlushRegion(dest_addr, size);
}
} // namespace Core::Memory } // namespace Core::Memory

View File

@ -5,12 +5,8 @@
#include <cstddef> #include <cstddef>
#include <memory> #include <memory>
#include <optional>
#include <span> #include <span>
#include <string> #include <string>
#include <vector>
#include "common/scratch_buffer.h"
#include "common/typed_address.h" #include "common/typed_address.h"
#include "core/hle/result.h" #include "core/hle/result.h"
@ -28,10 +24,6 @@ class PhysicalMemory;
class KProcess; class KProcess;
} // namespace Kernel } // namespace Kernel
namespace Tegra {
class MemoryManager;
}
namespace Core::Memory { namespace Core::Memory {
/** /**
@ -351,9 +343,6 @@ public:
*/ */
void ReadBlockUnsafe(Common::ProcessAddress src_addr, void* dest_buffer, std::size_t size); void ReadBlockUnsafe(Common::ProcessAddress src_addr, void* dest_buffer, std::size_t size);
const u8* GetSpan(const VAddr src_addr, const std::size_t size) const;
u8* GetSpan(const VAddr src_addr, const std::size_t size);
/** /**
* Writes a range of bytes into the current process' address space at the specified * Writes a range of bytes into the current process' address space at the specified
* virtual address. * virtual address.
@ -472,8 +461,6 @@ public:
void MarkRegionDebug(Common::ProcessAddress vaddr, u64 size, bool debug); void MarkRegionDebug(Common::ProcessAddress vaddr, u64 size, bool debug);
void SetGPUDirtyManagers(std::span<Core::GPUDirtyMemoryManager> managers); void SetGPUDirtyManagers(std::span<Core::GPUDirtyMemoryManager> managers);
void InvalidateRegion(Common::ProcessAddress dest_addr, size_t size);
void FlushRegion(Common::ProcessAddress dest_addr, size_t size);
private: private:
Core::System& system; Core::System& system;
@ -482,203 +469,4 @@ private:
std::unique_ptr<Impl> impl; std::unique_ptr<Impl> impl;
}; };
enum GuestMemoryFlags : u32 {
Read = 1 << 0,
Write = 1 << 1,
Safe = 1 << 2,
Cached = 1 << 3,
SafeRead = Read | Safe,
SafeWrite = Write | Safe,
SafeReadWrite = SafeRead | SafeWrite,
SafeReadCachedWrite = SafeReadWrite | Cached,
UnsafeRead = Read,
UnsafeWrite = Write,
UnsafeReadWrite = UnsafeRead | UnsafeWrite,
UnsafeReadCachedWrite = UnsafeReadWrite | Cached,
};
namespace {
template <typename M, typename T, GuestMemoryFlags FLAGS>
class GuestMemory {
using iterator = T*;
using const_iterator = const T*;
using value_type = T;
using element_type = T;
using iterator_category = std::contiguous_iterator_tag;
public:
GuestMemory() = delete;
explicit GuestMemory(M& memory_, u64 addr_, std::size_t size_,
Common::ScratchBuffer<T>* backup = nullptr)
: memory{memory_}, addr{addr_}, size{size_} {
static_assert(FLAGS & GuestMemoryFlags::Read || FLAGS & GuestMemoryFlags::Write);
if constexpr (FLAGS & GuestMemoryFlags::Read) {
Read(addr, size, backup);
}
}
~GuestMemory() = default;
T* data() noexcept {
return data_span.data();
}
const T* data() const noexcept {
return data_span.data();
}
[[nodiscard]] T* begin() noexcept {
return data();
}
[[nodiscard]] const T* begin() const noexcept {
return data();
}
[[nodiscard]] T* end() noexcept {
return data() + size;
}
[[nodiscard]] const T* end() const noexcept {
return data() + size;
}
T& operator[](size_t index) noexcept {
return data_span[index];
}
const T& operator[](size_t index) const noexcept {
return data_span[index];
}
void SetAddressAndSize(u64 addr_, std::size_t size_) noexcept {
addr = addr_;
size = size_;
addr_changed = true;
}
std::span<T> Read(u64 addr_, std::size_t size_,
Common::ScratchBuffer<T>* backup = nullptr) noexcept {
addr = addr_;
size = size_;
if (size == 0) {
is_data_copy = true;
return {};
}
if (TrySetSpan()) {
if constexpr (FLAGS & GuestMemoryFlags::Safe) {
memory.FlushRegion(addr, size * sizeof(T));
}
} else {
if (backup) {
backup->resize_destructive(size);
data_span = *backup;
} else {
data_copy.resize(size);
data_span = std::span(data_copy);
}
is_data_copy = true;
span_valid = true;
if constexpr (FLAGS & GuestMemoryFlags::Safe) {
memory.ReadBlock(addr, data_span.data(), size * sizeof(T));
} else {
memory.ReadBlockUnsafe(addr, data_span.data(), size * sizeof(T));
}
}
return data_span;
}
void Write(std::span<T> write_data) noexcept {
if constexpr (FLAGS & GuestMemoryFlags::Cached) {
memory.WriteBlockCached(addr, write_data.data(), size * sizeof(T));
} else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
memory.WriteBlock(addr, write_data.data(), size * sizeof(T));
} else {
memory.WriteBlockUnsafe(addr, write_data.data(), size * sizeof(T));
}
}
bool TrySetSpan() noexcept {
if (u8* ptr = memory.GetSpan(addr, size * sizeof(T)); ptr) {
data_span = {reinterpret_cast<T*>(ptr), size};
span_valid = true;
return true;
}
return false;
}
protected:
bool IsDataCopy() const noexcept {
return is_data_copy;
}
bool AddressChanged() const noexcept {
return addr_changed;
}
M& memory;
u64 addr;
size_t size;
std::span<T> data_span{};
std::vector<T> data_copy;
bool span_valid{false};
bool is_data_copy{false};
bool addr_changed{false};
};
template <typename M, typename T, GuestMemoryFlags FLAGS>
class GuestMemoryScoped : public GuestMemory<M, T, FLAGS> {
public:
GuestMemoryScoped() = delete;
explicit GuestMemoryScoped(M& memory_, u64 addr_, std::size_t size_,
Common::ScratchBuffer<T>* backup = nullptr)
: GuestMemory<M, T, FLAGS>(memory_, addr_, size_, backup) {
if constexpr (!(FLAGS & GuestMemoryFlags::Read)) {
if (!this->TrySetSpan()) {
if (backup) {
this->data_span = *backup;
this->span_valid = true;
this->is_data_copy = true;
}
}
}
}
~GuestMemoryScoped() {
if constexpr (FLAGS & GuestMemoryFlags::Write) {
if (this->size == 0) [[unlikely]] {
return;
}
if (this->AddressChanged() || this->IsDataCopy()) {
ASSERT(this->span_valid);
if constexpr (FLAGS & GuestMemoryFlags::Cached) {
this->memory.WriteBlockCached(this->addr, this->data_span.data(),
this->size * sizeof(T));
} else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
this->memory.WriteBlock(this->addr, this->data_span.data(),
this->size * sizeof(T));
} else {
this->memory.WriteBlockUnsafe(this->addr, this->data_span.data(),
this->size * sizeof(T));
}
} else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
this->memory.InvalidateRegion(this->addr, this->size * sizeof(T));
}
}
}
};
} // namespace
template <typename T, GuestMemoryFlags FLAGS>
using CpuGuestMemory = GuestMemory<Memory, T, FLAGS>;
template <typename T, GuestMemoryFlags FLAGS>
using CpuGuestMemoryScoped = GuestMemoryScoped<Memory, T, FLAGS>;
template <typename T, GuestMemoryFlags FLAGS>
using GpuGuestMemory = GuestMemory<Tegra::MemoryManager, T, FLAGS>;
template <typename T, GuestMemoryFlags FLAGS>
using GpuGuestMemoryScoped = GuestMemoryScoped<Tegra::MemoryManager, T, FLAGS>;
} // namespace Core::Memory } // namespace Core::Memory

View File

@ -523,8 +523,6 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en
} }
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED, "1");
// Share the same button mapping with non-Nintendo controllers
SDL_SetHint(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS, "0");
// Disable hidapi driver for xbox. Already default on Windows, this causes conflict with native // Disable hidapi driver for xbox. Already default on Windows, this causes conflict with native
// driver on Linux. // driver on Linux.
@ -802,9 +800,16 @@ ButtonMapping SDLDriver::GetButtonMappingForDevice(const Common::ParamPackage& p
// This list is missing ZL/ZR since those are not considered buttons in SDL GameController. // This list is missing ZL/ZR since those are not considered buttons in SDL GameController.
// We will add those afterwards // We will add those afterwards
// This list also excludes Screenshot since there's not really a mapping for that
ButtonBindings switch_to_sdl_button; ButtonBindings switch_to_sdl_button;
switch_to_sdl_button = GetDefaultButtonBinding(joystick); if (SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO ||
SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT ||
SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT) {
switch_to_sdl_button = GetNintendoButtonBinding(joystick);
} else {
switch_to_sdl_button = GetDefaultButtonBinding();
}
// Add the missing bindings for ZL/ZR // Add the missing bindings for ZL/ZR
static constexpr ZButtonBindings switch_to_sdl_axis{{ static constexpr ZButtonBindings switch_to_sdl_axis{{
@ -825,9 +830,32 @@ ButtonMapping SDLDriver::GetButtonMappingForDevice(const Common::ParamPackage& p
return GetSingleControllerMapping(joystick, switch_to_sdl_button, switch_to_sdl_axis); return GetSingleControllerMapping(joystick, switch_to_sdl_button, switch_to_sdl_axis);
} }
ButtonBindings SDLDriver::GetDefaultButtonBinding( ButtonBindings SDLDriver::GetDefaultButtonBinding() const {
return {
std::pair{Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B},
{Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A},
{Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y},
{Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X},
{Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK},
{Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
{Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
{Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
{Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START},
{Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK},
{Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT},
{Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP},
{Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
{Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN},
{Settings::NativeButton::SL, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
{Settings::NativeButton::SR, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
{Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE},
{Settings::NativeButton::Screenshot, SDL_CONTROLLER_BUTTON_MISC1},
};
}
ButtonBindings SDLDriver::GetNintendoButtonBinding(
const std::shared_ptr<SDLJoystick>& joystick) const { const std::shared_ptr<SDLJoystick>& joystick) const {
// Default SL/SR mapping for other controllers // Default SL/SR mapping for pro controllers
auto sl_button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER; auto sl_button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
auto sr_button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER; auto sr_button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
@ -841,10 +869,10 @@ ButtonBindings SDLDriver::GetDefaultButtonBinding(
} }
return { return {
std::pair{Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B}, std::pair{Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_A},
{Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A}, {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_B},
{Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y}, {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_X},
{Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X}, {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_Y},
{Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK}, {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK},
{Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK}, {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
{Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER}, {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},

View File

@ -100,8 +100,11 @@ private:
int axis_y, float offset_x, int axis_y, float offset_x,
float offset_y) const; float offset_y) const;
/// Returns the default button bindings list /// Returns the default button bindings list for generic controllers
ButtonBindings GetDefaultButtonBinding(const std::shared_ptr<SDLJoystick>& joystick) const; ButtonBindings GetDefaultButtonBinding() const;
/// Returns the default button bindings list for nintendo controllers
ButtonBindings GetNintendoButtonBinding(const std::shared_ptr<SDLJoystick>& joystick) const;
/// Returns the button mappings from a single controller /// Returns the button mappings from a single controller
ButtonMapping GetSingleControllerMapping(const std::shared_ptr<SDLJoystick>& joystick, ButtonMapping GetSingleControllerMapping(const std::shared_ptr<SDLJoystick>& joystick,

View File

@ -234,10 +234,9 @@ bool BufferCache<P>::DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 am
if (has_new_downloads) { if (has_new_downloads) {
memory_tracker.MarkRegionAsGpuModified(*cpu_dest_address, amount); memory_tracker.MarkRegionAsGpuModified(*cpu_dest_address, amount);
} }
tmp_buffer.resize_destructive(amount);
Core::Memory::CpuGuestMemoryScoped<u8, Core::Memory::GuestMemoryFlags::UnsafeReadWrite> tmp( cpu_memory.ReadBlockUnsafe(*cpu_src_address, tmp_buffer.data(), amount);
cpu_memory, *cpu_src_address, amount, &tmp_buffer); cpu_memory.WriteBlockUnsafe(*cpu_dest_address, tmp_buffer.data(), amount);
tmp.SetAddressAndSize(*cpu_dest_address, amount);
return true; return true;
} }

View File

@ -5,7 +5,6 @@
#include "common/microprofile.h" #include "common/microprofile.h"
#include "common/settings.h" #include "common/settings.h"
#include "core/core.h" #include "core/core.h"
#include "core/memory.h"
#include "video_core/dma_pusher.h" #include "video_core/dma_pusher.h"
#include "video_core/engines/maxwell_3d.h" #include "video_core/engines/maxwell_3d.h"
#include "video_core/gpu.h" #include "video_core/gpu.h"
@ -13,8 +12,6 @@
namespace Tegra { namespace Tegra {
constexpr u32 MacroRegistersStart = 0xE00;
DmaPusher::DmaPusher(Core::System& system_, GPU& gpu_, MemoryManager& memory_manager_, DmaPusher::DmaPusher(Core::System& system_, GPU& gpu_, MemoryManager& memory_manager_,
Control::ChannelState& channel_state_) Control::ChannelState& channel_state_)
: gpu{gpu_}, system{system_}, memory_manager{memory_manager_}, puller{gpu_, memory_manager_, : gpu{gpu_}, system{system_}, memory_manager{memory_manager_}, puller{gpu_, memory_manager_,
@ -77,16 +74,25 @@ bool DmaPusher::Step() {
} }
// Push buffer non-empty, read a word // Push buffer non-empty, read a word
if (dma_state.method >= MacroRegistersStart) { command_headers.resize_destructive(command_list_header.size);
if (subchannels[dma_state.subchannel]) { constexpr u32 MacroRegistersStart = 0xE00;
subchannels[dma_state.subchannel]->current_dirty = memory_manager.IsMemoryDirty( if (dma_state.method < MacroRegistersStart) {
dma_state.dma_get, command_list_header.size * sizeof(u32)); if (Settings::IsGPULevelHigh()) {
memory_manager.ReadBlock(dma_state.dma_get, command_headers.data(),
command_list_header.size * sizeof(u32));
} else {
memory_manager.ReadBlockUnsafe(dma_state.dma_get, command_headers.data(),
command_list_header.size * sizeof(u32));
} }
} else {
const size_t copy_size = command_list_header.size * sizeof(u32);
if (subchannels[dma_state.subchannel]) {
subchannels[dma_state.subchannel]->current_dirty =
memory_manager.IsMemoryDirty(dma_state.dma_get, copy_size);
}
memory_manager.ReadBlockUnsafe(dma_state.dma_get, command_headers.data(), copy_size);
} }
Core::Memory::GpuGuestMemory<Tegra::CommandHeader, ProcessCommands(command_headers);
Core::Memory::GuestMemoryFlags::UnsafeRead>
headers(memory_manager, dma_state.dma_get, command_list_header.size, &command_headers);
ProcessCommands(headers);
} }
return true; return true;

View File

@ -5,7 +5,6 @@
#include "common/algorithm.h" #include "common/algorithm.h"
#include "common/assert.h" #include "common/assert.h"
#include "core/memory.h"
#include "video_core/engines/engine_upload.h" #include "video_core/engines/engine_upload.h"
#include "video_core/memory_manager.h" #include "video_core/memory_manager.h"
#include "video_core/rasterizer_interface.h" #include "video_core/rasterizer_interface.h"
@ -47,11 +46,15 @@ void State::ProcessData(const u32* data, size_t num_data) {
void State::ProcessData(std::span<const u8> read_buffer) { void State::ProcessData(std::span<const u8> read_buffer) {
const GPUVAddr address{regs.dest.Address()}; const GPUVAddr address{regs.dest.Address()};
if (is_linear) { if (is_linear) {
for (size_t line = 0; line < regs.line_count; ++line) { if (regs.line_count == 1) {
const GPUVAddr dest_line = address + line * regs.dest.pitch; rasterizer->AccelerateInlineToMemory(address, copy_size, read_buffer);
std::span<const u8> buffer(read_buffer.data() + line * regs.line_length_in, } else {
regs.line_length_in); for (size_t line = 0; line < regs.line_count; ++line) {
rasterizer->AccelerateInlineToMemory(dest_line, regs.line_length_in, buffer); const GPUVAddr dest_line = address + line * regs.dest.pitch;
std::span<const u8> buffer(read_buffer.data() + line * regs.line_length_in,
regs.line_length_in);
rasterizer->AccelerateInlineToMemory(dest_line, regs.line_length_in, buffer);
}
} }
} else { } else {
u32 width = regs.dest.width; u32 width = regs.dest.width;
@ -67,14 +70,13 @@ void State::ProcessData(std::span<const u8> read_buffer) {
const std::size_t dst_size = Tegra::Texture::CalculateSize( const std::size_t dst_size = Tegra::Texture::CalculateSize(
true, bytes_per_pixel, width, regs.dest.height, regs.dest.depth, true, bytes_per_pixel, width, regs.dest.height, regs.dest.depth,
regs.dest.BlockHeight(), regs.dest.BlockDepth()); regs.dest.BlockHeight(), regs.dest.BlockDepth());
tmp_buffer.resize_destructive(dst_size);
Core::Memory::GpuGuestMemoryScoped<u8, Core::Memory::GuestMemoryFlags::SafeReadCachedWrite> memory_manager.ReadBlock(address, tmp_buffer.data(), dst_size);
tmp(memory_manager, address, dst_size, &tmp_buffer); Tegra::Texture::SwizzleSubrect(tmp_buffer, read_buffer, bytes_per_pixel, width,
regs.dest.height, regs.dest.depth, x_offset, regs.dest.y,
Tegra::Texture::SwizzleSubrect(tmp, read_buffer, bytes_per_pixel, width, regs.dest.height, x_elements, regs.line_count, regs.dest.BlockHeight(),
regs.dest.depth, x_offset, regs.dest.y, x_elements,
regs.line_count, regs.dest.BlockHeight(),
regs.dest.BlockDepth(), regs.line_length_in); regs.dest.BlockDepth(), regs.line_length_in);
memory_manager.WriteBlockCached(address, tmp_buffer.data(), dst_size);
} }
} }

View File

@ -84,6 +84,7 @@ Texture::TICEntry KeplerCompute::GetTICEntry(u32 tic_index) const {
Texture::TICEntry tic_entry; Texture::TICEntry tic_entry;
memory_manager.ReadBlockUnsafe(tic_address_gpu, &tic_entry, sizeof(Texture::TICEntry)); memory_manager.ReadBlockUnsafe(tic_address_gpu, &tic_entry, sizeof(Texture::TICEntry));
return tic_entry; return tic_entry;
} }

View File

@ -9,7 +9,6 @@
#include "common/settings.h" #include "common/settings.h"
#include "core/core.h" #include "core/core.h"
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/memory.h"
#include "video_core/dirty_flags.h" #include "video_core/dirty_flags.h"
#include "video_core/engines/draw_manager.h" #include "video_core/engines/draw_manager.h"
#include "video_core/engines/maxwell_3d.h" #include "video_core/engines/maxwell_3d.h"
@ -680,14 +679,17 @@ void Maxwell3D::ProcessCBData(u32 value) {
Texture::TICEntry Maxwell3D::GetTICEntry(u32 tic_index) const { Texture::TICEntry Maxwell3D::GetTICEntry(u32 tic_index) const {
const GPUVAddr tic_address_gpu{regs.tex_header.Address() + const GPUVAddr tic_address_gpu{regs.tex_header.Address() +
tic_index * sizeof(Texture::TICEntry)}; tic_index * sizeof(Texture::TICEntry)};
Texture::TICEntry tic_entry; Texture::TICEntry tic_entry;
memory_manager.ReadBlockUnsafe(tic_address_gpu, &tic_entry, sizeof(Texture::TICEntry)); memory_manager.ReadBlockUnsafe(tic_address_gpu, &tic_entry, sizeof(Texture::TICEntry));
return tic_entry; return tic_entry;
} }
Texture::TSCEntry Maxwell3D::GetTSCEntry(u32 tsc_index) const { Texture::TSCEntry Maxwell3D::GetTSCEntry(u32 tsc_index) const {
const GPUVAddr tsc_address_gpu{regs.tex_sampler.Address() + const GPUVAddr tsc_address_gpu{regs.tex_sampler.Address() +
tsc_index * sizeof(Texture::TSCEntry)}; tsc_index * sizeof(Texture::TSCEntry)};
Texture::TSCEntry tsc_entry; Texture::TSCEntry tsc_entry;
memory_manager.ReadBlockUnsafe(tsc_address_gpu, &tsc_entry, sizeof(Texture::TSCEntry)); memory_manager.ReadBlockUnsafe(tsc_address_gpu, &tsc_entry, sizeof(Texture::TSCEntry));
return tsc_entry; return tsc_entry;

View File

@ -7,7 +7,6 @@
#include "common/microprofile.h" #include "common/microprofile.h"
#include "common/settings.h" #include "common/settings.h"
#include "core/core.h" #include "core/core.h"
#include "core/memory.h"
#include "video_core/engines/maxwell_3d.h" #include "video_core/engines/maxwell_3d.h"
#include "video_core/engines/maxwell_dma.h" #include "video_core/engines/maxwell_dma.h"
#include "video_core/memory_manager.h" #include "video_core/memory_manager.h"
@ -131,12 +130,11 @@ void MaxwellDMA::Launch() {
UNIMPLEMENTED_IF(regs.offset_out % 16 != 0); UNIMPLEMENTED_IF(regs.offset_out % 16 != 0);
read_buffer.resize_destructive(16); read_buffer.resize_destructive(16);
for (u32 offset = 0; offset < regs.line_length_in; offset += 16) { for (u32 offset = 0; offset < regs.line_length_in; offset += 16) {
Core::Memory::GpuGuestMemoryScoped< memory_manager.ReadBlock(
u8, Core::Memory::GuestMemoryFlags::SafeReadCachedWrite> convert_linear_2_blocklinear_addr(regs.offset_in + offset),
tmp_write_buffer(memory_manager, read_buffer.data(), read_buffer.size());
convert_linear_2_blocklinear_addr(regs.offset_in + offset), memory_manager.WriteBlockCached(regs.offset_out + offset, read_buffer.data(),
16, &read_buffer); read_buffer.size());
tmp_write_buffer.SetAddressAndSize(regs.offset_out + offset, 16);
} }
} else if (is_src_pitch && !is_dst_pitch) { } else if (is_src_pitch && !is_dst_pitch) {
UNIMPLEMENTED_IF(regs.line_length_in % 16 != 0); UNIMPLEMENTED_IF(regs.line_length_in % 16 != 0);
@ -144,19 +142,20 @@ void MaxwellDMA::Launch() {
UNIMPLEMENTED_IF(regs.offset_out % 16 != 0); UNIMPLEMENTED_IF(regs.offset_out % 16 != 0);
read_buffer.resize_destructive(16); read_buffer.resize_destructive(16);
for (u32 offset = 0; offset < regs.line_length_in; offset += 16) { for (u32 offset = 0; offset < regs.line_length_in; offset += 16) {
Core::Memory::GpuGuestMemoryScoped< memory_manager.ReadBlock(regs.offset_in + offset, read_buffer.data(),
u8, Core::Memory::GuestMemoryFlags::SafeReadCachedWrite> read_buffer.size());
tmp_write_buffer(memory_manager, regs.offset_in + offset, 16, &read_buffer); memory_manager.WriteBlockCached(
tmp_write_buffer.SetAddressAndSize( convert_linear_2_blocklinear_addr(regs.offset_out + offset),
convert_linear_2_blocklinear_addr(regs.offset_out + offset), 16); read_buffer.data(), read_buffer.size());
} }
} else { } else {
if (!accelerate.BufferCopy(regs.offset_in, regs.offset_out, regs.line_length_in)) { if (!accelerate.BufferCopy(regs.offset_in, regs.offset_out, regs.line_length_in)) {
Core::Memory::GpuGuestMemoryScoped< read_buffer.resize_destructive(regs.line_length_in);
u8, Core::Memory::GuestMemoryFlags::SafeReadCachedWrite> memory_manager.ReadBlock(regs.offset_in, read_buffer.data(),
tmp_write_buffer(memory_manager, regs.offset_in, regs.line_length_in, regs.line_length_in,
&read_buffer); VideoCommon::CacheType::NoBufferCache);
tmp_write_buffer.SetAddressAndSize(regs.offset_out, regs.line_length_in); memory_manager.WriteBlockCached(regs.offset_out, read_buffer.data(),
regs.line_length_in);
} }
} }
} }
@ -223,15 +222,17 @@ void MaxwellDMA::CopyBlockLinearToPitch() {
CalculateSize(true, bytes_per_pixel, width, height, depth, block_height, block_depth); CalculateSize(true, bytes_per_pixel, width, height, depth, block_height, block_depth);
const size_t dst_size = dst_operand.pitch * regs.line_count; const size_t dst_size = dst_operand.pitch * regs.line_count;
read_buffer.resize_destructive(src_size);
write_buffer.resize_destructive(dst_size);
Core::Memory::GpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead> tmp_read_buffer( memory_manager.ReadBlock(src_operand.address, read_buffer.data(), src_size);
memory_manager, src_operand.address, src_size, &read_buffer); memory_manager.ReadBlock(dst_operand.address, write_buffer.data(), dst_size);
Core::Memory::GpuGuestMemoryScoped<u8, Core::Memory::GuestMemoryFlags::SafeReadCachedWrite>
tmp_write_buffer(memory_manager, dst_operand.address, dst_size, &write_buffer);
UnswizzleSubrect(tmp_write_buffer, tmp_read_buffer, bytes_per_pixel, width, height, depth, UnswizzleSubrect(write_buffer, read_buffer, bytes_per_pixel, width, height, depth, x_offset,
x_offset, src_params.origin.y, x_elements, regs.line_count, block_height, src_params.origin.y, x_elements, regs.line_count, block_height, block_depth,
block_depth, dst_operand.pitch); dst_operand.pitch);
memory_manager.WriteBlockCached(regs.offset_out, write_buffer.data(), dst_size);
} }
void MaxwellDMA::CopyPitchToBlockLinear() { void MaxwellDMA::CopyPitchToBlockLinear() {
@ -286,17 +287,18 @@ void MaxwellDMA::CopyPitchToBlockLinear() {
CalculateSize(true, bytes_per_pixel, width, height, depth, block_height, block_depth); CalculateSize(true, bytes_per_pixel, width, height, depth, block_height, block_depth);
const size_t src_size = static_cast<size_t>(regs.pitch_in) * regs.line_count; const size_t src_size = static_cast<size_t>(regs.pitch_in) * regs.line_count;
GPUVAddr src_addr = regs.offset_in; read_buffer.resize_destructive(src_size);
GPUVAddr dst_addr = regs.offset_out; write_buffer.resize_destructive(dst_size);
Core::Memory::GpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead> tmp_read_buffer(
memory_manager, src_addr, src_size, &read_buffer);
Core::Memory::GpuGuestMemoryScoped<u8, Core::Memory::GuestMemoryFlags::SafeReadCachedWrite>
tmp_write_buffer(memory_manager, dst_addr, dst_size, &write_buffer);
// If the input is linear and the output is tiled, swizzle the input and copy it over. memory_manager.ReadBlock(regs.offset_in, read_buffer.data(), src_size);
SwizzleSubrect(tmp_write_buffer, tmp_read_buffer, bytes_per_pixel, width, height, depth, memory_manager.ReadBlockUnsafe(regs.offset_out, write_buffer.data(), dst_size);
x_offset, dst_params.origin.y, x_elements, regs.line_count, block_height,
block_depth, regs.pitch_in); // If the input is linear and the output is tiled, swizzle the input and copy it over.
SwizzleSubrect(write_buffer, read_buffer, bytes_per_pixel, width, height, depth, x_offset,
dst_params.origin.y, x_elements, regs.line_count, block_height, block_depth,
regs.pitch_in);
memory_manager.WriteBlockCached(regs.offset_out, write_buffer.data(), dst_size);
} }
void MaxwellDMA::CopyBlockLinearToBlockLinear() { void MaxwellDMA::CopyBlockLinearToBlockLinear() {
@ -340,20 +342,23 @@ void MaxwellDMA::CopyBlockLinearToBlockLinear() {
const u32 pitch = x_elements * bytes_per_pixel; const u32 pitch = x_elements * bytes_per_pixel;
const size_t mid_buffer_size = pitch * regs.line_count; const size_t mid_buffer_size = pitch * regs.line_count;
read_buffer.resize_destructive(src_size);
write_buffer.resize_destructive(dst_size);
intermediate_buffer.resize_destructive(mid_buffer_size); intermediate_buffer.resize_destructive(mid_buffer_size);
Core::Memory::GpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead> tmp_read_buffer( memory_manager.ReadBlock(regs.offset_in, read_buffer.data(), src_size);
memory_manager, regs.offset_in, src_size, &read_buffer); memory_manager.ReadBlock(regs.offset_out, write_buffer.data(), dst_size);
Core::Memory::GpuGuestMemoryScoped<u8, Core::Memory::GuestMemoryFlags::SafeReadCachedWrite>
tmp_write_buffer(memory_manager, regs.offset_out, dst_size, &write_buffer);
UnswizzleSubrect(intermediate_buffer, tmp_read_buffer, bytes_per_pixel, src_width, src.height, UnswizzleSubrect(intermediate_buffer, read_buffer, bytes_per_pixel, src_width, src.height,
src.depth, src_x_offset, src.origin.y, x_elements, regs.line_count, src.depth, src_x_offset, src.origin.y, x_elements, regs.line_count,
src.block_size.height, src.block_size.depth, pitch); src.block_size.height, src.block_size.depth, pitch);
SwizzleSubrect(tmp_write_buffer, intermediate_buffer, bytes_per_pixel, dst_width, dst.height, SwizzleSubrect(write_buffer, intermediate_buffer, bytes_per_pixel, dst_width, dst.height,
dst.depth, dst_x_offset, dst.origin.y, x_elements, regs.line_count, dst.depth, dst_x_offset, dst.origin.y, x_elements, regs.line_count,
dst.block_size.height, dst.block_size.depth, pitch); dst.block_size.height, dst.block_size.depth, pitch);
memory_manager.WriteBlockCached(regs.offset_out, write_buffer.data(), dst_size);
} }
void MaxwellDMA::ReleaseSemaphore() { void MaxwellDMA::ReleaseSemaphore() {

View File

@ -159,11 +159,11 @@ bool SoftwareBlitEngine::Blit(Fermi2D::Surface& src, Fermi2D::Surface& dst,
const auto src_bytes_per_pixel = BytesPerBlock(PixelFormatFromRenderTargetFormat(src.format)); const auto src_bytes_per_pixel = BytesPerBlock(PixelFormatFromRenderTargetFormat(src.format));
const auto dst_bytes_per_pixel = BytesPerBlock(PixelFormatFromRenderTargetFormat(dst.format)); const auto dst_bytes_per_pixel = BytesPerBlock(PixelFormatFromRenderTargetFormat(dst.format));
const size_t src_size = get_surface_size(src, src_bytes_per_pixel); const size_t src_size = get_surface_size(src, src_bytes_per_pixel);
impl->tmp_buffer.resize_destructive(src_size);
Core::Memory::GpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead> tmp_buffer( memory_manager.ReadBlock(src.Address(), impl->tmp_buffer.data(), src_size);
memory_manager, src.Address(), src_size, &impl->tmp_buffer);
const size_t src_copy_size = src_extent_x * src_extent_y * src_bytes_per_pixel; const size_t src_copy_size = src_extent_x * src_extent_y * src_bytes_per_pixel;
const size_t dst_copy_size = dst_extent_x * dst_extent_y * dst_bytes_per_pixel; const size_t dst_copy_size = dst_extent_x * dst_extent_y * dst_bytes_per_pixel;
impl->src_buffer.resize_destructive(src_copy_size); impl->src_buffer.resize_destructive(src_copy_size);
@ -200,11 +200,12 @@ bool SoftwareBlitEngine::Blit(Fermi2D::Surface& src, Fermi2D::Surface& dst,
impl->dst_buffer.resize_destructive(dst_copy_size); impl->dst_buffer.resize_destructive(dst_copy_size);
if (src.linear == Fermi2D::MemoryLayout::BlockLinear) { if (src.linear == Fermi2D::MemoryLayout::BlockLinear) {
UnswizzleSubrect(impl->src_buffer, tmp_buffer, src_bytes_per_pixel, src.width, src.height, UnswizzleSubrect(impl->src_buffer, impl->tmp_buffer, src_bytes_per_pixel, src.width,
src.depth, config.src_x0, config.src_y0, src_extent_x, src_extent_y, src.height, src.depth, config.src_x0, config.src_y0, src_extent_x,
src.block_height, src.block_depth, src_extent_x * src_bytes_per_pixel); src_extent_y, src.block_height, src.block_depth,
src_extent_x * src_bytes_per_pixel);
} else { } else {
process_pitch_linear(false, tmp_buffer, impl->src_buffer, src_extent_x, src_extent_y, process_pitch_linear(false, impl->tmp_buffer, impl->src_buffer, src_extent_x, src_extent_y,
src.pitch, config.src_x0, config.src_y0, src_bytes_per_pixel); src.pitch, config.src_x0, config.src_y0, src_bytes_per_pixel);
} }
@ -220,18 +221,20 @@ bool SoftwareBlitEngine::Blit(Fermi2D::Surface& src, Fermi2D::Surface& dst,
} }
const size_t dst_size = get_surface_size(dst, dst_bytes_per_pixel); const size_t dst_size = get_surface_size(dst, dst_bytes_per_pixel);
Core::Memory::GpuGuestMemoryScoped<u8, Core::Memory::GuestMemoryFlags::SafeReadWrite> impl->tmp_buffer.resize_destructive(dst_size);
tmp_buffer2(memory_manager, dst.Address(), dst_size, &impl->tmp_buffer); memory_manager.ReadBlock(dst.Address(), impl->tmp_buffer.data(), dst_size);
if (dst.linear == Fermi2D::MemoryLayout::BlockLinear) { if (dst.linear == Fermi2D::MemoryLayout::BlockLinear) {
SwizzleSubrect(tmp_buffer2, impl->dst_buffer, dst_bytes_per_pixel, dst.width, dst.height, SwizzleSubrect(impl->tmp_buffer, impl->dst_buffer, dst_bytes_per_pixel, dst.width,
dst.depth, config.dst_x0, config.dst_y0, dst_extent_x, dst_extent_y, dst.height, dst.depth, config.dst_x0, config.dst_y0, dst_extent_x,
dst.block_height, dst.block_depth, dst_extent_x * dst_bytes_per_pixel); dst_extent_y, dst.block_height, dst.block_depth,
dst_extent_x * dst_bytes_per_pixel);
} else { } else {
process_pitch_linear(true, impl->dst_buffer, tmp_buffer2, dst_extent_x, dst_extent_y, process_pitch_linear(true, impl->dst_buffer, impl->tmp_buffer, dst_extent_x, dst_extent_y,
dst.pitch, config.dst_x0, config.dst_y0, dst.pitch, config.dst_x0, config.dst_y0,
static_cast<size_t>(dst_bytes_per_pixel)); static_cast<size_t>(dst_bytes_per_pixel));
} }
memory_manager.WriteBlock(dst.Address(), impl->tmp_buffer.data(), dst_size);
return true; return true;
} }

View File

@ -10,13 +10,13 @@
#include "core/device_memory.h" #include "core/device_memory.h"
#include "core/hle/kernel/k_page_table.h" #include "core/hle/kernel/k_page_table.h"
#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_process.h"
#include "core/memory.h"
#include "video_core/invalidation_accumulator.h" #include "video_core/invalidation_accumulator.h"
#include "video_core/memory_manager.h" #include "video_core/memory_manager.h"
#include "video_core/rasterizer_interface.h" #include "video_core/rasterizer_interface.h"
#include "video_core/renderer_base.h" #include "video_core/renderer_base.h"
namespace Tegra { namespace Tegra {
using Core::Memory::GuestMemoryFlags;
std::atomic<size_t> MemoryManager::unique_identifier_generator{}; std::atomic<size_t> MemoryManager::unique_identifier_generator{};
@ -587,10 +587,13 @@ void MemoryManager::InvalidateRegion(GPUVAddr gpu_addr, size_t size,
void MemoryManager::CopyBlock(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, std::size_t size, void MemoryManager::CopyBlock(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, std::size_t size,
VideoCommon::CacheType which) { VideoCommon::CacheType which) {
Core::Memory::GpuGuestMemoryScoped<u8, GuestMemoryFlags::SafeReadWrite> data( tmp_buffer.resize_destructive(size);
*this, gpu_src_addr, size); ReadBlock(gpu_src_addr, tmp_buffer.data(), size, which);
data.SetAddressAndSize(gpu_dest_addr, size);
// The output block must be flushed in case it has data modified from the GPU.
// Fixes NPC geometry in Zombie Panic in Wonderland DX
FlushRegion(gpu_dest_addr, size, which); FlushRegion(gpu_dest_addr, size, which);
WriteBlock(gpu_dest_addr, tmp_buffer.data(), size, which);
} }
bool MemoryManager::IsGranularRange(GPUVAddr gpu_addr, std::size_t size) const { bool MemoryManager::IsGranularRange(GPUVAddr gpu_addr, std::size_t size) const {
@ -755,23 +758,4 @@ void MemoryManager::FlushCaching() {
accumulator->Clear(); accumulator->Clear();
} }
const u8* MemoryManager::GetSpan(const GPUVAddr src_addr, const std::size_t size) const {
auto cpu_addr = GpuToCpuAddress(src_addr);
if (cpu_addr) {
return memory.GetSpan(*cpu_addr, size);
}
return nullptr;
}
u8* MemoryManager::GetSpan(const GPUVAddr src_addr, const std::size_t size) {
if (!IsContinuousRange(src_addr, size)) {
return nullptr;
}
auto cpu_addr = GpuToCpuAddress(src_addr);
if (cpu_addr) {
return memory.GetSpan(*cpu_addr, size);
}
return nullptr;
}
} // namespace Tegra } // namespace Tegra

View File

@ -15,7 +15,6 @@
#include "common/range_map.h" #include "common/range_map.h"
#include "common/scratch_buffer.h" #include "common/scratch_buffer.h"
#include "common/virtual_buffer.h" #include "common/virtual_buffer.h"
#include "core/memory.h"
#include "video_core/cache_types.h" #include "video_core/cache_types.h"
#include "video_core/pte_kind.h" #include "video_core/pte_kind.h"
@ -63,20 +62,6 @@ public:
[[nodiscard]] u8* GetPointer(GPUVAddr addr); [[nodiscard]] u8* GetPointer(GPUVAddr addr);
[[nodiscard]] const u8* GetPointer(GPUVAddr addr) const; [[nodiscard]] const u8* GetPointer(GPUVAddr addr) const;
template <typename T>
[[nodiscard]] T* GetPointer(GPUVAddr addr) {
const auto address{GpuToCpuAddress(addr)};
if (!address) {
return {};
}
return memory.GetPointer(*address);
}
template <typename T>
[[nodiscard]] const T* GetPointer(GPUVAddr addr) const {
return GetPointer<T*>(addr);
}
/** /**
* ReadBlock and WriteBlock are full read and write operations over virtual * ReadBlock and WriteBlock are full read and write operations over virtual
* GPU Memory. It's important to use these when GPU memory may not be continuous * GPU Memory. It's important to use these when GPU memory may not be continuous
@ -154,9 +139,6 @@ public:
void FlushCaching(); void FlushCaching();
const u8* GetSpan(const GPUVAddr src_addr, const std::size_t size) const;
u8* GetSpan(const GPUVAddr src_addr, const std::size_t size);
private: private:
template <bool is_big_pages, typename FuncMapped, typename FuncReserved, typename FuncUnmapped> template <bool is_big_pages, typename FuncMapped, typename FuncReserved, typename FuncUnmapped>
inline void MemoryOperation(GPUVAddr gpu_src_addr, std::size_t size, FuncMapped&& func_mapped, inline void MemoryOperation(GPUVAddr gpu_src_addr, std::size_t size, FuncMapped&& func_mapped,

View File

@ -8,7 +8,6 @@
#include "common/alignment.h" #include "common/alignment.h"
#include "common/settings.h" #include "common/settings.h"
#include "core/memory.h"
#include "video_core/control/channel_state.h" #include "video_core/control/channel_state.h"
#include "video_core/dirty_flags.h" #include "video_core/dirty_flags.h"
#include "video_core/engines/kepler_compute.h" #include "video_core/engines/kepler_compute.h"
@ -1027,19 +1026,19 @@ void TextureCache<P>::UploadImageContents(Image& image, StagingBuffer& staging)
runtime.AccelerateImageUpload(image, staging, uploads); runtime.AccelerateImageUpload(image, staging, uploads);
return; return;
} }
const size_t guest_size_bytes = image.guest_size_bytes;
Core::Memory::GpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::UnsafeRead> swizzle_data( swizzle_data_buffer.resize_destructive(guest_size_bytes);
*gpu_memory, gpu_addr, image.guest_size_bytes, &swizzle_data_buffer); gpu_memory->ReadBlockUnsafe(gpu_addr, swizzle_data_buffer.data(), guest_size_bytes);
if (True(image.flags & ImageFlagBits::Converted)) { if (True(image.flags & ImageFlagBits::Converted)) {
unswizzle_data_buffer.resize_destructive(image.unswizzled_size_bytes); unswizzle_data_buffer.resize_destructive(image.unswizzled_size_bytes);
auto copies = auto copies = UnswizzleImage(*gpu_memory, gpu_addr, image.info, swizzle_data_buffer,
UnswizzleImage(*gpu_memory, gpu_addr, image.info, swizzle_data, unswizzle_data_buffer); unswizzle_data_buffer);
ConvertImage(unswizzle_data_buffer, image.info, mapped_span, copies); ConvertImage(unswizzle_data_buffer, image.info, mapped_span, copies);
image.UploadMemory(staging, copies); image.UploadMemory(staging, copies);
} else { } else {
const auto copies = const auto copies =
UnswizzleImage(*gpu_memory, gpu_addr, image.info, swizzle_data, mapped_span); UnswizzleImage(*gpu_memory, gpu_addr, image.info, swizzle_data_buffer, mapped_span);
image.UploadMemory(staging, copies); image.UploadMemory(staging, copies);
} }
} }
@ -1232,12 +1231,11 @@ void TextureCache<P>::QueueAsyncDecode(Image& image, ImageId image_id) {
decode->image_id = image_id; decode->image_id = image_id;
async_decodes.push_back(std::move(decode)); async_decodes.push_back(std::move(decode));
static Common::ScratchBuffer<u8> local_unswizzle_data_buffer; Common::ScratchBuffer<u8> local_unswizzle_data_buffer(image.unswizzled_size_bytes);
local_unswizzle_data_buffer.resize_destructive(image.unswizzled_size_bytes); const size_t guest_size_bytes = image.guest_size_bytes;
Core::Memory::GpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::UnsafeRead> swizzle_data( swizzle_data_buffer.resize_destructive(guest_size_bytes);
*gpu_memory, image.gpu_addr, image.guest_size_bytes, &swizzle_data_buffer); gpu_memory->ReadBlockUnsafe(image.gpu_addr, swizzle_data_buffer.data(), guest_size_bytes);
auto copies = UnswizzleImage(*gpu_memory, image.gpu_addr, image.info, swizzle_data_buffer,
auto copies = UnswizzleImage(*gpu_memory, image.gpu_addr, image.info, swizzle_data,
local_unswizzle_data_buffer); local_unswizzle_data_buffer);
const size_t out_size = MapSizeBytes(image); const size_t out_size = MapSizeBytes(image);

View File

@ -20,7 +20,6 @@
#include "common/div_ceil.h" #include "common/div_ceil.h"
#include "common/scratch_buffer.h" #include "common/scratch_buffer.h"
#include "common/settings.h" #include "common/settings.h"
#include "core/memory.h"
#include "video_core/compatible_formats.h" #include "video_core/compatible_formats.h"
#include "video_core/engines/maxwell_3d.h" #include "video_core/engines/maxwell_3d.h"
#include "video_core/memory_manager.h" #include "video_core/memory_manager.h"
@ -545,15 +544,17 @@ void SwizzleBlockLinearImage(Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr
tile_size.height, info.tile_width_spacing); tile_size.height, info.tile_width_spacing);
const size_t subresource_size = sizes[level]; const size_t subresource_size = sizes[level];
tmp_buffer.resize_destructive(subresource_size);
const std::span<u8> dst(tmp_buffer);
for (s32 layer = 0; layer < info.resources.layers; ++layer) { for (s32 layer = 0; layer < info.resources.layers; ++layer) {
const std::span<const u8> src = input.subspan(host_offset); const std::span<const u8> src = input.subspan(host_offset);
{ gpu_memory.ReadBlockUnsafe(gpu_addr + guest_offset, dst.data(), dst.size_bytes());
Core::Memory::GpuGuestMemoryScoped<u8, Core::Memory::GuestMemoryFlags::UnsafeReadWrite>
dst(gpu_memory, gpu_addr + guest_offset, subresource_size, &tmp_buffer);
SwizzleTexture(dst, src, bytes_per_block, num_tiles.width, num_tiles.height, SwizzleTexture(dst, src, bytes_per_block, num_tiles.width, num_tiles.height,
num_tiles.depth, block.height, block.depth); num_tiles.depth, block.height, block.depth);
}
gpu_memory.WriteBlockUnsafe(gpu_addr + guest_offset, dst.data(), dst.size_bytes());
host_offset += host_bytes_per_layer; host_offset += host_bytes_per_layer;
guest_offset += layer_stride; guest_offset += layer_stride;
@ -836,7 +837,6 @@ boost::container::small_vector<BufferImageCopy, 16> UnswizzleImage(Tegra::Memory
const Extent3D size = info.size; const Extent3D size = info.size;
if (info.type == ImageType::Linear) { if (info.type == ImageType::Linear) {
ASSERT(output.size_bytes() >= guest_size_bytes);
gpu_memory.ReadBlockUnsafe(gpu_addr, output.data(), guest_size_bytes); gpu_memory.ReadBlockUnsafe(gpu_addr, output.data(), guest_size_bytes);
ASSERT((info.pitch >> bpp_log2) << bpp_log2 == info.pitch); ASSERT((info.pitch >> bpp_log2) << bpp_log2 == info.pitch);
@ -904,6 +904,16 @@ boost::container::small_vector<BufferImageCopy, 16> UnswizzleImage(Tegra::Memory
return copies; return copies;
} }
BufferCopy UploadBufferCopy(Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr,
const ImageBase& image, std::span<u8> output) {
gpu_memory.ReadBlockUnsafe(gpu_addr, output.data(), image.guest_size_bytes);
return BufferCopy{
.src_offset = 0,
.dst_offset = 0,
.size = image.guest_size_bytes,
};
}
void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8> output, void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8> output,
std::span<BufferImageCopy> copies) { std::span<BufferImageCopy> copies) {
u32 output_offset = 0; u32 output_offset = 0;

View File

@ -66,6 +66,9 @@ struct OverlapResult {
Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr, const ImageInfo& info, Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr, const ImageInfo& info,
std::span<const u8> input, std::span<u8> output); std::span<const u8> input, std::span<u8> output);
[[nodiscard]] BufferCopy UploadBufferCopy(Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr,
const ImageBase& image, std::span<u8> output);
void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8> output, void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8> output,
std::span<BufferImageCopy> copies); std::span<BufferImageCopy> copies);