diff options
Diffstat (limited to 'src')
46 files changed, 514 insertions, 624 deletions
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index ac0e1d796..5bb139483 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h @@ -438,7 +438,7 @@ inline float RequestParser::Pop() { template <> inline double RequestParser::Pop() { const u64 value = Pop<u64>(); - float real; + double real; std::memcpy(&real, &value, sizeof(real)); return real; } diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index fe710eb6e..42d9dd844 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -58,7 +58,7 @@ SharedPtr<WritableEvent> HLERequestContext::SleepClientThread( auto& kernel = Core::System::GetInstance().Kernel(); if (!writable_event) { // Create event if not provided - const auto pair = WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot, + const auto pair = WritableEvent::CreateEventPair(kernel, ResetType::Automatic, "HLE Pause Event: " + reason); writable_event = pair.writable; } diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h index 332876c27..2821176a7 100644 --- a/src/core/hle/kernel/object.h +++ b/src/core/hle/kernel/object.h @@ -33,8 +33,8 @@ enum class HandleType : u32 { }; enum class ResetType { - OneShot, ///< Reset automatically on object acquisition - Sticky, ///< Never reset automatically + Automatic, ///< Reset automatically on object acquisition + Manual, ///< Never reset automatically }; class Object : NonCopyable { diff --git a/src/core/hle/kernel/readable_event.cpp b/src/core/hle/kernel/readable_event.cpp index c2b798a4e..06463cd26 100644 --- a/src/core/hle/kernel/readable_event.cpp +++ b/src/core/hle/kernel/readable_event.cpp @@ -21,8 +21,9 @@ bool ReadableEvent::ShouldWait(const Thread* thread) const { void ReadableEvent::Acquire(Thread* thread) { ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); - if (reset_type == ResetType::OneShot) + if (reset_type == ResetType::Automatic) { signaled = false; + } } void ReadableEvent::Signal() { diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 2dcf174c5..c23106299 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1255,8 +1255,8 @@ static ResultCode MapProcessCodeMemory(Core::System& system, Handle process_hand return vm_manager.MapCodeMemory(dst_address, src_address, size); } -ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_handle, u64 dst_address, - u64 src_address, u64 size) { +static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_handle, + u64 dst_address, u64 src_address, u64 size) { LOG_DEBUG(Kernel_SVC, "called. process_handle=0x{:08X}, dst_address=0x{:016X}, src_address=0x{:016X}, " "size=0x{:016X}", @@ -1980,7 +1980,7 @@ static ResultCode CreateEvent(Core::System& system, Handle* write_handle, Handle auto& kernel = system.Kernel(); const auto [readable_event, writable_event] = - WritableEvent::CreateEventPair(kernel, ResetType::Sticky, "CreateEvent"); + WritableEvent::CreateEventPair(kernel, ResetType::Manual, "CreateEvent"); HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable(); @@ -2183,8 +2183,8 @@ static ResultCode GetProcessList(Core::System& system, u32* out_num_processes, return RESULT_SUCCESS; } -ResultCode GetThreadList(Core::System& system, u32* out_num_threads, VAddr out_thread_ids, - u32 out_thread_ids_size, Handle debug_handle) { +static ResultCode GetThreadList(Core::System& system, u32* out_num_threads, VAddr out_thread_ids, + u32 out_thread_ids_size, Handle debug_handle) { // TODO: Handle this case when debug events are supported. UNIMPLEMENTED_IF(debug_handle != InvalidHandle); diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 26a665bfd..1a32a109f 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -276,7 +276,7 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger RegisterHandlers(functions); auto& kernel = Core::System::GetInstance().Kernel(); - launchable_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky, + launchable_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual, "ISelfController:LaunchableEvent"); } @@ -442,10 +442,10 @@ void ISelfController::GetIdleTimeDetectionExtension(Kernel::HLERequestContext& c AppletMessageQueue::AppletMessageQueue() { auto& kernel = Core::System::GetInstance().Kernel(); - on_new_message = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky, + on_new_message = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual, "AMMessageQueue:OnMessageRecieved"); on_operation_mode_changed = Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::OneShot, "AMMessageQueue:OperationModeChanged"); + kernel, Kernel::ResetType::Automatic, "AMMessageQueue:OperationModeChanged"); } AppletMessageQueue::~AppletMessageQueue() = default; @@ -835,6 +835,7 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ERR_SIZE_OUT_OF_BOUNDS); + return; } std::memcpy(backing.buffer.data() + offset, data.data(), data.size()); @@ -857,6 +858,7 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ERR_SIZE_OUT_OF_BOUNDS); + return; } ctx.WriteBuffer(backing.buffer.data() + offset, size); diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index 7f70b10df..e812c66e9 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp @@ -26,11 +26,11 @@ namespace Service::AM::Applets { AppletDataBroker::AppletDataBroker() { auto& kernel = Core::System::GetInstance().Kernel(); state_changed_event = Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::Sticky, "ILibraryAppletAccessor:StateChangedEvent"); + kernel, Kernel::ResetType::Manual, "ILibraryAppletAccessor:StateChangedEvent"); pop_out_data_event = Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::Sticky, "ILibraryAppletAccessor:PopDataOutEvent"); + kernel, Kernel::ResetType::Manual, "ILibraryAppletAccessor:PopDataOutEvent"); pop_interactive_out_data_event = Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::Sticky, "ILibraryAppletAccessor:PopInteractiveDataOutEvent"); + kernel, Kernel::ResetType::Manual, "ILibraryAppletAccessor:PopInteractiveDataOutEvent"); } AppletDataBroker::~AppletDataBroker() = default; diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp index 51d8c26b4..bd4e38461 100644 --- a/src/core/hle/service/aoc/aoc_u.cpp +++ b/src/core/hle/service/aoc/aoc_u.cpp @@ -68,7 +68,7 @@ AOC_U::AOC_U() : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs RegisterHandlers(functions); auto& kernel = Core::System::GetInstance().Kernel(); - aoc_change_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky, + aoc_change_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual, "GetAddOnContentListChanged:Event"); } diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index 12875fb42..6ba41b20a 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp @@ -67,7 +67,7 @@ public: // This is the event handle used to check if the audio buffer was released auto& system = Core::System::GetInstance(); buffer_event = Kernel::WritableEvent::CreateEventPair( - system.Kernel(), Kernel::ResetType::Sticky, "IAudioOutBufferReleased"); + system.Kernel(), Kernel::ResetType::Manual, "IAudioOutBufferReleased"); stream = audio_core.OpenStream(system.CoreTiming(), audio_params.sample_rate, audio_params.channel_count, std::move(unique_name), diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 1dde6edb7..75db0c2dc 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -8,6 +8,7 @@ #include "audio_core/audio_renderer.h" #include "common/alignment.h" +#include "common/bit_util.h" #include "common/common_funcs.h" #include "common/logging/log.h" #include "common/string_util.h" @@ -46,7 +47,7 @@ public: auto& system = Core::System::GetInstance(); system_event = Kernel::WritableEvent::CreateEventPair( - system.Kernel(), Kernel::ResetType::Sticky, "IAudioRenderer:SystemEvent"); + system.Kernel(), Kernel::ResetType::Manual, "IAudioRenderer:SystemEvent"); renderer = std::make_unique<AudioCore::AudioRenderer>(system.CoreTiming(), audren_params, system_event.writable); } @@ -178,7 +179,7 @@ public: RegisterHandlers(functions); auto& kernel = Core::System::GetInstance().Kernel(); - buffer_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot, + buffer_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic, "IAudioOutBufferReleasedEvent"); } @@ -262,64 +263,304 @@ void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) { OpenAudioRendererImpl(ctx); } +static u64 CalculateNumPerformanceEntries(const AudioCore::AudioRendererParameter& params) { + // +1 represents the final mix. + return u64{params.effect_count} + params.submix_count + params.sink_count + params.voice_count + + 1; +} + void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - auto params = rp.PopRaw<AudioCore::AudioRendererParameter>(); LOG_DEBUG(Service_Audio, "called"); - u64 buffer_sz = Common::AlignUp(4 * params.mix_buffer_count, 0x40); - buffer_sz += params.submix_count * 1024; - buffer_sz += 0x940 * (params.submix_count + 1); - buffer_sz += 0x3F0 * params.voice_count; - buffer_sz += Common::AlignUp(8 * (params.submix_count + 1), 0x10); - buffer_sz += Common::AlignUp(8 * params.voice_count, 0x10); - buffer_sz += Common::AlignUp( - (0x3C0 * (params.sink_count + params.submix_count) + 4 * params.sample_count) * - (params.mix_buffer_count + 6), - 0x40); - - if (IsFeatureSupported(AudioFeatures::Splitter, params.revision)) { - const u32 count = params.submix_count + 1; - u64 node_count = Common::AlignUp(count, 0x40); - const u64 node_state_buffer_sz = - 4 * (node_count * node_count) + 0xC * node_count + 2 * (node_count / 8); - u64 edge_matrix_buffer_sz = 0; - node_count = Common::AlignUp(count * count, 0x40); - if (node_count >> 31 != 0) { - edge_matrix_buffer_sz = (node_count | 7) / 8; - } else { - edge_matrix_buffer_sz = node_count / 8; + // Several calculations below align the sizes being calculated + // onto a 64 byte boundary. + static constexpr u64 buffer_alignment_size = 64; + + // Some calculations that calculate portions of the buffer + // that will contain information, on the other hand, align + // the result of some of their calcularions on a 16 byte boundary. + static constexpr u64 info_field_alignment_size = 16; + + // Maximum detail entries that may exist at one time for performance + // frame statistics. + static constexpr u64 max_perf_detail_entries = 100; + + // Size of the data structure representing the bulk of the voice-related state. + static constexpr u64 voice_state_size = 0x100; + + // Size of the upsampler manager data structure + constexpr u64 upsampler_manager_size = 0x48; + + // Calculates the part of the size that relates to mix buffers. + const auto calculate_mix_buffer_sizes = [](const AudioCore::AudioRendererParameter& params) { + // As of 8.0.0 this is the maximum on voice channels. + constexpr u64 max_voice_channels = 6; + + // The service expects the sample_count member of the parameters to either be + // a value of 160 or 240, so the maximum sample count is assumed in order + // to adequately handle all values at runtime. + constexpr u64 default_max_sample_count = 240; + + const u64 total_mix_buffers = params.mix_buffer_count + max_voice_channels; + + u64 size = 0; + size += total_mix_buffers * (sizeof(s32) * params.sample_count); + size += total_mix_buffers * (sizeof(s32) * default_max_sample_count); + size += u64{params.submix_count} + params.sink_count; + size = Common::AlignUp(size, buffer_alignment_size); + size += Common::AlignUp(params.unknown_30, buffer_alignment_size); + size += Common::AlignUp(sizeof(s32) * params.mix_buffer_count, buffer_alignment_size); + return size; + }; + + // Calculates the portion of the size related to the mix data (and the sorting thereof). + const auto calculate_mix_info_size = [this](const AudioCore::AudioRendererParameter& params) { + // The size of the mixing info data structure. + constexpr u64 mix_info_size = 0x940; + + // Consists of total submixes with the final mix included. + const u64 total_mix_count = u64{params.submix_count} + 1; + + // The total number of effects that may be available to the audio renderer at any time. + constexpr u64 max_effects = 256; + + // Calculates the part of the size related to the audio node state. + // This will only be used if the audio revision supports the splitter. + const auto calculate_node_state_size = [](std::size_t num_nodes) { + // Internally within a nodestate, it appears to use a data structure + // similar to a std::bitset<64> twice. + constexpr u64 bit_size = Common::BitSize<u64>(); + constexpr u64 num_bitsets = 2; + + // Node state instances have three states internally for performing + // depth-first searches of nodes. Initialized, Found, and Done Sorting. + constexpr u64 num_states = 3; + + u64 size = 0; + size += (num_nodes * num_nodes) * sizeof(s32); + size += num_states * (num_nodes * sizeof(s32)); + size += num_bitsets * (Common::AlignUp(num_nodes, bit_size) / Common::BitSize<u8>()); + return size; + }; + + // Calculates the part of the size related to the adjacency (aka edge) matrix. + const auto calculate_edge_matrix_size = [](std::size_t num_nodes) { + return (num_nodes * num_nodes) * sizeof(s32); + }; + + u64 size = 0; + size += Common::AlignUp(sizeof(void*) * total_mix_count, info_field_alignment_size); + size += Common::AlignUp(mix_info_size * total_mix_count, info_field_alignment_size); + size += Common::AlignUp(sizeof(s32) * max_effects * params.submix_count, + info_field_alignment_size); + + if (IsFeatureSupported(AudioFeatures::Splitter, params.revision)) { + size += Common::AlignUp(calculate_node_state_size(total_mix_count) + + calculate_edge_matrix_size(total_mix_count), + info_field_alignment_size); } - buffer_sz += Common::AlignUp(node_state_buffer_sz + edge_matrix_buffer_sz, 0x10); - } - buffer_sz += 0x20 * (params.effect_count + 4 * params.voice_count) + 0x50; - if (IsFeatureSupported(AudioFeatures::Splitter, params.revision)) { - buffer_sz += 0xE0 * params.num_splitter_send_channels; - buffer_sz += 0x20 * params.splitter_count; - buffer_sz += Common::AlignUp(4 * params.num_splitter_send_channels, 0x10); - } - buffer_sz = Common::AlignUp(buffer_sz, 0x40) + 0x170 * params.sink_count; - u64 output_sz = buffer_sz + 0x280 * params.sink_count + 0x4B0 * params.effect_count + - ((params.voice_count * 256) | 0x40); - - if (params.performance_frame_count >= 1) { - output_sz = Common::AlignUp(((16 * params.sink_count + 16 * params.effect_count + - 16 * params.voice_count + 16) + - 0x658) * - (params.performance_frame_count + 1) + - 0xc0, - 0x40) + - output_sz; - } - output_sz = Common::AlignUp(output_sz + 0x1807e, 0x1000); + return size; + }; - IPC::ResponseBuilder rb{ctx, 4}; + // Calculates the part of the size related to voice channel info. + const auto calculate_voice_info_size = [](const AudioCore::AudioRendererParameter& params) { + constexpr u64 voice_info_size = 0x220; + constexpr u64 voice_resource_size = 0xD0; + + u64 size = 0; + size += Common::AlignUp(sizeof(void*) * params.voice_count, info_field_alignment_size); + size += Common::AlignUp(voice_info_size * params.voice_count, info_field_alignment_size); + size += + Common::AlignUp(voice_resource_size * params.voice_count, info_field_alignment_size); + size += Common::AlignUp(voice_state_size * params.voice_count, info_field_alignment_size); + return size; + }; + + // Calculates the part of the size related to memory pools. + const auto calculate_memory_pools_size = [](const AudioCore::AudioRendererParameter& params) { + const u64 num_memory_pools = sizeof(s32) * (u64{params.effect_count} + params.voice_count); + const u64 memory_pool_info_size = 0x20; + return Common::AlignUp(num_memory_pools * memory_pool_info_size, info_field_alignment_size); + }; + + // Calculates the part of the size related to the splitter context. + const auto calculate_splitter_context_size = + [this](const AudioCore::AudioRendererParameter& params) -> u64 { + if (!IsFeatureSupported(AudioFeatures::Splitter, params.revision)) { + return 0; + } + + constexpr u64 splitter_info_size = 0x20; + constexpr u64 splitter_destination_data_size = 0xE0; + + u64 size = 0; + size += params.num_splitter_send_channels; + size += + Common::AlignUp(splitter_info_size * params.splitter_count, info_field_alignment_size); + size += Common::AlignUp(splitter_destination_data_size * params.num_splitter_send_channels, + info_field_alignment_size); + + return size; + }; + + // Calculates the part of the size related to the upsampler info. + const auto calculate_upsampler_info_size = [](const AudioCore::AudioRendererParameter& params) { + constexpr u64 upsampler_info_size = 0x280; + // Yes, using the buffer size over info alignment size is intentional here. + return Common::AlignUp(upsampler_info_size * (u64{params.submix_count} + params.sink_count), + buffer_alignment_size); + }; + + // Calculates the part of the size related to effect info. + const auto calculate_effect_info_size = [](const AudioCore::AudioRendererParameter& params) { + constexpr u64 effect_info_size = 0x2B0; + return Common::AlignUp(effect_info_size * params.effect_count, info_field_alignment_size); + }; + + // Calculates the part of the size related to audio sink info. + const auto calculate_sink_info_size = [](const AudioCore::AudioRendererParameter& params) { + const u64 sink_info_size = 0x170; + return Common::AlignUp(sink_info_size * params.sink_count, info_field_alignment_size); + }; + + // Calculates the part of the size related to voice state info. + const auto calculate_voice_state_size = [](const AudioCore::AudioRendererParameter& params) { + const u64 voice_state_size = 0x100; + const u64 additional_size = buffer_alignment_size - 1; + return Common::AlignUp(voice_state_size * params.voice_count + additional_size, + info_field_alignment_size); + }; + + // Calculates the part of the size related to performance statistics. + const auto calculate_perf_size = [this](const AudioCore::AudioRendererParameter& params) { + // Extra size value appended to the end of the calculation. + constexpr u64 appended = 128; + + // Whether or not we assume the newer version of performance metrics data structures. + const bool is_v2 = + IsFeatureSupported(AudioFeatures::PerformanceMetricsVersion2, params.revision); + + // Data structure sizes + constexpr u64 perf_statistics_size = 0x0C; + const u64 header_size = is_v2 ? 0x30 : 0x18; + const u64 entry_size = is_v2 ? 0x18 : 0x10; + const u64 detail_size = is_v2 ? 0x18 : 0x10; + + const u64 entry_count = CalculateNumPerformanceEntries(params); + const u64 size_per_frame = + header_size + (entry_size * entry_count) + (detail_size * max_perf_detail_entries); + + u64 size = 0; + size += Common::AlignUp(size_per_frame * params.performance_frame_count + 1, + buffer_alignment_size); + size += Common::AlignUp(perf_statistics_size, buffer_alignment_size); + size += appended; + return size; + }; + + // Calculates the part of the size that relates to the audio command buffer. + const auto calculate_command_buffer_size = + [this](const AudioCore::AudioRendererParameter& params) { + constexpr u64 alignment = (buffer_alignment_size - 1) * 2; + + if (!IsFeatureSupported(AudioFeatures::VariadicCommandBuffer, params.revision)) { + constexpr u64 command_buffer_size = 0x18000; + + return command_buffer_size + alignment; + } + + // When the variadic command buffer is supported, this means + // the command generator for the audio renderer can issue commands + // that are (as one would expect), variable in size. So what we need to do + // is determine the maximum possible size for a few command data structures + // then multiply them by the amount of present commands indicated by the given + // respective audio parameters. + + constexpr u64 max_biquad_filters = 2; + constexpr u64 max_mix_buffers = 24; + + constexpr u64 biquad_filter_command_size = 0x2C; + + constexpr u64 depop_mix_command_size = 0x24; + constexpr u64 depop_setup_command_size = 0x50; + + constexpr u64 effect_command_max_size = 0x540; + + constexpr u64 mix_command_size = 0x1C; + constexpr u64 mix_ramp_command_size = 0x24; + constexpr u64 mix_ramp_grouped_command_size = 0x13C; + + constexpr u64 perf_command_size = 0x28; + + constexpr u64 sink_command_size = 0x130; + + constexpr u64 submix_command_max_size = + depop_mix_command_size + (mix_command_size * max_mix_buffers) * max_mix_buffers; + + constexpr u64 volume_command_size = 0x1C; + constexpr u64 volume_ramp_command_size = 0x20; + + constexpr u64 voice_biquad_filter_command_size = + biquad_filter_command_size * max_biquad_filters; + constexpr u64 voice_data_command_size = 0x9C; + const u64 voice_command_max_size = + (params.splitter_count * depop_setup_command_size) + + (voice_data_command_size + voice_biquad_filter_command_size + + volume_ramp_command_size + mix_ramp_grouped_command_size); + + // Now calculate the individual elements that comprise the size and add them together. + const u64 effect_commands_size = params.effect_count * effect_command_max_size; + + const u64 final_mix_commands_size = + depop_mix_command_size + volume_command_size * max_mix_buffers; + const u64 perf_commands_size = + perf_command_size * + (CalculateNumPerformanceEntries(params) + max_perf_detail_entries); + + const u64 sink_commands_size = params.sink_count * sink_command_size; + + const u64 splitter_commands_size = + params.num_splitter_send_channels * max_mix_buffers * mix_ramp_command_size; + + const u64 submix_commands_size = params.submix_count * submix_command_max_size; + + const u64 voice_commands_size = params.voice_count * voice_command_max_size; + + return effect_commands_size + final_mix_commands_size + perf_commands_size + + sink_commands_size + splitter_commands_size + submix_commands_size + + voice_commands_size + alignment; + }; + + IPC::RequestParser rp{ctx}; + const auto params = rp.PopRaw<AudioCore::AudioRendererParameter>(); + + u64 size = 0; + size += calculate_mix_buffer_sizes(params); + size += calculate_mix_info_size(params); + size += calculate_voice_info_size(params); + size += upsampler_manager_size; + size += calculate_memory_pools_size(params); + size += calculate_splitter_context_size(params); + + size = Common::AlignUp(size, buffer_alignment_size); + + size += calculate_upsampler_info_size(params); + size += calculate_effect_info_size(params); + size += calculate_sink_info_size(params); + size += calculate_voice_state_size(params); + size += calculate_perf_size(params); + size += calculate_command_buffer_size(params); + + // finally, 4KB page align the size, and we're done. + size = Common::AlignUp(size, 4096); + + IPC::ResponseBuilder rb{ctx, 4}; rb.Push(RESULT_SUCCESS); - rb.Push<u64>(output_sz); + rb.Push<u64>(size); - LOG_DEBUG(Service_Audio, "buffer_size=0x{:X}", output_sz); + LOG_DEBUG(Service_Audio, "buffer_size=0x{:X}", size); } void AudRenU::GetAudioDeviceService(Kernel::HLERequestContext& ctx) { @@ -357,10 +598,15 @@ void AudRenU::OpenAudioRendererImpl(Kernel::HLERequestContext& ctx) { } bool AudRenU::IsFeatureSupported(AudioFeatures feature, u32_le revision) const { - u32_be version_num = (revision - Common::MakeMagic('R', 'E', 'V', '0')); // Byte swap + // Byte swap + const u32_be version_num = revision - Common::MakeMagic('R', 'E', 'V', '0'); + switch (feature) { case AudioFeatures::Splitter: - return version_num >= 2u; + return version_num >= 2U; + case AudioFeatures::PerformanceMetricsVersion2: + case AudioFeatures::VariadicCommandBuffer: + return version_num >= 5U; default: return false; } diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h index e55d25973..1d3c8df61 100644 --- a/src/core/hle/service/audio/audren_u.h +++ b/src/core/hle/service/audio/audren_u.h @@ -28,6 +28,8 @@ private: enum class AudioFeatures : u32 { Splitter, + PerformanceMetricsVersion2, + VariadicCommandBuffer, }; bool IsFeatureSupported(AudioFeatures feature, u32_le revision) const; diff --git a/src/core/hle/service/btdrv/btdrv.cpp b/src/core/hle/service/btdrv/btdrv.cpp index 974ff8e1a..3c7ca2c44 100644 --- a/src/core/hle/service/btdrv/btdrv.cpp +++ b/src/core/hle/service/btdrv/btdrv.cpp @@ -34,8 +34,8 @@ public: RegisterHandlers(functions); auto& kernel = Core::System::GetInstance().Kernel(); - register_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot, - "BT:RegisterEvent"); + register_event = Kernel::WritableEvent::CreateEventPair( + kernel, Kernel::ResetType::Automatic, "BT:RegisterEvent"); } private: diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp index 4f15c3f19..b439ee7ec 100644 --- a/src/core/hle/service/btm/btm.cpp +++ b/src/core/hle/service/btm/btm.cpp @@ -57,13 +57,13 @@ public: RegisterHandlers(functions); auto& kernel = Core::System::GetInstance().Kernel(); - scan_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot, + scan_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic, "IBtmUserCore:ScanEvent"); connection_event = Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::OneShot, "IBtmUserCore:ConnectionEvent"); + kernel, Kernel::ResetType::Automatic, "IBtmUserCore:ConnectionEvent"); service_discovery = Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::OneShot, "IBtmUserCore:Discovery"); - config_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot, + kernel, Kernel::ResetType::Automatic, "IBtmUserCore:Discovery"); + config_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic, "IBtmUserCore:ConfigEvent"); } diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index e7fc7a619..fdd6d79a2 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -170,7 +170,7 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) { void Controller_NPad::OnInit() { auto& kernel = Core::System::GetInstance().Kernel(); styleset_changed_event = Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::OneShot, "npad:NpadStyleSetChanged"); + kernel, Kernel::ResetType::Automatic, "npad:NpadStyleSetChanged"); if (!IsControllerActivated()) { return; diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index c6babdd4d..a5cb06f8a 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp @@ -26,7 +26,7 @@ constexpr ResultCode ERR_NO_APPLICATION_AREA(ErrorModule::NFP, 152); Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) : ServiceFramework(name), module(std::move(module)) { auto& kernel = Core::System::GetInstance().Kernel(); - nfc_tag_load = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot, + nfc_tag_load = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic, "IUser:NFCTagDetected"); } @@ -67,9 +67,9 @@ public: auto& kernel = Core::System::GetInstance().Kernel(); deactivate_event = Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::OneShot, "IUser:DeactivateEvent"); + kernel, Kernel::ResetType::Automatic, "IUser:DeactivateEvent"); availability_change_event = Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::OneShot, "IUser:AvailabilityChangeEvent"); + kernel, Kernel::ResetType::Automatic, "IUser:AvailabilityChangeEvent"); } private: diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index f92571008..76b12b482 100644 --- a/src/core/hle/service/nifm/nifm.cpp +++ b/src/core/hle/service/nifm/nifm.cpp @@ -62,9 +62,9 @@ public: RegisterHandlers(functions); auto& kernel = Core::System::GetInstance().Kernel(); - event1 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot, + event1 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic, "IRequest:Event1"); - event2 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot, + event2 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic, "IRequest:Event2"); } diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp index 0dabcd23b..f319a3ca1 100644 --- a/src/core/hle/service/nim/nim.cpp +++ b/src/core/hle/service/nim/nim.cpp @@ -141,7 +141,7 @@ public: auto& kernel = Core::System::GetInstance().Kernel(); finished_event = Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::OneShot, + kernel, Kernel::ResetType::Automatic, "IEnsureNetworkClockAvailabilityService:FinishEvent"); } diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp index 3b9ab4b14..b60fc748b 100644 --- a/src/core/hle/service/nvdrv/interface.cpp +++ b/src/core/hle/service/nvdrv/interface.cpp @@ -129,7 +129,7 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name) RegisterHandlers(functions); auto& kernel = Core::System::GetInstance().Kernel(); - query_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot, + query_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic, "NVDRV::query_event"); } diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp index 4d150fc71..5731e815f 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue.cpp @@ -16,7 +16,7 @@ namespace Service::NVFlinger { BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) { auto& kernel = Core::System::GetInstance().Kernel(); - buffer_wait_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky, + buffer_wait_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual, "BufferQueue NativeHandle"); } diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp index 4ecb6bcef..298d85011 100644 --- a/src/core/hle/service/set/set.cpp +++ b/src/core/hle/service/set/set.cpp @@ -2,16 +2,15 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <algorithm> #include <chrono> #include "common/logging/log.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/client_port.h" -#include "core/hle/kernel/client_session.h" #include "core/hle/service/set/set.h" #include "core/settings.h" namespace Service::Set { - +namespace { constexpr std::array<LanguageCode, 17> available_language_codes = {{ LanguageCode::JA, LanguageCode::EN_US, @@ -32,41 +31,35 @@ constexpr std::array<LanguageCode, 17> available_language_codes = {{ LanguageCode::ZH_HANT, }}; -constexpr std::size_t pre4_0_0_max_entries = 0xF; -constexpr std::size_t post4_0_0_max_entries = 0x40; +constexpr std::size_t pre4_0_0_max_entries = 15; +constexpr std::size_t post4_0_0_max_entries = 17; constexpr ResultCode ERR_INVALID_LANGUAGE{ErrorModule::Settings, 625}; -LanguageCode GetLanguageCodeFromIndex(std::size_t index) { - return available_language_codes.at(index); +void PushResponseLanguageCode(Kernel::HLERequestContext& ctx, std::size_t num_language_codes) { + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push(static_cast<u32>(num_language_codes)); } -template <std::size_t size> -static std::array<LanguageCode, size> MakeLanguageCodeSubset() { - std::array<LanguageCode, size> arr; - std::copy_n(available_language_codes.begin(), size, arr.begin()); - return arr; +void GetAvailableLanguageCodesImpl(Kernel::HLERequestContext& ctx, std::size_t max_size) { + const std::size_t requested_amount = ctx.GetWriteBufferSize() / sizeof(LanguageCode); + const std::size_t copy_amount = std::min(requested_amount, max_size); + const std::size_t copy_size = copy_amount * sizeof(LanguageCode); + + ctx.WriteBuffer(available_language_codes.data(), copy_size); + PushResponseLanguageCode(ctx, copy_amount); } +} // Anonymous namespace -static void PushResponseLanguageCode(Kernel::HLERequestContext& ctx, std::size_t max_size) { - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(RESULT_SUCCESS); - if (available_language_codes.size() > max_size) { - rb.Push(static_cast<u32>(max_size)); - } else { - rb.Push(static_cast<u32>(available_language_codes.size())); - } +LanguageCode GetLanguageCodeFromIndex(std::size_t index) { + return available_language_codes.at(index); } void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_SET, "called"); - if (available_language_codes.size() > pre4_0_0_max_entries) { - ctx.WriteBuffer(MakeLanguageCodeSubset<pre4_0_0_max_entries>()); - } else { - ctx.WriteBuffer(available_language_codes); - } - PushResponseLanguageCode(ctx, pre4_0_0_max_entries); + GetAvailableLanguageCodesImpl(ctx, pre4_0_0_max_entries); } void SET::MakeLanguageCode(Kernel::HLERequestContext& ctx) { @@ -87,12 +80,7 @@ void SET::MakeLanguageCode(Kernel::HLERequestContext& ctx) { void SET::GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_SET, "called"); - if (available_language_codes.size() > post4_0_0_max_entries) { - ctx.WriteBuffer(MakeLanguageCodeSubset<post4_0_0_max_entries>()); - } else { - ctx.WriteBuffer(available_language_codes); - } - PushResponseLanguageCode(ctx, post4_0_0_max_entries); + GetAvailableLanguageCodesImpl(ctx, post4_0_0_max_entries); } void SET::GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx) { @@ -102,9 +90,9 @@ void SET::GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx) { } void SET::GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx) { - PushResponseLanguageCode(ctx, post4_0_0_max_entries); - LOG_DEBUG(Service_SET, "called"); + + PushResponseLanguageCode(ctx, post4_0_0_max_entries); } void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) { diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp index 01d80311b..a8d088305 100644 --- a/src/core/hle/service/vi/display/vi_display.cpp +++ b/src/core/hle/service/vi/display/vi_display.cpp @@ -17,7 +17,7 @@ namespace Service::VI { Display::Display(u64 id, std::string name) : id{id}, name{std::move(name)} { auto& kernel = Core::System::GetInstance().Kernel(); - vsync_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky, + vsync_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual, fmt::format("Display VSync Event {}", id)); } diff --git a/src/video_core/engines/engine_upload.cpp b/src/video_core/engines/engine_upload.cpp index f8aa4ff55..082a40cd9 100644 --- a/src/video_core/engines/engine_upload.cpp +++ b/src/video_core/engines/engine_upload.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <cstring> + #include "common/assert.h" #include "video_core/engines/engine_upload.h" #include "video_core/memory_manager.h" @@ -10,7 +12,9 @@ namespace Tegra::Engines::Upload { State::State(MemoryManager& memory_manager, Registers& regs) - : memory_manager(memory_manager), regs(regs) {} + : regs{regs}, memory_manager{memory_manager} {} + +State::~State() = default; void State::ProcessExec(const bool is_linear) { write_offset = 0; diff --git a/src/video_core/engines/engine_upload.h b/src/video_core/engines/engine_upload.h index 9c6e0d21c..ef4f5839a 100644 --- a/src/video_core/engines/engine_upload.h +++ b/src/video_core/engines/engine_upload.h @@ -4,10 +4,8 @@ #pragma once -#include <cstddef> #include <vector> #include "common/bit_field.h" -#include "common/common_funcs.h" #include "common/common_types.h" namespace Tegra { @@ -57,10 +55,10 @@ struct Registers { class State { public: State(MemoryManager& memory_manager, Registers& regs); - ~State() = default; + ~State(); - void ProcessExec(const bool is_linear); - void ProcessData(const u32 data, const bool is_last_call); + void ProcessExec(bool is_linear); + void ProcessData(u32 data, bool is_last_call); private: u32 write_offset = 0; diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index d7b586db9..39968d403 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -34,9 +34,9 @@ void Maxwell3D::InitializeRegisterDefaults() { // Depth range near/far is not always set, but is expected to be the default 0.0f, 1.0f. This is // needed for ARMS. - for (std::size_t viewport{}; viewport < Regs::NumViewports; ++viewport) { - regs.viewports[viewport].depth_range_near = 0.0f; - regs.viewports[viewport].depth_range_far = 1.0f; + for (auto& viewport : regs.viewports) { + viewport.depth_range_near = 0.0f; + viewport.depth_range_far = 1.0f; } // Doom and Bomberman seems to use the uninitialized registers and just enable blend @@ -47,13 +47,13 @@ void Maxwell3D::InitializeRegisterDefaults() { regs.blend.equation_a = Regs::Blend::Equation::Add; regs.blend.factor_source_a = Regs::Blend::Factor::One; regs.blend.factor_dest_a = Regs::Blend::Factor::Zero; - for (std::size_t blend_index = 0; blend_index < Regs::NumRenderTargets; blend_index++) { - regs.independent_blend[blend_index].equation_rgb = Regs::Blend::Equation::Add; - regs.independent_blend[blend_index].factor_source_rgb = Regs::Blend::Factor::One; - regs.independent_blend[blend_index].factor_dest_rgb = Regs::Blend::Factor::Zero; - regs.independent_blend[blend_index].equation_a = Regs::Blend::Equation::Add; - regs.independent_blend[blend_index].factor_source_a = Regs::Blend::Factor::One; - regs.independent_blend[blend_index].factor_dest_a = Regs::Blend::Factor::Zero; + for (auto& blend : regs.independent_blend) { + blend.equation_rgb = Regs::Blend::Equation::Add; + blend.factor_source_rgb = Regs::Blend::Factor::One; + blend.factor_dest_rgb = Regs::Blend::Factor::Zero; + blend.equation_a = Regs::Blend::Equation::Add; + blend.factor_source_a = Regs::Blend::Factor::One; + blend.factor_dest_a = Regs::Blend::Factor::Zero; } regs.stencil_front_op_fail = Regs::StencilOp::Keep; regs.stencil_front_op_zfail = Regs::StencilOp::Keep; @@ -75,11 +75,11 @@ void Maxwell3D::InitializeRegisterDefaults() { // TODO(bunnei): Some games do not initialize the color masks (e.g. Sonic Mania). Assuming a // default of enabled fixes rendering here. - for (std::size_t color_mask = 0; color_mask < Regs::NumRenderTargets; color_mask++) { - regs.color_mask[color_mask].R.Assign(1); - regs.color_mask[color_mask].G.Assign(1); - regs.color_mask[color_mask].B.Assign(1); - regs.color_mask[color_mask].A.Assign(1); + for (auto& color_mask : regs.color_mask) { + color_mask.R.Assign(1); + color_mask.G.Assign(1); + color_mask.B.Assign(1); + color_mask.A.Assign(1); } // Commercial games seem to assume this value is enabled and nouveau sets this value manually. @@ -178,13 +178,13 @@ void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) { // Vertex buffer if (method >= MAXWELL3D_REG_INDEX(vertex_array) && - method < MAXWELL3D_REG_INDEX(vertex_array) + 4 * 32) { + method < MAXWELL3D_REG_INDEX(vertex_array) + 4 * Regs::NumVertexArrays) { dirty_flags.vertex_array.set((method - MAXWELL3D_REG_INDEX(vertex_array)) >> 2); } else if (method >= MAXWELL3D_REG_INDEX(vertex_array_limit) && - method < MAXWELL3D_REG_INDEX(vertex_array_limit) + 2 * 32) { + method < MAXWELL3D_REG_INDEX(vertex_array_limit) + 2 * Regs::NumVertexArrays) { dirty_flags.vertex_array.set((method - MAXWELL3D_REG_INDEX(vertex_array_limit)) >> 1); } else if (method >= MAXWELL3D_REG_INDEX(instanced_arrays) && - method < MAXWELL3D_REG_INDEX(instanced_arrays) + 32) { + method < MAXWELL3D_REG_INDEX(instanced_arrays) + Regs::NumVertexArrays) { dirty_flags.vertex_array.set(method - MAXWELL3D_REG_INDEX(instanced_arrays)); } } @@ -442,7 +442,7 @@ Texture::TICEntry Maxwell3D::GetTICEntry(u32 tic_index) const { const auto a_type = tic_entry.a_type.Value(); // TODO(Subv): Different data types for separate components are not supported - ASSERT(r_type == g_type && r_type == b_type && r_type == a_type); + DEBUG_ASSERT(r_type == g_type && r_type == b_type && r_type == a_type); return tic_entry; } diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 4883b582a..48e4fec33 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -6,6 +6,7 @@ #include <array> #include <bitset> +#include <type_traits> #include <unordered_map> #include <vector> @@ -1107,6 +1108,7 @@ public: } regs{}; static_assert(sizeof(Regs) == Regs::NUM_REGS * sizeof(u32), "Maxwell3D Regs has wrong size"); + static_assert(std::is_trivially_copyable_v<Regs>, "Maxwell3D Regs must be trivially copyable"); struct State { struct ConstBufferInfo { diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp index 03856013f..1e2ff46b0 100644 --- a/src/video_core/gpu_thread.cpp +++ b/src/video_core/gpu_thread.cpp @@ -118,7 +118,7 @@ void SynchState::WaitForSynchronization(u64 fence) { // Wait for the GPU to be idle (all commands to be executed) { MICROPROFILE_SCOPE(GPU_wait); - std::unique_lock<std::mutex> lock{synchronization_mutex}; + std::unique_lock lock{synchronization_mutex}; synchronization_condition.wait(lock, [this, fence] { return signaled_fence >= fence; }); } } diff --git a/src/video_core/gpu_thread.h b/src/video_core/gpu_thread.h index cc14527c7..05a168a72 100644 --- a/src/video_core/gpu_thread.h +++ b/src/video_core/gpu_thread.h @@ -81,12 +81,6 @@ struct CommandDataContainer { CommandDataContainer(CommandData&& data, u64 next_fence) : data{std::move(data)}, fence{next_fence} {} - CommandDataContainer& operator=(const CommandDataContainer& t) { - data = std::move(t.data); - fence = t.fence; - return *this; - } - CommandData data; u64 fence{}; }; @@ -109,7 +103,7 @@ struct SynchState final { void TrySynchronize() { if (IsSynchronized()) { - std::lock_guard<std::mutex> lock{synchronization_mutex}; + std::lock_guard lock{synchronization_mutex}; synchronization_condition.notify_one(); } } diff --git a/src/video_core/macro_interpreter.cpp b/src/video_core/macro_interpreter.cpp index 524d9ea5a..fbea107ca 100644 --- a/src/video_core/macro_interpreter.cpp +++ b/src/video_core/macro_interpreter.cpp @@ -118,10 +118,10 @@ bool MacroInterpreter::Step(u32 offset, bool is_delay_slot) { static_cast<u32>(opcode.operation.Value())); } - if (opcode.is_exit) { + // An instruction with the Exit flag will not actually + // cause an exit if it's executed inside a delay slot. + if (opcode.is_exit && !is_delay_slot) { // Exit has a delay slot, execute the next instruction - // Note: Executing an exit during a branch delay slot will cause the instruction at the - // branch target to be executed before exiting. Step(offset, true); return false; } diff --git a/src/video_core/rasterizer_cache.h b/src/video_core/rasterizer_cache.h index f820f3ed9..0c4ea1494 100644 --- a/src/video_core/rasterizer_cache.h +++ b/src/video_core/rasterizer_cache.h @@ -144,8 +144,9 @@ protected: object->SetIsRegistered(false); rasterizer.UpdatePagesCachedCount(object->GetCpuAddr(), object->GetSizeInBytes(), -1); + const CacheAddr addr = object->GetCacheAddr(); interval_cache.subtract({GetInterval(object), ObjectSet{object}}); - map_cache.erase(object->GetCacheAddr()); + map_cache.erase(addr); } /// Returns a ticks counter used for tracking when cached objects were last modified diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 3cc945235..dbd8049f5 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -261,8 +261,8 @@ DrawParameters RasterizerOpenGL::SetupDraw() { // MakeQuadArray always generates u32 indexes params.index_format = GL_UNSIGNED_INT; params.count = (regs.vertex_buffer.count / 4) * 6; - params.index_buffer_offset = - primitive_assembler.MakeQuadArray(regs.vertex_buffer.first, params.count); + params.index_buffer_offset = primitive_assembler.MakeQuadArray( + regs.vertex_buffer.first, regs.vertex_buffer.count); } return params; } @@ -1135,7 +1135,9 @@ void RasterizerOpenGL::SyncTransformFeedback() { void RasterizerOpenGL::SyncPointState() { const auto& regs = system.GPU().Maxwell3D().regs; - state.point.size = regs.point_size; + // Limit the point size to 1 since nouveau sometimes sets a point size of 0 (and that's invalid + // in OpenGL). + state.point.size = std::max(1.0f, regs.point_size); } void RasterizerOpenGL::SyncPolygonOffset() { diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp index 254c0d499..fba9c594a 100644 --- a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp @@ -104,8 +104,9 @@ bool ShaderDiskCacheRaw::Save(FileUtil::IOFile& file) const { return true; } -ShaderDiskCacheOpenGL::ShaderDiskCacheOpenGL(Core::System& system) - : system{system}, precompiled_cache_virtual_file_offset{0} {} +ShaderDiskCacheOpenGL::ShaderDiskCacheOpenGL(Core::System& system) : system{system} {} + +ShaderDiskCacheOpenGL::~ShaderDiskCacheOpenGL() = default; std::optional<std::pair<std::vector<ShaderDiskCacheRaw>, std::vector<ShaderDiskCacheUsage>>> ShaderDiskCacheOpenGL::LoadTransferable() { @@ -243,7 +244,7 @@ ShaderDiskCacheOpenGL::LoadPrecompiledFile(FileUtil::IOFile& file) { return {}; } - const auto entry = LoadDecompiledEntry(); + auto entry = LoadDecompiledEntry(); if (!entry) { return {}; } @@ -287,13 +288,13 @@ std::optional<ShaderDiskCacheDecompiled> ShaderDiskCacheOpenGL::LoadDecompiledEn return {}; } - std::vector<u8> code(code_size); + std::string code(code_size, '\0'); if (!LoadArrayFromPrecompiled(code.data(), code.size())) { return {}; } ShaderDiskCacheDecompiled entry; - entry.code = std::string(reinterpret_cast<const char*>(code.data()), code_size); + entry.code = std::move(code); u32 const_buffers_count{}; if (!LoadObjectFromPrecompiled(const_buffers_count)) { @@ -303,12 +304,12 @@ std::optional<ShaderDiskCacheDecompiled> ShaderDiskCacheOpenGL::LoadDecompiledEn for (u32 i = 0; i < const_buffers_count; ++i) { u32 max_offset{}; u32 index{}; - u8 is_indirect{}; + bool is_indirect{}; if (!LoadObjectFromPrecompiled(max_offset) || !LoadObjectFromPrecompiled(index) || !LoadObjectFromPrecompiled(is_indirect)) { return {}; } - entry.entries.const_buffers.emplace_back(max_offset, is_indirect != 0, index); + entry.entries.const_buffers.emplace_back(max_offset, is_indirect, index); } u32 samplers_count{}; @@ -320,18 +321,17 @@ std::optional<ShaderDiskCacheDecompiled> ShaderDiskCacheOpenGL::LoadDecompiledEn u64 offset{}; u64 index{}; u32 type{}; - u8 is_array{}; - u8 is_shadow{}; - u8 is_bindless{}; + bool is_array{}; + bool is_shadow{}; + bool is_bindless{}; if (!LoadObjectFromPrecompiled(offset) || !LoadObjectFromPrecompiled(index) || !LoadObjectFromPrecompiled(type) || !LoadObjectFromPrecompiled(is_array) || !LoadObjectFromPrecompiled(is_shadow) || !LoadObjectFromPrecompiled(is_bindless)) { return {}; } - entry.entries.samplers.emplace_back(static_cast<std::size_t>(offset), - static_cast<std::size_t>(index), - static_cast<Tegra::Shader::TextureType>(type), - is_array != 0, is_shadow != 0, is_bindless != 0); + entry.entries.samplers.emplace_back( + static_cast<std::size_t>(offset), static_cast<std::size_t>(index), + static_cast<Tegra::Shader::TextureType>(type), is_array, is_shadow, is_bindless); } u32 global_memory_count{}; @@ -342,21 +342,20 @@ std::optional<ShaderDiskCacheDecompiled> ShaderDiskCacheOpenGL::LoadDecompiledEn for (u32 i = 0; i < global_memory_count; ++i) { u32 cbuf_index{}; u32 cbuf_offset{}; - u8 is_read{}; - u8 is_written{}; + bool is_read{}; + bool is_written{}; if (!LoadObjectFromPrecompiled(cbuf_index) || !LoadObjectFromPrecompiled(cbuf_offset) || !LoadObjectFromPrecompiled(is_read) || !LoadObjectFromPrecompiled(is_written)) { return {}; } - entry.entries.global_memory_entries.emplace_back(cbuf_index, cbuf_offset, is_read != 0, - is_written != 0); + entry.entries.global_memory_entries.emplace_back(cbuf_index, cbuf_offset, is_read, + is_written); } for (auto& clip_distance : entry.entries.clip_distances) { - u8 clip_distance_raw{}; - if (!LoadObjectFromPrecompiled(clip_distance_raw)) + if (!LoadObjectFromPrecompiled(clip_distance)) { return {}; - clip_distance = clip_distance_raw != 0; + } } u64 shader_length{}; @@ -384,7 +383,7 @@ bool ShaderDiskCacheOpenGL::SaveDecompiledFile(u64 unique_identifier, const std: for (const auto& cbuf : entries.const_buffers) { if (!SaveObjectToPrecompiled(static_cast<u32>(cbuf.GetMaxOffset())) || !SaveObjectToPrecompiled(static_cast<u32>(cbuf.GetIndex())) || - !SaveObjectToPrecompiled(static_cast<u8>(cbuf.IsIndirect() ? 1 : 0))) { + !SaveObjectToPrecompiled(cbuf.IsIndirect())) { return false; } } @@ -396,9 +395,9 @@ bool ShaderDiskCacheOpenGL::SaveDecompiledFile(u64 unique_identifier, const std: if (!SaveObjectToPrecompiled(static_cast<u64>(sampler.GetOffset())) || !SaveObjectToPrecompiled(static_cast<u64>(sampler.GetIndex())) || !SaveObjectToPrecompiled(static_cast<u32>(sampler.GetType())) || - !SaveObjectToPrecompiled(static_cast<u8>(sampler.IsArray() ? 1 : 0)) || - !SaveObjectToPrecompiled(static_cast<u8>(sampler.IsShadow() ? 1 : 0)) || - !SaveObjectToPrecompiled(static_cast<u8>(sampler.IsBindless() ? 1 : 0))) { + !SaveObjectToPrecompiled(sampler.IsArray()) || + !SaveObjectToPrecompiled(sampler.IsShadow()) || + !SaveObjectToPrecompiled(sampler.IsBindless())) { return false; } } @@ -409,14 +408,13 @@ bool ShaderDiskCacheOpenGL::SaveDecompiledFile(u64 unique_identifier, const std: for (const auto& gmem : entries.global_memory_entries) { if (!SaveObjectToPrecompiled(static_cast<u32>(gmem.GetCbufIndex())) || !SaveObjectToPrecompiled(static_cast<u32>(gmem.GetCbufOffset())) || - !SaveObjectToPrecompiled(static_cast<u8>(gmem.IsRead() ? 1 : 0)) || - !SaveObjectToPrecompiled(static_cast<u8>(gmem.IsWritten() ? 1 : 0))) { + !SaveObjectToPrecompiled(gmem.IsRead()) || !SaveObjectToPrecompiled(gmem.IsWritten())) { return false; } } for (const bool clip_distance : entries.clip_distances) { - if (!SaveObjectToPrecompiled(static_cast<u8>(clip_distance ? 1 : 0))) { + if (!SaveObjectToPrecompiled(clip_distance)) { return false; } } diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.h b/src/video_core/renderer_opengl/gl_shader_disk_cache.h index 0142b2e3b..2da0a4a23 100644 --- a/src/video_core/renderer_opengl/gl_shader_disk_cache.h +++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.h @@ -70,14 +70,14 @@ namespace std { template <> struct hash<OpenGL::BaseBindings> { - std::size_t operator()(const OpenGL::BaseBindings& bindings) const { + std::size_t operator()(const OpenGL::BaseBindings& bindings) const noexcept { return bindings.cbuf | bindings.gmem << 8 | bindings.sampler << 16; } }; template <> struct hash<OpenGL::ShaderDiskCacheUsage> { - std::size_t operator()(const OpenGL::ShaderDiskCacheUsage& usage) const { + std::size_t operator()(const OpenGL::ShaderDiskCacheUsage& usage) const noexcept { return static_cast<std::size_t>(usage.unique_identifier) ^ std::hash<OpenGL::BaseBindings>()(usage.bindings) ^ usage.primitive << 16; } @@ -162,6 +162,7 @@ struct ShaderDiskCacheDump { class ShaderDiskCacheOpenGL { public: explicit ShaderDiskCacheOpenGL(Core::System& system); + ~ShaderDiskCacheOpenGL(); /// Loads transferable cache. If file has a old version or on failure, it deletes the file. std::optional<std::pair<std::vector<ShaderDiskCacheRaw>, std::vector<ShaderDiskCacheUsage>>> @@ -259,20 +260,35 @@ private: return SaveArrayToPrecompiled(&object, 1); } + bool SaveObjectToPrecompiled(bool object) { + const auto value = static_cast<u8>(object); + return SaveArrayToPrecompiled(&value, 1); + } + template <typename T> bool LoadObjectFromPrecompiled(T& object) { return LoadArrayFromPrecompiled(&object, 1); } - // Copre system + bool LoadObjectFromPrecompiled(bool& object) { + u8 value; + const bool read_ok = LoadArrayFromPrecompiled(&value, 1); + if (!read_ok) { + return false; + } + + object = value != 0; + return true; + } + + // Core system Core::System& system; // Stored transferable shaders std::map<u64, std::unordered_set<ShaderDiskCacheUsage>> transferable; - // Stores whole precompiled cache which will be read from or saved to the precompiled chache - // file + // Stores whole precompiled cache which will be read from/saved to the precompiled cache file FileSys::VectorVfsFile precompiled_cache_virtual_file; // Stores the current offset of the precompiled cache file for IO purposes - std::size_t precompiled_cache_virtual_file_offset; + std::size_t precompiled_cache_virtual_file_offset = 0; // The cache has been loaded at boot bool tried_to_load{}; diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 6abf948f8..7ab0b4553 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -33,14 +33,14 @@ layout (std140, binding = EMULATION_UBO_BINDING) uniform vs_config { }; )"; - ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET); + const ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET); ProgramResult program = Decompile(device, program_ir, Maxwell3D::Regs::ShaderStage::Vertex, "vertex"); out += program.first; if (setup.IsDualProgram()) { - ShaderIR program_ir_b(setup.program.code_b, PROGRAM_OFFSET); + const ShaderIR program_ir_b(setup.program.code_b, PROGRAM_OFFSET); ProgramResult program_b = Decompile(device, program_ir_b, Maxwell3D::Regs::ShaderStage::Vertex, "vertex_b"); @@ -76,7 +76,7 @@ void main() { } })"; - return {out, program.second}; + return {std::move(out), std::move(program.second)}; } ProgramResult GenerateGeometryShader(const Device& device, const ShaderSetup& setup) { @@ -97,7 +97,7 @@ layout (std140, binding = EMULATION_UBO_BINDING) uniform gs_config { }; )"; - ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET); + const ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET); ProgramResult program = Decompile(device, program_ir, Maxwell3D::Regs::ShaderStage::Geometry, "geometry"); out += program.first; @@ -107,7 +107,7 @@ void main() { execute_geometry(); };)"; - return {out, program.second}; + return {std::move(out), std::move(program.second)}; } ProgramResult GenerateFragmentShader(const Device& device, const ShaderSetup& setup) { @@ -160,7 +160,7 @@ bool AlphaFunc(in float value) { } )"; - ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET); + const ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET); ProgramResult program = Decompile(device, program_ir, Maxwell3D::Regs::ShaderStage::Fragment, "fragment"); @@ -172,7 +172,7 @@ void main() { } )"; - return {out, program.second}; + return {std::move(out), std::move(program.second)}; } } // namespace OpenGL::GLShader diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h index 95b773135..ed7b5cff0 100644 --- a/src/video_core/renderer_opengl/maxwell_to_gl.h +++ b/src/video_core/renderer_opengl/maxwell_to_gl.h @@ -126,6 +126,8 @@ inline GLenum PrimitiveTopology(Maxwell::PrimitiveTopology topology) { return GL_TRIANGLES; case Maxwell::PrimitiveTopology::TriangleStrip: return GL_TRIANGLE_STRIP; + case Maxwell::PrimitiveTopology::TriangleFan: + return GL_TRIANGLE_FAN; default: LOG_CRITICAL(Render_OpenGL, "Unimplemented topology={}", static_cast<u32>(topology)); UNREACHABLE(); diff --git a/src/video_core/shader/shader_ir.cpp b/src/video_core/shader/shader_ir.cpp index e4eb0dfd9..196235e5d 100644 --- a/src/video_core/shader/shader_ir.cpp +++ b/src/video_core/shader/shader_ir.cpp @@ -21,6 +21,13 @@ using Tegra::Shader::PredCondition; using Tegra::Shader::PredOperation; using Tegra::Shader::Register; +ShaderIR::ShaderIR(const ProgramCode& program_code, u32 main_offset) + : program_code{program_code}, main_offset{main_offset} { + Decode(); +} + +ShaderIR::~ShaderIR() = default; + Node ShaderIR::StoreNode(NodeData&& node_data) { auto store = std::make_unique<NodeData>(node_data); const Node node = store.get(); diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h index 65f1e1de9..e4253fdb3 100644 --- a/src/video_core/shader/shader_ir.h +++ b/src/video_core/shader/shader_ir.h @@ -328,40 +328,31 @@ struct MetaTexture { u32 element{}; }; -inline constexpr MetaArithmetic PRECISE = {true}; -inline constexpr MetaArithmetic NO_PRECISE = {false}; +constexpr MetaArithmetic PRECISE = {true}; +constexpr MetaArithmetic NO_PRECISE = {false}; using Meta = std::variant<MetaArithmetic, MetaTexture, Tegra::Shader::HalfType>; /// Holds any kind of operation that can be done in the IR class OperationNode final { public: - template <typename... T> - explicit constexpr OperationNode(OperationCode code) : code{code}, meta{} {} + explicit OperationNode(OperationCode code) : code{code} {} - template <typename... T> - explicit constexpr OperationNode(OperationCode code, Meta&& meta) - : code{code}, meta{std::move(meta)} {} + explicit OperationNode(OperationCode code, Meta&& meta) : code{code}, meta{std::move(meta)} {} template <typename... T> - explicit constexpr OperationNode(OperationCode code, const T*... operands) + explicit OperationNode(OperationCode code, const T*... operands) : OperationNode(code, {}, operands...) {} template <typename... T> - explicit constexpr OperationNode(OperationCode code, Meta&& meta, const T*... operands_) - : code{code}, meta{std::move(meta)} { - - auto operands_list = {operands_...}; - for (auto& operand : operands_list) { - operands.push_back(operand); - } - } + explicit OperationNode(OperationCode code, Meta&& meta, const T*... operands_) + : code{code}, meta{std::move(meta)}, operands{operands_...} {} explicit OperationNode(OperationCode code, Meta&& meta, std::vector<Node>&& operands) : code{code}, meta{meta}, operands{std::move(operands)} {} explicit OperationNode(OperationCode code, std::vector<Node>&& operands) - : code{code}, meta{}, operands{std::move(operands)} {} + : code{code}, operands{std::move(operands)} {} OperationCode GetCode() const { return code; @@ -567,11 +558,8 @@ private: class ShaderIR final { public: - explicit ShaderIR(const ProgramCode& program_code, u32 main_offset) - : program_code{program_code}, main_offset{main_offset} { - - Decode(); - } + explicit ShaderIR(const ProgramCode& program_code, u32 main_offset); + ~ShaderIR(); const std::map<u32, NodeBlock>& GetBasicBlocks() const { return basic_blocks; @@ -814,11 +802,12 @@ private: void WriteLop3Instruction(NodeBlock& bb, Tegra::Shader::Register dest, Node op_a, Node op_b, Node op_c, Node imm_lut, bool sets_cc); - Node TrackCbuf(Node tracked, const NodeBlock& code, s64 cursor); + Node TrackCbuf(Node tracked, const NodeBlock& code, s64 cursor) const; - std::optional<u32> TrackImmediate(Node tracked, const NodeBlock& code, s64 cursor); + std::optional<u32> TrackImmediate(Node tracked, const NodeBlock& code, s64 cursor) const; - std::pair<Node, s64> TrackRegister(const GprNode* tracked, const NodeBlock& code, s64 cursor); + std::pair<Node, s64> TrackRegister(const GprNode* tracked, const NodeBlock& code, + s64 cursor) const; std::tuple<Node, Node, GlobalMemoryBase> TrackAndGetGlobalMemory(NodeBlock& bb, Node addr_register, @@ -835,12 +824,10 @@ private: return StoreNode(OperationNode(code, std::move(meta), operands...)); } - template <typename... T> Node Operation(OperationCode code, std::vector<Node>&& operands) { return StoreNode(OperationNode(code, std::move(operands))); } - template <typename... T> Node Operation(OperationCode code, Meta&& meta, std::vector<Node>&& operands) { return StoreNode(OperationNode(code, std::move(meta), std::move(operands))); } diff --git a/src/video_core/shader/track.cpp b/src/video_core/shader/track.cpp index 4505667ff..19ede1eb9 100644 --- a/src/video_core/shader/track.cpp +++ b/src/video_core/shader/track.cpp @@ -17,22 +17,24 @@ std::pair<Node, s64> FindOperation(const NodeBlock& code, s64 cursor, for (; cursor >= 0; --cursor) { const Node node = code.at(cursor); if (const auto operation = std::get_if<OperationNode>(node)) { - if (operation->GetCode() == operation_code) + if (operation->GetCode() == operation_code) { return {node, cursor}; + } } if (const auto conditional = std::get_if<ConditionalNode>(node)) { const auto& conditional_code = conditional->GetCode(); const auto [found, internal_cursor] = FindOperation( conditional_code, static_cast<s64>(conditional_code.size() - 1), operation_code); - if (found) + if (found) { return {found, cursor}; + } } } return {}; } } // namespace -Node ShaderIR::TrackCbuf(Node tracked, const NodeBlock& code, s64 cursor) { +Node ShaderIR::TrackCbuf(Node tracked, const NodeBlock& code, s64 cursor) const { if (const auto cbuf = std::get_if<CbufNode>(tracked)) { // Cbuf found, but it has to be immediate return std::holds_alternative<ImmediateNode>(*cbuf->GetOffset()) ? tracked : nullptr; @@ -65,7 +67,7 @@ Node ShaderIR::TrackCbuf(Node tracked, const NodeBlock& code, s64 cursor) { return nullptr; } -std::optional<u32> ShaderIR::TrackImmediate(Node tracked, const NodeBlock& code, s64 cursor) { +std::optional<u32> ShaderIR::TrackImmediate(Node tracked, const NodeBlock& code, s64 cursor) const { // Reduce the cursor in one to avoid infinite loops when the instruction sets the same register // that it uses as operand const auto [found, found_cursor] = @@ -80,7 +82,7 @@ std::optional<u32> ShaderIR::TrackImmediate(Node tracked, const NodeBlock& code, } std::pair<Node, s64> ShaderIR::TrackRegister(const GprNode* tracked, const NodeBlock& code, - s64 cursor) { + s64 cursor) const { for (; cursor >= 0; --cursor) { const auto [found_node, new_cursor] = FindOperation(code, cursor, OperationCode::Assign); if (!found_node) { diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 5138bd9a3..7e883991a 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -82,8 +82,6 @@ add_executable(yuzu util/limitable_input_dialog.h util/sequence_dialog/sequence_dialog.cpp util/sequence_dialog/sequence_dialog.h - util/spinbox.cpp - util/spinbox.h util/util.cpp util/util.h compatdb.cpp diff --git a/src/yuzu/applets/error.cpp b/src/yuzu/applets/error.cpp index 1fb2fe277..106dde9e2 100644 --- a/src/yuzu/applets/error.cpp +++ b/src/yuzu/applets/error.cpp @@ -54,6 +54,6 @@ void QtErrorDisplay::ShowCustomErrorText(ResultCode error, std::string dialog_te void QtErrorDisplay::MainWindowFinishedError() { // Acquire the HLE mutex - std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); + std::lock_guard lock{HLE::g_hle_lock}; callback(); } diff --git a/src/yuzu/applets/profile_select.cpp b/src/yuzu/applets/profile_select.cpp index 743b24d76..7fbc9deeb 100644 --- a/src/yuzu/applets/profile_select.cpp +++ b/src/yuzu/applets/profile_select.cpp @@ -84,10 +84,10 @@ QtProfileSelectionDialog::QtProfileSelectionDialog(QWidget* parent) tree_view->setContextMenuPolicy(Qt::NoContextMenu); item_model->insertColumns(0, 1); - item_model->setHeaderData(0, Qt::Horizontal, "Users"); + item_model->setHeaderData(0, Qt::Horizontal, tr("Users")); // We must register all custom types with the Qt Automoc system so that we are able to use it - // with signals/slots. In this case, QList falls under the umbrells of custom types. + // with signals/slots. In this case, QList falls under the umbrella of custom types. qRegisterMetaType<QList<QStandardItem*>>("QList<QStandardItem*>"); layout->setContentsMargins(0, 0, 0, 0); diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 5c98636c5..810954b36 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -379,6 +379,7 @@ void GRenderWindow::InitRenderTarget() { fmt.setVersion(4, 3); if (Settings::values.use_compatibility_profile) { fmt.setProfile(QSurfaceFormat::CompatibilityProfile); + fmt.setOption(QSurfaceFormat::FormatOption::DeprecatedFunctions); } else { fmt.setProfile(QSurfaceFormat::CoreProfile); } diff --git a/src/yuzu/debugger/graphics/graphics_breakpoints.cpp b/src/yuzu/debugger/graphics/graphics_breakpoints.cpp index 67ed0ba6d..1c80082a4 100644 --- a/src/yuzu/debugger/graphics/graphics_breakpoints.cpp +++ b/src/yuzu/debugger/graphics/graphics_breakpoints.cpp @@ -135,7 +135,7 @@ GraphicsBreakPointsWidget::GraphicsBreakPointsWidget( std::shared_ptr<Tegra::DebugContext> debug_context, QWidget* parent) : QDockWidget(tr("Maxwell Breakpoints"), parent), Tegra::DebugContext::BreakPointObserver( debug_context) { - setObjectName("TegraBreakPointsWidget"); + setObjectName(QStringLiteral("TegraBreakPointsWidget")); status_text = new QLabel(tr("Emulation running")); resume_button = new QPushButton(tr("Resume")); diff --git a/src/yuzu/debugger/profiler.cpp b/src/yuzu/debugger/profiler.cpp index 86e03e46d..f594ef076 100644 --- a/src/yuzu/debugger/profiler.cpp +++ b/src/yuzu/debugger/profiler.cpp @@ -47,7 +47,7 @@ private: #endif MicroProfileDialog::MicroProfileDialog(QWidget* parent) : QWidget(parent, Qt::Dialog) { - setObjectName("MicroProfile"); + setObjectName(QStringLiteral("MicroProfile")); setWindowTitle(tr("MicroProfile")); resize(1000, 600); // Remove the "?" button from the titlebar and enable the maximize button @@ -191,7 +191,7 @@ void MicroProfileDrawText(int x, int y, u32 hex_color, const char* text, u32 tex for (u32 i = 0; i < text_length; ++i) { // Position the text baseline 1 pixel above the bottom of the text cell, this gives nice // vertical alignment of text for a wide range of tested fonts. - mp_painter->drawText(x, y + MICROPROFILE_TEXT_HEIGHT - 2, QChar(text[i])); + mp_painter->drawText(x, y + MICROPROFILE_TEXT_HEIGHT - 2, QString{QLatin1Char{text[i]}}); x += MICROPROFILE_TEXT_WIDTH + 1; } } diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index 85b095688..cd8180f8b 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp @@ -91,19 +91,19 @@ WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address, const Kernel::HandleTa WaitTreeMutexInfo::~WaitTreeMutexInfo() = default; QString WaitTreeMutexInfo::GetText() const { - return tr("waiting for mutex 0x%1").arg(mutex_address, 16, 16, QLatin1Char('0')); + return tr("waiting for mutex 0x%1").arg(mutex_address, 16, 16, QLatin1Char{'0'}); } std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeMutexInfo::GetChildren() const { - std::vector<std::unique_ptr<WaitTreeItem>> list; - - bool has_waiters = (mutex_value & Kernel::Mutex::MutexHasWaitersFlag) != 0; + const bool has_waiters = (mutex_value & Kernel::Mutex::MutexHasWaitersFlag) != 0; + std::vector<std::unique_ptr<WaitTreeItem>> list; list.push_back(std::make_unique<WaitTreeText>(tr("has waiters: %1").arg(has_waiters))); list.push_back(std::make_unique<WaitTreeText>( - tr("owner handle: 0x%1").arg(owner_handle, 8, 16, QLatin1Char('0')))); - if (owner != nullptr) + tr("owner handle: 0x%1").arg(owner_handle, 8, 16, QLatin1Char{'0'}))); + if (owner != nullptr) { list.push_back(std::make_unique<WaitTreeThread>(*owner)); + } return list; } @@ -121,11 +121,14 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() cons u64 base_pointer = thread.GetContext().cpu_registers[BaseRegister]; while (base_pointer != 0) { - u64 lr = Memory::Read64(base_pointer + sizeof(u64)); - if (lr == 0) + const u64 lr = Memory::Read64(base_pointer + sizeof(u64)); + if (lr == 0) { break; - list.push_back( - std::make_unique<WaitTreeText>(tr("0x%1").arg(lr - sizeof(u32), 16, 16, QChar('0')))); + } + + list.push_back(std::make_unique<WaitTreeText>( + tr("0x%1").arg(lr - sizeof(u32), 16, 16, QLatin1Char{'0'}))); + base_pointer = Memory::Read64(base_pointer); } @@ -174,10 +177,10 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeWaitObject::GetChildren() con QString WaitTreeWaitObject::GetResetTypeQString(Kernel::ResetType reset_type) { switch (reset_type) { - case Kernel::ResetType::OneShot: - return tr("one shot"); - case Kernel::ResetType::Sticky: - return tr("sticky"); + case Kernel::ResetType::Automatic: + return tr("automatic reset"); + case Kernel::ResetType::Manual: + return tr("manual reset"); } UNREACHABLE(); return {}; @@ -249,9 +252,9 @@ QString WaitTreeThread::GetText() const { const auto& context = thread.GetContext(); const QString pc_info = tr(" PC = 0x%1 LR = 0x%2") - .arg(context.pc, 8, 16, QLatin1Char('0')) - .arg(context.cpu_registers[30], 8, 16, QLatin1Char('0')); - return WaitTreeWaitObject::GetText() + pc_info + " (" + status + ") "; + .arg(context.pc, 8, 16, QLatin1Char{'0'}) + .arg(context.cpu_registers[30], 8, 16, QLatin1Char{'0'}); + return QStringLiteral("%1%2 (%3) ").arg(WaitTreeWaitObject::GetText(), pc_info, status); } QColor WaitTreeThread::GetColor() const { @@ -424,7 +427,7 @@ void WaitTreeModel::InitItems() { } WaitTreeWidget::WaitTreeWidget(QWidget* parent) : QDockWidget(tr("Wait Tree"), parent) { - setObjectName("WaitTreeWidget"); + setObjectName(QStringLiteral("WaitTreeWidget")); view = new QTreeView(this); view->setHeaderHidden(true); setWidget(view); diff --git a/src/yuzu/util/spinbox.cpp b/src/yuzu/util/spinbox.cpp deleted file mode 100644 index 14ef1e884..000000000 --- a/src/yuzu/util/spinbox.cpp +++ /dev/null @@ -1,278 +0,0 @@ -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -// Copyright 2014 Tony Wasserka -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the owner nor the names of its contributors may -// be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include <cstdlib> -#include <QLineEdit> -#include <QRegExpValidator> -#include "common/assert.h" -#include "yuzu/util/spinbox.h" - -CSpinBox::CSpinBox(QWidget* parent) - : QAbstractSpinBox(parent), min_value(-100), max_value(100), value(0), base(10), num_digits(0) { - // TODO: Might be nice to not immediately call the slot. - // Think of an address that is being replaced by a different one, in which case a lot - // invalid intermediate addresses would be read from during editing. - connect(lineEdit(), &QLineEdit::textEdited, this, &CSpinBox::OnEditingFinished); - - UpdateText(); -} - -void CSpinBox::SetValue(qint64 val) { - auto old_value = value; - value = std::max(std::min(val, max_value), min_value); - - if (old_value != value) { - UpdateText(); - emit ValueChanged(value); - } -} - -void CSpinBox::SetRange(qint64 min, qint64 max) { - min_value = min; - max_value = max; - - SetValue(value); - UpdateText(); -} - -void CSpinBox::stepBy(int steps) { - auto new_value = value; - // Scale number of steps by the currently selected digit - // TODO: Move this code elsewhere and enable it. - // TODO: Support for num_digits==0, too - // TODO: Support base!=16, too - // TODO: Make the cursor not jump back to the end of the line... - /*if (base == 16 && num_digits > 0) { - int digit = num_digits - (lineEdit()->cursorPosition() - prefix.length()) - 1; - digit = std::max(0, std::min(digit, num_digits - 1)); - steps <<= digit * 4; - }*/ - - // Increment "new_value" by "steps", and perform annoying overflow checks, too. - if (steps < 0 && new_value + steps > new_value) { - new_value = std::numeric_limits<qint64>::min(); - } else if (steps > 0 && new_value + steps < new_value) { - new_value = std::numeric_limits<qint64>::max(); - } else { - new_value += steps; - } - - SetValue(new_value); - UpdateText(); -} - -QAbstractSpinBox::StepEnabled CSpinBox::stepEnabled() const { - StepEnabled ret = StepNone; - - if (value > min_value) - ret |= StepDownEnabled; - - if (value < max_value) - ret |= StepUpEnabled; - - return ret; -} - -void CSpinBox::SetBase(int base) { - this->base = base; - - UpdateText(); -} - -void CSpinBox::SetNumDigits(int num_digits) { - this->num_digits = num_digits; - - UpdateText(); -} - -void CSpinBox::SetPrefix(const QString& prefix) { - this->prefix = prefix; - - UpdateText(); -} - -void CSpinBox::SetSuffix(const QString& suffix) { - this->suffix = suffix; - - UpdateText(); -} - -static QString StringToInputMask(const QString& input) { - QString mask = input; - - // ... replace any special characters by their escaped counterparts ... - mask.replace("\\", "\\\\"); - mask.replace("A", "\\A"); - mask.replace("a", "\\a"); - mask.replace("N", "\\N"); - mask.replace("n", "\\n"); - mask.replace("X", "\\X"); - mask.replace("x", "\\x"); - mask.replace("9", "\\9"); - mask.replace("0", "\\0"); - mask.replace("D", "\\D"); - mask.replace("d", "\\d"); - mask.replace("#", "\\#"); - mask.replace("H", "\\H"); - mask.replace("h", "\\h"); - mask.replace("B", "\\B"); - mask.replace("b", "\\b"); - mask.replace(">", "\\>"); - mask.replace("<", "\\<"); - mask.replace("!", "\\!"); - - return mask; -} - -void CSpinBox::UpdateText() { - // If a fixed number of digits is used, we put the line edit in insertion mode by setting an - // input mask. - QString mask; - if (num_digits != 0) { - mask += StringToInputMask(prefix); - - // For base 10 and negative range, demand a single sign character - if (HasSign()) - mask += "X"; // identified as "-" or "+" in the validator - - // Uppercase digits greater than 9. - mask += ">"; - - // Match num_digits digits - // Digits irrelevant to the chosen number base are filtered in the validator - mask += QString("H").repeated(std::max(num_digits, 1)); - - // Switch off case conversion - mask += "!"; - - mask += StringToInputMask(suffix); - } - lineEdit()->setInputMask(mask); - - // Set new text without changing the cursor position. This will cause the cursor to briefly - // appear at the end of the line and then to jump back to its original position. That's - // a bit ugly, but better than having setText() move the cursor permanently all the time. - int cursor_position = lineEdit()->cursorPosition(); - lineEdit()->setText(TextFromValue()); - lineEdit()->setCursorPosition(cursor_position); -} - -QString CSpinBox::TextFromValue() { - return prefix + QString(HasSign() ? ((value < 0) ? "-" : "+") : "") + - QString("%1").arg(std::abs(value), num_digits, base, QLatin1Char('0')).toUpper() + - suffix; -} - -qint64 CSpinBox::ValueFromText() { - unsigned strpos = prefix.length(); - - QString num_string = text().mid(strpos, text().length() - strpos - suffix.length()); - return num_string.toLongLong(nullptr, base); -} - -bool CSpinBox::HasSign() const { - return base == 10 && min_value < 0; -} - -void CSpinBox::OnEditingFinished() { - // Only update for valid input - QString input = lineEdit()->text(); - int pos = 0; - if (QValidator::Acceptable == validate(input, pos)) - SetValue(ValueFromText()); -} - -QValidator::State CSpinBox::validate(QString& input, int& pos) const { - if (!prefix.isEmpty() && input.left(prefix.length()) != prefix) - return QValidator::Invalid; - - int strpos = prefix.length(); - - // Empty "numbers" allowed as intermediate values - if (strpos >= input.length() - HasSign() - suffix.length()) - return QValidator::Intermediate; - - DEBUG_ASSERT(base <= 10 || base == 16); - QString regexp; - - // Demand sign character for negative ranges - if (HasSign()) - regexp += "[+\\-]"; - - // Match digits corresponding to the chosen number base. - regexp += QString("[0-%1").arg(std::min(base, 9)); - if (base == 16) { - regexp += "a-fA-F"; - } - regexp += "]"; - - // Specify number of digits - if (num_digits > 0) { - regexp += QString("{%1}").arg(num_digits); - } else { - regexp += "+"; - } - - // Match string - QRegExp num_regexp(regexp); - int num_pos = strpos; - QString sub_input = input.mid(strpos, input.length() - strpos - suffix.length()); - - if (!num_regexp.exactMatch(sub_input) && num_regexp.matchedLength() == 0) - return QValidator::Invalid; - - sub_input = sub_input.left(num_regexp.matchedLength()); - bool ok; - qint64 val = sub_input.toLongLong(&ok, base); - - if (!ok) - return QValidator::Invalid; - - // Outside boundaries => don't accept - if (val < min_value || val > max_value) - return QValidator::Invalid; - - // Make sure we are actually at the end of this string... - strpos += num_regexp.matchedLength(); - - if (!suffix.isEmpty() && input.mid(strpos) != suffix) { - return QValidator::Invalid; - } else { - strpos += suffix.length(); - } - - if (strpos != input.length()) - return QValidator::Invalid; - - // At this point we can say for sure that the input is fine. Let's fix it up a bit though - input.replace(num_pos, sub_input.length(), sub_input.toUpper()); - - return QValidator::Acceptable; -} diff --git a/src/yuzu/util/spinbox.h b/src/yuzu/util/spinbox.h deleted file mode 100644 index 2fa1db3a4..000000000 --- a/src/yuzu/util/spinbox.h +++ /dev/null @@ -1,86 +0,0 @@ -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -// Copyright 2014 Tony Wasserka -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the owner nor the names of its contributors may -// be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#pragma once - -#include <QAbstractSpinBox> -#include <QtGlobal> - -class QVariant; - -/** - * A custom spin box widget with enhanced functionality over Qt's QSpinBox - */ -class CSpinBox : public QAbstractSpinBox { - Q_OBJECT - -public: - explicit CSpinBox(QWidget* parent = nullptr); - - void stepBy(int steps) override; - StepEnabled stepEnabled() const override; - - void SetValue(qint64 val); - - void SetRange(qint64 min, qint64 max); - - void SetBase(int base); - - void SetPrefix(const QString& prefix); - void SetSuffix(const QString& suffix); - - void SetNumDigits(int num_digits); - - QValidator::State validate(QString& input, int& pos) const override; - -signals: - void ValueChanged(qint64 val); - -private slots: - void OnEditingFinished(); - -private: - void UpdateText(); - - bool HasSign() const; - - QString TextFromValue(); - qint64 ValueFromText(); - - qint64 min_value, max_value; - - qint64 value; - - QString prefix, suffix; - - int base; - - int num_digits; -}; |