citra_qt: Prepare GUI for Vulkan support
This commit is contained in:
@ -22,7 +22,6 @@
|
|||||||
#include "core/frontend/applets/default_applets.h"
|
#include "core/frontend/applets/default_applets.h"
|
||||||
#include "core/frontend/camera/factory.h"
|
#include "core/frontend/camera/factory.h"
|
||||||
#include "core/frontend/mic.h"
|
#include "core/frontend/mic.h"
|
||||||
#include "core/frontend/scope_acquire_context.h"
|
|
||||||
#include "core/hle/service/am/am.h"
|
#include "core/hle/service/am/am.h"
|
||||||
#include "core/hle/service/nfc/nfc.h"
|
#include "core/hle/service/nfc/nfc.h"
|
||||||
#include "core/savestate.h"
|
#include "core/savestate.h"
|
||||||
|
@ -35,7 +35,6 @@
|
|||||||
#include "core/file_sys/cia_container.h"
|
#include "core/file_sys/cia_container.h"
|
||||||
#include "core/frontend/applets/default_applets.h"
|
#include "core/frontend/applets/default_applets.h"
|
||||||
#include "core/frontend/framebuffer_layout.h"
|
#include "core/frontend/framebuffer_layout.h"
|
||||||
#include "core/frontend/scope_acquire_context.h"
|
|
||||||
#include "core/gdbstub/gdbstub.h"
|
#include "core/gdbstub/gdbstub.h"
|
||||||
#include "core/hle/service/am/am.h"
|
#include "core/hle/service/am/am.h"
|
||||||
#include "core/hle/service/cfg/cfg.h"
|
#include "core/hle/service/cfg/cfg.h"
|
||||||
@ -359,7 +358,7 @@ int main(int argc, char** argv) {
|
|||||||
Core::System::GetInstance().RegisterImageInterface(std::make_shared<LodePNGImageInterface>());
|
Core::System::GetInstance().RegisterImageInterface(std::make_shared<LodePNGImageInterface>());
|
||||||
|
|
||||||
std::unique_ptr<EmuWindow_SDL2> emu_window{std::make_unique<EmuWindow_SDL2>(fullscreen)};
|
std::unique_ptr<EmuWindow_SDL2> emu_window{std::make_unique<EmuWindow_SDL2>(fullscreen)};
|
||||||
Frontend::ScopeAcquireContext scope(*emu_window);
|
const auto scope = emu_window->Acquire();
|
||||||
Core::System& system = Core::System::GetInstance();
|
Core::System& system = Core::System::GetInstance();
|
||||||
|
|
||||||
const Core::System::ResultStatus load_result{system.Load(*emu_window, filepath)};
|
const Core::System::ResultStatus load_result{system.Load(*emu_window, filepath)};
|
||||||
|
@ -109,7 +109,8 @@ void Config::ReadValues() {
|
|||||||
sdl2_config->GetInteger("Core", "cpu_clock_percentage", 100);
|
sdl2_config->GetInteger("Core", "cpu_clock_percentage", 100);
|
||||||
|
|
||||||
// Renderer
|
// Renderer
|
||||||
Settings::values.use_gles = sdl2_config->GetBoolean("Renderer", "use_gles", false);
|
Settings::values.graphics_api =
|
||||||
|
static_cast<Settings::GraphicsAPI>(sdl2_config->GetInteger("Renderer", "graphics_api", 0));
|
||||||
Settings::values.use_hw_renderer = sdl2_config->GetBoolean("Renderer", "use_hw_renderer", true);
|
Settings::values.use_hw_renderer = sdl2_config->GetBoolean("Renderer", "use_hw_renderer", true);
|
||||||
Settings::values.use_hw_shader = sdl2_config->GetBoolean("Renderer", "use_hw_shader", true);
|
Settings::values.use_hw_shader = sdl2_config->GetBoolean("Renderer", "use_hw_shader", true);
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
|
@ -147,7 +147,8 @@ EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) {
|
|||||||
|
|
||||||
SDL_SetMainReady();
|
SDL_SetMainReady();
|
||||||
|
|
||||||
if (Settings::values.use_gles) {
|
const bool is_opengles = Settings::values.graphics_api == Settings::GraphicsAPI::OpenGLES;
|
||||||
|
if (is_opengles) {
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
||||||
@ -201,7 +202,7 @@ EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto gl_load_func = Settings::values.use_gles ? gladLoadGLES2Loader : gladLoadGLLoader;
|
auto gl_load_func = is_opengles ? gladLoadGLES2Loader : gladLoadGLLoader;
|
||||||
|
|
||||||
if (!gl_load_func(static_cast<GLADloadproc>(SDL_GL_GetProcAddress))) {
|
if (!gl_load_func(static_cast<GLADloadproc>(SDL_GL_GetProcAddress))) {
|
||||||
LOG_CRITICAL(Frontend, "Failed to initialize GL functions: {}", SDL_GetError());
|
LOG_CRITICAL(Frontend, "Failed to initialize GL functions: {}", SDL_GetError());
|
||||||
|
@ -6,10 +6,11 @@
|
|||||||
#include <QDragEnterEvent>
|
#include <QDragEnterEvent>
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
|
#include <QMessageBox>
|
||||||
#include <QOffscreenSurface>
|
#include <QOffscreenSurface>
|
||||||
#include <QOpenGLContext>
|
#include <QOpenGLContext>
|
||||||
#include <QOpenGLFunctions>
|
|
||||||
#include <QOpenGLFunctions_4_3_Core>
|
#include <QOpenGLFunctions_4_3_Core>
|
||||||
|
#include <QOpenGLExtraFunctions>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include "citra_qt/bootmanager.h"
|
#include "citra_qt/bootmanager.h"
|
||||||
#include "citra_qt/main.h"
|
#include "citra_qt/main.h"
|
||||||
@ -17,13 +18,10 @@
|
|||||||
#include "common/scm_rev.h"
|
#include "common/scm_rev.h"
|
||||||
#include "core/3ds.h"
|
#include "core/3ds.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/frontend/scope_acquire_context.h"
|
|
||||||
#include "core/perf_stats.h"
|
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
#include "input_common/keyboard.h"
|
#include "input_common/keyboard.h"
|
||||||
#include "input_common/main.h"
|
#include "input_common/main.h"
|
||||||
#include "input_common/motion_emu.h"
|
#include "input_common/motion_emu.h"
|
||||||
#include "network/network.h"
|
|
||||||
#include "video_core/renderer_base.h"
|
#include "video_core/renderer_base.h"
|
||||||
#include "video_core/video_core.h"
|
#include "video_core/video_core.h"
|
||||||
|
|
||||||
@ -42,7 +40,7 @@ static GMainWindow* GetMainWindow() {
|
|||||||
|
|
||||||
void EmuThread::run() {
|
void EmuThread::run() {
|
||||||
MicroProfileOnThreadCreate("EmuThread");
|
MicroProfileOnThreadCreate("EmuThread");
|
||||||
Frontend::ScopeAcquireContext scope(core_context);
|
const auto scope = core_context.Acquire();
|
||||||
|
|
||||||
emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0);
|
emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0);
|
||||||
|
|
||||||
@ -111,88 +109,195 @@ void EmuThread::run() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGLWindow::OpenGLWindow(QWindow* parent, QWidget* event_handler, QOpenGLContext* shared_context)
|
class OpenGLSharedContext : public Frontend::GraphicsContext {
|
||||||
: QWindow(parent), context(std::make_unique<QOpenGLContext>(shared_context->parent())),
|
public:
|
||||||
event_handler(event_handler) {
|
/// Create the original context that should be shared from
|
||||||
|
explicit OpenGLSharedContext(QSurface* surface) : surface(surface) {
|
||||||
|
QSurfaceFormat format;
|
||||||
|
format.setVersion(4, 3);
|
||||||
|
format.setProfile(QSurfaceFormat::CoreProfile);
|
||||||
|
// TODO: expose a setting for buffer value (ie default/single/double/triple)
|
||||||
|
format.setSwapBehavior(QSurfaceFormat::DefaultSwapBehavior);
|
||||||
|
format.setSwapInterval(0);
|
||||||
|
|
||||||
// disable vsync for any shared contexts
|
context = std::make_unique<QOpenGLContext>();
|
||||||
auto format = shared_context->format();
|
context->setFormat(format);
|
||||||
format.setSwapInterval(Settings::values.use_vsync_new ? 1 : 0);
|
if (!context->create()) {
|
||||||
this->setFormat(format);
|
LOG_ERROR(Frontend, "Unable to create main openGL context");
|
||||||
|
}
|
||||||
context->setShareContext(shared_context);
|
|
||||||
context->setScreen(this->screen());
|
|
||||||
context->setFormat(format);
|
|
||||||
context->create();
|
|
||||||
|
|
||||||
setSurfaceType(QWindow::OpenGLSurface);
|
|
||||||
|
|
||||||
// TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground,
|
|
||||||
// WA_DontShowOnScreen, WA_DeleteOnClose
|
|
||||||
}
|
|
||||||
|
|
||||||
OpenGLWindow::~OpenGLWindow() {
|
|
||||||
context->doneCurrent();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLWindow::Present() {
|
|
||||||
if (!isExposed())
|
|
||||||
return;
|
|
||||||
|
|
||||||
context->makeCurrent(this);
|
|
||||||
if (VideoCore::g_renderer) {
|
|
||||||
VideoCore::g_renderer->TryPresent(100);
|
|
||||||
}
|
}
|
||||||
context->swapBuffers(this);
|
|
||||||
auto f = context->versionFunctions<QOpenGLFunctions_4_3_Core>();
|
|
||||||
f->glFinish();
|
|
||||||
QWindow::requestUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OpenGLWindow::event(QEvent* event) {
|
/// Create the shared contexts for rendering and presentation
|
||||||
switch (event->type()) {
|
explicit OpenGLSharedContext(QOpenGLContext* share_context, QSurface* main_surface = nullptr) {
|
||||||
case QEvent::UpdateRequest:
|
|
||||||
|
// disable vsync for any shared contexts
|
||||||
|
auto format = share_context->format();
|
||||||
|
format.setSwapInterval(main_surface ? Settings::values.use_vsync_new : 0);
|
||||||
|
|
||||||
|
context = std::make_unique<QOpenGLContext>();
|
||||||
|
context->setShareContext(share_context);
|
||||||
|
context->setFormat(format);
|
||||||
|
if (!context->create()) {
|
||||||
|
LOG_ERROR(Frontend, "Unable to create shared openGL context");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!main_surface) {
|
||||||
|
offscreen_surface = std::make_unique<QOffscreenSurface>(nullptr);
|
||||||
|
offscreen_surface->setFormat(format);
|
||||||
|
offscreen_surface->create();
|
||||||
|
surface = offscreen_surface.get();
|
||||||
|
} else {
|
||||||
|
surface = main_surface;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~OpenGLSharedContext() {
|
||||||
|
context->doneCurrent();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwapBuffers() override {
|
||||||
|
context->swapBuffers(surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MakeCurrent() override {
|
||||||
|
// We can't track the current state of the underlying context in this wrapper class because
|
||||||
|
// Qt may make the underlying context not current for one reason or another. In particular,
|
||||||
|
// the WebBrowser uses GL, so it seems to conflict if we aren't careful.
|
||||||
|
// Instead of always just making the context current (which does not have any caching to
|
||||||
|
// check if the underlying context is already current) we can check for the current context
|
||||||
|
// in the thread local data by calling `currentContext()` and checking if its ours.
|
||||||
|
if (QOpenGLContext::currentContext() != context.get()) {
|
||||||
|
context->makeCurrent(surface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoneCurrent() override {
|
||||||
|
context->doneCurrent();
|
||||||
|
}
|
||||||
|
|
||||||
|
QOpenGLContext* GetShareContext() const {
|
||||||
|
return context.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Avoid using Qt parent system here since we might move the QObjects to new threads
|
||||||
|
// As a note, this means we should avoid using slots/signals with the objects too
|
||||||
|
std::unique_ptr<QOpenGLContext> context;
|
||||||
|
std::unique_ptr<QOffscreenSurface> offscreen_surface{};
|
||||||
|
QSurface* surface;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DummyContext : public Frontend::GraphicsContext {};
|
||||||
|
|
||||||
|
class RenderWidget : public QWidget {
|
||||||
|
public:
|
||||||
|
RenderWidget(GRenderWindow* parent) : QWidget(parent), render_window(parent) {
|
||||||
|
setAttribute(Qt::WA_NativeWindow);
|
||||||
|
setAttribute(Qt::WA_PaintOnScreen);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~RenderWidget() = default;
|
||||||
|
|
||||||
|
virtual void Present() {}
|
||||||
|
|
||||||
|
void paintEvent(QPaintEvent* event) override {
|
||||||
Present();
|
Present();
|
||||||
return true;
|
update();
|
||||||
case QEvent::MouseButtonPress:
|
|
||||||
case QEvent::MouseButtonRelease:
|
|
||||||
case QEvent::MouseButtonDblClick:
|
|
||||||
case QEvent::MouseMove:
|
|
||||||
case QEvent::KeyPress:
|
|
||||||
case QEvent::KeyRelease:
|
|
||||||
case QEvent::FocusIn:
|
|
||||||
case QEvent::FocusOut:
|
|
||||||
case QEvent::FocusAboutToChange:
|
|
||||||
case QEvent::Enter:
|
|
||||||
case QEvent::Leave:
|
|
||||||
case QEvent::Wheel:
|
|
||||||
case QEvent::TabletMove:
|
|
||||||
case QEvent::TabletPress:
|
|
||||||
case QEvent::TabletRelease:
|
|
||||||
case QEvent::TabletEnterProximity:
|
|
||||||
case QEvent::TabletLeaveProximity:
|
|
||||||
case QEvent::TouchBegin:
|
|
||||||
case QEvent::TouchUpdate:
|
|
||||||
case QEvent::TouchEnd:
|
|
||||||
case QEvent::InputMethodQuery:
|
|
||||||
case QEvent::TouchCancel:
|
|
||||||
return QCoreApplication::sendEvent(event_handler, event);
|
|
||||||
case QEvent::Drop:
|
|
||||||
GetMainWindow()->DropAction(static_cast<QDropEvent*>(event));
|
|
||||||
return true;
|
|
||||||
case QEvent::DragEnter:
|
|
||||||
case QEvent::DragMove:
|
|
||||||
GetMainWindow()->AcceptDropEvent(static_cast<QDropEvent*>(event));
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return QWindow::event(event);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLWindow::exposeEvent(QExposeEvent* event) {
|
void resizeEvent(QResizeEvent* ev) override {
|
||||||
QWindow::requestUpdate();
|
render_window->resize(ev->size());
|
||||||
QWindow::exposeEvent(event);
|
render_window->OnFramebufferSizeChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void keyPressEvent(QKeyEvent* event) override {
|
||||||
|
InputCommon::GetKeyboard()->PressKey(event->key());
|
||||||
|
}
|
||||||
|
|
||||||
|
void keyReleaseEvent(QKeyEvent* event) override {
|
||||||
|
InputCommon::GetKeyboard()->ReleaseKey(event->key());
|
||||||
|
}
|
||||||
|
|
||||||
|
void mousePressEvent(QMouseEvent* event) override {
|
||||||
|
if (event->source() == Qt::MouseEventSynthesizedBySystem)
|
||||||
|
return; // touch input is handled in TouchBeginEvent
|
||||||
|
|
||||||
|
const auto pos{event->pos()};
|
||||||
|
if (event->button() == Qt::LeftButton) {
|
||||||
|
const auto [x, y] = render_window->ScaleTouch(pos);
|
||||||
|
render_window->TouchPressed(x, y);
|
||||||
|
} else if (event->button() == Qt::RightButton) {
|
||||||
|
InputCommon::GetMotionEmu()->BeginTilt(pos.x(), pos.y());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mouseMoveEvent(QMouseEvent* event) override {
|
||||||
|
if (event->source() == Qt::MouseEventSynthesizedBySystem)
|
||||||
|
return; // touch input is handled in TouchUpdateEvent
|
||||||
|
|
||||||
|
const auto pos{event->pos()};
|
||||||
|
const auto [x, y] = render_window->ScaleTouch(pos);
|
||||||
|
render_window->TouchMoved(x, y);
|
||||||
|
InputCommon::GetMotionEmu()->Tilt(pos.x(), pos.y());
|
||||||
|
}
|
||||||
|
|
||||||
|
void mouseReleaseEvent(QMouseEvent* event) override {
|
||||||
|
if (event->source() == Qt::MouseEventSynthesizedBySystem)
|
||||||
|
return; // touch input is handled in TouchEndEvent
|
||||||
|
|
||||||
|
if (event->button() == Qt::LeftButton)
|
||||||
|
render_window->TouchReleased();
|
||||||
|
else if (event->button() == Qt::RightButton)
|
||||||
|
InputCommon::GetMotionEmu()->EndTilt();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<unsigned, unsigned> GetSize() const {
|
||||||
|
return std::make_pair(width(), height());
|
||||||
|
}
|
||||||
|
|
||||||
|
QPaintEngine* paintEngine() const override {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
GRenderWindow* render_window;
|
||||||
|
};
|
||||||
|
|
||||||
|
class OpenGLRenderWidget : public RenderWidget {
|
||||||
|
public:
|
||||||
|
explicit OpenGLRenderWidget(GRenderWindow* parent) : RenderWidget(parent) {
|
||||||
|
windowHandle()->setSurfaceType(QWindow::OpenGLSurface);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetContext(std::unique_ptr<OpenGLSharedContext>&& context_) {
|
||||||
|
context = std::move(context_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Present() override {
|
||||||
|
if (!isVisible()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!Core::System::GetInstance().IsPoweredOn()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
context->MakeCurrent();
|
||||||
|
const auto f = context->GetShareContext()->extraFunctions();
|
||||||
|
f->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||||
|
VideoCore::g_renderer->TryPresent(100);
|
||||||
|
context->SwapBuffers();
|
||||||
|
f->glFinish();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<OpenGLSharedContext> context{};
|
||||||
|
};
|
||||||
|
|
||||||
|
class VulkanRenderWidget : public RenderWidget {
|
||||||
|
public:
|
||||||
|
explicit VulkanRenderWidget(GRenderWindow* parent) : RenderWidget(parent) {
|
||||||
|
windowHandle()->setSurfaceType(QWindow::VulkanSurface);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
GRenderWindow::GRenderWindow(QWidget* parent_, EmuThread* emu_thread)
|
GRenderWindow::GRenderWindow(QWidget* parent_, EmuThread* emu_thread)
|
||||||
: QWidget(parent_), emu_thread(emu_thread) {
|
: QWidget(parent_), emu_thread(emu_thread) {
|
||||||
@ -218,11 +323,11 @@ GRenderWindow::~GRenderWindow() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GRenderWindow::MakeCurrent() {
|
void GRenderWindow::MakeCurrent() {
|
||||||
core_context->MakeCurrent();
|
main_context->MakeCurrent();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GRenderWindow::DoneCurrent() {
|
void GRenderWindow::DoneCurrent() {
|
||||||
core_context->DoneCurrent();
|
main_context->DoneCurrent();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GRenderWindow::PollEvents() {
|
void GRenderWindow::PollEvents() {
|
||||||
@ -387,33 +492,67 @@ void GRenderWindow::resizeEvent(QResizeEvent* event) {
|
|||||||
OnFramebufferSizeChanged();
|
OnFramebufferSizeChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GRenderWindow::InitRenderTarget() {
|
std::unique_ptr<Frontend::GraphicsContext> GRenderWindow::CreateSharedContext() const {
|
||||||
|
const Settings::GraphicsAPI graphics_api = Settings::values.graphics_api;
|
||||||
|
if (graphics_api == Settings::GraphicsAPI::OpenGL ||
|
||||||
|
graphics_api == Settings::GraphicsAPI::OpenGLES) {
|
||||||
|
auto c = static_cast<OpenGLSharedContext*>(main_context.get());
|
||||||
|
// Bind the shared contexts to the main surface in case the backend wants to take over
|
||||||
|
// presentation
|
||||||
|
return std::make_unique<OpenGLSharedContext>(c->GetShareContext(),
|
||||||
|
child_widget->windowHandle());
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_unique<DummyContext>();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GRenderWindow::InitRenderTarget() {
|
||||||
ReleaseRenderTarget();
|
ReleaseRenderTarget();
|
||||||
|
|
||||||
|
{
|
||||||
|
// Create a dummy render widget so that Qt
|
||||||
|
// places the render window at the correct position.
|
||||||
|
const RenderWidget dummy_widget{this};
|
||||||
|
}
|
||||||
|
|
||||||
first_frame = false;
|
first_frame = false;
|
||||||
|
|
||||||
GMainWindow* parent = GetMainWindow();
|
const Settings::GraphicsAPI graphics_api = Settings::values.graphics_api;
|
||||||
QWindow* parent_win_handle = parent ? parent->windowHandle() : nullptr;
|
switch (graphics_api) {
|
||||||
child_window = new OpenGLWindow(parent_win_handle, this, QOpenGLContext::globalShareContext());
|
case Settings::GraphicsAPI::OpenGL:
|
||||||
child_window->create();
|
case Settings::GraphicsAPI::OpenGLES:
|
||||||
child_widget = createWindowContainer(child_window, this);
|
if (!InitializeOpenGL()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Settings::GraphicsAPI::Vulkan:
|
||||||
|
if (!InitializeVulkan()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
child_widget->resize(Core::kScreenTopWidth, Core::kScreenTopHeight + Core::kScreenBottomHeight);
|
child_widget->resize(Core::kScreenTopWidth, Core::kScreenTopHeight + Core::kScreenBottomHeight);
|
||||||
|
|
||||||
layout()->addWidget(child_widget);
|
layout()->addWidget(child_widget);
|
||||||
|
// Reset minimum required size to avoid resizing issues on the main window after restarting.
|
||||||
|
setMinimumSize(1, 1);
|
||||||
|
|
||||||
core_context = CreateSharedContext();
|
|
||||||
resize(Core::kScreenTopWidth, Core::kScreenTopHeight + Core::kScreenBottomHeight);
|
resize(Core::kScreenTopWidth, Core::kScreenTopHeight + Core::kScreenBottomHeight);
|
||||||
OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size);
|
OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size);
|
||||||
OnFramebufferSizeChanged();
|
OnFramebufferSizeChanged();
|
||||||
BackupGeometry();
|
BackupGeometry();
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GRenderWindow::ReleaseRenderTarget() {
|
void GRenderWindow::ReleaseRenderTarget() {
|
||||||
if (child_widget) {
|
if (child_widget) {
|
||||||
layout()->removeWidget(child_widget);
|
layout()->removeWidget(child_widget);
|
||||||
delete child_widget;
|
child_widget->deleteLater();
|
||||||
child_widget = nullptr;
|
child_widget = nullptr;
|
||||||
}
|
}
|
||||||
|
main_context.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GRenderWindow::CaptureScreenshot(u32 res_scale, const QString& screenshot_path) {
|
void GRenderWindow::CaptureScreenshot(u32 res_scale, const QString& screenshot_path) {
|
||||||
@ -438,6 +577,37 @@ void GRenderWindow::OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal
|
|||||||
setMinimumSize(minimal_size.first, minimal_size.second);
|
setMinimumSize(minimal_size.first, minimal_size.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GRenderWindow::InitializeOpenGL() {
|
||||||
|
// TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground,
|
||||||
|
// WA_DontShowOnScreen, WA_DeleteOnClose
|
||||||
|
auto child = new OpenGLRenderWidget(this);
|
||||||
|
child_widget = child;
|
||||||
|
child_widget->windowHandle()->create();
|
||||||
|
auto context = std::make_shared<OpenGLSharedContext>(child->windowHandle());
|
||||||
|
main_context = context;
|
||||||
|
child->SetContext(
|
||||||
|
std::make_unique<OpenGLSharedContext>(context->GetShareContext(), child->windowHandle()));
|
||||||
|
|
||||||
|
// Check for OpenGL 4.3 support
|
||||||
|
if (!QOpenGLContext::globalShareContext()->versionFunctions<QOpenGLFunctions_4_3_Core>()) {
|
||||||
|
QMessageBox::critical(this, tr("OpenGL 4.3 Unsupported"),
|
||||||
|
tr("Your GPU may not support OpenGL 4.3, or you do not "
|
||||||
|
"have the latest graphics driver."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GRenderWindow::InitializeVulkan() {
|
||||||
|
auto child = new VulkanRenderWidget(this);
|
||||||
|
child_widget = child;
|
||||||
|
child_widget->windowHandle()->create();
|
||||||
|
main_context = std::make_unique<DummyContext>();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void GRenderWindow::OnEmulationStarting(EmuThread* emu_thread) {
|
void GRenderWindow::OnEmulationStarting(EmuThread* emu_thread) {
|
||||||
this->emu_thread = emu_thread;
|
this->emu_thread = emu_thread;
|
||||||
}
|
}
|
||||||
@ -449,31 +619,3 @@ void GRenderWindow::OnEmulationStopping() {
|
|||||||
void GRenderWindow::showEvent(QShowEvent* event) {
|
void GRenderWindow::showEvent(QShowEvent* event) {
|
||||||
QWidget::showEvent(event);
|
QWidget::showEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Frontend::GraphicsContext> GRenderWindow::CreateSharedContext() const {
|
|
||||||
return std::make_unique<GLContext>(QOpenGLContext::globalShareContext());
|
|
||||||
}
|
|
||||||
|
|
||||||
GLContext::GLContext(QOpenGLContext* shared_context)
|
|
||||||
: context(std::make_unique<QOpenGLContext>(shared_context->parent())),
|
|
||||||
surface(std::make_unique<QOffscreenSurface>(nullptr)) {
|
|
||||||
|
|
||||||
// disable vsync for any shared contexts
|
|
||||||
auto format = shared_context->format();
|
|
||||||
format.setSwapInterval(0);
|
|
||||||
|
|
||||||
context->setShareContext(shared_context);
|
|
||||||
context->setFormat(format);
|
|
||||||
context->create();
|
|
||||||
surface->setParent(shared_context->parent());
|
|
||||||
surface->setFormat(format);
|
|
||||||
surface->create();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLContext::MakeCurrent() {
|
|
||||||
context->makeCurrent(surface.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLContext::DoneCurrent() {
|
|
||||||
context->doneCurrent();
|
|
||||||
}
|
|
||||||
|
@ -27,19 +27,6 @@ namespace VideoCore {
|
|||||||
enum class LoadCallbackStage;
|
enum class LoadCallbackStage;
|
||||||
}
|
}
|
||||||
|
|
||||||
class GLContext : public Frontend::GraphicsContext {
|
|
||||||
public:
|
|
||||||
explicit GLContext(QOpenGLContext* shared_context);
|
|
||||||
|
|
||||||
void MakeCurrent() override;
|
|
||||||
|
|
||||||
void DoneCurrent() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::unique_ptr<QOpenGLContext> context;
|
|
||||||
std::unique_ptr<QOffscreenSurface> surface;
|
|
||||||
};
|
|
||||||
|
|
||||||
class EmuThread final : public QThread {
|
class EmuThread final : public QThread {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -126,24 +113,6 @@ signals:
|
|||||||
void HideLoadingScreen();
|
void HideLoadingScreen();
|
||||||
};
|
};
|
||||||
|
|
||||||
class OpenGLWindow : public QWindow {
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
explicit OpenGLWindow(QWindow* parent, QWidget* event_handler, QOpenGLContext* shared_context);
|
|
||||||
|
|
||||||
~OpenGLWindow();
|
|
||||||
|
|
||||||
void Present();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool event(QEvent* event) override;
|
|
||||||
void exposeEvent(QExposeEvent* event) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::unique_ptr<QOpenGLContext> context;
|
|
||||||
QWidget* event_handler;
|
|
||||||
};
|
|
||||||
|
|
||||||
class GRenderWindow : public QWidget, public Frontend::EmuWindow {
|
class GRenderWindow : public QWidget, public Frontend::EmuWindow {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -179,13 +148,15 @@ public:
|
|||||||
|
|
||||||
void focusOutEvent(QFocusEvent* event) override;
|
void focusOutEvent(QFocusEvent* event) override;
|
||||||
|
|
||||||
void InitRenderTarget();
|
bool InitRenderTarget();
|
||||||
|
|
||||||
/// Destroy the previous run's child_widget which should also destroy the child_window
|
/// Destroy the previous run's child_widget which should also destroy the child_window
|
||||||
void ReleaseRenderTarget();
|
void ReleaseRenderTarget();
|
||||||
|
|
||||||
void CaptureScreenshot(u32 res_scale, const QString& screenshot_path);
|
void CaptureScreenshot(u32 res_scale, const QString& screenshot_path);
|
||||||
|
|
||||||
|
std::pair<u32, u32> ScaleTouch(const QPointF pos) const;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void OnEmulationStarting(EmuThread* emu_thread);
|
void OnEmulationStarting(EmuThread* emu_thread);
|
||||||
@ -205,29 +176,29 @@ signals:
|
|||||||
void MouseActivity();
|
void MouseActivity();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::pair<u32, u32> ScaleTouch(QPointF pos) const;
|
|
||||||
void TouchBeginEvent(const QTouchEvent* event);
|
void TouchBeginEvent(const QTouchEvent* event);
|
||||||
void TouchUpdateEvent(const QTouchEvent* event);
|
void TouchUpdateEvent(const QTouchEvent* event);
|
||||||
void TouchEndEvent();
|
void TouchEndEvent();
|
||||||
|
|
||||||
void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override;
|
void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override;
|
||||||
|
|
||||||
std::unique_ptr<GraphicsContext> core_context;
|
bool InitializeOpenGL();
|
||||||
|
bool InitializeVulkan();
|
||||||
QByteArray geometry;
|
|
||||||
|
|
||||||
/// Native window handle that backs this presentation widget
|
|
||||||
QWindow* child_window = nullptr;
|
|
||||||
|
|
||||||
/// In order to embed the window into GRenderWindow, you need to use createWindowContainer to
|
|
||||||
/// put the child_window into a widget then add it to the layout. This child_widget can be
|
|
||||||
/// parented to GRenderWindow and use Qt's lifetime system
|
|
||||||
QWidget* child_widget = nullptr;
|
|
||||||
|
|
||||||
EmuThread* emu_thread;
|
EmuThread* emu_thread;
|
||||||
|
|
||||||
|
// Main context that will be shared with all other contexts that are requested.
|
||||||
|
// If this is used in a shared context setting, then this should not be used directly, but
|
||||||
|
// should instead be shared from
|
||||||
|
std::shared_ptr<Frontend::GraphicsContext> main_context;
|
||||||
|
|
||||||
/// Temporary storage of the screenshot taken
|
/// Temporary storage of the screenshot taken
|
||||||
QImage screenshot_image;
|
QImage screenshot_image;
|
||||||
|
|
||||||
|
QByteArray geometry;
|
||||||
|
|
||||||
|
QWidget* child_widget = nullptr;
|
||||||
|
|
||||||
bool first_frame = false;
|
bool first_frame = false;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -17,8 +17,10 @@ ConfigureGraphics::ConfigureGraphics(QWidget* parent)
|
|||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
SetConfiguration();
|
SetConfiguration();
|
||||||
|
|
||||||
|
const bool not_running = !Core::System::GetInstance().IsPoweredOn();
|
||||||
ui->hw_renderer_group->setEnabled(ui->toggle_hw_renderer->isChecked());
|
ui->hw_renderer_group->setEnabled(ui->toggle_hw_renderer->isChecked());
|
||||||
ui->toggle_vsync_new->setEnabled(!Core::System::GetInstance().IsPoweredOn());
|
ui->toggle_vsync_new->setEnabled(not_running);
|
||||||
|
ui->graphics_api_combo->setEnabled(not_running);
|
||||||
|
|
||||||
connect(ui->toggle_hw_renderer, &QCheckBox::toggled, this, [this] {
|
connect(ui->toggle_hw_renderer, &QCheckBox::toggled, this, [this] {
|
||||||
auto checked = ui->toggle_hw_renderer->isChecked();
|
auto checked = ui->toggle_hw_renderer->isChecked();
|
||||||
|
@ -26,6 +26,36 @@
|
|||||||
<string>Renderer</string>
|
<string>Renderer</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Graphics API</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="graphics_api_combo">
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>OpenGL</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>OpenGLES</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Vulkan</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="toggle_hw_renderer">
|
<widget class="QCheckBox" name="toggle_hw_renderer">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
|
@ -17,12 +17,6 @@
|
|||||||
#include <QtGui>
|
#include <QtGui>
|
||||||
#include <QtWidgets>
|
#include <QtWidgets>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#ifdef __APPLE__
|
|
||||||
#include <unistd.h> // for chdir
|
|
||||||
#endif
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <windows.h>
|
|
||||||
#endif
|
|
||||||
#include "citra_qt/aboutdialog.h"
|
#include "citra_qt/aboutdialog.h"
|
||||||
#include "citra_qt/applets/mii_selector.h"
|
#include "citra_qt/applets/mii_selector.h"
|
||||||
#include "citra_qt/applets/swkbd.h"
|
#include "citra_qt/applets/swkbd.h"
|
||||||
@ -76,7 +70,6 @@
|
|||||||
#include "core/file_sys/archive_extsavedata.h"
|
#include "core/file_sys/archive_extsavedata.h"
|
||||||
#include "core/file_sys/archive_source_sd_savedata.h"
|
#include "core/file_sys/archive_source_sd_savedata.h"
|
||||||
#include "core/frontend/applets/default_applets.h"
|
#include "core/frontend/applets/default_applets.h"
|
||||||
#include "core/frontend/scope_acquire_context.h"
|
|
||||||
#include "core/gdbstub/gdbstub.h"
|
#include "core/gdbstub/gdbstub.h"
|
||||||
#include "core/hle/service/fs/archive.h"
|
#include "core/hle/service/fs/archive.h"
|
||||||
#include "core/hle/service/nfc/nfc.h"
|
#include "core/hle/service/nfc/nfc.h"
|
||||||
@ -90,6 +83,13 @@
|
|||||||
#include "video_core/renderer_base.h"
|
#include "video_core/renderer_base.h"
|
||||||
#include "video_core/video_core.h"
|
#include "video_core/video_core.h"
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <unistd.h> // for chdir
|
||||||
|
#endif
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_DISCORD_PRESENCE
|
#ifdef USE_DISCORD_PRESENCE
|
||||||
#include "citra_qt/discord_impl.h"
|
#include "citra_qt/discord_impl.h"
|
||||||
#endif
|
#endif
|
||||||
@ -914,20 +914,10 @@ bool GMainWindow::LoadROM(const QString& filename) {
|
|||||||
|
|
||||||
render_window->InitRenderTarget();
|
render_window->InitRenderTarget();
|
||||||
|
|
||||||
Frontend::ScopeAcquireContext scope(*render_window);
|
const auto scope = render_window->Acquire();
|
||||||
|
|
||||||
const QString below_gl43_title = tr("OpenGL 4.3 Unsupported");
|
Core::System& system = Core::System::GetInstance();
|
||||||
const QString below_gl43_message = tr("Your GPU may not support OpenGL 4.3, or you do not "
|
const Core::System::ResultStatus result = system.Load(*render_window, filename.toStdString());
|
||||||
"have the latest graphics driver.");
|
|
||||||
|
|
||||||
if (!QOpenGLContext::globalShareContext()->versionFunctions<QOpenGLFunctions_4_3_Core>()) {
|
|
||||||
QMessageBox::critical(this, below_gl43_title, below_gl43_message);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Core::System& system{Core::System::GetInstance()};
|
|
||||||
|
|
||||||
const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())};
|
|
||||||
|
|
||||||
if (result != Core::System::ResultStatus::Success) {
|
if (result != Core::System::ResultStatus::Success) {
|
||||||
switch (result) {
|
switch (result) {
|
||||||
@ -976,7 +966,7 @@ bool GMainWindow::LoadROM(const QString& filename) {
|
|||||||
case Core::System::ResultStatus::ErrorVideoCore:
|
case Core::System::ResultStatus::ErrorVideoCore:
|
||||||
QMessageBox::critical(
|
QMessageBox::critical(
|
||||||
this, tr("Video Core Error"),
|
this, tr("Video Core Error"),
|
||||||
tr("An error has occurred. Please <a "
|
tr("An error has occurred during intialization of the video backend. Please <a "
|
||||||
"href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>see "
|
"href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>see "
|
||||||
"the "
|
"the "
|
||||||
"log</a> for more details. "
|
"log</a> for more details. "
|
||||||
@ -991,10 +981,6 @@ bool GMainWindow::LoadROM(const QString& filename) {
|
|||||||
"proper drivers for your graphics card from the manufacturer's website."));
|
"proper drivers for your graphics card from the manufacturer's website."));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Core::System::ResultStatus::ErrorVideoCore_ErrorBelowGL43:
|
|
||||||
QMessageBox::critical(this, below_gl43_title, below_gl43_message);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
QMessageBox::critical(
|
QMessageBox::critical(
|
||||||
this, tr("Error while loading ROM!"),
|
this, tr("Error while loading ROM!"),
|
||||||
|
@ -110,8 +110,6 @@ add_library(core STATIC
|
|||||||
frontend/input.h
|
frontend/input.h
|
||||||
frontend/mic.cpp
|
frontend/mic.cpp
|
||||||
frontend/mic.h
|
frontend/mic.h
|
||||||
frontend/scope_acquire_context.cpp
|
|
||||||
frontend/scope_acquire_context.h
|
|
||||||
gdbstub/gdbstub.cpp
|
gdbstub/gdbstub.cpp
|
||||||
gdbstub/gdbstub.h
|
gdbstub/gdbstub.h
|
||||||
hle/applets/applet.cpp
|
hle/applets/applet.cpp
|
||||||
|
@ -424,8 +424,6 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mo
|
|||||||
switch (result) {
|
switch (result) {
|
||||||
case VideoCore::ResultStatus::ErrorGenericDrivers:
|
case VideoCore::ResultStatus::ErrorGenericDrivers:
|
||||||
return ResultStatus::ErrorVideoCore_ErrorGenericDrivers;
|
return ResultStatus::ErrorVideoCore_ErrorGenericDrivers;
|
||||||
case VideoCore::ResultStatus::ErrorBelowGL43:
|
|
||||||
return ResultStatus::ErrorVideoCore_ErrorBelowGL43;
|
|
||||||
default:
|
default:
|
||||||
return ResultStatus::ErrorVideoCore;
|
return ResultStatus::ErrorVideoCore;
|
||||||
}
|
}
|
||||||
|
@ -88,8 +88,6 @@ public:
|
|||||||
ErrorVideoCore, ///< Error in the video core
|
ErrorVideoCore, ///< Error in the video core
|
||||||
ErrorVideoCore_ErrorGenericDrivers, ///< Error in the video core due to the user having
|
ErrorVideoCore_ErrorGenericDrivers, ///< Error in the video core due to the user having
|
||||||
/// generic drivers installed
|
/// generic drivers installed
|
||||||
ErrorVideoCore_ErrorBelowGL43, ///< Error in the video core due to the user not having
|
|
||||||
/// OpenGL 4.3 or higher
|
|
||||||
ErrorSavestate, ///< Error saving or loading
|
ErrorSavestate, ///< Error saving or loading
|
||||||
ShutdownRequested, ///< Emulated program requested a system shutdown
|
ShutdownRequested, ///< Emulated program requested a system shutdown
|
||||||
ErrorUnknown ///< Any other error
|
ErrorUnknown ///< Any other error
|
||||||
|
@ -60,11 +60,33 @@ class GraphicsContext {
|
|||||||
public:
|
public:
|
||||||
virtual ~GraphicsContext();
|
virtual ~GraphicsContext();
|
||||||
|
|
||||||
|
/// Inform the driver to swap the front/back buffers and present the current image
|
||||||
|
virtual void SwapBuffers(){};
|
||||||
|
|
||||||
/// Makes the graphics context current for the caller thread
|
/// Makes the graphics context current for the caller thread
|
||||||
virtual void MakeCurrent() = 0;
|
virtual void MakeCurrent(){};
|
||||||
|
|
||||||
/// Releases (dunno if this is the "right" word) the context from the caller thread
|
/// Releases (dunno if this is the "right" word) the context from the caller thread
|
||||||
virtual void DoneCurrent() = 0;
|
virtual void DoneCurrent(){};
|
||||||
|
|
||||||
|
class Scoped {
|
||||||
|
public:
|
||||||
|
explicit Scoped(GraphicsContext& context_) : context(context_) {
|
||||||
|
context.MakeCurrent();
|
||||||
|
}
|
||||||
|
~Scoped() {
|
||||||
|
context.DoneCurrent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
GraphicsContext& context;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Calls MakeCurrent on the context and calls DoneCurrent when the scope for the returned value
|
||||||
|
/// ends
|
||||||
|
[[nodiscard]] Scoped Acquire() {
|
||||||
|
return Scoped{*this};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
// Copyright 2019 yuzu Emulator Project
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#include "core/frontend/emu_window.h"
|
|
||||||
#include "core/frontend/scope_acquire_context.h"
|
|
||||||
|
|
||||||
namespace Frontend {
|
|
||||||
|
|
||||||
ScopeAcquireContext::ScopeAcquireContext(Frontend::GraphicsContext& context) : context{context} {
|
|
||||||
context.MakeCurrent();
|
|
||||||
}
|
|
||||||
ScopeAcquireContext::~ScopeAcquireContext() {
|
|
||||||
context.DoneCurrent();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Frontend
|
|
@ -1,23 +0,0 @@
|
|||||||
// Copyright 2019 yuzu Emulator Project
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "common/common_types.h"
|
|
||||||
|
|
||||||
namespace Frontend {
|
|
||||||
|
|
||||||
class GraphicsContext;
|
|
||||||
|
|
||||||
/// Helper class to acquire/release window context within a given scope
|
|
||||||
class ScopeAcquireContext : NonCopyable {
|
|
||||||
public:
|
|
||||||
explicit ScopeAcquireContext(Frontend::GraphicsContext& context);
|
|
||||||
~ScopeAcquireContext();
|
|
||||||
|
|
||||||
private:
|
|
||||||
Frontend::GraphicsContext& context;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Frontend
|
|
@ -7,7 +7,6 @@
|
|||||||
#include "audio_core/dsp_interface.h"
|
#include "audio_core/dsp_interface.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/gdbstub/gdbstub.h"
|
#include "core/gdbstub/gdbstub.h"
|
||||||
#include "core/hle/kernel/shared_page.h"
|
|
||||||
#include "core/hle/service/cam/cam.h"
|
#include "core/hle/service/cam/cam.h"
|
||||||
#include "core/hle/service/hid/hid.h"
|
#include "core/hle/service/hid/hid.h"
|
||||||
#include "core/hle/service/ir/ir_rst.h"
|
#include "core/hle/service/ir/ir_rst.h"
|
||||||
@ -73,62 +72,62 @@ void Apply() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void LogSettings() {
|
void LogSettings() {
|
||||||
const auto log_setting = [](std::string_view name, const auto& value) {
|
const auto LogSetting = [](std::string_view name, const auto& value) {
|
||||||
LOG_INFO(Config, "{}: {}", name, value);
|
LOG_INFO(Config, "{}: {}", name, value);
|
||||||
};
|
};
|
||||||
|
|
||||||
LOG_INFO(Config, "Citra Configuration:");
|
LOG_INFO(Config, "Citra Configuration:");
|
||||||
log_setting("Core_UseCpuJit", values.use_cpu_jit);
|
LogSetting("Core_UseCpuJit", values.use_cpu_jit);
|
||||||
log_setting("Core_CPUClockPercentage", values.cpu_clock_percentage);
|
LogSetting("Core_CPUClockPercentage", values.cpu_clock_percentage);
|
||||||
log_setting("Renderer_UseGLES", values.use_gles);
|
LogSetting("Renderer_GraphicsAPI", values.graphics_api);
|
||||||
log_setting("Renderer_UseHwRenderer", values.use_hw_renderer);
|
LogSetting("Renderer_UseHwRenderer", values.use_hw_renderer);
|
||||||
log_setting("Renderer_UseHwShader", values.use_hw_shader);
|
LogSetting("Renderer_UseHwShader", values.use_hw_shader);
|
||||||
log_setting("Renderer_SeparableShader", values.separable_shader);
|
LogSetting("Renderer_SeparableShader", values.separable_shader);
|
||||||
log_setting("Renderer_ShadersAccurateMul", values.shaders_accurate_mul);
|
LogSetting("Renderer_ShadersAccurateMul", values.shaders_accurate_mul);
|
||||||
log_setting("Renderer_UseShaderJit", values.use_shader_jit);
|
LogSetting("Renderer_UseShaderJit", values.use_shader_jit);
|
||||||
log_setting("Renderer_UseResolutionFactor", values.resolution_factor);
|
LogSetting("Renderer_UseResolutionFactor", values.resolution_factor);
|
||||||
log_setting("Renderer_FrameLimit", values.frame_limit);
|
LogSetting("Renderer_FrameLimit", values.frame_limit);
|
||||||
log_setting("Renderer_UseFrameLimitAlternate", values.use_frame_limit_alternate);
|
LogSetting("Renderer_UseFrameLimitAlternate", values.use_frame_limit_alternate);
|
||||||
log_setting("Renderer_FrameLimitAlternate", values.frame_limit_alternate);
|
LogSetting("Renderer_FrameLimitAlternate", values.frame_limit_alternate);
|
||||||
log_setting("Renderer_VSyncNew", values.use_vsync_new);
|
LogSetting("Renderer_VSyncNew", values.use_vsync_new);
|
||||||
log_setting("Renderer_PostProcessingShader", values.pp_shader_name);
|
LogSetting("Renderer_PostProcessingShader", values.pp_shader_name);
|
||||||
log_setting("Renderer_FilterMode", values.filter_mode);
|
LogSetting("Renderer_FilterMode", values.filter_mode);
|
||||||
log_setting("Renderer_TextureFilterName", values.texture_filter_name);
|
LogSetting("Renderer_TextureFilterName", values.texture_filter_name);
|
||||||
log_setting("Stereoscopy_Render3d", values.render_3d);
|
LogSetting("Stereoscopy_Render3d", values.render_3d);
|
||||||
log_setting("Stereoscopy_Factor3d", values.factor_3d);
|
LogSetting("Stereoscopy_Factor3d", values.factor_3d);
|
||||||
log_setting("Layout_LayoutOption", values.layout_option);
|
LogSetting("Layout_LayoutOption", values.layout_option);
|
||||||
log_setting("Layout_SwapScreen", values.swap_screen);
|
LogSetting("Layout_SwapScreen", values.swap_screen);
|
||||||
log_setting("Layout_UprightScreen", values.upright_screen);
|
LogSetting("Layout_UprightScreen", values.upright_screen);
|
||||||
log_setting("Utility_DumpTextures", values.dump_textures);
|
LogSetting("Utility_DumpTextures", values.dump_textures);
|
||||||
log_setting("Utility_CustomTextures", values.custom_textures);
|
LogSetting("Utility_CustomTextures", values.custom_textures);
|
||||||
log_setting("Utility_UseDiskShaderCache", values.use_disk_shader_cache);
|
LogSetting("Utility_UseDiskShaderCache", values.use_disk_shader_cache);
|
||||||
log_setting("Audio_EnableDspLle", values.enable_dsp_lle);
|
LogSetting("Audio_EnableDspLle", values.enable_dsp_lle);
|
||||||
log_setting("Audio_EnableDspLleMultithread", values.enable_dsp_lle_multithread);
|
LogSetting("Audio_EnableDspLleMultithread", values.enable_dsp_lle_multithread);
|
||||||
log_setting("Audio_OutputEngine", values.sink_id);
|
LogSetting("Audio_OutputEngine", values.sink_id);
|
||||||
log_setting("Audio_EnableAudioStretching", values.enable_audio_stretching);
|
LogSetting("Audio_EnableAudioStretching", values.enable_audio_stretching);
|
||||||
log_setting("Audio_OutputDevice", values.audio_device_id);
|
LogSetting("Audio_OutputDevice", values.audio_device_id);
|
||||||
log_setting("Audio_InputDeviceType", values.mic_input_type);
|
LogSetting("Audio_InputDeviceType", values.mic_input_type);
|
||||||
log_setting("Audio_InputDevice", values.mic_input_device);
|
LogSetting("Audio_InputDevice", values.mic_input_device);
|
||||||
using namespace Service::CAM;
|
using namespace Service::CAM;
|
||||||
log_setting("Camera_OuterRightName", values.camera_name[OuterRightCamera]);
|
LogSetting("Camera_OuterRightName", values.camera_name[OuterRightCamera]);
|
||||||
log_setting("Camera_OuterRightConfig", values.camera_config[OuterRightCamera]);
|
LogSetting("Camera_OuterRightConfig", values.camera_config[OuterRightCamera]);
|
||||||
log_setting("Camera_OuterRightFlip", values.camera_flip[OuterRightCamera]);
|
LogSetting("Camera_OuterRightFlip", values.camera_flip[OuterRightCamera]);
|
||||||
log_setting("Camera_InnerName", values.camera_name[InnerCamera]);
|
LogSetting("Camera_InnerName", values.camera_name[InnerCamera]);
|
||||||
log_setting("Camera_InnerConfig", values.camera_config[InnerCamera]);
|
LogSetting("Camera_InnerConfig", values.camera_config[InnerCamera]);
|
||||||
log_setting("Camera_InnerFlip", values.camera_flip[InnerCamera]);
|
LogSetting("Camera_InnerFlip", values.camera_flip[InnerCamera]);
|
||||||
log_setting("Camera_OuterLeftName", values.camera_name[OuterLeftCamera]);
|
LogSetting("Camera_OuterLeftName", values.camera_name[OuterLeftCamera]);
|
||||||
log_setting("Camera_OuterLeftConfig", values.camera_config[OuterLeftCamera]);
|
LogSetting("Camera_OuterLeftConfig", values.camera_config[OuterLeftCamera]);
|
||||||
log_setting("Camera_OuterLeftFlip", values.camera_flip[OuterLeftCamera]);
|
LogSetting("Camera_OuterLeftFlip", values.camera_flip[OuterLeftCamera]);
|
||||||
log_setting("DataStorage_UseVirtualSd", values.use_virtual_sd);
|
LogSetting("DataStorage_UseVirtualSd", values.use_virtual_sd);
|
||||||
log_setting("DataStorage_UseCustomStorage", values.use_custom_storage);
|
LogSetting("DataStorage_UseCustomStorage", values.use_custom_storage);
|
||||||
if (values.use_custom_storage) {
|
if (values.use_custom_storage) {
|
||||||
log_setting("DataStorage_SdmcDir", FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir));
|
LogSetting("DataStorage_SdmcDir", FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir));
|
||||||
log_setting("DataStorage_NandDir", FileUtil::GetUserPath(FileUtil::UserPath::NANDDir));
|
LogSetting("DataStorage_NandDir", FileUtil::GetUserPath(FileUtil::UserPath::NANDDir));
|
||||||
}
|
}
|
||||||
log_setting("System_IsNew3ds", values.is_new_3ds);
|
LogSetting("System_IsNew3ds", values.is_new_3ds);
|
||||||
log_setting("System_RegionValue", values.region_value);
|
LogSetting("System_RegionValue", values.region_value);
|
||||||
log_setting("Debugging_UseGdbstub", values.use_gdbstub);
|
LogSetting("Debugging_UseGdbstub", values.use_gdbstub);
|
||||||
log_setting("Debugging_GdbstubPort", values.gdbstub_port);
|
LogSetting("Debugging_GdbstubPort", values.gdbstub_port);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadProfile(int index) {
|
void LoadProfile(int index) {
|
||||||
|
@ -14,6 +14,12 @@
|
|||||||
|
|
||||||
namespace Settings {
|
namespace Settings {
|
||||||
|
|
||||||
|
enum class GraphicsAPI {
|
||||||
|
OpenGL = 0,
|
||||||
|
OpenGLES = 1,
|
||||||
|
Vulkan = 2
|
||||||
|
};
|
||||||
|
|
||||||
enum class InitClock {
|
enum class InitClock {
|
||||||
SystemTime = 0,
|
SystemTime = 0,
|
||||||
FixedTime = 1,
|
FixedTime = 1,
|
||||||
@ -163,7 +169,7 @@ struct Values {
|
|||||||
u64 init_time;
|
u64 init_time;
|
||||||
|
|
||||||
// Renderer
|
// Renderer
|
||||||
bool use_gles;
|
GraphicsAPI graphics_api = GraphicsAPI::OpenGL;
|
||||||
bool use_hw_renderer;
|
bool use_hw_renderer;
|
||||||
bool use_hw_shader;
|
bool use_hw_shader;
|
||||||
bool separable_shader;
|
bool separable_shader;
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
#include <glad/glad.h>
|
#include <glad/glad.h>
|
||||||
#include "core/frontend/emu_window.h"
|
#include "core/frontend/emu_window.h"
|
||||||
#include "core/frontend/scope_acquire_context.h"
|
|
||||||
#include "video_core/renderer_opengl/frame_dumper_opengl.h"
|
#include "video_core/renderer_opengl/frame_dumper_opengl.h"
|
||||||
#include "video_core/renderer_opengl/renderer_opengl.h"
|
#include "video_core/renderer_opengl/renderer_opengl.h"
|
||||||
|
|
||||||
@ -39,7 +38,7 @@ void FrameDumperOpenGL::StopDumping() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void FrameDumperOpenGL::PresentLoop() {
|
void FrameDumperOpenGL::PresentLoop() {
|
||||||
Frontend::ScopeAcquireContext scope{*context};
|
const auto scope = context->Acquire();
|
||||||
InitializeOpenGLObjects();
|
InitializeOpenGLObjects();
|
||||||
|
|
||||||
const auto& layout = GetLayout();
|
const auto& layout = GetLayout();
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <boost/variant.hpp>
|
#include <boost/variant.hpp>
|
||||||
#include "core/frontend/scope_acquire_context.h"
|
|
||||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
||||||
#include "video_core/renderer_opengl/gl_shader_disk_cache.h"
|
#include "video_core/renderer_opengl/gl_shader_disk_cache.h"
|
||||||
#include "video_core/renderer_opengl/gl_shader_manager.h"
|
#include "video_core/renderer_opengl/gl_shader_manager.h"
|
||||||
@ -640,7 +639,7 @@ void ShaderProgramManager::LoadDiskCache(const std::atomic_bool& stop_loading,
|
|||||||
std::size_t built_shaders = 0; // It doesn't have be atomic since it's used behind a mutex
|
std::size_t built_shaders = 0; // It doesn't have be atomic since it's used behind a mutex
|
||||||
const auto LoadRawSepareble = [&](Frontend::GraphicsContext* context, std::size_t begin,
|
const auto LoadRawSepareble = [&](Frontend::GraphicsContext* context, std::size_t begin,
|
||||||
std::size_t end) {
|
std::size_t end) {
|
||||||
Frontend::ScopeAcquireContext scope(*context);
|
const auto scope = context->Acquire();
|
||||||
for (std::size_t i = begin; i < end; ++i) {
|
for (std::size_t i = begin; i < end; ++i) {
|
||||||
if (stop_loading || compilation_failed) {
|
if (stop_loading || compilation_failed) {
|
||||||
return;
|
return;
|
||||||
|
@ -1234,7 +1234,7 @@ static void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum
|
|||||||
VideoCore::ResultStatus RendererOpenGL::Init() {
|
VideoCore::ResultStatus RendererOpenGL::Init() {
|
||||||
#ifndef ANDROID
|
#ifndef ANDROID
|
||||||
if (!gladLoadGL()) {
|
if (!gladLoadGL()) {
|
||||||
return VideoCore::ResultStatus::ErrorBelowGL43;
|
return VideoCore::ResultStatus::ErrorRendererInit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Qualcomm has some spammy info messages that are marked as errors but not important
|
// Qualcomm has some spammy info messages that are marked as errors but not important
|
||||||
@ -1264,7 +1264,7 @@ VideoCore::ResultStatus RendererOpenGL::Init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!(GLAD_GL_VERSION_4_3 || GLAD_GL_ES_VERSION_3_1)) {
|
if (!(GLAD_GL_VERSION_4_3 || GLAD_GL_ES_VERSION_3_1)) {
|
||||||
return VideoCore::ResultStatus::ErrorBelowGL43;
|
return VideoCore::ResultStatus::ErrorRendererInit;
|
||||||
}
|
}
|
||||||
|
|
||||||
InitOpenGLObjects();
|
InitOpenGLObjects();
|
||||||
|
@ -43,7 +43,7 @@ ResultStatus Init(Frontend::EmuWindow& emu_window, Memory::MemorySystem& memory)
|
|||||||
g_memory = &memory;
|
g_memory = &memory;
|
||||||
Pica::Init();
|
Pica::Init();
|
||||||
|
|
||||||
OpenGL::GLES = Settings::values.use_gles;
|
OpenGL::GLES = Settings::values.graphics_api == Settings::GraphicsAPI::OpenGLES;
|
||||||
|
|
||||||
g_renderer = std::make_unique<OpenGL::RendererOpenGL>(emu_window);
|
g_renderer = std::make_unique<OpenGL::RendererOpenGL>(emu_window);
|
||||||
ResultStatus result = g_renderer->Init();
|
ResultStatus result = g_renderer->Init();
|
||||||
|
@ -49,8 +49,8 @@ extern Memory::MemorySystem* g_memory;
|
|||||||
|
|
||||||
enum class ResultStatus {
|
enum class ResultStatus {
|
||||||
Success,
|
Success,
|
||||||
ErrorGenericDrivers,
|
ErrorRendererInit,
|
||||||
ErrorBelowGL43,
|
ErrorGenericDrivers
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Initialize the video core
|
/// Initialize the video core
|
||||||
|
Reference in New Issue
Block a user