diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index ee6cf399d6a6..ddcbd0f9a74a 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -932,22 +932,15 @@ VKContext::VKContext(VulkanContext *vulkan, bool useRenderThread) // VkSampleCountFlagBits is arranged correctly for our purposes. // Only support MSAA levels that have support for all three of color, depth, stencil. - if (!caps_.isTilingGPU) { - // Check for depth stencil resolve. Without it, depth textures won't work, and we don't want that mess - // of compatibility reports, so we'll just disable multisampling in this case for now. - // There are potential workarounds for devices that don't support it, but those are nearly non-existent now. - const auto &resolveProperties = vulkan->GetPhysicalDeviceProperties().depthStencilResolve; - if (vulkan->Extensions().KHR_depth_stencil_resolve && - ((resolveProperties.supportedDepthResolveModes & resolveProperties.supportedStencilResolveModes) & VK_RESOLVE_MODE_SAMPLE_ZERO_BIT) != 0) { - caps_.multiSampleLevelsMask = (limits.framebufferColorSampleCounts & limits.framebufferDepthSampleCounts & limits.framebufferStencilSampleCounts); - } else { - caps_.multiSampleLevelsMask = 1; - } - } else { - caps_.multiSampleLevelsMask = 1; - } - if (caps_.vendor == GPUVendor::VENDOR_QUALCOMM) { + bool multisampleAllowed = true; + + caps_.deviceID = deviceProps.deviceID; + + if (caps_.vendor == GPUVendor::VENDOR_QUALCOMM) { + if (caps_.deviceID < 0x6000000) // On sub 6xx series GPUs, disallow multisample. + multisampleAllowed = false; + // Adreno 5xx devices, all known driver versions, fail to discard stencil when depth write is off. // See: https://github.com/hrydgard/ppsspp/pull/11684 if (deviceProps.deviceID >= 0x05000000 && deviceProps.deviceID < 0x06000000) { @@ -1007,13 +1000,38 @@ VKContext::VKContext(VulkanContext *vulkan, bool useRenderThread) bugs_.Infest(Bugs::UNIFORM_INDEXING_BROKEN); } } + + if (isOldVersion) { + // Very rough heuristic. + multisampleAllowed = false; + } + } + + if (!vulkan->Extensions().KHR_depth_stencil_resolve) { + INFO_LOG(G3D, "KHR_depth_stencil_resolve not supported, disabling multisampling"); + } + + // We limit multisampling functionality to reasonably recent and known-good tiling GPUs. + if (multisampleAllowed) { + // Check for depth stencil resolve. Without it, depth textures won't work, and we don't want that mess + // of compatibility reports, so we'll just disable multisampling in this case for now. + // There are potential workarounds for devices that don't support it, but those are nearly non-existent now. + const auto &resolveProperties = vulkan->GetPhysicalDeviceProperties().depthStencilResolve; + if (((resolveProperties.supportedDepthResolveModes & resolveProperties.supportedStencilResolveModes) & VK_RESOLVE_MODE_SAMPLE_ZERO_BIT) != 0) { + caps_.multiSampleLevelsMask = (limits.framebufferColorSampleCounts & limits.framebufferDepthSampleCounts & limits.framebufferStencilSampleCounts); + INFO_LOG(G3D, "Multisample levels mask: %d", caps_.multiSampleLevelsMask); + } else { + INFO_LOG(G3D, "Not enough depth/stencil resolve modes supported, disabling multisampling."); + caps_.multiSampleLevelsMask = 1; + } + } else { + caps_.multiSampleLevelsMask = 1; } // Vulkan can support this through input attachments and various extensions, but not worth // the trouble. caps_.framebufferFetchSupported = false; - caps_.deviceID = deviceProps.deviceID; device_ = vulkan->GetDevice(); VkBufferUsageFlags usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT; diff --git a/Common/UI/PopupScreens.cpp b/Common/UI/PopupScreens.cpp index f3dacb9971e6..2f70fd98106d 100644 --- a/Common/UI/PopupScreens.cpp +++ b/Common/UI/PopupScreens.cpp @@ -36,7 +36,7 @@ void MessagePopupScreen::OnCompleted(DialogResult result) { void ListPopupScreen::CreatePopupContents(UI::ViewGroup *parent) { using namespace UI; - listView_ = parent->Add(new ListView(&adaptor_, hidden_)); //, new LinearLayoutParams(1.0))); + listView_ = parent->Add(new ListView(&adaptor_, hidden_, icons_)); //, new LinearLayoutParams(1.0))); listView_->SetMaxHeight(screenManager()->getUIContext()->GetBounds().h - 140); listView_->OnChoice.Handle(this, &ListPopupScreen::OnListChoice); } @@ -105,6 +105,7 @@ UI::EventReturn PopupMultiChoice::HandleClick(UI::EventParams &e) { ListPopupScreen *popupScreen = new ListPopupScreen(ChopTitle(text_), choices, *value_ - minVal_, std::bind(&PopupMultiChoice::ChoiceCallback, this, std::placeholders::_1)); popupScreen->SetHiddenChoices(hidden_); + popupScreen->SetChoiceIcons(icons_); if (e.v) popupScreen->SetPopupOrigin(e.v); screenManager_->push(popupScreen); @@ -623,8 +624,12 @@ void AbstractChoiceWithValueDisplay::Draw(UIContext &dc) { textPadding_.right = w + paddingX; Choice::Draw(dc); + int imagePadding = 0; + if (rightIconImage_.isValid()) { + imagePadding = bounds_.h; + } dc.SetFontScale(scale, scale); - Bounds valueBounds(bounds_.x2() - textPadding_.right, bounds_.y, w, bounds_.h); + Bounds valueBounds(bounds_.x2() - textPadding_.right - imagePadding, bounds_.y, w, bounds_.h); dc.DrawTextRect(valueText.c_str(), valueBounds, style.fgColor, ALIGN_RIGHT | ALIGN_VCENTER | FLAG_WRAP_TEXT); dc.SetFontScale(1.0f, 1.0f); } else { diff --git a/Common/UI/PopupScreens.h b/Common/UI/PopupScreens.h index 8fdfb68e1f4c..962b5b036bab 100644 --- a/Common/UI/PopupScreens.h +++ b/Common/UI/PopupScreens.h @@ -32,6 +32,9 @@ class ListPopupScreen : public PopupScreen { void SetHiddenChoices(std::set hidden) { hidden_ = hidden; } + void SetChoiceIcons(std::map icons) { + icons_ = icons; + } const char *tag() const override { return "listpopup"; } UI::Event OnChoice; @@ -49,6 +52,7 @@ class ListPopupScreen : public PopupScreen { std::function callback_; bool showButtons_ = false; std::set hidden_; + std::map icons_; }; class MessagePopupScreen : public PopupScreen { @@ -231,6 +235,9 @@ class PopupMultiChoice : public AbstractChoiceWithValueDisplay { void HideChoice(int c) { hidden_.insert(c); } + void SetChoiceIcon(int c, ImageID id) { + icons_[c] = id; + } UI::Event OnChoice; @@ -254,6 +261,7 @@ class PopupMultiChoice : public AbstractChoiceWithValueDisplay { std::string valueText_; bool restoreFocus_ = false; std::set hidden_; + std::map icons_; }; // Allows passing in a dynamic vector of strings. Saves the string. diff --git a/Common/UI/ScrollView.cpp b/Common/UI/ScrollView.cpp index 25bad50c10de..94c712f0b4cd 100644 --- a/Common/UI/ScrollView.cpp +++ b/Common/UI/ScrollView.cpp @@ -496,9 +496,8 @@ void ScrollView::Update() { } } -ListView::ListView(ListAdaptor *a, std::set hidden, LayoutParams *layoutParams) - : ScrollView(ORIENT_VERTICAL, layoutParams), adaptor_(a), maxHeight_(0), hidden_(hidden) { - +ListView::ListView(ListAdaptor *a, std::set hidden, std::map icons, LayoutParams *layoutParams) + : ScrollView(ORIENT_VERTICAL, layoutParams), adaptor_(a), maxHeight_(0), hidden_(hidden), icons_(icons) { linLayout_ = new LinearLayout(ORIENT_VERTICAL); linLayout_->SetSpacing(0.0f); Add(linLayout_); @@ -510,7 +509,12 @@ void ListView::CreateAllItems() { // Let's not be clever yet, we'll just create them all up front and add them all in. for (int i = 0; i < adaptor_->GetNumItems(); i++) { if (hidden_.find(i) == hidden_.end()) { - View *v = linLayout_->Add(adaptor_->CreateItemView(i)); + ImageID *imageID = nullptr; + auto iter = icons_.find(i); + if (iter != icons_.end()) { + imageID = &iter->second; + } + View *v = linLayout_->Add(adaptor_->CreateItemView(i, imageID)); adaptor_->AddEventCallback(v, std::bind(&ListView::OnItemCallback, this, i, std::placeholders::_1)); } } @@ -538,8 +542,12 @@ EventReturn ListView::OnItemCallback(int num, EventParams &e) { return EVENT_DONE; } -View *ChoiceListAdaptor::CreateItemView(int index) { - return new Choice(items_[index]); +View *ChoiceListAdaptor::CreateItemView(int index, ImageID *optionalImageID) { + Choice *choice = new Choice(items_[index]); + if (optionalImageID) { + choice->SetIcon(*optionalImageID); + } + return choice; } bool ChoiceListAdaptor::AddEventCallback(View *view, std::function callback) { @@ -549,8 +557,12 @@ bool ChoiceListAdaptor::AddEventCallback(View *view, std::functionSetIcon(*optionalImageID); + } + return choice; } bool StringVectorListAdaptor::AddEventCallback(View *view, std::function callback) { diff --git a/Common/UI/ScrollView.h b/Common/UI/ScrollView.h index 9a0877b1df75..a5c31a2febb7 100644 --- a/Common/UI/ScrollView.h +++ b/Common/UI/ScrollView.h @@ -89,7 +89,7 @@ class ScrollView : public ViewGroup { class ListAdaptor { public: virtual ~ListAdaptor() {} - virtual View *CreateItemView(int index) = 0; + virtual View *CreateItemView(int index, ImageID *optionalImageID) = 0; virtual int GetNumItems() = 0; virtual bool AddEventCallback(View *view, std::function callback) { return false; } virtual std::string GetTitle(int index) const { return ""; } @@ -100,7 +100,7 @@ class ListAdaptor { class ChoiceListAdaptor : public ListAdaptor { public: ChoiceListAdaptor(const char *items[], int numItems) : items_(items), numItems_(numItems) {} - View *CreateItemView(int index) override; + View *CreateItemView(int index, ImageID *optionalImageID) override; int GetNumItems() override { return numItems_; } bool AddEventCallback(View *view, std::function callback) override; @@ -114,7 +114,7 @@ class StringVectorListAdaptor : public ListAdaptor { public: StringVectorListAdaptor() : selected_(-1) {} StringVectorListAdaptor(const std::vector &items, int selected = -1) : items_(items), selected_(selected) {} - View *CreateItemView(int index) override; + View *CreateItemView(int index, ImageID *optionalImageID) override; int GetNumItems() override { return (int)items_.size(); } bool AddEventCallback(View *view, std::function callback) override; void SetSelected(int sel) override { selected_ = sel; } @@ -130,7 +130,7 @@ class StringVectorListAdaptor : public ListAdaptor { // In the future, it might be smart and load/unload items as they go, but currently not. class ListView : public ScrollView { public: - ListView(ListAdaptor *a, std::set hidden = std::set(), LayoutParams *layoutParams = 0); + ListView(ListAdaptor *a, std::set hidden = std::set(), std::map icons = std::map(), LayoutParams *layoutParams = 0); int GetSelected() { return adaptor_->GetSelected(); } void Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert) override; @@ -146,6 +146,7 @@ class ListView : public ScrollView { LinearLayout *linLayout_; float maxHeight_; std::set hidden_; + std::map icons_; }; } // namespace UI diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index a56191a77f73..9d144bb1a923 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -301,12 +301,19 @@ void GameSettingsScreen::CreateGraphicsSettings(UI::ViewGroup *graphicsSettings) System_PostUIMessage(UIMessage::GPU_RENDER_RESIZED); return UI::EVENT_DONE; }); - msaaChoice->SetDisabledPtr(&g_Config.bSoftwareRendering); + if (g_Config.iMultiSampleLevel > 1 && draw->GetDeviceCaps().isTilingGPU) { + msaaChoice->SetIcon(ImageID("I_WARNING"), 0.7f); + } + msaaChoice->SetEnabledFunc([] { + return !g_Config.bSoftwareRendering && !g_Config.bSkipBufferEffects; + }); // Hide unsupported levels. for (int i = 1; i < 5; i++) { if ((draw->GetDeviceCaps().multiSampleLevelsMask & (1 << i)) == 0) { msaaChoice->HideChoice(i); + } else if (i > 0 && draw->GetDeviceCaps().isTilingGPU) { + msaaChoice->SetChoiceIcon(i, ImageID("I_WARNING")); } } }