Merge branch 'master' into netplay
This commit is contained in:
commit
59bc4d3038
|
@ -17,6 +17,7 @@ ipch/*
|
|||
*.vcxproj.user
|
||||
*.VC.opendb
|
||||
*.VC.db
|
||||
/.vscode/
|
||||
|
||||
# cmake stuff
|
||||
CMakeCache.txt
|
||||
|
|
|
@ -44,7 +44,7 @@ if(SUPPORTS_X11)
|
|||
option(USE_X11 "Support X11 window system" ON)
|
||||
endif()
|
||||
if(SUPPORTS_WAYLAND)
|
||||
option(USE_WAYLAND "Support Wayland window system" OFF)
|
||||
option(USE_WAYLAND "Support Wayland window system" ON)
|
||||
endif()
|
||||
if((LINUX OR FREEBSD) OR ANDROID)
|
||||
option(USE_EGL "Support EGL OpenGL context creation" ON)
|
||||
|
@ -53,6 +53,7 @@ if((LINUX OR FREEBSD) AND NOT ANDROID)
|
|||
option(USE_DRMKMS "Support DRM/KMS OpenGL contexts" OFF)
|
||||
option(USE_FBDEV "Support FBDev OpenGL contexts" OFF)
|
||||
option(USE_EVDEV "Support EVDev controller interface" OFF)
|
||||
option(USE_DBUS "Enable DBus support for screensaver inhibiting" ON)
|
||||
endif()
|
||||
|
||||
# Force EGL when using Wayland
|
||||
|
|
10
README.md
10
README.md
|
@ -1,8 +1,6 @@
|
|||
# DuckStation - PlayStation 1, aka. PSX Emulator
|
||||
[Latest News](#latest-news) | [Features](#features) | [Screenshots](#screenshots) | [Downloading and Running](#downloading-and-running) | [Building](#building) | [Disclaimers](#disclaimers)
|
||||
|
||||
**Discord Server:** https://discord.gg/Buktv3t
|
||||
|
||||
**Latest Builds for Windows and Linux (AppImage)** https://github.com/stenzek/duckstation/releases/tag/latest
|
||||
|
||||
**Game Compatibility List:** https://docs.google.com/spreadsheets/d/1H66MxViRjjE5f8hOl5RQmF5woS1murio2dsLn14kEqo/edit
|
||||
|
@ -144,14 +142,14 @@ Requirements:
|
|||
### Linux
|
||||
Requirements (Debian/Ubuntu package names):
|
||||
- CMake (`cmake`)
|
||||
- SDL2 (at least version 2.0.22) (`libsdl2-dev`, `libxrandr-dev`)
|
||||
- SDL2 (at least version 2.0.22) (`libsdl2-dev` `libxrandr-dev`)
|
||||
- pkgconfig (`pkg-config`)
|
||||
- Qt 6 (at least version 6.1.0) (`qtbase6-dev`, `qtbase6-private-dev`, `qtbase6-dev-tools`, `qttools6-dev`)
|
||||
- Qt 6 (at least version 6.1.0) (`qt6-base-dev` `qt6-base-private-dev` `qt6-base-dev-tools` `qt6-tools-dev` `libqt6svg6`)
|
||||
- libevdev (`libevdev-dev`)
|
||||
- git (`git`) (Note: needed to clone the repository and at build time)
|
||||
- When Wayland is enabled (default): `libwayland-dev` `libwayland-egl-backend-dev` `extra-cmake-modules`
|
||||
- When Wayland is enabled (default): (`libwayland-dev` `libwayland-egl-backend-dev` `extra-cmake-modules` `qt6-wayland`)
|
||||
- Optional for RetroAchievements (on by default): libcurl (`libcurl4-gnutls-dev`)
|
||||
- Optional for framebuffer output: DRM/GBM (`libgbm-dev`, `libdrm-dev`)
|
||||
- Optional for framebuffer output: DRM/GBM (`libgbm-dev` `libdrm-dev`)
|
||||
- Optional for faster building: Ninja (`ninja-build`)
|
||||
|
||||
1. Clone the repository. Submodules aren't necessary, there is only one and it is only used for Windows (`git clone https://github.com/stenzek/duckstation.git -b dev`).
|
||||
|
|
|
@ -202,14 +202,14 @@ Requisitos:
|
|||
### Linux
|
||||
Requisitos (Debian/Ubuntu):
|
||||
- CMake (`cmake`)
|
||||
- SDL2 (`libsdl2-dev`, `libxrandr-dev`)
|
||||
- SDL2 (`libsdl2-dev` `libxrandr-dev`)
|
||||
- pkgconfig (`pkg-config`)
|
||||
- Qt 5 (`qtbase5-dev`, `qtbase5-private-dev`, `qtbase5-dev-tools`, `qttools5-dev`)
|
||||
- Qt 6 (`qt6-base-dev` `qt6-base-private-dev` `qt6-base-dev-tools` `qt6-tools-dev` `libqt6svg6`)
|
||||
- libevdev (`libevdev-dev`)
|
||||
- git (`git`) (Nota: necessário para clonar o repositório e em tempo de construção)
|
||||
- Quando o wayland está ativado (padrão): `libwayland-dev` `libwayland-egl-backend-dev` `extra-cmake-modules`
|
||||
- Quando o wayland está ativado (padrão): (`libwayland-dev` `libwayland-egl-backend-dev` `extra-cmake-modules` `qt6-wayland`)
|
||||
- Opcional para RetroAchievements (ativado por padrão): libcurl (`libcurl4-gnutls-dev`)
|
||||
- Opcional para saída do framebuffer: DRM/GBM (`libgbm-dev`, `libdrm-dev`)
|
||||
- Opcional para saída do framebuffer: DRM/GBM (`libgbm-dev` `libdrm-dev`)
|
||||
- Opcional para construção rápida: Ninja (`ninja-build`)
|
||||
|
||||
1. Clone o repositório. Submódulos não são necessários, há apenas um e é usado apenas para Windows (`git clone https://github.com/stenzek/duckstation.git -b dev`).
|
||||
|
@ -293,4 +293,4 @@ Atalhos:
|
|||
Ícone feito icons8: https://icons8.com/icon/74847/platforms.undefined.short-title
|
||||
|
||||
"PlayStation" e "PSX" são marcas registradas da Sony Interactive Entertainment Europe Limited.
|
||||
Este projeto não é afiliado de forma alguma com a Sony Interactive Entertainment.
|
||||
Este projeto não é afiliado de forma alguma com a Sony Interactive Entertainment.
|
||||
|
|
|
@ -148,6 +148,7 @@ declare -a SYSLIBS=(
|
|||
"libhx509.so.5"
|
||||
"libsqlite3.so.0"
|
||||
"libcrypt.so.1"
|
||||
"libdbus-1.so.3"
|
||||
)
|
||||
|
||||
declare -a DEPLIBS=(
|
||||
|
|
|
@ -125,6 +125,8 @@ endif()
|
|||
|
||||
if(USE_WAYLAND)
|
||||
target_compile_definitions(common PRIVATE "-DUSE_WAYLAND=1")
|
||||
elseif(SUPPORTS_WAYLAND)
|
||||
message(WARNING "Wayland support for renderers is disabled.\nDuckStation will FAIL to start on Wayland.")
|
||||
endif()
|
||||
|
||||
if(USE_DRMKMS)
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "context.h"
|
||||
#include "../log.h"
|
||||
#include "loader.h"
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#ifdef __APPLE__
|
||||
#include <stdlib.h>
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#pragma once
|
||||
#include "types.h"
|
||||
#include <cinttypes>
|
||||
#include <cstdarg>
|
||||
#include <mutex>
|
||||
|
||||
enum LOGLEVEL
|
||||
|
|
|
@ -76,6 +76,8 @@ add_library(core
|
|||
negcon.h
|
||||
pad.cpp
|
||||
pad.h
|
||||
pcdrv.cpp
|
||||
pcdrv.h
|
||||
pgxp.cpp
|
||||
pgxp.h
|
||||
playstation_mouse.cpp
|
||||
|
|
|
@ -2019,6 +2019,27 @@ bool SafeReadMemoryWord(VirtualMemoryAddress addr, u32* value)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool SafeReadMemoryCString(VirtualMemoryAddress addr, std::string* value, u32 max_length /*= 1024*/)
|
||||
{
|
||||
value->clear();
|
||||
|
||||
u8 ch;
|
||||
while (SafeReadMemoryByte(addr, &ch))
|
||||
{
|
||||
if (ch == 0)
|
||||
return true;
|
||||
|
||||
value->push_back(ch);
|
||||
if (value->size() >= max_length)
|
||||
return true;
|
||||
|
||||
addr++;
|
||||
}
|
||||
|
||||
value->clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SafeWriteMemoryByte(VirtualMemoryAddress addr, u8 value)
|
||||
{
|
||||
u32 temp = ZeroExtend32(value);
|
||||
|
|
|
@ -7,13 +7,14 @@
|
|||
#include "digital_controller.h"
|
||||
#include "fmt/format.h"
|
||||
#include "guncon.h"
|
||||
#include "host.h"
|
||||
#include "negcon.h"
|
||||
#include "playstation_mouse.h"
|
||||
#include "util/state_wrapper.h"
|
||||
|
||||
static const Controller::ControllerInfo s_none_info = {ControllerType::None,
|
||||
"None",
|
||||
"Not Connected",
|
||||
TRANSLATABLE("ControllerType", "Not Connected"),
|
||||
nullptr,
|
||||
0,
|
||||
nullptr,
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
<ClCompile Include="netplay.cpp" />
|
||||
<ClCompile Include="pad.cpp" />
|
||||
<ClCompile Include="controller.cpp" />
|
||||
<ClCompile Include="pcdrv.cpp" />
|
||||
<ClCompile Include="pgxp.cpp" />
|
||||
<ClCompile Include="playstation_mouse.cpp" />
|
||||
<ClCompile Include="psf_loader.cpp" />
|
||||
|
@ -141,6 +142,7 @@
|
|||
<ClInclude Include="netplay.h" />
|
||||
<ClInclude Include="pad.h" />
|
||||
<ClInclude Include="controller.h" />
|
||||
<ClInclude Include="pcdrv.h" />
|
||||
<ClInclude Include="pgxp.h" />
|
||||
<ClInclude Include="playstation_mouse.h" />
|
||||
<ClInclude Include="psf_loader.h" />
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
<ClCompile Include="gpu_hw_d3d12.cpp" />
|
||||
<ClCompile Include="host.cpp" />
|
||||
<ClCompile Include="game_database.cpp" />
|
||||
<ClCompile Include="pcdrv.cpp" />
|
||||
<ClCompile Include="netplay.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -126,6 +127,7 @@
|
|||
<ClInclude Include="achievements.h" />
|
||||
<ClInclude Include="game_database.h" />
|
||||
<ClInclude Include="input_types.h" />
|
||||
<ClInclude Include="pcdrv.h" />
|
||||
<ClInclude Include="netplay.h" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "cpu_recompiler_thunks.h"
|
||||
#include "gte.h"
|
||||
#include "host.h"
|
||||
#include "pcdrv.h"
|
||||
#include "pgxp.h"
|
||||
#include "settings.h"
|
||||
#include "system.h"
|
||||
|
@ -293,6 +294,20 @@ void RaiseException(Exception excode)
|
|||
g_state.current_instruction_pc, GetExceptionVector());
|
||||
}
|
||||
|
||||
void RaiseBreakException(u32 CAUSE_bits, u32 EPC, u32 instruction_bits)
|
||||
{
|
||||
if (PCDrv::HandleSyscall(instruction_bits, g_state.regs))
|
||||
{
|
||||
// immediately return
|
||||
g_state.regs.npc = EPC + 4;
|
||||
FlushPipeline();
|
||||
return;
|
||||
}
|
||||
|
||||
// normal exception
|
||||
RaiseException(CAUSE_bits, EPC, GetExceptionVector());
|
||||
}
|
||||
|
||||
void SetExternalInterrupt(u8 bit)
|
||||
{
|
||||
g_state.cop0_regs.cause.Ip |= static_cast<u8>(1u << bit);
|
||||
|
@ -1109,7 +1124,10 @@ restart_instruction:
|
|||
|
||||
case InstructionFunct::break_:
|
||||
{
|
||||
RaiseException(Exception::BP);
|
||||
RaiseBreakException(Cop0Registers::CAUSE::MakeValueForException(
|
||||
Exception::BP, g_state.current_instruction_in_branch_delay_slot,
|
||||
g_state.current_instruction_was_branch_taken, g_state.current_instruction.cop.cop_n),
|
||||
g_state.current_instruction_pc, g_state.current_instruction.bits);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "types.h"
|
||||
#include <array>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class StateWrapper;
|
||||
|
@ -147,6 +148,7 @@ ALWAYS_INLINE bool InKernelMode()
|
|||
bool SafeReadMemoryByte(VirtualMemoryAddress addr, u8* value);
|
||||
bool SafeReadMemoryHalfWord(VirtualMemoryAddress addr, u16* value);
|
||||
bool SafeReadMemoryWord(VirtualMemoryAddress addr, u32* value);
|
||||
bool SafeReadMemoryCString(VirtualMemoryAddress addr, std::string* value, u32 max_length = 1024);
|
||||
bool SafeWriteMemoryByte(VirtualMemoryAddress addr, u8 value);
|
||||
bool SafeWriteMemoryHalfWord(VirtualMemoryAddress addr, u16 value);
|
||||
bool SafeWriteMemoryWord(VirtualMemoryAddress addr, u32 value);
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace CPU {
|
|||
// exceptions
|
||||
void RaiseException(Exception excode);
|
||||
void RaiseException(u32 CAUSE_bits, u32 EPC);
|
||||
void RaiseBreakException(u32 CAUSE_bits, u32 EPC, u32 instruction_bits);
|
||||
|
||||
ALWAYS_INLINE bool HasPendingInterrupt()
|
||||
{
|
||||
|
|
|
@ -931,8 +931,17 @@ void CodeGenerator::GenerateExceptionExit(const CodeBlockInstruction& cbi, Excep
|
|||
m_register_cache.FlushAllGuestRegisters(true, true);
|
||||
m_register_cache.FlushLoadDelay(true);
|
||||
|
||||
EmitFunctionCall(nullptr, static_cast<void (*)(u32, u32)>(&CPU::RaiseException), CAUSE_bits,
|
||||
GetCurrentInstructionPC());
|
||||
if (excode == Exception::BP)
|
||||
{
|
||||
EmitFunctionCall(nullptr, static_cast<void (*)(u32, u32, u32)>(&CPU::RaiseBreakException), CAUSE_bits,
|
||||
GetCurrentInstructionPC(), Value::FromConstantU32(cbi.instruction.bits));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitFunctionCall(nullptr, static_cast<void (*)(u32, u32)>(&CPU::RaiseException), CAUSE_bits,
|
||||
GetCurrentInstructionPC());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -232,18 +232,20 @@ void HostDisplay::CalculateDrawRect(s32 window_width, s32 window_height, float*
|
|||
apply_aspect_ratio ?
|
||||
(display_aspect_ratio / (static_cast<float>(m_display_width) / static_cast<float>(m_display_height))) :
|
||||
1.0f;
|
||||
const float display_width = g_settings.display_stretch_vertically ?
|
||||
static_cast<float>(m_display_width) : static_cast<float>(m_display_width) * x_scale;
|
||||
const float display_height = g_settings.display_stretch_vertically ?
|
||||
static_cast<float>(m_display_height) / x_scale : static_cast<float>(m_display_height);
|
||||
const float active_left = g_settings.display_stretch_vertically ?
|
||||
static_cast<float>(m_display_active_left) : static_cast<float>(m_display_active_left) * x_scale;
|
||||
const float active_top = g_settings.display_stretch_vertically ?
|
||||
static_cast<float>(m_display_active_top) / x_scale : static_cast<float>(m_display_active_top);
|
||||
const float display_width = g_settings.display_stretch_vertically ? static_cast<float>(m_display_width) :
|
||||
static_cast<float>(m_display_width) * x_scale;
|
||||
const float display_height = g_settings.display_stretch_vertically ? static_cast<float>(m_display_height) / x_scale :
|
||||
static_cast<float>(m_display_height);
|
||||
const float active_left = g_settings.display_stretch_vertically ? static_cast<float>(m_display_active_left) :
|
||||
static_cast<float>(m_display_active_left) * x_scale;
|
||||
const float active_top = g_settings.display_stretch_vertically ? static_cast<float>(m_display_active_top) / x_scale :
|
||||
static_cast<float>(m_display_active_top);
|
||||
const float active_width = g_settings.display_stretch_vertically ?
|
||||
static_cast<float>(m_display_active_width) : static_cast<float>(m_display_active_width) * x_scale;
|
||||
static_cast<float>(m_display_active_width) :
|
||||
static_cast<float>(m_display_active_width) * x_scale;
|
||||
const float active_height = g_settings.display_stretch_vertically ?
|
||||
static_cast<float>(m_display_active_height) / x_scale : static_cast<float>(m_display_active_height);
|
||||
static_cast<float>(m_display_active_height) / x_scale :
|
||||
static_cast<float>(m_display_active_height);
|
||||
if (out_x_scale)
|
||||
*out_x_scale = x_scale;
|
||||
|
||||
|
@ -500,11 +502,13 @@ bool HostDisplay::WriteDisplayTextureToFile(std::string filename, bool full_reso
|
|||
const float ss_height_scale = static_cast<float>(m_display_active_height) / static_cast<float>(m_display_height);
|
||||
const float ss_aspect_ratio = m_display_aspect_ratio * ss_width_scale / ss_height_scale;
|
||||
resize_width = g_settings.display_stretch_vertically ?
|
||||
m_display_texture_view_width : static_cast<s32>(static_cast<float>(resize_height) * ss_aspect_ratio);
|
||||
m_display_texture_view_width :
|
||||
static_cast<s32>(static_cast<float>(resize_height) * ss_aspect_ratio);
|
||||
resize_height = g_settings.display_stretch_vertically ?
|
||||
static_cast<s32>(static_cast<float>(resize_height) /
|
||||
(m_display_aspect_ratio / (static_cast<float>(m_display_width) / static_cast<float>(m_display_height)))) :
|
||||
resize_height;
|
||||
static_cast<s32>(static_cast<float>(resize_height) /
|
||||
(m_display_aspect_ratio /
|
||||
(static_cast<float>(m_display_width) / static_cast<float>(m_display_height)))) :
|
||||
resize_height;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -614,17 +618,65 @@ bool HostDisplay::WriteDisplayTextureToBuffer(std::vector<u32>* buffer, u32 resi
|
|||
return true;
|
||||
}
|
||||
|
||||
bool HostDisplay::WriteScreenshotToFile(std::string filename, bool compress_on_thread /*= false*/)
|
||||
bool HostDisplay::WriteScreenshotToFile(std::string filename, bool internal_resolution /* = false */,
|
||||
bool compress_on_thread /* = false */)
|
||||
{
|
||||
const u32 width = m_window_info.surface_width;
|
||||
const u32 height = m_window_info.surface_height;
|
||||
u32 width = m_window_info.surface_width;
|
||||
u32 height = m_window_info.surface_height;
|
||||
auto [draw_left, draw_top, draw_width, draw_height] = CalculateDrawRect(width, height);
|
||||
|
||||
if (internal_resolution && m_display_texture_view_width != 0 && m_display_texture_view_height != 0)
|
||||
{
|
||||
// If internal res, scale the computed draw rectangle to the internal res.
|
||||
// We re-use the draw rect because it's already been AR corrected.
|
||||
const float sar =
|
||||
static_cast<float>(m_display_texture_view_width) / static_cast<float>(m_display_texture_view_height);
|
||||
const float dar = static_cast<float>(draw_width) / static_cast<float>(draw_height);
|
||||
if (sar >= dar)
|
||||
{
|
||||
// stretch height, preserve width
|
||||
const float scale = static_cast<float>(m_display_texture_view_width) / static_cast<float>(draw_width);
|
||||
width = m_display_texture_view_width;
|
||||
height = static_cast<u32>(std::round(static_cast<float>(draw_height) * scale));
|
||||
}
|
||||
else
|
||||
{
|
||||
// stretch width, preserve height
|
||||
const float scale = static_cast<float>(m_display_texture_view_height) / static_cast<float>(draw_height);
|
||||
width = static_cast<u32>(std::round(static_cast<float>(draw_width) * scale));
|
||||
height = m_display_texture_view_height;
|
||||
}
|
||||
|
||||
// DX11 won't go past 16K texture size.
|
||||
constexpr u32 MAX_TEXTURE_SIZE = 16384;
|
||||
if (width > MAX_TEXTURE_SIZE)
|
||||
{
|
||||
height = static_cast<u32>(static_cast<float>(height) /
|
||||
(static_cast<float>(width) / static_cast<float>(MAX_TEXTURE_SIZE)));
|
||||
width = MAX_TEXTURE_SIZE;
|
||||
}
|
||||
if (height > MAX_TEXTURE_SIZE)
|
||||
{
|
||||
height = MAX_TEXTURE_SIZE;
|
||||
width = static_cast<u32>(static_cast<float>(width) /
|
||||
(static_cast<float>(height) / static_cast<float>(MAX_TEXTURE_SIZE)));
|
||||
}
|
||||
|
||||
// Remove padding, it's not part of the framebuffer.
|
||||
draw_left = 0;
|
||||
draw_top = 0;
|
||||
draw_width = static_cast<s32>(width);
|
||||
draw_height = static_cast<s32>(height);
|
||||
}
|
||||
if (width == 0 || height == 0)
|
||||
return false;
|
||||
|
||||
std::vector<u32> pixels;
|
||||
u32 pixels_stride;
|
||||
GPUTexture::Format pixels_format;
|
||||
if (!RenderScreenshot(width, height, &pixels, &pixels_stride, &pixels_format))
|
||||
if (!RenderScreenshot(width, height,
|
||||
Common::Rectangle<s32>::FromExtents(draw_top, draw_left, draw_width, draw_height), &pixels,
|
||||
&pixels_stride, &pixels_format))
|
||||
{
|
||||
Log_ErrorPrintf("Failed to render %ux%u screenshot", width, height);
|
||||
return false;
|
||||
|
|
|
@ -104,8 +104,8 @@ public:
|
|||
virtual bool Render(bool skip_present) = 0;
|
||||
|
||||
/// Renders the display with postprocessing to the specified image.
|
||||
virtual bool RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride,
|
||||
GPUTexture::Format* out_format) = 0;
|
||||
virtual bool RenderScreenshot(u32 width, u32 height, const Common::Rectangle<s32>& draw_rect,
|
||||
std::vector<u32>* out_pixels, u32* out_stride, GPUTexture::Format* out_format) = 0;
|
||||
|
||||
ALWAYS_INLINE bool IsVsyncEnabled() const { return m_vsync_enabled; }
|
||||
virtual void SetVSync(bool enabled) = 0;
|
||||
|
@ -206,7 +206,7 @@ public:
|
|||
bool clear_alpha = true);
|
||||
|
||||
/// Helper function to save screenshot to PNG.
|
||||
bool WriteScreenshotToFile(std::string filename, bool compress_on_thread = false);
|
||||
bool WriteScreenshotToFile(std::string filename, bool internal_resolution = false, bool compress_on_thread = false);
|
||||
|
||||
protected:
|
||||
ALWAYS_INLINE bool HasSoftwareCursor() const { return static_cast<bool>(m_cursor_texture); }
|
||||
|
@ -251,7 +251,7 @@ protected:
|
|||
bool m_vsync_enabled = false;
|
||||
};
|
||||
|
||||
/// Returns a pointer to the current host display abstraction. Assumes AcquireHostDisplay() has been caled.
|
||||
/// Returns a pointer to the current host display abstraction. Assumes AcquireHostDisplay() has been called.
|
||||
extern std::unique_ptr<HostDisplay> g_host_display;
|
||||
|
||||
namespace Host {
|
||||
|
|
|
@ -0,0 +1,330 @@
|
|||
// SPDX-FileCopyrightText: 2023 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||
|
||||
#include "pcdrv.h"
|
||||
#include "common/file_system.h"
|
||||
#include "common/log.h"
|
||||
#include "common/path.h"
|
||||
#include "common/string_util.h"
|
||||
#include "cpu_core.h"
|
||||
#include "settings.h"
|
||||
Log_SetChannel(PCDrv);
|
||||
|
||||
static constexpr u32 MAX_FILES = 100;
|
||||
|
||||
static std::vector<FileSystem::ManagedCFilePtr> s_files;
|
||||
|
||||
enum PCDrvAttribute : u32
|
||||
{
|
||||
PCDRV_ATTRIBUTE_READ_ONLY = (1 << 0),
|
||||
PCDRV_ATTRIBUTE_HIDDEN = (1 << 1),
|
||||
PCDRV_ATTRIBUTE_SYSTEM = (1 << 2),
|
||||
PCDRV_ATTRIBUTE_DIRECTORY = (1 << 4),
|
||||
PCDRV_ATTRIBUTE_ARCHIVE = (1 << 5),
|
||||
};
|
||||
|
||||
static s32 GetFreeFileHandle()
|
||||
{
|
||||
for (s32 i = 0; i < static_cast<s32>(s_files.size()); i++)
|
||||
{
|
||||
if (!s_files[i])
|
||||
return i;
|
||||
}
|
||||
|
||||
if (s_files.size() >= MAX_FILES)
|
||||
{
|
||||
Log_ErrorPrint("Too many open files.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const s32 index = static_cast<s32>(s_files.size());
|
||||
s_files.emplace_back(nullptr, [](std::FILE*) {});
|
||||
return index;
|
||||
}
|
||||
|
||||
static void CloseAllFiles()
|
||||
{
|
||||
if (!s_files.empty())
|
||||
Log_DevPrintf("Closing %zu open files.", s_files.size());
|
||||
|
||||
s_files.clear();
|
||||
}
|
||||
|
||||
static FILE* GetFileFromHandle(u32 handle)
|
||||
{
|
||||
if (handle >= static_cast<u32>(s_files.size()) || !s_files[handle])
|
||||
{
|
||||
Log_ErrorPrintf("Invalid file handle %d", static_cast<s32>(handle));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return s_files[handle].get();
|
||||
}
|
||||
|
||||
static bool CloseFileHandle(u32 handle)
|
||||
{
|
||||
if (handle >= static_cast<u32>(s_files.size()) || !s_files[handle])
|
||||
{
|
||||
Log_ErrorPrintf("Invalid file handle %d", static_cast<s32>(handle));
|
||||
return false;
|
||||
}
|
||||
|
||||
s_files[handle].reset();
|
||||
while (!s_files.empty() && !s_files.back())
|
||||
s_files.pop_back();
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::string ResolveHostPath(const std::string& path)
|
||||
{
|
||||
// Double-check that it falls within the directory of the elf.
|
||||
// Not a real sandbox, but emulators shouldn't be treated as such. Don't run untrusted code!
|
||||
const std::string& root = g_settings.pcdrv_root;
|
||||
std::string canonicalized_path = Path::Canonicalize(Path::Combine(root, path));
|
||||
if (canonicalized_path.length() < root.length() || // Length has to be longer (a file),
|
||||
!StringUtil::StartsWith(canonicalized_path, root) || // and start with the host root,
|
||||
canonicalized_path[root.length()] != FS_OSPATH_SEPARATOR_CHARACTER) // and we can't access a sibling.
|
||||
{
|
||||
Log_ErrorPrintf("Denying access to path outside of PCDrv directory. Requested path: '%s', "
|
||||
"Resolved path: '%s', Root directory: '%s'",
|
||||
path.c_str(), root.c_str(), canonicalized_path.c_str());
|
||||
canonicalized_path.clear();
|
||||
}
|
||||
|
||||
return canonicalized_path;
|
||||
}
|
||||
|
||||
void PCDrv::Initialize()
|
||||
{
|
||||
if (!g_settings.pcdrv_enable)
|
||||
return;
|
||||
|
||||
Log_WarningPrintf("%s PCDrv is enabled at '%s'", g_settings.pcdrv_enable_writes ? "Read/Write" : "Read-Only",
|
||||
g_settings.pcdrv_root.c_str());
|
||||
}
|
||||
|
||||
void PCDrv::Reset()
|
||||
{
|
||||
CloseAllFiles();
|
||||
}
|
||||
|
||||
void PCDrv::Shutdown()
|
||||
{
|
||||
CloseAllFiles();
|
||||
}
|
||||
|
||||
bool PCDrv::HandleSyscall(u32 instruction_bits, CPU::Registers& regs)
|
||||
{
|
||||
// Based on https://problemkaputt.de/psxspx-bios-pc-file-server.htm
|
||||
|
||||
#define RETURN_ERROR() \
|
||||
regs.v0 = 0xffffffff; \
|
||||
regs.v1 = 0xffffffff; // error code
|
||||
|
||||
if (!g_settings.pcdrv_enable)
|
||||
return false;
|
||||
|
||||
const u32 code = (instruction_bits >> 6) & 0xfffff; // 20 bits, funct = 0
|
||||
switch (code)
|
||||
{
|
||||
case 0x101: // PCinit
|
||||
{
|
||||
Log_DevPrintf("PCinit");
|
||||
CloseAllFiles();
|
||||
regs.v0 = 0;
|
||||
regs.v1 = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
case 0x102: // PCcreat
|
||||
case 0x103: // PCopen
|
||||
{
|
||||
const bool is_open = (code == 0x103);
|
||||
const char* func = (code == 0x102) ? "PCcreat" : "PCopen";
|
||||
const u32 mode = regs.a2;
|
||||
std::string filename;
|
||||
if (!CPU::SafeReadMemoryCString(regs.a1, &filename))
|
||||
{
|
||||
Log_ErrorPrintf("%s: Invalid string", func);
|
||||
return false;
|
||||
}
|
||||
|
||||
Log_DebugPrintf("%s: '%s' mode %u", func, filename.c_str(), mode);
|
||||
if ((filename = ResolveHostPath(filename)).empty())
|
||||
{
|
||||
RETURN_ERROR();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!is_open && !g_settings.pcdrv_enable_writes)
|
||||
{
|
||||
Log_ErrorPrintf("%s: Writes are not enabled", func);
|
||||
RETURN_ERROR();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Directories are unsupported for now, ignore other attributes
|
||||
if (mode & PCDRV_ATTRIBUTE_DIRECTORY)
|
||||
{
|
||||
Log_ErrorPrintf("%s: Directories are unsupported", func);
|
||||
RETURN_ERROR();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Create empty file, truncate if exists.
|
||||
const s32 handle = GetFreeFileHandle();
|
||||
if (handle < 0)
|
||||
{
|
||||
RETURN_ERROR();
|
||||
return true;
|
||||
}
|
||||
|
||||
s_files[handle] = FileSystem::OpenManagedCFile(filename.c_str(),
|
||||
is_open ? (g_settings.pcdrv_enable_writes ? "r+b" : "rb") : "w+b");
|
||||
if (!s_files[handle])
|
||||
{
|
||||
Log_ErrorPrintf("%s: Failed to open '%s'", func, filename.c_str());
|
||||
RETURN_ERROR();
|
||||
return true;
|
||||
}
|
||||
|
||||
Log_DebugPrintf("PCDrv: Opened '%s' => %d", filename.c_str(), handle);
|
||||
regs.v0 = 0;
|
||||
regs.v1 = static_cast<u32>(handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
case 0x104: // PCclose
|
||||
{
|
||||
Log_DebugPrintf("PCclose(%u)", regs.a1);
|
||||
|
||||
if (!CloseFileHandle(regs.a1))
|
||||
{
|
||||
RETURN_ERROR();
|
||||
return true;
|
||||
}
|
||||
|
||||
regs.v0 = 0;
|
||||
regs.v1 = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
case 0x105: // PCread
|
||||
{
|
||||
Log_DebugPrintf("PCread(%u, %u, 0x%08x)", regs.a1, regs.a2, regs.a3);
|
||||
|
||||
std::FILE* fp = GetFileFromHandle(regs.a1);
|
||||
if (!fp)
|
||||
{
|
||||
RETURN_ERROR();
|
||||
return true;
|
||||
}
|
||||
|
||||
const u32 count = regs.a2;
|
||||
u32 dstaddr = regs.a3;
|
||||
for (u32 i = 0; i < count; i++)
|
||||
{
|
||||
// Certainly less than optimal, but it's not like you're going to be reading megabytes of data here.
|
||||
u8 val;
|
||||
if (std::fread(&val, 1, 1, fp) != 1)
|
||||
{
|
||||
// Does not stop at EOF according to psx-spx.
|
||||
if (std::ferror(fp) != 0)
|
||||
{
|
||||
RETURN_ERROR();
|
||||
return true;
|
||||
}
|
||||
|
||||
val = 0;
|
||||
}
|
||||
|
||||
CPU::SafeWriteMemoryByte(dstaddr, val);
|
||||
dstaddr++;
|
||||
}
|
||||
|
||||
regs.v0 = 0;
|
||||
regs.v1 = count;
|
||||
return true;
|
||||
}
|
||||
|
||||
case 0x106: // PCwrite
|
||||
{
|
||||
Log_DebugPrintf("PCwrite(%u, %u, 0x%08x)", regs.a1, regs.a2, regs.a3);
|
||||
|
||||
std::FILE* fp = GetFileFromHandle(regs.a1);
|
||||
if (!fp)
|
||||
{
|
||||
RETURN_ERROR();
|
||||
return true;
|
||||
}
|
||||
|
||||
const u32 count = regs.a2;
|
||||
u32 srcaddr = regs.a3;
|
||||
u32 written = 0;
|
||||
for (u32 i = 0; i < count; i++)
|
||||
{
|
||||
u8 val;
|
||||
if (!CPU::SafeReadMemoryByte(srcaddr, &val))
|
||||
break;
|
||||
|
||||
if (std::fwrite(&val, 1, 1, fp) != 1)
|
||||
{
|
||||
RETURN_ERROR();
|
||||
return true;
|
||||
}
|
||||
|
||||
srcaddr++;
|
||||
written++;
|
||||
}
|
||||
|
||||
regs.v0 = 0;
|
||||
regs.v1 = written;
|
||||
return true;
|
||||
}
|
||||
|
||||
case 0x107: // PClseek
|
||||
{
|
||||
Log_DebugPrintf("PClseek(%u, %u, %u)", regs.a1, regs.a2, regs.a3);
|
||||
|
||||
std::FILE* fp = GetFileFromHandle(regs.a1);
|
||||
if (!fp)
|
||||
{
|
||||
RETURN_ERROR();
|
||||
return true;
|
||||
}
|
||||
|
||||
const s32 offset = static_cast<s32>(regs.a2);
|
||||
const u32 mode = regs.a3;
|
||||
int hmode;
|
||||
switch (mode)
|
||||
{
|
||||
case 0:
|
||||
hmode = SEEK_SET;
|
||||
break;
|
||||
case 1:
|
||||
hmode = SEEK_CUR;
|
||||
break;
|
||||
case 2:
|
||||
hmode = SEEK_END;
|
||||
break;
|
||||
default:
|
||||
RETURN_ERROR();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (FileSystem::FSeek64(fp, offset, hmode) != 0)
|
||||
{
|
||||
Log_ErrorPrintf("FSeek for PCDrv failed: %d %u", offset, hmode);
|
||||
RETURN_ERROR();
|
||||
return true;
|
||||
}
|
||||
|
||||
regs.v0 = 0;
|
||||
regs.v1 = static_cast<u32>(static_cast<s32>(FileSystem::FTell64(fp)));
|
||||
return true;
|
||||
}
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
// SPDX-FileCopyrightText: 2023 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||
|
||||
#pragma once
|
||||
#include "cpu_types.h"
|
||||
#include "types.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// HLE Implementation of PCDrv
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace PCDrv {
|
||||
void Initialize();
|
||||
void Reset();
|
||||
void Shutdown();
|
||||
|
||||
bool HandleSyscall(u32 instruction_bits, CPU::Registers& regs);
|
||||
}
|
|
@ -303,6 +303,9 @@ void Settings::Load(SettingsInterface& si)
|
|||
audio_dump_on_boot = si.GetBoolValue("Audio", "DumpOnBoot", false);
|
||||
|
||||
use_old_mdec_routines = si.GetBoolValue("Hacks", "UseOldMDECRoutines", false);
|
||||
pcdrv_enable = si.GetBoolValue("PCDrv", "Enabled", false);
|
||||
pcdrv_enable_writes = si.GetBoolValue("PCDrv", "EnableWrites", false);
|
||||
pcdrv_root = si.GetStringValue("PCDrv", "Root");
|
||||
|
||||
dma_max_slice_ticks = si.GetIntValue("Hacks", "DMAMaxSliceTicks", DEFAULT_DMA_MAX_SLICE_TICKS);
|
||||
dma_halt_ticks = si.GetIntValue("Hacks", "DMAHaltTicks", DEFAULT_DMA_HALT_TICKS);
|
||||
|
@ -522,6 +525,10 @@ void Settings::Save(SettingsInterface& si) const
|
|||
si.SetIntValue("Hacks", "GPUFIFOSize", gpu_fifo_size);
|
||||
si.SetIntValue("Hacks", "GPUMaxRunAhead", gpu_max_run_ahead);
|
||||
|
||||
si.SetBoolValue("PCDrv", "Enabled", pcdrv_enable);
|
||||
si.SetBoolValue("PCDrv", "EnableWrites", pcdrv_enable_writes);
|
||||
si.SetStringValue("PCDrv", "Root", pcdrv_root.c_str());
|
||||
|
||||
si.SetBoolValue("BIOS", "PatchTTYEnable", bios_patch_tty_enable);
|
||||
si.SetBoolValue("BIOS", "PatchFastBoot", bios_patch_fast_boot);
|
||||
|
||||
|
@ -610,10 +617,17 @@ void Settings::FixIncompatibleSettings(bool display_osd_messages)
|
|||
g_settings.cdrom_mute_cd_audio = false;
|
||||
g_settings.texture_replacements.enable_vram_write_replacements = false;
|
||||
g_settings.use_old_mdec_routines = false;
|
||||
g_settings.pcdrv_enable = false;
|
||||
g_settings.bios_patch_fast_boot = false;
|
||||
g_settings.bios_patch_tty_enable = false;
|
||||
}
|
||||
|
||||
if (g_settings.pcdrv_enable && g_settings.pcdrv_root.empty())
|
||||
{
|
||||
Log_WarningPrintf("Disabling PCDrv because no root directory is specified.");
|
||||
g_settings.pcdrv_enable = false;
|
||||
}
|
||||
|
||||
if (g_settings.display_integer_scaling && g_settings.display_linear_filtering)
|
||||
{
|
||||
Log_WarningPrintf("Disabling linear filter due to integer upscaling.");
|
||||
|
|
|
@ -170,6 +170,7 @@ struct Settings
|
|||
bool audio_dump_on_boot = false;
|
||||
|
||||
bool use_old_mdec_routines = false;
|
||||
bool pcdrv_enable = false;
|
||||
|
||||
// timing hacks section
|
||||
TickCount dma_max_slice_ticks = DEFAULT_DMA_MAX_SLICE_TICKS;
|
||||
|
@ -228,8 +229,6 @@ struct Settings
|
|||
}
|
||||
} texture_replacements;
|
||||
|
||||
// TODO: Controllers, memory cards, etc.
|
||||
|
||||
bool bios_patch_tty_enable = false;
|
||||
bool bios_patch_fast_boot = DEFAULT_FAST_BOOT_VALUE;
|
||||
bool enable_8mb_ram = false;
|
||||
|
@ -243,6 +242,9 @@ struct Settings
|
|||
|
||||
MultitapMode multitap_mode = DEFAULT_MULTITAP_MODE;
|
||||
|
||||
std::string pcdrv_root;
|
||||
bool pcdrv_enable_writes = false;
|
||||
|
||||
std::array<TinyString, NUM_CONTROLLER_AND_CARD_PORTS> GeneratePortLabels() const;
|
||||
|
||||
LOGLEVEL log_level = DEFAULT_LOG_LEVEL;
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
#include "cdrom.h"
|
||||
#include "common/bitfield.h"
|
||||
#include "common/fifo_queue.h"
|
||||
#include "common/file_system.h"
|
||||
#include "common/log.h"
|
||||
#include "common/path.h"
|
||||
#include "dma.h"
|
||||
#include "host.h"
|
||||
#include "imgui.h"
|
||||
|
@ -1493,7 +1493,7 @@ bool SPU::StartDumpingAudio(const char* filename)
|
|||
else
|
||||
new_suffix.Format("voice%u.wav", i);
|
||||
|
||||
std::string voice_filename(FileSystem::ReplaceExtension(filename, new_suffix));
|
||||
const std::string voice_filename = Path::ReplaceExtension(filename, new_suffix);
|
||||
if (!s_voice_dump_writers[i]->Open(voice_filename.c_str(), SAMPLE_RATE, 2))
|
||||
{
|
||||
Log_ErrorPrintf("Failed to open voice dump filename '%s'", voice_filename.c_str());
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "multitap.h"
|
||||
#include "netplay.h"
|
||||
#include "pad.h"
|
||||
#include "pcdrv.h"
|
||||
#include "pgxp.h"
|
||||
#include "psf_loader.h"
|
||||
#include "save_state_version.h"
|
||||
|
@ -1418,6 +1419,7 @@ bool System::Initialize(bool force_software_renderer)
|
|||
SPU::Initialize();
|
||||
MDEC::Initialize();
|
||||
SIO::Initialize();
|
||||
PCDrv::Initialize();
|
||||
|
||||
static constexpr float WARNING_DURATION = 15.0f;
|
||||
|
||||
|
@ -1473,6 +1475,7 @@ void System::DestroySystem()
|
|||
|
||||
g_texture_replacements.Shutdown();
|
||||
|
||||
PCDrv::Shutdown();
|
||||
SIO::Shutdown();
|
||||
MDEC::Shutdown();
|
||||
SPU::Shutdown();
|
||||
|
@ -1831,6 +1834,7 @@ void System::InternalReset()
|
|||
SPU::Reset();
|
||||
MDEC::Reset();
|
||||
SIO::Reset();
|
||||
PCDrv::Reset();
|
||||
s_frame_number = 1;
|
||||
s_internal_frame_number = 0;
|
||||
TimingEvents::Reset();
|
||||
|
@ -2064,8 +2068,9 @@ bool System::InternalSaveState(ByteStream* state, u32 screenshot_size /* = 256 *
|
|||
std::vector<u32> screenshot_buffer;
|
||||
u32 screenshot_stride;
|
||||
GPUTexture::Format screenshot_format;
|
||||
if (g_host_display->RenderScreenshot(screenshot_width, screenshot_height, &screenshot_buffer, &screenshot_stride,
|
||||
&screenshot_format) &&
|
||||
if (g_host_display->RenderScreenshot(screenshot_width, screenshot_height,
|
||||
Common::Rectangle<s32>::FromExtents(0, 0, screenshot_width, screenshot_height),
|
||||
&screenshot_buffer, &screenshot_stride, &screenshot_format) &&
|
||||
GPUTexture::ConvertTextureDataToRGBA8(screenshot_width, screenshot_height, screenshot_buffer, screenshot_stride,
|
||||
screenshot_format))
|
||||
{
|
||||
|
@ -3912,10 +3917,8 @@ bool System::SaveScreenshot(const char* filename /* = nullptr */, bool full_reso
|
|||
return false;
|
||||
}
|
||||
|
||||
const bool screenshot_saved =
|
||||
g_settings.display_internal_resolution_screenshots ?
|
||||
g_host_display->WriteDisplayTextureToFile(filename, full_resolution, apply_aspect_ratio, compress_on_thread) :
|
||||
g_host_display->WriteScreenshotToFile(filename, compress_on_thread);
|
||||
const bool screenshot_saved = g_host_display->WriteScreenshotToFile(
|
||||
filename, g_settings.display_internal_resolution_screenshots, compress_on_thread);
|
||||
|
||||
if (!screenshot_saved)
|
||||
{
|
||||
|
|
|
@ -175,6 +175,52 @@ static void addMSAATweakOption(SettingsDialog* dialog, QTableWidget* table, cons
|
|||
table->setCellWidget(row, 1, msaa);
|
||||
}
|
||||
|
||||
static void addDirectoryOption(SettingsDialog* dialog, QTableWidget* table, const QString& name, std::string section,
|
||||
std::string key)
|
||||
{
|
||||
const int row = table->rowCount();
|
||||
|
||||
table->insertRow(row);
|
||||
|
||||
QTableWidgetItem* name_item = new QTableWidgetItem(name);
|
||||
name_item->setFlags(name_item->flags() & ~(Qt::ItemIsEditable | Qt::ItemIsSelectable));
|
||||
table->setItem(row, 0, name_item);
|
||||
|
||||
QWidget* container = new QWidget(table);
|
||||
|
||||
QHBoxLayout* layout = new QHBoxLayout(container);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
QLineEdit* value = new QLineEdit(container);
|
||||
value->setObjectName(QStringLiteral("value"));
|
||||
SettingWidgetBinder::BindWidgetToStringSetting(dialog->getSettingsInterface(), value, std::move(section),
|
||||
std::move(key));
|
||||
layout->addWidget(value, 1);
|
||||
|
||||
QPushButton* browse = new QPushButton(container);
|
||||
browse->setText(QStringLiteral("..."));
|
||||
browse->setMaximumWidth(32);
|
||||
QObject::connect(browse, &QPushButton::clicked, browse, [browse, value, name]() {
|
||||
const QString path(QDir::toNativeSeparators(QFileDialog::getExistingDirectory(
|
||||
QtUtils::GetRootWidget(browse), qApp->translate("AdvancedSettingsWidget", "Select folder for %1").arg(name),
|
||||
value->text())));
|
||||
if (!path.isEmpty())
|
||||
value->setText(path);
|
||||
});
|
||||
layout->addWidget(browse, 0);
|
||||
|
||||
table->setCellWidget(row, 1, container);
|
||||
}
|
||||
|
||||
static void setDirectoryOption(QTableWidget* table, int row, const char* value)
|
||||
{
|
||||
QWidget* widget = table->cellWidget(row, 1);
|
||||
Assert(widget);
|
||||
QLineEdit* valuew = widget->findChild<QLineEdit*>(QStringLiteral("value"));
|
||||
Assert(valuew);
|
||||
valuew->setText(QString::fromUtf8(value));
|
||||
}
|
||||
|
||||
AdvancedSettingsWidget::AdvancedSettingsWidget(SettingsDialog* dialog, QWidget* parent)
|
||||
: QWidget(parent), m_dialog(dialog)
|
||||
{
|
||||
|
@ -299,6 +345,10 @@ void AdvancedSettingsWidget::addTweakOptions()
|
|||
|
||||
addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Create Save State Backups"), "General",
|
||||
"CreateSaveStateBackups", false);
|
||||
|
||||
addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Enable PCDrv"), "PCDrv", "Enabled", false);
|
||||
addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Enable PCDrv Writes"), "PCDrv", "EnableWrites", false);
|
||||
addDirectoryOption(m_dialog, m_ui.tweakOptionTable, tr("PCDrv Root Directory"), "PCDrv", "Root");
|
||||
}
|
||||
|
||||
void AdvancedSettingsWidget::onResetToDefaultClicked()
|
||||
|
@ -338,9 +388,13 @@ void AdvancedSettingsWidget::onResetToDefaultClicked()
|
|||
setIntRangeTweakOption(m_ui.tweakOptionTable, i++,
|
||||
static_cast<int>(Settings::DEFAULT_GPU_MAX_RUN_AHEAD)); // GPU max run-ahead
|
||||
setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Use debug host GPU device
|
||||
setBooleanTweakOption(m_ui.tweakOptionTable, i++, true); // Increase timer resolution
|
||||
setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Stretch Display Vertically
|
||||
setBooleanTweakOption(m_ui.tweakOptionTable, i++, true); // Increase Timer Resolution
|
||||
setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Allow booting without SBI file
|
||||
setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Create save state backups
|
||||
setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Enable PCDRV
|
||||
setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Enable PCDRV Writes
|
||||
setDirectoryOption(m_ui.tweakOptionTable, i++, ""); // PCDrv Root Directory
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -378,9 +432,13 @@ void AdvancedSettingsWidget::onResetToDefaultClicked()
|
|||
sif->DeleteValue("Hacks", "GPUFIFOSize");
|
||||
sif->DeleteValue("Hacks", "GPUMaxRunAhead");
|
||||
sif->DeleteValue("GPU", "UseDebugDevice");
|
||||
sif->DeleteValue("Display", "StretchVertically");
|
||||
sif->DeleteValue("Main", "IncreaseTimerResolution");
|
||||
sif->DeleteValue("CDROM", "AllowBootingWithoutSBIFile");
|
||||
sif->DeleteValue("General", "CreateSaveStateBackups");
|
||||
sif->DeleteValue("PCDrv", "Enabled");
|
||||
sif->DeleteValue("PCDrv", "EnableWrites");
|
||||
sif->DeleteValue("PCDrv", "Root");
|
||||
sif->Save();
|
||||
while (m_ui.tweakOptionTable->rowCount() > 0)
|
||||
m_ui.tweakOptionTable->removeRow(m_ui.tweakOptionTable->rowCount() - 1);
|
||||
|
|
|
@ -392,7 +392,7 @@ void ControllerSettingsDialog::createWidgets()
|
|||
|
||||
const Controller::ControllerInfo* ci =
|
||||
Controller::GetControllerInfo(m_port_bindings[global_slot]->getControllerType());
|
||||
const QString display_name(ci ? QString::fromUtf8(ci->display_name) : QStringLiteral("Unknown"));
|
||||
const QString display_name(ci ? qApp->translate("ControllerType", ci->display_name) : QStringLiteral("Unknown"));
|
||||
|
||||
QListWidgetItem* item = new QListWidgetItem();
|
||||
item->setText(mtap_enabled[port] ?
|
||||
|
@ -433,7 +433,7 @@ void ControllerSettingsDialog::updateListDescription(u32 global_slot, Controller
|
|||
const bool mtap_enabled = getBoolValue("Pad", (port == 0) ? "MultitapPort1" : "MultitapPort2", false);
|
||||
|
||||
const Controller::ControllerInfo* ci = Controller::GetControllerInfo(widget->getControllerType());
|
||||
const QString display_name(ci ? QString::fromUtf8(ci->display_name) : QStringLiteral("Unknown"));
|
||||
const QString display_name(ci ? qApp->translate("ControllerType", ci->display_name) : QStringLiteral("Unknown"));
|
||||
|
||||
item->setText(mtap_enabled ?
|
||||
(tr("Controller Port %1%2\n%3").arg(port + 1).arg(s_mtap_slot_names[slot]).arg(display_name)) :
|
||||
|
|
|
@ -148,7 +148,7 @@ static const ImWchar* QtHost::GetGlyphRangesJapanese()
|
|||
{
|
||||
// clang-format off
|
||||
// auto update by generate_update_glyph_ranges.py with duckstation-qt_ja.ts
|
||||
static const char16_t chars[] = u"←↑→↓□△○ 、。々「」〜あいうえおかがきぎくぐけげこごさざしじすずせそただちっつづてでとどなにぬねのはばびへべほぼぽまみむめもやゆよらりるれろわをんァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソタダチッツテデトドナニネノハバパヒビピフブプヘベペホボポマミムメモャヤュユョヨラリルレロワンー一上下不与両並中主了予事二互交人今介他付代令以件任休伸位低体作使例供依価係保信修個倍値停側傍備像優元先光入全公共具典内再凍処出分切初別利到制削前割力加効動勧化十協単去参及反収取古可右号各合同名向含告周呼命問善回囲固国圧在地垂型埋域基報場境増壊声売変外多大央失奨妥始子字存学安完定宛実密対専射小少岐左差巻帰常幅平年度座延式引弱張強当形影役待後従得御復微心必忘応性恐情意感態成我戻所手扱投択押拡持指振挿排探接推描提換損摩撃撮操改敗数整文料断新方既日早明映昨時景更書替最有望期未本来析枚果枠栄検概構標権機欄次止正歪残毎比水永求汎決況法波注海消深混済減測源準滑演点無照版牲特犠状獲率現理生用申画界番異疑発登的目直相瞬知短破確示禁秒称移程種穴空立端符等算管範簡粋精約純索細終組結統続維緑線編縮績繰置翻者耗背能自致般良色荷行表装補製複要見規視覧観解言計記設許訳証試詳認語説読調識警護象負販費質赤起超跡転軸軽較込近返追送逆通速連進遅遊達遠適遷選部重野量録長閉開間関防降限除隅隠集離電青非面音響頂順領頭頻頼題類飛高鮮黒%?X";
|
||||
static const char16_t chars[] = u"←↑→↓□△○ 、。々「」〜あいうえおかがきぎくぐけげこごさざしじすずせそただちっつづてでとどなにぬねのはばびへべほぼぽまみむめもやゆよらりるれろわをんァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソタダチッツテデトドナニネノハバパヒビピフブプヘベペホボポマミムメモャヤュユョヨラリルレロワンー一上下不与両並中主了予事二互交人今介他付代令以件任休伸位低体作使例供依価係保信修個倍値停側傍備像優元先光入全公共具典内再凍処出分切初別利到制削前割力加効動勧化十協単去参及反収取古可右号各合同名向含告周呼命問善回囲固国圧在地垂型埋域基報場境増壊声売変外多大央失奨妥始子字存学安完定宛実密対専射小少岐左差巻帰常幅平年度座延式引弱張強当形影役待後従得御復微心必忘応性恐情意感態成我戻所手扱投択押拡持指振挿排探接推描提換損摩撃撮操改敗数整文料断新方既日早明昔映昨時景更書替最有望期未本来析枚果枠栄検概構標権機欄次止正歪残毎比水永求汎決況法波注海消深混済減測源準滑演点無照版牲特犠状獲率現理生用申画界番異疑発登的目直相瞬知短破確示禁秒称移程種穴空立端符等算管範簡粋精約純索細終組結統続維緑線編縮績繰置翻者耗背能自致般良色荷行表装補製複要見規視覧観解言計記設許訳証試詳認語説読調識警護象負販費質赤起超跡転軸軽較込近返追送逆通速連進遅遊達遠適遷選部重野量録長閉開間関防降限除隅隠集離電青非面音響頂順領頭頻頼題類飛高鮮黒%?X";
|
||||
const int chars_length = sizeof(chars) / sizeof(chars[0]);
|
||||
// clang-format on
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -126,6 +126,14 @@ if(USE_X11)
|
|||
target_include_directories(frontend-common PRIVATE "${X11_INCLUDE_DIR}")
|
||||
endif()
|
||||
|
||||
if(USE_DBUS)
|
||||
target_compile_definitions(frontend-common PRIVATE USE_DBUS)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(DBUS REQUIRED dbus-1)
|
||||
target_include_directories(frontend-common PRIVATE ${DBUS_INCLUDE_DIRS})
|
||||
target_link_libraries(frontend-common PRIVATE ${DBUS_LINK_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(ENABLE_DISCORD_PRESENCE)
|
||||
target_compile_definitions(frontend-common PUBLIC -DWITH_DISCORD_PRESENCE=1)
|
||||
target_link_libraries(frontend-common PRIVATE discord-rpc)
|
||||
|
|
|
@ -705,8 +705,8 @@ bool D3D11HostDisplay::Render(bool skip_present)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride,
|
||||
GPUTexture::Format* out_format)
|
||||
bool D3D11HostDisplay::RenderScreenshot(u32 width, u32 height, const Common::Rectangle<s32>& draw_rect,
|
||||
std::vector<u32>* out_pixels, u32* out_stride, GPUTexture::Format* out_format)
|
||||
{
|
||||
static constexpr GPUTexture::Format hdformat = GPUTexture::Format::RGBA8;
|
||||
|
||||
|
@ -720,20 +720,18 @@ bool D3D11HostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>*
|
|||
|
||||
if (HasDisplayTexture())
|
||||
{
|
||||
const auto [left, top, draw_width, draw_height] = CalculateDrawRect(width, height);
|
||||
|
||||
if (!m_post_processing_chain.IsEmpty())
|
||||
{
|
||||
ApplyPostProcessingChain(render_texture.GetD3DRTV(), left, top, draw_width, draw_height,
|
||||
static_cast<D3D11::Texture*>(m_display_texture), m_display_texture_view_x,
|
||||
m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height,
|
||||
width, height);
|
||||
ApplyPostProcessingChain(render_texture.GetD3DRTV(), draw_rect.left, draw_rect.top, draw_rect.GetWidth(),
|
||||
draw_rect.GetHeight(), static_cast<D3D11::Texture*>(m_display_texture),
|
||||
m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
|
||||
m_display_texture_view_height, width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderDisplay(left, top, draw_width, draw_height, static_cast<D3D11::Texture*>(m_display_texture),
|
||||
m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
|
||||
m_display_texture_view_height, IsUsingLinearFiltering());
|
||||
RenderDisplay(draw_rect.left, draw_rect.top, draw_rect.GetWidth(), draw_rect.GetHeight(),
|
||||
static_cast<D3D11::Texture*>(m_display_texture), m_display_texture_view_x, m_display_texture_view_y,
|
||||
m_display_texture_view_width, m_display_texture_view_height, IsUsingLinearFiltering());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -67,8 +67,8 @@ public:
|
|||
void SetVSync(bool enabled) override;
|
||||
|
||||
bool Render(bool skip_present) override;
|
||||
bool RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride,
|
||||
GPUTexture::Format* out_format) override;
|
||||
bool RenderScreenshot(u32 width, u32 height, const Common::Rectangle<s32>& draw_rect, std::vector<u32>* out_pixels,
|
||||
u32* out_stride, GPUTexture::Format* out_format) override;
|
||||
|
||||
static AdapterAndModeList StaticGetAdapterAndModeList();
|
||||
|
||||
|
|
|
@ -615,8 +615,8 @@ bool D3D12HostDisplay::Render(bool skip_present)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool D3D12HostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride,
|
||||
GPUTexture::Format* out_format)
|
||||
bool D3D12HostDisplay::RenderScreenshot(u32 width, u32 height, const Common::Rectangle<s32>& draw_rect,
|
||||
std::vector<u32>* out_pixels, u32* out_stride, GPUTexture::Format* out_format)
|
||||
{
|
||||
static constexpr DXGI_FORMAT format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
static constexpr GPUTexture::Format hdformat = GPUTexture::Format::RGBA8;
|
||||
|
@ -630,14 +630,13 @@ bool D3D12HostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>*
|
|||
}
|
||||
|
||||
ID3D12GraphicsCommandList* cmdlist = g_d3d12_context->GetCommandList();
|
||||
const auto [left, top, draw_width, draw_height] = CalculateDrawRect(width, height);
|
||||
|
||||
if (HasDisplayTexture() && !m_post_processing_chain.IsEmpty())
|
||||
{
|
||||
ApplyPostProcessingChain(cmdlist, &render_texture, left, top, width, height,
|
||||
static_cast<D3D12::Texture*>(m_display_texture), m_display_texture_view_x,
|
||||
m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height,
|
||||
width, height);
|
||||
ApplyPostProcessingChain(cmdlist, &render_texture, draw_rect.left, draw_rect.top, draw_rect.GetWidth(),
|
||||
draw_rect.GetHeight(), static_cast<D3D12::Texture*>(m_display_texture),
|
||||
m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
|
||||
m_display_texture_view_height, width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -647,9 +646,9 @@ bool D3D12HostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>*
|
|||
|
||||
if (HasDisplayTexture())
|
||||
{
|
||||
RenderDisplay(cmdlist, left, top, draw_width, draw_height, static_cast<D3D12::Texture*>(m_display_texture),
|
||||
m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
|
||||
m_display_texture_view_height, IsUsingLinearFiltering());
|
||||
RenderDisplay(cmdlist, draw_rect.left, draw_rect.top, draw_rect.GetWidth(), draw_rect.GetHeight(),
|
||||
static_cast<D3D12::Texture*>(m_display_texture), m_display_texture_view_x, m_display_texture_view_y,
|
||||
m_display_texture_view_width, m_display_texture_view_height, IsUsingLinearFiltering());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -66,8 +66,8 @@ public:
|
|||
void SetVSync(bool enabled) override;
|
||||
|
||||
bool Render(bool skip_present) override;
|
||||
bool RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride,
|
||||
GPUTexture::Format* out_format) override;
|
||||
bool RenderScreenshot(u32 width, u32 height, const Common::Rectangle<s32>& draw_rect, std::vector<u32>* out_pixels,
|
||||
u32* out_stride, GPUTexture::Format* out_format) override;
|
||||
|
||||
bool SetGPUTimingEnabled(bool enabled) override;
|
||||
float GetAndResetAccumulatedGPUTime() override;
|
||||
|
|
|
@ -680,8 +680,8 @@ bool OpenGLHostDisplay::Render(bool skip_present)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride,
|
||||
GPUTexture::Format* out_format)
|
||||
bool OpenGLHostDisplay::RenderScreenshot(u32 width, u32 height, const Common::Rectangle<s32>& draw_rect,
|
||||
std::vector<u32>* out_pixels, u32* out_stride, GPUTexture::Format* out_format)
|
||||
{
|
||||
GL::Texture texture;
|
||||
if (!texture.Create(width, height, 1, 1, 1, GPUTexture::Format::RGBA8, nullptr, 0) || !texture.CreateFramebuffer())
|
||||
|
@ -692,14 +692,13 @@ bool OpenGLHostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>
|
|||
glDisable(GL_SCISSOR_TEST);
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
const auto [left, top, draw_width, draw_height] = CalculateDrawRect(width, height);
|
||||
|
||||
if (HasDisplayTexture() && !m_post_processing_chain.IsEmpty())
|
||||
{
|
||||
ApplyPostProcessingChain(texture.GetGLFramebufferID(), left, height - top - draw_height, draw_width, draw_height,
|
||||
static_cast<GL::Texture*>(m_display_texture), m_display_texture_view_x,
|
||||
m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height,
|
||||
width, height);
|
||||
ApplyPostProcessingChain(texture.GetGLFramebufferID(), draw_rect.left,
|
||||
height - draw_rect.top - draw_rect.GetHeight(), draw_rect.GetWidth(),
|
||||
draw_rect.GetHeight(), static_cast<GL::Texture*>(m_display_texture),
|
||||
m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
|
||||
m_display_texture_view_height, width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -708,9 +707,10 @@ bool OpenGLHostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>
|
|||
|
||||
if (HasDisplayTexture())
|
||||
{
|
||||
RenderDisplay(left, height - top - draw_height, draw_width, draw_height,
|
||||
static_cast<GL::Texture*>(m_display_texture), m_display_texture_view_x, m_display_texture_view_y,
|
||||
m_display_texture_view_width, m_display_texture_view_height, IsUsingLinearFiltering());
|
||||
RenderDisplay(draw_rect.left, height - draw_rect.top - draw_rect.GetHeight(), draw_rect.GetWidth(),
|
||||
draw_rect.GetHeight(), static_cast<GL::Texture*>(m_display_texture), m_display_texture_view_x,
|
||||
m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height,
|
||||
IsUsingLinearFiltering());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -55,8 +55,8 @@ public:
|
|||
void SetVSync(bool enabled) override;
|
||||
|
||||
bool Render(bool skip_present) override;
|
||||
bool RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride,
|
||||
GPUTexture::Format* out_format) override;
|
||||
bool RenderScreenshot(u32 width, u32 height, const Common::Rectangle<s32>& draw_rect, std::vector<u32>* out_pixels,
|
||||
u32* out_stride, GPUTexture::Format* out_format) override;
|
||||
|
||||
bool SetGPUTimingEnabled(bool enabled) override;
|
||||
float GetAndResetAccumulatedGPUTime() override;
|
||||
|
|
|
@ -3,17 +3,18 @@
|
|||
|
||||
#include "common/log.h"
|
||||
#include "common/string.h"
|
||||
#include "platform_misc.h"
|
||||
#include "input_manager.h"
|
||||
#include "platform_misc.h"
|
||||
#include <cinttypes>
|
||||
Log_SetChannel(FrontendCommon);
|
||||
|
||||
#ifdef USE_X11
|
||||
#include <cstdio>
|
||||
#include <spawn.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if !defined(USE_DBUS) && defined(USE_X11)
|
||||
#include <cstdio>
|
||||
#include <sys/wait.h>
|
||||
|
||||
static bool SetScreensaverInhibitX11(bool inhibit, const WindowInfo& wi)
|
||||
{
|
||||
TinyString command;
|
||||
|
@ -38,10 +39,80 @@ static bool SetScreensaverInhibitX11(bool inhibit, const WindowInfo& wi)
|
|||
return true;
|
||||
}
|
||||
|
||||
#endif // USE_X11
|
||||
#elif defined(USE_DBUS)
|
||||
#include <dbus/dbus.h>
|
||||
bool ChangeScreenSaverStateDBus(const bool inhibit_requested, const char* program_name, const char* reason)
|
||||
{
|
||||
static dbus_uint32_t s_cookie;
|
||||
// "error_dbus" doesn't need to be cleared in the end with "dbus_message_unref" at least if there is
|
||||
// no error set, since calling "dbus_error_free" reinitializes it like "dbus_error_init" after freeing.
|
||||
DBusError error_dbus;
|
||||
dbus_error_init(&error_dbus);
|
||||
DBusConnection* connection = nullptr;
|
||||
DBusMessage* message = nullptr;
|
||||
DBusMessage* response = nullptr;
|
||||
// Initialized here because initializations should be before "goto" statements.
|
||||
const char* bus_method = (inhibit_requested) ? "Inhibit" : "UnInhibit";
|
||||
// "dbus_bus_get" gets a pointer to the same connection in libdbus, if exists, without creating a new connection.
|
||||
// this doesn't need to be deleted, except if there's an error then calling "dbus_connection_unref", to free it,
|
||||
// might be better so a new connection is established on the next try.
|
||||
if (!(connection = dbus_bus_get(DBUS_BUS_SESSION, &error_dbus)) || (dbus_error_is_set(&error_dbus)))
|
||||
goto cleanup;
|
||||
if (!(message = dbus_message_new_method_call("org.freedesktop.ScreenSaver", "/org/freedesktop/ScreenSaver",
|
||||
"org.freedesktop.ScreenSaver", bus_method)))
|
||||
goto cleanup;
|
||||
// Initialize an append iterator for the message, gets freed with the message.
|
||||
DBusMessageIter message_itr;
|
||||
dbus_message_iter_init_append(message, &message_itr);
|
||||
if (inhibit_requested)
|
||||
{
|
||||
// Append process/window name.
|
||||
if (!dbus_message_iter_append_basic(&message_itr, DBUS_TYPE_STRING, &program_name))
|
||||
goto cleanup;
|
||||
// Append reason for inhibiting the screensaver.
|
||||
if (!dbus_message_iter_append_basic(&message_itr, DBUS_TYPE_STRING, &reason))
|
||||
goto cleanup;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only Append the cookie.
|
||||
if (!dbus_message_iter_append_basic(&message_itr, DBUS_TYPE_UINT32, &s_cookie))
|
||||
goto cleanup;
|
||||
}
|
||||
// Send message and get response.
|
||||
if (!(response =
|
||||
dbus_connection_send_with_reply_and_block(connection, message, DBUS_TIMEOUT_USE_DEFAULT, &error_dbus)) ||
|
||||
dbus_error_is_set(&error_dbus))
|
||||
goto cleanup;
|
||||
if (inhibit_requested)
|
||||
{
|
||||
// Get the cookie from the response message.
|
||||
if (!dbus_message_get_args(response, &error_dbus, DBUS_TYPE_UINT32, &s_cookie, DBUS_TYPE_INVALID))
|
||||
goto cleanup;
|
||||
}
|
||||
dbus_message_unref(message);
|
||||
dbus_message_unref(response);
|
||||
return true;
|
||||
cleanup:
|
||||
if (dbus_error_is_set(&error_dbus))
|
||||
dbus_error_free(&error_dbus);
|
||||
if (connection)
|
||||
dbus_connection_unref(connection);
|
||||
if (message)
|
||||
dbus_message_unref(message);
|
||||
if (response)
|
||||
dbus_message_unref(response);
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static bool SetScreensaverInhibit(bool inhibit)
|
||||
{
|
||||
#ifdef USE_DBUS
|
||||
return ChangeScreenSaverStateDBus(inhibit, "DuckStation", "DuckStation VM is running.");
|
||||
#else
|
||||
|
||||
std::optional<WindowInfo> wi(Host::GetTopLevelWindowInfo());
|
||||
if (!wi.has_value())
|
||||
{
|
||||
|
@ -60,6 +131,7 @@ static bool SetScreensaverInhibit(bool inhibit)
|
|||
Log_ErrorPrintf("Unknown type: %u", static_cast<unsigned>(wi->type));
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool s_screensaver_suspended;
|
||||
|
|
|
@ -677,8 +677,8 @@ bool VulkanHostDisplay::Render(bool skip_present)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride,
|
||||
GPUTexture::Format* out_format)
|
||||
bool VulkanHostDisplay::RenderScreenshot(u32 width, u32 height, const Common::Rectangle<s32>& draw_rect,
|
||||
std::vector<u32>* out_pixels, u32* out_stride, GPUTexture::Format* out_format)
|
||||
{
|
||||
// in theory we could do this without a swap chain, but postprocessing assumes it for now...
|
||||
if (!m_swap_chain)
|
||||
|
@ -746,20 +746,19 @@ bool VulkanHostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>
|
|||
"VulkanHostDisplay::RenderScreenshot: %ux%u", width, height);
|
||||
tex.TransitionToLayout(g_vulkan_context->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
|
||||
const auto [left, top, draw_width, draw_height] = CalculateDrawRect(width, height);
|
||||
|
||||
if (!m_post_processing_chain.IsEmpty())
|
||||
{
|
||||
ApplyPostProcessingChain(fb, left, top, draw_width, draw_height, static_cast<Vulkan::Texture*>(m_display_texture),
|
||||
m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
|
||||
m_display_texture_view_height, width, height);
|
||||
ApplyPostProcessingChain(fb, draw_rect.left, draw_rect.top, draw_rect.GetWidth(), draw_rect.GetHeight(),
|
||||
static_cast<Vulkan::Texture*>(m_display_texture), m_display_texture_view_x,
|
||||
m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height,
|
||||
width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
BeginSwapChainRenderPass(fb, width, height);
|
||||
RenderDisplay(left, top, draw_width, draw_height, static_cast<Vulkan::Texture*>(m_display_texture),
|
||||
m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
|
||||
m_display_texture_view_height, IsUsingLinearFiltering());
|
||||
RenderDisplay(draw_rect.left, draw_rect.top, draw_rect.GetWidth(), draw_rect.GetHeight(),
|
||||
static_cast<Vulkan::Texture*>(m_display_texture), m_display_texture_view_x, m_display_texture_view_y,
|
||||
m_display_texture_view_width, m_display_texture_view_height, IsUsingLinearFiltering());
|
||||
}
|
||||
|
||||
vkCmdEndRenderPass(g_vulkan_context->GetCurrentCommandBuffer());
|
||||
|
|
|
@ -59,8 +59,8 @@ public:
|
|||
void SetVSync(bool enabled) override;
|
||||
|
||||
bool Render(bool skip_present) override;
|
||||
bool RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride,
|
||||
GPUTexture::Format* out_format) override;
|
||||
bool RenderScreenshot(u32 width, u32 height, const Common::Rectangle<s32>& draw_rect, std::vector<u32>* out_pixels,
|
||||
u32* out_stride, GPUTexture::Format* out_format) override;
|
||||
|
||||
bool SetGPUTimingEnabled(bool enabled) override;
|
||||
float GetAndResetAccumulatedGPUTime() override;
|
||||
|
|
Loading…
Reference in New Issue