Skip to content

Commit

Permalink
Merge pull request #18472 from hrydgard/msaa-on-mobile
Browse files Browse the repository at this point in the history
Vulkan: Allow MSAA on modern-ish mobile devices, but add a little warning sign.
  • Loading branch information
hrydgard committed Dec 3, 2023
2 parents 0c760ba + 1f2dbfa commit c1637b0
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 31 deletions.
50 changes: 34 additions & 16 deletions Common/GPU/Vulkan/thin3d_vulkan.cpp
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down
9 changes: 7 additions & 2 deletions Common/UI/PopupScreens.cpp
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 {
Expand Down
8 changes: 8 additions & 0 deletions Common/UI/PopupScreens.h
Expand Up @@ -32,6 +32,9 @@ class ListPopupScreen : public PopupScreen {
void SetHiddenChoices(std::set<int> hidden) {
hidden_ = hidden;
}
void SetChoiceIcons(std::map<int, ImageID> icons) {
icons_ = icons;
}
const char *tag() const override { return "listpopup"; }

UI::Event OnChoice;
Expand All @@ -49,6 +52,7 @@ class ListPopupScreen : public PopupScreen {
std::function<void(int)> callback_;
bool showButtons_ = false;
std::set<int> hidden_;
std::map<int, ImageID> icons_;
};

class MessagePopupScreen : public PopupScreen {
Expand Down Expand Up @@ -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;

Expand All @@ -254,6 +261,7 @@ class PopupMultiChoice : public AbstractChoiceWithValueDisplay {
std::string valueText_;
bool restoreFocus_ = false;
std::set<int> hidden_;
std::map<int, ImageID> icons_;
};

// Allows passing in a dynamic vector of strings. Saves the string.
Expand Down
28 changes: 20 additions & 8 deletions Common/UI/ScrollView.cpp
Expand Up @@ -496,9 +496,8 @@ void ScrollView::Update() {
}
}

ListView::ListView(ListAdaptor *a, std::set<int> hidden, LayoutParams *layoutParams)
: ScrollView(ORIENT_VERTICAL, layoutParams), adaptor_(a), maxHeight_(0), hidden_(hidden) {

ListView::ListView(ListAdaptor *a, std::set<int> hidden, std::map<int, ImageID> 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_);
Expand All @@ -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));
}
}
Expand Down Expand Up @@ -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<EventReturn(EventParams &)> callback) {
Expand All @@ -549,8 +557,12 @@ bool ChoiceListAdaptor::AddEventCallback(View *view, std::function<EventReturn(E
}


View *StringVectorListAdaptor::CreateItemView(int index) {
return new Choice(items_[index], "", index == selected_);
View *StringVectorListAdaptor::CreateItemView(int index, ImageID *optionalImageID) {
Choice *choice = new Choice(items_[index], "", index == selected_);
if (optionalImageID) {
choice->SetIcon(*optionalImageID);
}
return choice;
}

bool StringVectorListAdaptor::AddEventCallback(View *view, std::function<EventReturn(EventParams &)> callback) {
Expand Down
9 changes: 5 additions & 4 deletions Common/UI/ScrollView.h
Expand Up @@ -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<EventReturn(EventParams &)> callback) { return false; }
virtual std::string GetTitle(int index) const { return ""; }
Expand All @@ -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<EventReturn(EventParams &)> callback) override;

Expand All @@ -114,7 +114,7 @@ class StringVectorListAdaptor : public ListAdaptor {
public:
StringVectorListAdaptor() : selected_(-1) {}
StringVectorListAdaptor(const std::vector<std::string> &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<EventReturn(EventParams &)> callback) override;
void SetSelected(int sel) override { selected_ = sel; }
Expand All @@ -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<int> hidden = std::set<int>(), LayoutParams *layoutParams = 0);
ListView(ListAdaptor *a, std::set<int> hidden = std::set<int>(), std::map<int, ImageID> icons = std::map<int, ImageID>(), LayoutParams *layoutParams = 0);

int GetSelected() { return adaptor_->GetSelected(); }
void Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert) override;
Expand All @@ -146,6 +146,7 @@ class ListView : public ScrollView {
LinearLayout *linLayout_;
float maxHeight_;
std::set<int> hidden_;
std::map<int, ImageID> icons_;
};

} // namespace UI
9 changes: 8 additions & 1 deletion UI/GameSettingsScreen.cpp
Expand Up @@ -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"));
}
}
}
Expand Down

0 comments on commit c1637b0

Please sign in to comment.