Compare commits

...

36 Commits

Author SHA1 Message Date
Ty Lamontagne
6b61ffbb63 GS Capture: Allow selecting the pixel format based on the current codec 2024-07-22 10:56:30 -04:00
Ty Lamontagne
dd7eef723a GS Capture: Set ffmpeg channel layout 2024-07-22 10:56:30 -04:00
TellowKrinkle
328275cd45 GS:Capture: VAAPI support 2024-07-21 14:31:22 -04:00
PCSX2 Bot
a4f1431bcc Qt: Update Base Translation 2024-07-20 23:10:29 +02:00
lightningterror
473df8dad4 Debugger: Cleanup warnings and casts.
MemoryViewWidget.cpp
BreakpointModel.cpp
2024-07-20 23:09:51 +02:00
lightningterror
042959958e GS/HW: Use enum for blend_hw shader bit everywhere.
Leftover places I forgot to replace.
2024-07-20 15:20:07 +02:00
KamFretoZ
cd4de28b9e OSD: Add PCSX2 Version toggle 2024-07-19 12:46:35 -04:00
TheTechnician27
24a87c3fee Qt: Disable Single Frame GS Dump tool when not playing a game 2024-07-19 09:14:43 -04:00
GovanifY
17567b960f qt/MainWindow: for disable hide window if render to main is enabled
This fixes a crash on wayland (and possibly others)
2024-07-19 07:49:50 -04:00
JordanTheToaster
7a3d22ecdf GameDB: TC SOLA fixes 2024-07-18 19:55:28 -04:00
Ty Lamontagne
7e5016fdab linux/cmake: Allow libbacktrace to be disabled 2024-07-18 16:46:24 -04:00
PCSX2 Bot
47606400fa Qt: Update Base Translation 2024-07-18 19:11:09 +02:00
TheLastRar
d6076a6107 DEV9: Use const in ICMP session 2024-07-18 19:10:40 +02:00
TheLastRar
95c57462cc DEV9: FreeBSD/Mac Fixes for ICMP session 2024-07-18 19:10:40 +02:00
TheLastRar
48a1ec3531 DEV9: Use std::unique_ptr for tracking active pings 2024-07-18 19:10:40 +02:00
TheLastRar
9da3bccca2 DEV9: Use vector for ICMP temp buffer 2024-07-18 19:10:40 +02:00
TheLastRar
a1a92920b2 DEV9: Fix handling of ICMP timeout 2024-07-18 19:10:40 +02:00
TheLastRar
b6b775e44e DEV9: Fix IP_PayloadPtr::WriteBytes() 2024-07-18 19:10:40 +02:00
TheLastRar
5ea46ac076 DEV9: Use non-blocking sockets for ICMP Sessions on Unix 2024-07-18 19:10:40 +02:00
TheLastRar
ab008bf5d0 DEV9: Correct ICMP log messages 2024-07-18 19:10:40 +02:00
TheLastRar
54782cbf70 DEV9: Amend ICMP_Session comments 2024-07-18 19:10:40 +02:00
TheLastRar
3c7cff99f4 DEV9: Eliminate c-style casts from ICMP_Session 2024-07-18 19:10:40 +02:00
TheLastRar
f326e8775f DEV9: Correct spelling in ICMP session 2024-07-18 19:10:40 +02:00
AKuHAK
a2a711b1b3 Bios: add support for Rom2 up to 4Mb 2024-07-18 11:50:57 -04:00
PCSX2 Bot
dfb857b68f Qt: Update Base Translation 2024-07-17 22:20:21 +02:00
TheLastRar
ad64d88e7b Common: Fix FreeBSD build 2024-07-17 22:15:09 +02:00
TheTechnician27
cbd207d3f4 Qt: Add Emerald theme and fix palette var names 2024-07-17 21:56:46 +02:00
gooosedev
4bf8b23204 Debugger: change how the nullbyte (0x00) are displayed in the memoryview widget. 2024-07-17 21:55:04 +02:00
Ty Lamontagne
951780b43d Debugger: Implement little endian memory view support 2024-07-17 21:55:04 +02:00
TheTechnician27
84fe413635 GameDB: Ensure NativeScaling doesn't nag users at native res 2024-07-17 15:01:07 -04:00
Mrlinkwii
17aaa31362 github: mention to verify games if making an issue
[ci skip]
2024-07-17 14:58:37 -04:00
TheTechnician27
f943bdad98 Covers: Use serial for cover image names when selected individually 2024-07-17 14:58:04 -04:00
JordanTheToaster
09b2b6f949 GameDB: Fix up ATV ORF 3 fixes 2024-07-17 20:57:56 +02:00
L1Q
c46902c0f5 ReadMe: Fix BIOS dump link. (#11552) 2024-07-17 20:57:07 +02:00
PCSX2 Bot
c0dce9f64b PAD: Update to latest controller database. 2024-07-17 20:55:31 +02:00
Silent
cd3e11bff7 InputManager: Release settings lock before shutting down the input source 2024-07-13 07:29:26 -04:00
35 changed files with 2499 additions and 2124 deletions

View File

@@ -18,6 +18,8 @@ body:
Please make an effort to make sure your issue isn't already reported.
Please make sure your game is verified using the built-in game verifier.
Do not create issues involving software piracy of BIOS or ISO files, our rules specifically prohibit this and your issue will be closed.
### Please Avoid Issues Pertaining to the Following:

View File

@@ -18,7 +18,7 @@ Installers and binaries for both stable and nightly builds are available from [o
PCSX2 supports Windows, Linux, and Mac platforms. Our [setup documentation page](https://pcsx2.net/docs/setup/requirements) contains additional details on software and hardware requirements.
Please note that a BIOS dump from a legitimately-owned PS2 console is required to use the emulator. For more information, visit [this page](https://pcsx2.net/docs/setup/gather/#how-to-dump-your-ps2-bios).
Please note that a BIOS dump from a legitimately-owned PS2 console is required to use the emulator. For more information, visit [this page](https://pcsx2.net/docs/setup/bios/).
## Contributing / Building

View File

@@ -11186,8 +11186,6 @@ SCUS-97436:
SCUS-97437:
name: "ATV Offroad Fury 3 [Demo]"
region: "NTSC-U"
speedHacks:
mtvu: 0 # Increases FPS drastically.
SCUS-97438:
name: "EyeToy - Antigrav [Demo]"
region: "NTSC-U"
@@ -11583,8 +11581,6 @@ SCUS-97513:
SCUS-97514:
name: "ATV Offroad Fury 3 [Greatest Hits]"
region: "NTSC-U"
speedHacks:
mtvu: 0 # Increases FPS drastically.
SCUS-97515:
name: "Hot Shots Golf FORE! [Greatest Hits]"
region: "NTSC-U"
@@ -12497,7 +12493,7 @@ SLED-51211:
gsHWFixes:
gpuTargetCLUT: 1 # Fixes bloom and sun rendering in front of everything.
autoFlush: 1 # Fixes bloom and sun rendering in front of everything.
halfPixelOffset: 4 # Aligns bloom effect.
halfPixelOffset: 2 # Aligns bloom effect.
bilinearUpscale: 2 # Reduces color banding of the sun glare.
nativeScaling: 2 # Fixes post lighting.
roundModes:
@@ -12585,6 +12581,7 @@ SLED-51902:
halfPixelOffset: 3 # Fixes double image.
gpuTargetCLUT: 1 # Fixes sun penetrating buildings.
autoFlush: 1 # Fixes sun occlusion.
bilinearUpscale: 2 # Fixes sun glare textures to behave like native.
SLED-51921:
name: "Final Fantasy X-2 [Demo]"
region: "PAL-Unk"
@@ -15583,7 +15580,7 @@ SLES-51044:
gsHWFixes:
gpuTargetCLUT: 1 # Fixes bloom and sun rendering in front of everything.
autoFlush: 1 # Fixes bloom and sun rendering in front of everything.
halfPixelOffset: 4 # Aligns bloom effect.
halfPixelOffset: 2 # Aligns bloom effect.
bilinearUpscale: 2 # Reduces color banding of the sun glare.
nativeScaling: 2 # Fixes post lighting.
roundModes:
@@ -17217,6 +17214,7 @@ SLES-51753:
halfPixelOffset: 3 # Fixes double image.
gpuTargetCLUT: 1 # Fixes sun penetrating buildings.
autoFlush: 1 # Fixes sun occlusion.
bilinearUpscale: 2 # Fixes sun glare textures to behave like native.
SLES-51754:
name: "True Crime - Streets of L.A."
region: "PAL-M5"
@@ -17226,6 +17224,7 @@ SLES-51754:
halfPixelOffset: 3 # Fixes double image.
gpuTargetCLUT: 1 # Fixes sun penetrating buildings.
autoFlush: 1 # Fixes sun occlusion.
bilinearUpscale: 2 # Fixes sun glare textures to behave like native.
SLES-51755:
name: "Disney/Pixar Finding Nemo"
region: "PAL-E"
@@ -20435,7 +20434,7 @@ SLES-52968:
gsHWFixes:
gpuTargetCLUT: 1 # Fixes bloom and sun rendering in front of everything.
autoFlush: 1 # Fixes bloom and sun rendering in front of everything.
halfPixelOffset: 4 # Aligns bloom effect.
halfPixelOffset: 2 # Aligns bloom effect.
bilinearUpscale: 2 # Reduces color banding of the sun glare.
nativeScaling: 2 # Fixes post lighting.
roundModes:
@@ -22926,8 +22925,6 @@ SLES-53753:
SLES-53754:
name: "ATV Offroad Fury 3"
region: "PAL-M6"
speedHacks:
mtvu: 0 # Increases FPS drastically.
SLES-53755:
name: "Castlevania - Curse of Darkness"
region: "PAL-M5"
@@ -28951,7 +28948,7 @@ SLKA-25039:
gsHWFixes:
gpuTargetCLUT: 1 # Fixes bloom and sun rendering in front of everything.
autoFlush: 1 # Fixes bloom and sun rendering in front of everything.
halfPixelOffset: 4 # Aligns bloom effect.
halfPixelOffset: 2 # Aligns bloom effect.
bilinearUpscale: 2 # Reduces color banding of the sun glare.
nativeScaling: 2 # Fixes post lighting.
roundModes:
@@ -40829,6 +40826,7 @@ SLPM-65729:
halfPixelOffset: 3 # Fixes double image.
gpuTargetCLUT: 1 # Fixes sun penetrating buildings.
autoFlush: 1 # Fixes sun occlusion.
bilinearUpscale: 2 # Fixes sun glare textures to behave like native.
SLPM-65730:
name: "ロックマンX8"
name-sort: "ろっくまんえっくす8"
@@ -42962,6 +42960,7 @@ SLPM-66098:
halfPixelOffset: 3 # Fixes double image.
gpuTargetCLUT: 1 # Fixes sun penetrating buildings.
autoFlush: 1 # Fixes sun occlusion.
bilinearUpscale: 2 # Fixes sun glare textures to behave like native.
SLPM-66099:
name: "Harukanaru Toki no Naka de 3 - Izayoiki [Premium Box-Triple Pack]"
region: "NTSC-J"
@@ -53682,7 +53681,7 @@ SLPS-25351:
gsHWFixes:
gpuTargetCLUT: 1 # Fixes bloom and sun rendering in front of everything.
autoFlush: 1 # Fixes bloom and sun rendering in front of everything.
halfPixelOffset: 4 # Aligns bloom effect.
halfPixelOffset: 2 # Aligns bloom effect.
bilinearUpscale: 2 # Reduces color banding of the sun glare.
nativeScaling: 2 # Fixes post lighting.
roundModes:
@@ -60443,7 +60442,7 @@ SLUS-20497:
gsHWFixes:
gpuTargetCLUT: 1 # Fixes bloom and sun rendering in front of everything.
autoFlush: 1 # Fixes bloom and sun rendering in front of everything.
halfPixelOffset: 4 # Aligns bloom effect.
halfPixelOffset: 2 # Aligns bloom effect.
bilinearUpscale: 2 # Reduces color banding of the sun glare.
nativeScaling: 2 # Fixes post lighting.
roundModes:
@@ -60712,6 +60711,7 @@ SLUS-20550:
halfPixelOffset: 3 # Fixes double image.
gpuTargetCLUT: 1 # Fixes sun penetrating buildings.
autoFlush: 1 # Fixes sun occlusion.
bilinearUpscale: 2 # Fixes sun glare textures to behave like native.
SLUS-20552:
name: "Grand Theft Auto - Vice City"
region: "NTSC-U"
@@ -69617,8 +69617,6 @@ SLUS-90009:
SLUS-97405:
name: "ATV Offroad Fury 3"
region: "NTSC-U"
speedHacks:
mtvu: 0 # Increases FPS drastically.
SRPM-70201:
name: "Space Venus Starring Morning Musume."
region: "NTSC-J"

View File

@@ -1690,6 +1690,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000005e040000220b000013050000,Xbox One Elite 2 Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000050b000002090000,Xbox One Elite Series 2,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
030000005e040000ea02000011050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
050082795e040000e002000003090000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
060000005e040000ea0200000b050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
060000005e040000ea0200000d050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b000001050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,

View File

@@ -23,6 +23,7 @@ if(UNIX AND NOT APPLE)
option(ENABLE_SETCAP "Enable networking capability for DEV9" OFF)
option(X11_API "Enable X11 support" ON)
option(WAYLAND_API "Enable Wayland support" ON)
option(USE_BACKTRACE "Enable libbacktrace support" ON)
endif()
if(UNIX)

View File

@@ -65,7 +65,10 @@ else()
find_package(Wayland REQUIRED Egl)
endif()
find_package(Libbacktrace REQUIRED)
if(USE_BACKTRACE)
find_package(Libbacktrace REQUIRED)
endif()
find_package(PkgConfig REQUIRED)
pkg_check_modules(DBUS REQUIRED dbus-1)
endif()

View File

@@ -167,10 +167,16 @@ else()
)
target_link_libraries(common PRIVATE
${DBUS_LINK_LIBRARIES}
libbacktrace::libbacktrace
X11::X11
X11::Xrandr
)
if(USE_BACKTRACE)
target_compile_definitions(common PRIVATE "HAS_LIBBACKTRACE=1")
target_link_libraries(common PRIVATE libbacktrace::libbacktrace)
endif()
if(${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
target_link_libraries(common PRIVATE cpuinfo)
endif()
endif()
set_source_files_properties(PrecompiledHeader.cpp PROPERTIES HEADER_FILE_ONLY TRUE)

View File

@@ -176,7 +176,7 @@ void CrashHandler::WriteDumpForCaller()
WriteMinidumpAndCallstack(nullptr);
}
#elif !defined(__APPLE__)
#elif !defined(__APPLE__) && defined(HAS_LIBBACKTRACE)
#include "FileSystem.h"
@@ -377,4 +377,4 @@ void CrashHandler::CrashSignalHandler(int signal, siginfo_t* siginfo, void* ctx)
std::abort();
}
#endif
#endif

View File

@@ -19,6 +19,10 @@
#include "fmt/core.h"
#if defined(__FreeBSD__)
#include "cpuinfo.h"
#endif
// FreeBSD does not have MAP_FIXED_NOREPLACE, but does have MAP_EXCL.
// MAP_FIXED combined with MAP_EXCL behaves like MAP_FIXED_NOREPLACE.
#if defined(__FreeBSD__) && !defined(MAP_FIXED_NOREPLACE)
@@ -142,6 +146,22 @@ size_t HostSys::GetRuntimePageSize()
size_t HostSys::GetRuntimeCacheLineSize()
{
#if defined(__FreeBSD__)
if (!cpuinfo_initialize())
return 0;
u32 max_line_size = 0;
for (u32 i = 0; i < cpuinfo_get_processors_count(); i++)
{
const u32 l1i = cpuinfo_get_processor(i)->cache.l1i->line_size;
const u32 l1d = cpuinfo_get_processor(i)->cache.l1d->line_size;
const u32 res = std::max<u32>(l1i, l1d);
max_line_size = std::max<u32>(max_line_size, res);
}
return static_cast<size_t>(max_line_size);
#else
int l1i = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
int l1d = sysconf(_SC_LEVEL1_ICACHE_LINESIZE);
int res = (l1i > l1d) ? l1i : l1d;
@@ -160,6 +180,7 @@ size_t HostSys::GetRuntimeCacheLineSize()
}
return (res > 0) ? static_cast<size_t>(res) : 0;
#endif
}
SharedMemoryMappingArea::SharedMemoryMappingArea(u8* base_ptr, size_t size, size_t num_pages)

View File

@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LGPL-3.0+
#include "MemoryViewWidget.h"
#include "common/Console.h"
#include "QtHost.h"
#include "QtUtils.h"
@@ -10,7 +11,6 @@
#include <QtWidgets/QInputDialog>
#include <QtWidgets/QMessageBox>
#include <QtGui/QClipboard>
#include <QtCore/QtEndian>
using namespace QtUtils;
@@ -66,48 +66,78 @@ void MemoryViewTable::DrawTable(QPainter& painter, const QPalette& palette, s32
const u32 currentRowAddress = startAddress + (i * 0x10);
s32 valX = valuexAxis;
segmentXAxis[0] = valX;
u32 currentSegmentAddress = currentRowAddress;
for (int j = 0; j < 16; j++)
for (int j = 0; j < 16 / static_cast<s32>(displayType); j++)
{
const u32 currentByteAddress = currentRowAddress + j;
valX += charWidth;
const u32 thisSegmentsStart = currentRowAddress + (j * static_cast<s32>(displayType));
if (!(j % (s32)displayType))
{
valX += charWidth;
currentSegmentAddress = currentByteAddress;
}
segmentXAxis[j] = valX;
bool penDefault = false;
if ((selectedAddress & ~0xF) == currentRowAddress)
{
if (selectedAddress == currentByteAddress)
if (selectedAddress >= thisSegmentsStart && selectedAddress < (thisSegmentsStart + static_cast<s32>(displayType)))
{ // If the current byte and row we are drawing is selected
if (!selectedText)
{
s32 charsIntoSegment = ((selectedAddress - thisSegmentsStart) * 2) + ((selectedNibbleHI ? 0 : 1) ^ littleEndian);
if (littleEndian)
charsIntoSegment = (static_cast<s32>(displayType) * 2) - charsIntoSegment - 1;
painter.setPen(QColor::fromRgb(205, 165, 0)); // SELECTED NIBBLE LINE COLOUR
const QPoint lineStart(valX + (selectedNibbleHI ? 0 : charWidth) + 1, y + (rowHeight * i));
const QPoint lineStart(valX + (charsIntoSegment * charWidth) + 1, y + (rowHeight * i));
painter.drawLine(lineStart, lineStart + QPoint(charWidth - 3, 0));
}
painter.setPen(QColor::fromRgb(0xaa, 0x22, 0x22)); // SELECTED BYTE COLOUR
}
// If the current selected byte is in our current segment, highlight the entire segment
else if (displayType != MemoryViewType::BYTE &&
currentSegmentAddress <= selectedAddress && (selectedAddress <= (currentSegmentAddress + (s32)displayType - 1)))
{
painter.setPen(palette.highlight().color()); // SELECTED SEGMENT COLOUR
}
else
{
penDefault = true;
painter.setPen(palette.text().color()); // Default colour
}
}
else
{
penDefault = true;
painter.setPen(palette.text().color()); // Default colour
}
bool valid;
const u8 val = static_cast<u8>(m_cpu->read8(currentByteAddress, valid));
painter.drawText(valX, y + (rowHeight * i), valid ? FilledQStringFromValue(val, 16) : "??");
valX += charWidth * 2;
switch (displayType)
{
case MemoryViewType::BYTE:
{
const u8 val = static_cast<u8>(m_cpu->read8(thisSegmentsStart, valid));
if (penDefault && val == 0)
painter.setPen(QColor::fromRgb(145, 145, 155)); // ZERO BYTE COLOUR
painter.drawText(valX, y + (rowHeight * i), valid ? FilledQStringFromValue(val, 16) : "??");
break;
}
case MemoryViewType::BYTEHW:
{
const u16 val = convertEndian<u16>(static_cast<u16>(m_cpu->read16(thisSegmentsStart, valid)));
if (penDefault && val == 0)
painter.setPen(QColor::fromRgb(145, 145, 155)); // ZERO BYTE COLOUR
painter.drawText(valX, y + (rowHeight * i), valid ? FilledQStringFromValue(val, 16) : "????");
break;
}
case MemoryViewType::WORD:
{
const u32 val = convertEndian<u32>(m_cpu->read32(thisSegmentsStart, valid));
if (penDefault && val == 0)
painter.setPen(QColor::fromRgb(145, 145, 155)); // ZERO BYTE COLOUR
painter.drawText(valX, y + (rowHeight * i), valid ? FilledQStringFromValue(val, 16) : "????????");
break;
}
case MemoryViewType::DWORD:
{
const u64 val = convertEndian<u64>(m_cpu->read64(thisSegmentsStart, valid));
if (penDefault && val == 0)
painter.setPen(QColor::fromRgb(145, 145, 155)); // ZERO BYTE COLOUR
painter.drawText(valX, y + (rowHeight * i), valid ? FilledQStringFromValue(val, 16) : "????????????????");
break;
}
}
valX += charWidth * 2 * static_cast<s32>(displayType);
}
// valX is our new X position after the hex values
@@ -146,12 +176,15 @@ void MemoryViewTable::SelectAt(QPoint pos)
const u32 selectedRow = (pos.y() - 2) / (rowHeight);
const s32 x = pos.x();
const s32 avgSegmentWidth = segmentXAxis[1] - segmentXAxis[0];
const u32 nibbleWidth = (avgSegmentWidth / (2 * (s32)displayType));
selectedAddress = (selectedRow * 0x10) + startAddress;
if (x <= segmentXAxis[0])
{
selectedText = false;
// The user clicked before the first segment
selectedText = false;
if (littleEndian)
selectedAddress += static_cast<s32>(displayType) - 1;
selectedNibbleHI = true;
}
else if (x > valuexAxis && x < textXAxis)
@@ -160,10 +193,13 @@ void MemoryViewTable::SelectAt(QPoint pos)
// The user clicked inside of the hexadecimal area
for (s32 i = 0; i < 16; i++)
{
if (i == 15 || (x >= segmentXAxis[i] && x < (segmentXAxis[i + 1])))
if (i == ((16 / static_cast<s32>(displayType)) - 1) || (x >= segmentXAxis[i] && x < (segmentXAxis[i + 1])))
{
selectedAddress = selectedAddress + i;
selectedNibbleHI = ((x - segmentXAxis[i]) < ((avgSegmentWidth / 2) - 2)); // Subtract 2 units, makes selecting nibbles feel more natural
u32 indexInSegment = (x - segmentXAxis[i]) / nibbleWidth;
if (littleEndian)
indexInSegment = (static_cast<s32>(displayType) * 2) - indexInSegment - 1;
selectedAddress = selectedAddress + i * static_cast<s32>(displayType) + (indexInSegment / 2);
selectedNibbleHI = littleEndian ? indexInSegment & 1 : !(indexInSegment & 1);
break;
}
}
@@ -185,13 +221,13 @@ u128 MemoryViewTable::GetSelectedSegment()
val.lo = m_cpu->read8(selectedAddress);
break;
case MemoryViewType::BYTEHW:
val.lo = qToBigEndian((u16)m_cpu->read16(selectedAddress & ~1));
val.lo = convertEndian(static_cast<u16>(m_cpu->read16(selectedAddress & ~1)));
break;
case MemoryViewType::WORD:
val.lo = qToBigEndian(m_cpu->read32(selectedAddress & ~3));
val.lo = convertEndian(m_cpu->read32(selectedAddress & ~3));
break;
case MemoryViewType::DWORD:
val._u64[0] = qToBigEndian(m_cpu->read64(selectedAddress & ~7));
val._u64[0] = convertEndian(m_cpu->read64(selectedAddress & ~7));
break;
}
return val;
@@ -210,7 +246,8 @@ void MemoryViewTable::InsertIntoSelectedHexView(u8 value)
});
}
void MemoryViewTable::InsertAtCurrentSelection(const QString& text) {
void MemoryViewTable::InsertAtCurrentSelection(const QString& text)
{
if (!m_cpu->isValidAddress(selectedAddress))
return;
@@ -218,16 +255,89 @@ void MemoryViewTable::InsertAtCurrentSelection(const QString& text) {
// This approach prevents one from pasting on a nibble boundary, but that is almost always
// user error, and we don't have an undo function in this view, so best to stay conservative.
QByteArray input = selectedText ? text.toUtf8() : QByteArray::fromHex(text.toUtf8());
Host::RunOnCPUThread([this, address = selectedAddress, cpu = m_cpu, inBytes = input] {
u32 currAddr = address;
for (int i = 0; i < inBytes.size(); i++)
{
cpu->write8(address + i, inBytes[i]);
cpu->write8(currAddr, inBytes[i]);
currAddr = nextAddress(currAddr);
QtHost::RunOnUIThread([this] { parent->update(); });
}
QtHost::RunOnUIThread([this, inBytes] { UpdateSelectedAddress(selectedAddress + inBytes.size()); parent->update(); });
});
}
u32 MemoryViewTable::nextAddress(u32 addr)
{
if (!littleEndian)
{
return addr + 1;
}
else
{
if (selectedAddress % static_cast<s32>(displayType) == 0)
return addr + (static_cast<s32>(displayType) * 2 - 1);
else
return addr - 1;
}
}
u32 MemoryViewTable::prevAddress(u32 addr)
{
if (!littleEndian)
{
return addr - 1;
}
else
{
// It works
if ((addr & (static_cast<u32>(displayType) - 1)) == (static_cast<u32>(displayType) - 1))
return addr - (static_cast<s32>(displayType) * 2 - 1);
else
return selectedAddress + 1;
}
}
void MemoryViewTable::ForwardSelection()
{
if (!littleEndian)
{
if ((selectedNibbleHI = !selectedNibbleHI))
UpdateSelectedAddress(selectedAddress + 1);
}
else
{
if ((selectedNibbleHI = !selectedNibbleHI))
{
if (selectedAddress % static_cast<s32>(displayType) == 0)
UpdateSelectedAddress(selectedAddress + (static_cast<s32>(displayType) * 2 - 1));
else
UpdateSelectedAddress(selectedAddress - 1);
}
}
}
void MemoryViewTable::BackwardSelection()
{
if (!littleEndian)
{
if (!(selectedNibbleHI = !selectedNibbleHI))
UpdateSelectedAddress(selectedAddress - 1);
}
else
{
if (!(selectedNibbleHI = !selectedNibbleHI))
{
// It works
if ((selectedAddress & (static_cast<u32>(displayType) - 1)) == (static_cast<u32>(displayType) - 1))
UpdateSelectedAddress(selectedAddress - (static_cast<s32>(displayType) * 2 - 1));
else
UpdateSelectedAddress(selectedAddress + 1);
}
}
}
// We need both key and keychar because `key` is easy to use, but is case insensitive
bool MemoryViewTable::KeyPress(int key, QChar keychar)
{
@@ -255,16 +365,16 @@ bool MemoryViewTable::KeyPress(int key, QChar keychar)
case Qt::Key::Key_Escape:
Host::RunOnCPUThread([this, address = selectedAddress, cpu = m_cpu] {
cpu->write8(address, 0);
QtHost::RunOnUIThread([this] { UpdateSelectedAddress(selectedAddress - 1); parent->update(); });
QtHost::RunOnUIThread([this] {BackwardSelection(); parent->update(); });
});
pressHandled = true;
break;
case Qt::Key::Key_Right:
UpdateSelectedAddress(selectedAddress + 1);
ForwardSelection();
pressHandled = true;
break;
case Qt::Key::Key_Left:
UpdateSelectedAddress(selectedAddress - 1);
BackwardSelection();
pressHandled = true;
break;
default:
@@ -278,13 +388,11 @@ bool MemoryViewTable::KeyPress(int key, QChar keychar)
if (keyCharIsText)
{
// Check if key pressed is hex before insertion (QString conversion fails otherwise)
const u8 keyPressed = (u8)QString(QChar(key)).toInt(&pressHandled, 16);
const u8 keyPressed = static_cast<u8>(QString(QChar(key)).toInt(&pressHandled, 16));
if (pressHandled)
{
InsertIntoSelectedHexView(keyPressed);
// Increment to the next nibble or byte
if ((selectedNibbleHI = !selectedNibbleHI))
UpdateSelectedAddress(selectedAddress + 1);
ForwardSelection();
}
}
@@ -293,19 +401,15 @@ bool MemoryViewTable::KeyPress(int key, QChar keychar)
case Qt::Key::Key_Backspace:
case Qt::Key::Key_Escape:
InsertIntoSelectedHexView(0);
// Move back a byte or nibble if it's backspace being pressed
if (!(selectedNibbleHI = !selectedNibbleHI))
UpdateSelectedAddress(selectedAddress - 1);
BackwardSelection();
pressHandled = true;
break;
case Qt::Key::Key_Right:
if ((selectedNibbleHI = !selectedNibbleHI))
UpdateSelectedAddress(selectedAddress + 1);
ForwardSelection();
pressHandled = true;
break;
case Qt::Key::Key_Left:
if (!(selectedNibbleHI = !selectedNibbleHI))
UpdateSelectedAddress(selectedAddress - 1);
BackwardSelection();
pressHandled = true;
break;
default:
@@ -403,6 +507,11 @@ void MemoryViewWidget::customMenuRequested(QPoint pos)
m_contextMenu->addSeparator();
m_actionLittleEndian = new QAction(tr("Show as Little Endian"));
m_actionLittleEndian->setCheckable(true);
m_contextMenu->addAction(m_actionLittleEndian);
connect(m_actionLittleEndian, &QAction::triggered, this, [this]() { m_table.SetLittleEndian(m_actionLittleEndian->isChecked()); });
// View Types
m_actionBYTE = new QAction(tr("Show as 1 byte"));
m_actionBYTE->setCheckable(true);
@@ -446,6 +555,8 @@ void MemoryViewWidget::customMenuRequested(QPoint pos)
m_contextMenu->addAction(action);
connect(action, &QAction::triggered, this, [this]() { contextPaste(); });
}
m_actionLittleEndian->setChecked(m_table.GetLittleEndian());
const MemoryViewType currentViewType = m_table.GetViewType();
m_actionBYTE->setChecked(currentViewType == MemoryViewType::BYTE);

View File

@@ -12,6 +12,7 @@
#include <QtWidgets/QMenu>
#include <QtWidgets/QTabBar>
#include <QtGui/QPainter>
#include <QtCore/QtEndian>
#include <vector>
@@ -28,22 +29,39 @@ class MemoryViewTable
QWidget* parent;
DebugInterface* m_cpu;
MemoryViewType displayType = MemoryViewType::BYTE;
bool littleEndian = true;
u32 rowCount;
u32 rowVisible;
s32 rowHeight;
// Stuff used for selection handling
// This gets set every paint and depends on the window size / current display mode (1byte,2byte,etc)
s32 valuexAxis; // Where the hexadecimal view begins
s32 textXAxis; // Where the text view begins
s32 row1YAxis; // Where the first row starts
s32 segmentXAxis[16]; // Where the segments begin
s32 valuexAxis; // Where the hexadecimal view begins
s32 textXAxis; // Where the text view begins
s32 row1YAxis; // Where the first row starts
s32 segmentXAxis[16]; // Where the segments begin
bool selectedText = false; // Whether the user has clicked on text or hex
bool selectedNibbleHI = false;
void InsertIntoSelectedHexView(u8 value);
template <class T>
T convertEndian(T in)
{
if (littleEndian)
{
return in;
}
else
{
return qToBigEndian(in);
}
}
u32 nextAddress(u32 addr);
u32 prevAddress(u32 addr);
public:
MemoryViewTable(QWidget* parent)
: parent(parent){};
@@ -60,6 +78,8 @@ public:
void SelectAt(QPoint pos);
u128 GetSelectedSegment();
void InsertAtCurrentSelection(const QString& text);
void ForwardSelection();
void BackwardSelection();
// Returns true if the keypress was handled
bool KeyPress(int key, QChar keychar);
@@ -72,6 +92,16 @@ public:
{
displayType = viewType;
}
bool GetLittleEndian()
{
return littleEndian;
}
void SetLittleEndian(bool le)
{
littleEndian = le;
}
};
@@ -111,6 +141,7 @@ private:
Ui::RegisterWidget ui;
QMenu* m_contextMenu = 0x0;
QAction* m_actionLittleEndian;
QAction* m_actionBYTE;
QAction* m_actionBYTEHW;
QAction* m_actionWORD;

View File

@@ -256,8 +256,6 @@ Qt::ItemFlags BreakpointModel::flags(const QModelIndex& index) const
{
volatile const int row = index.row();
const bool is_breakpoint = std::holds_alternative<BreakPoint>(m_breakpoints.at(row));
switch (index.column())
{
case BreakpointColumns::CONDITION:

View File

@@ -851,16 +851,16 @@ void MainWindow::restoreStateFromConfig()
void MainWindow::updateEmulationActions(bool starting, bool running, bool stopping)
{
const bool starting_or_running = starting || running;
const bool starting_or_running_or_stopping = starting || running || stopping;
m_ui.actionStartFile->setDisabled(starting_or_running || stopping);
m_ui.actionStartDisc->setDisabled(starting_or_running || stopping);
m_ui.actionStartBios->setDisabled(starting_or_running || stopping);
m_ui.actionToolbarStartFile->setDisabled(starting_or_running || stopping);
m_ui.actionToolbarStartDisc->setDisabled(starting_or_running || stopping);
m_ui.actionToolbarStartBios->setDisabled(starting_or_running || stopping);
m_ui.actionStartFullscreenUI->setDisabled(starting_or_running || stopping);
m_ui.actionToolbarStartFullscreenUI->setDisabled(starting_or_running || stopping);
m_ui.actionStartFile->setDisabled(starting_or_running_or_stopping);
m_ui.actionStartDisc->setDisabled(starting_or_running_or_stopping);
m_ui.actionStartBios->setDisabled(starting_or_running_or_stopping);
m_ui.actionToolbarStartFile->setDisabled(starting_or_running_or_stopping);
m_ui.actionToolbarStartDisc->setDisabled(starting_or_running_or_stopping);
m_ui.actionToolbarStartBios->setDisabled(starting_or_running_or_stopping);
m_ui.actionStartFullscreenUI->setDisabled(starting_or_running_or_stopping);
m_ui.actionToolbarStartFullscreenUI->setDisabled(starting_or_running_or_stopping);
m_ui.actionPowerOff->setEnabled(running);
m_ui.actionPowerOffWithoutSaving->setEnabled(running);
@@ -869,6 +869,7 @@ void MainWindow::updateEmulationActions(bool starting, bool running, bool stoppi
m_ui.actionScreenshot->setEnabled(running);
m_ui.menuChangeDisc->setEnabled(running);
m_ui.menuSaveState->setEnabled(running);
m_ui.actionSaveGSDump->setEnabled(running);
m_ui.actionToolbarPowerOff->setEnabled(running);
m_ui.actionToolbarReset->setEnabled(running);
@@ -902,8 +903,8 @@ void MainWindow::updateEmulationActions(bool starting, bool running, bool stoppi
}
// scanning needs to be disabled while running
m_ui.actionScanForNewGames->setDisabled(starting_or_running || stopping);
m_ui.actionRescanAllGames->setDisabled(starting_or_running || stopping);
m_ui.actionScanForNewGames->setDisabled(starting_or_running_or_stopping);
m_ui.actionRescanAllGames->setDisabled(starting_or_running_or_stopping);
}
void MainWindow::updateDisplayRelatedActions(bool has_surface, bool render_to_main, bool fullscreen)
@@ -1053,7 +1054,7 @@ bool MainWindow::shouldHideMouseCursor() const
bool MainWindow::shouldHideMainWindow() const
{
// NOTE: We can't use isRenderingToMain() here, because this happens post-fullscreen-switch.
return Host::GetBoolSettingValue("UI", "HideMainWindowWhenRunning", false) ||
return (Host::GetBoolSettingValue("UI", "HideMainWindowWhenRunning", false) && !g_emu_thread->shouldRenderToMain()) ||
(g_emu_thread->shouldRenderToMain() && (isRenderingFullscreen() || m_is_temporarily_windowed)) ||
QtHost::InNoGUIMode();
}
@@ -2664,7 +2665,7 @@ void MainWindow::setGameListEntryCoverImage(const GameList::Entry* entry)
return;
const QString old_filename = QString::fromStdString(GameList::GetCoverImagePathForEntry(entry));
const QString new_filename = QString::fromStdString(GameList::GetNewCoverImagePathForEntry(entry, filename.toUtf8().constData()));
const QString new_filename = QString::fromStdString(GameList::GetNewCoverImagePathForEntry(entry, filename.toUtf8().constData(), true));
if (new_filename.isEmpty())
return;

View File

@@ -124,6 +124,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.osdShowSettings, "EmuCore/GS", "OsdShowSettings", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.osdShowInputs, "EmuCore/GS", "OsdShowInputs", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.osdShowFrameTimes, "EmuCore/GS", "OsdShowFrameTimes", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.osdShowVersion, "EmuCore/GS", "OsdShowVersion", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.warnAboutUnsafeSettings, "EmuCore", "WarnAboutUnsafeSettings", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.fxaa, "EmuCore/GS", "fxaa", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.shadeBoost, "EmuCore/GS", "ShadeBoost", false);
@@ -396,6 +397,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
&GraphicsSettingsWidget::onEnableAudioCaptureArgumentsChanged);
onCaptureContainerChanged();
onCaptureCodecChanged();
onEnableVideoCaptureChanged();
onEnableVideoCaptureArgumentsChanged();
onVideoCaptureAutoResolutionChanged();
@@ -718,8 +720,11 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
dialog->registerWidgetHelp(m_ui.osdShowInputs, tr("Show Inputs"), tr("Unchecked"),
tr("Shows the current controller state of the system in the bottom-left corner of the display."));
dialog->registerWidgetHelp(
m_ui.osdShowFrameTimes, tr("Show Frame Times"), tr("Unchecked"), tr("Displays a graph showing the average frametimes."));
dialog->registerWidgetHelp(m_ui.osdShowFrameTimes, tr("Show Frame Times"), tr("Unchecked"),
tr("Displays a graph showing the average frametimes."));
dialog->registerWidgetHelp(m_ui.osdShowVersion, tr("Show PCSX2 Version"), tr("Unchecked"),
tr("Shows the current PCSX2 version on the top-right corner of the display"));
dialog->registerWidgetHelp(m_ui.warnAboutUnsafeSettings, tr("Warn About Unsafe Settings"), tr("Checked"),
tr("Displays warnings when settings are enabled which may break games."));
@@ -731,6 +736,10 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
"<b>If unsure, leave it on default.<b>"));
dialog->registerWidgetHelp(m_ui.videoCaptureFormat, tr("Video Format"), tr("Default"), tr("Selects which Video Format to be used for Video Capture. If by chance the codec does not support the format, the first format available will be used. "
"<b>If unsure, leave it on default.<b>"));
dialog->registerWidgetHelp(m_ui.videoCaptureBitrate, tr("Video Bitrate"), tr("6000 kbps"), tr("Sets the video bitrate to be used. "
"Larger bitrate generally yields better video quality at the cost of larger resulting file size."));
@@ -779,7 +788,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
dialog->registerWidgetHelp(m_ui.skipPresentingDuplicateFrames, tr("Skip Presenting Duplicate Frames"), tr("Unchecked"),
tr("Detects when idle frames are being presented in 25/30fps games, and skips presenting those frames. The frame is still "
"rendered, it just means the GPU has more time to complete it (this is NOT frame skipping). Can smooth our frame time "
"rendered, it just means the GPU has more time to complete it (this is NOT frame skipping). Can smooth out frame time "
"fluctuations when the CPU/GPU are near maximum utilization, but makes frame pacing more inconsistent and can increase "
"input lag."));
@@ -910,6 +919,7 @@ void GraphicsSettingsWidget::onCaptureContainerChanged()
SettingWidgetBinder::BindWidgetToStringSetting(
m_dialog->getSettingsInterface(), m_ui.videoCaptureCodec, "EmuCore/GS", "VideoCaptureCodec");
connect(m_ui.videoCaptureCodec, &QComboBox::currentIndexChanged, this, &GraphicsSettingsWidget::onCaptureCodecChanged);
m_ui.audioCaptureCodec->disconnect();
m_ui.audioCaptureCodec->clear();
@@ -925,6 +935,30 @@ void GraphicsSettingsWidget::onCaptureContainerChanged()
m_dialog->getSettingsInterface(), m_ui.audioCaptureCodec, "EmuCore/GS", "AudioCaptureCodec");
}
void GraphicsSettingsWidget::GraphicsSettingsWidget::onCaptureCodecChanged()
{
m_ui.videoCaptureFormat->disconnect();
m_ui.videoCaptureFormat->clear();
//: This string refers to a default pixel format
m_ui.videoCaptureFormat->addItem(tr("Default"), "");
const std::string codec(
m_dialog->getEffectiveStringValue("EmuCore/GS", "VideoCaptureCodec", ""));
if (!codec.empty())
{
for (const auto& [id, name] : GSCapture::GetVideoFormatList(codec.c_str()))
{
const QString qid(QString::number(id));
const QString qname(QString::fromStdString(name));
m_ui.videoCaptureFormat->addItem(qname, qid);
}
}
SettingWidgetBinder::BindWidgetToStringSetting(
m_dialog->getSettingsInterface(), m_ui.videoCaptureFormat, "EmuCore/GS", "VideoCaptureFormat");
}
void GraphicsSettingsWidget::onEnableVideoCaptureChanged()
{
const bool enabled = m_dialog->getEffectiveBoolValue("EmuCore/GS", "EnableVideoCapture", true);

View File

@@ -38,6 +38,7 @@ private Q_SLOTS:
void onTextureReplacementChanged();
void onShadeBoostChanged();
void onCaptureContainerChanged();
void onCaptureCodecChanged();
void onEnableVideoCaptureChanged();
void onEnableVideoCaptureArgumentsChanged();
void onVideoCaptureAutoResolutionChanged();

View File

@@ -1610,59 +1610,17 @@
</item>
<item row="1" column="0" colspan="2">
<layout class="QGridLayout" name="gridLayout_6">
<item row="3" column="1">
<widget class="QCheckBox" name="osdShowIndicators">
<property name="text">
<string>Show Indicators</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="osdShowResolution">
<property name="text">
<string>Show Resolution</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QCheckBox" name="osdShowInputs">
<property name="text">
<string>Show Inputs</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="osdShowGPU">
<property name="text">
<string>Show GPU Usage</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="osdShowSettings">
<property name="text">
<string>Show Settings</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="osdShowFPS">
<property name="text">
<string>Show FPS</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="osdShowMessages">
<item row="1" column="0">
<widget class="QCheckBox" name="osdShowVersion">
<property name="text">
<string>Show OSD Messages</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="osdShowGSStats">
<property name="text">
<string>Show Statistics</string>
<string>Show PCSX2 Version</string>
</property>
</widget>
</item>
@@ -1673,27 +1631,76 @@
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="osdShowSpeed">
<item row="3" column="1">
<widget class="QCheckBox" name="osdShowIndicators">
<property name="text">
<string>Show Speed Percentages</string>
<string>Show Indicators</string>
</property>
</widget>
</item>
<item row="5" column="1">
<item row="0" column="0">
<widget class="QCheckBox" name="osdShowMessages">
<property name="text">
<string>Show OSD Messages</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QCheckBox" name="warnAboutUnsafeSettings">
<property name="text">
<string>Warn About Unsafe Settings</string>
</property>
</widget>
</item>
<item row="5" column="0">
<item row="2" column="1">
<widget class="QCheckBox" name="osdShowGPU">
<property name="text">
<string>Show GPU Usage</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="osdShowResolution">
<property name="text">
<string>Show Resolution</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QCheckBox" name="osdShowFrameTimes">
<property name="text">
<string>Show Frame Times</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QCheckBox" name="osdShowGSStats">
<property name="text">
<string>Show Statistics</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="osdShowSpeed">
<property name="text">
<string>Show Speed Percentages</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QCheckBox" name="osdShowInputs">
<property name="text">
<string>Show Inputs</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="osdShowSettings">
<property name="text">
<string>Show Settings</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
@@ -1840,13 +1847,23 @@
<widget class="QComboBox" name="videoCaptureCodec"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="videoCaptureFomatLabel">
<property name="text">
<string>Format:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="videoCaptureFormat"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="videoCaptureBitrateLabel">
<property name="text">
<string>Bitrate:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<item row="2" column="1">
<widget class="QSpinBox" name="videoCaptureBitrate">
<property name="suffix">
<string extracomment="Unit that will appear next to a number. Alter the space or whatever is needed before the text depending on your language."> kbps</string>
@@ -1862,14 +1879,14 @@
</property>
</widget>
</item>
<item row="2" column="0">
<item row="3" column="0">
<widget class="QLabel" name="videoCaptureResolutionLabel">
<property name="text">
<string>Resolution:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<item row="3" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_10" stretch="1,0,1,0">
<item>
<widget class="QSpinBox" name="videoCaptureWidth">
@@ -1919,14 +1936,14 @@
</item>
</layout>
</item>
<item row="3" column="0" colspan="2">
<item row="4" column="0" colspan="2">
<widget class="QCheckBox" name="enableVideoCaptureArguments">
<property name="text">
<string>Extra Arguments</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<item row="5" column="0" colspan="2">
<widget class="QLineEdit" name="videoCaptureArguments"/>
</item>
</layout>

View File

@@ -39,6 +39,8 @@ const char* InterfaceSettingsWidget::THEME_NAMES[] = {
QT_TRANSLATE_NOOP("InterfaceSettingsWidget", "Ruby (Black/Red) [Dark]"),
//: Ignore what Crowdin says in this string about "[Light]/[Dark]" being untouchable here, these are not variables in this case and must be translated.
QT_TRANSLATE_NOOP("InterfaceSettingsWidget", "Sapphire (Black/Blue) [Dark]"),
//: Ignore what Crowdin says in this string about "[Light]/[Dark]" being untouchable here, these are not variables in this case and must be translated.
QT_TRANSLATE_NOOP("InterfaceSettingsWidget", "Emerald (Black/Green) [Dark]"),
//: "Custom.qss" must be kept as-is.
QT_TRANSLATE_NOOP("InterfaceSettingsWidget", "Custom.qss [Drop in PCSX2 Folder]"),
nullptr};
@@ -61,6 +63,7 @@ const char* InterfaceSettingsWidget::THEME_VALUES[] = {
"CobaltSky",
"Ruby",
"Sapphire",
"Emerald",
"Custom",
nullptr};

View File

@@ -108,28 +108,28 @@ void QtHost::SetStyleFromSettings()
const QColor blue(198, 238, 255);
const QColor blue2(0, 88, 208);
QPalette darkPalette;
darkPalette.setColor(QPalette::Window, darkGray);
darkPalette.setColor(QPalette::WindowText, Qt::white);
darkPalette.setColor(QPalette::Base, black);
darkPalette.setColor(QPalette::AlternateBase, darkGray);
darkPalette.setColor(QPalette::ToolTipBase, blue2);
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
darkPalette.setColor(QPalette::Text, Qt::white);
darkPalette.setColor(QPalette::Button, darkGray);
darkPalette.setColor(QPalette::ButtonText, Qt::white);
darkPalette.setColor(QPalette::Link, blue);
darkPalette.setColor(QPalette::Highlight, blue2);
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
darkPalette.setColor(QPalette::PlaceholderText, QColor(Qt::white).darker());
QPalette darkBluePalette;
darkBluePalette.setColor(QPalette::Window, darkGray);
darkBluePalette.setColor(QPalette::WindowText, Qt::white);
darkBluePalette.setColor(QPalette::Base, black);
darkBluePalette.setColor(QPalette::AlternateBase, darkGray);
darkBluePalette.setColor(QPalette::ToolTipBase, blue2);
darkBluePalette.setColor(QPalette::ToolTipText, Qt::white);
darkBluePalette.setColor(QPalette::Text, Qt::white);
darkBluePalette.setColor(QPalette::Button, darkGray);
darkBluePalette.setColor(QPalette::ButtonText, Qt::white);
darkBluePalette.setColor(QPalette::Link, blue);
darkBluePalette.setColor(QPalette::Highlight, blue2);
darkBluePalette.setColor(QPalette::HighlightedText, Qt::white);
darkBluePalette.setColor(QPalette::PlaceholderText, QColor(Qt::white).darker());
darkPalette.setColor(QPalette::Active, QPalette::Button, darkGray);
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::Light, darkGray);
darkBluePalette.setColor(QPalette::Active, QPalette::Button, darkGray);
darkBluePalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
darkBluePalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
darkBluePalette.setColor(QPalette::Disabled, QPalette::Text, gray);
darkBluePalette.setColor(QPalette::Disabled, QPalette::Light, darkGray);
qApp->setPalette(darkPalette);
qApp->setPalette(darkBluePalette);
}
else if (theme == "GreyMatter")
{
@@ -143,28 +143,28 @@ void QtHost::SetStyleFromSettings()
const QColor gray(111, 111, 111);
const QColor blue(198, 238, 255);
QPalette darkPalette;
darkPalette.setColor(QPalette::Window, darkGray);
darkPalette.setColor(QPalette::WindowText, Qt::white);
darkPalette.setColor(QPalette::Base, lighterGray);
darkPalette.setColor(QPalette::AlternateBase, darkGray);
darkPalette.setColor(QPalette::ToolTipBase, darkGray);
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
darkPalette.setColor(QPalette::Text, Qt::white);
darkPalette.setColor(QPalette::Button, lighterGray);
darkPalette.setColor(QPalette::ButtonText, Qt::white);
darkPalette.setColor(QPalette::Link, blue);
darkPalette.setColor(QPalette::Highlight, lighterGray.lighter());
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
darkPalette.setColor(QPalette::PlaceholderText, QColor(Qt::white).darker());
QPalette greyMatterPalette;
greyMatterPalette.setColor(QPalette::Window, darkGray);
greyMatterPalette.setColor(QPalette::WindowText, Qt::white);
greyMatterPalette.setColor(QPalette::Base, lighterGray);
greyMatterPalette.setColor(QPalette::AlternateBase, darkGray);
greyMatterPalette.setColor(QPalette::ToolTipBase, darkGray);
greyMatterPalette.setColor(QPalette::ToolTipText, Qt::white);
greyMatterPalette.setColor(QPalette::Text, Qt::white);
greyMatterPalette.setColor(QPalette::Button, lighterGray);
greyMatterPalette.setColor(QPalette::ButtonText, Qt::white);
greyMatterPalette.setColor(QPalette::Link, blue);
greyMatterPalette.setColor(QPalette::Highlight, lighterGray.lighter());
greyMatterPalette.setColor(QPalette::HighlightedText, Qt::white);
greyMatterPalette.setColor(QPalette::PlaceholderText, QColor(Qt::white).darker());
darkPalette.setColor(QPalette::Active, QPalette::Button, lighterGray);
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray.lighter());
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray.lighter());
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray.lighter());
darkPalette.setColor(QPalette::Disabled, QPalette::Light, darkGray);
greyMatterPalette.setColor(QPalette::Active, QPalette::Button, lighterGray);
greyMatterPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray.lighter());
greyMatterPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray.lighter());
greyMatterPalette.setColor(QPalette::Disabled, QPalette::Text, gray.lighter());
greyMatterPalette.setColor(QPalette::Disabled, QPalette::Light, darkGray);
qApp->setPalette(darkPalette);
qApp->setPalette(greyMatterPalette);
}
else if (theme == "UntouchedLagoon")
{
@@ -178,27 +178,27 @@ void QtHost::SetStyleFromSettings()
const QColor tameTeal(160, 190, 185);
const QColor grayBlue(160, 180, 190);
QPalette standardPalette;
standardPalette.setColor(QPalette::Window, tameTeal);
standardPalette.setColor(QPalette::WindowText, black.lighter());
standardPalette.setColor(QPalette::Base, grayBlue);
standardPalette.setColor(QPalette::AlternateBase, tameTeal);
standardPalette.setColor(QPalette::ToolTipBase, tameTeal);
standardPalette.setColor(QPalette::ToolTipText, grayBlue);
standardPalette.setColor(QPalette::Text, black);
standardPalette.setColor(QPalette::Button, tameTeal);
standardPalette.setColor(QPalette::ButtonText, black);
standardPalette.setColor(QPalette::Link, black.lighter());
standardPalette.setColor(QPalette::Highlight, teal);
standardPalette.setColor(QPalette::HighlightedText, grayBlue.lighter());
QPalette untouchedLagoonPalette;
untouchedLagoonPalette.setColor(QPalette::Window, tameTeal);
untouchedLagoonPalette.setColor(QPalette::WindowText, black.lighter());
untouchedLagoonPalette.setColor(QPalette::Base, grayBlue);
untouchedLagoonPalette.setColor(QPalette::AlternateBase, tameTeal);
untouchedLagoonPalette.setColor(QPalette::ToolTipBase, tameTeal);
untouchedLagoonPalette.setColor(QPalette::ToolTipText, grayBlue);
untouchedLagoonPalette.setColor(QPalette::Text, black);
untouchedLagoonPalette.setColor(QPalette::Button, tameTeal);
untouchedLagoonPalette.setColor(QPalette::ButtonText, black);
untouchedLagoonPalette.setColor(QPalette::Link, black.lighter());
untouchedLagoonPalette.setColor(QPalette::Highlight, teal);
untouchedLagoonPalette.setColor(QPalette::HighlightedText, grayBlue.lighter());
standardPalette.setColor(QPalette::Active, QPalette::Button, tameTeal);
standardPalette.setColor(QPalette::Disabled, QPalette::ButtonText, darkteal);
standardPalette.setColor(QPalette::Disabled, QPalette::WindowText, darkteal.lighter());
standardPalette.setColor(QPalette::Disabled, QPalette::Text, darkteal.lighter());
standardPalette.setColor(QPalette::Disabled, QPalette::Light, tameTeal);
untouchedLagoonPalette.setColor(QPalette::Active, QPalette::Button, tameTeal);
untouchedLagoonPalette.setColor(QPalette::Disabled, QPalette::ButtonText, darkteal);
untouchedLagoonPalette.setColor(QPalette::Disabled, QPalette::WindowText, darkteal.lighter());
untouchedLagoonPalette.setColor(QPalette::Disabled, QPalette::Text, darkteal.lighter());
untouchedLagoonPalette.setColor(QPalette::Disabled, QPalette::Light, tameTeal);
qApp->setPalette(standardPalette);
qApp->setPalette(untouchedLagoonPalette);
}
else if (theme == "BabyPastel")
{
@@ -214,27 +214,27 @@ void QtHost::SetStyleFromSettings()
const QColor congoPink(255, 127, 121);
const QColor blue(221, 225, 239);
QPalette standardPalette;
standardPalette.setColor(QPalette::Window, pink);
standardPalette.setColor(QPalette::WindowText, black);
standardPalette.setColor(QPalette::Base, brightPink);
standardPalette.setColor(QPalette::AlternateBase, blue);
standardPalette.setColor(QPalette::ToolTipBase, pink);
standardPalette.setColor(QPalette::ToolTipText, brightPink);
standardPalette.setColor(QPalette::Text, black);
standardPalette.setColor(QPalette::Button, pink);
standardPalette.setColor(QPalette::ButtonText, black);
standardPalette.setColor(QPalette::Link, black);
standardPalette.setColor(QPalette::Highlight, congoPink);
standardPalette.setColor(QPalette::HighlightedText, black);
QPalette babyPastelPalette;
babyPastelPalette.setColor(QPalette::Window, pink);
babyPastelPalette.setColor(QPalette::WindowText, black);
babyPastelPalette.setColor(QPalette::Base, brightPink);
babyPastelPalette.setColor(QPalette::AlternateBase, blue);
babyPastelPalette.setColor(QPalette::ToolTipBase, pink);
babyPastelPalette.setColor(QPalette::ToolTipText, brightPink);
babyPastelPalette.setColor(QPalette::Text, black);
babyPastelPalette.setColor(QPalette::Button, pink);
babyPastelPalette.setColor(QPalette::ButtonText, black);
babyPastelPalette.setColor(QPalette::Link, black);
babyPastelPalette.setColor(QPalette::Highlight, congoPink);
babyPastelPalette.setColor(QPalette::HighlightedText, black);
standardPalette.setColor(QPalette::Active, QPalette::Button, pink);
standardPalette.setColor(QPalette::Disabled, QPalette::ButtonText, redpinkish);
standardPalette.setColor(QPalette::Disabled, QPalette::WindowText, redpinkish);
standardPalette.setColor(QPalette::Disabled, QPalette::Text, redpinkish);
standardPalette.setColor(QPalette::Disabled, QPalette::Light, gray);
babyPastelPalette.setColor(QPalette::Active, QPalette::Button, pink);
babyPastelPalette.setColor(QPalette::Disabled, QPalette::ButtonText, redpinkish);
babyPastelPalette.setColor(QPalette::Disabled, QPalette::WindowText, redpinkish);
babyPastelPalette.setColor(QPalette::Disabled, QPalette::Text, redpinkish);
babyPastelPalette.setColor(QPalette::Disabled, QPalette::Light, gray);
qApp->setPalette(standardPalette);
qApp->setPalette(babyPastelPalette);
}
else if (theme == "PizzaBrown")
{
@@ -250,26 +250,27 @@ void QtHost::SetStyleFromSettings()
const QColor comp(248, 230, 213);
const QColor highlight(188, 100, 60);
QPalette standardPalette;
standardPalette.setColor(QPalette::Window, main);
standardPalette.setColor(QPalette::WindowText, Qt::black);
standardPalette.setColor(QPalette::Base, comp);
standardPalette.setColor(QPalette::AlternateBase, extr);
standardPalette.setColor(QPalette::ToolTipBase, comp);
standardPalette.setColor(QPalette::ToolTipText, Qt::black);
standardPalette.setColor(QPalette::Text, Qt::black);
standardPalette.setColor(QPalette::Button, extr);
standardPalette.setColor(QPalette::ButtonText, Qt::black);
standardPalette.setColor(QPalette::Link, highlight.darker());
standardPalette.setColor(QPalette::Highlight, highlight);
standardPalette.setColor(QPalette::HighlightedText, Qt::white);
standardPalette.setColor(QPalette::Active, QPalette::Button, extr);
standardPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray.darker());
standardPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray.darker());
standardPalette.setColor(QPalette::Disabled, QPalette::Text, Qt::gray);
standardPalette.setColor(QPalette::Disabled, QPalette::Light, gray.lighter());
QPalette pizzaPalette;
pizzaPalette.setColor(QPalette::Window, main);
pizzaPalette.setColor(QPalette::WindowText, Qt::black);
pizzaPalette.setColor(QPalette::Base, comp);
pizzaPalette.setColor(QPalette::AlternateBase, extr);
pizzaPalette.setColor(QPalette::ToolTipBase, comp);
pizzaPalette.setColor(QPalette::ToolTipText, Qt::black);
pizzaPalette.setColor(QPalette::Text, Qt::black);
pizzaPalette.setColor(QPalette::Button, extr);
pizzaPalette.setColor(QPalette::ButtonText, Qt::black);
pizzaPalette.setColor(QPalette::Link, highlight.darker());
pizzaPalette.setColor(QPalette::Highlight, highlight);
pizzaPalette.setColor(QPalette::HighlightedText, Qt::white);
pizzaPalette.setColor(QPalette::Active, QPalette::Button, extr);
pizzaPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray.darker());
pizzaPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray.darker());
pizzaPalette.setColor(QPalette::Disabled, QPalette::Text, Qt::gray);
pizzaPalette.setColor(QPalette::Disabled, QPalette::Light, gray.lighter());
qApp->setPalette(standardPalette);
qApp->setPalette(pizzaPalette);
}
else if (theme == "PCSX2Blue")
{
@@ -283,27 +284,27 @@ void QtHost::SetStyleFromSettings()
const QColor blue(106, 156, 255);
const QColor lightBlue(130, 155, 241);
QPalette standardPalette;
standardPalette.setColor(QPalette::Window, blue2.lighter());
standardPalette.setColor(QPalette::WindowText, blackish);
standardPalette.setColor(QPalette::Base, lightBlue);
standardPalette.setColor(QPalette::AlternateBase, blue2.lighter());
standardPalette.setColor(QPalette::ToolTipBase, blue2);
standardPalette.setColor(QPalette::ToolTipText, Qt::white);
standardPalette.setColor(QPalette::Text, blackish);
standardPalette.setColor(QPalette::Button, blue);
standardPalette.setColor(QPalette::ButtonText, blackish);
standardPalette.setColor(QPalette::Link, darkBlue);
standardPalette.setColor(QPalette::Highlight, Qt::white);
standardPalette.setColor(QPalette::HighlightedText, blackish);
QPalette pcsx2BluePalette;
pcsx2BluePalette.setColor(QPalette::Window, blue2.lighter());
pcsx2BluePalette.setColor(QPalette::WindowText, blackish);
pcsx2BluePalette.setColor(QPalette::Base, lightBlue);
pcsx2BluePalette.setColor(QPalette::AlternateBase, blue2.lighter());
pcsx2BluePalette.setColor(QPalette::ToolTipBase, blue2);
pcsx2BluePalette.setColor(QPalette::ToolTipText, Qt::white);
pcsx2BluePalette.setColor(QPalette::Text, blackish);
pcsx2BluePalette.setColor(QPalette::Button, blue);
pcsx2BluePalette.setColor(QPalette::ButtonText, blackish);
pcsx2BluePalette.setColor(QPalette::Link, darkBlue);
pcsx2BluePalette.setColor(QPalette::Highlight, Qt::white);
pcsx2BluePalette.setColor(QPalette::HighlightedText, blackish);
standardPalette.setColor(QPalette::Active, QPalette::Button, blue);
standardPalette.setColor(QPalette::Disabled, QPalette::ButtonText, darkBlue);
standardPalette.setColor(QPalette::Disabled, QPalette::WindowText, darkBlue);
standardPalette.setColor(QPalette::Disabled, QPalette::Text, darkBlue);
standardPalette.setColor(QPalette::Disabled, QPalette::Light, darkBlue);
pcsx2BluePalette.setColor(QPalette::Active, QPalette::Button, blue);
pcsx2BluePalette.setColor(QPalette::Disabled, QPalette::ButtonText, darkBlue);
pcsx2BluePalette.setColor(QPalette::Disabled, QPalette::WindowText, darkBlue);
pcsx2BluePalette.setColor(QPalette::Disabled, QPalette::Text, darkBlue);
pcsx2BluePalette.setColor(QPalette::Disabled, QPalette::Light, darkBlue);
qApp->setPalette(standardPalette);
qApp->setPalette(pcsx2BluePalette);
}
else if (theme == "ScarletDevilRed")
{
@@ -315,27 +316,27 @@ void QtHost::SetStyleFromSettings()
const QColor purplishRed(120, 45, 69);
const QColor brightRed(200, 45, 69);
QPalette darkPalette;
darkPalette.setColor(QPalette::Window, darkRed);
darkPalette.setColor(QPalette::WindowText, Qt::white);
darkPalette.setColor(QPalette::Base, purplishRed);
darkPalette.setColor(QPalette::AlternateBase, darkRed);
darkPalette.setColor(QPalette::ToolTipBase, darkRed);
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
darkPalette.setColor(QPalette::Text, Qt::white);
darkPalette.setColor(QPalette::Button, purplishRed.darker());
darkPalette.setColor(QPalette::ButtonText, Qt::white);
darkPalette.setColor(QPalette::Link, brightRed);
darkPalette.setColor(QPalette::Highlight, brightRed);
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
QPalette scarletDevilPalette;
scarletDevilPalette.setColor(QPalette::Window, darkRed);
scarletDevilPalette.setColor(QPalette::WindowText, Qt::white);
scarletDevilPalette.setColor(QPalette::Base, purplishRed);
scarletDevilPalette.setColor(QPalette::AlternateBase, darkRed);
scarletDevilPalette.setColor(QPalette::ToolTipBase, darkRed);
scarletDevilPalette.setColor(QPalette::ToolTipText, Qt::white);
scarletDevilPalette.setColor(QPalette::Text, Qt::white);
scarletDevilPalette.setColor(QPalette::Button, purplishRed.darker());
scarletDevilPalette.setColor(QPalette::ButtonText, Qt::white);
scarletDevilPalette.setColor(QPalette::Link, brightRed);
scarletDevilPalette.setColor(QPalette::Highlight, brightRed);
scarletDevilPalette.setColor(QPalette::HighlightedText, Qt::white);
darkPalette.setColor(QPalette::Active, QPalette::Button, purplishRed.darker());
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, brightRed);
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, brightRed);
darkPalette.setColor(QPalette::Disabled, QPalette::Text, brightRed);
darkPalette.setColor(QPalette::Disabled, QPalette::Light, darkRed);
scarletDevilPalette.setColor(QPalette::Active, QPalette::Button, purplishRed.darker());
scarletDevilPalette.setColor(QPalette::Disabled, QPalette::ButtonText, brightRed);
scarletDevilPalette.setColor(QPalette::Disabled, QPalette::WindowText, brightRed);
scarletDevilPalette.setColor(QPalette::Disabled, QPalette::Text, brightRed);
scarletDevilPalette.setColor(QPalette::Disabled, QPalette::Light, darkRed);
qApp->setPalette(darkPalette);
qApp->setPalette(scarletDevilPalette);
}
else if (theme == "VioletAngelPurple")
{
@@ -347,27 +348,27 @@ void QtHost::SetStyleFromSettings()
const QColor darkerPurple(90, 30, 105);
const QColor nauticalPurple(110, 30, 125);
QPalette darkPalette;
darkPalette.setColor(QPalette::Window, blackishblue);
darkPalette.setColor(QPalette::WindowText, Qt::white);
darkPalette.setColor(QPalette::Base, nauticalPurple);
darkPalette.setColor(QPalette::AlternateBase, blackishblue);
darkPalette.setColor(QPalette::ToolTipBase, nauticalPurple);
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
darkPalette.setColor(QPalette::Text, Qt::white);
darkPalette.setColor(QPalette::Button, nauticalPurple.darker());
darkPalette.setColor(QPalette::ButtonText, Qt::white);
darkPalette.setColor(QPalette::Link, darkerPurple.lighter());
darkPalette.setColor(QPalette::Highlight, darkerPurple.lighter());
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
QPalette violetAngelPalette;
violetAngelPalette.setColor(QPalette::Window, blackishblue);
violetAngelPalette.setColor(QPalette::WindowText, Qt::white);
violetAngelPalette.setColor(QPalette::Base, nauticalPurple);
violetAngelPalette.setColor(QPalette::AlternateBase, blackishblue);
violetAngelPalette.setColor(QPalette::ToolTipBase, nauticalPurple);
violetAngelPalette.setColor(QPalette::ToolTipText, Qt::white);
violetAngelPalette.setColor(QPalette::Text, Qt::white);
violetAngelPalette.setColor(QPalette::Button, nauticalPurple.darker());
violetAngelPalette.setColor(QPalette::ButtonText, Qt::white);
violetAngelPalette.setColor(QPalette::Link, darkerPurple.lighter());
violetAngelPalette.setColor(QPalette::Highlight, darkerPurple.lighter());
violetAngelPalette.setColor(QPalette::HighlightedText, Qt::white);
darkPalette.setColor(QPalette::Active, QPalette::Button, nauticalPurple.darker());
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, darkerPurple.lighter());
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, darkerPurple.lighter());
darkPalette.setColor(QPalette::Disabled, QPalette::Text, darkerPurple.darker());
darkPalette.setColor(QPalette::Disabled, QPalette::Light, nauticalPurple);
violetAngelPalette.setColor(QPalette::Active, QPalette::Button, nauticalPurple.darker());
violetAngelPalette.setColor(QPalette::Disabled, QPalette::ButtonText, darkerPurple.lighter());
violetAngelPalette.setColor(QPalette::Disabled, QPalette::WindowText, darkerPurple.lighter());
violetAngelPalette.setColor(QPalette::Disabled, QPalette::Text, darkerPurple.darker());
violetAngelPalette.setColor(QPalette::Disabled, QPalette::Light, nauticalPurple);
qApp->setPalette(darkPalette);
qApp->setPalette(violetAngelPalette);
}
else if (theme == "CobaltSky")
{
@@ -383,27 +384,27 @@ void QtHost::SetStyleFromSettings()
const QColor highlight(36, 93, 218);
const QColor link(0, 202, 255);
QPalette darkPalette;
darkPalette.setColor(QPalette::Window, royalBlue);
darkPalette.setColor(QPalette::WindowText, Qt::white);
darkPalette.setColor(QPalette::Base, royalBlue.lighter());
darkPalette.setColor(QPalette::AlternateBase, darkishBlue);
darkPalette.setColor(QPalette::ToolTipBase, darkishBlue);
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
darkPalette.setColor(QPalette::Text, Qt::white);
darkPalette.setColor(QPalette::Button, lighterBlue);
darkPalette.setColor(QPalette::ButtonText, Qt::white);
darkPalette.setColor(QPalette::Link, link);
darkPalette.setColor(QPalette::Highlight, highlight);
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
QPalette cobaltSkyPalette;
cobaltSkyPalette.setColor(QPalette::Window, royalBlue);
cobaltSkyPalette.setColor(QPalette::WindowText, Qt::white);
cobaltSkyPalette.setColor(QPalette::Base, royalBlue.lighter());
cobaltSkyPalette.setColor(QPalette::AlternateBase, darkishBlue);
cobaltSkyPalette.setColor(QPalette::ToolTipBase, darkishBlue);
cobaltSkyPalette.setColor(QPalette::ToolTipText, Qt::white);
cobaltSkyPalette.setColor(QPalette::Text, Qt::white);
cobaltSkyPalette.setColor(QPalette::Button, lighterBlue);
cobaltSkyPalette.setColor(QPalette::ButtonText, Qt::white);
cobaltSkyPalette.setColor(QPalette::Link, link);
cobaltSkyPalette.setColor(QPalette::Highlight, highlight);
cobaltSkyPalette.setColor(QPalette::HighlightedText, Qt::white);
darkPalette.setColor(QPalette::Active, QPalette::Button, lighterBlue);
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::Light, gray);
cobaltSkyPalette.setColor(QPalette::Active, QPalette::Button, lighterBlue);
cobaltSkyPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
cobaltSkyPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
cobaltSkyPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
cobaltSkyPalette.setColor(QPalette::Disabled, QPalette::Light, gray);
qApp->setPalette(darkPalette);
qApp->setPalette(cobaltSkyPalette);
}
else if (theme == "Ruby")
{
@@ -415,27 +416,27 @@ void QtHost::SetStyleFromSettings()
const QColor slate(18, 18, 18);
const QColor rubyish(172, 21, 31);
QPalette darkPalette;
darkPalette.setColor(QPalette::Window, slate);
darkPalette.setColor(QPalette::WindowText, Qt::white);
darkPalette.setColor(QPalette::Base, slate.lighter());
darkPalette.setColor(QPalette::AlternateBase, slate.lighter());
darkPalette.setColor(QPalette::ToolTipBase, slate);
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
darkPalette.setColor(QPalette::Text, Qt::white);
darkPalette.setColor(QPalette::Button, slate);
darkPalette.setColor(QPalette::ButtonText, Qt::white);
darkPalette.setColor(QPalette::Link, Qt::white);
darkPalette.setColor(QPalette::Highlight, rubyish);
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
QPalette rubyPalette;
rubyPalette.setColor(QPalette::Window, slate);
rubyPalette.setColor(QPalette::WindowText, Qt::white);
rubyPalette.setColor(QPalette::Base, slate.lighter());
rubyPalette.setColor(QPalette::AlternateBase, slate.lighter());
rubyPalette.setColor(QPalette::ToolTipBase, slate);
rubyPalette.setColor(QPalette::ToolTipText, Qt::white);
rubyPalette.setColor(QPalette::Text, Qt::white);
rubyPalette.setColor(QPalette::Button, slate);
rubyPalette.setColor(QPalette::ButtonText, Qt::white);
rubyPalette.setColor(QPalette::Link, Qt::white);
rubyPalette.setColor(QPalette::Highlight, rubyish);
rubyPalette.setColor(QPalette::HighlightedText, Qt::white);
darkPalette.setColor(QPalette::Active, QPalette::Button, slate);
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::Light, slate.lighter());
rubyPalette.setColor(QPalette::Active, QPalette::Button, slate);
rubyPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
rubyPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
rubyPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
rubyPalette.setColor(QPalette::Disabled, QPalette::Light, slate.lighter());
qApp->setPalette(darkPalette);
qApp->setPalette(rubyPalette);
}
else if (theme == "Sapphire")
{
@@ -447,27 +448,59 @@ void QtHost::SetStyleFromSettings()
const QColor slate(18, 18, 18);
const QColor persianBlue(32, 35, 204);
QPalette darkPalette;
darkPalette.setColor(QPalette::Window, slate);
darkPalette.setColor(QPalette::WindowText, Qt::white);
darkPalette.setColor(QPalette::Base, slate.lighter());
darkPalette.setColor(QPalette::AlternateBase, slate.lighter());
darkPalette.setColor(QPalette::ToolTipBase, slate);
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
darkPalette.setColor(QPalette::Text, Qt::white);
darkPalette.setColor(QPalette::Button, slate);
darkPalette.setColor(QPalette::ButtonText, Qt::white);
darkPalette.setColor(QPalette::Link, Qt::white);
darkPalette.setColor(QPalette::Highlight, persianBlue);
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
QPalette sapphirePalette;
sapphirePalette.setColor(QPalette::Window, slate);
sapphirePalette.setColor(QPalette::WindowText, Qt::white);
sapphirePalette.setColor(QPalette::Base, slate.lighter());
sapphirePalette.setColor(QPalette::AlternateBase, slate.lighter());
sapphirePalette.setColor(QPalette::ToolTipBase, slate);
sapphirePalette.setColor(QPalette::ToolTipText, Qt::white);
sapphirePalette.setColor(QPalette::Text, Qt::white);
sapphirePalette.setColor(QPalette::Button, slate);
sapphirePalette.setColor(QPalette::ButtonText, Qt::white);
sapphirePalette.setColor(QPalette::Link, Qt::white);
sapphirePalette.setColor(QPalette::Highlight, persianBlue);
sapphirePalette.setColor(QPalette::HighlightedText, Qt::white);
darkPalette.setColor(QPalette::Active, QPalette::Button, slate);
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::Light, slate.lighter());
sapphirePalette.setColor(QPalette::Active, QPalette::Button, slate);
sapphirePalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
sapphirePalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
sapphirePalette.setColor(QPalette::Disabled, QPalette::Text, gray);
sapphirePalette.setColor(QPalette::Disabled, QPalette::Light, slate.lighter());
qApp->setPalette(darkPalette);
qApp->setPalette(sapphirePalette);
}
else if (theme == "Emerald")
{
// Custom palette by RedDevilus, Black as main color and Blue as complimentary.
// Alternative dark (black) theme.
qApp->setStyle(QStyleFactory::create("Fusion"));
const QColor gray(128, 128, 128);
const QColor slate(18, 18, 18);
const QColor evergreenEmerald(15, 81, 59);
QPalette emeraldPalette;
emeraldPalette.setColor(QPalette::Window, slate);
emeraldPalette.setColor(QPalette::WindowText, Qt::white);
emeraldPalette.setColor(QPalette::Base, slate.lighter());
emeraldPalette.setColor(QPalette::AlternateBase, slate.lighter());
emeraldPalette.setColor(QPalette::ToolTipBase, slate);
emeraldPalette.setColor(QPalette::ToolTipText, Qt::white);
emeraldPalette.setColor(QPalette::Text, Qt::white);
emeraldPalette.setColor(QPalette::Button, slate);
emeraldPalette.setColor(QPalette::ButtonText, Qt::white);
emeraldPalette.setColor(QPalette::Link, Qt::white);
emeraldPalette.setColor(QPalette::Highlight, evergreenEmerald);
emeraldPalette.setColor(QPalette::HighlightedText, Qt::white);
emeraldPalette.setColor(QPalette::Active, QPalette::Button, slate);
emeraldPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
emeraldPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
emeraldPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
emeraldPalette.setColor(QPalette::Disabled, QPalette::Light, slate.lighter());
qApp->setPalette(emeraldPalette);
}
else if (theme == "Custom")
{

File diff suppressed because it is too large Load Diff

View File

@@ -621,6 +621,7 @@ struct Pcsx2Config
OsdShowSettings : 1,
OsdShowInputs : 1,
OsdShowFrameTimes : 1,
OsdShowVersion : 1,
HWSpinGPUForReadbacks : 1,
HWSpinCPUForReadbacks : 1,
GPUPaletteConversion : 1,
@@ -730,6 +731,7 @@ struct Pcsx2Config
std::string CaptureContainer = DEFAULT_CAPTURE_CONTAINER;
std::string VideoCaptureCodec;
std::string VideoCaptureFormat;
std::string VideoCaptureParameters;
std::string AudioCaptureCodec;
std::string AudioCaptureParameters;

View File

@@ -96,10 +96,10 @@ namespace PacketReader::IP
{
//If buffer & data point to the same location
//Then no copy is needed
if (data == buffer)
if (data == &buffer[*offset])
return;
memcpy(buffer, data, length);
memcpy(&buffer[*offset], data, length);
*offset += length;
}
virtual IP_Payload* Clone() const

View File

@@ -15,8 +15,11 @@
#endif
#include <algorithm>
#include <bit>
#include <thread>
#include <errno.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
@@ -35,36 +38,38 @@ using namespace PacketReader::IP::ICMP;
using namespace std::chrono_literals;
/* Ping is kindof annoying to do crossplatform
All platforms restrict raw sockets
Windows provides an api for ICMP
ICMP_ECHO_REPLY should always be used, ignore ICMP_ECHO_REPLY32
IP_OPTION_INFORMATION should always be used, ignore IP_OPTION_INFORMATION32
Linux
We have access to raw sockets via CAP_NET_RAW (for pcap)
However we may be missing that cap on some builds
Linux has socket(PF_INET, SOCK_DGRAM, IPPROTO_ICMP), used similar to raw sockets but for ICMP only
Auto filters responses
Requires net.ipv4.ping_group_range sysctl, default off on alot of distros
Timeouts reported via sock_extended_err control messages (with IP_RECVERR socket option set)
Mac
Raw sockets restricted
Mac has socket(PF_INET, SOCK_DGRAM, IPPROTO_ICMP)
No restriction to using it
Implementation differs, is more versatile than linux
Does not auto filter responses
Timeouts reported as a normal packet
FreeBSD
Raw sockets restricted
No unprivilaged ICMP sockets
Timeouts reported as a normal packet??
Ping cli
Present for all platforms, but command args differ
/*
* Ping is kindof annoying to do crossplatform
* All platforms restrict raw sockets
*
* Windows provides an api for ICMP
* ICMP_ECHO_REPLY should always be used, ignore ICMP_ECHO_REPLY32
* IP_OPTION_INFORMATION should always be used, ignore IP_OPTION_INFORMATION32
*
* Linux
* We have access to raw sockets via CAP_NET_RAW (for pcap)
* However we may be missing that cap on some builds
* Also hava socket(PF_INET, SOCK_DGRAM, IPPROTO_ICMP), used similarly to raw sockets, but for ICMP only
* Auto filters responses
* Requires net.ipv4.ping_group_range sysctl, default off on a lot of distros
* Timeouts reported via sock_extended_err control messages (with IP_RECVERR socket option set)
*
* Mac
* Raw sockets restricted
* Mac has socket(PF_INET, SOCK_DGRAM, IPPROTO_ICMP)
* No restriction to using it with ICMP_ECHO
* Implementation differs, is more versatile than linux
* Does not auto filter responses
* Timeouts reported as a normal packet
*
* FreeBSD
* Raw sockets restricted
* No unprivilaged ICMP sockets
* Timeouts reported as a normal packet??
*
* Ping cli
* Present for all platforms, but command args differ
* Not used here
*/
namespace Sessions
@@ -95,29 +100,36 @@ namespace Sessions
return;
}
//Allocate return buffer
//Documentation says + 8 to allow for an ICMP error message
//In testing, ICMP_ECHO_REPLY structure itself was returned with data set to null
/*
* Allocate response buffer
* Documentation says + 8 to allow for an ICMP error message
* In testing, ICMP_ECHO_REPLY structure itself was returned with data set to null
*/
icmpResponseBufferLen = sizeof(ICMP_ECHO_REPLY) + requestSize + 8;
icmpResponseBuffer = std::make_unique<u8[]>(icmpResponseBufferLen);
icmpResponseBuffer = std::make_unique<std::byte[]>(icmpResponseBufferLen);
#elif defined(__POSIX__)
{
/*
* Allocate response buffer
* Size needed depends on which socket protocol (ICMP or raw) we use aswell as os
*/
switch (icmpConnectionKind)
{
//Two different methods for raw/icmp sockets bettween the unix OSes
//Play it safe and only enable when we know which of the two methods we use
// Two different methods for raw/icmp sockets between the Unix OSes
// Play it safe and only enable when we know which of the two methods we use
#if defined(ICMP_SOCKETS_LINUX) || defined(ICMP_SOCKETS_BSD)
case (PingType::ICMP):
icmpSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
if (icmpSocket != -1)
{
#if defined(ICMP_SOCKETS_LINUX)
//Space for ICMP header, as MSG_ERRQUEUE returns what we sent
//An extra +8 required sometimes, for some reason?
// Only need space for ICMP header, as MSG_ERRQUEUE returns data we sent
// Testing found an extra + 8 was required sometimes, for some reason?
icmpResponseBufferLen = 8 + requestSize + 8;
#elif defined(ICMP_SOCKETS_BSD)
//Returned IP Header, ICMP Header & either data or failed ICMP packet
icmpResponseBufferLen = 20 + 8 + std::max(20 + 8, requestSize);
// Returned IP Header, ICMP Header & either data or failed ICMP packet
// Sometimes get full packet in ICMP error response
icmpResponseBufferLen = 20 + 8 + (20 + 8 + requestSize);
#endif
break;
}
@@ -132,16 +144,17 @@ namespace Sessions
if (icmpSocket != -1)
{
#if defined(ICMP_SOCKETS_LINUX)
//We get packet + header
// We get IP packet + ICMP header
icmpResponseBufferLen = 20 + 8 + requestSize;
#elif defined(ICMP_SOCKETS_BSD)
//As above, but we will also directly recive error ICMP messages
// As above, but we will also directly receive error ICMP messages
icmpResponseBufferLen = 20 + 8 + std::max(20 + 8, requestSize);
#endif
break;
}
DevCon.WriteLn("DEV9: ICMP: Failed To Open RAW Socket");
[[fallthrough]];
#endif
default:
@@ -149,11 +162,11 @@ namespace Sessions
return;
}
icmpResponseBuffer = std::make_unique<u8[]>(icmpResponseBufferLen);
icmpResponseBuffer = std::make_unique<std::byte[]>(icmpResponseBufferLen);
#endif
}
bool ICMP_Session::Ping::IsInitialised()
bool ICMP_Session::Ping::IsInitialised() const
{
#ifdef _WIN32
return icmpFile != INVALID_HANDLE_VALUE;
@@ -169,19 +182,29 @@ namespace Sessions
#endif
}
//Note, we can finish reading but have no data
// Returned PingResult.data is only valid when PingResult.type is 0
ICMP_Session::PingResult* ICMP_Session::Ping::Recv()
{
#ifdef _WIN32
if (WaitForSingleObject(icmpEvent, 0) == WAIT_OBJECT_0)
{
ResetEvent(icmpEvent);
//Prep buffer for reasing
[[maybe_unused]] int count = IcmpParseReplies(icmpResponseBuffer.get(), icmpResponseBufferLen);
pxAssert(count == 1);
ICMP_ECHO_REPLY* pingRet = (ICMP_ECHO_REPLY*)icmpResponseBuffer.get();
//Map status to ICMP type/code
const int count = IcmpParseReplies(icmpResponseBuffer.get(), icmpResponseBufferLen);
pxAssert(count <= 1);
// Timeout
if (count == 0)
{
result.type = -2;
result.code = 0;
return &result;
}
// Rely on implicit object creation
const ICMP_ECHO_REPLY* pingRet = reinterpret_cast<ICMP_ECHO_REPLY*>(icmpResponseBuffer.get());
// Map status to ICMP type/code
switch (pingRet->Status)
{
case (IP_SUCCESS):
@@ -208,21 +231,23 @@ namespace Sessions
result.type = 3;
result.code = 4;
break;
case (IP_BAD_ROUTE): //Bad source route
case (IP_BAD_ROUTE): // Bad source route
result.type = 3;
result.code = 5;
break;
case (IP_BAD_DESTINATION):
//I think this could be either
//Destination network unknown
//or
//Destination host unknown
//Use host unkown
/*
* I think this could be mapped to either
* Destination network unknown
* or
* Destination host unknown
* Lets map to host unknown
*/
result.type = 3;
result.code = 7;
break;
case (IP_REQ_TIMED_OUT):
//Return nothing
// Return nothing
result.type = -2;
result.code = 0;
break;
@@ -239,7 +264,7 @@ namespace Sessions
result.code = 0;
break;
//Unexpected Errors
// Unexpected errors
case (IP_BUF_TOO_SMALL):
case (IP_NO_RESOURCES):
case (IP_BAD_OPTION):
@@ -255,7 +280,7 @@ namespace Sessions
}
result.dataLength = pingRet->DataSize;
result.data = (u8*)pingRet->Data;
result.data = static_cast<u8*>(pingRet->Data);
result.address.integer = pingRet->Address;
return &result;
@@ -268,82 +293,30 @@ namespace Sessions
case (PingType::ICMP):
case (PingType::RAW):
{
int ret;
#if defined(ICMP_SOCKETS_BSD)
fd_set sReady;
fd_set sExcept;
timeval nowait{0};
FD_ZERO(&sReady);
FD_ZERO(&sExcept);
FD_SET(icmpSocket, &sReady);
FD_SET(icmpSocket, &sExcept);
ret = select(icmpSocket + 1, &sReady, nullptr, &sExcept, &nowait);
bool hasData;
if (ret == -1)
{
hasData = false;
Console.WriteLn("DEV9: ICMP: select failed. Error Code: %d", errno);
}
else if (FD_ISSET(icmpSocket, &sExcept))
{
hasData = false;
int error = 0;
socklen_t len = sizeof(error);
if (getsockopt(icmpSocket, SOL_SOCKET, SO_ERROR, (char*)&error, &len) < 0)
Console.Error("DEV9: ICMP: Unkown ICMP Connection Error (getsockopt Error: %d)", errno);
else
Console.Error("DEV9: ICMP: Recv Error: %d", error);
}
else
hasData = FD_ISSET(icmpSocket, &sReady);
if (hasData == false)
{
if (std::chrono::steady_clock::now() - icmpDeathClockStart > ICMP_TIMEOUT)
{
result.type = -2;
result.code = 0;
return &result;
}
else
return nullptr;
}
#endif
sockaddr endpoint{0};
sockaddr_in endpoint{};
iovec iov;
iov.iov_base = icmpResponseBuffer.get();
iov.iov_len = icmpResponseBufferLen;
#if defined(ICMP_SOCKETS_LINUX)
//Needs to hold cmsghdr + sock_extended_err + sockaddr_in
//for ICMP error responses (total 44 bytes)
//Unkown for other types of error
u8 cbuff[64];
// Needs to hold cmsghdr + sock_extended_err + sockaddr_in
// for ICMP error responses, this is a total of 44 bytes
// Unknown size needed for other error types
std::byte cbuff[64]{};
#endif
msghdr msg{0};
msghdr msg{};
msg.msg_name = &endpoint;
msg.msg_namelen = sizeof(endpoint);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
#if defined(ICMP_SOCKETS_LINUX)
ret = recvmsg(icmpSocket, &msg, MSG_DONTWAIT);
#elif defined(ICMP_SOCKETS_BSD)
ret = recvmsg(icmpSocket, &msg, 0);
#endif
int ret = recvmsg(icmpSocket, &msg, 0);
if (ret == -1)
{
int err = errno;
#if defined(ICMP_SOCKETS_LINUX)
if (err == EAGAIN || err == EWOULDBLOCK)
{
if (std::chrono::steady_clock::now() - icmpDeathClockStart > ICMP_TIMEOUT)
@@ -355,14 +328,16 @@ namespace Sessions
else
return nullptr;
}
#if defined(ICMP_SOCKETS_LINUX)
else
{
msg.msg_control = &cbuff;
msg.msg_controllen = sizeof(cbuff);
ret = recvmsg(icmpSocket, &msg, MSG_ERRQUEUE | MSG_DONTWAIT);
ret = recvmsg(icmpSocket, &msg, MSG_ERRQUEUE);
}
#endif
if (ret == -1)
#endif
{
Console.Error("DEV9: ICMP: RecvMsg Error: %d", err);
result.type = -1;
@@ -373,40 +348,59 @@ namespace Sessions
if (msg.msg_flags & MSG_TRUNC)
Console.Error("DEV9: ICMP: RecvMsg Truncated");
#if defined(ICMP_SOCKETS_LINUX)
if (msg.msg_flags & MSG_CTRUNC)
Console.Error("DEV9: ICMP: RecvMsg Control Truncated");
sock_extended_err* ex_err = nullptr;
// On Linux, ICMP errors are stored in control messages retrieved using MSG_ERRQUEUE
sock_extended_err* exErrorPtr = nullptr;
cmsghdr* cmsg;
/* Receive auxiliary data in msgh */
// Search though control messages, taking the latest mesage
// We should only have at most 1 message
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg))
{
if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR)
{
ex_err = (sock_extended_err*)CMSG_DATA(cmsg);
pxAssert(!exErrorPtr);
exErrorPtr = reinterpret_cast<sock_extended_err*>(CMSG_DATA(cmsg));
continue;
}
pxAssert(false);
}
if (ex_err != nullptr)
if (exErrorPtr != nullptr)
{
if (ex_err->ee_origin == SO_EE_ORIGIN_ICMP)
{
result.type = ex_err->ee_type;
result.code = ex_err->ee_code;
/*
* The pointer returned cannot be assumed to be suitably aligned for accessing arbitrary payload data types
* So we would need to memcpy sock_extended_err
*/
sock_extended_err exError;
std::memcpy(&exError, exErrorPtr, sizeof(exError));
sockaddr_in* sockaddr = (sockaddr_in*)SO_EE_OFFENDER(ex_err);
result.address = *(IP_Address*)&sockaddr->sin_addr;
// Process the error
if (exError.ee_origin == SO_EE_ORIGIN_ICMP)
{
result.type = exError.ee_type;
result.code = exError.ee_code;
/*
* SO_EE_OFFENDER reads data relative to, but not necessarily included in struct sock_extended_err
* So we need to pass the original pointer provided to us from CMSG_DATA()
* However, the input pointer needs to be of type sock_extended_err*, hence the reinterpret_cast
* The pointer returned may not be suitably aligned (see CMSG_DATA), so we need to memcpy
*/
sockaddr_in errorEndpoint;
std::memcpy(&errorEndpoint, SO_EE_OFFENDER(exErrorPtr), sizeof(errorEndpoint));
result.address = std::bit_cast<IP_Address>(errorEndpoint.sin_addr);
return &result;
}
else
{
Console.Error("DEV9: ICMP: Recv Error %d", ex_err->ee_errno);
Console.Error("DEV9: ICMP: Recv error %d", exError.ee_errno);
result.type = -1;
result.code = ex_err->ee_errno;
result.code = exError.ee_errno;
return &result;
}
}
@@ -424,60 +418,66 @@ namespace Sessions
else
#endif
{
ip* ipHeader = (ip*)icmpResponseBuffer.get();
int headerLength = ipHeader->ip_hl << 2;
// Rely on implicit object creation
const ip* ipHeader = reinterpret_cast<ip*>(icmpResponseBuffer.get());
const int headerLength = ipHeader->ip_hl << 2;
pxAssert(headerLength == 20);
offset = headerLength;
#ifdef __APPLE__
//Apple (old BSD)'s raw IP sockets implementation converts the ip_len field to host byte order
//and additionally subtracts the header length.
//https://www.unix.com/man-page/mojave/4/ip/
// Apple (old BSD)'s raw IP sockets implementation converts the ip_len field to host byte order
// and additionally subtracts the header length.
// https://www.unix.com/man-page/mojave/4/ip/
length = ipHeader->ip_len;
#else
length = ntohs(ipHeader->ip_len) - headerLength;
#endif
}
ICMP_Packet icmp(&icmpResponseBuffer[offset], length);
// Rely on implicit object creation for u8
ICMP_Packet icmp(reinterpret_cast<u8*>(&icmpResponseBuffer[offset]), length);
PayloadPtr* icmpPayload = static_cast<PayloadPtr*>(icmp.GetPayload());
result.type = icmp.type;
result.code = icmp.code;
sockaddr_in* sockaddr = (sockaddr_in*)&endpoint;
result.address = *(IP_Address*)&sockaddr->sin_addr;
result.address = std::bit_cast<IP_Address>(endpoint.sin_addr);
if (icmp.type == 0)
{
//Check if response is to us
// Check if response is for us
if (icmpConnectionKind == PingType::RAW)
{
ICMP_HeaderDataIdentifier headerData(icmp.headerData);
const ICMP_HeaderDataIdentifier headerData(icmp.headerData);
if (headerData.identifier != icmpId)
return nullptr;
}
//While icmp (and its PayloadPtr) will be destroyed when leaving this function
//the data pointed to it persist in icmpResponseBuffer
// While icmp (and its PayloadPtr) will be destroyed when leaving this function
// the data it points to persists in icmpResponseBuffer
result.dataLength = icmpPayload->GetLength();
result.data = icmpPayload->data;
return &result;
}
#if defined(ICMP_SOCKETS_BSD)
// On BSD/Mac, ICMP errors are returned as normal packets
else if (icmp.type == 3 || icmp.type == 4 || icmp.type == 5 || icmp.type == 11)
{
//Check if response is to us
//We need to extract the sent header
// Extract the packet the ICMP message is responding to
IP_Packet ipPacket(icmpPayload->data, icmpPayload->GetLength(), true);
IP_PayloadPtr* ipPayload = static_cast<IP_PayloadPtr*>(ipPacket.GetPayload());
ICMP_Packet retIcmp(ipPayload->data, ipPayload->GetLength());
ICMP_HeaderDataIdentifier headerData(icmp.headerData);
if (ipPacket.protocol != static_cast<u8>(IP_Type::ICMP))
return nullptr;
IP_PayloadPtr* ipPayload = static_cast<IP_PayloadPtr*>(ipPacket.GetPayload());
ICMP_Packet icmpInner(ipPayload->data, ipPayload->GetLength());
// Check if response is for us
const ICMP_HeaderDataIdentifier headerData(icmpInner.headerData);
if (headerData.identifier != icmpId)
return nullptr;
//This response is for us
// This response is for us
return &result;
}
#endif
@@ -487,7 +487,7 @@ namespace Sessions
Console.Error("DEV9: ICMP: Unexpected packet");
pxAssert(false);
#endif
//Assume not for us
// Assume not for us
return nullptr;
}
}
@@ -503,25 +503,25 @@ namespace Sessions
bool ICMP_Session::Ping::Send(IP_Address parAdapterIP, IP_Address parDestIP, int parTimeToLive, PayloadPtr* parPayload)
{
#ifdef _WIN32
//Documentation is incorrect, IP_OPTION_INFORMATION is to be used regardless of platform
IP_OPTION_INFORMATION ipInfo{0};
// Documentation is incorrect, IP_OPTION_INFORMATION is to be used regardless of platform
IP_OPTION_INFORMATION ipInfo{};
ipInfo.Ttl = parTimeToLive;
DWORD ret;
if (parAdapterIP.integer != 0)
ret = IcmpSendEcho2Ex(icmpFile, icmpEvent, nullptr, nullptr, parAdapterIP.integer, parDestIP.integer, parPayload->data, parPayload->GetLength(), &ipInfo, icmpResponseBuffer.get(), icmpResponseBufferLen,
(DWORD)std::chrono::duration_cast<std::chrono::milliseconds>(ICMP_TIMEOUT).count());
static_cast<DWORD>(std::chrono::duration_cast<std::chrono::milliseconds>(ICMP_TIMEOUT).count()));
else
ret = IcmpSendEcho2(icmpFile, icmpEvent, nullptr, nullptr, parDestIP.integer, parPayload->data, parPayload->GetLength(), &ipInfo, icmpResponseBuffer.get(), icmpResponseBufferLen,
(DWORD)std::chrono::duration_cast<std::chrono::milliseconds>(ICMP_TIMEOUT).count());
static_cast<DWORD>(std::chrono::duration_cast<std::chrono::milliseconds>(ICMP_TIMEOUT).count()));
//Documentation states that IcmpSendEcho2 returns ERROR_IO_PENDING
//However, it actully returns zero, with the error set to ERROR_IO_PENDING
// Documentation states that IcmpSendEcho2 returns ERROR_IO_PENDING
// However, it actually returns zero, with the error set to ERROR_IO_PENDING
if (ret == 0)
ret = GetLastError();
if (ret != ERROR_IO_PENDING)
{
Console.Error("DEV9: ICMP: Failed to Send Echo, %d", GetLastError());
Console.Error("DEV9: ICMP: Failed to send echo, %d", GetLastError());
return false;
}
@@ -534,16 +534,16 @@ namespace Sessions
{
icmpDeathClockStart = std::chrono::steady_clock::now();
//broadcast and multicast mignt need extra setsockopts
//I don't think any game will broadcast/multicast ping
// Broadcast and multicast might need extra setsockopts calls
// I don't think any game will do a broadcast/multicast ping
if (parAdapterIP.integer != 0)
{
sockaddr_in endpoint{0};
sockaddr_in endpoint{};
endpoint.sin_family = AF_INET;
*(IP_Address*)&endpoint.sin_addr = parAdapterIP;
endpoint.sin_addr = std::bit_cast<in_addr>(parAdapterIP);
if (bind(icmpSocket, (const sockaddr*)&endpoint, sizeof(endpoint)) == -1)
if (bind(icmpSocket, reinterpret_cast<const sockaddr*>(&endpoint), sizeof(endpoint)) == -1)
{
Console.Error("DEV9: ICMP: Failed to bind socket. Error: %d", errno);
::close(icmpSocket);
@@ -553,8 +553,8 @@ namespace Sessions
}
#if defined(ICMP_SOCKETS_LINUX)
int value = 1;
if (setsockopt(icmpSocket, SOL_IP, IP_RECVERR, (char*)&value, sizeof(value)))
const int value = 1;
if (setsockopt(icmpSocket, SOL_IP, IP_RECVERR, reinterpret_cast<const char*>(&value), sizeof(value)))
{
Console.Error("DEV9: ICMP: Failed to setsockopt IP_RECVERR. Error: %d", errno);
::close(icmpSocket);
@@ -563,8 +563,8 @@ namespace Sessions
}
#endif
// TTL (Note multicast & regular ttl are seperate)
if (setsockopt(icmpSocket, IPPROTO_IP, IP_TTL, (const char*)&parTimeToLive, sizeof(parTimeToLive)) == -1)
// TTL (Note multicast & regular ttl are separate)
if (setsockopt(icmpSocket, IPPROTO_IP, IP_TTL, reinterpret_cast<const char*>(&parTimeToLive), sizeof(parTimeToLive)) == -1)
{
Console.Error("DEV9: ICMP: Failed to set TTL. Error: %d", errno);
::close(icmpSocket);
@@ -572,13 +572,23 @@ namespace Sessions
return false;
}
// Non-blocking
int blocking = 1;
if (ioctl(icmpSocket, FIONBIO, &blocking) == -1)
{
Console.Error("DEV9: ICMP: Failed to set non-blocking. Error: %d", errno);
::close(icmpSocket);
icmpSocket = -1;
return false;
}
#if defined(ICMP_SOCKETS_LINUX)
if (icmpConnectionKind == PingType::ICMP)
{
//We get assigned a port
sockaddr_in endpoint{0};
// We get assigned a port/Id
sockaddr_in endpoint{};
socklen_t endpointsize = sizeof(endpoint);
if (getsockname(icmpSocket, (sockaddr*)&endpoint, &endpointsize) == -1)
if (getsockname(icmpSocket, reinterpret_cast<sockaddr*>(&endpoint), &endpointsize) == -1)
{
Console.Error("DEV9: ICMP: Failed to get id. Error: %d", errno);
::close(icmpSocket);
@@ -591,15 +601,15 @@ namespace Sessions
else
#endif
{
//Use time, in ms, as id
icmpId = (u16)std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
// Use time, in ms, as id
icmpId = static_cast<u16>(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count());
}
ICMP_Packet icmp(parPayload->Clone());
icmp.type = 8;
icmp.code = 0;
//We only send one icmp packet per identifier
// We only send one icmp packet per identifier
ICMP_HeaderDataIdentifier headerData(icmpId, 1);
headerData.WriteHeaderData(icmp.headerData);
@@ -609,17 +619,27 @@ namespace Sessions
int offset = 0;
icmp.WriteBytes(buffer.get(), &offset);
sockaddr_in endpoint{0};
sockaddr_in endpoint{};
endpoint.sin_family = AF_INET;
*(IP_Address*)&endpoint.sin_addr.s_addr = parDestIP;
endpoint.sin_addr = std::bit_cast<in_addr>(parDestIP);
const int ret = sendto(icmpSocket, buffer.get(), icmp.GetLength(), 0, (const sockaddr*)&endpoint, sizeof(endpoint));
if (ret == -1)
int ret = -1;
while (ret == -1)
{
Console.Error("DEV9: ICMP: Send Error %d", errno);
::close(icmpSocket);
icmpSocket = -1;
return false;
ret = sendto(icmpSocket, buffer.get(), icmp.GetLength(), 0, reinterpret_cast<const sockaddr*>(&endpoint), sizeof(endpoint));
if (ret == -1)
{
const int err = errno;
if (err == EAGAIN || err == EWOULDBLOCK)
std::this_thread::yield();
else
{
Console.Error("DEV9: ICMP: Send error %d", errno);
::close(icmpSocket);
icmpSocket = -1;
return false;
}
}
}
return true;
@@ -665,16 +685,15 @@ namespace Sessions
for (size_t i = 0; i < pings.size(); i++)
{
ICMP_Session::PingResult* pingRet = nullptr;
pingRet = pings[i]->Recv();
const ICMP_Session::PingResult* pingRet = pings[i]->Recv();
if (pingRet != nullptr)
{
Ping* ping = pings[i];
//Remove ping from list and unlock
std::unique_ptr<Ping> ping = std::move(pings[i]);
// Remove ping from list and unlock mutex
pings.erase(pings.begin() + i);
lock.unlock();
//Create return ICMP packet
// Create return ICMP packet
std::optional<ReceivedPayload> ret;
if (pingRet->type >= 0)
{
@@ -686,22 +705,19 @@ namespace Sessions
}
else
{
//We will copy the original packet back here
//Allocate fullsize buffer
u8* temp = new u8[ping->originalPacket->GetLength()];
//Allocate data
int responseSize = ping->originalPacket->GetHeaderLength() + 8;
// Copy the original packet into the returned ICMP packet
// Allocate fullsize buffer
std::vector<u8> temp = std::vector<u8>(ping->originalPacket->GetLength());
// Allocate returned ICMP payload
const int responseSize = ping->originalPacket->GetHeaderLength() + 8;
data = new PayloadData(responseSize);
//Write packet back into bytes
// Write packet into buffer
int offset = 0;
ping->originalPacket->WriteBytes(temp, &offset);
ping->originalPacket->WriteBytes(temp.data(), &offset);
//Copy only needed bytes
memcpy(data->data.get(), temp, responseSize);
//cleanup
delete[] temp;
// Copy only needed bytes
memcpy(data->data.get(), temp.data(), responseSize);
}
std::unique_ptr<ICMP_Packet> pRet = std::make_unique<ICMP_Packet>(data);
@@ -716,16 +732,13 @@ namespace Sessions
else
DevCon.WriteLn("DEV9: ICMP: ICMP timeout");
//free ping
delete ping;
if (ret.has_value())
DevCon.WriteLn("DEV9: ICMP: Return Ping");
if (--open == 0)
RaiseEventConnectionClosed();
if (ret.has_value())
DevCon.WriteLn("DEV9: ICMP: Return Ping");
//Return packet
// Return packet
return ret;
}
}
@@ -741,7 +754,7 @@ namespace Sessions
return false;
}
//Note, expects caller to set ipTimeToLive before calling
// Expects caller to set ipTimeToLive before calling
bool ICMP_Session::Send(PacketReader::IP::IP_Payload* payload, IP_Packet* packet)
{
IP_PayloadPtr* ipPayload = static_cast<IP_PayloadPtr*>(payload);
@@ -751,16 +764,19 @@ namespace Sessions
switch (icmp.type)
{
case 3: //Port Closed
case 3: // Port Closed
switch (icmp.code)
{
case 3:
{
Console.Error("DEV9: ICMP: Recived Packet Rejected, Port Closed");
//RE:Outbreak Hackfix
//TODO, check if still needed
Console.Error("DEV9: ICMP: Received Packet Rejected, Port Closed");
/*
* RE:Outbreak Hackfix
* ICMP port closed messages has an extra 4 bytes of padding before the packet copy
* this can be tested by trying to connect without using the resurrection server DNS
* turbo mode may be needed to trigger the bug, depending on the DNS server's latency
*/
std::unique_ptr<IP_Packet> retPkt;
if ((icmpPayload->data[0] & 0xF0) == (4 << 4))
retPkt = std::make_unique<IP_Packet>(icmpPayload->data, icmpPayload->GetLength(), true);
@@ -776,20 +792,20 @@ namespace Sessions
retPkt = std::make_unique<IP_Packet>(&icmpPayload->data[off], icmpPayload->GetLength(), true);
}
IP_Address srvIP = retPkt->sourceIP;
u8 prot = retPkt->protocol;
const IP_Address srvIP = retPkt->sourceIP;
const u8 prot = retPkt->protocol;
u16 srvPort = 0;
u16 ps2Port = 0;
switch (prot)
{
case (u8)IP_Type::TCP:
case (u8)IP_Type::UDP:
//Read ports directly from the payload
//both UDP and TCP have the same locations for ports
case static_cast<u8>(IP_Type::TCP):
case static_cast<u8>(IP_Type::UDP):
// Read ports directly from the payload
// both UDP and TCP have the same locations for ports
IP_PayloadPtr* payload = static_cast<IP_PayloadPtr*>(retPkt->GetPayload());
int offset = 0;
NetLib::ReadUInt16(payload->data, &offset, &srvPort); //src
NetLib::ReadUInt16(payload->data, &offset, &ps2Port); //dst
NetLib::ReadUInt16(payload->data, &offset, &srvPort); // src
NetLib::ReadUInt16(payload->data, &offset, &ps2Port); // dst
}
ConnectionKey Key{};
@@ -798,7 +814,7 @@ namespace Sessions
Key.ps2Port = ps2Port;
Key.srvPort = srvPort;
//is from Normal Port?
// Is from Normal Port?
BaseSession* s = nullptr;
connections->TryGetValue(Key, &s);
@@ -809,7 +825,7 @@ namespace Sessions
break;
}
//Is from Fixed Port?
// Is from Fixed Port?
Key.ip = {};
Key.srvPort = 0;
connections->TryGetValue(Key, &s);
@@ -827,18 +843,17 @@ namespace Sessions
Console.Error("DEV9: ICMP: Unsupported ICMP Code For Destination Unreachable %d", icmp.code);
}
break;
case 8: //Echo
case 8: // Echo
{
DevCon.WriteLn("DEV9: ICMP: Send Ping");
open++;
Ping* ping = new Ping(icmpPayload->GetLength());
std::unique_ptr<Ping> ping = std::make_unique<Ping>(icmpPayload->GetLength());
if (!ping->IsInitialised())
{
if (--open == 0)
RaiseEventConnectionClosed();
delete ping;
return false;
}
@@ -846,18 +861,17 @@ namespace Sessions
{
if (--open == 0)
RaiseEventConnectionClosed();
delete ping;
return false;
}
memcpy(ping->headerData, icmp.headerData, 4);
//Need to copy IP_Packet, original is stack allocated
// Need to copy IP_Packet, original is stack allocated
ping->originalPacket = std::make_unique<IP_Packet>(*packet);
{
std::scoped_lock lock(ping_mutex);
pings.push_back(ping);
pings.push_back(std::move(ping));
}
break;
@@ -876,10 +890,8 @@ namespace Sessions
ICMP_Session::~ICMP_Session()
{
// Cleanup
std::scoped_lock lock(ping_mutex);
//Cleanup
for (size_t i = 0; i < pings.size(); i++)
delete pings[i];
pings.clear();
}
} // namespace Sessions

View File

@@ -47,30 +47,29 @@ namespace Sessions
static PingType icmpConnectionKind;
//Sockets
// Sockets
int icmpSocket{-1};
std::chrono::steady_clock::time_point icmpDeathClockStart;
u16 icmpId;
#endif
//Return buffers
// Return buffers
PingResult result{};
int icmpResponseBufferLen{0};
std::unique_ptr<u8[]> icmpResponseBuffer;
std::unique_ptr<std::byte[]> icmpResponseBuffer;
public:
Ping(int requestSize);
bool IsInitialised();
bool IsInitialised() const;
PingResult* Recv();
bool Send(PacketReader::IP::IP_Address parAdapterIP, PacketReader::IP::IP_Address parDestIP, int parTimeToLive, PacketReader::PayloadPtr* parPayload);
~Ping();
};
SimpleQueue<PacketReader::IP::ICMP::ICMP_Packet*> _recvBuff;
std::mutex ping_mutex;
std::vector<Ping*> pings;
std::vector<std::unique_ptr<Ping>> pings;
ThreadSafeMap<Sessions::ConnectionKey, Sessions::BaseSession*>* connections;
std::atomic<int> open{0};

View File

@@ -1054,6 +1054,7 @@ static void HotkeyToggleOSD()
GSConfig.OsdShowSettings ^= EmuConfig.GS.OsdShowSettings;
GSConfig.OsdShowInputs ^= EmuConfig.GS.OsdShowInputs;
GSConfig.OsdShowFrameTimes ^= EmuConfig.GS.OsdShowFrameTimes;
GSConfig.OsdShowVersion ^= EmuConfig.GS.OsdShowVersion;
}
BEGIN_HOTKEY_LIST(g_gs_hotkeys){"Screenshot", TRANSLATE_NOOP("Hotkeys", "Graphics"),

View File

@@ -42,6 +42,8 @@ extern "C" {
#include "libavutil/dict.h"
#include "libavutil/opt.h"
#include "libavutil/version.h"
#include "libavutil/channel_layout.h"
#include "libavutil/pixdesc.h"
#include "libswscale/swscale.h"
#include "libswscale/version.h"
#include "libswresample/swresample.h"
@@ -88,7 +90,8 @@ extern "C" {
#else
#define AVUTIL_57_IMPORTS(X) \
X(av_channel_layout_default) \
X(av_channel_layout_copy)
X(av_channel_layout_copy) \
X(av_opt_set_chlayout)
#endif
#define VISIT_AVUTIL_IMPORTS(X) \
@@ -115,7 +118,8 @@ extern "C" {
X(av_hwframe_transfer_data) \
X(av_hwframe_get_buffer) \
X(av_buffer_ref) \
X(av_buffer_unref)
X(av_buffer_unref) \
X(av_get_pix_fmt_name)
#define VISIT_SWSCALE_IMPORTS(X) \
X(sws_getCachedContext) \
@@ -445,23 +449,30 @@ bool GSCapture::BeginCapture(float fps, GSVector2i recommendedResolution, float
wrap_av_reduce(&s_video_codec_context->time_base.num, &s_video_codec_context->time_base.den, 10000,
static_cast<s64>(static_cast<double>(fps) * 10000.0), std::numeric_limits<s32>::max());
// Default to YUV 4:2:0 if the codec doesn't specify a pixel format.
AVPixelFormat sw_pix_fmt = AV_PIX_FMT_YUV420P;
// Default to NV12 if not overridden by the user
const AVPixelFormat preferred_sw_pix_fmt = GSConfig.VideoCaptureFormat.empty() ? AV_PIX_FMT_NV12 : static_cast<AVPixelFormat>(std::stoi(GSConfig.VideoCaptureFormat));
AVPixelFormat sw_pix_fmt = preferred_sw_pix_fmt;
if (vcodec->pix_fmts)
{
// Prefer YUV420 given the choice, but otherwise fall back to whatever it supports.
sw_pix_fmt = vcodec->pix_fmts[0];
for (u32 i = 0; vcodec->pix_fmts[i] != AV_PIX_FMT_NONE; i++)
{
if (vcodec->pix_fmts[i] == AV_PIX_FMT_YUV420P)
if (vcodec->pix_fmts[i] == preferred_sw_pix_fmt)
{
sw_pix_fmt = vcodec->pix_fmts[i];
break;
}
}
}
if (sw_pix_fmt == AV_PIX_FMT_VAAPI)
sw_pix_fmt = AV_PIX_FMT_NV12;
s_video_codec_context->pix_fmt = sw_pix_fmt;
if (preferred_sw_pix_fmt != sw_pix_fmt)
Console.Warning("GSCapture: preferred pixel format (%d) was unsupported by the codec. Using (%d) instead.", preferred_sw_pix_fmt, sw_pix_fmt);
// Can we use hardware encoding?
const AVCodecHWConfig* hwconfig = wrap_avcodec_get_hw_config(vcodec, 0);
if (hwconfig && hwconfig->pix_fmt != AV_PIX_FMT_NONE && hwconfig->pix_fmt != sw_pix_fmt)
@@ -688,9 +699,16 @@ bool GSCapture::BeginCapture(float fps, GSVector2i recommendedResolution, float
return false;
}
#if LIBAVUTIL_VERSION_MAJOR >= 57
const AVChannelLayout layout = AV_CHANNEL_LAYOUT_STEREO;
wrap_av_opt_set_chlayout(s_swr_context, "in_chlayout", &layout, 0);
wrap_av_opt_set_chlayout(s_swr_context, "out_chlayout", &layout, 0);
#endif
wrap_av_opt_set_int(s_swr_context, "in_channel_count", AUDIO_CHANNELS, 0);
wrap_av_opt_set_int(s_swr_context, "in_sample_rate", sample_rate, 0);
wrap_av_opt_set_sample_fmt(s_swr_context, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);
wrap_av_opt_set_int(s_swr_context, "out_channel_count", AUDIO_CHANNELS, 0);
wrap_av_opt_set_int(s_swr_context, "out_sample_rate", sample_rate, 0);
wrap_av_opt_set_sample_fmt(s_swr_context, "out_sample_fmt", s_audio_codec_context->sample_fmt, 0);
@@ -1491,3 +1509,33 @@ GSCapture::CodecList GSCapture::GetAudioCodecList(const char* container)
{
return GetCodecListForContainer(container, AVMEDIA_TYPE_AUDIO);
}
GSCapture::FormatList GSCapture::GetVideoFormatList(const char* codec)
{
FormatList ret;
if (!LoadFFmpeg(false))
return ret;
const AVCodec* v_codec = wrap_avcodec_find_encoder_by_name(codec);
if (!v_codec)
{
Console.Error("(GetVideoFormatList) avcodec_find_encoder_by_name() failed");
return ret;
}
// rawvideo doesn't have a list of formats.
if(v_codec->pix_fmts == nullptr)
{
Console.Error("(GetVideoFormatList) v_codec->pix_fmts is null.");
return ret;
}
for (int i = 0; v_codec->pix_fmts[i] != AVPixelFormat::AV_PIX_FMT_NONE; i++)
{
ret.emplace_back(v_codec->pix_fmts[i], wrap_av_get_pix_fmt_name(v_codec->pix_fmts[i]));
}
return ret;
}

View File

@@ -37,4 +37,8 @@ namespace GSCapture
using CodecList = std::vector<CodecName>;
CodecList GetVideoCodecList(const char* container);
CodecList GetAudioCodecList(const char* container);
using FormatName = std::pair<int , std::string>; // id,name
using FormatList = std::vector<FormatName>;
FormatList GetVideoFormatList(const char* codec);
}; // namespace GSCapture

View File

@@ -4668,7 +4668,6 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
blend.op = GSDevice::OP_ADD;
// Render pass 2: Add or subtract result of render pass 1(Cd) from Cs.
m_conf.blend_second_pass.enable = true;
m_conf.blend_second_pass.blend_hw = 0;
m_conf.blend_second_pass.dither = dither * GSConfig.Dithering;
m_conf.blend_second_pass.blend = {true, blend_second_pass.src, GSDevice::CONST_ONE, blend_second_pass.op, GSDevice::CONST_ONE, GSDevice::CONST_ZERO, false, 0};
}
@@ -4743,8 +4742,12 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
m_conf.ps.blend_hw = static_cast<u8>(HWBlendType::SRC_DOUBLE);
}
if (m_conf.ps.blend_c == 2 && (m_conf.ps.blend_hw == 2 || m_conf.ps.blend_hw == 4 || m_conf.blend_second_pass.blend_hw == 2))
if (m_conf.ps.blend_c == 2 && (m_conf.ps.blend_hw == static_cast<u8>(HWBlendType::SRC_ALPHA_DST_FACTOR)
|| m_conf.ps.blend_hw == static_cast<u8>(HWBlendType::SRC_HALF_ONE_DST_FACTOR)
|| m_conf.blend_second_pass.blend_hw == static_cast<u8>(HWBlendType::SRC_ALPHA_DST_FACTOR)))
{
m_conf.cb_ps.TA_MaxDepth_Af.a = static_cast<float>(AFIX) / 128.0f;
}
const GSDevice::BlendFactor src_factor_alpha = m_conf.blend_second_pass.enable ? GSDevice::CONST_ZERO : GSDevice::CONST_ONE;
const GSDevice::BlendFactor dst_factor_alpha = m_conf.blend_second_pass.enable ? GSDevice::CONST_ONE : GSDevice::CONST_ZERO;

View File

@@ -640,7 +640,7 @@ bool GameDatabaseSchema::GameEntry::configMatchesHWFix(const Pcsx2Config::GSOpti
return (config.UpscaleMultiplier <= 1.0f || config.UserHacks_RoundSprite == value);
case GSHWFixId::NativeScaling:
return (static_cast<int>(config.UserHacks_NativeScaling) == value);
return (config.UpscaleMultiplier <= 1.0f || static_cast<int>(config.UserHacks_NativeScaling) == value);
case GSHWFixId::TexturePreloading:
return (static_cast<int>(config.TexturePreloading) <= value);

View File

@@ -3123,6 +3123,9 @@ void FullscreenUI::DrawInterfaceSettingsPage()
FSUI_CSTR(
"Shows on-screen-display messages when events occur such as save states being created/loaded, screenshots being taken, etc."),
"EmuCore/GS", "OsdShowMessages", true);
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_INFO, "Show PCSX2 Version"),
FSUI_CSTR("Shows the current PCSX2 version on the top-right corner of the display."), "EmuCore/GS",
"OsdShowVersion", false);
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_TACHOMETER_ALT, "Show Speed"),
FSUI_CSTR("Shows the current emulation speed of the system in the top-right corner of the display as a percentage."), "EmuCore/GS",
"OsdShowSpeed", false);
@@ -3287,11 +3290,11 @@ void FullscreenUI::DrawEmulationSettingsPage()
MenuHeading(FSUI_CSTR("Speed Control"));
DrawFloatListSetting(bsi, FSUI_ICONSTR(ICON_FA_PLAY,"Normal Speed"), FSUI_CSTR("Sets the speed when running without fast forwarding."), "Framerate",
DrawFloatListSetting(bsi, FSUI_ICONSTR(ICON_FA_PLAY, "Normal Speed"), FSUI_CSTR("Sets the speed when running without fast forwarding."), "Framerate",
"NominalScalar", 1.00f, speed_entries, speed_values, std::size(speed_entries), true);
DrawFloatListSetting(bsi, FSUI_ICONSTR(ICON_FA_FAST_FORWARD,"Fast Forward Speed"), FSUI_CSTR("Sets the speed when using the fast forward hotkey."), "Framerate",
DrawFloatListSetting(bsi, FSUI_ICONSTR(ICON_FA_FAST_FORWARD, "Fast Forward Speed"), FSUI_CSTR("Sets the speed when using the fast forward hotkey."), "Framerate",
"TurboScalar", 2.00f, speed_entries, speed_values, std::size(speed_entries), true);
DrawFloatListSetting(bsi, FSUI_ICONSTR(ICON_PF_SLOW_MOTION,"Slow Motion Speed"), FSUI_CSTR("Sets the speed when using the slow motion hotkey."), "Framerate",
DrawFloatListSetting(bsi, FSUI_ICONSTR(ICON_PF_SLOW_MOTION, "Slow Motion Speed"), FSUI_CSTR("Sets the speed when using the slow motion hotkey."), "Framerate",
"SlomoScalar", 0.50f, speed_entries, speed_values, std::size(speed_entries), true);
MenuHeading(FSUI_CSTR("System Settings"));
@@ -3597,7 +3600,7 @@ void FullscreenUI::DrawGraphicsSettingsPage(SettingsInterface* bsi, bool show_ad
BeginMenuButtons();
MenuHeading(FSUI_CSTR("Renderer"));
DrawStringListSetting(bsi, FSUI_ICONSTR(ICON_FA_PAINT_BRUSH,"Renderer"), FSUI_CSTR("Selects the API used to render the emulated GS."), "EmuCore/GS",
DrawStringListSetting(bsi, FSUI_ICONSTR(ICON_FA_PAINT_BRUSH, "Renderer"), FSUI_CSTR("Selects the API used to render the emulated GS."), "EmuCore/GS",
"Renderer", "-1", s_renderer_names, s_renderer_values, std::size(s_renderer_names), true);
MenuHeading(FSUI_CSTR("Display"));
@@ -3950,7 +3953,7 @@ void FullscreenUI::DrawAudioSettingsPage()
DrawIntRangeSetting(bsi, FSUI_ICONSTR(ICON_FA_VOLUME_UP, "Output Volume"),
FSUI_CSTR("Controls the volume of the audio played on the host."), "SPU2/Output", "OutputVolume", 100,
0, 100, "%d%%");
DrawIntRangeSetting(bsi, FSUI_ICONSTR(ICON_FA_FAST_FORWARD,"Fast Forward Volume"),
DrawIntRangeSetting(bsi, FSUI_ICONSTR(ICON_FA_FAST_FORWARD, "Fast Forward Volume"),
FSUI_CSTR("Controls the volume of the audio played on the host when fast forwarding."), "SPU2/Output",
"FastForwardVolume", 100, 0, 100, "%d%%");
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_VOLUME_MUTE, "Mute All Sound"),

View File

@@ -24,6 +24,7 @@
#include "SIO/Pad/PadBase.h"
#include "USB/USB.h"
#include "VMManager.h"
#include "svnrev.h"
#include "common/BitUtils.h"
#include "common/FileSystem.h"
@@ -121,6 +122,7 @@ __ri void ImGuiManager::DrawPerformanceOverlay(float& position_y, float scale, f
{
bool first = true;
const float speed = PerformanceMetrics::GetSpeed();
if (GSConfig.OsdShowFPS)
{
switch (PerformanceMetrics::GetInternalFPSMethod())
@@ -152,6 +154,16 @@ __ri void ImGuiManager::DrawPerformanceOverlay(float& position_y, float scale, f
else
text.append_format(" ({:.0f}%)", target_speed * 100.0f);
}
if (GSConfig.OsdShowVersion)
{
if (GSConfig.OsdShowFPS || GSConfig.OsdShowSpeed)
{
text.append_format(" | ");
}
text.append_format("PCSX2 {}", GIT_REV);
}
if (!text.empty())
{
ImU32 color;

View File

@@ -1605,7 +1605,10 @@ void InputManager::UpdateInputSourceState(SettingsInterface& si, std::unique_loc
{
if (s_input_sources[static_cast<u32>(type)])
{
settings_lock.unlock();
s_input_sources[static_cast<u32>(type)]->Shutdown();
settings_lock.lock();
s_input_sources[static_cast<u32>(type)].reset();
}
}

View File

@@ -39,18 +39,18 @@ void iopMemRelease()
// which is performed by MemInit and PsxMemInit()
void iopMemReset()
{
pxAssert( iopMem );
pxAssert(iopMem);
DbgCon.WriteLn("IOP resetting main memory...");
memset(psxMemWLUT, 0, 0x2000 * sizeof(uptr) * 2); // clears both allocations, RLUT and WLUT
memset(psxMemWLUT, 0, 0x2000 * sizeof(uptr) * 2); // clears both allocations, RLUT and WLUT
// Trick! We're accessing RLUT here through WLUT, since it's the non-const pointer.
// So the ones with a 0x2000 prefixed are RLUT tables.
// Map IOP main memory, which is Read/Write, and mirrored three times
// at 0x0, 0x8000, and 0xa000:
for (int i=0; i<0x0080; i++)
for (int i = 0; i < 0x0080; i++)
{
psxMemWLUT[i + 0x0000] = (uptr)&iopMem->Main[(i & 0x1f) << 16];
@@ -78,7 +78,7 @@ void iopMemReset()
psxMemWLUT[i + 0x2000 + 0x1e00] = (uptr)&eeMem->ROM1[i << 16];
}
for (int i = 0; i < 0x0008; i++)
for (int i = 0; i < 0x0040; i++)
{
psxMemWLUT[i + 0x2000 + 0x1e40] = (uptr)&eeMem->ROM2[i << 16];
}
@@ -318,7 +318,7 @@ void iopMemWrite16(u32 mem, u16 value)
default:
psxHu16(mem) = value;
break;
break;
}
} else
{
@@ -443,7 +443,7 @@ void iopMemWrite32(u32 mem, u32 value)
case 0x60:
psHu32(SBUS_F260) = 0;
return;
return;
}
#if PSX_EXTRALOGS
@@ -529,11 +529,11 @@ bool iopMemSafeWriteBytes(u32 mem, const void* src, u32 size)
std::string iopMemReadString(u32 mem, int maxlen)
{
std::string ret;
char c;
std::string ret;
char c;
while ((c = iopMemRead8(mem++)) && maxlen--)
ret.push_back(c);
while ((c = iopMemRead8(mem++)) && maxlen--)
ret.push_back(c);
return ret;
return ret;
}

View File

@@ -11,7 +11,7 @@ namespace Ps2MemSize
static constexpr u32 TotalRam = _1mb * 128;// 128 MB total memory.
static constexpr u32 Rom = _1mb * 4; // 4 MB main rom
static constexpr u32 Rom1 = _1mb * 4; // DVD player
static constexpr u32 Rom2 = 0x00080000; // Chinese rom extension
static constexpr u32 Rom2 = _1mb * 4; // Chinese rom extension
static constexpr u32 Hardware = _64kb;
static constexpr u32 Scratch = _16kb;

View File

@@ -629,6 +629,7 @@ Pcsx2Config::GSOptions::GSOptions()
OsdShowSettings = false;
OsdShowInputs = false;
OsdShowFrameTimes = false;
OsdShowVersion = false;
HWDownloadMode = GSHardwareDownloadMode::Enabled;
HWSpinGPUForReadbacks = false;
@@ -749,6 +750,7 @@ bool Pcsx2Config::GSOptions::OptionsAreEqual(const GSOptions& right) const
OpEqu(CaptureContainer) &&
OpEqu(VideoCaptureCodec) &&
OpEqu(VideoCaptureFormat) &&
OpEqu(VideoCaptureParameters) &&
OpEqu(AudioCaptureCodec) &&
OpEqu(AudioCaptureParameters) &&
@@ -833,6 +835,7 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap)
SettingsWrapBitBool(OsdShowSettings);
SettingsWrapBitBool(OsdShowInputs);
SettingsWrapBitBool(OsdShowFrameTimes);
SettingsWrapBitBool(OsdShowVersion);
SettingsWrapBitBool(HWSpinGPUForReadbacks);
SettingsWrapBitBool(HWSpinCPUForReadbacks);
@@ -923,6 +926,7 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap)
SettingsWrapEntryEx(CaptureContainer, "CaptureContainer");
SettingsWrapEntryEx(VideoCaptureCodec, "VideoCaptureCodec");
SettingsWrapEntryEx(VideoCaptureFormat, "VideoCaptureFormat");
SettingsWrapEntryEx(VideoCaptureParameters, "VideoCaptureParameters");
SettingsWrapEntryEx(AudioCaptureCodec, "AudioCaptureCodec");
SettingsWrapEntryEx(AudioCaptureParameters, "AudioCaptureParameters");

View File

@@ -548,7 +548,7 @@ static void recReserveRAM()
recLUT_SetPage(recLUT, hwLUT, recROM1, 0xa000, i, i - 0x1e00);
}
for (int i = 0x1e40; i < 0x1e48; i++)
for (int i = 0x1e40; i < 0x1e80; i++)
{
recLUT_SetPage(recLUT, hwLUT, recROM2, 0x0000, i, i - 0x1e40);
recLUT_SetPage(recLUT, hwLUT, recROM2, 0x8000, i, i - 0x1e40);
@@ -691,7 +691,7 @@ static void recExecute()
if (!fastjmp_set(&m_SetJmp_StateCheck))
{
eeCpuExecuting = true;
((void(*)())EnterRecompiledCode)();
((void (*)())EnterRecompiledCode)();
// Generally unreachable code here ...
}
@@ -1544,7 +1544,7 @@ void dynarecMemcheck(size_t i)
auto mc = CBreakPoints::GetMemChecks(BREAKPOINT_EE)[i];
if(mc.hasCond)
if (mc.hasCond)
{
if (!mc.cond.Evaluate())
return;
@@ -1557,7 +1557,7 @@ void dynarecMemcheck(size_t i)
else
DevCon.WriteLn("Hit load breakpoint @0x%x", cpuRegs.pc);
}
CBreakPoints::SetBreakpointTriggered(true, BREAKPOINT_EE);
VMManager::SetPaused(true);
recExitExecution();