If there are multiple Vulkan devices, show a setting to allow the user to choose.

This commit is contained in:
Henrik Rydgård 2018-04-15 09:56:37 +02:00
parent b9388f50e1
commit b037efdb55
18 changed files with 124 additions and 33 deletions

View File

@ -213,6 +213,7 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) {
assert(gpu_count > 0);
physical_devices_.resize(gpu_count);
physicalDeviceProperties_.resize(gpu_count);
res = vkEnumeratePhysicalDevices(instance_, &gpu_count, physical_devices_.data());
if (res != VK_SUCCESS) {
init_error_ = "Failed to enumerate physical devices";
@ -221,6 +222,9 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) {
return res;
}
for (uint32_t i = 0; i < gpu_count; i++) {
vkGetPhysicalDeviceProperties(physical_devices_[i], &physicalDeviceProperties_[i]);
}
return VK_SUCCESS;
}
@ -417,6 +421,14 @@ bool VulkanContext::CheckLayers(const std::vector<LayerProperties> &layer_props,
return true;
}
int VulkanContext::GetPhysicalDeviceByName(std::string name) {
for (size_t i = 0; i < physical_devices_.size(); i++) {
if (physicalDeviceProperties_[i].deviceName == name)
return (int)i;
}
return -1;
}
int VulkanContext::GetBestPhysicalDevice() {
// Rules: Prefer discrete over embedded.
// Prefer nVidia over Intel.
@ -490,7 +502,6 @@ void VulkanContext::ChooseDevice(int physical_device) {
// This is as good a place as any to do this
vkGetPhysicalDeviceMemoryProperties(physical_devices_[physical_device_], &memory_properties);
vkGetPhysicalDeviceProperties(physical_devices_[physical_device_], &gpu_props);
// Optional features
vkGetPhysicalDeviceFeatures(physical_devices_[physical_device_], &featuresAvailable_);

View File

@ -128,6 +128,7 @@ public:
void DestroyInstance();
int GetBestPhysicalDevice();
int GetPhysicalDeviceByName(std::string name);
void ChooseDevice(int physical_device);
bool EnableDeviceExtension(const char *extension);
VkResult CreateDevice();
@ -173,6 +174,12 @@ public:
VkPhysicalDevice GetPhysicalDevice(int n = 0) const {
return physical_devices_[n];
}
int GetCurrentPhysicalDevice() const {
return physical_device_;
}
int GetNumPhysicalDevices() const {
return (int)physical_devices_.size();
}
VkQueue GetGraphicsQueue() const {
return gfx_queue_;
@ -182,8 +189,8 @@ public:
return graphics_queue_family_index_;
}
const VkPhysicalDeviceProperties &GetPhysicalDeviceProperties() {
return gpu_props;
const VkPhysicalDeviceProperties &GetPhysicalDeviceProperties(int i) const {
return physicalDeviceProperties_[i];
}
VkResult GetInstanceLayerExtensionList(const char *layerName, std::vector<VkExtensionProperties> &extensions);
@ -281,7 +288,7 @@ private:
int physical_device_ = -1;
uint32_t graphics_queue_family_index_ = -1;
VkPhysicalDeviceProperties gpu_props{};
std::vector<VkPhysicalDeviceProperties> physicalDeviceProperties_{};
std::vector<VkQueueFamilyProperties> queue_props;
VkPhysicalDeviceMemoryProperties memory_properties{};

View File

@ -507,6 +507,7 @@ static ConfigSetting graphicsSettings[] = {
ConfigSetting("CardboardYShift", &g_Config.iCardboardXShift, 0, true, true),
ConfigSetting("ShowFPSCounter", &g_Config.iShowFPSCounter, 0, true, true),
ReportedConfigSetting("GraphicsBackend", &g_Config.iGPUBackend, &DefaultGPUBackend),
ConfigSetting("VulkanDevice", &g_Config.VulkanDevice, "", true, false),
ReportedConfigSetting("RenderingMode", &g_Config.iRenderingMode, &DefaultRenderingMode, true, true),
ConfigSetting("SoftwareRenderer", &g_Config.bSoftwareRendering, false, true, true),
ReportedConfigSetting("HardwareTransform", &g_Config.bHardwareTransform, true, true, true),

View File

@ -153,6 +153,9 @@ public:
// GFX
int iGPUBackend;
// We have separate device parameters for each backend so it doesn't get erased if you switch backends.
// If not set, will use the "best" device.
std::string VulkanDevice;
bool bSoftwareRendering;
bool bHardwareTransform; // only used in the GLES backend
bool bSoftwareSkinning; // may speed up some games

View File

@ -1007,7 +1007,7 @@ void DrawEngineVulkan::TessellationDataTransferVulkan::PrepareBuffers(float *&po
float color[4];
};
int ssboAlignment = vulkan_->GetPhysicalDeviceProperties().limits.minStorageBufferOffsetAlignment;
int ssboAlignment = vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).limits.minStorageBufferOffsetAlignment;
uint8_t *data = (uint8_t *)push_->PushAligned(size * sizeof(TessData), &offset_, &buf_, ssboAlignment);
range_ = size * sizeof(TessData);

View File

@ -175,7 +175,7 @@ GPU_Vulkan::~GPU_Vulkan() {
void GPU_Vulkan::CheckGPUFeatures() {
uint32_t features = 0;
switch (vulkan_->GetPhysicalDeviceProperties().vendorID) {
switch (vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).vendorID) {
case VULKAN_VENDOR_AMD:
// Accurate depth is required on AMD (due to reverse-Z driver bug) so we ignore the compat flag to disable it on those. See #9545
features |= GPU_SUPPORTS_ACCURATE_DEPTH;
@ -183,7 +183,7 @@ void GPU_Vulkan::CheckGPUFeatures() {
case VULKAN_VENDOR_ARM:
// Also required on older ARM Mali drivers, like the one on many Galaxy S7.
if (!PSP_CoreParameter().compat.flags().DisableAccurateDepth ||
vulkan_->GetPhysicalDeviceProperties().driverVersion <= VK_MAKE_VERSION(428, 811, 2674)) {
vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).driverVersion <= VK_MAKE_VERSION(428, 811, 2674)) {
features |= GPU_SUPPORTS_ACCURATE_DEPTH;
}
break;
@ -212,7 +212,7 @@ void GPU_Vulkan::CheckGPUFeatures() {
features |= GPU_SUPPORTS_DEPTH_CLAMP;
}
if (vulkan_->GetFeaturesEnabled().dualSrcBlend) {
switch (vulkan_->GetPhysicalDeviceProperties().vendorID) {
switch (vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).vendorID) {
// We thought we had a bug here on nVidia but turns out we accidentally #ifdef-ed out crucial
// code on Android.
case VULKAN_VENDOR_INTEL:
@ -220,7 +220,7 @@ void GPU_Vulkan::CheckGPUFeatures() {
break;
case VULKAN_VENDOR_AMD:
// See issue #10074, and also #10065 (AMD) and #10109 for the choice of the driver version to check for
if (vulkan_->GetPhysicalDeviceProperties().driverVersion >= 0x00407000)
if (vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).driverVersion >= 0x00407000)
features |= GPU_SUPPORTS_DUALSOURCE_BLEND;
break;
default:
@ -310,7 +310,7 @@ void GPU_Vulkan::EndHostFrame() {
// Needs to be called on GPU thread, not reporting thread.
void GPU_Vulkan::BuildReportingInfo() {
const auto &props = vulkan_->GetPhysicalDeviceProperties();
const auto &props = vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice());
const auto &features = vulkan_->GetFeaturesAvailable();
#define CHECK_BOOL_FEATURE(n) do { if (features.n) { featureNames += ", " #n; } } while (false)

View File

@ -676,7 +676,7 @@ bool PipelineManagerVulkan::LoadCache(FILE *file, bool loadRawPipelineCache, Sha
WARN_LOG(G3D, "Bad Vulkan pipeline cache header - ignoring");
return false;
}
if (0 != memcmp(header->uuid, vulkan_->GetPhysicalDeviceProperties().pipelineCacheUUID, VK_UUID_SIZE)) {
if (0 != memcmp(header->uuid, vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).pipelineCacheUUID, VK_UUID_SIZE)) {
// Wrong hardware/driver/etc.
WARN_LOG(G3D, "Bad Vulkan pipeline cache UUID - ignoring");
return false;

View File

@ -159,7 +159,7 @@ std::string VulkanVertexShader::GetShaderString(DebugShaderStringType type) cons
ShaderManagerVulkan::ShaderManagerVulkan(VulkanContext *vulkan)
: vulkan_(vulkan), lastVShader_(nullptr), lastFShader_(nullptr), fsCache_(16), vsCache_(16) {
codeBuffer_ = new char[16384];
uboAlignment_ = vulkan_->GetPhysicalDeviceProperties().limits.minUniformBufferOffsetAlignment;
uboAlignment_ = vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).limits.minUniformBufferOffsetAlignment;
memset(&ub_base, 0, sizeof(ub_base));
memset(&ub_lights, 0, sizeof(ub_lights));
memset(&ub_bones, 0, sizeof(ub_bones));
@ -176,7 +176,7 @@ ShaderManagerVulkan::~ShaderManagerVulkan() {
void ShaderManagerVulkan::DeviceRestore(VulkanContext *vulkan) {
vulkan_ = vulkan;
uboAlignment_ = vulkan_->GetPhysicalDeviceProperties().limits.minUniformBufferOffsetAlignment;
uboAlignment_ = vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).limits.minUniformBufferOffsetAlignment;
}
void ShaderManagerVulkan::Clear() {

View File

@ -683,7 +683,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) {
uint32_t bufferOffset;
VkBuffer texBuf;
// nvidia returns 1 but that can't be healthy... let's align by 16 as a minimum.
int pushAlignment = std::max(16, (int)vulkan_->GetPhysicalDeviceProperties().limits.optimalBufferCopyOffsetAlignment);
int pushAlignment = std::max(16, (int)vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).limits.optimalBufferCopyOffsetAlignment);
void *data = drawEngine_->GetPushBufferForTextureData()->PushAligned(size, &bufferOffset, &texBuf, pushAlignment);
if (replaced.Valid()) {
replaced.Load(i, data, stride);

View File

@ -202,6 +202,19 @@ void GameSettingsScreen::CreateViews() {
renderingBackendChoice->HideChoice(3);
}
#endif
Draw::DrawContext *draw = screenManager()->getDrawContext();
if (draw->GetDeviceList().size() > 0) {
// Some backends don't support switching so no point in showing multiple devices.
std::string *deviceNameSetting = nullptr;
if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN) {
deviceNameSetting = &g_Config.VulkanDevice;
}
if (deviceNameSetting) {
PopupMultiChoiceDynamic *deviceChoice = graphicsSettings->Add(new PopupMultiChoiceDynamic(deviceNameSetting, gr->T("Device"), draw->GetDeviceList(), nullptr, screenManager()));
deviceChoice->OnChoice.Handle(this, &GameSettingsScreen::OnRenderingBackend);
}
}
static const char *renderingMode[] = { "Non-Buffered Rendering", "Buffered Rendering"};
PopupMultiChoice *renderingModeChoice = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iRenderingMode, gr->T("Mode"), renderingMode, 0, ARRAY_SIZE(renderingMode), gr->GetName(), screenManager()));

View File

@ -109,7 +109,12 @@ bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_m
g_Vulkan = nullptr;
return false;
}
g_Vulkan->ChooseDevice(g_Vulkan->GetBestPhysicalDevice());
int deviceNum = g_Vulkan->GetPhysicalDeviceByName(g_Config.VulkanDevice);
if (deviceNum < 0) {
deviceNum = g_Vulkan->GetBestPhysicalDevice();
g_Config.VulkanDevice = g_Vulkan->GetPhysicalDeviceProperties(deviceNum).deviceName;
}
g_Vulkan->ChooseDevice(deviceNum);
if (g_Vulkan->EnableDeviceExtension(VK_NV_DEDICATED_ALLOCATION_EXTENSION_NAME)) {
supportsDedicatedAlloc_ = true;
}

View File

@ -850,7 +850,7 @@ void VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKRStep &step
// See pull request #10723.
bool maliBugWorkaround = step.render.numDraws == 0 &&
step.render.color == VKRRenderPassAction::CLEAR &&
vulkan_->GetPhysicalDeviceProperties().driverVersion == 0xaa9c4b29;
vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).driverVersion == 0xaa9c4b29;
if (maliBugWorkaround) {
TransitionImageLayout2(cmd, step.render.framebuffer->color.image, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT,
fb->color.layout, VK_IMAGE_LAYOUT_GENERAL,

View File

@ -136,7 +136,7 @@ VulkanRenderManager::VulkanRenderManager(VulkanContext *vulkan) : vulkan_(vulkan
queueRunner_.CreateDeviceObjects();
// Temporary AMD hack for issue #10097
if (vulkan_->GetPhysicalDeviceProperties().vendorID == VULKAN_VENDOR_AMD) {
if (vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).vendorID == VULKAN_VENDOR_AMD) {
useThread_ = false;
}
}

View File

@ -491,6 +491,7 @@ struct DeviceCaps {
bool framebufferBlitSupported;
bool framebufferDepthCopySupported;
bool framebufferDepthBlitSupported;
std::string deviceName; // The device name to use when creating the thin3d context, to get the same one.
};
struct TextureDesc {
@ -532,6 +533,7 @@ public:
virtual uint32_t GetDataFormatSupport(DataFormat fmt) const = 0;
virtual std::vector<std::string> GetFeatureList() const { return std::vector<std::string>(); }
virtual std::vector<std::string> GetExtensionList() const { return std::vector<std::string>(); }
virtual std::vector<std::string> GetDeviceList() const { return std::vector<std::string>(); }
virtual uint32_t GetSupportedShaderLanguages() const = 0;

View File

@ -33,6 +33,6 @@ DrawContext *T3DCreateDX9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapt
DrawContext *T3DCreateD3D11Context(ID3D11Device *device, ID3D11DeviceContext *context, ID3D11Device1 *device1, ID3D11DeviceContext1 *context1, D3D_FEATURE_LEVEL featureLevel, HWND hWnd);
#endif
DrawContext *T3DCreateVulkanContext(VulkanContext *context, bool split);
DrawContext *T3DCreateVulkanContext(VulkanContext *context, bool splitSubmit);
} // namespace Draw

View File

@ -261,7 +261,7 @@ public:
// Returns the binding offset, and the VkBuffer to bind.
size_t PushUBO(VulkanPushBuffer *buf, VulkanContext *vulkan, VkBuffer *vkbuf) {
return buf->PushAligned(ubo_, uboSize_, vulkan->GetPhysicalDeviceProperties().limits.minUniformBufferOffsetAlignment, vkbuf);
return buf->PushAligned(ubo_, uboSize_, vulkan->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).limits.minUniformBufferOffsetAlignment, vkbuf);
}
int GetUniformLoc(const char *name);
@ -350,6 +350,13 @@ public:
const DeviceCaps &GetDeviceCaps() const override {
return caps_;
}
std::vector<std::string> GetDeviceList() const override {
std::vector<std::string> list;
for (int i = 0; i < vulkan_->GetNumPhysicalDevices(); i++) {
list.push_back(vulkan_->GetPhysicalDeviceProperties(i).deviceName);
}
return list;
}
uint32_t GetSupportedShaderLanguages() const override {
return (uint32_t)ShaderLanguage::GLSL_VULKAN | (uint32_t)ShaderLanguage::SPIRV_VULKAN;
}
@ -446,13 +453,13 @@ public:
// TODO: Make these actually query the right information
switch (info) {
case APINAME: return "Vulkan";
case VENDORSTRING: return vulkan_->GetPhysicalDeviceProperties().deviceName;
case VENDOR: return VulkanVendorString(vulkan_->GetPhysicalDeviceProperties().vendorID);
case DRIVER: return FormatDriverVersion(vulkan_->GetPhysicalDeviceProperties());
case VENDORSTRING: return vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).deviceName;
case VENDOR: return VulkanVendorString(vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).vendorID);
case DRIVER: return FormatDriverVersion(vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()));
case SHADELANGVERSION: return "N/A";;
case APIVERSION:
{
uint32_t ver = vulkan_->GetPhysicalDeviceProperties().apiVersion;
uint32_t ver = vulkan_->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).apiVersion;
return StringFromFormat("%d.%d.%d", ver >> 22, (ver >> 12) & 0x3ff, ver & 0xfff);
}
default: return "?";
@ -746,7 +753,7 @@ VKContext::VKContext(VulkanContext *vulkan, bool splitSubmit)
caps_.framebufferDepthCopySupported = true; // Will pretty much always be the case.
caps_.preferredDepthBufferFormat = DataFormat::D24_S8; // TODO: Ask vulkan.
switch (vulkan->GetPhysicalDeviceProperties().vendorID) {
switch (vulkan->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).vendorID) {
case VULKAN_VENDOR_AMD: caps_.vendor = GPUVendor::VENDOR_AMD; break;
case VULKAN_VENDOR_ARM: caps_.vendor = GPUVendor::VENDOR_ARM; break;
case VULKAN_VENDOR_IMGTEC: caps_.vendor = GPUVendor::VENDOR_IMGTEC; break;

View File

@ -444,6 +444,8 @@ void PopupMultiChoice::Update() {
}
void PopupMultiChoice::UpdateText() {
if (!choices_)
return;
I18NCategory *category = GetI18NCategory(category_);
// Clamp the value to be safe.
if (*value_ < minVal_ || *value_ > minVal_ + numChoices_ - 1) {
@ -466,6 +468,7 @@ void PopupMultiChoice::ChoiceCallback(int num) {
if (restoreFocus_) {
SetFocusedView(this);
}
PostChoiceCallback(num);
}
}

View File

@ -237,11 +237,13 @@ private:
class PopupMultiChoice : public UI::Choice {
public:
PopupMultiChoice(int *value, const std::string &text, const char **choices, int minVal, int numChoices,
const char *category, ScreenManager *screenManager, UI::LayoutParams *layoutParams = 0)
const char *category, ScreenManager *screenManager, UI::LayoutParams *layoutParams = nullptr)
: UI::Choice(text, "", false, layoutParams), value_(value), choices_(choices), minVal_(minVal), numChoices_(numChoices),
category_(category), screenManager_(screenManager) {
if (*value >= numChoices+minVal) *value = numChoices+minVal-1;
if (*value < minVal) *value = minVal;
if (*value >= numChoices + minVal)
*value = numChoices + minVal - 1;
if (*value < minVal)
*value = minVal;
OnClick.Handle(this, &PopupMultiChoice::HandleClick);
UpdateText();
}
@ -255,16 +257,19 @@ public:
UI::Event OnChoice;
private:
void UpdateText();
UI::EventReturn HandleClick(UI::EventParams &e);
void ChoiceCallback(int num);
protected:
int *value_;
const char **choices_;
int minVal_;
int numChoices_;
void UpdateText();
private:
UI::EventReturn HandleClick(UI::EventParams &e);
void ChoiceCallback(int num);
virtual void PostChoiceCallback(int num) {}
const char *category_;
ScreenManager *screenManager_;
std::string valueText_;
@ -272,6 +277,40 @@ private:
std::set<int> hidden_;
};
// Allows passing in a dynamic vector of strings. Saves the string.
class PopupMultiChoiceDynamic : public PopupMultiChoice {
public:
PopupMultiChoiceDynamic(std::string *value, const std::string &text, std::vector<std::string> choices,
const char *category, ScreenManager *screenManager, UI::LayoutParams *layoutParams = nullptr)
: UI::PopupMultiChoice(&valueInt_, text, nullptr, 0, (int)choices.size(), category, screenManager, layoutParams),
valueStr_(value) {
choices_ = new const char *[numChoices_];
valueInt_ = 0;
for (int i = 0; i < numChoices_; i++) {
choices_[i] = new char[choices[i].size() + 1];
memcpy((char *)choices_[i], choices[i].c_str(), choices[i].size() + 1);
if (*value == choices_[i])
valueInt_ = i;
}
value_ = &valueInt_;
UpdateText();
}
~PopupMultiChoiceDynamic() {
for (int i = 0; i < numChoices_; i++) {
delete[] choices_[i];
}
delete[] choices_;
}
protected:
void PostChoiceCallback(int num) {
*valueStr_ = choices_[num];
}
private:
int valueInt_;
std::string *valueStr_;
};
class PopupSliderChoice : public Choice {
public: