1/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
2/* If you are missing that file, acquire a complete release at teeworlds.com. */
3#include "menus.h"
4
5#include <base/str.h>
6
7#include <engine/graphics.h>
8#include <engine/shared/config.h>
9
10#include <game/client/components/tooltips.h>
11#include <game/client/gameclient.h>
12#include <game/client/ui.h>
13#include <game/client/ui_listbox.h>
14#include <game/client/ui_scrollregion.h>
15#include <game/localization.h>
16
17#include <array>
18#include <memory>
19#include <numeric>
20#include <string>
21#include <vector>
22
23void CMenus::RenderSettingsGraphics(CUIRect MainView)
24{
25 CUIRect Button;
26 char aBuf[128];
27 bool CheckSettings = false;
28
29 static const int MAX_RESOLUTIONS = 256;
30 static CVideoMode s_aModes[MAX_RESOLUTIONS];
31 static int s_NumNodes = Graphics()->GetVideoModes(pModes: s_aModes, MaxModes: MAX_RESOLUTIONS, Screen: g_Config.m_GfxScreen);
32 static int s_GfxFsaaSamples = g_Config.m_GfxFsaaSamples;
33 static bool s_GfxBackendChanged = false;
34 static bool s_GfxGpuChanged = false;
35
36 static int s_InitDisplayAllVideoModes = g_Config.m_GfxDisplayAllVideoModes;
37
38 static bool s_WasInit = false;
39 static bool s_ModesReload = false;
40 if(!s_WasInit)
41 {
42 s_WasInit = true;
43
44 Graphics()->AddWindowPropChangeListener(pFunc: []() {
45 s_ModesReload = true;
46 });
47 }
48
49 if(s_ModesReload || g_Config.m_GfxDisplayAllVideoModes != s_InitDisplayAllVideoModes)
50 {
51 s_NumNodes = Graphics()->GetVideoModes(pModes: s_aModes, MaxModes: MAX_RESOLUTIONS, Screen: g_Config.m_GfxScreen);
52 s_ModesReload = false;
53 s_InitDisplayAllVideoModes = g_Config.m_GfxDisplayAllVideoModes;
54 }
55
56 CUIRect ModeList, ModeLabel;
57 MainView.VSplitLeft(Cut: 350.0f, pLeft: &MainView, pRight: &ModeList);
58 ModeList.HSplitTop(Cut: 24.0f, pTop: &ModeLabel, pBottom: &ModeList);
59 MainView.VSplitLeft(Cut: 340.0f, pLeft: &MainView, pRight: nullptr);
60
61 // display mode list
62 static CListBox s_ListBox;
63 static const float sc_RowHeightResList = 22.0f;
64 static const float sc_FontSizeResListHeader = 12.0f;
65 static const float sc_FontSizeResList = 10.0f;
66
67 {
68 int G = std::gcd(m: g_Config.m_GfxScreenWidth, n: g_Config.m_GfxScreenHeight);
69 str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "%s: %dx%d @%dhz (%d:%d)",
70 Localize(pStr: "Current"),
71 (int)(g_Config.m_GfxScreenWidth * Graphics()->ScreenHiDPIScale()),
72 (int)(g_Config.m_GfxScreenHeight * Graphics()->ScreenHiDPIScale()),
73 g_Config.m_GfxScreenRefreshRate,
74 g_Config.m_GfxScreenWidth / G,
75 g_Config.m_GfxScreenHeight / G);
76 Ui()->DoLabel(pRect: &ModeLabel, pText: aBuf, Size: sc_FontSizeResListHeader, Align: TEXTALIGN_MC);
77 }
78
79 int OldSelected = -1;
80 s_ListBox.SetActive(!Ui()->IsPopupOpen());
81 s_ListBox.DoStart(RowHeight: sc_RowHeightResList, NumItems: s_NumNodes, ItemsPerRow: 1, RowsPerScroll: 3, SelectedIndex: OldSelected, pRect: &ModeList);
82
83 for(int i = 0; i < s_NumNodes; ++i)
84 {
85 if(g_Config.m_GfxScreenWidth == s_aModes[i].m_WindowWidth &&
86 g_Config.m_GfxScreenHeight == s_aModes[i].m_WindowHeight &&
87 g_Config.m_GfxScreenRefreshRate == s_aModes[i].m_RefreshRate)
88 {
89 OldSelected = i;
90 }
91
92 const CListboxItem Item = s_ListBox.DoNextItem(pId: &s_aModes[i], Selected: OldSelected == i);
93 if(!Item.m_Visible)
94 continue;
95
96 int G = std::gcd(m: s_aModes[i].m_WindowWidth, n: s_aModes[i].m_WindowHeight);
97 str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: " %dx%d @%dhz (%d:%d)", s_aModes[i].m_CanvasWidth, s_aModes[i].m_CanvasHeight, s_aModes[i].m_RefreshRate, s_aModes[i].m_WindowWidth / G, s_aModes[i].m_WindowHeight / G);
98 Ui()->DoLabel(pRect: &Item.m_Rect, pText: aBuf, Size: sc_FontSizeResList, Align: TEXTALIGN_ML);
99 }
100
101 const int NewSelected = s_ListBox.DoEnd();
102 if(OldSelected != NewSelected)
103 {
104 g_Config.m_GfxScreenWidth = s_aModes[NewSelected].m_WindowWidth;
105 g_Config.m_GfxScreenHeight = s_aModes[NewSelected].m_WindowHeight;
106 g_Config.m_GfxScreenRefreshRate = s_aModes[NewSelected].m_RefreshRate;
107 Graphics()->ResizeToScreen();
108 }
109
110 // switches
111 CUIRect WindowModeDropDown;
112 MainView.HSplitTop(Cut: 20.0f, pTop: &WindowModeDropDown, pBottom: &MainView);
113
114 const char *apWindowModes[] = {Localize(pStr: "Windowed"), Localize(pStr: "Windowed borderless"), Localize(pStr: "Windowed fullscreen"), Localize(pStr: "Desktop fullscreen"), Localize(pStr: "Fullscreen")};
115 static const int s_NumWindowMode = std::size(apWindowModes);
116
117 const int OldWindowMode = (g_Config.m_GfxFullscreen ? (g_Config.m_GfxFullscreen == 1 ? 4 : (g_Config.m_GfxFullscreen == 2 ? 3 : 2)) : (g_Config.m_GfxBorderless ? 1 : 0));
118
119 static CUi::SDropDownState s_WindowModeDropDownState;
120 static CScrollRegion s_WindowModeDropDownScrollRegion;
121 s_WindowModeDropDownState.m_SelectionPopupContext.m_pScrollRegion = &s_WindowModeDropDownScrollRegion;
122 const int NewWindowMode = Ui()->DoDropDown(pRect: &WindowModeDropDown, CurSelection: OldWindowMode, pStrs: apWindowModes, Num: s_NumWindowMode, State&: s_WindowModeDropDownState);
123 if(OldWindowMode != NewWindowMode)
124 {
125 if(NewWindowMode == 0)
126 Graphics()->SetWindowParams(FullscreenMode: 0, IsBorderless: false);
127 else if(NewWindowMode == 1)
128 Graphics()->SetWindowParams(FullscreenMode: 0, IsBorderless: true);
129 else if(NewWindowMode == 2)
130 Graphics()->SetWindowParams(FullscreenMode: 3, IsBorderless: false);
131 else if(NewWindowMode == 3)
132 Graphics()->SetWindowParams(FullscreenMode: 2, IsBorderless: false);
133 else if(NewWindowMode == 4)
134 Graphics()->SetWindowParams(FullscreenMode: 1, IsBorderless: false);
135 }
136
137 if(Graphics()->GetNumScreens() > 1)
138 {
139 CUIRect ScreenDropDown;
140 MainView.HSplitTop(Cut: 2.0f, pTop: nullptr, pBottom: &MainView);
141 MainView.HSplitTop(Cut: 20.0f, pTop: &ScreenDropDown, pBottom: &MainView);
142
143 const int NumScreens = Graphics()->GetNumScreens();
144 static std::vector<std::string> s_vScreenNames;
145 static std::vector<const char *> s_vpScreenNames;
146 s_vScreenNames.resize(sz: NumScreens);
147 s_vpScreenNames.resize(sz: NumScreens);
148
149 for(int i = 0; i < NumScreens; ++i)
150 {
151 str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "%s %d: %s", Localize(pStr: "Screen"), i, Graphics()->GetScreenName(Screen: i));
152 s_vScreenNames[i] = aBuf;
153 s_vpScreenNames[i] = s_vScreenNames[i].c_str();
154 }
155
156 static CUi::SDropDownState s_ScreenDropDownState;
157 static CScrollRegion s_ScreenDropDownScrollRegion;
158 s_ScreenDropDownState.m_SelectionPopupContext.m_pScrollRegion = &s_ScreenDropDownScrollRegion;
159 const int NewScreen = Ui()->DoDropDown(pRect: &ScreenDropDown, CurSelection: g_Config.m_GfxScreen, pStrs: s_vpScreenNames.data(), Num: s_vpScreenNames.size(), State&: s_ScreenDropDownState);
160 if(NewScreen != g_Config.m_GfxScreen)
161 Graphics()->SwitchWindowScreen(Index: NewScreen, MoveToCenter: true);
162 }
163
164 MainView.HSplitTop(Cut: 2.0f, pTop: nullptr, pBottom: &MainView);
165 MainView.HSplitTop(Cut: 20.0f, pTop: &Button, pBottom: &MainView);
166 str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "%s (%s)", Localize(pStr: "V-Sync"), Localize(pStr: "may cause delay"));
167 if(DoButton_CheckBox(pId: &g_Config.m_GfxVsync, pText: aBuf, Checked: g_Config.m_GfxVsync, pRect: &Button))
168 {
169 Graphics()->SetVSync(!g_Config.m_GfxVsync);
170 }
171
172 bool MultiSamplingChanged = false;
173 MainView.HSplitTop(Cut: 20.0f, pTop: &Button, pBottom: &MainView);
174 str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "%s (%s)", Localize(pStr: "FSAA samples"), Localize(pStr: "may cause delay"));
175 int GfxFsaaSamplesMouseButton = DoButton_CheckBox_Number(pId: &g_Config.m_GfxFsaaSamples, pText: aBuf, Checked: g_Config.m_GfxFsaaSamples, pRect: &Button);
176 int CurFSAA = g_Config.m_GfxFsaaSamples == 0 ? 1 : g_Config.m_GfxFsaaSamples;
177 if(GfxFsaaSamplesMouseButton == 1) // inc
178 {
179 g_Config.m_GfxFsaaSamples = std::pow(x: 2, y: (int)std::log2(x: CurFSAA) + 1);
180 if(g_Config.m_GfxFsaaSamples > 64)
181 g_Config.m_GfxFsaaSamples = 0;
182 MultiSamplingChanged = true;
183 }
184 else if(GfxFsaaSamplesMouseButton == 2) // dec
185 {
186 if(CurFSAA == 1)
187 g_Config.m_GfxFsaaSamples = 64;
188 else if(CurFSAA == 2)
189 g_Config.m_GfxFsaaSamples = 0;
190 else
191 g_Config.m_GfxFsaaSamples = std::pow(x: 2, y: (int)std::log2(x: CurFSAA) - 1);
192 MultiSamplingChanged = true;
193 }
194
195 uint32_t MultiSamplingCountBackend = 0;
196 if(MultiSamplingChanged)
197 {
198 if(Graphics()->SetMultiSampling(ReqMultiSamplingCount: g_Config.m_GfxFsaaSamples, MultiSamplingCountBackend))
199 {
200 // try again with 0 if mouse click was increasing multi sampling
201 // else just accept the current value as is
202 if((uint32_t)g_Config.m_GfxFsaaSamples > MultiSamplingCountBackend && GfxFsaaSamplesMouseButton == 1)
203 Graphics()->SetMultiSampling(ReqMultiSamplingCount: 0, MultiSamplingCountBackend);
204 g_Config.m_GfxFsaaSamples = (int)MultiSamplingCountBackend;
205 }
206 else
207 {
208 CheckSettings = true;
209 }
210 }
211
212 MainView.HSplitTop(Cut: 20.0f, pTop: &Button, pBottom: &MainView);
213 if(DoButton_CheckBox(pId: &g_Config.m_GfxHighDetail, pText: Localize(pStr: "High Detail"), Checked: g_Config.m_GfxHighDetail, pRect: &Button))
214 g_Config.m_GfxHighDetail ^= 1;
215 GameClient()->m_Tooltips.DoToolTip(pId: &g_Config.m_GfxHighDetail, pNearRect: &Button, pText: Localize(pStr: "Allows maps to render with more detail"));
216
217 MainView.HSplitTop(Cut: 20.0f, pTop: &Button, pBottom: &MainView);
218 if(DoButton_CheckBox(pId: &g_Config.m_ClShowfps, pText: Localize(pStr: "Show FPS"), Checked: g_Config.m_ClShowfps, pRect: &Button))
219 g_Config.m_ClShowfps ^= 1;
220 GameClient()->m_Tooltips.DoToolTip(pId: &g_Config.m_ClShowfps, pNearRect: &Button, pText: Localize(pStr: "Renders your frame rate in the top right"));
221
222 MainView.HSplitTop(Cut: 20.0f, pTop: &Button, pBottom: &MainView);
223 str_copy(dst&: aBuf, src: " ");
224 str_append(dst&: aBuf, src: Localize(pStr: "Hz", pContext: "Hertz"));
225 Ui()->DoScrollbarOption(pId: &g_Config.m_GfxRefreshRate, pOption: &g_Config.m_GfxRefreshRate, pRect: &Button, pStr: Localize(pStr: "Refresh Rate"), Min: 10, Max: 1000, pScale: &CUi::ms_LinearScrollbarScale, Flags: CUi::SCROLLBAR_OPTION_INFINITE | CUi::SCROLLBAR_OPTION_NOCLAMPVALUE | CUi::SCROLLBAR_OPTION_DELAYUPDATE, pSuffix: aBuf);
226
227 MainView.HSplitTop(Cut: 2.0f, pTop: nullptr, pBottom: &MainView);
228 static CButtonContainer s_UiColorResetId;
229 DoLine_ColorPicker(pResetId: &s_UiColorResetId, LineSize: 25.0f, LabelSize: 13.0f, BottomMargin: 2.0f, pMainRect: &MainView, pText: Localize(pStr: "UI Color"), pColorValue: &g_Config.m_UiColor, DefaultColor: color_cast<ColorRGBA>(hsl: ColorHSLA(0xE4A046AFU, true)), CheckBoxSpacing: false, pCheckBoxValue: nullptr, Alpha: true);
230
231 // Backend list
232 struct SMenuBackendInfo
233 {
234 int m_Major = 0;
235 int m_Minor = 0;
236 int m_Patch = 0;
237 const char *m_pBackendName = "";
238 bool m_Found = false;
239 };
240 std::array<std::array<SMenuBackendInfo, EGraphicsDriverAgeType::GRAPHICS_DRIVER_AGE_TYPE_COUNT>, EBackendType::BACKEND_TYPE_COUNT> aaSupportedBackends{};
241 uint32_t FoundBackendCount = 0;
242 for(uint32_t i = 0; i < BACKEND_TYPE_COUNT; ++i)
243 {
244 if(EBackendType(i) == BACKEND_TYPE_AUTO)
245 continue;
246 for(uint32_t n = 0; n < GRAPHICS_DRIVER_AGE_TYPE_COUNT; ++n)
247 {
248 auto &Info = aaSupportedBackends[i][n];
249 if(Graphics()->GetDriverVersion(DriverAgeType: EGraphicsDriverAgeType(n), Major&: Info.m_Major, Minor&: Info.m_Minor, Patch&: Info.m_Patch, pName&: Info.m_pBackendName, BackendType: EBackendType(i)))
250 {
251 // don't count blocked opengl drivers
252 if(EBackendType(i) != BACKEND_TYPE_OPENGL || EGraphicsDriverAgeType(n) == GRAPHICS_DRIVER_AGE_TYPE_LEGACY || g_Config.m_GfxDriverIsBlocked == 0)
253 {
254 Info.m_Found = true;
255 ++FoundBackendCount;
256 }
257 }
258 }
259 }
260
261 if(FoundBackendCount > 1)
262 {
263 CUIRect Text, BackendDropDown;
264 MainView.HSplitTop(Cut: 10.0f, pTop: nullptr, pBottom: &MainView);
265 MainView.HSplitTop(Cut: 20.0f, pTop: &Text, pBottom: &MainView);
266 MainView.HSplitTop(Cut: 2.0f, pTop: nullptr, pBottom: &MainView);
267 MainView.HSplitTop(Cut: 20.0f, pTop: &BackendDropDown, pBottom: &MainView);
268 Ui()->DoLabel(pRect: &Text, pText: Localize(pStr: "Renderer"), Size: 16.0f, Align: TEXTALIGN_MC);
269
270 static std::vector<std::string> s_vBackendIdNames;
271 static std::vector<const char *> s_vpBackendIdNamesCStr;
272 static std::vector<SMenuBackendInfo> s_vBackendInfos;
273
274 size_t BackendCount = FoundBackendCount + 1;
275 s_vBackendIdNames.resize(sz: BackendCount);
276 s_vpBackendIdNamesCStr.resize(sz: BackendCount);
277 s_vBackendInfos.resize(sz: BackendCount);
278
279 char aTmpBackendName[256];
280
281 auto IsInfoDefault = [](const SMenuBackendInfo &CheckInfo) {
282 return str_comp_nocase(a: CheckInfo.m_pBackendName, b: DefaultConfig::GfxBackend) == 0 && CheckInfo.m_Major == DefaultConfig::GfxGLMajor && CheckInfo.m_Minor == DefaultConfig::GfxGLMinor && CheckInfo.m_Patch == DefaultConfig::GfxGLPatch;
283 };
284
285 int OldSelectedBackend = -1;
286 uint32_t CurCounter = 0;
287 for(uint32_t i = 0; i < BACKEND_TYPE_COUNT; ++i)
288 {
289 for(uint32_t n = 0; n < GRAPHICS_DRIVER_AGE_TYPE_COUNT; ++n)
290 {
291 auto &Info = aaSupportedBackends[i][n];
292 if(Info.m_Found)
293 {
294 bool IsDefault = IsInfoDefault(Info);
295 str_format(buffer: aTmpBackendName, buffer_size: sizeof(aTmpBackendName), format: "%s (%d.%d.%d)%s%s", Info.m_pBackendName, Info.m_Major, Info.m_Minor, Info.m_Patch, IsDefault ? " - " : "", IsDefault ? Localize(pStr: "default") : "");
296 s_vBackendIdNames[CurCounter] = aTmpBackendName;
297 s_vpBackendIdNamesCStr[CurCounter] = s_vBackendIdNames[CurCounter].c_str();
298 if(str_comp_nocase(a: Info.m_pBackendName, b: g_Config.m_GfxBackend) == 0 && g_Config.m_GfxGLMajor == Info.m_Major && g_Config.m_GfxGLMinor == Info.m_Minor && g_Config.m_GfxGLPatch == Info.m_Patch)
299 {
300 OldSelectedBackend = CurCounter;
301 }
302
303 s_vBackendInfos[CurCounter] = Info;
304 ++CurCounter;
305 }
306 }
307 }
308
309 if(OldSelectedBackend != -1)
310 {
311 // no custom selected
312 BackendCount -= 1;
313 }
314 else
315 {
316 // custom selected one
317 str_format(buffer: aTmpBackendName, buffer_size: sizeof(aTmpBackendName), format: "%s (%s %d.%d.%d)", Localize(pStr: "custom"), g_Config.m_GfxBackend, g_Config.m_GfxGLMajor, g_Config.m_GfxGLMinor, g_Config.m_GfxGLPatch);
318 s_vBackendIdNames[CurCounter] = aTmpBackendName;
319 s_vpBackendIdNamesCStr[CurCounter] = s_vBackendIdNames[CurCounter].c_str();
320 OldSelectedBackend = CurCounter;
321
322 s_vBackendInfos[CurCounter].m_pBackendName = "custom";
323 s_vBackendInfos[CurCounter].m_Major = g_Config.m_GfxGLMajor;
324 s_vBackendInfos[CurCounter].m_Minor = g_Config.m_GfxGLMinor;
325 s_vBackendInfos[CurCounter].m_Patch = g_Config.m_GfxGLPatch;
326 }
327
328 static int s_OldSelectedBackend = -1;
329 if(s_OldSelectedBackend == -1)
330 s_OldSelectedBackend = OldSelectedBackend;
331
332 static CUi::SDropDownState s_BackendDropDownState;
333 static CScrollRegion s_BackendDropDownScrollRegion;
334 s_BackendDropDownState.m_SelectionPopupContext.m_pScrollRegion = &s_BackendDropDownScrollRegion;
335 const int NewBackend = Ui()->DoDropDown(pRect: &BackendDropDown, CurSelection: OldSelectedBackend, pStrs: s_vpBackendIdNamesCStr.data(), Num: BackendCount, State&: s_BackendDropDownState);
336 if(OldSelectedBackend != NewBackend)
337 {
338 str_copy(dst&: g_Config.m_GfxBackend, src: s_vBackendInfos[NewBackend].m_pBackendName);
339 g_Config.m_GfxGLMajor = s_vBackendInfos[NewBackend].m_Major;
340 g_Config.m_GfxGLMinor = s_vBackendInfos[NewBackend].m_Minor;
341 g_Config.m_GfxGLPatch = s_vBackendInfos[NewBackend].m_Patch;
342
343 CheckSettings = true;
344 s_GfxBackendChanged = s_OldSelectedBackend != NewBackend;
345 }
346 }
347
348 // GPU list
349 const auto &GpuList = Graphics()->GetGpus();
350 if(GpuList.m_vGpus.size() > 1)
351 {
352 CUIRect Text, GpuDropDown;
353 MainView.HSplitTop(Cut: 10.0f, pTop: nullptr, pBottom: &MainView);
354 MainView.HSplitTop(Cut: 20.0f, pTop: &Text, pBottom: &MainView);
355 MainView.HSplitTop(Cut: 2.0f, pTop: nullptr, pBottom: &MainView);
356 MainView.HSplitTop(Cut: 20.0f, pTop: &GpuDropDown, pBottom: &MainView);
357 Ui()->DoLabel(pRect: &Text, pText: Localize(pStr: "Graphics card"), Size: 16.0f, Align: TEXTALIGN_MC);
358
359 static std::vector<const char *> s_vpGpuIdNames;
360
361 size_t GpuCount = GpuList.m_vGpus.size() + 1;
362 s_vpGpuIdNames.resize(sz: GpuCount);
363
364 char aCurDeviceName[256 + 4];
365
366 int OldSelectedGpu = -1;
367 for(size_t i = 0; i < GpuCount; ++i)
368 {
369 if(i == 0)
370 {
371 str_format(buffer: aCurDeviceName, buffer_size: sizeof(aCurDeviceName), format: "%s (%s)", Localize(pStr: "auto"), GpuList.m_AutoGpu.m_aName);
372 s_vpGpuIdNames[i] = aCurDeviceName;
373 if(str_comp(a: "auto", b: g_Config.m_GfxGpuName) == 0)
374 {
375 OldSelectedGpu = 0;
376 }
377 }
378 else
379 {
380 s_vpGpuIdNames[i] = GpuList.m_vGpus[i - 1].m_aName;
381 if(str_comp(a: GpuList.m_vGpus[i - 1].m_aName, b: g_Config.m_GfxGpuName) == 0)
382 {
383 OldSelectedGpu = i;
384 }
385 }
386 }
387
388 static int s_OldSelectedGpu = -1;
389 if(s_OldSelectedGpu == -1)
390 s_OldSelectedGpu = OldSelectedGpu;
391
392 static CUi::SDropDownState s_GpuDropDownState;
393 static CScrollRegion s_GpuDropDownScrollRegion;
394 s_GpuDropDownState.m_SelectionPopupContext.m_pScrollRegion = &s_GpuDropDownScrollRegion;
395 const int NewGpu = Ui()->DoDropDown(pRect: &GpuDropDown, CurSelection: OldSelectedGpu, pStrs: s_vpGpuIdNames.data(), Num: GpuCount, State&: s_GpuDropDownState);
396 if(OldSelectedGpu != NewGpu)
397 {
398 if(NewGpu == 0)
399 str_copy(dst&: g_Config.m_GfxGpuName, src: "auto");
400 else
401 str_copy(dst&: g_Config.m_GfxGpuName, src: GpuList.m_vGpus[NewGpu - 1].m_aName);
402 CheckSettings = true;
403 s_GfxGpuChanged = NewGpu != s_OldSelectedGpu;
404 }
405 }
406
407 // check if the new settings require a restart
408 if(CheckSettings)
409 {
410 m_NeedRestartGraphics = !(s_GfxFsaaSamples == g_Config.m_GfxFsaaSamples &&
411 !s_GfxBackendChanged &&
412 !s_GfxGpuChanged);
413 }
414}
415