mirror of
https://github.com/stenzek/duckstation.git
synced 2026-02-17 03:44:36 +00:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9e87d1afed | ||
|
|
801b90146a | ||
|
|
85332addd5 | ||
|
|
499ca01a1e | ||
|
|
c201d7f4ff | ||
|
|
d777983d74 | ||
|
|
e0175b55db | ||
|
|
445428c978 |
@@ -3627,6 +3627,7 @@ SLPS-01689:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- NeGcon
|
||||
- NeGconRumble
|
||||
metadata:
|
||||
publisher: "Atlus Co"
|
||||
developer: "Atlus Co"
|
||||
@@ -29014,6 +29015,7 @@ SLES-00477:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- NeGcon
|
||||
- NeGconRumble
|
||||
metadata:
|
||||
publisher: "Sony"
|
||||
developer: "Codemasters"
|
||||
@@ -29043,6 +29045,7 @@ SLES-01204:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- NeGcon
|
||||
- NeGconRumble
|
||||
metadata:
|
||||
publisher: "Sony"
|
||||
developer: "Codemasters"
|
||||
@@ -29072,6 +29075,7 @@ SCUS-94474:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- NeGcon
|
||||
- NeGconRumble
|
||||
metadata:
|
||||
publisher: "Sony"
|
||||
developer: "Codemasters"
|
||||
@@ -29092,6 +29096,7 @@ SLPS-91477:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- NeGcon
|
||||
- NeGconRumble
|
||||
metadata:
|
||||
publisher: "Spike"
|
||||
developer: "Codemasters"
|
||||
@@ -29112,6 +29117,7 @@ SLPS-03274:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- NeGcon
|
||||
- NeGconRumble
|
||||
metadata:
|
||||
publisher: "Spike"
|
||||
developer: "Codemasters"
|
||||
@@ -29136,6 +29142,7 @@ SLES-02605:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- NeGcon
|
||||
- NeGconRumble
|
||||
metadata:
|
||||
publisher: "Codemasters"
|
||||
developer: "Codemasters"
|
||||
@@ -29164,6 +29171,7 @@ SLUS-01222:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- NeGcon
|
||||
- NeGconRumble
|
||||
settings:
|
||||
displayActiveStartOffset: 64
|
||||
displayActiveEndOffset: 68
|
||||
@@ -29189,6 +29197,7 @@ SLPS-91431:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- NeGcon
|
||||
- NeGconRumble
|
||||
metadata:
|
||||
publisher: "Spike"
|
||||
developer: "Codemasters"
|
||||
@@ -70340,6 +70349,7 @@ SCES-00984:
|
||||
- AnalogJoystick
|
||||
- DigitalController
|
||||
- NeGcon
|
||||
- NeGconRumble
|
||||
metadata:
|
||||
publisher: "Sony"
|
||||
developer: "Polyphony Digital"
|
||||
@@ -70385,6 +70395,7 @@ SCPS-10045:
|
||||
- AnalogJoystick
|
||||
- DigitalController
|
||||
- NeGcon
|
||||
- NeGconRumble
|
||||
codes:
|
||||
- SCPS-10045
|
||||
- SCPS-45149
|
||||
@@ -70415,6 +70426,7 @@ SCUS-94194:
|
||||
- AnalogJoystick
|
||||
- DigitalController
|
||||
- NeGcon
|
||||
- NeGconRumble
|
||||
metadata:
|
||||
publisher: "Sony"
|
||||
developer: "Polyphony Digital"
|
||||
@@ -113003,6 +113015,7 @@ SLES-02191:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- NeGcon
|
||||
- NeGconRumble
|
||||
metadata:
|
||||
publisher: "Electronic Arts"
|
||||
developer: "Stormfront Studios"
|
||||
@@ -113024,6 +113037,7 @@ SLUS-00962:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- NeGcon
|
||||
- NeGconRumble
|
||||
metadata:
|
||||
publisher: "Electronic Arts"
|
||||
developer: "Stormfront Studios"
|
||||
@@ -113045,6 +113059,7 @@ SLUS-01263:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- NeGcon
|
||||
- NeGconRumble
|
||||
metadata:
|
||||
publisher: "Electronic Arts"
|
||||
developer: "Black Box Games"
|
||||
@@ -113061,6 +113076,7 @@ SLUS-01263:
|
||||
linkCable: false
|
||||
SLES-00905:
|
||||
name: "NASCAR 98"
|
||||
sortName: "NASCAR 1998 (Europe)"
|
||||
saveName: "NASCAR 98 (Europe)"
|
||||
controllers:
|
||||
- AnalogController
|
||||
@@ -113083,9 +113099,11 @@ SLES-00905:
|
||||
linkCable: false
|
||||
SLES-00765:
|
||||
name: "NASCAR 98"
|
||||
sortName: "NASCAR 1998 (France)"
|
||||
saveName: "NASCAR 98 (France)"
|
||||
SLES-00880:
|
||||
name: "NASCAR 98"
|
||||
sortName: "NASCAR 1998 (Germany)"
|
||||
saveName: "NASCAR 98 (Germany)"
|
||||
controllers:
|
||||
- AnalogController
|
||||
@@ -113109,6 +113127,7 @@ SLES-00880:
|
||||
SLPS-01295:
|
||||
name: "NASCAR 98"
|
||||
localizedName: "ナスカー98"
|
||||
sortName: "NASCAR 1998 (Japan)"
|
||||
saveName: "NASCAR 98 (Japan)"
|
||||
controllers:
|
||||
- AnalogController
|
||||
@@ -113131,6 +113150,7 @@ SLPS-01295:
|
||||
linkCable: false
|
||||
SLUS-00521:
|
||||
name: "NASCAR 98"
|
||||
sortName: "NASCAR 1998 (USA)"
|
||||
saveName: "NASCAR 98 (USA)"
|
||||
controllers:
|
||||
- AnalogController
|
||||
@@ -113153,6 +113173,7 @@ SLUS-00521:
|
||||
linkCable: false
|
||||
SLUS-00647:
|
||||
name: "NASCAR 98 Collector's Edition"
|
||||
sortName: "NASCAR 1998 Collector's Edition (USA)"
|
||||
saveName: "NASCAR 98 Collector's Edition (USA)"
|
||||
controllers:
|
||||
- AnalogController
|
||||
@@ -113175,11 +113196,13 @@ SLUS-00647:
|
||||
linkCable: false
|
||||
SLES-01447:
|
||||
name: "NASCAR 99"
|
||||
sortName: "NASCAR 1999 (Europe)"
|
||||
saveName: "NASCAR 99 (Europe)"
|
||||
controllers:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- NeGcon
|
||||
- NeGconRumble
|
||||
metadata:
|
||||
publisher: "Electronic Arts"
|
||||
developer: "Stormfront Studios"
|
||||
@@ -113196,11 +113219,13 @@ SLES-01447:
|
||||
linkCable: false
|
||||
SLES-01452:
|
||||
name: "NASCAR 99"
|
||||
sortName: "NASCAR 1999 (France)"
|
||||
saveName: "NASCAR 99 (France)"
|
||||
controllers:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- NeGcon
|
||||
- NeGconRumble
|
||||
metadata:
|
||||
publisher: "Electronic Arts"
|
||||
developer: "Stormfront Studios"
|
||||
@@ -113217,11 +113242,13 @@ SLES-01452:
|
||||
linkCable: false
|
||||
SLES-01453:
|
||||
name: "NASCAR 99"
|
||||
sortName: "NASCAR 1999 (Germany)"
|
||||
saveName: "NASCAR 99 (Germany)"
|
||||
controllers:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- NeGcon
|
||||
- NeGconRumble
|
||||
metadata:
|
||||
publisher: "Electronic Arts"
|
||||
developer: "Stormfront Studios"
|
||||
@@ -113238,11 +113265,13 @@ SLES-01453:
|
||||
linkCable: false
|
||||
SLUS-00740:
|
||||
name: "NASCAR 99"
|
||||
sortName: "NASCAR 1999 (USA)"
|
||||
saveName: "NASCAR 99 (USA)"
|
||||
controllers:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- NeGcon
|
||||
- NeGconRumble
|
||||
metadata:
|
||||
publisher: "Electronic Arts"
|
||||
developer: "Stormfront Studios"
|
||||
@@ -113259,11 +113288,13 @@ SLUS-00740:
|
||||
linkCable: false
|
||||
SLUS-00883:
|
||||
name: "NASCAR 99 Legacy"
|
||||
sortName: "NASCAR 1999 Legacy (USA)"
|
||||
saveName: "NASCAR 99 Legacy (USA)"
|
||||
controllers:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- NeGcon
|
||||
- NeGconRumble
|
||||
metadata:
|
||||
publisher: "Electronic Arts"
|
||||
developer: "Stormfront Studios"
|
||||
@@ -118447,11 +118478,13 @@ SLUS-00764:
|
||||
linkCable: false
|
||||
SLES-01876:
|
||||
name: "Need for Speed - High Stakes"
|
||||
sortName: "Need for Speed 4 - High Stakes (Australia)"
|
||||
saveName: "Need for Speed - High Stakes (Australia)"
|
||||
controllers:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- NeGcon
|
||||
- NeGconRumble
|
||||
metadata:
|
||||
publisher: "Electronic Arts"
|
||||
developer: "EA Canada"
|
||||
@@ -118468,6 +118501,7 @@ SLES-01876:
|
||||
linkCable: false
|
||||
SLUS-00826:
|
||||
name: "Need for Speed - High Stakes"
|
||||
sortName: "Need for Speed 4 - High Stakes (USA)"
|
||||
saveName: "Need for Speed - High Stakes (USA)"
|
||||
compatibility:
|
||||
rating: NoIssues
|
||||
@@ -118476,6 +118510,7 @@ SLUS-00826:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- NeGcon
|
||||
- NeGconRumble
|
||||
metadata:
|
||||
publisher: "Electronic Arts"
|
||||
developer: "EA Canada"
|
||||
@@ -118492,6 +118527,7 @@ SLUS-00826:
|
||||
linkCable: false
|
||||
SLES-02689:
|
||||
name: "Need for Speed - Porsche 2000"
|
||||
sortName: "Need for Speed 5 - Porsche 2000 (Europe) (En,De,Sv)"
|
||||
saveName: "Need for Speed - Porsche 2000 (Europe) (En,De,Sv)"
|
||||
controllers:
|
||||
- AnalogController
|
||||
@@ -118516,6 +118552,7 @@ SLES-02689:
|
||||
linkCable: false
|
||||
SLES-02700:
|
||||
name: "Need for Speed - Porsche 2000"
|
||||
sortName: "Need for Speed 5 - Porsche 2000 (Europe) (Fr,Es,It)"
|
||||
saveName: "Need for Speed - Porsche 2000 (Europe) (Fr,Es,It)"
|
||||
controllers:
|
||||
- AnalogController
|
||||
@@ -118540,6 +118577,7 @@ SLES-02700:
|
||||
linkCable: false
|
||||
SLUS-01104:
|
||||
name: "Need for Speed - Porsche Unleashed"
|
||||
sortName: "Need for Speed 5 - Porsche Unleashed (USA)"
|
||||
saveName: "Need for Speed - Porsche Unleashed (USA)"
|
||||
compatibility:
|
||||
rating: NoIssues
|
||||
@@ -118564,6 +118602,7 @@ SLUS-01104:
|
||||
linkCable: false
|
||||
SLES-01790:
|
||||
name: "Need for Speed - Road Challenge"
|
||||
sortName: "Need for Speed 4 - Road Challenge (Europe) (En,Es,It)"
|
||||
saveName: "Need for Speed - Road Challenge (Europe) (En,Es,It)"
|
||||
controllers:
|
||||
- AnalogController
|
||||
@@ -118587,6 +118626,7 @@ SLES-01790:
|
||||
linkCable: false
|
||||
SLES-01788:
|
||||
name: "Need for Speed - Road Challenge"
|
||||
sortName: "Need for Speed 4 - Road Challenge (Europe) (En,Sv)"
|
||||
saveName: "Need for Speed - Road Challenge (Europe) (En,Sv)"
|
||||
controllers:
|
||||
- AnalogController
|
||||
@@ -118609,6 +118649,7 @@ SLES-01788:
|
||||
linkCable: false
|
||||
SLES-01789:
|
||||
name: "Need for Speed - Road Challenge"
|
||||
sortName: "Need for Speed 4 - Road Challenge (Europe) (Fr,De)"
|
||||
saveName: "Need for Speed - Road Challenge (Europe) (Fr,De)"
|
||||
controllers:
|
||||
- AnalogController
|
||||
@@ -118679,6 +118720,7 @@ SLUS-01003:
|
||||
linkCable: false
|
||||
SLES-00658:
|
||||
name: "Need for Speed II"
|
||||
sortName: "Need for Speed 2 (Europe) (En,Fr,De,Es,It,Sv)"
|
||||
saveName: "Need for Speed II (Europe) (En,Fr,De,Es,It,Sv)"
|
||||
compatibility:
|
||||
rating: NoIssues
|
||||
@@ -118709,6 +118751,7 @@ SLES-00658:
|
||||
linkCable: false
|
||||
SLUS-00276:
|
||||
name: "Need for Speed II"
|
||||
sortName: "Need for Speed 2 (USA)"
|
||||
saveName: "Need for Speed II (USA)"
|
||||
compatibility:
|
||||
rating: NoIssues
|
||||
@@ -118739,6 +118782,7 @@ SLUS-00276:
|
||||
linkCable: false
|
||||
SLES-01154:
|
||||
name: "Need for Speed III - Hot Pursuit"
|
||||
sortName: "Need for Speed 3 - Hot Pursuit (Europe) (En,Fr,De,Es,It,Sv)"
|
||||
saveName: "Need for Speed III - Hot Pursuit (Europe) (En,Fr,De,Es,It,Sv)"
|
||||
controllers:
|
||||
- AnalogController
|
||||
@@ -118765,6 +118809,7 @@ SLES-01154:
|
||||
linkCable: false
|
||||
SLUS-00620:
|
||||
name: "Need for Speed III - Hot Pursuit"
|
||||
sortName: "Need for Speed 3 - Hot Pursuit (USA)"
|
||||
saveName: "Need for Speed III - Hot Pursuit (USA)"
|
||||
compatibility:
|
||||
rating: NoIssues
|
||||
@@ -139298,6 +139343,7 @@ SLPS-01601:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- NeGcon
|
||||
- NeGconRumble
|
||||
codes:
|
||||
- SLPS-01601
|
||||
- SLPS-02258
|
||||
@@ -139329,6 +139375,7 @@ SLPS-02679:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- NeGcon
|
||||
- NeGconRumble
|
||||
metadata:
|
||||
publisher: "Prism Arts"
|
||||
developer: "Prism Arts"
|
||||
@@ -144362,6 +144409,7 @@ SLPS-02388:
|
||||
linkCable: false
|
||||
SLES-00223:
|
||||
name: "Road & Track Presents - The Need for Speed"
|
||||
sortName: "Need for Speed 1 (Europe) (En,De)"
|
||||
saveName: "Road & Track Presents - The Need for Speed (Europe) (En,De)"
|
||||
compatibility:
|
||||
rating: NoIssues
|
||||
@@ -144386,6 +144434,7 @@ SLES-00223:
|
||||
linkCable: true
|
||||
SLUS-00204:
|
||||
name: "Road & Track Presents - The Need for Speed"
|
||||
sortName: "Need for Speed 1 (USA)"
|
||||
saveName: "Road & Track Presents - The Need for Speed (USA)"
|
||||
compatibility:
|
||||
rating: NoIssues
|
||||
@@ -153665,6 +153714,7 @@ SLPM-86344:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- NeGcon
|
||||
- NeGconRumble
|
||||
metadata:
|
||||
publisher: "Taito"
|
||||
developer: "Taito"
|
||||
@@ -173565,6 +173615,7 @@ SLUS-00996:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- NeGcon
|
||||
- NeGconRumble
|
||||
metadata:
|
||||
publisher: "Codemasters"
|
||||
developer: "Codemasters"
|
||||
@@ -173588,6 +173639,7 @@ SLES-01542:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- NeGcon
|
||||
- NeGconRumble
|
||||
metadata:
|
||||
publisher: "Codemasters"
|
||||
developer: "Codemasters"
|
||||
@@ -173611,6 +173663,7 @@ SLES-01547:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- NeGcon
|
||||
- NeGconRumble
|
||||
metadata:
|
||||
publisher: "Codemasters"
|
||||
developer: "Codemasters"
|
||||
@@ -173633,6 +173686,7 @@ SLUS-00611:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- NeGcon
|
||||
- NeGconRumble
|
||||
metadata:
|
||||
publisher: "3DO"
|
||||
developer: "Codemasters"
|
||||
@@ -173654,6 +173708,7 @@ SLES-00376:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- NeGcon
|
||||
- NeGconRumble
|
||||
metadata:
|
||||
publisher: "Codemasters"
|
||||
developer: "Codemasters"
|
||||
@@ -173676,6 +173731,7 @@ SLPS-01410:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- NeGcon
|
||||
- NeGconRumble
|
||||
metadata:
|
||||
publisher: "Upstar (Lay-Up)"
|
||||
developer: "Codemasters"
|
||||
@@ -173697,6 +173753,7 @@ SLES-02572:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- NeGcon
|
||||
- NeGconRumble
|
||||
libcrypt: true
|
||||
metadata:
|
||||
publisher: "Codemasters"
|
||||
@@ -173721,6 +173778,7 @@ SLES-02573:
|
||||
- AnalogController
|
||||
- DigitalController
|
||||
- NeGcon
|
||||
- NeGconRumble
|
||||
libcrypt: true
|
||||
metadata:
|
||||
publisher: "Codemasters"
|
||||
|
||||
@@ -3816,6 +3816,9 @@ void FullscreenUI::DrawGraphicsSettingsPage()
|
||||
options.emplace_back(FSUI_STR("Default"), current_adapter.has_value() && current_adapter->empty());
|
||||
for (const GPUDevice::AdapterInfo& adapter : s_settings_locals.graphics_adapter_list_cache)
|
||||
{
|
||||
if (adapter.name.empty())
|
||||
continue;
|
||||
|
||||
const bool checked = (current_adapter.has_value() && current_adapter.value() == adapter.name);
|
||||
options.emplace_back(adapter.name, checked);
|
||||
}
|
||||
@@ -4017,7 +4020,7 @@ void FullscreenUI::DrawGraphicsSettingsPage()
|
||||
FSUI_VSTR("Use Global Setting")))
|
||||
{
|
||||
const GPUDevice::AdapterInfo* selected_adapter = nullptr;
|
||||
if (current_adapter.has_value())
|
||||
if (current_adapter.has_value() && !current_adapter->empty())
|
||||
{
|
||||
for (const GPUDevice::AdapterInfo& ai : s_settings_locals.graphics_adapter_list_cache)
|
||||
{
|
||||
@@ -4067,7 +4070,10 @@ void FullscreenUI::DrawGraphicsSettingsPage()
|
||||
else
|
||||
bsi->SetStringValue("GPU", "FullscreenMode", value);
|
||||
SetSettingsChanged(bsi);
|
||||
ShowToast(OSDMessageType::Info, std::string(), FSUI_STR("Resolution change will be applied after restarting."));
|
||||
Host::RunOnCoreThread([]() {
|
||||
if (VideoThread::IsFullscreen())
|
||||
VideoThread::RecreateRenderWindow();
|
||||
});
|
||||
};
|
||||
OpenChoiceDialog(FSUI_ICONVSTR(ICON_FA_TV, "Fullscreen Resolution"), false, std::move(options),
|
||||
std::move(callback));
|
||||
|
||||
@@ -611,7 +611,6 @@ TRANSLATE_NOOP("FullscreenUI", "Reset Settings");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Resets all configuration to defaults (including bindings).");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Resets all settings to the defaults.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Resets memory card directory to default (user directory).");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Resolution change will be applied after restarting.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Restart Game");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Restore Defaults");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Resume Game");
|
||||
|
||||
@@ -64,10 +64,9 @@ namespace MiniHost {
|
||||
/// Use two async worker threads, should be enough for most tasks.
|
||||
static constexpr u32 NUM_ASYNC_WORKER_THREADS = 2;
|
||||
|
||||
// static constexpr u32 DEFAULT_WINDOW_WIDTH = 1280;
|
||||
// static constexpr u32 DEFAULT_WINDOW_HEIGHT = 720;
|
||||
static constexpr u32 DEFAULT_WINDOW_WIDTH = 1920;
|
||||
static constexpr u32 DEFAULT_WINDOW_HEIGHT = 1080;
|
||||
static constexpr float DEFAULT_WINDOW_REFRESH_RATE = 60.0f;
|
||||
|
||||
static constexpr auto CORE_THREAD_POLL_INTERVAL =
|
||||
std::chrono::milliseconds(8); // how often we'll poll controllers when paused
|
||||
@@ -111,6 +110,7 @@ struct SDLHostState
|
||||
float sdl_window_scale = 0.0f;
|
||||
float sdl_window_refresh_rate = 0.0f;
|
||||
WindowInfoPrerotation force_prerotation = WindowInfoPrerotation::Identity;
|
||||
bool use_window_fullscreen_mode = false;
|
||||
|
||||
Threading::Thread core_thread;
|
||||
Threading::Thread video_thread;
|
||||
@@ -161,6 +161,23 @@ bool MiniHost::EarlyProcessStartup()
|
||||
return false;
|
||||
}
|
||||
|
||||
s_state.func_event_id = SDL_RegisterEvents(1);
|
||||
if (s_state.func_event_id == static_cast<u32>(-1))
|
||||
{
|
||||
Host::ReportFatalError("Error", TinyString::from_format("SDL_RegisterEvents() failed: {}", SDL_GetError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
// If we're running without a windowing system, force fullscreen.
|
||||
if (const char* video_driver = SDL_GetCurrentVideoDriver(); video_driver && std::strcmp(video_driver, "kmsdrm") == 0)
|
||||
{
|
||||
fprintf(stderr, "kmsdrm video driver detected, using fullscreen display mode for windows.\n");
|
||||
s_state.use_window_fullscreen_mode = true;
|
||||
s_state.start_fullscreen_ui_fullscreen = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !__has_include("scmversion/tag.h")
|
||||
//
|
||||
// To those distributing their own builds or packages of DuckStation, and seeing this message:
|
||||
@@ -358,7 +375,19 @@ std::optional<WindowInfo> MiniHost::TranslateSDLWindowInfo(SDL_Window* win, Erro
|
||||
int window_px_width = 1, window_px_height = 1;
|
||||
SDL_GetWindowSize(win, &window_width, &window_height);
|
||||
SDL_GetWindowSizeInPixels(win, &window_px_width, &window_px_height);
|
||||
s_state.sdl_window_scale = SDL_GetWindowDisplayScale(win);
|
||||
|
||||
// For kmsdrm, assume 720p is 100% scale. Jank, but no other way to do it outside of querying the display size..
|
||||
if (s_state.use_window_fullscreen_mode)
|
||||
{
|
||||
s_state.sdl_window_scale = std::clamp(std::min(window_px_width / 1280.0f, window_px_height / 720.0f), 1.0f, 4.0f);
|
||||
INFO_LOG("Using window fullscreen display mode, setting scale to {}", s_state.sdl_window_scale);
|
||||
}
|
||||
else
|
||||
{
|
||||
s_state.sdl_window_scale = SDL_GetWindowDisplayScale(win);
|
||||
INFO_LOG("Using window scale of {} (window size {}x{}, pixel size {}x{})", s_state.sdl_window_scale, window_width,
|
||||
window_height, window_px_width, window_px_height);
|
||||
}
|
||||
|
||||
const SDL_DisplayMode* dispmode = nullptr;
|
||||
|
||||
@@ -494,24 +523,61 @@ std::optional<WindowInfo> Host::AcquireRenderWindow(RenderAPI render_api, bool f
|
||||
else if (render_api == RenderAPI::Vulkan)
|
||||
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_VULKAN_BOOLEAN, true);
|
||||
|
||||
if (fullscreen)
|
||||
{
|
||||
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_BORDERLESS_BOOLEAN, true);
|
||||
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_FULLSCREEN_BOOLEAN, true);
|
||||
}
|
||||
std::optional<SDL_DisplayMode> window_fullscreen_mode;
|
||||
|
||||
if (s32 window_x, window_y, window_width, window_height;
|
||||
MiniHost::GetSavedPlatformWindowGeometry(&window_x, &window_y, &window_width, &window_height))
|
||||
if (!s_state.use_window_fullscreen_mode)
|
||||
{
|
||||
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, window_x);
|
||||
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, window_y);
|
||||
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, window_width);
|
||||
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, window_height);
|
||||
if (fullscreen)
|
||||
{
|
||||
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_BORDERLESS_BOOLEAN, true);
|
||||
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_FULLSCREEN_BOOLEAN, true);
|
||||
}
|
||||
|
||||
if (s32 window_x, window_y, window_width, window_height;
|
||||
MiniHost::GetSavedPlatformWindowGeometry(&window_x, &window_y, &window_width, &window_height))
|
||||
{
|
||||
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, window_x);
|
||||
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, window_y);
|
||||
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, window_width);
|
||||
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, window_height);
|
||||
}
|
||||
else
|
||||
{
|
||||
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, DEFAULT_WINDOW_WIDTH);
|
||||
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, DEFAULT_WINDOW_HEIGHT);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, DEFAULT_WINDOW_WIDTH);
|
||||
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, DEFAULT_WINDOW_HEIGHT);
|
||||
std::optional<GPUDevice::ExclusiveFullscreenMode> fullscreen_mode =
|
||||
GPUDevice::ExclusiveFullscreenMode::Parse(Core::GetTinyStringSettingValue("GPU", "FullscreenMode"));
|
||||
if (!fullscreen_mode.has_value())
|
||||
{
|
||||
INFO_LOG("Using default fullscreen mode ({}x{})", DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT);
|
||||
fullscreen_mode =
|
||||
GPUDevice::ExclusiveFullscreenMode{DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT, DEFAULT_WINDOW_REFRESH_RATE};
|
||||
}
|
||||
|
||||
window_fullscreen_mode.emplace();
|
||||
if (SDL_GetClosestFullscreenDisplayMode(SDL_GetPrimaryDisplay(), fullscreen_mode->width, fullscreen_mode->height,
|
||||
fullscreen_mode->refresh_rate, true, &window_fullscreen_mode.value()))
|
||||
{
|
||||
INFO_LOG("Requesting window fullscreen display mode {}x{} @ {} hz (closest match: {}x{} @ {} hz)",
|
||||
fullscreen_mode->width, fullscreen_mode->height, fullscreen_mode->refresh_rate,
|
||||
window_fullscreen_mode->w, window_fullscreen_mode->h, window_fullscreen_mode->refresh_rate);
|
||||
|
||||
// For GL we need to set the window size to the display mode. Annoyingly can't set the refresh rate...
|
||||
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, window_fullscreen_mode->w);
|
||||
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, window_fullscreen_mode->h);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG("SDL_GetClosestFullscreenDisplayMode() failed: {}", SDL_GetError());
|
||||
window_fullscreen_mode.reset();
|
||||
}
|
||||
|
||||
// Force fullscreen.
|
||||
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_FULLSCREEN_BOOLEAN, true);
|
||||
}
|
||||
|
||||
s_state.sdl_window = SDL_CreateWindowWithProperties(props);
|
||||
@@ -519,6 +585,12 @@ std::optional<WindowInfo> Host::AcquireRenderWindow(RenderAPI render_api, bool f
|
||||
|
||||
if (s_state.sdl_window)
|
||||
{
|
||||
if (window_fullscreen_mode.has_value() &&
|
||||
!SDL_SetWindowFullscreenMode(s_state.sdl_window, &window_fullscreen_mode.value()))
|
||||
{
|
||||
ERROR_LOG("SDL_SetWindowFullscreenMode() failed: {}", SDL_GetError());
|
||||
}
|
||||
|
||||
wi = TranslateSDLWindowInfo(s_state.sdl_window, error);
|
||||
if (!wi.has_value())
|
||||
{
|
||||
@@ -1698,13 +1770,6 @@ int main(int argc, char* argv[])
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
s_state.func_event_id = SDL_RegisterEvents(1);
|
||||
if (s_state.func_event_id == static_cast<u32>(-1))
|
||||
{
|
||||
Host::ReportFatalError("Error", TinyString::from_format("SDL_RegisterEvents() failed: {}", SDL_GetError()));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!EarlyProcessStartup())
|
||||
return EXIT_FAILURE;
|
||||
|
||||
|
||||
@@ -299,6 +299,10 @@ if(NOT APPLE)
|
||||
set(RCC_FILE "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/resources/duckstation-qt.rcc")
|
||||
qt_add_binary_resources(duckstation-qt-rcc resources/duckstation-qt.qrc DESTINATION ${RCC_FILE} OPTIONS -no-compress)
|
||||
add_dependencies(duckstation-qt duckstation-qt-rcc)
|
||||
|
||||
# Need to ensure the resources directory exists, it might not. Happens when low CPU count and parallel builds.
|
||||
add_custom_target(duckstation-qt-rcc-mkdir COMMAND ${CMAKE_COMMAND} -E create_directory "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/resources")
|
||||
add_dependencies(duckstation-qt-rcc duckstation-qt-rcc-mkdir)
|
||||
else()
|
||||
set(RCC_FILE "${CMAKE_CURRENT_BINARY_DIR}/duckstation-qt.rcc")
|
||||
qt_add_binary_resources(duckstation-qt-rcc resources/duckstation-qt.qrc DESTINATION ${RCC_FILE} OPTIONS -no-compress)
|
||||
|
||||
@@ -683,6 +683,9 @@ void GraphicsSettingsWidget::populateGPUAdaptersAndResolutions(RenderAPI render_
|
||||
const std::string current_adapter_name = m_dialog->getEffectiveStringValue("GPU", "Adapter", "");
|
||||
for (const GPUDevice::AdapterInfo& adapter : m_adapters)
|
||||
{
|
||||
if (adapter.name.empty())
|
||||
continue;
|
||||
|
||||
const QString qadaptername = QString::fromStdString(adapter.name);
|
||||
m_ui.adapter->addItem(qadaptername, QVariant(qadaptername));
|
||||
if (adapter.name == current_adapter_name)
|
||||
|
||||
@@ -200,6 +200,7 @@ if(NOT ANDROID)
|
||||
sdl_audio_stream.cpp
|
||||
sdl_input_source.cpp
|
||||
sdl_input_source.h
|
||||
sdl_video_helpers.h
|
||||
)
|
||||
if(ENABLE_OPENGL)
|
||||
target_sources(util PRIVATE
|
||||
|
||||
@@ -37,6 +37,7 @@ LOG_CHANNEL(GPUDevice);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_OPENGL
|
||||
#include "opengl_context.h"
|
||||
#include "opengl_device.h"
|
||||
#endif
|
||||
|
||||
@@ -394,8 +395,7 @@ std::optional<GPUDevice::AdapterInfoList> GPUDevice::GetAdapterListForAPI(Render
|
||||
#ifdef ENABLE_OPENGL
|
||||
case RenderAPI::OpenGL:
|
||||
case RenderAPI::OpenGLES:
|
||||
// No way of querying.
|
||||
ret = AdapterInfoList();
|
||||
ret = OpenGLContext::GetAdapterList(window_type, error);
|
||||
break;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -210,3 +210,13 @@ std::unique_ptr<OpenGLContext> OpenGLContext::Create(WindowInfo& wi, SurfaceHand
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
GPUDevice::AdapterInfoList OpenGLContext::GetAdapterList(WindowInfoType window_type, Error* error)
|
||||
{
|
||||
#ifdef ENABLE_SDL
|
||||
if (window_type == WindowInfoType::SDL)
|
||||
return OpenGLContextSDL::GetAdapterList(window_type, error);
|
||||
#endif
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gpu_device.h"
|
||||
#include "window_info.h"
|
||||
|
||||
#include "common/types.h"
|
||||
@@ -52,6 +53,8 @@ public:
|
||||
static std::unique_ptr<OpenGLContext> Create(WindowInfo& wi, SurfaceHandle* surface, bool prefer_gles_context,
|
||||
Error* error);
|
||||
|
||||
static GPUDevice::AdapterInfoList GetAdapterList(WindowInfoType window_type, Error* error);
|
||||
|
||||
protected:
|
||||
Version m_version = {};
|
||||
};
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2019-2026 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||
|
||||
#include "opengl_context_sdl.h"
|
||||
#include "gpu_texture.h"
|
||||
#include "opengl_loader.h"
|
||||
#include "sdl_video_helpers.h"
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/error.h"
|
||||
#include "common/log.h"
|
||||
#include "common/scoped_guard.h"
|
||||
|
||||
#include "SDL3/SDL.h"
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
LOG_CHANNEL(GPUDevice);
|
||||
|
||||
@@ -35,6 +36,26 @@ std::unique_ptr<OpenGLContext> OpenGLContextSDL::Create(WindowInfo& wi, SurfaceH
|
||||
return context;
|
||||
}
|
||||
|
||||
GPUDevice::AdapterInfoList OpenGLContextSDL::GetAdapterList(WindowInfoType window_type, Error* error)
|
||||
{
|
||||
std::vector<GPUDevice::ExclusiveFullscreenMode> fullscreen_modes = SDLVideoHelpers::GetFullscreenModeList();
|
||||
if (fullscreen_modes.empty())
|
||||
{
|
||||
// no point adding anything if no modes
|
||||
return {};
|
||||
}
|
||||
|
||||
// Set some reasonable defaults, since we don't know this until we actually create the context.
|
||||
GPUDevice::AdapterInfoList ret;
|
||||
GPUDevice::AdapterInfo& ai = ret.emplace_back();
|
||||
ai.driver_type = GPUDriverType::Unknown;
|
||||
ai.max_multisamples = 8;
|
||||
ai.supports_sample_shading = true;
|
||||
ai.max_texture_size = 16384;
|
||||
ai.fullscreen_modes = std::move(fullscreen_modes);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool OpenGLContextSDL::Initialize(WindowInfo& wi, SurfaceHandle* surface, std::span<const Version> versions_to_try,
|
||||
bool share_context, Error* error)
|
||||
{
|
||||
|
||||
@@ -19,6 +19,7 @@ public:
|
||||
|
||||
static std::unique_ptr<OpenGLContext> Create(WindowInfo& wi, SurfaceHandle* surface,
|
||||
std::span<const Version> versions_to_try, Error* error);
|
||||
static GPUDevice::AdapterInfoList GetAdapterList(WindowInfoType window_type, Error* error);
|
||||
|
||||
void* GetProcAddress(const char* name) override;
|
||||
SurfaceHandle CreateSurface(WindowInfo& wi, Error* error = nullptr) override;
|
||||
|
||||
54
src/util/sdl_video_helpers.h
Normal file
54
src/util/sdl_video_helpers.h
Normal file
@@ -0,0 +1,54 @@
|
||||
// SPDX-FileCopyrightText: 2019-2026 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gpu_device.h"
|
||||
|
||||
#include "common/error.h"
|
||||
#include "common/log.h"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace SDLVideoHelpers {
|
||||
|
||||
inline std::vector<GPUDevice::ExclusiveFullscreenMode> GetFullscreenModeList()
|
||||
{
|
||||
int display_count = 0;
|
||||
const SDL_DisplayID* const displays = SDL_GetDisplays(&display_count);
|
||||
if (display_count <= 0)
|
||||
{
|
||||
GENERIC_LOG(Log::Channel::SDL, Log::Level::Error, Log::Color::Default, "SDL_GetDisplays() returned no displays: {}",
|
||||
SDL_GetError());
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<GPUDevice::ExclusiveFullscreenMode> modes;
|
||||
for (int i = 0; i < display_count; i++)
|
||||
{
|
||||
int dm_count = 0;
|
||||
const SDL_DisplayMode* const* const dms = SDL_GetFullscreenDisplayModes(displays[i], &dm_count);
|
||||
if (dm_count <= 0)
|
||||
{
|
||||
GENERIC_LOG(Log::Channel::SDL, Log::Level::Error, Log::Color::Default,
|
||||
"SDL_GetFullscreenDisplayModes() returned no modes for display {}: {}", displays[i], SDL_GetError());
|
||||
continue;
|
||||
}
|
||||
|
||||
modes.reserve(modes.size() + static_cast<size_t>(dm_count));
|
||||
|
||||
for (int j = 0; j < dm_count; j++)
|
||||
{
|
||||
const SDL_DisplayMode* const dm = dms[j];
|
||||
const GPUDevice::ExclusiveFullscreenMode mode{static_cast<u32>(dm->w), static_cast<u32>(dm->h), dm->refresh_rate};
|
||||
if (std::ranges::find(modes, mode) == modes.end())
|
||||
modes.push_back(mode);
|
||||
}
|
||||
}
|
||||
|
||||
return modes;
|
||||
}
|
||||
|
||||
} // namespace SDLVideoHelpers
|
||||
@@ -92,6 +92,7 @@
|
||||
<ClInclude Include="postprocessing_shader_fx.h" />
|
||||
<ClInclude Include="postprocessing_shader_glsl.h" />
|
||||
<ClInclude Include="postprocessing_shader_slang.h" />
|
||||
<ClInclude Include="sdl_video_helpers.h" />
|
||||
<ClInclude Include="sdl_input_source.h" />
|
||||
<ClInclude Include="shadergen.h" />
|
||||
<ClInclude Include="shiftjis.h" />
|
||||
|
||||
@@ -82,6 +82,7 @@
|
||||
<ClInclude Include="core_audio_stream.h" />
|
||||
<ClInclude Include="vulkan_headers.h" />
|
||||
<ClInclude Include="gpu_types.h" />
|
||||
<ClInclude Include="sdl_video_helpers.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="state_wrapper.cpp" />
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "common/log.h"
|
||||
|
||||
#ifdef ENABLE_SDL
|
||||
#include "sdl_video_helpers.h"
|
||||
#include <SDL3/SDL_vulkan.h>
|
||||
#endif
|
||||
|
||||
@@ -58,6 +59,8 @@ static void LockedDestroyVulkanInstance();
|
||||
static bool SelectInstanceExtensions(VulkanDevice::ExtensionList* extension_list, WindowInfoType wtype,
|
||||
bool debug_instance, Error* error);
|
||||
|
||||
static std::vector<GPUDevice::ExclusiveFullscreenMode> EnumerateFullscreenModes(WindowInfoType wtype);
|
||||
|
||||
VKAPI_ATTR static VkBool32 VKAPI_CALL DebugMessengerCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
|
||||
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||
@@ -597,6 +600,12 @@ void VulkanLoader::LockedReleaseVulkanInstance()
|
||||
// We specifically keep the instance around even after releasing it.
|
||||
// Both AMD on Windows and Mesa leak a few tens of megabytes for every instance...
|
||||
DEV_LOG("Released Vulkan instance, reference count {}", s_locals.reference_count);
|
||||
|
||||
#ifdef ENABLE_SDL
|
||||
// SDL Vulkan kinda breaks OpenGL contexts if the instance isn't destroyed...
|
||||
if (s_locals.window_type == WindowInfoType::SDL && s_locals.reference_count == 0)
|
||||
LockedDestroyVulkanInstance();
|
||||
#endif
|
||||
}
|
||||
|
||||
void VulkanLoader::LockedDestroyVulkanInstance()
|
||||
@@ -735,6 +744,16 @@ VulkanLoader::GPUList VulkanLoader::EnumerateGPUs(Error* error)
|
||||
return gpus;
|
||||
}
|
||||
|
||||
std::vector<GPUDevice::ExclusiveFullscreenMode> VulkanLoader::EnumerateFullscreenModes(WindowInfoType wtype)
|
||||
{
|
||||
#ifdef ENABLE_SDL
|
||||
if (wtype == WindowInfoType::SDL)
|
||||
return SDLVideoHelpers::GetFullscreenModeList();
|
||||
#endif
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool VulkanLoader::IsSuitableDefaultRenderer(WindowInfoType window_type)
|
||||
{
|
||||
#ifdef __ANDROID__
|
||||
@@ -834,6 +853,7 @@ GPUDriverType VulkanLoader::GuessDriverType(const VkPhysicalDeviceProperties& de
|
||||
std::optional<GPUDevice::AdapterInfoList> VulkanLoader::GetAdapterList(WindowInfoType window_type, Error* error)
|
||||
{
|
||||
std::optional<GPUDevice::AdapterInfoList> ret;
|
||||
std::vector<GPUDevice::ExclusiveFullscreenMode> fullscreen_modes;
|
||||
GPUList gpus;
|
||||
{
|
||||
const std::lock_guard lock(s_locals.mutex);
|
||||
@@ -842,6 +862,7 @@ std::optional<GPUDevice::AdapterInfoList> VulkanLoader::GetAdapterList(WindowInf
|
||||
if (s_locals.instance != VK_NULL_HANDLE)
|
||||
{
|
||||
gpus = EnumerateGPUs(error);
|
||||
fullscreen_modes = EnumerateFullscreenModes(window_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -851,6 +872,7 @@ std::optional<GPUDevice::AdapterInfoList> VulkanLoader::GetAdapterList(WindowInf
|
||||
return ret;
|
||||
|
||||
gpus = EnumerateGPUs(error);
|
||||
fullscreen_modes = EnumerateFullscreenModes(window_type);
|
||||
|
||||
LockedReleaseVulkanInstance();
|
||||
}
|
||||
@@ -858,8 +880,18 @@ std::optional<GPUDevice::AdapterInfoList> VulkanLoader::GetAdapterList(WindowInf
|
||||
|
||||
ret.emplace();
|
||||
ret->reserve(gpus.size());
|
||||
for (auto& [physical_device, adapter_info] : gpus)
|
||||
ret->push_back(std::move(adapter_info));
|
||||
for (size_t i = 0; i < gpus.size(); i++)
|
||||
{
|
||||
GPUDevice::AdapterInfo& ai = gpus[i].second;
|
||||
|
||||
// splat fullscreen modes across gpus
|
||||
if (i == (gpus.size() - 1))
|
||||
ai.fullscreen_modes = std::move(fullscreen_modes);
|
||||
else
|
||||
ai.fullscreen_modes = fullscreen_modes;
|
||||
|
||||
ret->push_back(std::move(ai));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user