mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Vulkan: Allow MSAA on modern-ish mobile devices, but add a little warning 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.
This commit is contained in:
parent
0c760bae91
commit
1f2dbfaf25
6 changed files with 82 additions and 31 deletions
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -32,6 +32,9 @@ public:
|
|||
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;
|
||||
|
@ -49,6 +52,7 @@ private:
|
|||
std::function<void(int)> callback_;
|
||||
bool showButtons_ = false;
|
||||
std::set<int> hidden_;
|
||||
std::map<int, ImageID> icons_;
|
||||
};
|
||||
|
||||
class MessagePopupScreen : public PopupScreen {
|
||||
|
@ -231,6 +235,9 @@ public:
|
|||
void HideChoice(int c) {
|
||||
hidden_.insert(c);
|
||||
}
|
||||
void SetChoiceIcon(int c, ImageID id) {
|
||||
icons_[c] = id;
|
||||
}
|
||||
|
||||
UI::Event OnChoice;
|
||||
|
||||
|
@ -254,6 +261,7 @@ private:
|
|||
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.
|
||||
|
|
|
@ -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_);
|
||||
|
@ -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<EventReturn(EventParams &)> callback) {
|
||||
|
@ -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) {
|
||||
|
|
|
@ -89,7 +89,7 @@ private:
|
|||
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 ""; }
|
||||
|
@ -100,7 +100,7 @@ public:
|
|||
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;
|
||||
|
||||
|
@ -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; }
|
||||
|
@ -130,7 +130,7 @@ private:
|
|||
// 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;
|
||||
|
@ -146,6 +146,7 @@ private:
|
|||
LinearLayout *linLayout_;
|
||||
float maxHeight_;
|
||||
std::set<int> hidden_;
|
||||
std::map<int, ImageID> icons_;
|
||||
};
|
||||
|
||||
} // namespace UI
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue