early-access version 1365
This commit is contained in:
parent
0b9f90d2c9
commit
678f626689
@ -1,7 +1,7 @@
|
|||||||
yuzu emulator early access
|
yuzu emulator early access
|
||||||
=============
|
=============
|
||||||
|
|
||||||
This is the source code for early-access 1360.
|
This is the source code for early-access 1365.
|
||||||
|
|
||||||
## Legal Notice
|
## Legal Notice
|
||||||
|
|
||||||
|
@ -402,8 +402,6 @@ add_library(core STATIC
|
|||||||
hle/service/ldr/ldr.h
|
hle/service/ldr/ldr.h
|
||||||
hle/service/lm/lm.cpp
|
hle/service/lm/lm.cpp
|
||||||
hle/service/lm/lm.h
|
hle/service/lm/lm.h
|
||||||
hle/service/lm/manager.cpp
|
|
||||||
hle/service/lm/manager.h
|
|
||||||
hle/service/mig/mig.cpp
|
hle/service/mig/mig.cpp
|
||||||
hle/service/mig/mig.h
|
hle/service/mig/mig.h
|
||||||
hle/service/mii/manager.cpp
|
hle/service/mii/manager.cpp
|
||||||
|
@ -36,7 +36,6 @@
|
|||||||
#include "core/hle/service/apm/controller.h"
|
#include "core/hle/service/apm/controller.h"
|
||||||
#include "core/hle/service/filesystem/filesystem.h"
|
#include "core/hle/service/filesystem/filesystem.h"
|
||||||
#include "core/hle/service/glue/manager.h"
|
#include "core/hle/service/glue/manager.h"
|
||||||
#include "core/hle/service/lm/manager.h"
|
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
#include "core/hle/service/sm/sm.h"
|
#include "core/hle/service/sm/sm.h"
|
||||||
#include "core/hle/service/time/time_manager.h"
|
#include "core/hle/service/time/time_manager.h"
|
||||||
@ -293,8 +292,6 @@ struct System::Impl {
|
|||||||
perf_stats->GetMeanFrametime());
|
perf_stats->GetMeanFrametime());
|
||||||
}
|
}
|
||||||
|
|
||||||
lm_manager.Flush();
|
|
||||||
|
|
||||||
is_powered_on = false;
|
is_powered_on = false;
|
||||||
exit_lock = false;
|
exit_lock = false;
|
||||||
|
|
||||||
@ -398,7 +395,6 @@ struct System::Impl {
|
|||||||
|
|
||||||
/// Service State
|
/// Service State
|
||||||
Service::Glue::ARPManager arp_manager;
|
Service::Glue::ARPManager arp_manager;
|
||||||
Service::LM::Manager lm_manager{reporter};
|
|
||||||
Service::Time::TimeManager time_manager;
|
Service::Time::TimeManager time_manager;
|
||||||
|
|
||||||
/// Service manager
|
/// Service manager
|
||||||
@ -720,14 +716,6 @@ const Service::APM::Controller& System::GetAPMController() const {
|
|||||||
return impl->apm_controller;
|
return impl->apm_controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
Service::LM::Manager& System::GetLogManager() {
|
|
||||||
return impl->lm_manager;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Service::LM::Manager& System::GetLogManager() const {
|
|
||||||
return impl->lm_manager;
|
|
||||||
}
|
|
||||||
|
|
||||||
Service::Time::TimeManager& System::GetTimeManager() {
|
Service::Time::TimeManager& System::GetTimeManager() {
|
||||||
return impl->time_manager;
|
return impl->time_manager;
|
||||||
}
|
}
|
||||||
|
@ -62,10 +62,6 @@ namespace Glue {
|
|||||||
class ARPManager;
|
class ARPManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace LM {
|
|
||||||
class Manager;
|
|
||||||
} // namespace LM
|
|
||||||
|
|
||||||
namespace SM {
|
namespace SM {
|
||||||
class ServiceManager;
|
class ServiceManager;
|
||||||
} // namespace SM
|
} // namespace SM
|
||||||
@ -351,9 +347,6 @@ public:
|
|||||||
[[nodiscard]] Service::APM::Controller& GetAPMController();
|
[[nodiscard]] Service::APM::Controller& GetAPMController();
|
||||||
[[nodiscard]] const Service::APM::Controller& GetAPMController() const;
|
[[nodiscard]] const Service::APM::Controller& GetAPMController() const;
|
||||||
|
|
||||||
[[nodiscard]] Service::LM::Manager& GetLogManager();
|
|
||||||
[[nodiscard]] const Service::LM::Manager& GetLogManager() const;
|
|
||||||
|
|
||||||
[[nodiscard]] Service::Time::TimeManager& GetTimeManager();
|
[[nodiscard]] Service::Time::TimeManager& GetTimeManager();
|
||||||
[[nodiscard]] const Service::Time::TimeManager& GetTimeManager() const;
|
[[nodiscard]] const Service::Time::TimeManager& GetTimeManager() const;
|
||||||
|
|
||||||
|
@ -5,22 +5,71 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <boost/container_hash/hash.hpp>
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/scope_exit.h"
|
#include "common/scope_exit.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/hle/ipc_helpers.h"
|
#include "core/hle/ipc_helpers.h"
|
||||||
#include "core/hle/service/lm/lm.h"
|
#include "core/hle/service/lm/lm.h"
|
||||||
#include "core/hle/service/lm/manager.h"
|
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
|
||||||
namespace Service::LM {
|
namespace Service::LM {
|
||||||
|
enum class LogSeverity : u8 {
|
||||||
|
Trace = 0,
|
||||||
|
Info = 1,
|
||||||
|
Warning = 2,
|
||||||
|
Error = 3,
|
||||||
|
Fatal = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
// To keep flags out of hashing as well as the payload size
|
||||||
|
struct LogPacketHeaderEntry {
|
||||||
|
u64_le pid{};
|
||||||
|
u64_le tid{};
|
||||||
|
LogSeverity severity{};
|
||||||
|
u8 verbosity{};
|
||||||
|
|
||||||
|
auto operator<=>(const LogPacketHeaderEntry&) const = default;
|
||||||
|
};
|
||||||
|
} // namespace Service::LM
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
template <>
|
||||||
|
struct hash<Service::LM::LogPacketHeaderEntry> {
|
||||||
|
std::size_t operator()(const Service::LM::LogPacketHeaderEntry& k) const noexcept {
|
||||||
|
std::size_t seed{};
|
||||||
|
boost::hash_combine(seed, k.pid);
|
||||||
|
boost::hash_combine(seed, k.tid);
|
||||||
|
boost::hash_combine(seed, k.severity);
|
||||||
|
boost::hash_combine(seed, k.verbosity);
|
||||||
|
return seed;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
} // namespace std
|
||||||
|
|
||||||
|
namespace Service::LM {
|
||||||
|
|
||||||
|
enum class LogDestination : u32 {
|
||||||
|
TargetManager = 1 << 0,
|
||||||
|
Uart = 1 << 1,
|
||||||
|
UartSleep = 1 << 2,
|
||||||
|
All = 0xffff,
|
||||||
|
};
|
||||||
|
DECLARE_ENUM_FLAG_OPERATORS(LogDestination);
|
||||||
|
|
||||||
|
enum class LogPacketFlags : u8 {
|
||||||
|
Head = 1 << 0,
|
||||||
|
Tail = 1 << 1,
|
||||||
|
LittleEndian = 1 << 2,
|
||||||
|
};
|
||||||
|
DECLARE_ENUM_FLAG_OPERATORS(LogPacketFlags);
|
||||||
|
|
||||||
class ILogger final : public ServiceFramework<ILogger> {
|
class ILogger final : public ServiceFramework<ILogger> {
|
||||||
public:
|
public:
|
||||||
explicit ILogger(Core::System& system_)
|
explicit ILogger(Core::System& system_) : ServiceFramework{system_, "ILogger"} {
|
||||||
: ServiceFramework{system_, "ILogger"}, manager{system_.GetLogManager()},
|
|
||||||
memory{system_.Memory()} {
|
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, &ILogger::Log, "Log"},
|
{0, &ILogger::Log, "Log"},
|
||||||
{1, &ILogger::SetDestination, "SetDestination"},
|
{1, &ILogger::SetDestination, "SetDestination"},
|
||||||
@ -30,54 +79,262 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void Log(Kernel::HLERequestContext& ctx) {
|
void Log(Kernel::HLERequestContext& ctx) {
|
||||||
|
std::size_t offset{};
|
||||||
|
const auto data = ctx.ReadBuffer();
|
||||||
|
|
||||||
// This function only succeeds - Get that out of the way
|
// This function only succeeds - Get that out of the way
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
|
||||||
// Read MessageHeader, despite not doing anything with it right now
|
if (data.size() < sizeof(LogPacketHeader)) {
|
||||||
MessageHeader header{};
|
LOG_ERROR(Service_LM, "Data size is too small for header! size={}", data.size());
|
||||||
VAddr addr{ctx.BufferDescriptorX()[0].Address()};
|
return;
|
||||||
const VAddr end_addr{addr + ctx.BufferDescriptorX()[0].size};
|
|
||||||
memory.ReadBlock(addr, &header, sizeof(MessageHeader));
|
|
||||||
addr += sizeof(MessageHeader);
|
|
||||||
|
|
||||||
FieldMap fields;
|
|
||||||
while (addr < end_addr) {
|
|
||||||
const auto field = static_cast<Field>(memory.Read8(addr++));
|
|
||||||
const auto length = memory.Read8(addr++);
|
|
||||||
|
|
||||||
if (static_cast<Field>(memory.Read8(addr)) == Field::Skip) {
|
|
||||||
++addr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SCOPE_EXIT({ addr += length; });
|
LogPacketHeader header{};
|
||||||
|
std::memcpy(&header, data.data(), sizeof(LogPacketHeader));
|
||||||
|
offset += sizeof(LogPacketHeader);
|
||||||
|
|
||||||
if (field == Field::Skip) {
|
LogPacketHeaderEntry entry{
|
||||||
continue;
|
.pid = header.pid,
|
||||||
|
.tid = header.tid,
|
||||||
|
.severity = header.severity,
|
||||||
|
.verbosity = header.verbosity,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (True(header.flags & LogPacketFlags::Head)) {
|
||||||
|
std::vector<u8> tmp(data.size() - sizeof(LogPacketHeader));
|
||||||
|
std::memcpy(tmp.data(), data.data() + offset, tmp.size());
|
||||||
|
entries[entry] = std::move(tmp);
|
||||||
|
} else {
|
||||||
|
// Append to existing entry
|
||||||
|
if (!entries.contains(entry)) {
|
||||||
|
LOG_ERROR(Service_LM, "Log entry does not exist!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::vector<u8> tmp(data.size() - sizeof(LogPacketHeader));
|
||||||
|
|
||||||
|
auto& existing_entry = entries[entry];
|
||||||
|
const auto base = existing_entry.size();
|
||||||
|
existing_entry.resize(base + (data.size() - sizeof(LogPacketHeader)));
|
||||||
|
std::memcpy(existing_entry.data() + base, data.data() + offset,
|
||||||
|
(data.size() - sizeof(LogPacketHeader)));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<u8> data(length);
|
if (True(header.flags & LogPacketFlags::Tail)) {
|
||||||
memory.ReadBlock(addr, data.data(), length);
|
auto it = entries.find(entry);
|
||||||
fields.emplace(field, std::move(data));
|
if (it == entries.end()) {
|
||||||
|
LOG_ERROR(Service_LM, "Log entry does not exist!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ParseLog(it->first, it->second);
|
||||||
|
entries.erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
manager.Log({header, std::move(fields)});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetDestination(Kernel::HLERequestContext& ctx) {
|
void SetDestination(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto destination = rp.PopEnum<DestinationFlag>();
|
const auto log_destination = rp.PopEnum<LogDestination>();
|
||||||
|
|
||||||
LOG_DEBUG(Service_LM, "called, destination={:08X}", destination);
|
LOG_DEBUG(Service_LM, "called, destination={}", DestinationToString(log_destination));
|
||||||
|
destination = log_destination;
|
||||||
manager.SetDestination(destination);
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
Manager& manager;
|
u32 ReadLeb128(const std::vector<u8>& data, std::size_t& offset) {
|
||||||
Core::Memory::Memory& memory;
|
u32 result{};
|
||||||
|
u32 shift{};
|
||||||
|
do {
|
||||||
|
result |= (data[offset] & 0x7f) << shift;
|
||||||
|
shift += 7;
|
||||||
|
offset++;
|
||||||
|
if (offset >= data.size()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while ((data[offset] & 0x80) != 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::string> ReadString(const std::vector<u8>& data, std::size_t& offset,
|
||||||
|
std::size_t length) {
|
||||||
|
if (length == 0) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
const auto length_to_read = std::min(length, data.size() - offset);
|
||||||
|
|
||||||
|
std::string output(length_to_read, '\0');
|
||||||
|
std::memcpy(output.data(), data.data() + offset, length_to_read);
|
||||||
|
offset += length_to_read;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32_le ReadAsU32(const std::vector<u8>& data, std::size_t& offset, std::size_t length) {
|
||||||
|
ASSERT(length == sizeof(u32));
|
||||||
|
u32_le output{};
|
||||||
|
std::memcpy(&output, data.data() + offset, sizeof(u32));
|
||||||
|
offset += length;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64_le ReadAsU64(const std::vector<u8>& data, std::size_t& offset, std::size_t length) {
|
||||||
|
ASSERT(length == sizeof(u64));
|
||||||
|
u64_le output{};
|
||||||
|
std::memcpy(&output, data.data() + offset, sizeof(u64));
|
||||||
|
offset += length;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ParseLog(const LogPacketHeaderEntry entry, const std::vector<u8>& log_data) {
|
||||||
|
// Possible entries
|
||||||
|
std::optional<std::string> text_log;
|
||||||
|
std::optional<u32> line_number;
|
||||||
|
std::optional<std::string> file_name;
|
||||||
|
std::optional<std::string> function_name;
|
||||||
|
std::optional<std::string> module_name;
|
||||||
|
std::optional<std::string> thread_name;
|
||||||
|
std::optional<u64> log_pack_drop_count;
|
||||||
|
std::optional<s64> user_system_clock;
|
||||||
|
std::optional<std::string> process_name;
|
||||||
|
|
||||||
|
std::size_t offset{};
|
||||||
|
while (offset < log_data.size()) {
|
||||||
|
const auto key = static_cast<LogDataChunkKey>(ReadLeb128(log_data, offset));
|
||||||
|
const auto chunk_size = ReadLeb128(log_data, offset);
|
||||||
|
|
||||||
|
switch (key) {
|
||||||
|
case LogDataChunkKey::LogSessionBegin:
|
||||||
|
case LogDataChunkKey::LogSessionEnd:
|
||||||
|
break;
|
||||||
|
case LogDataChunkKey::TextLog:
|
||||||
|
text_log = ReadString(log_data, offset, chunk_size);
|
||||||
|
break;
|
||||||
|
case LogDataChunkKey::LineNumber:
|
||||||
|
line_number = ReadAsU32(log_data, offset, chunk_size);
|
||||||
|
break;
|
||||||
|
case LogDataChunkKey::FileName:
|
||||||
|
file_name = ReadString(log_data, offset, chunk_size);
|
||||||
|
break;
|
||||||
|
case LogDataChunkKey::FunctionName:
|
||||||
|
function_name = ReadString(log_data, offset, chunk_size);
|
||||||
|
break;
|
||||||
|
case LogDataChunkKey::ModuleName:
|
||||||
|
module_name = ReadString(log_data, offset, chunk_size);
|
||||||
|
break;
|
||||||
|
case LogDataChunkKey::ThreadName:
|
||||||
|
thread_name = ReadString(log_data, offset, chunk_size);
|
||||||
|
break;
|
||||||
|
case LogDataChunkKey::LogPacketDropCount:
|
||||||
|
log_pack_drop_count = ReadAsU64(log_data, offset, chunk_size);
|
||||||
|
break;
|
||||||
|
case LogDataChunkKey::UserSystemClock:
|
||||||
|
user_system_clock = ReadAsU64(log_data, offset, chunk_size);
|
||||||
|
break;
|
||||||
|
case LogDataChunkKey::ProcessName:
|
||||||
|
process_name = ReadString(log_data, offset, chunk_size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string output_log{};
|
||||||
|
if (process_name) {
|
||||||
|
output_log += fmt::format("Process: {}\n", *process_name);
|
||||||
|
}
|
||||||
|
if (module_name) {
|
||||||
|
output_log += fmt::format("Module: {}\n", *module_name);
|
||||||
|
}
|
||||||
|
if (file_name) {
|
||||||
|
output_log += fmt::format("File: {}\n", *file_name);
|
||||||
|
}
|
||||||
|
if (function_name) {
|
||||||
|
output_log += fmt::format("Function: {}\n", *function_name);
|
||||||
|
}
|
||||||
|
if (line_number && *line_number != 0) {
|
||||||
|
output_log += fmt::format("Line: {}\n", *line_number);
|
||||||
|
}
|
||||||
|
output_log += fmt::format("ProcessID: {}\n", entry.pid);
|
||||||
|
output_log += fmt::format("ThreadID: {}\n", entry.tid);
|
||||||
|
|
||||||
|
if (text_log) {
|
||||||
|
output_log += fmt::format("Log Text: {}\n", *text_log);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (entry.severity) {
|
||||||
|
case LogSeverity::Trace:
|
||||||
|
LOG_DEBUG(Service_LM, "LogManager DEBUG ({}):\n{}", DestinationToString(destination),
|
||||||
|
output_log);
|
||||||
|
break;
|
||||||
|
case LogSeverity::Info:
|
||||||
|
LOG_INFO(Service_LM, "LogManager INFO ({}):\n{}", DestinationToString(destination),
|
||||||
|
output_log);
|
||||||
|
break;
|
||||||
|
case LogSeverity::Warning:
|
||||||
|
LOG_WARNING(Service_LM, "LogManager WARNING ({}):\n{}",
|
||||||
|
DestinationToString(destination), output_log);
|
||||||
|
break;
|
||||||
|
case LogSeverity::Error:
|
||||||
|
LOG_ERROR(Service_LM, "LogManager ERROR ({}):\n{}", DestinationToString(destination),
|
||||||
|
output_log);
|
||||||
|
break;
|
||||||
|
case LogSeverity::Fatal:
|
||||||
|
LOG_CRITICAL(Service_LM, "LogManager FATAL ({}):\n{}", DestinationToString(destination),
|
||||||
|
output_log);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_CRITICAL(Service_LM, "LogManager UNKNOWN ({}):\n{}",
|
||||||
|
DestinationToString(destination), output_log);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string DestinationToString(LogDestination destination) {
|
||||||
|
if (True(destination & LogDestination::All)) {
|
||||||
|
return "TargetManager | Uart | UartSleep";
|
||||||
|
}
|
||||||
|
std::string output{};
|
||||||
|
if (True(destination & LogDestination::TargetManager)) {
|
||||||
|
output += "| TargetManager";
|
||||||
|
}
|
||||||
|
if (True(destination & LogDestination::Uart)) {
|
||||||
|
output += "| Uart";
|
||||||
|
}
|
||||||
|
if (True(destination & LogDestination::UartSleep)) {
|
||||||
|
output += "| UartSleep";
|
||||||
|
}
|
||||||
|
if (output.length() > 0) {
|
||||||
|
return output.substr(2);
|
||||||
|
}
|
||||||
|
return "No Destination";
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class LogDataChunkKey : u32 {
|
||||||
|
LogSessionBegin = 0,
|
||||||
|
LogSessionEnd = 1,
|
||||||
|
TextLog = 2,
|
||||||
|
LineNumber = 3,
|
||||||
|
FileName = 4,
|
||||||
|
FunctionName = 5,
|
||||||
|
ModuleName = 6,
|
||||||
|
ThreadName = 7,
|
||||||
|
LogPacketDropCount = 8,
|
||||||
|
UserSystemClock = 9,
|
||||||
|
ProcessName = 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LogPacketHeader {
|
||||||
|
u64_le pid{};
|
||||||
|
u64_le tid{};
|
||||||
|
LogPacketFlags flags{};
|
||||||
|
INSERT_PADDING_BYTES(1);
|
||||||
|
LogSeverity severity{};
|
||||||
|
u8 verbosity{};
|
||||||
|
u32_le payload_size{};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(LogPacketHeader) == 0x18, "LogPacketHeader is an invalid size");
|
||||||
|
|
||||||
|
std::unordered_map<LogPacketHeaderEntry, std::vector<u8>> entries{};
|
||||||
|
LogDestination destination{LogDestination::All};
|
||||||
};
|
};
|
||||||
|
|
||||||
class LM final : public ServiceFramework<LM> {
|
class LM final : public ServiceFramework<LM> {
|
||||||
|
@ -155,8 +155,14 @@ NvResult nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::ve
|
|||||||
return NvResult::BadParameter;
|
return NvResult::BadParameter;
|
||||||
}
|
}
|
||||||
if (events_interface.registered[event_id]) {
|
if (events_interface.registered[event_id]) {
|
||||||
|
const auto event_state = events_interface.status[event_id];
|
||||||
|
if (event_state != EventState::Free) {
|
||||||
|
LOG_WARNING(Service_NVDRV, "Event already registered! Unregistering previous event");
|
||||||
|
events_interface.UnregisterEvent(event_id);
|
||||||
|
} else {
|
||||||
return NvResult::BadParameter;
|
return NvResult::BadParameter;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
events_interface.RegisterEvent(event_id);
|
events_interface.RegisterEvent(event_id);
|
||||||
return NvResult::Success;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
#include "core/hle/kernel/memory/page_table.h"
|
#include "core/hle/kernel/memory/page_table.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
#include "core/hle/service/lm/manager.h"
|
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
#include "core/reporter.h"
|
#include "core/reporter.h"
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
@ -360,55 +359,6 @@ void Reporter::SaveErrorReport(u64 title_id, ResultCode result,
|
|||||||
SaveToFile(std::move(out), GetPath("error_report", title_id, timestamp));
|
SaveToFile(std::move(out), GetPath("error_report", title_id, timestamp));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reporter::SaveLogReport(u32 destination, std::vector<Service::LM::LogMessage> messages) const {
|
|
||||||
if (!IsReportingEnabled()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto timestamp = GetTimestamp();
|
|
||||||
json out;
|
|
||||||
|
|
||||||
out["yuzu_version"] = GetYuzuVersionData();
|
|
||||||
out["report_common"] =
|
|
||||||
GetReportCommonData(system.CurrentProcess()->GetTitleID(), RESULT_SUCCESS, timestamp);
|
|
||||||
|
|
||||||
out["log_destination"] =
|
|
||||||
fmt::format("{}", static_cast<Service::LM::DestinationFlag>(destination));
|
|
||||||
|
|
||||||
auto json_messages = json::array();
|
|
||||||
std::transform(messages.begin(), messages.end(), std::back_inserter(json_messages),
|
|
||||||
[](const Service::LM::LogMessage& message) {
|
|
||||||
json out;
|
|
||||||
out["is_head"] = fmt::format("{}", message.header.IsHeadLog());
|
|
||||||
out["is_tail"] = fmt::format("{}", message.header.IsTailLog());
|
|
||||||
out["pid"] = fmt::format("{:016X}", message.header.pid);
|
|
||||||
out["thread_context"] =
|
|
||||||
fmt::format("{:016X}", message.header.thread_context);
|
|
||||||
out["payload_size"] = fmt::format("{:016X}", message.header.payload_size);
|
|
||||||
out["flags"] = fmt::format("{:04X}", message.header.flags.Value());
|
|
||||||
out["severity"] = fmt::format("{}", message.header.severity.Value());
|
|
||||||
out["verbosity"] = fmt::format("{:02X}", message.header.verbosity);
|
|
||||||
|
|
||||||
auto fields = json::array();
|
|
||||||
std::transform(message.fields.begin(), message.fields.end(),
|
|
||||||
std::back_inserter(fields), [](const auto& kv) {
|
|
||||||
json out;
|
|
||||||
out["type"] = fmt::format("{}", kv.first);
|
|
||||||
out["data"] =
|
|
||||||
Service::LM::FormatField(kv.first, kv.second);
|
|
||||||
return out;
|
|
||||||
});
|
|
||||||
|
|
||||||
out["fields"] = std::move(fields);
|
|
||||||
return out;
|
|
||||||
});
|
|
||||||
|
|
||||||
out["log_messages"] = std::move(json_messages);
|
|
||||||
|
|
||||||
SaveToFile(std::move(out),
|
|
||||||
GetPath("log_report", system.CurrentProcess()->GetTitleID(), timestamp));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Reporter::SaveFilesystemAccessReport(Service::FileSystem::LogMode log_mode,
|
void Reporter::SaveFilesystemAccessReport(Service::FileSystem::LogMode log_mode,
|
||||||
std::string log_message) const {
|
std::string log_message) const {
|
||||||
if (!IsReportingEnabled())
|
if (!IsReportingEnabled())
|
||||||
|
@ -72,9 +72,6 @@ public:
|
|||||||
void SaveFilesystemAccessReport(Service::FileSystem::LogMode log_mode,
|
void SaveFilesystemAccessReport(Service::FileSystem::LogMode log_mode,
|
||||||
std::string log_message) const;
|
std::string log_message) const;
|
||||||
|
|
||||||
// Used by lm services
|
|
||||||
void SaveLogReport(u32 destination, std::vector<Service::LM::LogMessage> messages) const;
|
|
||||||
|
|
||||||
// Can be used anywhere to generate a backtrace and general info report at any point during
|
// Can be used anywhere to generate a backtrace and general info report at any point during
|
||||||
// execution. Not intended to be used for anything other than debugging or testing.
|
// execution. Not intended to be used for anything other than debugging or testing.
|
||||||
void SaveUserReport() const;
|
void SaveUserReport() const;
|
||||||
|
@ -81,10 +81,14 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool RumblePlay(u16 amp_low, u16 amp_high) {
|
bool RumblePlay(u16 amp_low, u16 amp_high) {
|
||||||
|
constexpr u32 rumble_max_duration_ms = 1000;
|
||||||
|
|
||||||
if (sdl_controller) {
|
if (sdl_controller) {
|
||||||
return SDL_GameControllerRumble(sdl_controller.get(), amp_low, amp_high, 0) == 0;
|
return SDL_GameControllerRumble(sdl_controller.get(), amp_low, amp_high,
|
||||||
|
rumble_max_duration_ms) == 0;
|
||||||
} else if (sdl_joystick) {
|
} else if (sdl_joystick) {
|
||||||
return SDL_JoystickRumble(sdl_joystick.get(), amp_low, amp_high, 0) == 0;
|
return SDL_JoystickRumble(sdl_joystick.get(), amp_low, amp_high,
|
||||||
|
rumble_max_duration_ms) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -284,10 +284,10 @@ target_link_libraries(video_core PRIVATE sirit)
|
|||||||
|
|
||||||
if (ENABLE_NSIGHT_AFTERMATH)
|
if (ENABLE_NSIGHT_AFTERMATH)
|
||||||
if (NOT DEFINED ENV{NSIGHT_AFTERMATH_SDK})
|
if (NOT DEFINED ENV{NSIGHT_AFTERMATH_SDK})
|
||||||
message(ERROR "Environment variable NSIGHT_AFTERMATH_SDK has to be provided")
|
message(FATAL_ERROR "Environment variable NSIGHT_AFTERMATH_SDK has to be provided")
|
||||||
endif()
|
endif()
|
||||||
if (NOT WIN32)
|
if (NOT WIN32)
|
||||||
message(ERROR "Nsight Aftermath doesn't support non-Windows platforms")
|
message(FATAL_ERROR "Nsight Aftermath doesn't support non-Windows platforms")
|
||||||
endif()
|
endif()
|
||||||
target_compile_definitions(video_core PRIVATE HAS_NSIGHT_AFTERMATH)
|
target_compile_definitions(video_core PRIVATE HAS_NSIGHT_AFTERMATH)
|
||||||
target_include_directories(video_core PRIVATE "$ENV{NSIGHT_AFTERMATH_SDK}/include")
|
target_include_directories(video_core PRIVATE "$ENV{NSIGHT_AFTERMATH_SDK}/include")
|
||||||
|
@ -140,6 +140,7 @@ void BufferCacheRuntime::BindIndexBuffer(PrimitiveTopology topology, IndexFormat
|
|||||||
u32 offset, [[maybe_unused]] u32 size) {
|
u32 offset, [[maybe_unused]] u32 size) {
|
||||||
VkIndexType vk_index_type = MaxwellToVK::IndexFormat(index_format);
|
VkIndexType vk_index_type = MaxwellToVK::IndexFormat(index_format);
|
||||||
VkDeviceSize vk_offset = offset;
|
VkDeviceSize vk_offset = offset;
|
||||||
|
VkBuffer vk_buffer = buffer;
|
||||||
if (topology == PrimitiveTopology::Quads) {
|
if (topology == PrimitiveTopology::Quads) {
|
||||||
vk_index_type = VK_INDEX_TYPE_UINT32;
|
vk_index_type = VK_INDEX_TYPE_UINT32;
|
||||||
std::tie(buffer, vk_offset) =
|
std::tie(buffer, vk_offset) =
|
||||||
@ -148,8 +149,13 @@ void BufferCacheRuntime::BindIndexBuffer(PrimitiveTopology topology, IndexFormat
|
|||||||
vk_index_type = VK_INDEX_TYPE_UINT16;
|
vk_index_type = VK_INDEX_TYPE_UINT16;
|
||||||
std::tie(buffer, vk_offset) = uint8_pass.Assemble(num_indices, buffer, offset);
|
std::tie(buffer, vk_offset) = uint8_pass.Assemble(num_indices, buffer, offset);
|
||||||
}
|
}
|
||||||
scheduler.Record([buffer, vk_offset, vk_index_type](vk::CommandBuffer cmdbuf) {
|
if (vk_buffer == VK_NULL_HANDLE) {
|
||||||
cmdbuf.BindIndexBuffer(buffer, vk_offset, vk_index_type);
|
// Vulkan doesn't support null index buffers. Replace it with our own null buffer.
|
||||||
|
ReserveNullIndexBuffer();
|
||||||
|
vk_buffer = *null_index_buffer;
|
||||||
|
}
|
||||||
|
scheduler.Record([vk_buffer, vk_offset, vk_index_type](vk::CommandBuffer cmdbuf) {
|
||||||
|
cmdbuf.BindIndexBuffer(vk_buffer, vk_offset, vk_index_type);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,4 +282,29 @@ void BufferCacheRuntime::ReserveQuadArrayLUT(u32 num_indices, bool wait_for_idle
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BufferCacheRuntime::ReserveNullIndexBuffer() {
|
||||||
|
if (null_index_buffer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
null_index_buffer = device.GetLogical().CreateBuffer(VkBufferCreateInfo{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.flags = 0,
|
||||||
|
.size = 4,
|
||||||
|
.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||||
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||||
|
.queueFamilyIndexCount = 0,
|
||||||
|
.pQueueFamilyIndices = nullptr,
|
||||||
|
});
|
||||||
|
if (device.HasDebuggingToolAttached()) {
|
||||||
|
null_index_buffer.SetObjectNameEXT("Null index buffer");
|
||||||
|
}
|
||||||
|
null_index_buffer_commit = memory_allocator.Commit(null_index_buffer, MemoryUsage::DeviceLocal);
|
||||||
|
|
||||||
|
scheduler.RequestOutsideRenderPassOperationContext();
|
||||||
|
scheduler.Record([buffer = *null_index_buffer](vk::CommandBuffer cmdbuf) {
|
||||||
|
cmdbuf.FillBuffer(buffer, 0, VK_WHOLE_SIZE, 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
@ -90,6 +90,8 @@ private:
|
|||||||
|
|
||||||
void ReserveQuadArrayLUT(u32 num_indices, bool wait_for_idle);
|
void ReserveQuadArrayLUT(u32 num_indices, bool wait_for_idle);
|
||||||
|
|
||||||
|
void ReserveNullIndexBuffer();
|
||||||
|
|
||||||
const Device& device;
|
const Device& device;
|
||||||
MemoryAllocator& memory_allocator;
|
MemoryAllocator& memory_allocator;
|
||||||
VKScheduler& scheduler;
|
VKScheduler& scheduler;
|
||||||
@ -101,6 +103,9 @@ private:
|
|||||||
VkIndexType quad_array_lut_index_type{};
|
VkIndexType quad_array_lut_index_type{};
|
||||||
u32 current_num_indices = 0;
|
u32 current_num_indices = 0;
|
||||||
|
|
||||||
|
vk::Buffer null_index_buffer;
|
||||||
|
MemoryCommit null_index_buffer_commit;
|
||||||
|
|
||||||
Uint8Pass uint8_pass;
|
Uint8Pass uint8_pass;
|
||||||
QuadIndexedPass quad_index_pass;
|
QuadIndexedPass quad_index_pass;
|
||||||
};
|
};
|
||||||
|
@ -392,7 +392,7 @@ void ShaderIR::SetInternalFlagsFromInteger(NodeBlock& bb, Node value, bool sets_
|
|||||||
case 0: // Operation Node
|
case 0: // Operation Node
|
||||||
SearchOperands(bb, value);
|
SearchOperands(bb, value);
|
||||||
break;
|
break;
|
||||||
case 2: // Genral Purpose Node
|
case 2: // General Purpose Node
|
||||||
if (const auto* gpr = std::get_if<GprNode>(value.get())) {
|
if (const auto* gpr = std::get_if<GprNode>(value.get())) {
|
||||||
LOG_DEBUG(HW_GPU, "GprNode: index={}", gpr->GetIndex());
|
LOG_DEBUG(HW_GPU, "GprNode: index={}", gpr->GetIndex());
|
||||||
Node zerop = Operation(OperationCode::LogicalIEqual, std::move(value),
|
Node zerop = Operation(OperationCode::LogicalIEqual, std::move(value),
|
||||||
|
@ -12,21 +12,12 @@
|
|||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#define VK_NO_PROTOTYPES
|
|
||||||
#include <vulkan/vulkan.h>
|
|
||||||
|
|
||||||
#include <GFSDK_Aftermath.h>
|
|
||||||
#include <GFSDK_Aftermath_Defines.h>
|
|
||||||
#include <GFSDK_Aftermath_GpuCrashDump.h>
|
|
||||||
#include <GFSDK_Aftermath_GpuCrashDumpDecoding.h>
|
|
||||||
|
|
||||||
#include "common/common_paths.h"
|
#include "common/common_paths.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/file_util.h"
|
#include "common/file_util.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/scope_exit.h"
|
#include "common/scope_exit.h"
|
||||||
|
#include "video_core/vulkan_common/nsight_aftermath_tracker.h"
|
||||||
#include "video_core/renderer_vulkan/nsight_aftermath_tracker.h"
|
|
||||||
|
|
||||||
namespace Vulkan {
|
namespace Vulkan {
|
||||||
|
|
||||||
@ -53,7 +44,7 @@ NsightAftermathTracker::NsightAftermathTracker() {
|
|||||||
!dl.GetSymbol("GFSDK_Aftermath_GpuCrashDump_GetJSON",
|
!dl.GetSymbol("GFSDK_Aftermath_GpuCrashDump_GetJSON",
|
||||||
&GFSDK_Aftermath_GpuCrashDump_GetJSON)) {
|
&GFSDK_Aftermath_GpuCrashDump_GetJSON)) {
|
||||||
LOG_ERROR(Render_Vulkan, "Failed to load Nsight Aftermath function pointers");
|
LOG_ERROR(Render_Vulkan, "Failed to load Nsight Aftermath function pointers");
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
dump_dir = Common::FS::GetUserPath(Common::FS::UserPath::LogDir) + "gpucrash";
|
dump_dir = Common::FS::GetUserPath(Common::FS::UserPath::LogDir) + "gpucrash";
|
||||||
|
|
||||||
|
@ -8,16 +8,16 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "common/dynamic_library.h"
|
||||||
|
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||||
|
|
||||||
#ifdef HAS_NSIGHT_AFTERMATH
|
#ifdef HAS_NSIGHT_AFTERMATH
|
||||||
#include <GFSDK_Aftermath_Defines.h>
|
#include <GFSDK_Aftermath_Defines.h>
|
||||||
#include <GFSDK_Aftermath_GpuCrashDump.h>
|
#include <GFSDK_Aftermath_GpuCrashDump.h>
|
||||||
#include <GFSDK_Aftermath_GpuCrashDumpDecoding.h>
|
#include <GFSDK_Aftermath_GpuCrashDumpDecoding.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "common/dynamic_library.h"
|
|
||||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
|
||||||
|
|
||||||
namespace Vulkan {
|
namespace Vulkan {
|
||||||
|
|
||||||
class NsightAftermathTracker {
|
class NsightAftermathTracker {
|
||||||
|
@ -444,6 +444,11 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
|||||||
"Blacklisting AMD proprietary on RDNA devices from VK_EXT_extended_dynamic_state");
|
"Blacklisting AMD proprietary on RDNA devices from VK_EXT_extended_dynamic_state");
|
||||||
ext_extended_dynamic_state = false;
|
ext_extended_dynamic_state = false;
|
||||||
}
|
}
|
||||||
|
if (is_float16_supported && driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS) {
|
||||||
|
// Intel's compiler crashes when using fp16 on Astral Chain, disable it for the time being.
|
||||||
|
LOG_WARNING(Render_Vulkan, "Blacklisting Intel proprietary from float16 math");
|
||||||
|
is_float16_supported = false;
|
||||||
|
}
|
||||||
|
|
||||||
graphics_queue = logical.GetQueue(graphics_family);
|
graphics_queue = logical.GetQueue(graphics_family);
|
||||||
present_queue = logical.GetQueue(present_family);
|
present_queue = logical.GetQueue(present_family);
|
||||||
|
Loading…
Reference in New Issue
Block a user