ui: device picker shows the auto-selected adapter; no wrap on stepper clicks
This commit is contained in:
parent
855ed66c82
commit
2cab1be8eb
4 changed files with 82 additions and 23 deletions
|
|
@ -20,6 +20,10 @@ struct GraphicsDeviceList {
|
||||||
// "vulkan_device"); empty when no backend has published a list.
|
// "vulkan_device"); empty when no backend has published a list.
|
||||||
std::string cvar_name;
|
std::string cvar_name;
|
||||||
std::vector<std::string> device_names;
|
std::vector<std::string> device_names;
|
||||||
|
// Index (in device_names / cvar order) of the device the backend actually
|
||||||
|
// selected this session; -1 while unknown. Lets UI show the device that
|
||||||
|
// automatic selection resolved to.
|
||||||
|
int32_t active_index = -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
void SetGraphicsDeviceList(GraphicsDeviceList list);
|
void SetGraphicsDeviceList(GraphicsDeviceList list);
|
||||||
|
|
|
||||||
|
|
@ -345,6 +345,28 @@ bool D3D12Provider::Initialize() {
|
||||||
dxgi_factory->Release();
|
dxgi_factory->Release();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// Publish which cvar-order index the selection landed on (the automatic
|
||||||
|
// path walks a preference-ordered enumeration, so its index does not match
|
||||||
|
// the published list) so the settings device picker can show the adapter
|
||||||
|
// automatic selection resolved to. Matched by LUID against the plain
|
||||||
|
// enumeration the list was built from.
|
||||||
|
{
|
||||||
|
GraphicsDeviceList device_list = GetGraphicsDeviceList();
|
||||||
|
IDXGIAdapter1* match_adapter;
|
||||||
|
for (uint32_t i = 0; dxgi_factory->EnumAdapters1(i, &match_adapter) == S_OK; ++i) {
|
||||||
|
DXGI_ADAPTER_DESC1 match_desc;
|
||||||
|
const bool matched =
|
||||||
|
SUCCEEDED(match_adapter->GetDesc1(&match_desc)) &&
|
||||||
|
match_desc.AdapterLuid.LowPart == adapter_desc.AdapterLuid.LowPart &&
|
||||||
|
match_desc.AdapterLuid.HighPart == adapter_desc.AdapterLuid.HighPart;
|
||||||
|
match_adapter->Release();
|
||||||
|
if (matched) {
|
||||||
|
device_list.active_index = int32_t(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SetGraphicsDeviceList(std::move(device_list));
|
||||||
|
}
|
||||||
adapter_vendor_id_ = GpuVendorID(adapter_desc.VendorId);
|
adapter_vendor_id_ = GpuVendorID(adapter_desc.VendorId);
|
||||||
int adapter_name_mb_size =
|
int adapter_name_mb_size =
|
||||||
WideCharToMultiByte(CP_UTF8, 0, adapter_desc.Description, -1, nullptr, 0, nullptr, nullptr);
|
WideCharToMultiByte(CP_UTF8, 0, adapter_desc.Description, -1, nullptr, 0, nullptr, nullptr);
|
||||||
|
|
|
||||||
|
|
@ -220,16 +220,19 @@ std::vector<std::string_view> GetSimpleSettingsCvars() {
|
||||||
return cvars;
|
return cvars;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0 = automatic selection (cvar -1); i+1 = the list's device i.
|
// The picker lists devices directly (no separate automatic entry):
|
||||||
|
// automatic selection (cvar -1) reads as the device the backend reported
|
||||||
|
// actually picking.
|
||||||
int DeviceIndexFromCvar(const GraphicsDeviceList& device_list) {
|
int DeviceIndexFromCvar(const GraphicsDeviceList& device_list) {
|
||||||
if (device_list.device_names.empty() || !HasCvar(device_list.cvar_name)) {
|
if (device_list.device_names.empty() || !HasCvar(device_list.cvar_name)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int32_t current = rex::cvar::Query<int32_t>(device_list.cvar_name);
|
int32_t current = rex::cvar::Query<int32_t>(device_list.cvar_name);
|
||||||
if (current >= 0 && current < static_cast<int32_t>(device_list.device_names.size())) {
|
if (current >= 0 && current < static_cast<int32_t>(device_list.device_names.size())) {
|
||||||
return current + 1;
|
return current;
|
||||||
}
|
}
|
||||||
return 0;
|
return std::clamp(device_list.active_index, 0,
|
||||||
|
static_cast<int32_t>(device_list.device_names.size()) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ResolutionIndexFromScale(int32_t scale) {
|
int ResolutionIndexFromScale(int32_t scale) {
|
||||||
|
|
@ -952,10 +955,14 @@ void SimpleSettingsDialog::SaveVideo() {
|
||||||
std::clamp(aspect_ratio_index_, 0, static_cast<int>(kAspectRatioLabels.size()) - 1);
|
std::clamp(aspect_ratio_index_, 0, static_cast<int>(kAspectRatioLabels.size()) - 1);
|
||||||
field_of_view_ = std::clamp(field_of_view_, 40.0f, 120.0f);
|
field_of_view_ = std::clamp(field_of_view_, 40.0f, 120.0f);
|
||||||
if (!device_list_.device_names.empty() && HasCvar(device_list_.cvar_name)) {
|
if (!device_list_.device_names.empty() && HasCvar(device_list_.cvar_name)) {
|
||||||
device_index_ =
|
device_index_ = std::clamp(device_index_, 0,
|
||||||
std::clamp(device_index_, 0, static_cast<int>(device_list_.device_names.size()));
|
static_cast<int>(device_list_.device_names.size()) - 1);
|
||||||
|
// Selecting the device automatic selection already picked keeps the cvar
|
||||||
|
// automatic, so new hardware still re-picks the best adapter.
|
||||||
rex::cvar::SetFlagByName(device_list_.cvar_name,
|
rex::cvar::SetFlagByName(device_list_.cvar_name,
|
||||||
device_index_ == 0 ? "-1" : std::to_string(device_index_ - 1));
|
device_index_ == device_list_.active_index
|
||||||
|
? "-1"
|
||||||
|
: std::to_string(device_index_));
|
||||||
}
|
}
|
||||||
const auto scale = std::to_string(kResolutionScales[resolution_scale_index_]);
|
const auto scale = std::to_string(kResolutionScales[resolution_scale_index_]);
|
||||||
rex::cvar::SetFlagByName("resolution_scale", scale);
|
rex::cvar::SetFlagByName("resolution_scale", scale);
|
||||||
|
|
@ -1058,19 +1065,20 @@ void SimpleSettingsDialog::BuildRows(std::vector<RowSpec>& rows, int category) {
|
||||||
row.kind = RowSpec::kEnum;
|
row.kind = RowSpec::kEnum;
|
||||||
row.label = "Graphics Device";
|
row.label = "Graphics Device";
|
||||||
row.desc =
|
row.desc =
|
||||||
"Select which GPU renders the game. Auto picks the highest-performance adapter.";
|
"Select which GPU renders the game. The highest-performance "
|
||||||
|
"adapter is selected automatically.";
|
||||||
// Index-prefixed labels: virtual display drivers (Parsec etc.) make
|
// Index-prefixed labels: virtual display drivers (Parsec etc.) make
|
||||||
// the same physical GPU enumerate several times, and the index is
|
// the same physical GPU enumerate several times, and the index is
|
||||||
// what the device cvar and the startup log speak in.
|
// what the device cvar and the startup log speak in. No separate
|
||||||
row.options.push_back("Auto (recommended)");
|
// automatic entry; the row shows the adapter automatic selection
|
||||||
|
// resolved to, and re-selecting it keeps the choice automatic.
|
||||||
for (size_t i = 0; i < device_list_.device_names.size(); ++i) {
|
for (size_t i = 0; i < device_list_.device_names.size(); ++i) {
|
||||||
row.options.push_back(std::to_string(i) + ": " + device_list_.device_names[i]);
|
row.options.push_back(std::to_string(i) + ": " + device_list_.device_names[i]);
|
||||||
}
|
}
|
||||||
row.index = &device_index_;
|
row.index = &device_index_;
|
||||||
if (device_index_ > 0 && device_index_ <= int(device_list_.device_names.size())) {
|
row.reset = [this] {
|
||||||
row.desc_extra = "Current: " + row.options[device_index_];
|
device_index_ = std::max(device_list_.active_index, 0);
|
||||||
}
|
};
|
||||||
row.reset = [this] { device_index_ = 0; };
|
|
||||||
rows.push_back(std::move(row));
|
rows.push_back(std::move(row));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
|
@ -2333,12 +2341,17 @@ void SimpleSettingsDialog::OnDraw(ImGuiIO& io) {
|
||||||
// a circle greys out (and stops responding) at its end of the range.
|
// a circle greys out (and stops responding) at its end of the range.
|
||||||
const bool can_left = row.enabled && value > 0;
|
const bool can_left = row.enabled && value > 0;
|
||||||
const bool can_right = row.enabled && value < count - 1;
|
const bool can_right = row.enabled && value < count - 1;
|
||||||
bool left_hover = can_left &&
|
// Hit areas are tracked separately from enablement: a click on a
|
||||||
mouse_in(left_center.x - chevron_r - 4.0f, cy - chevron_r - 4.0f,
|
// greyed-out stepper must be swallowed, not fall through to the
|
||||||
left_center.x + chevron_r + 4.0f, cy + chevron_r + 4.0f);
|
// row-body wrap-around cycle below.
|
||||||
bool right_hover = can_right &&
|
const bool left_hit =
|
||||||
mouse_in(right_center.x - chevron_r - 4.0f, cy - chevron_r - 4.0f,
|
mouse_in(left_center.x - chevron_r - 4.0f, cy - chevron_r - 4.0f,
|
||||||
right_center.x + chevron_r + 4.0f, cy + chevron_r + 4.0f);
|
left_center.x + chevron_r + 4.0f, cy + chevron_r + 4.0f);
|
||||||
|
const bool right_hit =
|
||||||
|
mouse_in(right_center.x - chevron_r - 4.0f, cy - chevron_r - 4.0f,
|
||||||
|
right_center.x + chevron_r + 4.0f, cy + chevron_r + 4.0f);
|
||||||
|
bool left_hover = can_left && left_hit;
|
||||||
|
bool right_hover = can_right && right_hit;
|
||||||
const ImU32 chev_disabled = focused ? kColChevDisabledOnDark : kColChevDisabled;
|
const ImU32 chev_disabled = focused ? kColChevDisabledOnDark : kColChevDisabled;
|
||||||
DrawChevron(dl, left_center, chevron_r, true,
|
DrawChevron(dl, left_center, chevron_r, true,
|
||||||
can_left ? (left_hover ? kColInteractHover : kColInteract)
|
can_left ? (left_hover ? kColInteractHover : kColInteract)
|
||||||
|
|
@ -2369,10 +2382,14 @@ void SimpleSettingsDialog::OnDraw(ImGuiIO& io) {
|
||||||
text.c_str());
|
text.c_str());
|
||||||
}
|
}
|
||||||
if (clicked && row.enabled) {
|
if (clicked && row.enabled) {
|
||||||
if (left_hover) {
|
if (left_hit) {
|
||||||
step_row(row, -1);
|
if (can_left) {
|
||||||
} else if (right_hover) {
|
step_row(row, -1);
|
||||||
step_row(row, 1);
|
}
|
||||||
|
} else if (right_hit) {
|
||||||
|
if (can_right) {
|
||||||
|
step_row(row, 1);
|
||||||
|
}
|
||||||
} else if (hovered) {
|
} else if (hovered) {
|
||||||
activate_row(row); // row-body click cycles with wrap-around
|
activate_row(row); // row-body click cycles with wrap-around
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -165,6 +165,22 @@ std::unique_ptr<VulkanProvider> VulkanProvider::Create(const bool with_gpu_emula
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Publish which enumeration index the selection landed on (the automatic
|
||||||
|
// path walks a preference-ordered copy of the list) so the settings device
|
||||||
|
// picker can show the device automatic selection resolved to.
|
||||||
|
{
|
||||||
|
const VkPhysicalDevice active_physical_device =
|
||||||
|
provider->vulkan_device_->physical_device();
|
||||||
|
for (size_t i = 0; i < physical_devices.size(); ++i) {
|
||||||
|
if (physical_devices[i] == active_physical_device) {
|
||||||
|
GraphicsDeviceList device_list = GetGraphicsDeviceList();
|
||||||
|
device_list.active_index = int32_t(i);
|
||||||
|
SetGraphicsDeviceList(std::move(device_list));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (with_presentation) {
|
if (with_presentation) {
|
||||||
provider->ui_samplers_ = UISamplers::Create(provider->vulkan_device_.get());
|
provider->ui_samplers_ = UISamplers::Create(provider->vulkan_device_.get());
|
||||||
if (!provider->ui_samplers_) {
|
if (!provider->ui_samplers_) {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue