From b037efdb55d4ccc00130931b4ffea3dad8271037 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 15 Apr 2018 09:56:37 +0200 Subject: [PATCH 1/3] If there are multiple Vulkan devices, show a setting to allow the user to choose. --- Common/Vulkan/VulkanContext.cpp | 13 +++++- Common/Vulkan/VulkanContext.h | 13 ++++-- Core/Config.cpp | 1 + Core/Config.h | 3 ++ GPU/Vulkan/DrawEngineVulkan.cpp | 2 +- GPU/Vulkan/GPU_Vulkan.cpp | 10 ++--- GPU/Vulkan/PipelineManagerVulkan.cpp | 2 +- GPU/Vulkan/ShaderManagerVulkan.cpp | 4 +- GPU/Vulkan/TextureCacheVulkan.cpp | 2 +- UI/GameSettingsScreen.cpp | 13 ++++++ Windows/GPU/WindowsVulkanContext.cpp | 7 ++- ext/native/thin3d/VulkanQueueRunner.cpp | 2 +- ext/native/thin3d/VulkanRenderManager.cpp | 2 +- ext/native/thin3d/thin3d.h | 2 + ext/native/thin3d/thin3d_create.h | 2 +- ext/native/thin3d/thin3d_vulkan.cpp | 19 +++++--- ext/native/ui/ui_screen.cpp | 3 ++ ext/native/ui/ui_screen.h | 55 +++++++++++++++++++---- 18 files changed, 123 insertions(+), 32 deletions(-) diff --git a/Common/Vulkan/VulkanContext.cpp b/Common/Vulkan/VulkanContext.cpp index 5b3da0b7d79a..ffe7ba5a3f43 100644 --- a/Common/Vulkan/VulkanContext.cpp +++ b/Common/Vulkan/VulkanContext.cpp @@ -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 &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_); diff --git a/Common/Vulkan/VulkanContext.h b/Common/Vulkan/VulkanContext.h index 6466f7b39049..e58824cd26c5 100644 --- a/Common/Vulkan/VulkanContext.h +++ b/Common/Vulkan/VulkanContext.h @@ -128,6 +128,7 @@ class VulkanContext { 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 @@ class VulkanContext { 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 @@ class VulkanContext { 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 &extensions); @@ -281,7 +288,7 @@ class VulkanContext { int physical_device_ = -1; uint32_t graphics_queue_family_index_ = -1; - VkPhysicalDeviceProperties gpu_props{}; + std::vector physicalDeviceProperties_{}; std::vector queue_props; VkPhysicalDeviceMemoryProperties memory_properties{}; diff --git a/Core/Config.cpp b/Core/Config.cpp index e2bde296d9fc..9350941f3c54 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -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), diff --git a/Core/Config.h b/Core/Config.h index 466624ce6722..3a022646c932 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -153,6 +153,9 @@ struct Config { // 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 diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index b8c62f596ecd..76643d606691 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -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); diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 5790fe146e31..69cd57feb606 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -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) diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index 4498dedb78fb..83cdf0ee28ac 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -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; diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index 2168eae5b1b9..3a06fc2d0d42 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -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() { diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index 8553985564db..cc6d6dedaa54 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -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); diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 904477697e72..be1d8ef3e60e 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -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())); diff --git a/Windows/GPU/WindowsVulkanContext.cpp b/Windows/GPU/WindowsVulkanContext.cpp index 0e71ace5435c..3ec3d0820738 100644 --- a/Windows/GPU/WindowsVulkanContext.cpp +++ b/Windows/GPU/WindowsVulkanContext.cpp @@ -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; } diff --git a/ext/native/thin3d/VulkanQueueRunner.cpp b/ext/native/thin3d/VulkanQueueRunner.cpp index 1be6960540be..ed71016192f8 100644 --- a/ext/native/thin3d/VulkanQueueRunner.cpp +++ b/ext/native/thin3d/VulkanQueueRunner.cpp @@ -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, diff --git a/ext/native/thin3d/VulkanRenderManager.cpp b/ext/native/thin3d/VulkanRenderManager.cpp index 325d0f6851e3..e59344279802 100644 --- a/ext/native/thin3d/VulkanRenderManager.cpp +++ b/ext/native/thin3d/VulkanRenderManager.cpp @@ -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; } } diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index 323850fe434c..3c95516ce039 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -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 @@ class DrawContext { virtual uint32_t GetDataFormatSupport(DataFormat fmt) const = 0; virtual std::vector GetFeatureList() const { return std::vector(); } virtual std::vector GetExtensionList() const { return std::vector(); } + virtual std::vector GetDeviceList() const { return std::vector(); } virtual uint32_t GetSupportedShaderLanguages() const = 0; diff --git a/ext/native/thin3d/thin3d_create.h b/ext/native/thin3d/thin3d_create.h index 3d4ea0f1a4ab..9d2ea4a844f9 100644 --- a/ext/native/thin3d/thin3d_create.h +++ b/ext/native/thin3d/thin3d_create.h @@ -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 diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp index c71ff4f716d3..065bf4c7f0d0 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/ext/native/thin3d/thin3d_vulkan.cpp @@ -261,7 +261,7 @@ class VKPipeline : public Pipeline { // 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 @@ class VKContext : public DrawContext { const DeviceCaps &GetDeviceCaps() const override { return caps_; } + std::vector GetDeviceList() const override { + std::vector 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 @@ class VKContext : public DrawContext { // 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; diff --git a/ext/native/ui/ui_screen.cpp b/ext/native/ui/ui_screen.cpp index e6830635f398..b4a4edb76b47 100644 --- a/ext/native/ui/ui_screen.cpp +++ b/ext/native/ui/ui_screen.cpp @@ -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); } } diff --git a/ext/native/ui/ui_screen.h b/ext/native/ui/ui_screen.h index f2fe7b157fa6..fb0bda449421 100644 --- a/ext/native/ui/ui_screen.h +++ b/ext/native/ui/ui_screen.h @@ -237,11 +237,13 @@ class TextEditPopupScreen : public PopupScreen { 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 @@ class PopupMultiChoice : public UI::Choice { UI::Event OnChoice; -private: +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) {} - int *value_; - const char **choices_; - int minVal_; - int numChoices_; const char *category_; ScreenManager *screenManager_; std::string valueText_; @@ -272,6 +277,40 @@ class PopupMultiChoice : public UI::Choice { std::set 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 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: From 8ee3cd52e89fab0d78d18fc2b99a5132712e25c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 15 Apr 2018 10:53:07 +0200 Subject: [PATCH 2/3] D3D11: Allow the user to select rendering device. --- Core/Config.cpp | 3 ++ Core/Config.h | 3 ++ UI/GameSettingsScreen.cpp | 8 +++-- Windows/GPU/D3D11Context.cpp | 53 +++++++++++++++++++++--------- Windows/GPU/D3D11Context.h | 5 ++- ext/native/thin3d/thin3d_create.h | 4 ++- ext/native/thin3d/thin3d_d3d11.cpp | 18 +++++----- 7 files changed, 65 insertions(+), 29 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index 9350941f3c54..04a7b488e605 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -508,6 +508,9 @@ static ConfigSetting graphicsSettings[] = { ConfigSetting("ShowFPSCounter", &g_Config.iShowFPSCounter, 0, true, true), ReportedConfigSetting("GraphicsBackend", &g_Config.iGPUBackend, &DefaultGPUBackend), ConfigSetting("VulkanDevice", &g_Config.VulkanDevice, "", true, false), +#ifdef _WIN32 + ConfigSetting("D3D11Device", &g_Config.D3D11Device, "", true, false), +#endif ReportedConfigSetting("RenderingMode", &g_Config.iRenderingMode, &DefaultRenderingMode, true, true), ConfigSetting("SoftwareRenderer", &g_Config.bSoftwareRendering, false, true, true), ReportedConfigSetting("HardwareTransform", &g_Config.bHardwareTransform, true, true, true), diff --git a/Core/Config.h b/Core/Config.h index 3a022646c932..24f963edee7f 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -156,6 +156,9 @@ struct Config { // 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; +#ifdef _WIN32 + std::string D3D11Device; +#endif bool bSoftwareRendering; bool bHardwareTransform; // only used in the GLES backend bool bSoftwareSkinning; // may speed up some games diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index be1d8ef3e60e..f41d8b4fdb1a 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -203,13 +203,17 @@ void GameSettingsScreen::CreateViews() { } #endif Draw::DrawContext *draw = screenManager()->getDrawContext(); - if (draw->GetDeviceList().size() > 0) { + if (draw->GetDeviceList().size() > 1) { // 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; } - +#ifdef _WIN32 + if (g_Config.iGPUBackend == (int)GPUBackend::DIRECT3D11) { + deviceNameSetting = &g_Config.D3D11Device; + } +#endif if (deviceNameSetting) { PopupMultiChoiceDynamic *deviceChoice = graphicsSettings->Add(new PopupMultiChoiceDynamic(deviceNameSetting, gr->T("Device"), draw->GetDeviceList(), nullptr, screenManager())); deviceChoice->OnChoice.Handle(this, &GameSettingsScreen::OnRenderingBackend); diff --git a/Windows/GPU/D3D11Context.cpp b/Windows/GPU/D3D11Context.cpp index 28b1540af3b9..4470464582e0 100644 --- a/Windows/GPU/D3D11Context.cpp +++ b/Windows/GPU/D3D11Context.cpp @@ -2,6 +2,7 @@ #include "Common/CommonWindows.h" #include +#include #include #include "base/logging.h" @@ -22,6 +23,12 @@ #define __uuidof(type) IID_##type #endif +#ifndef DXGI_ERROR_NOT_FOUND +#define _FACDXGI 0x87a +#define MAKE_DXGI_HRESULT(code) MAKE_HRESULT(1, _FACDXGI, code) +#define DXGI_ERROR_NOT_FOUND MAKE_DXGI_HRESULT(2) +#endif + #if PPSSPP_PLATFORM(UWP) #error This file should not be compiled for UWP. #endif @@ -41,7 +48,7 @@ void D3D11Context::SwapInterval(int interval) { // Dummy } -HRESULT D3D11Context::CreateTheDevice() { +HRESULT D3D11Context::CreateTheDevice(IDXGIAdapter *adapter) { bool windowed = true; #ifdef _DEBUG UINT createDeviceFlags = D3D11_CREATE_DEVICE_DEBUG; @@ -70,19 +77,13 @@ HRESULT D3D11Context::CreateTheDevice() { const UINT numFeatureLevels = ARRAYSIZE(featureLevels); HRESULT hr = S_OK; - // Temporarily commenting out until we can dynamically load D3D11CreateDevice. - for (UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++) { - driverType_ = driverTypes[driverTypeIndex]; - hr = ptr_D3D11CreateDevice(nullptr, driverType_, nullptr, createDeviceFlags, (D3D_FEATURE_LEVEL *)featureLevels, numFeatureLevels, + D3D_DRIVER_TYPE driverType = D3D_DRIVER_TYPE_UNKNOWN; + hr = ptr_D3D11CreateDevice(adapter, driverType, nullptr, createDeviceFlags, (D3D_FEATURE_LEVEL *)featureLevels, numFeatureLevels, + D3D11_SDK_VERSION, &device_, &featureLevel_, &context_); + if (hr == E_INVALIDARG) { + // DirectX 11.0 platforms will not recognize D3D_FEATURE_LEVEL_11_1 so we need to retry without it + hr = ptr_D3D11CreateDevice(adapter, driverType, nullptr, createDeviceFlags, (D3D_FEATURE_LEVEL *)&featureLevels[3], numFeatureLevels - 3, D3D11_SDK_VERSION, &device_, &featureLevel_, &context_); - - if (hr == E_INVALIDARG) { - // DirectX 11.0 platforms will not recognize D3D_FEATURE_LEVEL_11_1 so we need to retry without it - hr = ptr_D3D11CreateDevice(nullptr, driverType_, nullptr, createDeviceFlags, (D3D_FEATURE_LEVEL *)&featureLevels[3], numFeatureLevels - 3, - D3D11_SDK_VERSION, &device_, &featureLevel_, &context_); - } - if (SUCCEEDED(hr)) - break; } return hr; } @@ -99,8 +100,30 @@ bool D3D11Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) { LoadD3D11Error result = LoadD3D11(); HRESULT hr = E_FAIL; + std::vector adapterNames; if (result == LoadD3D11Error::SUCCESS) { - hr = CreateTheDevice(); + std::vector adapters; + int chosenAdapter = 0; + + IDXGIFactory * pFactory = nullptr; + ptr_CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&pFactory); + + IDXGIAdapter *pAdapter; + for (UINT i = 0; pFactory->EnumAdapters(i, &pAdapter) != DXGI_ERROR_NOT_FOUND; i++) { + adapters.push_back(pAdapter); + DXGI_ADAPTER_DESC desc; + pAdapter->GetDesc(&desc); + std::string str = ConvertWStringToUTF8(desc.Description); + adapterNames.push_back(str); + if (str == g_Config.D3D11Device) { + chosenAdapter = i; + } + } + + hr = CreateTheDevice(adapters[chosenAdapter]); + for (int i = 0; i < (int)adapters.size(); i++) { + adapters[i]->Release(); + } } if (FAILED(hr)) { @@ -146,7 +169,7 @@ bool D3D11Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) { } #endif - draw_ = Draw::T3DCreateD3D11Context(device_, context_, device1_, context1_, featureLevel_, hWnd_); + draw_ = Draw::T3DCreateD3D11Context(device_, context_, device1_, context1_, featureLevel_, hWnd_, adapterNames); SetGPUBackend(GPUBackend::DIRECT3D11); bool success = draw_->CreatePresets(); // If we can run D3D11, there's a compiler installed. I think. assert(success); diff --git a/Windows/GPU/D3D11Context.h b/Windows/GPU/D3D11Context.h index b0f424762831..88f1547295af 100644 --- a/Windows/GPU/D3D11Context.h +++ b/Windows/GPU/D3D11Context.h @@ -40,7 +40,7 @@ class D3D11Context : public WindowsGraphicsContext { Draw::DrawContext *GetDrawContext() override { return draw_; } private: - HRESULT CreateTheDevice(); + HRESULT CreateTheDevice(IDXGIAdapter *adapter); void LostBackbuffer(); void GotBackbuffer(); @@ -60,7 +60,6 @@ class D3D11Context : public WindowsGraphicsContext { ID3D11InfoQueue *d3dInfoQueue_ = nullptr; #endif - D3D_DRIVER_TYPE driverType_; D3D_FEATURE_LEVEL featureLevel_ = D3D_FEATURE_LEVEL_11_0; int adapterId; HDC hDC; // Private GDI Device Context @@ -68,4 +67,4 @@ class D3D11Context : public WindowsGraphicsContext { HMODULE hD3D11; int width; int height; -}; \ No newline at end of file +}; diff --git a/ext/native/thin3d/thin3d_create.h b/ext/native/thin3d/thin3d_create.h index 9d2ea4a844f9..a89c74ab96a7 100644 --- a/ext/native/thin3d/thin3d_create.h +++ b/ext/native/thin3d/thin3d_create.h @@ -1,5 +1,7 @@ #pragma once +#include +#include #include "thin3d/thin3d.h" // Separated this stuff into its own file so we don't get Windows.h included if all we want is the thin3d declarations. @@ -30,7 +32,7 @@ DrawContext *T3DCreateGLContext(); #ifdef _WIN32 DrawContext *T3DCreateDX9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, IDirect3DDevice9 *device, IDirect3DDevice9Ex *deviceEx); -DrawContext *T3DCreateD3D11Context(ID3D11Device *device, ID3D11DeviceContext *context, ID3D11Device1 *device1, ID3D11DeviceContext1 *context1, D3D_FEATURE_LEVEL featureLevel, HWND hWnd); +DrawContext *T3DCreateD3D11Context(ID3D11Device *device, ID3D11DeviceContext *context, ID3D11Device1 *device1, ID3D11DeviceContext1 *context1, D3D_FEATURE_LEVEL featureLevel, HWND hWnd, std::vector adapterNames); #endif DrawContext *T3DCreateVulkanContext(VulkanContext *context, bool splitSubmit); diff --git a/ext/native/thin3d/thin3d_d3d11.cpp b/ext/native/thin3d/thin3d_d3d11.cpp index 9a3ce86e5a0c..f5e0c2da2796 100644 --- a/ext/native/thin3d/thin3d_d3d11.cpp +++ b/ext/native/thin3d/thin3d_d3d11.cpp @@ -38,12 +38,15 @@ class D3D11RasterState; class D3D11DrawContext : public DrawContext { public: - D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *deviceContext, ID3D11Device1 *device1, ID3D11DeviceContext1 *deviceContext1, D3D_FEATURE_LEVEL featureLevel, HWND hWnd); + D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *deviceContext, ID3D11Device1 *device1, ID3D11DeviceContext1 *deviceContext1, D3D_FEATURE_LEVEL featureLevel, HWND hWnd, std::vector deviceList); ~D3D11DrawContext(); const DeviceCaps &GetDeviceCaps() const override { return caps_; } + std::vector GetDeviceList() const override { + return deviceList_; + } uint32_t GetSupportedShaderLanguages() const override { return (uint32_t)ShaderLanguage::HLSL_D3D11 | (uint32_t)ShaderLanguage::HLSL_D3D11_BYTECODE; } @@ -210,15 +213,17 @@ class D3D11DrawContext : public DrawContext { // System info D3D_FEATURE_LEVEL featureLevel_; std::string adapterDesc_; + std::vector deviceList_; }; -D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *deviceContext, ID3D11Device1 *device1, ID3D11DeviceContext1 *deviceContext1, D3D_FEATURE_LEVEL featureLevel, HWND hWnd) +D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *deviceContext, ID3D11Device1 *device1, ID3D11DeviceContext1 *deviceContext1, D3D_FEATURE_LEVEL featureLevel, HWND hWnd, std::vector deviceList) : device_(device), context_(deviceContext1), device1_(device1), context1_(deviceContext1), featureLevel_(featureLevel), - hWnd_(hWnd) { + hWnd_(hWnd), + deviceList_(deviceList) { // Seems like a fair approximation... caps_.dualSourceBlend = featureLevel_ >= D3D_FEATURE_LEVEL_10_0; @@ -229,7 +234,6 @@ D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *de caps_.framebufferDepthBlitSupported = false; caps_.framebufferDepthCopySupported = true; - D3D11_FEATURE_DATA_D3D11_OPTIONS options{}; HRESULT result = device_->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &options, sizeof(options)); if (SUCCEEDED(result)) { @@ -239,8 +243,6 @@ D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *de // caps_.logicOpSupported = true; } } - // Obtain DXGI factory from device (since we used nullptr for pAdapter above) - IDXGIFactory1* dxgiFactory = nullptr; IDXGIDevice* dxgiDevice = nullptr; IDXGIAdapter* adapter = nullptr; HRESULT hr = device_->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast(&dxgiDevice)); @@ -1552,8 +1554,8 @@ void D3D11DrawContext::GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h } } -DrawContext *T3DCreateD3D11Context(ID3D11Device *device, ID3D11DeviceContext *context, ID3D11Device1 *device1, ID3D11DeviceContext1 *context1, D3D_FEATURE_LEVEL featureLevel, HWND hWnd) { - return new D3D11DrawContext(device, context, device1, context1, featureLevel, hWnd); +DrawContext *T3DCreateD3D11Context(ID3D11Device *device, ID3D11DeviceContext *context, ID3D11Device1 *device1, ID3D11DeviceContext1 *context1, D3D_FEATURE_LEVEL featureLevel, HWND hWnd, std::vector adapterNames) { + return new D3D11DrawContext(device, context, device1, context1, featureLevel, hWnd, adapterNames); } } // namespace Draw From 238521a2978e84c528e24f6015c218df117b0155 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 6 Jun 2018 10:24:16 +0200 Subject: [PATCH 3/3] Rename device choice config options as requested. --- Core/Config.cpp | 4 ++-- Core/Config.h | 4 ++-- UI/GameSettingsScreen.cpp | 7 ++++--- Windows/GPU/D3D11Context.cpp | 2 +- Windows/GPU/WindowsVulkanContext.cpp | 4 ++-- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index 04a7b488e605..69ec5d6baae3 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -507,9 +507,9 @@ 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), + ConfigSetting("VulkanDevice", &g_Config.sVulkanDevice, "", true, false), #ifdef _WIN32 - ConfigSetting("D3D11Device", &g_Config.D3D11Device, "", true, false), + ConfigSetting("D3D11Device", &g_Config.sD3D11Device, "", true, false), #endif ReportedConfigSetting("RenderingMode", &g_Config.iRenderingMode, &DefaultRenderingMode, true, true), ConfigSetting("SoftwareRenderer", &g_Config.bSoftwareRendering, false, true, true), diff --git a/Core/Config.h b/Core/Config.h index 24f963edee7f..05b5f62c94e4 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -155,9 +155,9 @@ struct Config { 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; + std::string sVulkanDevice; #ifdef _WIN32 - std::string D3D11Device; + std::string sD3D11Device; #endif bool bSoftwareRendering; bool bHardwareTransform; // only used in the GLES backend diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index f41d8b4fdb1a..cced4b40f3fa 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -203,15 +203,16 @@ void GameSettingsScreen::CreateViews() { } #endif Draw::DrawContext *draw = screenManager()->getDrawContext(); + + // Backends that don't allow a device choice will only expose one device. if (draw->GetDeviceList().size() > 1) { - // 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; + deviceNameSetting = &g_Config.sVulkanDevice; } #ifdef _WIN32 if (g_Config.iGPUBackend == (int)GPUBackend::DIRECT3D11) { - deviceNameSetting = &g_Config.D3D11Device; + deviceNameSetting = &g_Config.sD3D11Device; } #endif if (deviceNameSetting) { diff --git a/Windows/GPU/D3D11Context.cpp b/Windows/GPU/D3D11Context.cpp index 4470464582e0..7e6b74827170 100644 --- a/Windows/GPU/D3D11Context.cpp +++ b/Windows/GPU/D3D11Context.cpp @@ -115,7 +115,7 @@ bool D3D11Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) { pAdapter->GetDesc(&desc); std::string str = ConvertWStringToUTF8(desc.Description); adapterNames.push_back(str); - if (str == g_Config.D3D11Device) { + if (str == g_Config.sD3D11Device) { chosenAdapter = i; } } diff --git a/Windows/GPU/WindowsVulkanContext.cpp b/Windows/GPU/WindowsVulkanContext.cpp index 3ec3d0820738..e82b5bc92b3e 100644 --- a/Windows/GPU/WindowsVulkanContext.cpp +++ b/Windows/GPU/WindowsVulkanContext.cpp @@ -109,10 +109,10 @@ bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_m g_Vulkan = nullptr; return false; } - int deviceNum = g_Vulkan->GetPhysicalDeviceByName(g_Config.VulkanDevice); + int deviceNum = g_Vulkan->GetPhysicalDeviceByName(g_Config.sVulkanDevice); if (deviceNum < 0) { deviceNum = g_Vulkan->GetBestPhysicalDevice(); - g_Config.VulkanDevice = g_Vulkan->GetPhysicalDeviceProperties(deviceNum).deviceName; + g_Config.sVulkanDevice = g_Vulkan->GetPhysicalDeviceProperties(deviceNum).deviceName; } g_Vulkan->ChooseDevice(deviceNum); if (g_Vulkan->EnableDeviceExtension(VK_NV_DEDICATED_ALLOCATION_EXTENSION_NAME)) {