forked from stenzek/duckstation
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgraphicssettingswidget.cpp
More file actions
1300 lines (1176 loc) · 80.4 KB
/
graphicssettingswidget.cpp
File metadata and controls
1300 lines (1176 loc) · 80.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
#include "graphicssettingswidget.h"
#include "qtutils.h"
#include "settingswindow.h"
#include "settingwidgetbinder.h"
#include "ui_texturereplacementsettingsdialog.h"
#include "core/fullscreen_ui.h"
#include "core/game_database.h"
#include "core/gpu.h"
#include "core/settings.h"
#include "util/imgui_manager.h"
#include "util/ini_settings_interface.h"
#include "util/media_capture.h"
#include "common/error.h"
#include <QtCore/QDir>
#include <QtWidgets/QDialog>
#include <QtWidgets/QFileDialog>
#include <QtWidgets/QInputDialog>
#include <algorithm>
#include "moc_graphicssettingswidget.cpp"
static QVariant GetMSAAModeValue(uint multisamples, bool ssaa)
{
const uint userdata = (multisamples & 0x7FFFFFFFu) | (static_cast<uint>(ssaa) << 31);
return QVariant(userdata);
}
static void DecodeMSAAModeValue(const QVariant& userdata, uint* multisamples, bool* ssaa)
{
bool ok;
const uint value = userdata.toUInt(&ok);
if (!ok || value == 0)
{
*multisamples = 1;
*ssaa = false;
return;
}
*multisamples = value & 0x7FFFFFFFu;
*ssaa = (value & (1u << 31)) != 0u;
}
GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget* parent)
: QWidget(parent), m_dialog(dialog)
{
SettingsInterface* sif = dialog->getSettingsInterface();
m_ui.setupUi(this);
setupAdditionalUi();
removePlatformSpecificUi();
// Rendering Tab
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.renderer, "GPU", "Renderer", &Settings::ParseRendererName,
&Settings::GetRendererName, &Settings::GetRendererDisplayName,
Settings::DEFAULT_GPU_RENDERER, GPURenderer::Count);
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.textureFiltering, "GPU", "TextureFilter",
&Settings::ParseTextureFilterName, &Settings::GetTextureFilterName,
&Settings::GetTextureFilterDisplayName,
Settings::DEFAULT_GPU_TEXTURE_FILTER, GPUTextureFilter::Count);
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.spriteTextureFiltering, "GPU", "SpriteTextureFilter",
&Settings::ParseTextureFilterName, &Settings::GetTextureFilterName,
&Settings::GetTextureFilterDisplayName,
Settings::DEFAULT_GPU_TEXTURE_FILTER, GPUTextureFilter::Count);
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.gpuDitheringMode, "GPU", "DitheringMode",
&Settings::ParseGPUDitheringModeName, &Settings::GetGPUDitheringModeName,
&Settings::GetGPUDitheringModeDisplayName,
Settings::DEFAULT_GPU_DITHERING_MODE, GPUDitheringMode::MaxCount);
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.gpuDownsampleMode, "GPU", "DownsampleMode",
&Settings::ParseDownsampleModeName, &Settings::GetDownsampleModeName,
&Settings::GetDownsampleModeDisplayName,
Settings::DEFAULT_GPU_DOWNSAMPLE_MODE, GPUDownsampleMode::Count);
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.displayAspectRatio, "Display", "AspectRatio",
&Settings::ParseDisplayAspectRatio, &Settings::GetDisplayAspectRatioName,
&Settings::GetDisplayAspectRatioDisplayName,
Settings::DEFAULT_DISPLAY_ASPECT_RATIO, DisplayAspectRatio::Count);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.customAspectRatioNumerator, "Display",
"CustomAspectRatioNumerator", 1);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.customAspectRatioDenominator, "Display",
"CustomAspectRatioDenominator", 1);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.widescreenHack, "GPU", "WidescreenHack", false);
SettingWidgetBinder::BindWidgetToEnumSetting(
sif, m_ui.displayDeinterlacing, "GPU", "DeinterlacingMode", &Settings::ParseDisplayDeinterlacingMode,
&Settings::GetDisplayDeinterlacingModeName, &Settings::GetDisplayDeinterlacingModeDisplayName,
Settings::DEFAULT_DISPLAY_DEINTERLACING_MODE, DisplayDeinterlacingMode::Count);
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.displayCropMode, "Display", "CropMode",
&Settings::ParseDisplayCropMode, &Settings::GetDisplayCropModeName,
&Settings::GetDisplayCropModeDisplayName,
Settings::DEFAULT_DISPLAY_CROP_MODE, DisplayCropMode::MaxCount);
SettingWidgetBinder::BindWidgetToEnumSetting(
sif, m_ui.displayScaling, "Display", "Scaling", &Settings::ParseDisplayScaling, &Settings::GetDisplayScalingName,
&Settings::GetDisplayScalingDisplayName, Settings::DEFAULT_DISPLAY_SCALING, DisplayScalingMode::Count);
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.displayScaling24Bit, "Display", "Scaling24Bit",
&Settings::ParseDisplayScaling, &Settings::GetDisplayScalingName,
&Settings::GetDisplayScalingDisplayName,
Settings::DEFAULT_DISPLAY_SCALING, DisplayScalingMode::Count);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.gpuDownsampleScale, "GPU", "DownsampleScale", 1);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pgxpEnable, "GPU", "PGXPEnable", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pgxpDepthBuffer, "GPU", "PGXPDepthBuffer", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.force43For24Bit, "Display", "Force4_3For24Bit", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.chromaSmoothingFor24Bit, "GPU", "ChromaSmoothing24Bit", false);
connect(m_ui.renderer, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&GraphicsSettingsWidget::updateRendererDependentOptions);
connect(m_ui.textureFiltering, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&GraphicsSettingsWidget::updateResolutionDependentOptions);
connect(m_ui.displayAspectRatio, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&GraphicsSettingsWidget::onAspectRatioChanged);
connect(m_ui.gpuDownsampleMode, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&GraphicsSettingsWidget::onDownsampleModeChanged);
connect(m_ui.pgxpEnable, &QCheckBox::checkStateChanged, this, &GraphicsSettingsWidget::updatePGXPSettingsEnabled);
SettingWidgetBinder::SetAvailability(m_ui.renderer,
!m_dialog->hasGameTrait(GameDatabase::Trait::ForceSoftwareRenderer));
SettingWidgetBinder::SetAvailability(m_ui.resolutionScale,
!m_dialog->hasGameTrait(GameDatabase::Trait::DisableUpscaling));
SettingWidgetBinder::SetAvailability(m_ui.textureFiltering,
!m_dialog->hasGameTrait(GameDatabase::Trait::DisableTextureFiltering));
SettingWidgetBinder::SetAvailability(m_ui.spriteTextureFiltering,
!m_dialog->hasGameTrait(GameDatabase::Trait::DisableTextureFiltering) ||
!m_dialog->hasGameTrait(GameDatabase::Trait::DisableSpriteTextureFiltering));
SettingWidgetBinder::SetAvailability(m_ui.pgxpEnable, !m_dialog->hasGameTrait(GameDatabase::Trait::DisablePGXP));
SettingWidgetBinder::SetAvailability(m_ui.pgxpDepthBuffer,
!m_dialog->hasGameTrait(GameDatabase::Trait::DisablePGXPDepthBuffer));
SettingWidgetBinder::SetAvailability(m_ui.widescreenHack,
!m_dialog->hasGameTrait(GameDatabase::Trait::DisableWidescreen));
// Advanced Tab
SettingWidgetBinder::BindWidgetToEnumSetting(
sif, m_ui.exclusiveFullscreenControl, "Display", "ExclusiveFullscreenControl",
&Settings::ParseDisplayExclusiveFullscreenControl, &Settings::GetDisplayExclusiveFullscreenControlName,
&Settings::GetDisplayExclusiveFullscreenControlDisplayName, Settings::DEFAULT_DISPLAY_EXCLUSIVE_FULLSCREEN_CONTROL,
DisplayExclusiveFullscreenControl::Count);
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.displayAlignment, "Display", "Alignment",
&Settings::ParseDisplayAlignment, &Settings::GetDisplayAlignmentName,
&Settings::GetDisplayAlignmentDisplayName,
Settings::DEFAULT_DISPLAY_ALIGNMENT, DisplayAlignment::Count);
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.displayRotation, "Display", "Rotation",
&Settings::ParseDisplayRotation, &Settings::GetDisplayRotationName,
&Settings::GetDisplayRotationDisplayName,
Settings::DEFAULT_DISPLAY_ROTATION, DisplayRotation::Count);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableMailboxPresentation, "Display",
"DisableMailboxPresentation", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.automaticallyResizeWindow, "Display", "AutoResizeWindow",
false);
#ifdef _WIN32
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.blitSwapChain, "Display", "UseBlitSwapChain", false);
#endif
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.gpuLineDetectMode, "GPU", "LineDetectMode",
&Settings::ParseLineDetectModeName, &Settings::GetLineDetectModeName,
&Settings::GetLineDetectModeDisplayName,
Settings::DEFAULT_GPU_LINE_DETECT_MODE, GPULineDetectMode::Count);
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.gpuWireframeMode, "GPU", "WireframeMode",
Settings::ParseGPUWireframeMode, Settings::GetGPUWireframeModeName,
&Settings::GetGPUWireframeModeDisplayName,
Settings::DEFAULT_GPU_WIREFRAME_MODE, GPUWireframeMode::Count);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.gpuThread, "GPU", "UseThread", true);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.maxQueuedFrames, "GPU", "MaxQueuedFrames",
Settings::DEFAULT_GPU_MAX_QUEUED_FRAMES);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.scaledInterlacing, "GPU", "ScaledInterlacing", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.useSoftwareRendererForReadbacks, "GPU",
"UseSoftwareRendererForReadbacks", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.forceRoundedTexcoords, "GPU", "ForceRoundTextureCoordinates",
false);
connect(m_ui.gpuThread, &QCheckBox::checkStateChanged, this, &GraphicsSettingsWidget::onGPUThreadChanged);
SettingWidgetBinder::SetAvailability(m_ui.scaledInterlacing,
!m_dialog->hasGameTrait(GameDatabase::Trait::DisableScaledInterlacing));
SettingWidgetBinder::SetForceEnabled(m_ui.useSoftwareRendererForReadbacks,
m_dialog->hasGameTrait(GameDatabase::Trait::ForceSoftwareRendererForReadbacks));
SettingWidgetBinder::SetForceEnabled(
m_ui.forceRoundedTexcoords, m_dialog->hasGameTrait(GameDatabase::Trait::ForceRoundUpscaledTextureCoordinates));
// PGXP Tab
SettingWidgetBinder::BindWidgetToFloatSetting(sif, m_ui.pgxpGeometryTolerance, "GPU", "PGXPTolerance", -1.0f);
SettingWidgetBinder::BindWidgetToFloatSetting(sif, m_ui.pgxpDepthClearThreshold, "GPU", "PGXPDepthThreshold",
Settings::DEFAULT_GPU_PGXP_DEPTH_THRESHOLD);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pgxpTextureCorrection, "GPU", "PGXPTextureCorrection", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pgxpColorCorrection, "GPU", "PGXPColorCorrection", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pgxpCulling, "GPU", "PGXPCulling", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pgxpPreserveProjPrecision, "GPU", "PGXPPreserveProjFP", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pgxpCPU, "GPU", "PGXPCPU", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pgxpVertexCache, "GPU", "PGXPVertexCache", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pgxpDisableOn2DPolygons, "GPU", "PGXPDisableOn2DPolygons",
false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pgxpTransparentDepthTest, "GPU", "PGXPTransparentDepthTest",
false);
connect(m_ui.pgxpTextureCorrection, &QCheckBox::checkStateChanged, this,
&GraphicsSettingsWidget::updatePGXPSettingsEnabled);
connect(m_ui.pgxpDepthBuffer, &QCheckBox::checkStateChanged, this,
&GraphicsSettingsWidget::updatePGXPSettingsEnabled);
SettingWidgetBinder::SetAvailability(m_ui.pgxpTextureCorrection,
!m_dialog->hasGameTrait(GameDatabase::Trait::DisablePGXPTextureCorrection));
SettingWidgetBinder::SetAvailability(m_ui.pgxpColorCorrection,
!m_dialog->hasGameTrait(GameDatabase::Trait::DisablePGXPColorCorrection));
SettingWidgetBinder::SetAvailability(m_ui.pgxpCulling,
!m_dialog->hasGameTrait(GameDatabase::Trait::DisablePGXPCulling));
SettingWidgetBinder::SetForceEnabled(m_ui.pgxpCPU, m_dialog->hasGameTrait(GameDatabase::Trait::ForcePGXPCPUMode));
SettingWidgetBinder::SetForceEnabled(m_ui.pgxpVertexCache,
m_dialog->hasGameTrait(GameDatabase::Trait::ForcePGXPVertexCache));
SettingWidgetBinder::SetForceEnabled(m_ui.pgxpDisableOn2DPolygons,
m_dialog->hasGameTrait(GameDatabase::Trait::DisablePGXPOn2DPolygons));
if (auto dbentry = m_dialog->getDatabaseEntry(); dbentry && dbentry->gpu_pgxp_preserve_proj_fp.has_value())
{
if (*dbentry->gpu_pgxp_preserve_proj_fp)
SettingWidgetBinder::SetForceEnabled(m_ui.pgxpPreserveProjPrecision, true);
else
SettingWidgetBinder::SetAvailability(m_ui.pgxpPreserveProjPrecision, false);
}
// OSD Tab
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.osdScale, "Display", "OSDScale", 100);
SettingWidgetBinder::BindWidgetToFloatSetting(sif, m_ui.osdMargin, "Display", "OSDMargin",
ImGuiManager::DEFAULT_SCREEN_MARGIN);
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.fullscreenUITheme, "UI", "FullscreenUITheme");
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showOSDMessages, "Display", "ShowOSDMessages", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showFPS, "Display", "ShowFPS", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showSpeed, "Display", "ShowSpeed", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showResolution, "Display", "ShowResolution", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showCPU, "Display", "ShowCPU", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showGPU, "Display", "ShowGPU", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showInput, "Display", "ShowInputs", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showGPUStatistics, "Display", "ShowGPUStatistics", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showLatencyStatistics, "Display", "ShowLatencyStatistics",
false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showStatusIndicators, "Display", "ShowStatusIndicators", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showFrameTimes, "Display", "ShowFrameTimes", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showSettings, "Display", "ShowEnhancements", false);
connect(m_ui.fullscreenUITheme, QOverload<int>::of(&QComboBox::currentIndexChanged), g_emu_thread,
&EmuThread::updateFullscreenUITheme);
// Capture Tab
SettingWidgetBinder::BindWidgetToEnumSetting(
sif, m_ui.screenshotSize, "Display", "ScreenshotMode", &Settings::ParseDisplayScreenshotMode,
&Settings::GetDisplayScreenshotModeName, &Settings::GetDisplayScreenshotModeDisplayName,
Settings::DEFAULT_DISPLAY_SCREENSHOT_MODE, DisplayScreenshotMode::Count);
SettingWidgetBinder::BindWidgetToEnumSetting(
sif, m_ui.screenshotFormat, "Display", "ScreenshotFormat", &Settings::ParseDisplayScreenshotFormat,
&Settings::GetDisplayScreenshotFormatName, &Settings::GetDisplayScreenshotFormatDisplayName,
Settings::DEFAULT_DISPLAY_SCREENSHOT_FORMAT, DisplayScreenshotFormat::Count);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.screenshotQuality, "Display", "ScreenshotQuality",
Settings::DEFAULT_DISPLAY_SCREENSHOT_QUALITY);
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.mediaCaptureBackend, "MediaCapture", "Backend",
&MediaCapture::ParseBackendName, &MediaCapture::GetBackendName,
&MediaCapture::GetBackendDisplayName,
Settings::DEFAULT_MEDIA_CAPTURE_BACKEND, MediaCaptureBackend::MaxCount);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableVideoCapture, "MediaCapture", "VideoCapture", true);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.videoCaptureWidth, "MediaCapture", "VideoWidth",
Settings::DEFAULT_MEDIA_CAPTURE_VIDEO_WIDTH);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.videoCaptureHeight, "MediaCapture", "VideoHeight",
Settings::DEFAULT_MEDIA_CAPTURE_VIDEO_HEIGHT);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.videoCaptureResolutionAuto, "MediaCapture", "VideoAutoSize",
false);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.videoCaptureBitrate, "MediaCapture", "VideoBitrate",
Settings::DEFAULT_MEDIA_CAPTURE_VIDEO_BITRATE);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableVideoCaptureArguments, "MediaCapture",
"VideoCodecUseArgs", false);
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.videoCaptureArguments, "MediaCapture", "AudioCodecArgs");
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableAudioCapture, "MediaCapture", "AudioCapture", true);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.audioCaptureBitrate, "MediaCapture", "AudioBitrate",
Settings::DEFAULT_MEDIA_CAPTURE_AUDIO_BITRATE);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableVideoCaptureArguments, "MediaCapture",
"VideoCodecUseArgs", false);
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.audioCaptureArguments, "MediaCapture", "AudioCodecArgs");
connect(m_ui.mediaCaptureBackend, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&GraphicsSettingsWidget::onMediaCaptureBackendChanged);
connect(m_ui.enableVideoCapture, &QCheckBox::checkStateChanged, this,
&GraphicsSettingsWidget::onMediaCaptureVideoEnabledChanged);
connect(m_ui.videoCaptureResolutionAuto, &QCheckBox::checkStateChanged, this,
&GraphicsSettingsWidget::onMediaCaptureVideoAutoResolutionChanged);
connect(m_ui.enableAudioCapture, &QCheckBox::checkStateChanged, this,
&GraphicsSettingsWidget::onMediaCaptureAudioEnabledChanged);
// Texture Replacements Tab
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableTextureCache, "GPU", "EnableTextureCache", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.preloadTextureReplacements, "TextureReplacements",
"PreloadTextures", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableTextureReplacements, "TextureReplacements",
"EnableTextureReplacements", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.alwaysTrackUploads, "TextureReplacements",
"AlwaysTrackUploads", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableTextureDumping, "TextureReplacements", "DumpTextures",
false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.dumpReplacedTextures, "TextureReplacements",
"DumpReplacedTextures", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.vramWriteReplacement, "TextureReplacements",
"EnableVRAMWriteReplacements", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.vramWriteDumping, "TextureReplacements", "DumpVRAMWrites",
false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.useOldMDECRoutines, "Hacks", "UseOldMDECRoutines", false);
if (!m_dialog->isPerGameSettings())
{
SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.texturesDirectory, m_ui.texturesDirectoryBrowse,
tr("Select Textures Directory"), m_ui.texturesDirectoryOpen,
m_ui.texturesDirectoryReset, "Folders", "Textures",
Path::Combine(EmuFolders::DataRoot, "textures"));
}
else
{
m_ui.tabTextureReplacementsLayout->removeWidget(m_ui.texturesDirectoryGroup);
delete m_ui.texturesDirectoryGroup;
m_ui.texturesDirectoryGroup = nullptr;
m_ui.texturesDirectoryBrowse = nullptr;
m_ui.texturesDirectoryOpen = nullptr;
m_ui.texturesDirectoryReset = nullptr;
m_ui.texturesDirectoryLabel = nullptr;
m_ui.texturesDirectory = nullptr;
}
connect(m_ui.enableTextureCache, &QCheckBox::checkStateChanged, this,
&GraphicsSettingsWidget::onEnableTextureCacheChanged);
connect(m_ui.enableTextureReplacements, &QCheckBox::checkStateChanged, this,
&GraphicsSettingsWidget::onEnableAnyTextureReplacementsChanged);
connect(m_ui.enableTextureDumping, &QCheckBox::checkStateChanged, this,
&GraphicsSettingsWidget::onEnableAnyTextureDumpingChanged);
connect(m_ui.vramWriteReplacement, &QCheckBox::checkStateChanged, this,
&GraphicsSettingsWidget::onEnableAnyTextureReplacementsChanged);
connect(m_ui.vramWriteDumping, &QCheckBox::checkStateChanged, this,
&GraphicsSettingsWidget::onEnableAnyTextureDumpingChanged);
connect(m_ui.textureReplacementOptions, &QPushButton::clicked, this,
&GraphicsSettingsWidget::onTextureReplacementOptionsClicked);
// Debugging Tab
SettingWidgetBinder::BindWidgetToEnumSetting(
sif, m_ui.gpuDumpCompressionMode, "GPU", "DumpCompressionMode", &Settings::ParseGPUDumpCompressionMode,
&Settings::GetGPUDumpCompressionModeName, &Settings::GetGPUDumpCompressionModeDisplayName,
Settings::DEFAULT_GPU_DUMP_COMPRESSION_MODE, GPUDumpCompressionMode::MaxCount);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.gpuDumpFastReplayMode, "GPU", "DumpFastReplayMode", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.useDebugDevice, "GPU", "UseDebugDevice", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.useGPUBasedValidation, "GPU", "UseGPUBasedValidation", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.preferGLESContext, "GPU", "PreferGLESContext",
Settings::DEFAULT_GPU_PREFER_GLES_CONTEXT);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableShaderCache, "GPU", "DisableShaderCache", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableDualSource, "GPU", "DisableDualSourceBlend", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableFramebufferFetch, "GPU", "DisableFramebufferFetch",
false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableTextureBuffers, "GPU", "DisableTextureBuffers", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableTextureCopyToSelf, "GPU", "DisableTextureCopyToSelf",
false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableMemoryImport, "GPU", "DisableMemoryImport", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableRasterOrderViews, "GPU", "DisableRasterOrderViews",
false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableComputeShaders, "GPU", "DisableComputeShaders", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableCompressedTextures, "GPU", "DisableCompressedTextures",
false);
// Init all dependent options.
updateRendererDependentOptions();
onAspectRatioChanged();
onDownsampleModeChanged();
updateResolutionDependentOptions();
onMediaCaptureBackendChanged();
onMediaCaptureAudioEnabledChanged();
onMediaCaptureVideoEnabledChanged();
onEnableTextureCacheChanged();
onEnableAnyTextureReplacementsChanged();
onGPUThreadChanged();
onShowDebugSettingsChanged(QtHost::ShouldShowDebugOptions());
// Rendering Tab
dialog->registerWidgetHelp(
m_ui.renderer, tr("Renderer"), QString::fromUtf8(Settings::GetRendererDisplayName(Settings::DEFAULT_GPU_RENDERER)),
tr("Selects the backend to use for rendering the console/game visuals. <br>Depending on your system and hardware, "
"Direct3D 11 and OpenGL hardware backends may be available. <br>The software renderer offers the best "
"compatibility, but is the slowest and does not offer any enhancements."));
dialog->registerWidgetHelp(
m_ui.adapter, tr("Adapter"), tr("(Default)"),
tr("If your system contains multiple GPUs or adapters, you can select which GPU you wish to use for the hardware "
"renderers. <br>This option is only supported in Direct3D and Vulkan. OpenGL will always use the default "
"device."));
dialog->registerWidgetHelp(
m_ui.resolutionScale, tr("Internal Resolution"), "1x",
tr("Setting this beyond 1x will enhance the resolution of rendered 3D polygons and lines. Only applies "
"to the hardware backends. <br>This option is usually safe, with most games looking fine at "
"higher resolutions. Higher resolutions require a more powerful GPU."));
dialog->registerWidgetHelp(
m_ui.gpuDownsampleMode, tr("Down-Sampling"), tr("Disabled"),
tr("Downsamples the rendered image prior to displaying it. Can improve overall image quality in mixed 2D/3D games, "
"but should be disabled for pure 3D games."));
dialog->registerWidgetHelp(m_ui.gpuDownsampleScale, tr("Down-Sampling Display Scale"), tr("1x"),
tr("Selects the resolution scale that will be applied to the final image. 1x will "
"downsample to the original console resolution."));
dialog->registerWidgetHelp(
m_ui.textureFiltering, tr("Texture Filtering"),
QString::fromUtf8(Settings::GetTextureFilterDisplayName(Settings::DEFAULT_GPU_TEXTURE_FILTER)),
tr("Smooths out the blockiness of magnified textures on 3D objects by using filtering. <br>Will have a "
"greater effect on higher resolution scales."));
dialog->registerWidgetHelp(
m_ui.spriteTextureFiltering, tr("Sprite Texture Filtering"),
QString::fromUtf8(Settings::GetTextureFilterDisplayName(Settings::DEFAULT_GPU_TEXTURE_FILTER)),
tr("Smooths out the blockiness of magnified textures on 2D objects by using filtering. This filter only applies to "
"sprites and other 2D elements, such as the HUD."));
dialog->registerWidgetHelp(
m_ui.gpuDitheringMode, tr("Dithering"),
QString::fromUtf8(Settings::GetGPUDitheringModeDisplayName(Settings::DEFAULT_GPU_DITHERING_MODE)),
tr("Controls how dithering is applied in the emulated GPU. True Color disables dithering and produces the nicest "
"looking gradients. Scaled options make the dither pattern less noticeable at higher resolutions. Shader "
"Blending options perform blending in software, and are more accurate but have a <strong>significant</strong> "
"performance penalty."));
dialog->registerWidgetHelp(
m_ui.displayAspectRatio, tr("Aspect Ratio"),
QString::fromUtf8(Settings::GetDisplayAspectRatioDisplayName(Settings::DEFAULT_DISPLAY_ASPECT_RATIO)),
tr("Changes the aspect ratio used to display the console's output to the screen. The default is Auto (Game Native) "
"which automatically adjusts the aspect ratio to match how a game would be shown on a typical TV of the era."));
dialog->registerWidgetHelp(
m_ui.displayDeinterlacing, tr("Deinterlacing"),
QString::fromUtf8(Settings::GetDisplayDeinterlacingModeDisplayName(Settings::DEFAULT_DISPLAY_DEINTERLACING_MODE)),
tr("Determines which algorithm is used to convert interlaced frames to progressive for display on your system. "
"Using progressive rendering provides the best quality output, but some games require interlaced rendering."));
dialog->registerWidgetHelp(
m_ui.displayCropMode, tr("Crop"),
QString::fromUtf8(Settings::GetDisplayCropModeDisplayName(Settings::DEFAULT_DISPLAY_CROP_MODE)),
tr("Determines how much of the area typically not visible on a consumer TV set to crop/hide. Some games display "
"content in the overscan area, or use it for screen effects. May not display correctly with the \"All Borders\" "
"setting. \"Only Overscan\" offers a good compromise between stability and hiding black borders."));
dialog->registerWidgetHelp(
m_ui.displayScaling, tr("Scaling"), tr("Bilinear (Smooth)"),
tr("Determines how the emulated console's output is upscaled or downscaled to your monitor's resolution."));
dialog->registerWidgetHelp(
m_ui.displayScaling24Bit, tr("FMV Scaling"), tr("Bilinear (Smooth)"),
tr("Determines the scaling algorithm used when 24-bit content is active, typically FMVs."));
dialog->registerWidgetHelp(
m_ui.widescreenHack, tr("Widescreen Rendering"), tr("Unchecked"),
tr("Scales vertex positions in screen-space to a widescreen aspect ratio, essentially "
"increasing the field of view from 4:3 to the chosen display aspect ratio in 3D games. <b><u>May not be "
"compatible with all games.</u></b>"));
dialog->registerWidgetHelp(m_ui.pgxpEnable, tr("PGXP Geometry Correction"), tr("Unchecked"),
tr("Reduces \"wobbly\" polygons and \"warping\" textures that are common in PS1 games. "
"<strong>May not be compatible with all games.</strong>"));
dialog->registerWidgetHelp(
m_ui.pgxpDepthBuffer, tr("PGXP Depth Buffer"), tr("Unchecked"),
tr("Attempts to reduce polygon Z-fighting by testing pixels against the depth values from PGXP. Low compatibility, "
"but can work well in some games. Other games may need a threshold adjustment."));
dialog->registerWidgetHelp(
m_ui.force43For24Bit, tr("Force 4:3 For FMVs"), tr("Unchecked"),
tr("Switches back to 4:3 display aspect ratio when displaying 24-bit content, usually FMVs."));
dialog->registerWidgetHelp(m_ui.chromaSmoothingFor24Bit, tr("FMV Chroma Smoothing"), tr("Unchecked"),
tr("Smooths out blockyness between colour transitions in 24-bit content, usually FMVs."));
// Advanced Tab
dialog->registerWidgetHelp(m_ui.fullscreenMode, tr("Fullscreen Mode"), tr("Borderless Fullscreen"),
tr("Chooses the fullscreen resolution and frequency."));
dialog->registerWidgetHelp(m_ui.exclusiveFullscreenControl, tr("Exclusive Fullscreen Control"), tr("Automatic"),
tr("Controls whether exclusive fullscreen can be utilized by Vulkan drivers."));
dialog->registerWidgetHelp(
m_ui.displayAlignment, tr("Position"),
QString::fromUtf8(Settings::GetDisplayAlignmentDisplayName(Settings::DEFAULT_DISPLAY_ALIGNMENT)),
tr("Determines the position on the screen when black borders must be added."));
dialog->registerWidgetHelp(
m_ui.disableMailboxPresentation, tr("Disable Mailbox Presentation"), tr("Unchecked"),
tr("Forces the use of FIFO over Mailbox presentation, i.e. double buffering instead of triple buffering. "
"Usually results in worse frame pacing."));
dialog->registerWidgetHelp(m_ui.automaticallyResizeWindow, tr("Automatically Resize Window"), tr("Unchecked"),
tr("Automatically resizes the window to match the internal resolution. <strong>For high "
"internal resolutions, this will create very large windows.</strong>"));
#ifdef _WIN32
dialog->registerWidgetHelp(m_ui.blitSwapChain, tr("Use Blit Swap Chain"), tr("Unchecked"),
tr("Uses a blit presentation model instead of flipping when using the Direct3D 11 "
"renderer. This usually results in slower performance, but may be required for some "
"streaming applications, or to uncap framerates on some systems."));
#endif
dialog->registerWidgetHelp(
m_ui.gpuLineDetectMode, tr("Line Detection"),
QString::fromUtf8(Settings::GetLineDetectModeDisplayName(Settings::DEFAULT_GPU_LINE_DETECT_MODE)),
tr("Attempts to detect one pixel high/wide lines that rely on non-upscaled rasterization "
"behavior, filling in gaps introduced by upscaling."));
dialog->registerWidgetHelp(
m_ui.msaaMode, tr("Multi-Sampling"), tr("Disabled"),
tr("Uses multi-sampled anti-aliasing when rendering 3D polygons. Can improve visuals with a lower performance "
"requirement compared to upscaling, <strong>but often introduces rendering errors.</strong>"));
dialog->registerWidgetHelp(m_ui.gpuWireframeMode, tr("Wireframe Mode"), tr("Disabled"),
tr("Draws a wireframe outline of the triangles rendered by the console's GPU, either as a "
"replacement or an overlay."));
dialog->registerWidgetHelp(m_ui.gpuThread, tr("Threaded Rendering"), tr("Checked"),
tr("Uses a second thread for drawing graphics. Provides a significant speed improvement "
"particularly with the software renderer, and is safe to use."));
dialog->registerWidgetHelp(m_ui.scaledInterlacing, tr("Scaled Interlacing"), tr("Checked"),
tr("Scales line skipping in interlaced rendering to the internal resolution. This makes "
"the combing less obvious at higher resolutions. Usually safe to enable."));
dialog->registerWidgetHelp(
m_ui.useSoftwareRendererForReadbacks, tr("Software Renderer Readbacks"), tr("Unchecked"),
tr("Runs the software renderer in parallel for VRAM readbacks. On some systems, this may result in greater "
"performance when using graphical enhancements with the hardware renderer."));
dialog->registerWidgetHelp(
m_ui.forceRoundedTexcoords, tr("Round Upscaled Texture Coordinates"), tr("Unchecked"),
tr("Rounds texture coordinates instead of flooring when upscaling. Can fix misaligned textures in some games, but "
"break others, and is incompatible with texture filtering."));
// PGXP Tab
dialog->registerWidgetHelp(
m_ui.pgxpGeometryTolerance, tr("Geometry Tolerance"), tr("-1.00px (Disabled)"),
tr("Discards precise geometry when it is found to be offset past the specified threshold. This can help with games "
"that have vertices significantly moved by PGXP, but is still a hack/workaround."));
dialog->registerWidgetHelp(m_ui.pgxpDepthClearThreshold, tr("Depth Clear Threshold"),
QStringLiteral("%1").arg(Settings::DEFAULT_GPU_PGXP_DEPTH_THRESHOLD),
tr("Determines the increase in depth that will result in the depth buffer being cleared. "
"Can help with depth issues in some games, but is still a hack/workaround."));
dialog->registerWidgetHelp(m_ui.pgxpTextureCorrection, tr("Perspective Correct Textures"), tr("Checked"),
tr("Uses perspective-correct interpolation for texture coordinates, straightening out "
"warped textures. Requires geometry correction enabled."));
dialog->registerWidgetHelp(
m_ui.pgxpColorCorrection, tr("Perspective Correct Colors"), tr("Unchecked"),
tr("Uses perspective-correct interpolation for vertex colors, which can improve visuals in some games, but cause "
"rendering errors in others. Requires geometry correction enabled."));
dialog->registerWidgetHelp(m_ui.pgxpCulling, tr("Culling Correction"), tr("Checked"),
tr("Increases the precision of polygon culling, reducing the number of holes in geometry. "
"Requires geometry correction enabled."));
dialog->registerWidgetHelp(
m_ui.pgxpPreserveProjPrecision, tr("Preserve Projection Precision"), tr("Unchecked"),
tr("Adds additional precision to PGXP data post-projection. May improve visuals in some games."));
dialog->registerWidgetHelp(m_ui.pgxpCPU, tr("CPU Mode"), tr("Unchecked"),
tr("Uses PGXP for all instructions, not just memory operations. Required for PGXP to "
"correct wobble in some games, but has a high performance cost."));
dialog->registerWidgetHelp(
m_ui.pgxpVertexCache, tr("Vertex Cache"), tr("Unchecked"),
tr("Uses screen-space vertex positions to obtain precise positions, instead of tracking memory accesses. Can "
"provide PGXP compatibility for some games, but <strong>generally provides no benefit.</strong>"));
dialog->registerWidgetHelp(m_ui.pgxpDisableOn2DPolygons, tr("Disable on 2D Polygons"), tr("Unchecked"),
tr("Uses native resolution coordinates for 2D polygons, instead of precise coordinates. "
"Can fix misaligned UI in some games, but otherwise should be left disabled. The game "
"database will enable this automatically when needed."));
dialog->registerWidgetHelp(m_ui.pgxpTransparentDepthTest, tr("Depth Test Transparent Polygons"), tr("Unchecked"),
tr("Enables depth testing for semi-transparent polygons. Usually these include shadows, "
"and tend to clip through the ground when depth testing is enabled. Depth writes for "
"semi-transparent polygons are disabled regardless of this setting."));
// OSD Tab
dialog->registerWidgetHelp(
m_ui.osdScale, tr("OSD Scale"), tr("100%"),
tr("Changes the size at which on-screen elements, including status and messages are displayed."));
dialog->registerWidgetHelp(m_ui.fullscreenUITheme, tr("Theme"), tr("Automatic"),
tr("Determines the theme to use for on-screen display elements and the Big Picture UI."));
dialog->registerWidgetHelp(m_ui.showOSDMessages, tr("Show OSD Messages"), tr("Checked"),
tr("Shows on-screen-display messages when events occur such as save states being "
"created/loaded, screenshots being taken, etc."));
dialog->registerWidgetHelp(m_ui.showResolution, tr("Show Resolution"), tr("Unchecked"),
tr("Shows the resolution of the game in the top-right corner of the display."));
dialog->registerWidgetHelp(
m_ui.showSpeed, tr("Show Emulation Speed"), tr("Unchecked"),
tr("Shows the current emulation speed of the system in the top-right corner of the display as a percentage."));
dialog->registerWidgetHelp(m_ui.showFPS, tr("Show FPS"), tr("Unchecked"),
tr("Shows the internal frame rate of the game in the top-right corner of the display."));
dialog->registerWidgetHelp(
m_ui.showCPU, tr("Show CPU Usage"), tr("Unchecked"),
tr("Shows the host's CPU usage of each system thread in the top-right corner of the display."));
dialog->registerWidgetHelp(m_ui.showGPU, tr("Show GPU Usage"), tr("Unchecked"),
tr("Shows the host's GPU usage in the top-right corner of the display."));
dialog->registerWidgetHelp(m_ui.showGPUStatistics, tr("Show GPU Statistics"), tr("Unchecked"),
tr("Shows information about the emulated GPU in the top-right corner of the display."));
dialog->registerWidgetHelp(
m_ui.showLatencyStatistics, tr("Show Latency Statistics"), tr("Unchecked"),
tr("Shows information about input and audio latency in the top-right corner of the display."));
dialog->registerWidgetHelp(
m_ui.showFrameTimes, tr("Show Frame Times"), tr("Unchecked"),
tr("Shows the history of frame rendering times as a graph in the top-right corner of the display."));
dialog->registerWidgetHelp(
m_ui.showInput, tr("Show Controller Input"), tr("Unchecked"),
tr("Shows the current controller state of the system in the bottom-left corner of the display."));
dialog->registerWidgetHelp(m_ui.showSettings, tr("Show Settings"), tr("Unchecked"),
tr("Shows a summary of current settings in the bottom-right corner of the display."));
dialog->registerWidgetHelp(m_ui.showStatusIndicators, tr("Show Status Indicators"), tr("Checked"),
tr("Shows indicators on screen when the system is not running in its \"normal\" state. "
"For example, fast forwarding, or being paused."));
// Capture Tab
dialog->registerWidgetHelp(m_ui.screenshotSize, tr("Screenshot Size"), tr("Screen Resolution"),
tr("Determines the resolution at which screenshots will be saved. Internal resolutions "
"preserve more detail at the cost of file size."));
dialog->registerWidgetHelp(
m_ui.screenshotFormat, tr("Screenshot Format"), tr("PNG"),
tr("Selects the format which will be used to save screenshots. JPEG produces smaller files, but loses detail."));
dialog->registerWidgetHelp(m_ui.screenshotQuality, tr("Screenshot Quality"),
QStringLiteral("%1%").arg(Settings::DEFAULT_DISPLAY_SCREENSHOT_QUALITY),
tr("Selects the quality at which screenshots will be compressed. Higher values preserve "
"more detail for JPEG, and reduce file size for PNG."));
dialog->registerWidgetHelp(
m_ui.mediaCaptureBackend, tr("Backend"),
QString::fromUtf8(MediaCapture::GetBackendDisplayName(Settings::DEFAULT_MEDIA_CAPTURE_BACKEND)),
tr("Selects the framework that is used to encode video/audio."));
dialog->registerWidgetHelp(m_ui.captureContainer, tr("Container"), tr("MP4"),
tr("Determines the file format used to contain the captured audio/video."));
dialog->registerWidgetHelp(m_ui.enableVideoCapture, tr("Capture Video"), tr("Checked"),
tr("Captures video to the chosen file when media capture is started. If unchecked, the "
"file will only contain audio."));
dialog->registerWidgetHelp(
m_ui.videoCaptureCodec, tr("Video Codec"), tr("Default"),
tr("Selects which Video Codec to be used for media capture. <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."));
dialog->registerWidgetHelp(
m_ui.videoCaptureResolutionAuto, tr("Automatic Resolution"), tr("Unchecked"),
tr("When checked, the video capture resolution will follows the internal resolution of the running "
"game. <b>Be careful when using this setting especially when you are upscaling, as higher internal "
"resolutions (above 4x) can cause system slowdown.</b>"));
dialog->registerWidgetHelp(m_ui.enableVideoCaptureArguments, tr("Enable Extra Video Arguments"), tr("Unchecked"),
tr("Allows you to pass arguments to the selected video codec."));
dialog->registerWidgetHelp(
m_ui.videoCaptureArguments, tr("Extra Video Arguments"), tr("Empty"),
tr("Parameters passed to the selected video codec.<br><b>You must use '=' to separate key from value and ':' to "
"separate two pairs from each other.</b><br>For example: \"crf = 21 : preset = veryfast\""));
dialog->registerWidgetHelp(m_ui.enableAudioCapture, tr("Capture Audio"), tr("Checked"),
tr("Captures audio to the chosen file when media capture is started. If unchecked, the "
"file will only contain video."));
dialog->registerWidgetHelp(
m_ui.audioCaptureCodec, tr("Audio Codec"), tr("Default"),
tr("Selects which Audio Codec to be used for media capture. <b>If unsure, leave it on default.<b>"));
dialog->registerWidgetHelp(m_ui.audioCaptureBitrate, tr("Audio Bitrate"), tr("128 kbps"),
tr("Sets the audio bitrate to be used."));
dialog->registerWidgetHelp(m_ui.enableAudioCaptureArguments, tr("Enable Extra Audio Arguments"), tr("Unchecked"),
tr("Allows you to pass arguments to the selected audio codec."));
dialog->registerWidgetHelp(
m_ui.audioCaptureArguments, tr("Extra Audio Arguments"), tr("Empty"),
tr("Parameters passed to the selected audio codec.<br><b>You must use '=' to separate key from value and ':' to "
"separate two pairs from each other.</b><br>For example: \"compression_level = 4 : joint_stereo = 1\""));
// Texture Replacements Tab
dialog->registerWidgetHelp(
m_ui.enableTextureCache, tr("Enable Texture Cache"), tr("Unchecked"),
tr("Enables caching of guest textures, required for texture replacement. <strong>The texture cache is currently "
"experimental, and may cause rendering errors in some games.</strong>"));
dialog->registerWidgetHelp(m_ui.preloadTextureReplacements, tr("Preload Texture Replacements"), tr("Unchecked"),
tr("Loads all replacement texture to RAM, reducing stuttering at runtime."));
dialog->registerWidgetHelp(m_ui.enableTextureReplacements, tr("Enable Texture Replacements"), tr("Unchecked"),
tr("Enables loading of replacement textures. Not compatible with all games."));
dialog->registerWidgetHelp(
m_ui.alwaysTrackUploads, tr("Always Track Uploads"), tr("Unchecked"),
tr("Forces texture upload tracking to be enabled regardless of whether it is needed. Reduces performance, but "
"allows toggling replacements on and off. <strong>Not required for replacements to load, </strong>normally "
"tracking is automatically enabled when needed."));
dialog->registerWidgetHelp(
m_ui.enableTextureDumping, tr("Enable Texture Dumping"), tr("Unchecked"),
tr("Enables dumping of textures to image files, which can be replaced. Not compatible with all games."));
dialog->registerWidgetHelp(m_ui.dumpReplacedTextures, tr("Dump Replaced Textures"), tr("Unchecked"),
tr("Dumps textures that have replacements already loaded."));
dialog->registerWidgetHelp(m_ui.vramWriteReplacement, tr("Enable VRAM Write Replacement"), tr("Unchecked"),
tr("Enables the replacement of background textures in supported games."));
dialog->registerWidgetHelp(m_ui.vramWriteDumping, tr("Enable VRAM Write Dumping"), tr("Unchecked"),
tr("Writes backgrounds that can be replaced to the dump directory."));
dialog->registerWidgetHelp(m_ui.useOldMDECRoutines, tr("Use Old MDEC Routines"), tr("Unchecked"),
tr("Enables the older, less accurate MDEC decoding routines. May be required for old "
"replacement backgrounds to match/load."));
// Debugging Tab
dialog->registerWidgetHelp(
m_ui.useDebugDevice, tr("Use Debug Device"), tr("Unchecked"),
tr("Enable debugging when supported by the host's renderer API. <strong>Only for developer use.</strong>"));
dialog->registerWidgetHelp(
m_ui.useGPUBasedValidation, tr("Use GPU-Based Validation"), tr("Unchecked"),
tr("Enable GPU-based validation when supported by the renderer API. <strong>Only for developer use.</strong>"));
dialog->registerWidgetHelp(
m_ui.preferGLESContext, tr("Prefer OpenGL ES Context"), tr("Unchecked"),
tr("Uses OpenGL ES even when desktop OpenGL is supported. May improve performance on some SBC drivers."));
dialog->registerWidgetHelp(
m_ui.disableShaderCache, tr("Disable Shader Cache"), tr("Unchecked"),
tr("Forces shaders to be compiled for every run of the program. <strong>Only for developer use.</strong>"));
dialog->registerWidgetHelp(m_ui.disableDualSource, tr("Disable Dual-Source Blending"), tr("Unchecked"),
tr("Prevents dual-source blending from being used. Useful for testing broken graphics "
"drivers. <strong>Only for developer use.</strong>"));
dialog->registerWidgetHelp(m_ui.disableFramebufferFetch, tr("Disable Framebuffer Fetch"), tr("Unchecked"),
tr("Prevents the framebuffer fetch extensions from being used. Useful for testing broken "
"graphics drivers. <strong>Only for developer use.</strong>"));
dialog->registerWidgetHelp(
m_ui.disableTextureBuffers, tr("Disable Texture Buffers"), tr("Unchecked"),
tr("Forces VRAM updates through texture updates, instead of texture buffers and draws. Useful for testing broken "
"graphics drivers. <strong>Only for developer use.</strong>"));
dialog->registerWidgetHelp(m_ui.disableTextureCopyToSelf, tr("Disable Texture Copies To Self"), tr("Unchecked"),
tr("Disables the use of self-copy updates for the VRAM texture. Useful for testing broken "
"graphics drivers. <strong>Only for developer use.</strong>"));
dialog->registerWidgetHelp(m_ui.disableMemoryImport, tr("Disable Memory Import"), tr("Unchecked"),
tr("Disables the use of host memory importing. Useful for testing broken graphics "
"drivers. <strong>Only for developer use.</strong>"));
dialog->registerWidgetHelp(m_ui.disableRasterOrderViews, tr("Disable Rasterizer Order Views"), tr("Unchecked"),
tr("Disables the use of rasterizer order views. Useful for testing broken graphics "
"drivers. <strong>Only for developer use.</strong>"));
dialog->registerWidgetHelp(m_ui.disableComputeShaders, tr("Disable Compute Shaders"), tr("Unchecked"),
tr("Disables the use of compute shaders. Useful for testing broken graphics drivers. "
"<strong>Only for developer use.</strong>"));
dialog->registerWidgetHelp(m_ui.disableCompressedTextures, tr("Disable Compressed Textures"), tr("Unchecked"),
tr("Disables the use of compressed textures. Useful for testing broken graphics drivers. "
"<strong>Only for developer use.</strong>"));
}
GraphicsSettingsWidget::~GraphicsSettingsWidget() = default;
void GraphicsSettingsWidget::setupAdditionalUi()
{
// OSD Tab
const std::vector<std::string_view> fsui_theme_names = FullscreenUI::GetThemeNames();
const std::span<const char* const> fsui_theme_values = FullscreenUI::GetThemeConfigNames();
for (size_t i = 0; i < fsui_theme_names.size(); i++)
{
m_ui.fullscreenUITheme->addItem(QtUtils::StringViewToQString(fsui_theme_names[i]),
QString::fromUtf8(fsui_theme_values[i]));
}
}
void GraphicsSettingsWidget::removePlatformSpecificUi()
{
#ifndef _WIN32
m_ui.advancedDisplayOptionsLayout->removeWidget(m_ui.blitSwapChain);
delete m_ui.blitSwapChain;
m_ui.blitSwapChain = nullptr;
#endif
}
GPURenderer GraphicsSettingsWidget::getEffectiveRenderer() const
{
return Settings::ParseRendererName(
m_dialog
->getEffectiveStringValue("GPU", "Renderer", Settings::GetRendererName(Settings::DEFAULT_GPU_RENDERER))
.c_str())
.value_or(Settings::DEFAULT_GPU_RENDERER);
}
bool GraphicsSettingsWidget::effectiveRendererIsHardware() const
{
return (getEffectiveRenderer() != GPURenderer::Software);
}
void GraphicsSettingsWidget::onShowDebugSettingsChanged(bool enabled)
{
m_ui.tabs->setTabVisible(TAB_INDEX_DEBUGGING, enabled);
}
void GraphicsSettingsWidget::updateRendererDependentOptions()
{
const GPURenderer renderer = getEffectiveRenderer();
const RenderAPI render_api = Settings::GetRenderAPIForRenderer(renderer);
const bool is_hardware = (renderer != GPURenderer::Software);
m_ui.resolutionScale->setEnabled(is_hardware && !m_dialog->hasGameTrait(GameDatabase::Trait::DisableUpscaling));
m_ui.resolutionScaleLabel->setEnabled(is_hardware && !m_dialog->hasGameTrait(GameDatabase::Trait::DisableUpscaling));
m_ui.msaaMode->setEnabled(is_hardware);
m_ui.msaaModeLabel->setEnabled(is_hardware);
m_ui.textureFiltering->setEnabled(is_hardware &&
!m_dialog->hasGameTrait(GameDatabase::Trait::DisableTextureFiltering));
m_ui.textureFilteringLabel->setEnabled(is_hardware &&
!m_dialog->hasGameTrait(GameDatabase::Trait::DisableTextureFiltering));
m_ui.spriteTextureFiltering->setEnabled(is_hardware &&
!m_dialog->hasGameTrait(GameDatabase::Trait::DisableTextureFiltering) &&
!m_dialog->hasGameTrait(GameDatabase::Trait::DisableSpriteTextureFiltering));
m_ui.spriteTextureFilteringLabel->setEnabled(
is_hardware && !m_dialog->hasGameTrait(GameDatabase::Trait::DisableTextureFiltering) &&
!m_dialog->hasGameTrait(GameDatabase::Trait::DisableSpriteTextureFiltering));
m_ui.gpuDownsampleLabel->setEnabled(is_hardware);
m_ui.gpuDownsampleMode->setEnabled(is_hardware);
m_ui.gpuDownsampleScale->setEnabled(is_hardware);
m_ui.gpuDitheringModeLabel->setEnabled(is_hardware);
m_ui.gpuDitheringMode->setEnabled(is_hardware);
m_ui.pgxpEnable->setEnabled(is_hardware && !m_dialog->hasGameTrait(GameDatabase::Trait::DisablePGXP));
m_ui.gpuLineDetectMode->setEnabled(is_hardware);
m_ui.gpuLineDetectModeLabel->setEnabled(is_hardware);
m_ui.gpuWireframeMode->setEnabled(is_hardware);
m_ui.gpuWireframeModeLabel->setEnabled(is_hardware);
m_ui.scaledInterlacing->setEnabled(is_hardware &&
!m_dialog->hasGameTrait(GameDatabase::Trait::DisableScaledInterlacing));
m_ui.useSoftwareRendererForReadbacks->setEnabled(
is_hardware && !m_dialog->hasGameTrait(GameDatabase::Trait::ForceSoftwareRendererForReadbacks));
m_ui.forceRoundedTexcoords->setEnabled(
is_hardware && !m_dialog->hasGameTrait(GameDatabase::Trait::ForceRoundUpscaledTextureCoordinates));
m_ui.tabs->setTabEnabled(TAB_INDEX_TEXTURE_REPLACEMENTS, is_hardware);
#ifdef _WIN32
m_ui.blitSwapChain->setVisible(render_api == RenderAPI::D3D11);
#endif
populateGPUAdaptersAndResolutions(render_api);
updatePGXPSettingsEnabled();
}
void GraphicsSettingsWidget::populateGPUAdaptersAndResolutions(RenderAPI render_api)
{
// Don't re-query, it's expensive.
if (m_adapters_render_api != render_api)
{
m_adapters_render_api = render_api;
m_adapters = GPUDevice::GetAdapterListForAPI(render_api);
}
const GPUDevice::AdapterInfo* current_adapter = nullptr;
SettingsInterface* const sif = m_dialog->getSettingsInterface();
{
SettingWidgetBinder::DisconnectWidget(m_ui.adapter);
m_ui.adapter->clear();
m_ui.adapter->addItem(tr("Default"), QVariant(QString()));
const std::string current_adapter_name = m_dialog->getEffectiveStringValue("GPU", "Adapter", "");
for (const GPUDevice::AdapterInfo& adapter : m_adapters)
{
const QString qadaptername = QString::fromStdString(adapter.name);
m_ui.adapter->addItem(qadaptername, QVariant(qadaptername));
if (adapter.name == current_adapter_name)
current_adapter = &adapter;
}
if (!m_adapters.empty())
{
if (current_adapter_name.empty())
{
// default adapter
current_adapter = &m_adapters.front();
}
else if (!current_adapter)
{
// if the adapter is not available, ensure it's in the list anyway, otherwise select the default
const QString qadaptername = QString::fromStdString(current_adapter_name);
m_ui.adapter->addItem(qadaptername, QVariant(qadaptername));
}
}
// disable it if we don't have a choice
m_ui.adapter->setEnabled(!m_adapters.empty());
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.adapter, "GPU", "Adapter");
connect(m_ui.adapter, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&GraphicsSettingsWidget::updateRendererDependentOptions);
}
{
SettingWidgetBinder::DisconnectWidget(m_ui.fullscreenMode);
m_ui.fullscreenMode->clear();
m_ui.fullscreenMode->addItem(tr("Borderless Fullscreen"), QVariant(QString()));
const std::string current_fullscreen_mode = m_dialog->getEffectiveStringValue("GPU", "FullscreenMode", "");
bool current_fullscreen_mode_found = false;
if (current_adapter)
{
for (const GPUDevice::ExclusiveFullscreenMode& mode : current_adapter->fullscreen_modes)
{
const TinyString mode_str = mode.ToString();
current_fullscreen_mode_found = current_fullscreen_mode_found || (current_fullscreen_mode == mode_str.view());
const QString qmodename = QtUtils::StringViewToQString(mode_str);
m_ui.fullscreenMode->addItem(qmodename, QVariant(qmodename));
}
}
// if the current mode is not valid (e.g. adapter change), ensure it's in the list so the user isn't confused
if (!current_fullscreen_mode_found && !current_fullscreen_mode.empty())
{
const QString qmodename = QtUtils::StringViewToQString(current_fullscreen_mode);
m_ui.fullscreenMode->addItem(qmodename, QVariant(qmodename));
}
// disable it if we don't have a choice
const bool has_fullscreen_modes = (current_adapter && !current_adapter->fullscreen_modes.empty());
const bool has_exclusive_fullscreen_control = (render_api == RenderAPI::Vulkan);
m_ui.fullscreenMode->setVisible(has_fullscreen_modes);
if (has_fullscreen_modes)
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.fullscreenMode, "GPU", "FullscreenMode");
m_ui.exclusiveFullscreenControl->setVisible(has_exclusive_fullscreen_control);
m_ui.exclusiveFullscreenLabel->setVisible(has_fullscreen_modes || has_exclusive_fullscreen_control);
}
if (!m_dialog->hasGameTrait(GameDatabase::Trait::DisableUpscaling))
{
SettingWidgetBinder::DisconnectWidget(m_ui.resolutionScale);
m_ui.resolutionScale->clear();
const int max_scale =
static_cast<int>(current_adapter ? std::max<u32>(current_adapter->max_texture_size / 1024, 1) : 16);
populateUpscalingModes(m_ui.resolutionScale, max_scale);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.resolutionScale, "GPU", "ResolutionScale", 1);
connect(m_ui.resolutionScale, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&GraphicsSettingsWidget::updateResolutionDependentOptions);
}
{
SettingWidgetBinder::DisconnectWidget(m_ui.msaaMode);
m_ui.msaaMode->clear();
if (m_dialog->isPerGameSettings())
m_ui.msaaMode->addItem(tr("Use Global Setting"));
const u32 max_multisamples = current_adapter ? current_adapter->max_multisamples : 8;
m_ui.msaaMode->addItem(tr("Disabled"), GetMSAAModeValue(1, false));
for (uint i = 2; i <= max_multisamples; i *= 2)
m_ui.msaaMode->addItem(tr("%1x MSAA").arg(i), GetMSAAModeValue(i, false));
for (uint i = 2; i <= max_multisamples; i *= 2)
m_ui.msaaMode->addItem(tr("%1x SSAA").arg(i), GetMSAAModeValue(i, true));
if (!m_dialog->isPerGameSettings() || (m_dialog->containsSettingValue("GPU", "Multisamples") ||
m_dialog->containsSettingValue("GPU", "PerSampleShading")))
{
const QVariant current_msaa_mode(
GetMSAAModeValue(static_cast<uint>(m_dialog->getEffectiveIntValue("GPU", "Multisamples", 1)),
m_dialog->getEffectiveBoolValue("GPU", "PerSampleShading", false)));
const int current_msaa_index = m_ui.msaaMode->findData(current_msaa_mode);
if (current_msaa_index >= 0)
m_ui.msaaMode->setCurrentIndex(current_msaa_index);
}
else
{
m_ui.msaaMode->setCurrentIndex(0);
}
connect(m_ui.msaaMode, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this]() {
const int index = m_ui.msaaMode->currentIndex();
if (m_dialog->isPerGameSettings() && index == 0)
{
m_dialog->removeSettingValue("GPU", "Multisamples");
m_dialog->removeSettingValue("GPU", "PerSampleShading");
}
else
{
uint multisamples;
bool ssaa;
DecodeMSAAModeValue(m_ui.msaaMode->itemData(index), &multisamples, &ssaa);
m_dialog->setIntSettingValue("GPU", "Multisamples", static_cast<int>(multisamples));
m_dialog->setBoolSettingValue("GPU", "PerSampleShading", ssaa);
}
});
}
}
void GraphicsSettingsWidget::populateUpscalingModes(QComboBox* cb, int max_scale)
{
static constexpr const std::pair<int, const char*> templates[] = {
{0, QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "Automatic (Based on Window Size)")},
{1, QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "1x Native (Default)")},
{3, QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "3x Native (for 720p)")},
{5, QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "5x Native (for 1080p)")},
{6, QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "6x Native (for 1440p)")},
{9, QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "9x Native (for 4K)")},
};
for (int scale = 0; scale <= max_scale; scale++)
{
const auto it = std::find_if(std::begin(templates), std::end(templates),
[&scale](const std::pair<int, const char*>& it) { return scale == it.first; });
cb->addItem((it != std::end(templates)) ? qApp->translate("GraphicsSettingsWidget", it->second) :
qApp->translate("GraphicsSettingsWidget", "%1x Native").arg(scale));
}
}
void GraphicsSettingsWidget::updatePGXPSettingsEnabled()
{
const bool enabled = (effectiveRendererIsHardware() && m_dialog->getEffectiveBoolValue("GPU", "PGXPEnable", false) &&
!m_dialog->hasGameTrait(GameDatabase::Trait::DisablePGXP));
const bool tc_enabled = (enabled && m_dialog->getEffectiveBoolValue("GPU", "PGXPTextureCorrection", true));
const bool depth_enabled = (enabled && m_dialog->getEffectiveBoolValue("GPU", "PGXPDepthBuffer", false));
m_ui.tabs->setTabEnabled(TAB_INDEX_PGXP, enabled);
m_ui.pgxpTab->setEnabled(enabled);
m_ui.pgxpCulling->setEnabled(enabled && !m_dialog->hasGameTrait(GameDatabase::Trait::DisablePGXPCulling));
m_ui.pgxpTextureCorrection->setEnabled(enabled &&
!m_dialog->hasGameTrait(GameDatabase::Trait::DisablePGXPTextureCorrection));
m_ui.pgxpColorCorrection->setEnabled(tc_enabled &&
!m_dialog->hasGameTrait(GameDatabase::Trait::DisablePGXPColorCorrection));
m_ui.pgxpDepthBuffer->setEnabled(enabled && !m_dialog->hasGameTrait(GameDatabase::Trait::DisablePGXPDepthBuffer));
m_ui.pgxpPreserveProjPrecision->setEnabled(
enabled && (!m_dialog->hasDatabaseEntry() || !m_dialog->getDatabaseEntry()->gpu_pgxp_preserve_proj_fp.has_value()));
m_ui.pgxpCPU->setEnabled(enabled && !m_dialog->hasGameTrait(GameDatabase::Trait::ForcePGXPCPUMode));
m_ui.pgxpVertexCache->setEnabled(enabled && !m_dialog->hasGameTrait(GameDatabase::Trait::ForcePGXPVertexCache));
m_ui.pgxpGeometryTolerance->setEnabled(enabled);
m_ui.pgxpGeometryToleranceLabel->setEnabled(enabled);
m_ui.pgxpDepthClearThreshold->setEnabled(depth_enabled);
m_ui.pgxpDepthClearThresholdLabel->setEnabled(depth_enabled);
m_ui.pgxpDisableOn2DPolygons->setEnabled(enabled &&
!m_dialog->hasGameTrait(GameDatabase::Trait::DisablePGXPOn2DPolygons));
m_ui.pgxpTransparentDepthTest->setEnabled(depth_enabled);
}
void GraphicsSettingsWidget::onAspectRatioChanged()
{
const DisplayAspectRatio ratio =