summaryrefslogtreecommitdiffstats
path: root/src/citra_qt
diff options
context:
space:
mode:
Diffstat (limited to 'src/citra_qt')
-rw-r--r--src/citra_qt/CMakeLists.txt3
-rw-r--r--src/citra_qt/bootmanager.cpp2
-rw-r--r--src/citra_qt/config.cpp10
-rw-r--r--src/citra_qt/configure_general.cpp2
-rw-r--r--src/citra_qt/configure_general.ui7
-rw-r--r--src/citra_qt/debugger/graphics_breakpoints.cpp6
-rw-r--r--src/citra_qt/debugger/graphics_framebuffer.cpp6
-rw-r--r--src/citra_qt/debugger/graphics_tracing.cpp4
-rw-r--r--src/citra_qt/debugger/graphics_vertex_shader.cpp6
-rw-r--r--src/citra_qt/debugger/profiler.cpp39
-rw-r--r--src/citra_qt/debugger/profiler.h3
-rw-r--r--src/citra_qt/game_list.cpp16
-rw-r--r--src/citra_qt/game_list.h2
-rw-r--r--src/citra_qt/game_list_p.h106
-rw-r--r--src/citra_qt/main.cpp20
-rw-r--r--src/citra_qt/util/util.cpp2
16 files changed, 187 insertions, 47 deletions
diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt
index 6660d9879..3f0099200 100644
--- a/src/citra_qt/CMakeLists.txt
+++ b/src/citra_qt/CMakeLists.txt
@@ -55,6 +55,7 @@ set(HEADERS
configure_dialog.h
configure_general.h
game_list.h
+ game_list_p.h
hotkeys.h
main.h
ui_settings.h
@@ -92,7 +93,7 @@ else()
endif()
target_link_libraries(citra-qt core video_core audio_core common qhexedit)
target_link_libraries(citra-qt ${OPENGL_gl_LIBRARY} ${CITRA_QT_LIBS})
-target_link_libraries(citra-qt ${PLATFORM_LIBRARIES})
+target_link_libraries(citra-qt ${PLATFORM_LIBRARIES} Threads::Threads)
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux|FreeBSD|OpenBSD|NetBSD")
install(TARGETS citra-qt RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp
index 8e60b9cad..01b81c11c 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/citra_qt/bootmanager.cpp
@@ -71,7 +71,9 @@ void EmuThread::run() {
// Shutdown the core emulation
System::Shutdown();
+#if MICROPROFILE_ENABLED
MicroProfileOnThreadExit();
+#endif
render_window->moveContext();
}
diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp
index e363be38a..b5bb75537 100644
--- a/src/citra_qt/config.cpp
+++ b/src/citra_qt/config.cpp
@@ -45,12 +45,17 @@ void Config::ReadValues() {
qt_config->beginGroup("Renderer");
Settings::values.use_hw_renderer = qt_config->value("use_hw_renderer", false).toBool();
Settings::values.use_shader_jit = qt_config->value("use_shader_jit", true).toBool();
+ Settings::values.use_scaled_resolution = qt_config->value("use_scaled_resolution", false).toBool();
Settings::values.bg_red = qt_config->value("bg_red", 1.0).toFloat();
Settings::values.bg_green = qt_config->value("bg_green", 1.0).toFloat();
Settings::values.bg_blue = qt_config->value("bg_blue", 1.0).toFloat();
qt_config->endGroup();
+ qt_config->beginGroup("Audio");
+ Settings::values.sink_id = qt_config->value("output_engine", "auto").toString().toStdString();
+ qt_config->endGroup();
+
qt_config->beginGroup("Data Storage");
Settings::values.use_virtual_sd = qt_config->value("use_virtual_sd", true).toBool();
qt_config->endGroup();
@@ -129,6 +134,7 @@ void Config::SaveValues() {
qt_config->beginGroup("Renderer");
qt_config->setValue("use_hw_renderer", Settings::values.use_hw_renderer);
qt_config->setValue("use_shader_jit", Settings::values.use_shader_jit);
+ qt_config->setValue("use_scaled_resolution", Settings::values.use_scaled_resolution);
// Cast to double because Qt's written float values are not human-readable
qt_config->setValue("bg_red", (double)Settings::values.bg_red);
@@ -136,6 +142,10 @@ void Config::SaveValues() {
qt_config->setValue("bg_blue", (double)Settings::values.bg_blue);
qt_config->endGroup();
+ qt_config->beginGroup("Audio");
+ qt_config->setValue("output_engine", QString::fromStdString(Settings::values.sink_id));
+ qt_config->endGroup();
+
qt_config->beginGroup("Data Storage");
qt_config->setValue("use_virtual_sd", Settings::values.use_virtual_sd);
qt_config->endGroup();
diff --git a/src/citra_qt/configure_general.cpp b/src/citra_qt/configure_general.cpp
index a27d0d26c..62648e665 100644
--- a/src/citra_qt/configure_general.cpp
+++ b/src/citra_qt/configure_general.cpp
@@ -25,6 +25,7 @@ void ConfigureGeneral::setConfiguration() {
ui->region_combobox->setCurrentIndex(Settings::values.region_value);
ui->toogle_hw_renderer->setChecked(Settings::values.use_hw_renderer);
ui->toogle_shader_jit->setChecked(Settings::values.use_shader_jit);
+ ui->toogle_scaled_resolution->setChecked(Settings::values.use_scaled_resolution);
}
void ConfigureGeneral::applyConfiguration() {
@@ -33,5 +34,6 @@ void ConfigureGeneral::applyConfiguration() {
Settings::values.region_value = ui->region_combobox->currentIndex();
Settings::values.use_hw_renderer = ui->toogle_hw_renderer->isChecked();
Settings::values.use_shader_jit = ui->toogle_shader_jit->isChecked();
+ Settings::values.use_scaled_resolution = ui->toogle_scaled_resolution->isChecked();
Settings::Apply();
}
diff --git a/src/citra_qt/configure_general.ui b/src/citra_qt/configure_general.ui
index 47184c5c6..5eb309793 100644
--- a/src/citra_qt/configure_general.ui
+++ b/src/citra_qt/configure_general.ui
@@ -128,6 +128,13 @@
</property>
</widget>
</item>
+ <item>
+ <widget class="QCheckBox" name="toogle_scaled_resolution">
+ <property name="text">
+ <string>Enable scaled resolution</string>
+ </property>
+ </widget>
+ </item>
</layout>
</item>
</layout>
diff --git a/src/citra_qt/debugger/graphics_breakpoints.cpp b/src/citra_qt/debugger/graphics_breakpoints.cpp
index 819ec7707..fe66918a8 100644
--- a/src/citra_qt/debugger/graphics_breakpoints.cpp
+++ b/src/citra_qt/debugger/graphics_breakpoints.cpp
@@ -44,7 +44,7 @@ QVariant BreakPointModel::data(const QModelIndex& index, int role) const
{ Pica::DebugContext::Event::PicaCommandProcessed, tr("Pica command processed") },
{ Pica::DebugContext::Event::IncomingPrimitiveBatch, tr("Incoming primitive batch") },
{ Pica::DebugContext::Event::FinishedPrimitiveBatch, tr("Finished primitive batch") },
- { Pica::DebugContext::Event::VertexLoaded, tr("Vertex loaded") },
+ { Pica::DebugContext::Event::VertexShaderInvocation, tr("Vertex shader invocation") },
{ Pica::DebugContext::Event::IncomingDisplayTransfer, tr("Incoming display transfer") },
{ Pica::DebugContext::Event::GSPCommandProcessed, tr("GSP command processed") },
{ Pica::DebugContext::Event::BufferSwapped, tr("Buffers swapped") }
@@ -75,7 +75,7 @@ QVariant BreakPointModel::data(const QModelIndex& index, int role) const
case Role_IsEnabled:
{
auto context = context_weak.lock();
- return context && context->breakpoints[event].enabled;
+ return context && context->breakpoints[(int)event].enabled;
}
default:
@@ -110,7 +110,7 @@ bool BreakPointModel::setData(const QModelIndex& index, const QVariant& value, i
if (!context)
return false;
- context->breakpoints[event].enabled = value == Qt::Checked;
+ context->breakpoints[(int)event].enabled = value == Qt::Checked;
QModelIndex changed_index = createIndex(index.row(), 0);
emit dataChanged(changed_index, changed_index);
return true;
diff --git a/src/citra_qt/debugger/graphics_framebuffer.cpp b/src/citra_qt/debugger/graphics_framebuffer.cpp
index c30e75933..68cff78b2 100644
--- a/src/citra_qt/debugger/graphics_framebuffer.cpp
+++ b/src/citra_qt/debugger/graphics_framebuffer.cpp
@@ -346,5 +346,11 @@ u32 GraphicsFramebufferWidget::BytesPerPixel(GraphicsFramebufferWidget::Format f
case Format::RGBA4:
case Format::D16:
return 2;
+ default:
+ UNREACHABLE_MSG("GraphicsFramebufferWidget::BytesPerPixel: this "
+ "should not be reached as this function should "
+ "be given a format which is in "
+ "GraphicsFramebufferWidget::Format. Instead got %i",
+ static_cast<int>(format));
}
}
diff --git a/src/citra_qt/debugger/graphics_tracing.cpp b/src/citra_qt/debugger/graphics_tracing.cpp
index e06498744..1402f8e79 100644
--- a/src/citra_qt/debugger/graphics_tracing.cpp
+++ b/src/citra_qt/debugger/graphics_tracing.cpp
@@ -2,6 +2,9 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <algorithm>
+#include <array>
+#include <iterator>
#include <memory>
#include <boost/range/algorithm/copy.hpp>
@@ -18,6 +21,7 @@
#include "core/hw/gpu.h"
#include "core/hw/lcd.h"
+#include "core/tracer/recorder.h"
#include "nihstro/float24.h"
diff --git a/src/citra_qt/debugger/graphics_vertex_shader.cpp b/src/citra_qt/debugger/graphics_vertex_shader.cpp
index d648d4640..854f6ff16 100644
--- a/src/citra_qt/debugger/graphics_vertex_shader.cpp
+++ b/src/citra_qt/debugger/graphics_vertex_shader.cpp
@@ -365,7 +365,7 @@ GraphicsVertexShaderWidget::GraphicsVertexShaderWidget(std::shared_ptr< Pica::De
input_data[i]->setValidator(new QDoubleValidator(input_data[i]));
}
- breakpoint_warning = new QLabel(tr("(data only available at VertexLoaded breakpoints)"));
+ breakpoint_warning = new QLabel(tr("(data only available at vertex shader invocation breakpoints)"));
// TODO: Add some button for jumping to the shader entry point
@@ -454,7 +454,7 @@ GraphicsVertexShaderWidget::GraphicsVertexShaderWidget(std::shared_ptr< Pica::De
void GraphicsVertexShaderWidget::OnBreakPointHit(Pica::DebugContext::Event event, void* data) {
auto input = static_cast<Pica::Shader::InputVertex*>(data);
- if (event == Pica::DebugContext::Event::VertexLoaded) {
+ if (event == Pica::DebugContext::Event::VertexShaderInvocation) {
Reload(true, data);
} else {
// No vertex data is retrievable => invalidate currently stored vertex data
@@ -515,7 +515,7 @@ void GraphicsVertexShaderWidget::Reload(bool replace_vertex_data, void* vertex_d
}
// Initialize debug info text for current cycle count
- cycle_index->setMaximum(debug_data.records.size() - 1);
+ cycle_index->setMaximum(static_cast<int>(debug_data.records.size() - 1));
OnCycleIndexChanged(cycle_index->value());
model->endResetModel();
diff --git a/src/citra_qt/debugger/profiler.cpp b/src/citra_qt/debugger/profiler.cpp
index 4f6ba0e1f..7bb010f77 100644
--- a/src/citra_qt/debugger/profiler.cpp
+++ b/src/citra_qt/debugger/profiler.cpp
@@ -9,13 +9,16 @@
#include "citra_qt/debugger/profiler.h"
#include "citra_qt/util/util.h"
+#include "common/common_types.h"
#include "common/microprofile.h"
#include "common/profiler_reporting.h"
// Include the implementation of the UI in this file. This isn't in microprofile.cpp because the
// non-Qt frontends don't need it (and don't implement the UI drawing hooks either).
+#if MICROPROFILE_ENABLED
#define MICROPROFILEUI_IMPL 1
#include "common/microprofileui.h"
+#endif
using namespace Common::Profiling;
@@ -34,21 +37,9 @@ static QVariant GetDataForColumn(int col, const AggregatedDuration& duration)
}
}
-static const TimingCategoryInfo* GetCategoryInfo(int id)
-{
- const auto& categories = GetProfilingManager().GetTimingCategoriesInfo();
- if ((size_t)id >= categories.size()) {
- return nullptr;
- } else {
- return &categories[id];
- }
-}
-
ProfilerModel::ProfilerModel(QObject* parent) : QAbstractItemModel(parent)
{
updateProfilingInfo();
- const auto& categories = GetProfilingManager().GetTimingCategoriesInfo();
- results.time_per_category.resize(categories.size());
}
QVariant ProfilerModel::headerData(int section, Qt::Orientation orientation, int role) const
@@ -85,7 +76,7 @@ int ProfilerModel::rowCount(const QModelIndex& parent) const
if (parent.isValid()) {
return 0;
} else {
- return static_cast<int>(results.time_per_category.size() + 2);
+ return 2;
}
}
@@ -104,17 +95,6 @@ QVariant ProfilerModel::data(const QModelIndex& index, int role) const
} else {
return GetDataForColumn(index.column(), results.interframe_time);
}
- } else {
- if (index.column() == 0) {
- const TimingCategoryInfo* info = GetCategoryInfo(index.row() - 2);
- return info != nullptr ? QString(info->name) : QVariant();
- } else {
- if (index.row() - 2 < (int)results.time_per_category.size()) {
- return GetDataForColumn(index.column(), results.time_per_category[index.row() - 2]);
- } else {
- return QVariant();
- }
- }
}
}
@@ -148,6 +128,8 @@ void ProfilerWidget::setProfilingInfoUpdateEnabled(bool enable)
}
}
+#if MICROPROFILE_ENABLED
+
class MicroProfileWidget : public QWidget {
public:
MicroProfileWidget(QWidget* parent = nullptr);
@@ -171,6 +153,8 @@ private:
QTimer update_timer;
};
+#endif
+
MicroProfileDialog::MicroProfileDialog(QWidget* parent)
: QWidget(parent, Qt::Dialog)
{
@@ -180,6 +164,8 @@ MicroProfileDialog::MicroProfileDialog(QWidget* parent)
// Remove the "?" button from the titlebar and enable the maximize button
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint | Qt::WindowMaximizeButtonHint);
+#if MICROPROFILE_ENABLED
+
MicroProfileWidget* widget = new MicroProfileWidget(this);
QLayout* layout = new QVBoxLayout(this);
@@ -191,6 +177,7 @@ MicroProfileDialog::MicroProfileDialog(QWidget* parent)
setFocusProxy(widget);
widget->setFocusPolicy(Qt::StrongFocus);
widget->setFocus();
+#endif
}
QAction* MicroProfileDialog::toggleViewAction() {
@@ -218,6 +205,9 @@ void MicroProfileDialog::hideEvent(QHideEvent* ev) {
QWidget::hideEvent(ev);
}
+
+#if MICROPROFILE_ENABLED
+
/// There's no way to pass a user pointer to MicroProfile, so this variable is used to make the
/// QPainter available inside the drawing callbacks.
static QPainter* mp_painter = nullptr;
@@ -337,3 +327,4 @@ void MicroProfileDrawLine2D(u32 vertices_length, float* vertices, u32 hex_color)
mp_painter->drawPolyline(point_buf.data(), vertices_length);
point_buf.clear();
}
+#endif
diff --git a/src/citra_qt/debugger/profiler.h b/src/citra_qt/debugger/profiler.h
index 036054740..3b38ed8ec 100644
--- a/src/citra_qt/debugger/profiler.h
+++ b/src/citra_qt/debugger/profiler.h
@@ -7,8 +7,10 @@
#include <QAbstractItemModel>
#include <QDockWidget>
#include <QTimer>
+
#include "ui_profiler.h"
+#include "common/microprofile.h"
#include "common/profiler_reporting.h"
class ProfilerModel : public QAbstractItemModel
@@ -49,6 +51,7 @@ private:
QTimer update_timer;
};
+
class MicroProfileDialog : public QWidget {
Q_OBJECT
diff --git a/src/citra_qt/game_list.cpp b/src/citra_qt/game_list.cpp
index d14532102..d4ac9c96e 100644
--- a/src/citra_qt/game_list.cpp
+++ b/src/citra_qt/game_list.cpp
@@ -34,8 +34,8 @@ GameList::GameList(QWidget* parent)
tree_view->setUniformRowHeights(true);
item_model->insertColumns(0, COLUMN_COUNT);
- item_model->setHeaderData(COLUMN_FILE_TYPE, Qt::Horizontal, "File type");
item_model->setHeaderData(COLUMN_NAME, Qt::Horizontal, "Name");
+ item_model->setHeaderData(COLUMN_FILE_TYPE, Qt::Horizontal, "File type");
item_model->setHeaderData(COLUMN_SIZE, Qt::Horizontal, "Size");
connect(tree_view, SIGNAL(activated(const QModelIndex&)), this, SLOT(ValidateEntry(const QModelIndex&)));
@@ -109,7 +109,11 @@ void GameList::SaveInterfaceLayout()
void GameList::LoadInterfaceLayout()
{
auto header = tree_view->header();
- header->restoreState(UISettings::values.gamelist_header_state);
+ if (!header->restoreState(UISettings::values.gamelist_header_state)) {
+ // We are using the name column to display icons and titles
+ // so make it as large as possible as default.
+ header->resizeSection(COLUMN_NAME, header->width());
+ }
item_model->sort(header->sortIndicatorSection(), header->sortIndicatorOrder());
}
@@ -143,9 +147,15 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, bool d
LOG_WARNING(Frontend, "Filetype and extension of file %s do not match.", physical_name.c_str());
}
+ std::vector<u8> smdh;
+ std::unique_ptr<Loader::AppLoader> loader = Loader::GetLoader(FileUtil::IOFile(physical_name, "rb"), filetype, filename_filename, physical_name);
+
+ if (loader)
+ loader->ReadIcon(smdh);
+
emit EntryReady({
+ new GameListItemPath(QString::fromStdString(physical_name), smdh),
new GameListItem(QString::fromStdString(Loader::GetFileTypeString(filetype))),
- new GameListItemPath(QString::fromStdString(physical_name)),
new GameListItemSize(FileUtil::GetSize(physical_name)),
});
}
diff --git a/src/citra_qt/game_list.h b/src/citra_qt/game_list.h
index 48febdc60..198674f04 100644
--- a/src/citra_qt/game_list.h
+++ b/src/citra_qt/game_list.h
@@ -20,8 +20,8 @@ class GameList : public QWidget {
public:
enum {
- COLUMN_FILE_TYPE,
COLUMN_NAME,
+ COLUMN_FILE_TYPE,
COLUMN_SIZE,
COLUMN_COUNT, // Number of columns
};
diff --git a/src/citra_qt/game_list_p.h b/src/citra_qt/game_list_p.h
index 820012bce..284f5da81 100644
--- a/src/citra_qt/game_list_p.h
+++ b/src/citra_qt/game_list_p.h
@@ -6,13 +6,85 @@
#include <atomic>
+#include <QImage>
#include <QRunnable>
#include <QStandardItem>
#include <QString>
#include "citra_qt/util/util.h"
#include "common/string_util.h"
+#include "common/color.h"
+#include "core/loader/loader.h"
+
+#include "video_core/utils.h"
+
+/**
+ * Tests if data is a valid SMDH by its length and magic number.
+ * @param smdh_data data buffer to test
+ * @return bool test result
+ */
+static bool IsValidSMDH(const std::vector<u8>& smdh_data) {
+ if (smdh_data.size() < sizeof(Loader::SMDH))
+ return false;
+
+ u32 magic;
+ memcpy(&magic, smdh_data.data(), 4);
+
+ return Loader::MakeMagic('S', 'M', 'D', 'H') == magic;
+}
+
+/**
+ * Gets game icon from SMDH
+ * @param sdmh SMDH data
+ * @param large If true, returns large icon (48x48), otherwise returns small icon (24x24)
+ * @return QPixmap game icon
+ */
+static QPixmap GetIconFromSMDH(const Loader::SMDH& smdh, bool large) {
+ u32 size;
+ const u8* icon_data;
+
+ if (large) {
+ size = 48;
+ icon_data = smdh.large_icon.data();
+ } else {
+ size = 24;
+ icon_data = smdh.small_icon.data();
+ }
+
+ QImage icon(size, size, QImage::Format::Format_RGB888);
+ for (u32 x = 0; x < size; ++x) {
+ for (u32 y = 0; y < size; ++y) {
+ u32 coarse_y = y & ~7;
+ auto v = Color::DecodeRGB565(
+ icon_data + VideoCore::GetMortonOffset(x, y, 2) + coarse_y * size * 2);
+ icon.setPixel(x, y, qRgb(v.r(), v.g(), v.b()));
+ }
+ }
+ return QPixmap::fromImage(icon);
+}
+
+/**
+ * Gets the default icon (for games without valid SMDH)
+ * @param large If true, returns large icon (48x48), otherwise returns small icon (24x24)
+ * @return QPixmap default icon
+ */
+static QPixmap GetDefaultIcon(bool large) {
+ int size = large ? 48 : 24;
+ QPixmap icon(size, size);
+ icon.fill(Qt::transparent);
+ return icon;
+}
+
+/**
+ * Gets the short game title fromn SMDH
+ * @param sdmh SMDH data
+ * @param language title language
+ * @return QString short title
+ */
+static QString GetShortTitleFromSMDH(const Loader::SMDH& smdh, Loader::SMDH::TitleLanguage language) {
+ return QString::fromUtf16(smdh.titles[static_cast<int>(language)].short_title.data());
+}
class GameListItem : public QStandardItem {
@@ -27,29 +99,43 @@ public:
* A specialization of GameListItem for path values.
* This class ensures that for every full path value it holds, a correct string representation
* of just the filename (with no extension) will be displayed to the user.
+ * If this class recieves valid SMDH data, it will also display game icons and titles.
*/
class GameListItemPath : public GameListItem {
public:
static const int FullPathRole = Qt::UserRole + 1;
+ static const int TitleRole = Qt::UserRole + 2;
GameListItemPath(): GameListItem() {}
- GameListItemPath(const QString& game_path): GameListItem()
+ GameListItemPath(const QString& game_path, const std::vector<u8>& smdh_data): GameListItem()
{
setData(game_path, FullPathRole);
+
+ if (!IsValidSMDH(smdh_data)) {
+ // SMDH is not valid, set a default icon
+ setData(GetDefaultIcon(true), Qt::DecorationRole);
+ return;
+ }
+
+ Loader::SMDH smdh;
+ memcpy(&smdh, smdh_data.data(), sizeof(Loader::SMDH));
+
+ // Get icon from SMDH
+ setData(GetIconFromSMDH(smdh, true), Qt::DecorationRole);
+
+ // Get title form SMDH
+ setData(GetShortTitleFromSMDH(smdh, Loader::SMDH::TitleLanguage::English), TitleRole);
}
- void setData(const QVariant& value, int role) override
- {
- // By specializing setData for FullPathRole, we can ensure that the two string
- // representations of the data are always accurate and in the correct format.
- if (role == FullPathRole) {
+ QVariant data(int role) const override {
+ if (role == Qt::DisplayRole) {
std::string filename;
- Common::SplitPath(value.toString().toStdString(), nullptr, &filename, nullptr);
- GameListItem::setData(QString::fromStdString(filename), Qt::DisplayRole);
- GameListItem::setData(value, FullPathRole);
+ Common::SplitPath(data(FullPathRole).toString().toStdString(), nullptr, &filename, nullptr);
+ QString title = data(TitleRole).toString();
+ return QString::fromStdString(filename) + (title.isEmpty() ? "" : "\n " + title);
} else {
- GameListItem::setData(value, role);
+ return GameListItem::data(role);
}
}
};
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index 2ca1e51f6..a85c94a4b 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -6,6 +6,9 @@
#include <memory>
#include <thread>
+#include <glad/glad.h>
+
+#define QT_NO_OPENGL
#include <QDesktopWidget>
#include <QtGui>
#include <QFileDialog>
@@ -69,8 +72,10 @@ GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr)
addDockWidget(Qt::BottomDockWidgetArea, profilerWidget);
profilerWidget->hide();
+#if MICROPROFILE_ENABLED
microProfileDialog = new MicroProfileDialog(this);
microProfileDialog->hide();
+#endif
disasmWidget = new DisassemblerWidget(this, emu_thread.get());
addDockWidget(Qt::BottomDockWidgetArea, disasmWidget);
@@ -110,7 +115,9 @@ GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr)
QMenu* debug_menu = ui.menu_View->addMenu(tr("Debugging"));
debug_menu->addAction(profilerWidget->toggleViewAction());
+#if MICROPROFILE_ENABLED
debug_menu->addAction(microProfileDialog->toggleViewAction());
+#endif
debug_menu->addAction(disasmWidget->toggleViewAction());
debug_menu->addAction(registersWidget->toggleViewAction());
debug_menu->addAction(callstackWidget->toggleViewAction());
@@ -136,8 +143,10 @@ GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr)
restoreGeometry(UISettings::values.geometry);
restoreState(UISettings::values.state);
render_window->restoreGeometry(UISettings::values.renderwindow_geometry);
+#if MICROPROFILE_ENABLED
microProfileDialog->restoreGeometry(UISettings::values.microprofile_geometry);
microProfileDialog->setVisible(UISettings::values.microprofile_visible);
+#endif
game_list->LoadInterfaceLayout();
@@ -234,6 +243,14 @@ bool GMainWindow::InitializeSystem() {
if (emu_thread != nullptr)
ShutdownGame();
+ render_window->MakeCurrent();
+ if (!gladLoadGL()) {
+ QMessageBox::critical(this, tr("Error while starting Citra!"),
+ tr("Failed to initialize the video core!\n\n"
+ "Please ensure that your GPU supports OpenGL 3.3 and that you have the latest graphics driver."));
+ return false;
+ }
+
// Initialize the core emulation
System::Result system_result = System::Init(render_window);
if (System::Result::Success != system_result) {
@@ -511,9 +528,10 @@ void GMainWindow::closeEvent(QCloseEvent* event) {
UISettings::values.geometry = saveGeometry();
UISettings::values.state = saveState();
UISettings::values.renderwindow_geometry = render_window->saveGeometry();
+#if MICROPROFILE_ENABLED
UISettings::values.microprofile_geometry = microProfileDialog->saveGeometry();
UISettings::values.microprofile_visible = microProfileDialog->isVisible();
-
+#endif
UISettings::values.single_window_mode = ui.action_Single_Window_Mode->isChecked();
UISettings::values.display_titlebar = ui.actionDisplay_widget_title_bars->isChecked();
UISettings::values.first_start = false;
diff --git a/src/citra_qt/util/util.cpp b/src/citra_qt/util/util.cpp
index 8734a8efd..2f9beb5cc 100644
--- a/src/citra_qt/util/util.cpp
+++ b/src/citra_qt/util/util.cpp
@@ -19,7 +19,7 @@ QString ReadableByteSize(qulonglong size) {
static const std::array<const char*, 6> units = { "B", "KiB", "MiB", "GiB", "TiB", "PiB" };
if (size == 0)
return "0";
- int digit_groups = std::min<int>((int)(std::log10(size) / std::log10(1024)), units.size());
+ int digit_groups = std::min<int>(static_cast<int>(std::log10(size) / std::log10(1024)), static_cast<int>(units.size()));
return QString("%L1 %2").arg(size / std::pow(1024, digit_groups), 0, 'f', 1)
.arg(units[digit_groups]);
}