diff options
Diffstat (limited to 'src/yuzu/bootmanager.cpp')
-rw-r--r-- | src/yuzu/bootmanager.cpp | 185 |
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() { |