Compare commits

..

1 Commits

Author SHA1 Message Date
Subv
5c49e56d41 GPU: Implement the NVGPU_IOCTL_CHANNEL_KICKOFF_PB ioctl2 command.
This behaves quite similarly to the SubmitGPFIFO command. Referenced from Ryujinx.
Many thanks to @gdkchan for investigating this!
2018-07-21 15:50:02 -05:00
14 changed files with 107 additions and 91 deletions

View File

@@ -26,7 +26,7 @@
#define USA_DIR "USA"
#define JAP_DIR "JAP"
// Subdirs in the User dir returned by GetUserPath(UserPath::UserDir)
// Subdirs in the User dir returned by GetUserPath(D_USER_IDX)
#define CONFIG_DIR "config"
#define CACHE_DIR "cache"
#define SDMC_DIR "sdmc"
@@ -35,11 +35,11 @@
#define LOG_DIR "log"
// Filenames
// Files in the directory returned by GetUserPath(UserPath::ConfigDir)
// Files in the directory returned by GetUserPath(D_CONFIG_IDX)
#define EMU_CONFIG "emu.ini"
#define DEBUGGER_CONFIG "debugger.ini"
#define LOGGER_CONFIG "logger.ini"
// Files in the directory returned by GetUserPath(UserPath::LogDir)
// Files in the directory returned by GetUserPath(D_LOGS_IDX)
#define LOG_FILE "yuzu_log.txt"
// Sys files

View File

@@ -3,7 +3,6 @@
// Refer to the license.txt file included.
#include <sstream>
#include <unordered_map>
#include "common/assert.h"
#include "common/common_funcs.h"
#include "common/common_paths.h"
@@ -682,68 +681,67 @@ std::string GetSysDirectory() {
// Returns a string with a yuzu data dir or file in the user's home
// directory. To be used in "multi-user" mode (that is, installed).
const std::string& GetUserPath(UserPath path, const std::string& new_path) {
static std::unordered_map<UserPath, std::string> paths;
auto& user_path = paths[UserPath::UserDir];
const std::string& GetUserPath(const unsigned int DirIDX, const std::string& newPath) {
static std::string paths[NUM_PATH_INDICES];
// Set up all paths and files on the first run
if (user_path.empty()) {
if (paths[D_USER_IDX].empty()) {
#ifdef _WIN32
user_path = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP;
if (!FileUtil::IsDirectory(user_path)) {
user_path = AppDataRoamingDirectory() + DIR_SEP EMU_DATA_DIR DIR_SEP;
paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP;
if (!FileUtil::IsDirectory(paths[D_USER_IDX])) {
paths[D_USER_IDX] = AppDataRoamingDirectory() + DIR_SEP EMU_DATA_DIR DIR_SEP;
} else {
LOG_INFO(Common_Filesystem, "Using the local user directory");
}
paths.emplace(UserPath::ConfigDir, user_path + CONFIG_DIR DIR_SEP);
paths.emplace(UserPath::CacheDir, user_path + CACHE_DIR DIR_SEP);
paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
#else
if (FileUtil::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) {
user_path = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP;
paths.emplace(UserPath::ConfigDir, user_path + CONFIG_DIR DIR_SEP);
paths.emplace(UserPath::CacheDir, user_path + CACHE_DIR DIR_SEP);
paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP;
paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
} else {
std::string data_dir = GetUserDirectory("XDG_DATA_HOME");
std::string config_dir = GetUserDirectory("XDG_CONFIG_HOME");
std::string cache_dir = GetUserDirectory("XDG_CACHE_HOME");
user_path = data_dir + DIR_SEP EMU_DATA_DIR DIR_SEP;
paths.emplace(UserPath::ConfigDir, config_dir + DIR_SEP EMU_DATA_DIR DIR_SEP);
paths.emplace(UserPath::CacheDir, cache_dir + DIR_SEP EMU_DATA_DIR DIR_SEP);
paths[D_USER_IDX] = data_dir + DIR_SEP EMU_DATA_DIR DIR_SEP;
paths[D_CONFIG_IDX] = config_dir + DIR_SEP EMU_DATA_DIR DIR_SEP;
paths[D_CACHE_IDX] = cache_dir + DIR_SEP EMU_DATA_DIR DIR_SEP;
}
#endif
paths.emplace(UserPath::SDMCDir, user_path + SDMC_DIR DIR_SEP);
paths.emplace(UserPath::NANDDir, user_path + NAND_DIR DIR_SEP);
paths.emplace(UserPath::SysDataDir, user_path + SYSDATA_DIR DIR_SEP);
paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP;
paths[D_NAND_IDX] = paths[D_USER_IDX] + NAND_DIR DIR_SEP;
paths[D_SYSDATA_IDX] = paths[D_USER_IDX] + SYSDATA_DIR DIR_SEP;
// TODO: Put the logs in a better location for each OS
paths.emplace(UserPath::LogDir, user_path + LOG_DIR DIR_SEP);
paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOG_DIR DIR_SEP;
}
if (!new_path.empty()) {
if (!FileUtil::IsDirectory(new_path)) {
LOG_ERROR(Common_Filesystem, "Invalid path specified {}", new_path);
return paths[path];
if (!newPath.empty()) {
if (!FileUtil::IsDirectory(newPath)) {
LOG_ERROR(Common_Filesystem, "Invalid path specified {}", newPath);
return paths[DirIDX];
} else {
paths[path] = new_path;
paths[DirIDX] = newPath;
}
switch (path) {
case UserPath::RootDir:
user_path = paths[UserPath::RootDir] + DIR_SEP;
switch (DirIDX) {
case D_ROOT_IDX:
paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP;
break;
case UserPath::UserDir:
user_path = paths[UserPath::RootDir] + DIR_SEP;
paths[UserPath::ConfigDir] = user_path + CONFIG_DIR DIR_SEP;
paths[UserPath::CacheDir] = user_path + CACHE_DIR DIR_SEP;
paths[UserPath::SDMCDir] = user_path + SDMC_DIR DIR_SEP;
paths[UserPath::NANDDir] = user_path + NAND_DIR DIR_SEP;
case D_USER_IDX:
paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP;
paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP;
paths[D_NAND_IDX] = paths[D_USER_IDX] + NAND_DIR DIR_SEP;
break;
}
}
return paths[path];
return paths[DirIDX];
}
size_t WriteStringToFile(bool text_file, const std::string& str, const char* filename) {

View File

@@ -16,20 +16,21 @@
#include "common/string_util.h"
#endif
namespace FileUtil {
// User paths for GetUserPath
enum class UserPath {
CacheDir,
ConfigDir,
LogDir,
NANDDir,
RootDir,
SDMCDir,
SysDataDir,
UserDir,
// User directory indices for GetUserPath
enum {
D_USER_IDX,
D_ROOT_IDX,
D_CONFIG_IDX,
D_CACHE_IDX,
D_SDMC_IDX,
D_NAND_IDX,
D_SYSDATA_IDX,
D_LOGS_IDX,
NUM_PATH_INDICES
};
namespace FileUtil {
// FileSystem tree node/
struct FSTEntry {
bool isDirectory;
@@ -122,7 +123,7 @@ bool SetCurrentDir(const std::string& directory);
// Returns a pointer to a string with a yuzu data dir in the user's home
// directory. To be used in "multi-user" mode (that is, installed).
const std::string& GetUserPath(UserPath path, const std::string& new_path = "");
const std::string& GetUserPath(const unsigned int DirIDX, const std::string& newPath = "");
// Returns the path to where the sys file are
std::string GetSysDirectory();

View File

@@ -272,9 +272,9 @@ void RegisterFileSystems() {
sdmc_factory = nullptr;
auto nand_directory = std::make_shared<FileSys::RealVfsDirectory>(
FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), FileSys::Mode::Write);
FileUtil::GetUserPath(D_NAND_IDX), FileSys::Mode::Write);
auto sd_directory = std::make_shared<FileSys::RealVfsDirectory>(
FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir), FileSys::Mode::Write);
FileUtil::GetUserPath(D_SDMC_IDX), FileSys::Mode::Write);
auto savedata = std::make_unique<FileSys::SaveDataFactory>(std::move(nand_directory));
save_data_factory = std::move(savedata);

View File

@@ -42,7 +42,7 @@ PL_U::PL_U() : ServiceFramework("pl:u") {
RegisterHandlers(functions);
// Attempt to load shared font data from disk
const std::string filepath{FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir) + SHARED_FONT};
const std::string filepath{FileUtil::GetUserPath(D_SYSDATA_IDX) + SHARED_FONT};
FileUtil::CreateFullPath(filepath); // Create path if not already created
FileUtil::IOFile file(filepath, "rb");

View File

@@ -42,6 +42,9 @@ u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u
if (command.cmd == NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO) {
return SubmitGPFIFO(input, output);
}
if (command.cmd == NVGPU_IOCTL_CHANNEL_KICKOFF_PB) {
return KickoffPB(input, output);
}
}
UNIMPLEMENTED_MSG("Unimplemented ioctl");
@@ -127,14 +130,37 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& outp
IoctlSubmitGpfifo params{};
std::memcpy(&params, input.data(), sizeof(IoctlSubmitGpfifo));
LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}",
params.gpfifo, params.num_entries, params.flags);
params.address, params.num_entries, params.flags);
auto entries = std::vector<IoctlGpfifoEntry>();
entries.resize(params.num_entries);
std::memcpy(&entries[0], &input.data()[sizeof(IoctlSubmitGpfifo)],
params.num_entries * sizeof(IoctlGpfifoEntry));
for (auto entry : entries) {
VAddr va_addr = entry.Address();
Tegra::GPUVAddr va_addr = entry.Address();
Core::System::GetInstance().GPU().ProcessCommandList(va_addr, entry.sz);
}
params.fence_out.id = 0;
params.fence_out.value = 0;
std::memcpy(output.data(), &params, output.size());
return 0;
}
u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output) {
if (input.size() < sizeof(IoctlSubmitGpfifo)) {
UNIMPLEMENTED();
}
IoctlSubmitGpfifo params{};
std::memcpy(&params, input.data(), sizeof(IoctlSubmitGpfifo));
LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}",
params.address, params.num_entries, params.flags);
std::vector<IoctlGpfifoEntry> entries(params.num_entries);
Memory::ReadBlock(params.address, entries.data(),
params.num_entries * sizeof(IoctlGpfifoEntry));
for (auto entry : entries) {
Tegra::GPUVAddr va_addr = entry.Address();
Core::System::GetInstance().GPU().ProcessCommandList(va_addr, entry.sz);
}
params.fence_out.id = 0;

View File

@@ -15,6 +15,7 @@ namespace Service::Nvidia::Devices {
class nvmap;
constexpr u32 NVGPU_IOCTL_MAGIC('H');
constexpr u32 NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO(0x8);
constexpr u32 NVGPU_IOCTL_CHANNEL_KICKOFF_PB(0x1b);
class nvhost_gpu final : public nvdevice {
public:
@@ -158,14 +159,14 @@ private:
BitField<31, 1, u32_le> unk2;
};
VAddr Address() const {
return (static_cast<VAddr>(gpu_va_hi) << 32) | entry0;
Tegra::GPUVAddr Address() const {
return (static_cast<Tegra::GPUVAddr>(gpu_va_hi) << 32) | entry0;
}
};
static_assert(sizeof(IoctlGpfifoEntry) == 8, "IoctlGpfifoEntry is incorrect size");
struct IoctlSubmitGpfifo {
u64_le gpfifo; // (ignored) pointer to gpfifo fence structs
u64_le address; // pointer to gpfifo entry structs
u32_le num_entries; // number of fence objects being submitted
u32_le flags;
IoctlFence fence_out; // returned new fence object for others to wait on
@@ -193,6 +194,7 @@ private:
u32 AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output);
u32 AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output);
u32 SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output);
u32 KickoffPB(const std::vector<u8>& input, std::vector<u8>& output);
u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
u32 ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output);

View File

@@ -101,7 +101,7 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name)
{8, &NVDRV::SetClientPID, "SetClientPID"},
{9, nullptr, "DumpGraphicsMemoryInfo"},
{10, nullptr, "InitializeDevtools"},
{11, nullptr, "Ioctl2"},
{11, &NVDRV::Ioctl, "Ioctl2"},
{12, nullptr, "Ioctl3"},
{13, &NVDRV::FinishInitialize, "FinishInitialize"},
};

View File

@@ -37,8 +37,7 @@ static u64 GenerateTelemetryId() {
u64 GetTelemetryId() {
u64 telemetry_id{};
static const std::string& filename{FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) +
"telemetry_id"};
static const std::string& filename{FileUtil::GetUserPath(D_CONFIG_IDX) + "telemetry_id"};
if (FileUtil::Exists(filename)) {
FileUtil::IOFile file(filename, "rb");
@@ -62,8 +61,7 @@ u64 GetTelemetryId() {
u64 RegenerateTelemetryId() {
const u64 new_telemetry_id{GenerateTelemetryId()};
static const std::string& filename{FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) +
"telemetry_id"};
static const std::string& filename{FileUtil::GetUserPath(D_CONFIG_IDX) + "telemetry_id"};
FileUtil::IOFile file(filename, "wb");
if (!file.IsOpen()) {

View File

@@ -10,7 +10,7 @@
Config::Config() {
// TODO: Don't hardcode the path; let the frontend decide where to put the config files.
qt_config_loc = FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) + "qt-config.ini";
qt_config_loc = FileUtil::GetUserPath(D_CONFIG_IDX) + "qt-config.ini";
FileUtil::CreateFullPath(qt_config_loc);
qt_config = new QSettings(QString::fromStdString(qt_config_loc), QSettings::IniFormat);

View File

@@ -19,7 +19,7 @@ ConfigureDebug::ConfigureDebug(QWidget* parent) : QWidget(parent), ui(new Ui::Co
ui->setupUi(this);
this->setConfiguration();
connect(ui->open_log_button, &QPushButton::pressed, []() {
QString path = QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::LogDir));
QString path = QString::fromStdString(FileUtil::GetUserPath(D_LOGS_IDX));
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
});
}

View File

@@ -909,16 +909,6 @@ void GMainWindow::UpdateUITheme() {
#undef main
#endif
static void InitializeLogging() {
Log::Filter log_filter;
log_filter.ParseFilterString(Settings::values.log_filter);
Log::SetGlobalFilter(log_filter);
const std::string& log_dir = FileUtil::GetUserPath(FileUtil::UserPath::LogDir);
FileUtil::CreateFullPath(log_dir);
Log::AddBackend(std::make_unique<Log::FileBackend>(log_dir + LOG_FILE));
}
int main(int argc, char* argv[]) {
MicroProfileOnThreadCreate("Frontend");
SCOPE_EXIT({ MicroProfileShutdown(); });
@@ -937,7 +927,13 @@ int main(int argc, char* argv[]) {
GMainWindow main_window;
// After settings have been loaded by GMainWindow, apply the filter
InitializeLogging();
Log::Filter log_filter;
log_filter.ParseFilterString(Settings::values.log_filter);
Log::SetGlobalFilter(log_filter);
FileUtil::CreateFullPath(FileUtil::GetUserPath(D_LOGS_IDX));
Log::AddBackend(
std::make_unique<Log::FileBackend>(FileUtil::GetUserPath(D_LOGS_IDX) + LOG_FILE));
main_window.show();
return app.exec();
}

View File

@@ -15,7 +15,7 @@
Config::Config() {
// TODO: Don't hardcode the path; let the frontend decide where to put the config files.
sdl2_config_loc = FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) + "sdl2-config.ini";
sdl2_config_loc = FileUtil::GetUserPath(D_CONFIG_IDX) + "sdl2-config.ini";
sdl2_config = std::make_unique<INIReader>(sdl2_config_loc);
Reload();

View File

@@ -56,18 +56,6 @@ static void PrintVersion() {
std::cout << "yuzu " << Common::g_scm_branch << " " << Common::g_scm_desc << std::endl;
}
static void InitializeLogging() {
Log::Filter log_filter(Log::Level::Debug);
log_filter.ParseFilterString(Settings::values.log_filter);
Log::SetGlobalFilter(log_filter);
Log::AddBackend(std::make_unique<Log::ColorConsoleBackend>());
const std::string& log_dir = FileUtil::GetUserPath(FileUtil::UserPath::LogDir);
FileUtil::CreateFullPath(log_dir);
Log::AddBackend(std::make_unique<Log::FileBackend>(log_dir + LOG_FILE));
}
/// Application entry point
int main(int argc, char** argv) {
Config config;
@@ -136,7 +124,14 @@ int main(int argc, char** argv) {
LocalFree(argv_w);
#endif
InitializeLogging();
Log::Filter log_filter(Log::Level::Debug);
log_filter.ParseFilterString(Settings::values.log_filter);
Log::SetGlobalFilter(log_filter);
Log::AddBackend(std::make_unique<Log::ColorConsoleBackend>());
FileUtil::CreateFullPath(FileUtil::GetUserPath(D_LOGS_IDX));
Log::AddBackend(
std::make_unique<Log::FileBackend>(FileUtil::GetUserPath(D_LOGS_IDX) + LOG_FILE));
MicroProfileOnThreadCreate("EmuThread");
SCOPE_EXIT({ MicroProfileShutdown(); });