1 // Copyright 2016 Citra Emulator Project
2 // Licensed under GPLv2 or any later version
3 // Refer to the license.txt file included.
4 
5 #include <QColorDialog>
6 #include <QComboBox>
7 #ifdef HAS_VULKAN
8 #include <QVulkanInstance>
9 #endif
10 
11 #include "common/common_types.h"
12 #include "common/logging/log.h"
13 #include "core/core.h"
14 #include "core/settings.h"
15 #include "ui_configure_graphics.h"
16 #include "yuzu/configuration/configuration_shared.h"
17 #include "yuzu/configuration/configure_graphics.h"
18 
19 #ifdef HAS_VULKAN
20 #include "video_core/renderer_vulkan/renderer_vulkan.h"
21 #endif
22 
ConfigureGraphics(QWidget * parent)23 ConfigureGraphics::ConfigureGraphics(QWidget* parent)
24     : QWidget(parent), ui(new Ui::ConfigureGraphics) {
25     vulkan_device = Settings::values.vulkan_device.GetValue();
26     RetrieveVulkanDevices();
27 
28     ui->setupUi(this);
29 
30     SetupPerGameUI();
31 
32     SetConfiguration();
33 
34     connect(ui->api, qOverload<int>(&QComboBox::currentIndexChanged), this, [this] {
35         UpdateDeviceComboBox();
36         if (!Settings::IsConfiguringGlobal()) {
37             ConfigurationShared::SetHighlight(
38                 ui->api_layout, ui->api->currentIndex() != ConfigurationShared::USE_GLOBAL_INDEX);
39         }
40     });
41     connect(ui->device, qOverload<int>(&QComboBox::activated), this,
42             [this](int device) { UpdateDeviceSelection(device); });
43 
44     connect(ui->bg_button, &QPushButton::clicked, this, [this] {
45         const QColor new_bg_color = QColorDialog::getColor(bg_color);
46         if (!new_bg_color.isValid()) {
47             return;
48         }
49         UpdateBackgroundColorButton(new_bg_color);
50     });
51 
52     ui->bg_label->setVisible(Settings::IsConfiguringGlobal());
53     ui->bg_combobox->setVisible(!Settings::IsConfiguringGlobal());
54 }
55 
UpdateDeviceSelection(int device)56 void ConfigureGraphics::UpdateDeviceSelection(int device) {
57     if (device == -1) {
58         return;
59     }
60     if (GetCurrentGraphicsBackend() == Settings::RendererBackend::Vulkan) {
61         vulkan_device = device;
62     }
63 }
64 
65 ConfigureGraphics::~ConfigureGraphics() = default;
66 
SetConfiguration()67 void ConfigureGraphics::SetConfiguration() {
68     const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
69 
70     ui->api->setEnabled(runtime_lock);
71     ui->use_asynchronous_gpu_emulation->setEnabled(runtime_lock);
72     ui->use_disk_shader_cache->setEnabled(runtime_lock);
73     ui->use_nvdec_emulation->setEnabled(runtime_lock);
74     ui->use_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache.GetValue());
75     ui->use_asynchronous_gpu_emulation->setChecked(
76         Settings::values.use_asynchronous_gpu_emulation.GetValue());
77     ui->use_nvdec_emulation->setChecked(Settings::values.use_nvdec_emulation.GetValue());
78 
79     if (Settings::IsConfiguringGlobal()) {
80         ui->api->setCurrentIndex(static_cast<int>(Settings::values.renderer_backend.GetValue()));
81         ui->aspect_ratio_combobox->setCurrentIndex(Settings::values.aspect_ratio.GetValue());
82     } else {
83         ConfigurationShared::SetPerGameSetting(ui->api, &Settings::values.renderer_backend);
84         ConfigurationShared::SetHighlight(ui->api_layout,
85                                           !Settings::values.renderer_backend.UsingGlobal());
86         ConfigurationShared::SetPerGameSetting(ui->aspect_ratio_combobox,
87                                                &Settings::values.aspect_ratio);
88 
89         ui->bg_combobox->setCurrentIndex(Settings::values.bg_red.UsingGlobal() ? 0 : 1);
90         ui->bg_button->setEnabled(!Settings::values.bg_red.UsingGlobal());
91         ConfigurationShared::SetHighlight(ui->ar_label,
92                                           !Settings::values.aspect_ratio.UsingGlobal());
93         ConfigurationShared::SetHighlight(ui->bg_layout, !Settings::values.bg_red.UsingGlobal());
94     }
95 
96     UpdateBackgroundColorButton(QColor::fromRgbF(Settings::values.bg_red.GetValue(),
97                                                  Settings::values.bg_green.GetValue(),
98                                                  Settings::values.bg_blue.GetValue()));
99     UpdateDeviceComboBox();
100 }
101 
ApplyConfiguration()102 void ConfigureGraphics::ApplyConfiguration() {
103     if (Settings::IsConfiguringGlobal()) {
104         // Guard if during game and set to game-specific value
105         if (Settings::values.renderer_backend.UsingGlobal()) {
106             Settings::values.renderer_backend.SetValue(GetCurrentGraphicsBackend());
107         }
108         if (Settings::values.vulkan_device.UsingGlobal()) {
109             Settings::values.vulkan_device.SetValue(vulkan_device);
110         }
111         if (Settings::values.aspect_ratio.UsingGlobal()) {
112             Settings::values.aspect_ratio.SetValue(ui->aspect_ratio_combobox->currentIndex());
113         }
114         if (Settings::values.use_disk_shader_cache.UsingGlobal()) {
115             Settings::values.use_disk_shader_cache.SetValue(ui->use_disk_shader_cache->isChecked());
116         }
117         if (Settings::values.use_asynchronous_gpu_emulation.UsingGlobal()) {
118             Settings::values.use_asynchronous_gpu_emulation.SetValue(
119                 ui->use_asynchronous_gpu_emulation->isChecked());
120         }
121         if (Settings::values.use_nvdec_emulation.UsingGlobal()) {
122             Settings::values.use_nvdec_emulation.SetValue(ui->use_nvdec_emulation->isChecked());
123         }
124         if (Settings::values.bg_red.UsingGlobal()) {
125             Settings::values.bg_red.SetValue(static_cast<float>(bg_color.redF()));
126             Settings::values.bg_green.SetValue(static_cast<float>(bg_color.greenF()));
127             Settings::values.bg_blue.SetValue(static_cast<float>(bg_color.blueF()));
128         }
129     } else {
130         if (ui->api->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
131             Settings::values.renderer_backend.SetGlobal(true);
132             Settings::values.vulkan_device.SetGlobal(true);
133         } else {
134             Settings::values.renderer_backend.SetGlobal(false);
135             Settings::values.renderer_backend.SetValue(GetCurrentGraphicsBackend());
136             if (GetCurrentGraphicsBackend() == Settings::RendererBackend::Vulkan) {
137                 Settings::values.vulkan_device.SetGlobal(false);
138                 Settings::values.vulkan_device.SetValue(vulkan_device);
139             } else {
140                 Settings::values.vulkan_device.SetGlobal(true);
141             }
142         }
143 
144         ConfigurationShared::ApplyPerGameSetting(&Settings::values.aspect_ratio,
145                                                  ui->aspect_ratio_combobox);
146 
147         ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_disk_shader_cache,
148                                                  ui->use_disk_shader_cache, use_disk_shader_cache);
149         ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_gpu_emulation,
150                                                  ui->use_asynchronous_gpu_emulation,
151                                                  use_asynchronous_gpu_emulation);
152         ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_nvdec_emulation,
153                                                  ui->use_nvdec_emulation, use_nvdec_emulation);
154 
155         if (ui->bg_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
156             Settings::values.bg_red.SetGlobal(true);
157             Settings::values.bg_green.SetGlobal(true);
158             Settings::values.bg_blue.SetGlobal(true);
159         } else {
160             Settings::values.bg_red.SetGlobal(false);
161             Settings::values.bg_green.SetGlobal(false);
162             Settings::values.bg_blue.SetGlobal(false);
163             Settings::values.bg_red.SetValue(static_cast<float>(bg_color.redF()));
164             Settings::values.bg_green.SetValue(static_cast<float>(bg_color.greenF()));
165             Settings::values.bg_blue.SetValue(static_cast<float>(bg_color.blueF()));
166         }
167     }
168 }
169 
changeEvent(QEvent * event)170 void ConfigureGraphics::changeEvent(QEvent* event) {
171     if (event->type() == QEvent::LanguageChange) {
172         RetranslateUI();
173     }
174 
175     QWidget::changeEvent(event);
176 }
177 
RetranslateUI()178 void ConfigureGraphics::RetranslateUI() {
179     ui->retranslateUi(this);
180 }
181 
UpdateBackgroundColorButton(QColor color)182 void ConfigureGraphics::UpdateBackgroundColorButton(QColor color) {
183     bg_color = color;
184 
185     QPixmap pixmap(ui->bg_button->size());
186     pixmap.fill(bg_color);
187 
188     const QIcon color_icon(pixmap);
189     ui->bg_button->setIcon(color_icon);
190 }
191 
UpdateDeviceComboBox()192 void ConfigureGraphics::UpdateDeviceComboBox() {
193     ui->device->clear();
194 
195     bool enabled = false;
196 
197     if (!Settings::IsConfiguringGlobal() &&
198         ui->api->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
199         vulkan_device = Settings::values.vulkan_device.GetValue();
200     }
201     switch (GetCurrentGraphicsBackend()) {
202     case Settings::RendererBackend::OpenGL:
203         ui->device->addItem(tr("OpenGL Graphics Device"));
204         enabled = false;
205         break;
206     case Settings::RendererBackend::Vulkan:
207         for (const auto& device : vulkan_devices) {
208             ui->device->addItem(device);
209         }
210         ui->device->setCurrentIndex(vulkan_device);
211         enabled = !vulkan_devices.empty();
212         break;
213     }
214     // If in per-game config and use global is selected, don't enable.
215     enabled &= !(!Settings::IsConfiguringGlobal() &&
216                  ui->api->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX);
217     ui->device->setEnabled(enabled && !Core::System::GetInstance().IsPoweredOn());
218 }
219 
RetrieveVulkanDevices()220 void ConfigureGraphics::RetrieveVulkanDevices() {
221 #ifdef HAS_VULKAN
222     vulkan_devices.clear();
223     for (auto& name : Vulkan::RendererVulkan::EnumerateDevices()) {
224         vulkan_devices.push_back(QString::fromStdString(name));
225     }
226 #endif
227 }
228 
GetCurrentGraphicsBackend() const229 Settings::RendererBackend ConfigureGraphics::GetCurrentGraphicsBackend() const {
230     if (Settings::IsConfiguringGlobal()) {
231         return static_cast<Settings::RendererBackend>(ui->api->currentIndex());
232     }
233 
234     if (ui->api->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
235         Settings::values.renderer_backend.SetGlobal(true);
236         return Settings::values.renderer_backend.GetValue();
237     }
238     Settings::values.renderer_backend.SetGlobal(false);
239     return static_cast<Settings::RendererBackend>(ui->api->currentIndex() -
240                                                   ConfigurationShared::USE_GLOBAL_OFFSET);
241 }
242 
SetupPerGameUI()243 void ConfigureGraphics::SetupPerGameUI() {
244     if (Settings::IsConfiguringGlobal()) {
245         ui->api->setEnabled(Settings::values.renderer_backend.UsingGlobal());
246         ui->device->setEnabled(Settings::values.renderer_backend.UsingGlobal());
247         ui->aspect_ratio_combobox->setEnabled(Settings::values.aspect_ratio.UsingGlobal());
248         ui->use_asynchronous_gpu_emulation->setEnabled(
249             Settings::values.use_asynchronous_gpu_emulation.UsingGlobal());
250         ui->use_nvdec_emulation->setEnabled(Settings::values.use_nvdec_emulation.UsingGlobal());
251         ui->use_disk_shader_cache->setEnabled(Settings::values.use_disk_shader_cache.UsingGlobal());
252         ui->bg_button->setEnabled(Settings::values.bg_red.UsingGlobal());
253 
254         return;
255     }
256 
257     connect(ui->bg_combobox, qOverload<int>(&QComboBox::activated), this, [this](int index) {
258         ui->bg_button->setEnabled(index == 1);
259         ConfigurationShared::SetHighlight(ui->bg_layout, index == 1);
260     });
261 
262     ConfigurationShared::SetColoredTristate(
263         ui->use_disk_shader_cache, Settings::values.use_disk_shader_cache, use_disk_shader_cache);
264     ConfigurationShared::SetColoredTristate(
265         ui->use_nvdec_emulation, Settings::values.use_nvdec_emulation, use_nvdec_emulation);
266     ConfigurationShared::SetColoredTristate(ui->use_asynchronous_gpu_emulation,
267                                             Settings::values.use_asynchronous_gpu_emulation,
268                                             use_asynchronous_gpu_emulation);
269 
270     ConfigurationShared::SetColoredComboBox(ui->aspect_ratio_combobox, ui->ar_label,
271                                             Settings::values.aspect_ratio.GetValue(true));
272     ConfigurationShared::InsertGlobalItem(
273         ui->api, static_cast<int>(Settings::values.renderer_backend.GetValue(true)));
274 }
275