Skip to content

Commit

Permalink
Vulkan: Allow MSAA on modern-ish mobile devices, but add a little war…
Browse files Browse the repository at this point in the history
…ning sign.

MSAA on tiler GPUs, the way we use it (we are not able to eliminate
load/store operations yet) can consume huge amounts of bandwidth, so let's be a
little bit careful.
  • Loading branch information
hrydgard committed Dec 3, 2023
1 parent 0c760ba commit 1f2dbfa
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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 1f2dbfa

Please sign in to comment.