Compare commits

..

6 Commits

Author SHA1 Message Date
Lioncash
0a7f09a99b gl_shader_disk_cache: in-class initialize virtual file offset of ShaderDiskCacheOpenGL
Given the offset is assigned a fixed value in the constructor, we can
just assign it directly and get rid of the need to write the name of the
variable again in the constructor initializer list.
2019-05-19 02:55:18 -04:00
Lioncash
634b78a4c6 gl_shader_disk_cache: Default ShaderDiskCacheOpenGL's destructor in the cpp file
Given the disk shader cache contains non-trivial types, we should
default it in the cpp file in order to prevent inlining of the
complex destruction logic.
2019-05-19 02:50:50 -04:00
Lioncash
7fdc644c44 gl_shader_disk_cache: Make hash specializations noexcept
The standard library expects hash specializations that don't throw
exceptions. Make this explicit in the type to allow selection of better
code paths if possible in implementations.
2019-05-19 02:46:45 -04:00
Lioncash
683c4e523f gl_shader_disk_cache: Remove redundant code string construction in LoadDecompiledEntry()
We don't need to load the code into a vector and then construct a string
over the data. We can just create a string with the necessary size ahead
of time, and read the data directly into it, getting rid of an
unnecessary heap allocation.
2019-05-19 02:46:44 -04:00
Lioncash
5e4c227608 gl_shader_disk_cache: Make variable non-const in decompiled entry case
std::move does nothing when applied to a const variable. Resources can't
be moved if the object is immutable. With this change, we don't end up
making several unnecessary heap allocations and copies.
2019-05-19 02:46:44 -04:00
Lioncash
f417be9d3b gl_shader_disk_cache: Special-case boolean handling
Booleans don't have a guaranteed size, but we still want to have them
integrate into the disk cache system without needing to actually use a
different type. We can do this by supplying non-template overloads for
the bool type.

Non-template overloads always have precedence during function
resolution, so this is safe to provide.

This gets rid of the need to smatter ternary conditionals, as well as
the need to use u8 types to store the value in.
2019-05-19 02:46:38 -04:00
5 changed files with 65 additions and 54 deletions

View File

@@ -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;
}
}

View File

@@ -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{};

View File

@@ -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(QStringLiteral("TegraBreakPointsWidget"));
setObjectName("TegraBreakPointsWidget");
status_text = new QLabel(tr("Emulation running"));
resume_button = new QPushButton(tr("Resume"));

View File

@@ -47,7 +47,7 @@ private:
#endif
MicroProfileDialog::MicroProfileDialog(QWidget* parent) : QWidget(parent, Qt::Dialog) {
setObjectName(QStringLiteral("MicroProfile"));
setObjectName("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, QString{QLatin1Char{text[i]}});
mp_painter->drawText(x, y + MICROPROFILE_TEXT_HEIGHT - 2, QChar(text[i]));
x += MICROPROFILE_TEXT_WIDTH + 1;
}
}

View File

@@ -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 {
const bool has_waiters = (mutex_value & Kernel::Mutex::MutexHasWaitersFlag) != 0;
std::vector<std::unique_ptr<WaitTreeItem>> list;
bool has_waiters = (mutex_value & Kernel::Mutex::MutexHasWaitersFlag) != 0;
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,14 +121,11 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() cons
u64 base_pointer = thread.GetContext().cpu_registers[BaseRegister];
while (base_pointer != 0) {
const u64 lr = Memory::Read64(base_pointer + sizeof(u64));
if (lr == 0) {
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, QLatin1Char{'0'})));
list.push_back(
std::make_unique<WaitTreeText>(tr("0x%1").arg(lr - sizeof(u32), 16, 16, QChar('0'))));
base_pointer = Memory::Read64(base_pointer);
}
@@ -252,9 +249,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 QStringLiteral("%1%2 (%3) ").arg(WaitTreeWaitObject::GetText(), pc_info, status);
.arg(context.pc, 8, 16, QLatin1Char('0'))
.arg(context.cpu_registers[30], 8, 16, QLatin1Char('0'));
return WaitTreeWaitObject::GetText() + pc_info + " (" + status + ") ";
}
QColor WaitTreeThread::GetColor() const {
@@ -427,7 +424,7 @@ void WaitTreeModel::InitItems() {
}
WaitTreeWidget::WaitTreeWidget(QWidget* parent) : QDockWidget(tr("Wait Tree"), parent) {
setObjectName(QStringLiteral("WaitTreeWidget"));
setObjectName("WaitTreeWidget");
view = new QTreeView(this);
view->setHeaderHidden(true);
setWidget(view);