Compare commits

..

3 Commits

Author SHA1 Message Date
unknown
f27c65eb91 Use QString instead of std::string where applicable 2019-02-08 14:18:41 +01:00
Mat M
996ddb202b Use constexpr char array instead of string where applicable
Co-Authored-By: FreddyFunk <frederic.laing.development@gmail.com>
2019-02-08 14:03:10 +01:00
unknown
9d411699d8 frontend: Open transferable shader cache for a selected game in the gamelist 2019-02-08 09:05:51 +01:00
10 changed files with 96 additions and 59 deletions

View File

@@ -5,12 +5,12 @@ add_library(video_core STATIC
debug_utils/debug_utils.h
engines/fermi_2d.cpp
engines/fermi_2d.h
engines/kepler_compute.cpp
engines/kepler_compute.h
engines/kepler_memory.cpp
engines/kepler_memory.h
engines/maxwell_3d.cpp
engines/maxwell_3d.h
engines/maxwell_compute.cpp
engines/maxwell_compute.h
engines/maxwell_dma.cpp
engines/maxwell_dma.h
engines/shader_bytecode.h

View File

@@ -1,34 +0,0 @@
// Copyright 2018 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/logging/log.h"
#include "core/core.h"
#include "core/memory.h"
#include "video_core/engines/kepler_compute.h"
#include "video_core/memory_manager.h"
namespace Tegra::Engines {
KeplerCompute::KeplerCompute(MemoryManager& memory_manager) : memory_manager{memory_manager} {}
KeplerCompute::~KeplerCompute() = default;
void KeplerCompute::CallMethod(const GPU::MethodCall& method_call) {
ASSERT_MSG(method_call.method < Regs::NUM_REGS,
"Invalid KeplerCompute register, increase the size of the Regs structure");
regs.reg_array[method_call.method] = method_call.argument;
switch (method_call.method) {
case KEPLER_COMPUTE_REG_INDEX(launch):
// Abort execution since compute shaders can be used to alter game memory (e.g. CUDA
// kernels)
UNREACHABLE_MSG("Compute shaders are not implemented");
break;
default:
break;
}
}
} // namespace Tegra::Engines

View File

@@ -0,0 +1,28 @@
// Copyright 2018 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/logging/log.h"
#include "core/core.h"
#include "video_core/engines/maxwell_compute.h"
namespace Tegra::Engines {
void MaxwellCompute::CallMethod(const GPU::MethodCall& method_call) {
ASSERT_MSG(method_call.method < Regs::NUM_REGS,
"Invalid MaxwellCompute register, increase the size of the Regs structure");
regs.reg_array[method_call.method] = method_call.argument;
switch (method_call.method) {
case MAXWELL_COMPUTE_REG_INDEX(compute): {
LOG_CRITICAL(HW_GPU, "Compute shaders are not implemented");
UNREACHABLE();
break;
}
default:
break;
}
}
} // namespace Tegra::Engines

View File

@@ -10,48 +10,47 @@
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "video_core/gpu.h"
#include "video_core/memory_manager.h"
namespace Tegra::Engines {
#define KEPLER_COMPUTE_REG_INDEX(field_name) \
(offsetof(Tegra::Engines::KeplerCompute::Regs, field_name) / sizeof(u32))
#define MAXWELL_COMPUTE_REG_INDEX(field_name) \
(offsetof(Tegra::Engines::MaxwellCompute::Regs, field_name) / sizeof(u32))
class KeplerCompute final {
class MaxwellCompute final {
public:
explicit KeplerCompute(MemoryManager& memory_manager);
~KeplerCompute();
static constexpr std::size_t NumConstBuffers = 8;
MaxwellCompute() = default;
~MaxwellCompute() = default;
struct Regs {
static constexpr std::size_t NUM_REGS = 0xCF8;
union {
struct {
INSERT_PADDING_WORDS(0xAF);
INSERT_PADDING_WORDS(0x281);
u32 launch;
union {
u32 compute_end;
BitField<0, 1, u32> unknown;
} compute;
INSERT_PADDING_WORDS(0xC48);
INSERT_PADDING_WORDS(0xA76);
};
std::array<u32, NUM_REGS> reg_array;
};
} regs{};
static_assert(sizeof(Regs) == Regs::NUM_REGS * sizeof(u32),
"KeplerCompute Regs has wrong size");
MemoryManager& memory_manager;
static_assert(sizeof(Regs) == Regs::NUM_REGS * sizeof(u32),
"MaxwellCompute Regs has wrong size");
/// Write the value to the register identified by method.
void CallMethod(const GPU::MethodCall& method_call);
};
#define ASSERT_REG_POSITION(field_name, position) \
static_assert(offsetof(KeplerCompute::Regs, field_name) == position * 4, \
static_assert(offsetof(MaxwellCompute::Regs, field_name) == position * 4, \
"Field " #field_name " has invalid position")
ASSERT_REG_POSITION(launch, 0xAF);
ASSERT_REG_POSITION(compute, 0x281);
#undef ASSERT_REG_POSITION

View File

@@ -6,9 +6,9 @@
#include "core/core_timing.h"
#include "core/memory.h"
#include "video_core/engines/fermi_2d.h"
#include "video_core/engines/kepler_compute.h"
#include "video_core/engines/kepler_memory.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/engines/maxwell_compute.h"
#include "video_core/engines/maxwell_dma.h"
#include "video_core/gpu.h"
#include "video_core/rasterizer_interface.h"
@@ -31,7 +31,7 @@ GPU::GPU(VideoCore::RasterizerInterface& rasterizer) {
dma_pusher = std::make_unique<Tegra::DmaPusher>(*this);
maxwell_3d = std::make_unique<Engines::Maxwell3D>(rasterizer, *memory_manager);
fermi_2d = std::make_unique<Engines::Fermi2D>(rasterizer, *memory_manager);
kepler_compute = std::make_unique<Engines::KeplerCompute>(*memory_manager);
maxwell_compute = std::make_unique<Engines::MaxwellCompute>();
maxwell_dma = std::make_unique<Engines::MaxwellDMA>(rasterizer, *memory_manager);
kepler_memory = std::make_unique<Engines::KeplerMemory>(rasterizer, *memory_manager);
}
@@ -245,8 +245,8 @@ void GPU::CallEngineMethod(const MethodCall& method_call) {
case EngineID::MAXWELL_B:
maxwell_3d->CallMethod(method_call);
break;
case EngineID::KEPLER_COMPUTE_B:
kepler_compute->CallMethod(method_call);
case EngineID::MAXWELL_COMPUTE_B:
maxwell_compute->CallMethod(method_call);
break;
case EngineID::MAXWELL_DMA_COPY_A:
maxwell_dma->CallMethod(method_call);

View File

@@ -102,15 +102,15 @@ struct FramebufferConfig {
namespace Engines {
class Fermi2D;
class Maxwell3D;
class MaxwellCompute;
class MaxwellDMA;
class KeplerCompute;
class KeplerMemory;
} // namespace Engines
enum class EngineID {
FERMI_TWOD_A = 0x902D, // 2D Engine
MAXWELL_B = 0xB197, // 3D Engine
KEPLER_COMPUTE_B = 0xB1C0,
MAXWELL_COMPUTE_B = 0xB1C0,
KEPLER_INLINE_TO_MEMORY_B = 0xA140,
MAXWELL_DMA_COPY_A = 0xB0B5,
};
@@ -208,7 +208,7 @@ private:
/// 2D engine
std::unique_ptr<Engines::Fermi2D> fermi_2d;
/// Compute engine
std::unique_ptr<Engines::KeplerCompute> kepler_compute;
std::unique_ptr<Engines::MaxwellCompute> maxwell_compute;
/// DMA engine
std::unique_ptr<Engines::MaxwellDMA> maxwell_dma;
/// Inline memory engine

View File

@@ -329,6 +329,8 @@ void GameList::PopupContextMenu(const QPoint& menu_location) {
QMenu context_menu;
QAction* open_save_location = context_menu.addAction(tr("Open Save Data Location"));
QAction* open_lfs_location = context_menu.addAction(tr("Open Mod Data Location"));
QAction* open_transferable_shader_cache =
context_menu.addAction(tr("Open Transferable Shader Cache"));
context_menu.addSeparator();
QAction* dump_romfs = context_menu.addAction(tr("Dump RomFS"));
QAction* copy_tid = context_menu.addAction(tr("Copy Title ID to Clipboard"));
@@ -344,6 +346,8 @@ void GameList::PopupContextMenu(const QPoint& menu_location) {
[&]() { emit OpenFolderRequested(program_id, GameListOpenTarget::SaveData); });
connect(open_lfs_location, &QAction::triggered,
[&]() { emit OpenFolderRequested(program_id, GameListOpenTarget::ModData); });
connect(open_transferable_shader_cache, &QAction::triggered,
[&]() { emit OpenTransferableShaderCacheRequested(program_id); });
connect(dump_romfs, &QAction::triggered, [&]() { emit DumpRomFSRequested(program_id, path); });
connect(copy_tid, &QAction::triggered, [&]() { emit CopyTIDRequested(program_id); });
connect(navigate_to_gamedb_entry, &QAction::triggered,

View File

@@ -66,6 +66,7 @@ signals:
void GameChosen(QString game_path);
void ShouldCancelWorker();
void OpenFolderRequested(u64 program_id, GameListOpenTarget target);
void OpenTransferableShaderCacheRequested(u64 program_id);
void DumpRomFSRequested(u64 program_id, const std::string& game_path);
void CopyTIDRequested(u64 program_id);
void NavigateToGamedbEntryRequested(u64 program_id,

View File

@@ -632,6 +632,8 @@ void GMainWindow::RestoreUIState() {
void GMainWindow::ConnectWidgetEvents() {
connect(game_list, &GameList::GameChosen, this, &GMainWindow::OnGameListLoadFile);
connect(game_list, &GameList::OpenFolderRequested, this, &GMainWindow::OnGameListOpenFolder);
connect(game_list, &GameList::OpenTransferableShaderCacheRequested, this,
&GMainWindow::OnTransferableShaderCacheOpenFile);
connect(game_list, &GameList::DumpRomFSRequested, this, &GMainWindow::OnGameListDumpRomFS);
connect(game_list, &GameList::CopyTIDRequested, this, &GMainWindow::OnGameListCopyTID);
connect(game_list, &GameList::NavigateToGamedbEntryRequested, this,
@@ -1066,6 +1068,42 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
QDesktopServices::openUrl(QUrl::fromLocalFile(qpath));
}
void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) {
ASSERT(program_id != 0);
constexpr char open_target[] = "Transferable Shader Cache";
const QString tranferable_shader_cache_folder_path =
QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir)) + "opengl" +
DIR_SEP + "transferable";
const QString transferable_shader_cache_file_path =
tranferable_shader_cache_folder_path + DIR_SEP +
QString::fromStdString(fmt::format("{:016X}", program_id)) + ".bin";
if (!QFile(transferable_shader_cache_file_path).exists()) {
QMessageBox::warning(this,
tr("Error Opening %1 File").arg(QString::fromStdString(open_target)),
tr("File does not exist!"));
return;
}
LOG_INFO(Frontend, "Opening {} path for program_id={:016x}", open_target, program_id);
// Windows supports opening a folder with selecting a specified file in explorer. On every other
// OS we just open the transferable shader cache folder without preselecting the transferable
// shader cache file for the selected game.
#if defined(Q_OS_WIN)
const QString explorer = "explorer";
QStringList param;
if (!QFileInfo(transferable_shader_cache_file_path).isDir()) {
param << QLatin1String("/select,");
}
param << QDir::toNativeSeparators(transferable_shader_cache_file_path);
QProcess::startDetached(explorer, param);
#else
QDesktopServices::openUrl(QUrl::fromLocalFile(tranferable_shader_cache_folder_path));
#endif
}
static std::size_t CalculateRomFSEntrySize(const FileSys::VirtualDir& dir, bool full) {
std::size_t out = 0;

View File

@@ -176,6 +176,7 @@ private slots:
/// Called whenever a user selects a game in the game list widget.
void OnGameListLoadFile(QString game_path);
void OnGameListOpenFolder(u64 program_id, GameListOpenTarget target);
void OnTransferableShaderCacheOpenFile(u64 program_id);
void OnGameListDumpRomFS(u64 program_id, const std::string& game_path);
void OnGameListCopyTID(u64 program_id);
void OnGameListNavigateToGamedbEntry(u64 program_id,