summaryrefslogtreecommitdiff
path: root/src/yuzu/bootmanager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/yuzu/bootmanager.cpp')
-rw-r--r--src/yuzu/bootmanager.cpp185
1 files changed, 128 insertions, 57 deletions
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index 114f17c06..24251247d 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -1,12 +1,12 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
+// SPDX-FileCopyrightText: 2014 Citra Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
#include <glad/glad.h>
#include <QApplication>
+#include <QCameraImageCapture>
+#include <QCameraInfo>
#include <QHBoxLayout>
-#include <QKeyEvent>
#include <QMessageBox>
#include <QPainter>
#include <QScreen>
@@ -28,17 +28,17 @@
#include "common/assert.h"
#include "common/microprofile.h"
#include "common/scm_rev.h"
-#include "common/scope_exit.h"
#include "common/settings.h"
#include "core/core.h"
+#include "core/cpu_manager.h"
#include "core/frontend/framebuffer_layout.h"
+#include "input_common/drivers/camera.h"
#include "input_common/drivers/keyboard.h"
#include "input_common/drivers/mouse.h"
#include "input_common/drivers/tas_input.h"
#include "input_common/drivers/touch_screen.h"
#include "input_common/main.h"
#include "video_core/renderer_base.h"
-#include "video_core/video_core.h"
#include "yuzu/bootmanager.h"
#include "yuzu/main.h"
@@ -47,12 +47,13 @@ EmuThread::EmuThread(Core::System& system_) : system{system_} {}
EmuThread::~EmuThread() = default;
void EmuThread::run() {
- std::string name = "yuzu:EmuControlThread";
+ std::string name = "EmuControlThread";
MicroProfileOnThreadCreate(name.c_str());
Common::SetCurrentThreadName(name.c_str());
auto& gpu = system.GPU();
auto stop_token = stop_source.get_token();
+ bool debugger_should_start = system.DebuggerEnabled();
system.RegisterHostThread();
@@ -75,6 +76,8 @@ void EmuThread::run() {
gpu.ReleaseContext();
+ system.GetCpuManager().OnGpuReady();
+
// Holds whether the cpu was running during the last iteration,
// so that the DebugModeLeft signal can be emitted before the
// next execution step
@@ -92,6 +95,12 @@ void EmuThread::run() {
this->SetRunning(false);
emit ErrorThrown(result, system.GetStatusDetails());
}
+
+ if (debugger_should_start) {
+ system.InitializeDebugger();
+ debugger_should_start = false;
+ }
+
running_wait.Wait();
result = system.Pause();
if (result != Core::SystemResultStatus::Success) {
@@ -105,11 +114,9 @@ void EmuThread::run() {
was_active = true;
emit DebugModeEntered();
}
- } else if (exec_step) {
- UNIMPLEMENTED();
} else {
std::unique_lock lock{running_mutex};
- running_cv.wait(lock, stop_token, [this] { return IsRunning() || exec_step; });
+ running_cv.wait(lock, stop_token, [this] { return IsRunning(); });
}
}
@@ -125,7 +132,7 @@ void EmuThread::run() {
class OpenGLSharedContext : public Core::Frontend::GraphicsContext {
public:
/// Create the original context that should be shared from
- explicit OpenGLSharedContext(QSurface* surface) : surface(surface) {
+ explicit OpenGLSharedContext(QSurface* surface_) : surface{surface_} {
QSurfaceFormat format;
format.setVersion(4, 6);
format.setProfile(QSurfaceFormat::CompatibilityProfile);
@@ -362,9 +369,9 @@ void GRenderWindow::RestoreGeometry() {
QWidget::restoreGeometry(geometry);
}
-void GRenderWindow::restoreGeometry(const QByteArray& geometry) {
+void GRenderWindow::restoreGeometry(const QByteArray& geometry_) {
// Make sure users of this class don't need to deal with backing up the geometry themselves
- QWidget::restoreGeometry(geometry);
+ QWidget::restoreGeometry(geometry_);
BackupGeometry();
}
@@ -750,7 +757,7 @@ void GRenderWindow::mouseMoveEvent(QMouseEvent* event) {
input_subsystem->GetMouse()->MouseMove(x, y, touch_x, touch_y, center_x, center_y);
if (Settings::values.mouse_panning && !Settings::values.mouse_enabled) {
- QCursor::setPos(mapToGlobal({center_x, center_y}));
+ QCursor::setPos(mapToGlobal(QPoint{center_x, center_y}));
}
emit MouseActivity();
@@ -775,65 +782,123 @@ void GRenderWindow::wheelEvent(QWheelEvent* event) {
void GRenderWindow::TouchBeginEvent(const QTouchEvent* event) {
QList<QTouchEvent::TouchPoint> touch_points = event->touchPoints();
for (const auto& touch_point : touch_points) {
- if (!TouchUpdate(touch_point)) {
- TouchStart(touch_point);
- }
+ const auto [x, y] = ScaleTouch(touch_point.pos());
+ const auto [touch_x, touch_y] = MapToTouchScreen(x, y);
+ input_subsystem->GetTouchScreen()->TouchPressed(touch_x, touch_y, touch_point.id());
}
}
void GRenderWindow::TouchUpdateEvent(const QTouchEvent* event) {
QList<QTouchEvent::TouchPoint> touch_points = event->touchPoints();
+ input_subsystem->GetTouchScreen()->ClearActiveFlag();
for (const auto& touch_point : touch_points) {
- if (!TouchUpdate(touch_point)) {
- TouchStart(touch_point);
- }
- }
- // Release all inactive points
- for (std::size_t id = 0; id < touch_ids.size(); ++id) {
- if (!TouchExist(touch_ids[id], touch_points)) {
- touch_ids[id] = 0;
- input_subsystem->GetTouchScreen()->TouchReleased(id);
- }
+ const auto [x, y] = ScaleTouch(touch_point.pos());
+ const auto [touch_x, touch_y] = MapToTouchScreen(x, y);
+ input_subsystem->GetTouchScreen()->TouchMoved(touch_x, touch_y, touch_point.id());
}
+ input_subsystem->GetTouchScreen()->ReleaseInactiveTouch();
}
void GRenderWindow::TouchEndEvent() {
- for (std::size_t id = 0; id < touch_ids.size(); ++id) {
- if (touch_ids[id] != 0) {
- touch_ids[id] = 0;
- input_subsystem->GetTouchScreen()->TouchReleased(id);
+ input_subsystem->GetTouchScreen()->ReleaseAllTouch();
+}
+
+void GRenderWindow::InitializeCamera() {
+ constexpr auto camera_update_ms = std::chrono::milliseconds{50}; // (50ms, 20Hz)
+ if (!Settings::values.enable_ir_sensor) {
+ return;
+ }
+
+ bool camera_found = false;
+ const QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
+ for (const QCameraInfo& cameraInfo : cameras) {
+ if (Settings::values.ir_sensor_device.GetValue() == cameraInfo.deviceName().toStdString() ||
+ Settings::values.ir_sensor_device.GetValue() == "Auto") {
+ camera = std::make_unique<QCamera>(cameraInfo);
+ if (!camera->isCaptureModeSupported(QCamera::CaptureMode::CaptureViewfinder) &&
+ !camera->isCaptureModeSupported(QCamera::CaptureMode::CaptureStillImage)) {
+ LOG_ERROR(Frontend,
+ "Camera doesn't support CaptureViewfinder or CaptureStillImage");
+ continue;
+ }
+ camera_found = true;
+ break;
}
}
+
+ if (!camera_found) {
+ return;
+ }
+
+ camera_capture = std::make_unique<QCameraImageCapture>(camera.get());
+
+ if (!camera_capture->isCaptureDestinationSupported(
+ QCameraImageCapture::CaptureDestination::CaptureToBuffer)) {
+ LOG_ERROR(Frontend, "Camera doesn't support saving to buffer");
+ return;
+ }
+
+ camera_capture->setCaptureDestination(QCameraImageCapture::CaptureDestination::CaptureToBuffer);
+ connect(camera_capture.get(), &QCameraImageCapture::imageCaptured, this,
+ &GRenderWindow::OnCameraCapture);
+ camera->unload();
+ if (camera->isCaptureModeSupported(QCamera::CaptureMode::CaptureViewfinder)) {
+ camera->setCaptureMode(QCamera::CaptureViewfinder);
+ } else if (camera->isCaptureModeSupported(QCamera::CaptureMode::CaptureStillImage)) {
+ camera->setCaptureMode(QCamera::CaptureStillImage);
+ }
+ camera->load();
+ camera->start();
+
+ pending_camera_snapshots = 0;
+ is_virtual_camera = false;
+
+ camera_timer = std::make_unique<QTimer>();
+ connect(camera_timer.get(), &QTimer::timeout, [this] { RequestCameraCapture(); });
+ // This timer should be dependent of camera resolution 5ms for every 100 pixels
+ camera_timer->start(camera_update_ms);
}
-void GRenderWindow::TouchStart(const QTouchEvent::TouchPoint& touch_point) {
- for (std::size_t id = 0; id < touch_ids.size(); ++id) {
- if (touch_ids[id] == 0) {
- touch_ids[id] = touch_point.id() + 1;
- const auto [x, y] = ScaleTouch(touch_point.pos());
- const auto [touch_x, touch_y] = MapToTouchScreen(x, y);
- input_subsystem->GetTouchScreen()->TouchPressed(touch_x, touch_y, id);
- }
+void GRenderWindow::FinalizeCamera() {
+ if (camera_timer) {
+ camera_timer->stop();
+ }
+ if (camera) {
+ camera->unload();
}
}
-bool GRenderWindow::TouchUpdate(const QTouchEvent::TouchPoint& touch_point) {
- for (std::size_t id = 0; id < touch_ids.size(); ++id) {
- if (touch_ids[id] == static_cast<std::size_t>(touch_point.id() + 1)) {
- const auto [x, y] = ScaleTouch(touch_point.pos());
- const auto [touch_x, touch_y] = MapToTouchScreen(x, y);
- input_subsystem->GetTouchScreen()->TouchMoved(touch_x, touch_y, id);
- return true;
- }
+void GRenderWindow::RequestCameraCapture() {
+ if (!Settings::values.enable_ir_sensor) {
+ return;
}
- return false;
+
+ // If the camera doesn't capture, test for virtual cameras
+ if (pending_camera_snapshots > 5) {
+ is_virtual_camera = true;
+ }
+ // Virtual cameras like obs need to reset the camera every capture
+ if (is_virtual_camera) {
+ camera->stop();
+ camera->start();
+ }
+
+ pending_camera_snapshots++;
+ camera_capture->capture();
}
-bool GRenderWindow::TouchExist(std::size_t id,
- const QList<QTouchEvent::TouchPoint>& touch_points) const {
- return std::any_of(touch_points.begin(), touch_points.end(), [id](const auto& point) {
- return id == static_cast<std::size_t>(point.id() + 1);
- });
+void GRenderWindow::OnCameraCapture(int requestId, const QImage& img) {
+ constexpr std::size_t camera_width = 320;
+ constexpr std::size_t camera_height = 240;
+ const auto converted =
+ img.scaled(camera_width, camera_height, Qt::AspectRatioMode::IgnoreAspectRatio,
+ Qt::TransformationMode::SmoothTransformation)
+ .mirrored(false, true);
+ std::vector<u32> camera_data{};
+ camera_data.resize(camera_width * camera_height);
+ std::memcpy(camera_data.data(), converted.bits(), camera_width * camera_height * sizeof(u32));
+ input_subsystem->GetCamera()->SetCameraData(camera_width, camera_height, camera_data);
+ pending_camera_snapshots = 0;
}
bool GRenderWindow::event(QEvent* event) {
@@ -936,6 +1001,12 @@ void GRenderWindow::CaptureScreenshot(const QString& screenshot_path) {
auto& renderer = system.Renderer();
const f32 res_scale = Settings::values.resolution_info.up_factor;
+ if (renderer.IsScreenshotPending()) {
+ LOG_WARNING(Render,
+ "A screenshot is already requested or in progress, ignoring the request");
+ return;
+ }
+
const Layout::FramebufferLayout layout{Layout::FrameLayoutFromResolutionScale(res_scale)};
screenshot_image = QImage(QSize(layout.width, layout.height), QImage::Format_RGB32);
renderer.RequestScreenshot(
@@ -1036,8 +1107,8 @@ QStringList GRenderWindow::GetUnsupportedGLExtensions() const {
}
if (!unsupported_ext.empty()) {
- LOG_ERROR(Frontend, "GPU does not support all required extensions: {}",
- glGetString(GL_RENDERER));
+ const std::string gl_renderer{reinterpret_cast<const char*>(glGetString(GL_RENDERER))};
+ LOG_ERROR(Frontend, "GPU does not support all required extensions: {}", gl_renderer);
}
for (const QString& ext : unsupported_ext) {
LOG_ERROR(Frontend, "Unsupported GL extension: {}", ext.toStdString());
@@ -1046,8 +1117,8 @@ QStringList GRenderWindow::GetUnsupportedGLExtensions() const {
return unsupported_ext;
}
-void GRenderWindow::OnEmulationStarting(EmuThread* emu_thread) {
- this->emu_thread = emu_thread;
+void GRenderWindow::OnEmulationStarting(EmuThread* emu_thread_) {
+ emu_thread = emu_thread_;
}
void GRenderWindow::OnEmulationStopping() {