summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/LicenseAdapter.kt1
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/SetupAdapter.kt22
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt17
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt15
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/RunnableViewHolder.kt3
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SettingViewHolder.kt16
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.kt23
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SliderViewHolder.kt9
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SubmenuViewHolder.kt1
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt4
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt145
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/model/HomeViewModel.kt7
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/model/SetupPage.kt14
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt109
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ViewUtils.kt35
-rw-r--r--src/android/app/src/main/res/layout-w600dp/fragment_setup.xml60
-rw-r--r--src/android/app/src/main/res/layout-w600dp/page_setup.xml69
-rw-r--r--src/android/app/src/main/res/layout/dialog_slider.xml13
-rw-r--r--src/android/app/src/main/res/layout/fragment_setup.xml62
-rw-r--r--src/android/app/src/main/res/layout/list_item_setting.xml62
-rw-r--r--src/android/app/src/main/res/layout/page_setup.xml30
-rw-r--r--src/android/app/src/main/res/values/strings.xml2
-rw-r--r--src/common/settings_common.cpp2
-rw-r--r--src/common/settings_enums.h16
-rw-r--r--src/common/settings_setting.h10
-rw-r--r--src/core/hid/hid_types.h26
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.h16
-rw-r--r--src/core/hle/service/hid/hid.cpp68
-rw-r--r--src/core/hle/service/nvnflinger/buffer_queue_producer.cpp1
-rw-r--r--src/core/hle/service/nvnflinger/window.h1
-rw-r--r--src/core/hle/service/ssl/ssl_backend_securetransport.cpp2
-rw-r--r--src/core/memory.h125
-rw-r--r--src/video_core/engines/maxwell_dma.cpp1
-rw-r--r--src/video_core/renderer_opengl/gl_graphics_pipeline.cpp18
-rw-r--r--src/video_core/renderer_opengl/gl_graphics_pipeline.h2
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp179
-rw-r--r--src/video_core/vulkan_common/vulkan_device.h9
-rw-r--r--src/yuzu/game_list.cpp8
38 files changed, 769 insertions, 434 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/LicenseAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/LicenseAdapter.kt
index 7006651d0..bc6ff1364 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/LicenseAdapter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/LicenseAdapter.kt
@@ -49,6 +49,7 @@ class LicenseAdapter(private val activity: AppCompatActivity, var licenses: List
val context = YuzuApplication.appContext
binding.textSettingName.text = context.getString(license.titleId)
binding.textSettingDescription.text = context.getString(license.descriptionId)
+ binding.textSettingValue.visibility = View.GONE
}
}
}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/SetupAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/SetupAdapter.kt
index 481ddd5a5..6b46d359e 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/SetupAdapter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/SetupAdapter.kt
@@ -5,13 +5,19 @@ package org.yuzu.yuzu_emu.adapters
import android.text.Html
import android.view.LayoutInflater
+import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.res.ResourcesCompat
+import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.button.MaterialButton
import org.yuzu.yuzu_emu.databinding.PageSetupBinding
+import org.yuzu.yuzu_emu.model.HomeViewModel
+import org.yuzu.yuzu_emu.model.SetupCallback
import org.yuzu.yuzu_emu.model.SetupPage
+import org.yuzu.yuzu_emu.model.StepState
+import org.yuzu.yuzu_emu.utils.ViewUtils
class SetupAdapter(val activity: AppCompatActivity, val pages: List<SetupPage>) :
RecyclerView.Adapter<SetupAdapter.SetupPageViewHolder>() {
@@ -26,7 +32,7 @@ class SetupAdapter(val activity: AppCompatActivity, val pages: List<SetupPage>)
holder.bind(pages[position])
inner class SetupPageViewHolder(val binding: PageSetupBinding) :
- RecyclerView.ViewHolder(binding.root) {
+ RecyclerView.ViewHolder(binding.root), SetupCallback {
lateinit var page: SetupPage
init {
@@ -35,6 +41,12 @@ class SetupAdapter(val activity: AppCompatActivity, val pages: List<SetupPage>)
fun bind(page: SetupPage) {
this.page = page
+
+ if (page.stepCompleted.invoke() == StepState.COMPLETE) {
+ binding.buttonAction.visibility = View.INVISIBLE
+ binding.textConfirmation.visibility = View.VISIBLE
+ }
+
binding.icon.setImageDrawable(
ResourcesCompat.getDrawable(
activity.resources,
@@ -62,9 +74,15 @@ class SetupAdapter(val activity: AppCompatActivity, val pages: List<SetupPage>)
MaterialButton.ICON_GRAVITY_END
}
setOnClickListener {
- page.buttonAction.invoke()
+ page.buttonAction.invoke(this@SetupPageViewHolder)
}
}
}
+
+ override fun onStepCompleted() {
+ ViewUtils.hideView(binding.buttonAction, 200)
+ ViewUtils.showView(binding.textConfirmation, 200)
+ ViewModelProvider(activity)[HomeViewModel::class.java].setShouldPageForward(true)
+ }
}
}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt
index ce0b92c90..9711e2c51 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt
@@ -207,8 +207,11 @@ class SettingsAdapter(
val sliderBinding = DialogSliderBinding.inflate(inflater)
textSliderValue = sliderBinding.textValue
- textSliderValue!!.text = sliderProgress.toString()
- sliderBinding.textUnits.text = item.units
+ textSliderValue!!.text = String.format(
+ context.getString(R.string.value_with_units),
+ sliderProgress.toString(),
+ item.units
+ )
sliderBinding.slider.apply {
valueFrom = item.min.toFloat()
@@ -216,7 +219,11 @@ class SettingsAdapter(
value = sliderProgress.toFloat()
addOnChangeListener { _: Slider, value: Float, _: Boolean ->
sliderProgress = value.toInt()
- textSliderValue!!.text = sliderProgress.toString()
+ textSliderValue!!.text = String.format(
+ context.getString(R.string.value_with_units),
+ sliderProgress.toString(),
+ item.units
+ )
}
}
@@ -225,10 +232,6 @@ class SettingsAdapter(
.setView(sliderBinding.root)
.setPositiveButton(android.R.string.ok, this)
.setNegativeButton(android.R.string.cancel, defaultCancelListener)
- .setNeutralButton(R.string.slider_default) { dialog: DialogInterface, which: Int ->
- sliderBinding.slider.value = item.defaultValue!!.toFloat()
- onClick(dialog, which)
- }
.show()
}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt
index 7955532ee..79572fc06 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt
@@ -25,12 +25,17 @@ class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA
binding.textSettingDescription.setText(item.descriptionId)
binding.textSettingDescription.visibility = View.VISIBLE
} else {
- val epochTime = setting.value.toLong()
- val instant = Instant.ofEpochMilli(epochTime * 1000)
- val zonedTime = ZonedDateTime.ofInstant(instant, ZoneId.of("UTC"))
- val dateFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)
- binding.textSettingDescription.text = dateFormatter.format(zonedTime)
+ binding.textSettingDescription.visibility = View.GONE
}
+
+ binding.textSettingValue.visibility = View.VISIBLE
+ val epochTime = setting.value.toLong()
+ val instant = Instant.ofEpochMilli(epochTime * 1000)
+ val zonedTime = ZonedDateTime.ofInstant(instant, ZoneId.of("UTC"))
+ val dateFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)
+ binding.textSettingValue.text = dateFormatter.format(zonedTime)
+
+ setStyle(setting.isEditable, binding)
}
override fun onClick(clicked: View) {
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/RunnableViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/RunnableViewHolder.kt
index 5dad5945f..83a2e94f1 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/RunnableViewHolder.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/RunnableViewHolder.kt
@@ -23,6 +23,9 @@ class RunnableViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA
} else {
binding.textSettingDescription.visibility = View.GONE
}
+ binding.textSettingValue.visibility = View.GONE
+
+ setStyle(setting.isEditable, binding)
}
override fun onClick(clicked: View) {
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SettingViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SettingViewHolder.kt
index f56460893..0fd1d2eaa 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SettingViewHolder.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SettingViewHolder.kt
@@ -5,6 +5,8 @@ package org.yuzu.yuzu_emu.features.settings.ui.viewholder
import android.view.View
import androidx.recyclerview.widget.RecyclerView
+import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
+import org.yuzu.yuzu_emu.databinding.ListItemSettingSwitchBinding
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
@@ -33,4 +35,18 @@ abstract class SettingViewHolder(itemView: View, protected val adapter: Settings
abstract override fun onClick(clicked: View)
abstract override fun onLongClick(clicked: View): Boolean
+
+ fun setStyle(isEditable: Boolean, binding: ListItemSettingBinding) {
+ val opacity = if (isEditable) 1.0f else 0.5f
+ binding.textSettingName.alpha = opacity
+ binding.textSettingDescription.alpha = opacity
+ binding.textSettingValue.alpha = opacity
+ }
+
+ fun setStyle(isEditable: Boolean, binding: ListItemSettingSwitchBinding) {
+ binding.switchWidget.isEnabled = isEditable
+ val opacity = if (isEditable) 1.0f else 0.5f
+ binding.textSettingName.alpha = opacity
+ binding.textSettingDescription.alpha = opacity
+ }
}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.kt
index e4e321bd3..b42d955aa 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.kt
@@ -17,28 +17,33 @@ class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: Setti
override fun bind(item: SettingsItem) {
setting = item
binding.textSettingName.setText(item.nameId)
- binding.textSettingDescription.visibility = View.VISIBLE
if (item.descriptionId != 0) {
binding.textSettingDescription.setText(item.descriptionId)
- } else if (item is SingleChoiceSetting) {
- val resMgr = binding.textSettingDescription.context.resources
+ binding.textSettingDescription.visibility = View.VISIBLE
+ } else {
+ binding.textSettingDescription.visibility = View.GONE
+ }
+
+ binding.textSettingValue.visibility = View.VISIBLE
+ if (item is SingleChoiceSetting) {
+ val resMgr = binding.textSettingValue.context.resources
val values = resMgr.getIntArray(item.valuesId)
for (i in values.indices) {
if (values[i] == item.selectedValue) {
- binding.textSettingDescription.text = resMgr.getStringArray(item.choicesId)[i]
- return
+ binding.textSettingValue.text = resMgr.getStringArray(item.choicesId)[i]
+ break
}
}
} else if (item is StringSingleChoiceSetting) {
for (i in item.values!!.indices) {
if (item.values[i] == item.selectedValue) {
- binding.textSettingDescription.text = item.choices[i]
- return
+ binding.textSettingValue.text = item.choices[i]
+ break
}
}
- } else {
- binding.textSettingDescription.visibility = View.GONE
}
+
+ setStyle(setting.isEditable, binding)
}
override fun onClick(clicked: View) {
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SliderViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SliderViewHolder.kt
index cc3f39aa5..a23b5d109 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SliderViewHolder.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SliderViewHolder.kt
@@ -4,6 +4,7 @@
package org.yuzu.yuzu_emu.features.settings.ui.viewholder
import android.view.View
+import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting
@@ -22,6 +23,14 @@ class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAda
} else {
binding.textSettingDescription.visibility = View.GONE
}
+ binding.textSettingValue.visibility = View.VISIBLE
+ binding.textSettingValue.text = String.format(
+ binding.textSettingValue.context.getString(R.string.value_with_units),
+ setting.selectedValue,
+ setting.units
+ )
+
+ setStyle(setting.isEditable, binding)
}
override fun onClick(clicked: View) {
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SubmenuViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SubmenuViewHolder.kt
index c545b4174..1cf581a9d 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SubmenuViewHolder.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SubmenuViewHolder.kt
@@ -22,6 +22,7 @@ class SubmenuViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAd
} else {
binding.textSettingDescription.visibility = View.GONE
}
+ binding.textSettingValue.visibility = View.GONE
}
override fun onClick(clicked: View) {
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt
index 54f531795..ef34bf5f4 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt
@@ -25,12 +25,12 @@ class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter
binding.textSettingDescription.text = ""
binding.textSettingDescription.visibility = View.GONE
}
- binding.switchWidget.isChecked = setting.isChecked
binding.switchWidget.setOnCheckedChangeListener { _: CompoundButton, _: Boolean ->
adapter.onBooleanClick(item, bindingAdapterPosition, binding.switchWidget.isChecked)
}
+ binding.switchWidget.isChecked = setting.isChecked
- binding.switchWidget.isEnabled = setting.isEditable
+ setStyle(setting.isEditable, binding)
}
override fun onClick(clicked: View) {
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt
index 6c4ddaf6b..d50c421a0 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt
@@ -19,6 +19,7 @@ import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.isVisible
+import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.navigation.findNavController
@@ -32,10 +33,13 @@ import org.yuzu.yuzu_emu.adapters.SetupAdapter
import org.yuzu.yuzu_emu.databinding.FragmentSetupBinding
import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.model.HomeViewModel
+import org.yuzu.yuzu_emu.model.SetupCallback
import org.yuzu.yuzu_emu.model.SetupPage
+import org.yuzu.yuzu_emu.model.StepState
import org.yuzu.yuzu_emu.ui.main.MainActivity
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
import org.yuzu.yuzu_emu.utils.GameHelper
+import org.yuzu.yuzu_emu.utils.ViewUtils
class SetupFragment : Fragment() {
private var _binding: FragmentSetupBinding? = null
@@ -112,14 +116,22 @@ class SetupFragment : Fragment() {
0,
false,
R.string.give_permission,
- { permissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS) },
+ {
+ notificationCallback = it
+ permissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
+ },
true,
R.string.notification_warning,
R.string.notification_warning_description,
0,
{
- NotificationManagerCompat.from(requireContext())
+ if (NotificationManagerCompat.from(requireContext())
.areNotificationsEnabled()
+ ) {
+ StepState.COMPLETE
+ } else {
+ StepState.INCOMPLETE
+ }
}
)
)
@@ -133,12 +145,22 @@ class SetupFragment : Fragment() {
R.drawable.ic_add,
true,
R.string.select_keys,
- { mainActivity.getProdKey.launch(arrayOf("*/*")) },
+ {
+ keyCallback = it
+ getProdKey.launch(arrayOf("*/*"))
+ },
true,
R.string.install_prod_keys_warning,
R.string.install_prod_keys_warning_description,
R.string.install_prod_keys_warning_help,
- { File(DirectoryInitialization.userDirectory + "/keys/prod.keys").exists() }
+ {
+ val file = File(DirectoryInitialization.userDirectory + "/keys/prod.keys")
+ if (file.exists()) {
+ StepState.COMPLETE
+ } else {
+ StepState.INCOMPLETE
+ }
+ }
)
)
add(
@@ -150,9 +172,8 @@ class SetupFragment : Fragment() {
true,
R.string.add_games,
{
- mainActivity.getGamesDirectory.launch(
- Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data
- )
+ gamesDirCallback = it
+ getGamesDirectory.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data)
},
true,
R.string.add_games_warning,
@@ -163,7 +184,11 @@ class SetupFragment : Fragment() {
PreferenceManager.getDefaultSharedPreferences(
YuzuApplication.appContext
)
- preferences.getString(GameHelper.KEY_GAME_PATH, "")!!.isNotEmpty()
+ if (preferences.getString(GameHelper.KEY_GAME_PATH, "")!!.isNotEmpty()) {
+ StepState.COMPLETE
+ } else {
+ StepState.INCOMPLETE
+ }
}
)
)
@@ -181,6 +206,13 @@ class SetupFragment : Fragment() {
)
}
+ homeViewModel.shouldPageForward.observe(viewLifecycleOwner) {
+ if (it) {
+ pageForward()
+ homeViewModel.setShouldPageForward(false)
+ }
+ }
+
binding.viewPager2.apply {
adapter = SetupAdapter(requireActivity() as AppCompatActivity, pages)
offscreenPageLimit = 2
@@ -194,15 +226,15 @@ class SetupFragment : Fragment() {
super.onPageSelected(position)
if (position == 1 && previousPosition == 0) {
- showView(binding.buttonNext)
- showView(binding.buttonBack)
+ ViewUtils.showView(binding.buttonNext)
+ ViewUtils.showView(binding.buttonBack)
} else if (position == 0 && previousPosition == 1) {
- hideView(binding.buttonBack)
- hideView(binding.buttonNext)
+ ViewUtils.hideView(binding.buttonBack)
+ ViewUtils.hideView(binding.buttonNext)
} else if (position == pages.size - 1 && previousPosition == pages.size - 2) {
- hideView(binding.buttonNext)
+ ViewUtils.hideView(binding.buttonNext)
} else if (position == pages.size - 2 && previousPosition == pages.size - 1) {
- showView(binding.buttonNext)
+ ViewUtils.showView(binding.buttonNext)
}
previousPosition = position
@@ -215,7 +247,8 @@ class SetupFragment : Fragment() {
// Checks if the user has completed the task on the current page
if (currentPage.hasWarning) {
- if (currentPage.taskCompleted.invoke()) {
+ val stepState = currentPage.stepCompleted.invoke()
+ if (stepState != StepState.INCOMPLETE) {
pageForward()
return@setOnClickListener
}
@@ -264,9 +297,15 @@ class SetupFragment : Fragment() {
_binding = null
}
+ private lateinit var notificationCallback: SetupCallback
+
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
private val permissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) {
+ if (it) {
+ notificationCallback.onStepCompleted()
+ }
+
if (!it &&
!shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS)
) {
@@ -277,6 +316,27 @@ class SetupFragment : Fragment() {
}
}
+ private lateinit var keyCallback: SetupCallback
+
+ val getProdKey =
+ registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
+ if (result != null) {
+ if (mainActivity.processKey(result)) {
+ keyCallback.onStepCompleted()
+ }
+ }
+ }
+
+ private lateinit var gamesDirCallback: SetupCallback
+
+ val getGamesDirectory =
+ registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { result ->
+ if (result != null) {
+ mainActivity.processGamesDir(result)
+ gamesDirCallback.onStepCompleted()
+ }
+ }
+
private fun finishSetup() {
PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext).edit()
.putBoolean(Settings.PREF_FIRST_APP_LAUNCH, false)
@@ -284,33 +344,6 @@ class SetupFragment : Fragment() {
mainActivity.finishSetup(binding.root.findNavController())
}
- private fun showView(view: View) {
- view.apply {
- alpha = 0f
- visibility = View.VISIBLE
- isClickable = true
- }.animate().apply {
- duration = 300
- alpha(1f)
- }.start()
- }
-
- private fun hideView(view: View) {
- if (view.visibility == View.INVISIBLE) {
- return
- }
-
- view.apply {
- alpha = 1f
- isClickable = false
- }.animate().apply {
- duration = 300
- alpha(0f)
- }.withEndAction {
- view.visibility = View.INVISIBLE
- }
- }
-
fun pageForward() {
binding.viewPager2.currentItem = binding.viewPager2.currentItem + 1
}
@@ -326,15 +359,29 @@ class SetupFragment : Fragment() {
private fun setInsets() =
ViewCompat.setOnApplyWindowInsetsListener(
binding.root
- ) { view: View, windowInsets: WindowInsetsCompat ->
+ ) { _: View, windowInsets: WindowInsetsCompat ->
val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout())
- view.setPadding(
- barInsets.left + cutoutInsets.left,
- barInsets.top + cutoutInsets.top,
- barInsets.right + cutoutInsets.right,
- barInsets.bottom + cutoutInsets.bottom
- )
+
+ val leftPadding = barInsets.left + cutoutInsets.left
+ val topPadding = barInsets.top + cutoutInsets.top
+ val rightPadding = barInsets.right + cutoutInsets.right
+ val bottomPadding = barInsets.bottom + cutoutInsets.bottom
+
+ if (resources.getBoolean(R.bool.small_layout)) {
+ binding.viewPager2
+ .updatePadding(left = leftPadding, top = topPadding, right = rightPadding)
+ binding.constraintButtons
+ .updatePadding(left = leftPadding, right = rightPadding, bottom = bottomPadding)
+ } else {
+ binding.viewPager2.updatePadding(top = topPadding, bottom = bottomPadding)
+ binding.constraintButtons
+ .updatePadding(
+ left = leftPadding,
+ right = rightPadding,
+ bottom = bottomPadding
+ )
+ }
windowInsets
}
}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/HomeViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/HomeViewModel.kt
index 263ee7144..e13d84c9c 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/HomeViewModel.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/HomeViewModel.kt
@@ -14,6 +14,9 @@ class HomeViewModel : ViewModel() {
private val _statusBarShadeVisible = MutableLiveData(true)
val statusBarShadeVisible: LiveData<Boolean> get() = _statusBarShadeVisible
+ private val _shouldPageForward = MutableLiveData(false)
+ val shouldPageForward: LiveData<Boolean> get() = _shouldPageForward
+
var navigatedToSetup = false
init {
@@ -33,4 +36,8 @@ class HomeViewModel : ViewModel() {
}
_statusBarShadeVisible.value = visible
}
+
+ fun setShouldPageForward(pageForward: Boolean) {
+ _shouldPageForward.value = pageForward
+ }
}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/SetupPage.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/SetupPage.kt
index a0c878e1c..09a128ae6 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/SetupPage.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/SetupPage.kt
@@ -10,10 +10,20 @@ data class SetupPage(
val buttonIconId: Int,
val leftAlignedIcon: Boolean,
val buttonTextId: Int,
- val buttonAction: () -> Unit,
+ val buttonAction: (callback: SetupCallback) -> Unit,
val hasWarning: Boolean,
val warningTitleId: Int = 0,
val warningDescriptionId: Int = 0,
val warningHelpLinkId: Int = 0,
- val taskCompleted: () -> Boolean = { true }
+ val stepCompleted: () -> StepState = { StepState.UNDEFINED }
)
+
+interface SetupCallback {
+ fun onStepCompleted()
+}
+
+enum class StepState {
+ COMPLETE,
+ INCOMPLETE,
+ UNDEFINED
+}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
index f7d7aed1e..f77d06262 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
@@ -266,73 +266,80 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
val getGamesDirectory =
registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { result ->
- if (result == null) {
- return@registerForActivityResult
+ if (result != null) {
+ processGamesDir(result)
}
+ }
- contentResolver.takePersistableUriPermission(
- result,
- Intent.FLAG_GRANT_READ_URI_PERMISSION
- )
+ fun processGamesDir(result: Uri) {
+ contentResolver.takePersistableUriPermission(
+ result,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION
+ )
- // When a new directory is picked, we currently will reset the existing games
- // database. This effectively means that only one game directory is supported.
- PreferenceManager.getDefaultSharedPreferences(applicationContext).edit()
- .putString(GameHelper.KEY_GAME_PATH, result.toString())
- .apply()
+ // When a new directory is picked, we currently will reset the existing games
+ // database. This effectively means that only one game directory is supported.
+ PreferenceManager.getDefaultSharedPreferences(applicationContext).edit()
+ .putString(GameHelper.KEY_GAME_PATH, result.toString())
+ .apply()
- Toast.makeText(
- applicationContext,
- R.string.games_dir_selected,
- Toast.LENGTH_LONG
- ).show()
+ Toast.makeText(
+ applicationContext,
+ R.string.games_dir_selected,
+ Toast.LENGTH_LONG
+ ).show()
- gamesViewModel.reloadGames(true)
- }
+ gamesViewModel.reloadGames(true)
+ }
val getProdKey =
registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
- if (result == null) {
- return@registerForActivityResult
+ if (result != null) {
+ processKey(result)
}
+ }
- if (FileUtil.getExtension(result) != "keys") {
- MessageDialogFragment.newInstance(
- R.string.reading_keys_failure,
- R.string.install_prod_keys_failure_extension_description
- ).show(supportFragmentManager, MessageDialogFragment.TAG)
- return@registerForActivityResult
- }
+ fun processKey(result: Uri): Boolean {
+ if (FileUtil.getExtension(result) != "keys") {
+ MessageDialogFragment.newInstance(
+ R.string.reading_keys_failure,
+ R.string.install_prod_keys_failure_extension_description
+ ).show(supportFragmentManager, MessageDialogFragment.TAG)
+ return false
+ }
- contentResolver.takePersistableUriPermission(
+ contentResolver.takePersistableUriPermission(
+ result,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION
+ )
+
+ val dstPath = DirectoryInitialization.userDirectory + "/keys/"
+ if (FileUtil.copyUriToInternalStorage(
+ applicationContext,
result,
- Intent.FLAG_GRANT_READ_URI_PERMISSION
+ dstPath,
+ "prod.keys"
)
-
- val dstPath = DirectoryInitialization.userDirectory + "/keys/"
- if (FileUtil.copyUriToInternalStorage(
+ ) {
+ if (NativeLibrary.reloadKeys()) {
+ Toast.makeText(
applicationContext,
- result,
- dstPath,
- "prod.keys"
- )
- ) {
- if (NativeLibrary.reloadKeys()) {
- Toast.makeText(
- applicationContext,
- R.string.install_keys_success,
- Toast.LENGTH_SHORT
- ).show()
- gamesViewModel.reloadGames(true)
- } else {
- MessageDialogFragment.newInstance(
- R.string.invalid_keys_error,
- R.string.install_keys_failure_description,
- R.string.dumping_keys_quickstart_link
- ).show(supportFragmentManager, MessageDialogFragment.TAG)
- }
+ R.string.install_keys_success,
+ Toast.LENGTH_SHORT
+ ).show()
+ gamesViewModel.reloadGames(true)
+ return true
+ } else {
+ MessageDialogFragment.newInstance(
+ R.string.invalid_keys_error,
+ R.string.install_keys_failure_description,
+ R.string.dumping_keys_quickstart_link
+ ).show(supportFragmentManager, MessageDialogFragment.TAG)
+ return false
}
}
+ return false
+ }
val getFirmware =
registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ViewUtils.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ViewUtils.kt
new file mode 100644
index 000000000..f9a3e4126
--- /dev/null
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ViewUtils.kt
@@ -0,0 +1,35 @@
+// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+package org.yuzu.yuzu_emu.utils
+
+import android.view.View
+
+object ViewUtils {
+ fun showView(view: View, length: Long = 300) {
+ view.apply {
+ alpha = 0f
+ visibility = View.VISIBLE
+ isClickable = true
+ }.animate().apply {
+ duration = length
+ alpha(1f)
+ }.start()
+ }
+
+ fun hideView(view: View, length: Long = 300) {
+ if (view.visibility == View.INVISIBLE) {
+ return
+ }
+
+ view.apply {
+ alpha = 1f
+ isClickable = false
+ }.animate().apply {
+ duration = length
+ alpha(0f)
+ }.withEndAction {
+ view.visibility = View.INVISIBLE
+ }.start()
+ }
+}
diff --git a/src/android/app/src/main/res/layout-w600dp/fragment_setup.xml b/src/android/app/src/main/res/layout-w600dp/fragment_setup.xml
index cbe631d88..406df9eab 100644
--- a/src/android/app/src/main/res/layout-w600dp/fragment_setup.xml
+++ b/src/android/app/src/main/res/layout-w600dp/fragment_setup.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<androidx.constraintlayout.widget.ConstraintLayout
+<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/setup_root"
@@ -8,33 +8,39 @@
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewPager2"
- android:layout_width="0dp"
- android:layout_height="0dp"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentBottom="true"
+ android:clipToPadding="false" />
- <com.google.android.material.button.MaterialButton
- style="@style/Widget.Material3.Button.TextButton"
- android:id="@+id/button_next"
- android:layout_width="wrap_content"
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/constraint_buttons"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_margin="16dp"
- android:text="@string/next"
- android:visibility="invisible"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent" />
+ android:layout_alignParentBottom="true"
+ android:layout_margin="8dp">
- <com.google.android.material.button.MaterialButton
- android:id="@+id/button_back"
- style="@style/Widget.Material3.Button.TextButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_margin="16dp"
- android:text="@string/back"
- android:visibility="invisible"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintStart_toStartOf="parent" />
+ <com.google.android.material.button.MaterialButton
+ android:id="@+id/button_next"
+ style="@style/Widget.Material3.Button.TextButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/next"
+ android:visibility="invisible"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent" />
+
+ <com.google.android.material.button.MaterialButton
+ android:id="@+id/button_back"
+ style="@style/Widget.Material3.Button.TextButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/back"
+ android:visibility="invisible"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
-</androidx.constraintlayout.widget.ConstraintLayout>
+</RelativeLayout>
diff --git a/src/android/app/src/main/res/layout-w600dp/page_setup.xml b/src/android/app/src/main/res/layout-w600dp/page_setup.xml
index e1c26b2f8..9e0ab8ecb 100644
--- a/src/android/app/src/main/res/layout-w600dp/page_setup.xml
+++ b/src/android/app/src/main/res/layout-w600dp/page_setup.xml
@@ -21,45 +21,76 @@
</LinearLayout>
- <LinearLayout
+ <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_weight="1"
- android:orientation="vertical"
- android:gravity="center">
+ android:layout_weight="1">
<com.google.android.material.textview.MaterialTextView
- style="@style/TextAppearance.Material3.DisplaySmall"
android:id="@+id/text_title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textAlignment="center"
+ style="@style/TextAppearance.Material3.DisplaySmall"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:gravity="center"
android:textColor="?attr/colorOnSurface"
android:textStyle="bold"
+ app:layout_constraintBottom_toTopOf="@+id/text_description"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintVertical_weight="2"
tools:text="@string/welcome" />
<com.google.android.material.textview.MaterialTextView
- style="@style/TextAppearance.Material3.TitleLarge"
android:id="@+id/text_description"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="16dp"
- android:paddingHorizontal="32dp"
- android:textAlignment="center"
- android:textSize="26sp"
- app:lineHeight="40sp"
+ style="@style/TextAppearance.Material3.TitleLarge"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:gravity="center"
+ android:textSize="20sp"
+ android:paddingHorizontal="16dp"
+ app:layout_constraintBottom_toTopOf="@+id/button_action"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/text_title"
+ app:layout_constraintVertical_weight="2"
+ app:lineHeight="30sp"
tools:text="@string/welcome_description" />
+ <com.google.android.material.textview.MaterialTextView
+ android:id="@+id/text_confirmation"
+ style="@style/TextAppearance.Material3.TitleLarge"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:paddingHorizontal="16dp"
+ android:paddingBottom="20dp"
+ android:gravity="center"
+ android:textSize="30sp"
+ android:visibility="invisible"
+ android:text="@string/step_complete"
+ android:textStyle="bold"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/text_description"
+ app:layout_constraintVertical_weight="1"
+ app:lineHeight="30sp" />
+
<com.google.android.material.button.MaterialButton
android:id="@+id/button_action"
android:layout_width="wrap_content"
android:layout_height="56dp"
- android:layout_marginTop="32dp"
+ android:layout_marginTop="16dp"
+ android:layout_marginBottom="48dp"
android:textSize="20sp"
- app:iconSize="24sp"
app:iconGravity="end"
+ app:iconSize="24sp"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/text_description"
tools:text="Get started" />
- </LinearLayout>
+ </androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
diff --git a/src/android/app/src/main/res/layout/dialog_slider.xml b/src/android/app/src/main/res/layout/dialog_slider.xml
index 8c84cb606..d1cb31739 100644
--- a/src/android/app/src/main/res/layout/dialog_slider.xml
+++ b/src/android/app/src/main/res/layout/dialog_slider.xml
@@ -5,23 +5,16 @@
android:layout_height="wrap_content"
android:orientation="vertical">
- <TextView
+ <com.google.android.material.textview.MaterialTextView
android:id="@+id/text_value"
+ style="@style/TextAppearance.Material3.LabelMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="@dimen/spacing_medlarge"
android:layout_marginTop="@dimen/spacing_medlarge"
- tools:text="75" />
-
- <TextView
- android:id="@+id/text_units"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignTop="@+id/text_value"
- android:layout_toEndOf="@+id/text_value"
- tools:text="%" />
+ tools:text="75%" />
<com.google.android.material.slider.Slider
android:id="@+id/slider"
diff --git a/src/android/app/src/main/res/layout/fragment_setup.xml b/src/android/app/src/main/res/layout/fragment_setup.xml
index d7bafaea2..9499f6463 100644
--- a/src/android/app/src/main/res/layout/fragment_setup.xml
+++ b/src/android/app/src/main/res/layout/fragment_setup.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<androidx.constraintlayout.widget.ConstraintLayout
+<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/setup_root"
@@ -8,35 +8,39 @@
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewPager2"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:clipToPadding="false"
- android:layout_marginBottom="16dp"
- app:layout_constraintBottom_toTopOf="@+id/button_next"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
-
- <com.google.android.material.button.MaterialButton
- style="@style/Widget.Material3.Button.TextButton"
- android:id="@+id/button_next"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_margin="12dp"
- android:text="@string/next"
- android:visibility="invisible"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent" />
+ android:layout_above="@+id/constraint_buttons"
+ android:layout_alignParentTop="true"
+ android:clipToPadding="false" />
- <com.google.android.material.button.MaterialButton
- style="@style/Widget.Material3.Button.TextButton"
- android:id="@+id/button_back"
- android:layout_width="wrap_content"
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/constraint_buttons"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_margin="12dp"
- android:text="@string/back"
- android:visibility="invisible"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintStart_toStartOf="parent" />
+ android:layout_margin="8dp"
+ android:layout_alignParentBottom="true">
+
+ <com.google.android.material.button.MaterialButton
+ android:id="@+id/button_next"
+ style="@style/Widget.Material3.Button.TextButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/next"
+ android:visibility="invisible"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent" />
+
+ <com.google.android.material.button.MaterialButton
+ android:id="@+id/button_back"
+ style="@style/Widget.Material3.Button.TextButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/back"
+ android:visibility="invisible"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
-</androidx.constraintlayout.widget.ConstraintLayout>
+</RelativeLayout>
diff --git a/src/android/app/src/main/res/layout/list_item_setting.xml b/src/android/app/src/main/res/layout/list_item_setting.xml
index ec896342b..f1037a740 100644
--- a/src/android/app/src/main/res/layout/list_item_setting.xml
+++ b/src/android/app/src/main/res/layout/list_item_setting.xml
@@ -1,9 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
@@ -11,31 +12,40 @@
android:minHeight="72dp"
android:padding="@dimen/spacing_large">
- <com.google.android.material.textview.MaterialTextView
- style="@style/TextAppearance.Material3.HeadlineMedium"
- android:id="@+id/text_setting_name"
- android:layout_width="0dp"
+ <LinearLayout
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_alignParentEnd="true"
- android:layout_alignParentStart="true"
- android:layout_alignParentTop="true"
- android:textSize="16sp"
- android:textAlignment="viewStart"
- app:lineHeight="28dp"
- tools:text="Setting Name" />
+ android:orientation="vertical">
- <TextView
- style="@style/TextAppearance.Material3.BodySmall"
- android:id="@+id/text_setting_description"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentEnd="true"
- android:layout_alignParentStart="true"
- android:layout_alignStart="@+id/text_setting_name"
- android:layout_below="@+id/text_setting_name"
- android:layout_marginTop="@dimen/spacing_small"
- android:visibility="visible"
- android:textAlignment="viewStart"
- tools:text="@string/app_disclaimer" />
+ <com.google.android.material.textview.MaterialTextView
+ android:id="@+id/text_setting_name"
+ style="@style/TextAppearance.Material3.HeadlineMedium"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textAlignment="viewStart"
+ android:textSize="16sp"
+ app:lineHeight="22dp"
+ tools:text="Setting Name" />
+
+ <com.google.android.material.textview.MaterialTextView
+ android:id="@+id/text_setting_description"
+ style="@style/TextAppearance.Material3.BodySmall"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/spacing_small"
+ android:textAlignment="viewStart"
+ tools:text="@string/app_disclaimer" />
+
+ <com.google.android.material.textview.MaterialTextView
+ android:id="@+id/text_setting_value"
+ style="@style/TextAppearance.Material3.LabelMedium"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/spacing_small"
+ android:textAlignment="viewStart"
+ android:textStyle="bold"
+ tools:text="1x" />
+
+ </LinearLayout>
</RelativeLayout>
diff --git a/src/android/app/src/main/res/layout/page_setup.xml b/src/android/app/src/main/res/layout/page_setup.xml
index 1436ef308..535abcf02 100644
--- a/src/android/app/src/main/res/layout/page_setup.xml
+++ b/src/android/app/src/main/res/layout/page_setup.xml
@@ -21,11 +21,12 @@
app:layout_constraintVertical_chainStyle="spread"
app:layout_constraintWidth_max="220dp"
app:layout_constraintWidth_min="110dp"
- app:layout_constraintVertical_weight="3" />
+ app:layout_constraintVertical_weight="3"
+ tools:src="@drawable/ic_notification" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/text_title"
- style="@style/TextAppearance.Material3.DisplayMedium"
+ style="@style/TextAppearance.Material3.DisplaySmall"
android:layout_width="0dp"
android:layout_height="0dp"
android:textAlignment="center"
@@ -44,23 +45,42 @@
android:layout_width="0dp"
android:layout_height="0dp"
android:textAlignment="center"
- android:textSize="26sp"
+ android:textSize="20sp"
android:paddingHorizontal="16dp"
app:layout_constraintBottom_toTopOf="@+id/button_action"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_title"
app:layout_constraintVertical_weight="2"
- app:lineHeight="40sp"
+ app:lineHeight="30sp"
tools:text="@string/welcome_description" />
+ <com.google.android.material.textview.MaterialTextView
+ android:id="@+id/text_confirmation"
+ style="@style/TextAppearance.Material3.TitleLarge"
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ android:paddingHorizontal="16dp"
+ android:paddingTop="24dp"
+ android:textAlignment="center"
+ android:textSize="30sp"
+ android:visibility="invisible"
+ android:text="@string/step_complete"
+ android:textStyle="bold"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/text_description"
+ app:layout_constraintVertical_weight="1"
+ app:lineHeight="30sp" />
+
<com.google.android.material.button.MaterialButton
android:id="@+id/button_action"
android:layout_width="wrap_content"
android:layout_height="56dp"
- android:textSize="20sp"
android:layout_marginTop="16dp"
android:layout_marginBottom="48dp"
+ android:textSize="20sp"
app:iconGravity="end"
app:iconSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml
index 02e25504d..de1b2909b 100644
--- a/src/android/app/src/main/res/values/strings.xml
+++ b/src/android/app/src/main/res/values/strings.xml
@@ -29,6 +29,7 @@
<string name="back">Back</string>
<string name="add_games">Add Games</string>
<string name="add_games_description">Select your games folder</string>
+ <string name="step_complete">Complete!</string>
<!-- Home strings -->
<string name="home_games">Games</string>
@@ -149,6 +150,7 @@
<string name="frame_limit_slider">Limit speed percent</string>
<string name="frame_limit_slider_description">Specifies the percentage to limit emulation speed. 100% is the normal speed. Values higher or lower will increase or decrease the speed limit.</string>
<string name="cpu_accuracy">CPU accuracy</string>
+ <string name="value_with_units">%1$s%2$s</string>
<!-- System settings strings -->
<string name="use_docked_mode">Docked Mode</string>
diff --git a/src/common/settings_common.cpp b/src/common/settings_common.cpp
index dedf5ef90..137b65d5f 100644
--- a/src/common/settings_common.cpp
+++ b/src/common/settings_common.cpp
@@ -1,7 +1,9 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
+#include <functional>
#include <string>
+#include <vector>
#include "common/settings_common.h"
namespace Settings {
diff --git a/src/common/settings_enums.h b/src/common/settings_enums.h
index a1a29ebf6..e7cb59ea5 100644
--- a/src/common/settings_enums.h
+++ b/src/common/settings_enums.h
@@ -12,8 +12,8 @@ namespace Settings {
template <typename T>
struct EnumMetadata {
- static constexpr std::vector<std::pair<std::string, T>> Canonicalizations();
- static constexpr u32 Index();
+ static std::vector<std::pair<std::string, T>> Canonicalizations();
+ static u32 Index();
};
#define PAIR_45(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_46(N, __VA_ARGS__))
@@ -66,11 +66,11 @@ struct EnumMetadata {
#define ENUM(NAME, ...) \
enum class NAME : u32 { __VA_ARGS__ }; \
template <> \
- constexpr std::vector<std::pair<std::string, NAME>> EnumMetadata<NAME>::Canonicalizations() { \
+ inline std::vector<std::pair<std::string, NAME>> EnumMetadata<NAME>::Canonicalizations() { \
return {PAIR(NAME, __VA_ARGS__)}; \
} \
template <> \
- constexpr u32 EnumMetadata<NAME>::Index() { \
+ inline u32 EnumMetadata<NAME>::Index() { \
return __COUNTER__; \
}
@@ -85,7 +85,7 @@ enum class AudioEngine : u32 {
};
template <>
-constexpr std::vector<std::pair<std::string, AudioEngine>>
+inline std::vector<std::pair<std::string, AudioEngine>>
EnumMetadata<AudioEngine>::Canonicalizations() {
return {
{"auto", AudioEngine::Auto},
@@ -96,7 +96,7 @@ EnumMetadata<AudioEngine>::Canonicalizations() {
}
template <>
-constexpr u32 EnumMetadata<AudioEngine>::Index() {
+inline u32 EnumMetadata<AudioEngine>::Index() {
// This is just a sufficiently large number that is more than the number of other enums declared
// here
return 100;
@@ -147,7 +147,7 @@ ENUM(AntiAliasing, None, Fxaa, Smaa, MaxEnum);
ENUM(AspectRatio, R16_9, R4_3, R21_9, R16_10, Stretch);
template <typename Type>
-constexpr std::string CanonicalizeEnum(Type id) {
+inline std::string CanonicalizeEnum(Type id) {
const auto group = EnumMetadata<Type>::Canonicalizations();
for (auto& [name, value] : group) {
if (value == id) {
@@ -158,7 +158,7 @@ constexpr std::string CanonicalizeEnum(Type id) {
}
template <typename Type>
-constexpr Type ToEnum(const std::string& canonicalization) {
+inline Type ToEnum(const std::string& canonicalization) {
const auto group = EnumMetadata<Type>::Canonicalizations();
for (auto& [name, value] : group) {
if (name == canonicalization) {
diff --git a/src/common/settings_setting.h b/src/common/settings_setting.h
index a8beb06e9..e10843c73 100644
--- a/src/common/settings_setting.h
+++ b/src/common/settings_setting.h
@@ -190,7 +190,7 @@ public:
}
}
- [[nodiscard]] std::string constexpr Canonicalize() const override final {
+ [[nodiscard]] std::string Canonicalize() const override final {
if constexpr (std::is_enum_v<Type>) {
return CanonicalizeEnum(this->GetValue());
} else {
@@ -256,11 +256,11 @@ public:
* @param runtime_modifiable_ Suggests whether this is modifiable while a guest is loaded
* @param other_setting_ A second Setting to associate to this one in metadata
*/
+ template <typename T = BasicSetting>
explicit SwitchableSetting(Linkage& linkage, const Type& default_val, const std::string& name,
Category category_, u32 specialization_ = Specialization::Default,
bool save_ = true, bool runtime_modifiable_ = false,
- BasicSetting* other_setting_ = nullptr)
- requires(!ranged)
+ typename std::enable_if<!ranged, T*>::type other_setting_ = nullptr)
: Setting<Type, false>{
linkage, default_val, name, category_, specialization_,
save_, runtime_modifiable_, other_setting_} {
@@ -282,12 +282,12 @@ public:
* @param runtime_modifiable_ Suggests whether this is modifiable while a guest is loaded
* @param other_setting_ A second Setting to associate to this one in metadata
*/
+ template <typename T = BasicSetting>
explicit SwitchableSetting(Linkage& linkage, const Type& default_val, const Type& min_val,
const Type& max_val, const std::string& name, Category category_,
u32 specialization_ = Specialization::Default, bool save_ = true,
bool runtime_modifiable_ = false,
- BasicSetting* other_setting_ = nullptr)
- requires(ranged)
+ typename std::enable_if<ranged, T*>::type other_setting_ = nullptr)
: Setting<Type, true>{linkage, default_val, min_val,
max_val, name, category_,
specialization_, save_, runtime_modifiable_,
diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h
index 6b35f448c..00beb40dd 100644
--- a/src/core/hid/hid_types.h
+++ b/src/core/hid/hid_types.h
@@ -289,6 +289,19 @@ enum class GyroscopeZeroDriftMode : u32 {
Tight = 2,
};
+// This is nn::settings::system::TouchScreenMode
+enum class TouchScreenMode : u32 {
+ Stylus = 0,
+ Standard = 1,
+};
+
+// This is nn::hid::TouchScreenModeForNx
+enum class TouchScreenModeForNx : u8 {
+ UseSystemSetting,
+ Finger,
+ Heat2,
+};
+
// This is nn::hid::NpadStyleTag
struct NpadStyleTag {
union {
@@ -334,6 +347,14 @@ struct TouchState {
};
static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size");
+// This is nn::hid::TouchScreenConfigurationForNx
+struct TouchScreenConfigurationForNx {
+ TouchScreenModeForNx mode{TouchScreenModeForNx::UseSystemSetting};
+ INSERT_PADDING_BYTES(0xF);
+};
+static_assert(sizeof(TouchScreenConfigurationForNx) == 0x10,
+ "TouchScreenConfigurationForNx is an invalid size");
+
struct NpadColor {
u8 r{};
u8 g{};
@@ -662,6 +683,11 @@ struct MouseState {
};
static_assert(sizeof(MouseState) == 0x28, "MouseState is an invalid size");
+struct UniquePadId {
+ u64 id;
+};
+static_assert(sizeof(UniquePadId) == 0x8, "UniquePadId is an invalid size");
+
/// Converts a NpadIdType to an array index.
constexpr size_t NpadIdTypeToIndex(NpadIdType npad_id_type) {
switch (npad_id_type) {
diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h
index e57a3a80e..dd00921fd 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.h
+++ b/src/core/hle/service/hid/controllers/touchscreen.h
@@ -16,22 +16,6 @@ class EmulatedConsole;
namespace Service::HID {
class Controller_Touchscreen final : public ControllerBase {
public:
- // This is nn::hid::TouchScreenModeForNx
- enum class TouchScreenModeForNx : u8 {
- UseSystemSetting,
- Finger,
- Heat2,
- };
-
- // This is nn::hid::TouchScreenConfigurationForNx
- struct TouchScreenConfigurationForNx {
- TouchScreenModeForNx mode{TouchScreenModeForNx::UseSystemSetting};
- INSERT_PADDING_BYTES_NOINIT(0x7);
- INSERT_PADDING_BYTES_NOINIT(0xF); // Reserved
- };
- static_assert(sizeof(TouchScreenConfigurationForNx) == 0x17,
- "TouchScreenConfigurationForNx is an invalid size");
-
explicit Controller_Touchscreen(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
~Controller_Touchscreen() override;
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 2bf1d8a27..fd466db7b 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -2368,7 +2368,7 @@ void Hid::GetNpadCommunicationMode(HLERequestContext& ctx) {
void Hid::SetTouchScreenConfiguration(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- const auto touchscreen_mode{rp.PopRaw<Controller_Touchscreen::TouchScreenConfigurationForNx>()};
+ const auto touchscreen_mode{rp.PopRaw<Core::HID::TouchScreenConfigurationForNx>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_WARNING(Service_HID, "(STUBBED) called, touchscreen_mode={}, applet_resource_user_id={}",
@@ -2543,7 +2543,8 @@ public:
class HidSys final : public ServiceFramework<HidSys> {
public:
- explicit HidSys(Core::System& system_) : ServiceFramework{system_, "hid:sys"} {
+ explicit HidSys(Core::System& system_)
+ : ServiceFramework{system_, "hid:sys"}, service_context{system_, "hid:sys"} {
// clang-format off
static const FunctionInfo functions[] = {
{31, nullptr, "SendKeyboardLockKeyEvent"},
@@ -2568,7 +2569,7 @@ public:
{303, &HidSys::ApplyNpadSystemCommonPolicy, "ApplyNpadSystemCommonPolicy"},
{304, nullptr, "EnableAssigningSingleOnSlSrPress"},
{305, nullptr, "DisableAssigningSingleOnSlSrPress"},
- {306, nullptr, "GetLastActiveNpad"},
+ {306, &HidSys::GetLastActiveNpad, "GetLastActiveNpad"},
{307, nullptr, "GetNpadSystemExtStyle"},
{308, nullptr, "ApplyNpadSystemCommonPolicyFull"},
{309, nullptr, "GetNpadFullKeyGripColor"},
@@ -2624,7 +2625,7 @@ public:
{700, nullptr, "ActivateUniquePad"},
{702, nullptr, "AcquireUniquePadConnectionEventHandle"},
{703, nullptr, "GetUniquePadIds"},
- {751, nullptr, "AcquireJoyDetachOnBluetoothOffEventHandle"},
+ {751, &HidSys::AcquireJoyDetachOnBluetoothOffEventHandle, "AcquireJoyDetachOnBluetoothOffEventHandle"},
{800, nullptr, "ListSixAxisSensorHandles"},
{801, nullptr, "IsSixAxisSensorUserCalibrationSupported"},
{802, nullptr, "ResetSixAxisSensorCalibrationValues"},
@@ -2650,7 +2651,7 @@ public:
{830, nullptr, "SetNotificationLedPattern"},
{831, nullptr, "SetNotificationLedPatternWithTimeout"},
{832, nullptr, "PrepareHidsForNotificationWake"},
- {850, nullptr, "IsUsbFullKeyControllerEnabled"},
+ {850, &HidSys::IsUsbFullKeyControllerEnabled, "IsUsbFullKeyControllerEnabled"},
{851, nullptr, "EnableUsbFullKeyController"},
{852, nullptr, "IsUsbConnected"},
{870, nullptr, "IsHandheldButtonPressedOnConsoleMode"},
@@ -2682,7 +2683,7 @@ public:
{1150, nullptr, "SetTouchScreenMagnification"},
{1151, nullptr, "GetTouchScreenFirmwareVersion"},
{1152, nullptr, "SetTouchScreenDefaultConfiguration"},
- {1153, nullptr, "GetTouchScreenDefaultConfiguration"},
+ {1153, &HidSys::GetTouchScreenDefaultConfiguration, "GetTouchScreenDefaultConfiguration"},
{1154, nullptr, "IsFirmwareAvailableForNotification"},
{1155, nullptr, "SetForceHandheldStyleVibration"},
{1156, nullptr, "SendConnectionTriggerWithoutTimeoutEvent"},
@@ -2749,6 +2750,8 @@ public:
// clang-format on
RegisterHandlers(functions);
+
+ joy_detach_event = service_context.CreateEvent("HidSys::JoyDetachEvent");
}
private:
@@ -2760,17 +2763,66 @@ private:
rb.Push(ResultSuccess);
}
+ void GetLastActiveNpad(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_HID, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(Core::HID::NpadIdType::Handheld);
+ }
+
void GetUniquePadsFromNpad(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()};
- const s64 total_entries = 0;
LOG_WARNING(Service_HID, "(STUBBED) called, npad_id_type={}", npad_id_type);
+ const std::vector<Core::HID::UniquePadId> unique_pads{};
+
+ ctx.WriteBuffer(unique_pads);
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
- rb.Push(total_entries);
+ rb.Push(static_cast<u32>(unique_pads.size()));
}
+
+ void AcquireJoyDetachOnBluetoothOffEventHandle(HLERequestContext& ctx) {
+ LOG_INFO(Service_AM, "called");
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(ResultSuccess);
+ rb.PushCopyObjects(joy_detach_event->GetReadableEvent());
+ }
+
+ void IsUsbFullKeyControllerEnabled(HLERequestContext& ctx) {
+ const bool is_enabled = false;
+
+ LOG_WARNING(Service_HID, "(STUBBED) called, is_enabled={}", is_enabled);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(is_enabled);
+ }
+
+ void GetTouchScreenDefaultConfiguration(HLERequestContext& ctx) {
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+
+ Core::HID::TouchScreenConfigurationForNx touchscreen_config{
+ .mode = Core::HID::TouchScreenModeForNx::Finger,
+ };
+
+ if (touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Heat2 &&
+ touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Finger) {
+ touchscreen_config.mode = Core::HID::TouchScreenModeForNx::UseSystemSetting;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 6};
+ rb.Push(ResultSuccess);
+ rb.PushRaw(touchscreen_config);
+ }
+
+ Kernel::KEvent* joy_detach_event;
+ KernelHelpers::ServiceContext service_context;
};
void LoopProcess(Core::System& system) {
diff --git a/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp
index b16f9933f..dc6917d5d 100644
--- a/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp
+++ b/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp
@@ -449,6 +449,7 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,
case NativeWindowScalingMode::ScaleToWindow:
case NativeWindowScalingMode::ScaleCrop:
case NativeWindowScalingMode::NoScaleCrop:
+ case NativeWindowScalingMode::PreserveAspectRatio:
break;
default:
LOG_ERROR(Service_Nvnflinger, "unknown scaling mode {}", scaling_mode);
diff --git a/src/core/hle/service/nvnflinger/window.h b/src/core/hle/service/nvnflinger/window.h
index 61cca5b01..36d6cde3d 100644
--- a/src/core/hle/service/nvnflinger/window.h
+++ b/src/core/hle/service/nvnflinger/window.h
@@ -41,6 +41,7 @@ enum class NativeWindowScalingMode : s32 {
ScaleToWindow = 1,
ScaleCrop = 2,
NoScaleCrop = 3,
+ PreserveAspectRatio = 4,
};
/// Transform parameter for QueueBuffer
diff --git a/src/core/hle/service/ssl/ssl_backend_securetransport.cpp b/src/core/hle/service/ssl/ssl_backend_securetransport.cpp
index 370678f48..c48914f64 100644
--- a/src/core/hle/service/ssl/ssl_backend_securetransport.cpp
+++ b/src/core/hle/service/ssl/ssl_backend_securetransport.cpp
@@ -100,7 +100,7 @@ public:
Result DoHandshake() override {
OSStatus status = SSLHandshake(context);
- return HandleReturn("SSLHandshake", 0, status).Code();
+ return HandleReturn("SSLHandshake", 0, status);
}
Result Read(size_t* out_size, std::span<u8> data) override {
diff --git a/src/core/memory.h b/src/core/memory.h
index 2eb61ffd3..13047a545 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -509,9 +509,9 @@ class GuestMemory {
public:
GuestMemory() = delete;
- explicit GuestMemory(M& memory_, u64 addr_, std::size_t size_,
+ explicit GuestMemory(M& memory, u64 addr, std::size_t size,
Common::ScratchBuffer<T>* backup = nullptr)
- : memory{memory_}, addr{addr_}, size{size_} {
+ : m_memory{memory}, m_addr{addr}, m_size{size} {
static_assert(FLAGS & GuestMemoryFlags::Read || FLAGS & GuestMemoryFlags::Write);
if constexpr (FLAGS & GuestMemoryFlags::Read) {
Read(addr, size, backup);
@@ -521,89 +521,97 @@ public:
~GuestMemory() = default;
T* data() noexcept {
- return data_span.data();
+ return m_data_span.data();
}
const T* data() const noexcept {
- return data_span.data();
+ return m_data_span.data();
+ }
+
+ size_t size() const noexcept {
+ return m_size;
+ }
+
+ size_t size_bytes() const noexcept {
+ return this->size() * sizeof(T);
}
[[nodiscard]] T* begin() noexcept {
- return data();
+ return this->data();
}
[[nodiscard]] const T* begin() const noexcept {
- return data();
+ return this->data();
}
[[nodiscard]] T* end() noexcept {
- return data() + size;
+ return this->data() + this->size();
}
[[nodiscard]] const T* end() const noexcept {
- return data() + size;
+ return this->data() + this->size();
}
T& operator[](size_t index) noexcept {
- return data_span[index];
+ return m_data_span[index];
}
const T& operator[](size_t index) const noexcept {
- return data_span[index];
+ return m_data_span[index];
}
- void SetAddressAndSize(u64 addr_, std::size_t size_) noexcept {
- addr = addr_;
- size = size_;
- addr_changed = true;
+ void SetAddressAndSize(u64 addr, std::size_t size) noexcept {
+ m_addr = addr;
+ m_size = size;
+ m_addr_changed = true;
}
- std::span<T> Read(u64 addr_, std::size_t size_,
+ std::span<T> Read(u64 addr, std::size_t size,
Common::ScratchBuffer<T>* backup = nullptr) noexcept {
- addr = addr_;
- size = size_;
- if (size == 0) {
- is_data_copy = true;
+ m_addr = addr;
+ m_size = size;
+ if (m_size == 0) {
+ m_is_data_copy = true;
return {};
}
- if (TrySetSpan()) {
+ if (this->TrySetSpan()) {
if constexpr (FLAGS & GuestMemoryFlags::Safe) {
- memory.FlushRegion(addr, size * sizeof(T));
+ m_memory.FlushRegion(m_addr, this->size_bytes());
}
} else {
if (backup) {
- backup->resize_destructive(size);
- data_span = *backup;
+ backup->resize_destructive(this->size());
+ m_data_span = *backup;
} else {
- data_copy.resize(size);
- data_span = std::span(data_copy);
+ m_data_copy.resize(this->size());
+ m_data_span = std::span(m_data_copy);
}
- is_data_copy = true;
- span_valid = true;
+ m_is_data_copy = true;
+ m_span_valid = true;
if constexpr (FLAGS & GuestMemoryFlags::Safe) {
- memory.ReadBlock(addr, data_span.data(), size * sizeof(T));
+ m_memory.ReadBlock(m_addr, this->data(), this->size_bytes());
} else {
- memory.ReadBlockUnsafe(addr, data_span.data(), size * sizeof(T));
+ m_memory.ReadBlockUnsafe(m_addr, this->data(), this->size_bytes());
}
}
- return data_span;
+ return m_data_span;
}
void Write(std::span<T> write_data) noexcept {
if constexpr (FLAGS & GuestMemoryFlags::Cached) {
- memory.WriteBlockCached(addr, write_data.data(), size * sizeof(T));
+ m_memory.WriteBlockCached(m_addr, write_data.data(), this->size_bytes());
} else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
- memory.WriteBlock(addr, write_data.data(), size * sizeof(T));
+ m_memory.WriteBlock(m_addr, write_data.data(), this->size_bytes());
} else {
- memory.WriteBlockUnsafe(addr, write_data.data(), size * sizeof(T));
+ m_memory.WriteBlockUnsafe(m_addr, write_data.data(), this->size_bytes());
}
}
bool TrySetSpan() noexcept {
- if (u8* ptr = memory.GetSpan(addr, size * sizeof(T)); ptr) {
- data_span = {reinterpret_cast<T*>(ptr), size};
- span_valid = true;
+ if (u8* ptr = m_memory.GetSpan(m_addr, this->size_bytes()); ptr) {
+ m_data_span = {reinterpret_cast<T*>(ptr), this->size()};
+ m_span_valid = true;
return true;
}
return false;
@@ -611,36 +619,36 @@ public:
protected:
bool IsDataCopy() const noexcept {
- return is_data_copy;
+ return m_is_data_copy;
}
bool AddressChanged() const noexcept {
- return addr_changed;
+ return m_addr_changed;
}
- M& memory;
- u64 addr;
- size_t size;
- std::span<T> data_span{};
- std::vector<T> data_copy;
- bool span_valid{false};
- bool is_data_copy{false};
- bool addr_changed{false};
+ M& m_memory;
+ u64 m_addr{};
+ size_t m_size{};
+ std::span<T> m_data_span{};
+ std::vector<T> m_data_copy{};
+ bool m_span_valid{false};
+ bool m_is_data_copy{false};
+ bool m_addr_changed{false};
};
template <typename M, typename T, GuestMemoryFlags FLAGS>
class GuestMemoryScoped : public GuestMemory<M, T, FLAGS> {
public:
GuestMemoryScoped() = delete;
- explicit GuestMemoryScoped(M& memory_, u64 addr_, std::size_t size_,
+ explicit GuestMemoryScoped(M& memory, u64 addr, std::size_t size,
Common::ScratchBuffer<T>* backup = nullptr)
- : GuestMemory<M, T, FLAGS>(memory_, addr_, size_, backup) {
+ : GuestMemory<M, T, FLAGS>(memory, addr, size, backup) {
if constexpr (!(FLAGS & GuestMemoryFlags::Read)) {
if (!this->TrySetSpan()) {
if (backup) {
- this->data_span = *backup;
- this->span_valid = true;
- this->is_data_copy = true;
+ this->m_data_span = *backup;
+ this->m_span_valid = true;
+ this->m_is_data_copy = true;
}
}
}
@@ -648,24 +656,21 @@ public:
~GuestMemoryScoped() {
if constexpr (FLAGS & GuestMemoryFlags::Write) {
- if (this->size == 0) [[unlikely]] {
+ if (this->size() == 0) [[unlikely]] {
return;
}
if (this->AddressChanged() || this->IsDataCopy()) {
- ASSERT(this->span_valid);
+ ASSERT(this->m_span_valid);
if constexpr (FLAGS & GuestMemoryFlags::Cached) {
- this->memory.WriteBlockCached(this->addr, this->data_span.data(),
- this->size * sizeof(T));
+ this->m_memory.WriteBlockCached(this->m_addr, this->data(), this->size_bytes());
} else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
- this->memory.WriteBlock(this->addr, this->data_span.data(),
- this->size * sizeof(T));
+ this->m_memory.WriteBlock(this->m_addr, this->data(), this->size_bytes());
} else {
- this->memory.WriteBlockUnsafe(this->addr, this->data_span.data(),
- this->size * sizeof(T));
+ this->m_memory.WriteBlockUnsafe(this->m_addr, this->data(), this->size_bytes());
}
} else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
- this->memory.InvalidateRegion(this->addr, this->size * sizeof(T));
+ this->m_memory.InvalidateRegion(this->m_addr, this->size_bytes());
}
}
}
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp
index cd8e24b0b..da8eab7ee 100644
--- a/src/video_core/engines/maxwell_dma.cpp
+++ b/src/video_core/engines/maxwell_dma.cpp
@@ -5,6 +5,7 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/microprofile.h"
+#include "common/polyfill_ranges.h"
#include "common/settings.h"
#include "core/core.h"
#include "core/memory.h"
diff --git a/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp b/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp
index f822fa856..44a771d65 100644
--- a/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp
+++ b/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp
@@ -220,7 +220,8 @@ GraphicsPipeline::GraphicsPipeline(const Device& device, TextureCache& texture_c
ASSERT(num_textures <= MAX_TEXTURES);
ASSERT(num_images <= MAX_IMAGES);
- const bool assembly_shaders{assembly_programs[0].handle != 0};
+ const auto backend = device.GetShaderBackend();
+ const bool assembly_shaders{backend == Settings::ShaderBackend::Glasm};
use_storage_buffers =
!assembly_shaders || num_storage_buffers <= device.GetMaxGLASMStorageBufferBlocks();
writes_global_memory &= !use_storage_buffers;
@@ -230,7 +231,6 @@ GraphicsPipeline::GraphicsPipeline(const Device& device, TextureCache& texture_c
GenerateTransformFeedbackState();
}
const bool in_parallel = thread_worker != nullptr;
- const auto backend = device.GetShaderBackend();
auto func{[this, sources_ = std::move(sources), sources_spirv_ = std::move(sources_spirv),
shader_notify, backend, in_parallel,
force_context_flush](ShaderContext::Context*) mutable {
@@ -559,15 +559,13 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
}
void GraphicsPipeline::ConfigureTransformFeedbackImpl() const {
- glTransformFeedbackStreamAttribsNV(num_xfb_attribs, xfb_attribs.data(), num_xfb_strides,
- xfb_streams.data(), GL_INTERLEAVED_ATTRIBS);
+ glTransformFeedbackAttribsNV(num_xfb_attribs, xfb_attribs.data(), GL_SEPARATE_ATTRIBS);
}
void GraphicsPipeline::GenerateTransformFeedbackState() {
// TODO(Rodrigo): Inject SKIP_COMPONENTS*_NV when required. An unimplemented message will signal
// when this is required.
GLint* cursor{xfb_attribs.data()};
- GLint* current_stream{xfb_streams.data()};
for (size_t feedback = 0; feedback < Maxwell::NumTransformFeedbackBuffers; ++feedback) {
const auto& layout = key.xfb_state.layouts[feedback];
@@ -575,15 +573,6 @@ void GraphicsPipeline::GenerateTransformFeedbackState() {
if (layout.varying_count == 0) {
continue;
}
- *current_stream = static_cast<GLint>(feedback);
- if (current_stream != xfb_streams.data()) {
- // When stepping one stream, push the expected token
- cursor[0] = GL_NEXT_BUFFER_NV;
- cursor[1] = 0;
- cursor[2] = 0;
- cursor += XFB_ENTRY_STRIDE;
- }
- ++current_stream;
const auto& locations = key.xfb_state.varyings[feedback];
std::optional<u32> current_index;
@@ -619,7 +608,6 @@ void GraphicsPipeline::GenerateTransformFeedbackState() {
}
}
num_xfb_attribs = static_cast<GLsizei>((cursor - xfb_attribs.data()) / XFB_ENTRY_STRIDE);
- num_xfb_strides = static_cast<GLsizei>(current_stream - xfb_streams.data());
}
void GraphicsPipeline::WaitForBuild() {
diff --git a/src/video_core/renderer_opengl/gl_graphics_pipeline.h b/src/video_core/renderer_opengl/gl_graphics_pipeline.h
index 7b3d7eae8..74fc9cc3d 100644
--- a/src/video_core/renderer_opengl/gl_graphics_pipeline.h
+++ b/src/video_core/renderer_opengl/gl_graphics_pipeline.h
@@ -154,9 +154,7 @@ private:
static constexpr std::size_t XFB_ENTRY_STRIDE = 3;
GLsizei num_xfb_attribs{};
- GLsizei num_xfb_strides{};
std::array<GLint, 128 * XFB_ENTRY_STRIDE * Maxwell::NumTransformFeedbackBuffers> xfb_attribs{};
- std::array<GLint, Maxwell::NumTransformFeedbackBuffers> xfb_streams{};
std::mutex built_mutex;
std::condition_variable built_condvar;
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index 710929ac5..adde96aa5 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -326,6 +326,43 @@ std::vector<const char*> ExtensionListForVulkan(
} // Anonymous namespace
+void Device::RemoveExtension(bool& extension, const std::string& extension_name) {
+ extension = false;
+ loaded_extensions.erase(extension_name);
+}
+
+void Device::RemoveExtensionIfUnsuitable(bool is_suitable, const std::string& extension_name) {
+ if (loaded_extensions.contains(extension_name) && !is_suitable) {
+ LOG_WARNING(Render_Vulkan, "Removing unsuitable extension {}", extension_name);
+ this->RemoveExtension(is_suitable, extension_name);
+ }
+}
+
+template <typename Feature>
+void Device::RemoveExtensionFeature(bool& extension, Feature& feature,
+ const std::string& extension_name) {
+ // Unload extension.
+ this->RemoveExtension(extension, extension_name);
+
+ // Save sType and pNext for chain.
+ VkStructureType sType = feature.sType;
+ void* pNext = feature.pNext;
+
+ // Clear feature struct and restore chain.
+ feature = {};
+ feature.sType = sType;
+ feature.pNext = pNext;
+}
+
+template <typename Feature>
+void Device::RemoveExtensionFeatureIfUnsuitable(bool is_suitable, Feature& feature,
+ const std::string& extension_name) {
+ if (loaded_extensions.contains(extension_name) && !is_suitable) {
+ LOG_WARNING(Render_Vulkan, "Removing features for unsuitable extension {}", extension_name);
+ this->RemoveExtensionFeature(is_suitable, feature, extension_name);
+ }
+}
+
Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR surface,
const vk::InstanceDispatch& dld_)
: instance{instance_}, dld{dld_}, physical{physical_},
@@ -397,21 +434,20 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
if (is_qualcomm || is_turnip) {
LOG_WARNING(Render_Vulkan,
"Qualcomm and Turnip drivers have broken VK_EXT_custom_border_color");
- extensions.custom_border_color = false;
- loaded_extensions.erase(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME);
+ RemoveExtensionFeature(extensions.custom_border_color, features.custom_border_color,
+ VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME);
}
if (is_qualcomm) {
must_emulate_scaled_formats = true;
LOG_WARNING(Render_Vulkan, "Qualcomm drivers have broken VK_EXT_extended_dynamic_state");
- extensions.extended_dynamic_state = false;
- loaded_extensions.erase(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
+ RemoveExtensionFeature(extensions.extended_dynamic_state, features.extended_dynamic_state,
+ VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
LOG_WARNING(Render_Vulkan,
"Qualcomm drivers have a slow VK_KHR_push_descriptor implementation");
- extensions.push_descriptor = false;
- loaded_extensions.erase(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
+ RemoveExtension(extensions.push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
#if defined(ANDROID) && defined(ARCHITECTURE_arm64)
// Patch the driver to enable BCn textures.
@@ -440,15 +476,12 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
must_emulate_scaled_formats = true;
LOG_WARNING(Render_Vulkan, "ARM drivers have broken VK_EXT_extended_dynamic_state");
- extensions.extended_dynamic_state = false;
- loaded_extensions.erase(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
+ RemoveExtensionFeature(extensions.extended_dynamic_state, features.extended_dynamic_state,
+ VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
LOG_WARNING(Render_Vulkan, "ARM drivers have broken VK_EXT_extended_dynamic_state2");
- features.extended_dynamic_state2.extendedDynamicState2 = false;
- features.extended_dynamic_state2.extendedDynamicState2LogicOp = false;
- features.extended_dynamic_state2.extendedDynamicState2PatchControlPoints = false;
- extensions.extended_dynamic_state2 = false;
- loaded_extensions.erase(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
+ RemoveExtensionFeature(extensions.extended_dynamic_state2, features.extended_dynamic_state2,
+ VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
}
if (is_nvidia) {
@@ -464,8 +497,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
case NvidiaArchitecture::VoltaOrOlder:
if (nv_major_version < 527) {
LOG_WARNING(Render_Vulkan, "Volta and older have broken VK_KHR_push_descriptor");
- extensions.push_descriptor = false;
- loaded_extensions.erase(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
+ RemoveExtension(extensions.push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
}
break;
}
@@ -480,8 +512,9 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
if (version < VK_MAKE_API_VERSION(0, 21, 2, 0)) {
LOG_WARNING(Render_Vulkan,
"RADV versions older than 21.2 have broken VK_EXT_extended_dynamic_state");
- extensions.extended_dynamic_state = false;
- loaded_extensions.erase(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
+ RemoveExtensionFeature(extensions.extended_dynamic_state,
+ features.extended_dynamic_state,
+ VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
}
}
if (extensions.extended_dynamic_state2 && is_radv) {
@@ -490,11 +523,9 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
LOG_WARNING(
Render_Vulkan,
"RADV versions older than 22.3.1 have broken VK_EXT_extended_dynamic_state2");
- features.extended_dynamic_state2.extendedDynamicState2 = false;
- features.extended_dynamic_state2.extendedDynamicState2LogicOp = false;
- features.extended_dynamic_state2.extendedDynamicState2PatchControlPoints = false;
- extensions.extended_dynamic_state2 = false;
- loaded_extensions.erase(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
+ RemoveExtensionFeature(extensions.extended_dynamic_state2,
+ features.extended_dynamic_state2,
+ VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
}
}
if (extensions.extended_dynamic_state2 && is_qualcomm) {
@@ -504,11 +535,9 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
// Qualcomm Adreno 7xx drivers do not properly support extended_dynamic_state2.
LOG_WARNING(Render_Vulkan,
"Qualcomm Adreno 7xx drivers have broken VK_EXT_extended_dynamic_state2");
- features.extended_dynamic_state2.extendedDynamicState2 = false;
- features.extended_dynamic_state2.extendedDynamicState2LogicOp = false;
- features.extended_dynamic_state2.extendedDynamicState2PatchControlPoints = false;
- extensions.extended_dynamic_state2 = false;
- loaded_extensions.erase(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
+ RemoveExtensionFeature(extensions.extended_dynamic_state2,
+ features.extended_dynamic_state2,
+ VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
}
}
if (extensions.extended_dynamic_state3 && is_radv) {
@@ -540,9 +569,9 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
if (is_rdna2) {
LOG_WARNING(Render_Vulkan,
"RADV has broken VK_EXT_vertex_input_dynamic_state on RDNA2 hardware");
- features.vertex_input_dynamic_state.vertexInputDynamicState = false;
- extensions.vertex_input_dynamic_state = false;
- loaded_extensions.erase(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME);
+ RemoveExtensionFeature(extensions.vertex_input_dynamic_state,
+ features.vertex_input_dynamic_state,
+ VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME);
}
}
if (extensions.vertex_input_dynamic_state && is_qualcomm) {
@@ -553,9 +582,9 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
LOG_WARNING(
Render_Vulkan,
"Qualcomm Adreno 7xx drivers have broken VK_EXT_vertex_input_dynamic_state");
- features.vertex_input_dynamic_state.vertexInputDynamicState = false;
- extensions.vertex_input_dynamic_state = false;
- loaded_extensions.erase(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME);
+ RemoveExtensionFeature(extensions.vertex_input_dynamic_state,
+ features.vertex_input_dynamic_state,
+ VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME);
}
}
@@ -575,8 +604,8 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
if (!features.shader_float16_int8.shaderFloat16) {
LOG_WARNING(Render_Vulkan,
"AMD GCN4 and earlier have broken VK_EXT_sampler_filter_minmax");
- extensions.sampler_filter_minmax = false;
- loaded_extensions.erase(VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME);
+ RemoveExtension(extensions.sampler_filter_minmax,
+ VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME);
}
}
@@ -584,8 +613,9 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
const u32 version = (properties.properties.driverVersion << 3) >> 3;
if (version < VK_MAKE_API_VERSION(27, 20, 100, 0)) {
LOG_WARNING(Render_Vulkan, "Intel has broken VK_EXT_vertex_input_dynamic_state");
- extensions.vertex_input_dynamic_state = false;
- loaded_extensions.erase(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME);
+ RemoveExtensionFeature(extensions.vertex_input_dynamic_state,
+ features.vertex_input_dynamic_state,
+ VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME);
}
}
if (features.shader_float16_int8.shaderFloat16 && is_intel_windows) {
@@ -612,8 +642,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
// mesa/mesa/-/commit/ff91c5ca42bc80aa411cb3fd8f550aa6fdd16bdc
LOG_WARNING(Render_Vulkan,
"ANV drivers 22.3.0 to 23.1.0 have broken VK_KHR_push_descriptor");
- extensions.push_descriptor = false;
- loaded_extensions.erase(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
+ RemoveExtension(extensions.push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
}
}
if (is_mvk) {
@@ -1007,34 +1036,29 @@ bool Device::GetSuitability(bool requires_swapchain) {
return suitable;
}
-void Device::RemoveExtensionIfUnsuitable(bool is_suitable, const std::string& extension_name) {
- if (loaded_extensions.contains(extension_name) && !is_suitable) {
- LOG_WARNING(Render_Vulkan, "Removing unsuitable extension {}", extension_name);
- loaded_extensions.erase(extension_name);
- }
-}
-
void Device::RemoveUnsuitableExtensions() {
// VK_EXT_custom_border_color
extensions.custom_border_color = features.custom_border_color.customBorderColors &&
features.custom_border_color.customBorderColorWithoutFormat;
- RemoveExtensionIfUnsuitable(extensions.custom_border_color,
- VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME);
+ RemoveExtensionFeatureIfUnsuitable(extensions.custom_border_color, features.custom_border_color,
+ VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME);
// VK_EXT_depth_clip_control
extensions.depth_clip_control = features.depth_clip_control.depthClipControl;
- RemoveExtensionIfUnsuitable(extensions.depth_clip_control,
- VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME);
+ RemoveExtensionFeatureIfUnsuitable(extensions.depth_clip_control, features.depth_clip_control,
+ VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME);
// VK_EXT_extended_dynamic_state
extensions.extended_dynamic_state = features.extended_dynamic_state.extendedDynamicState;
- RemoveExtensionIfUnsuitable(extensions.extended_dynamic_state,
- VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
+ RemoveExtensionFeatureIfUnsuitable(extensions.extended_dynamic_state,
+ features.extended_dynamic_state,
+ VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
// VK_EXT_extended_dynamic_state2
extensions.extended_dynamic_state2 = features.extended_dynamic_state2.extendedDynamicState2;
- RemoveExtensionIfUnsuitable(extensions.extended_dynamic_state2,
- VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
+ RemoveExtensionFeatureIfUnsuitable(extensions.extended_dynamic_state2,
+ features.extended_dynamic_state2,
+ VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
// VK_EXT_extended_dynamic_state3
dynamic_state3_blending =
@@ -1048,35 +1072,38 @@ void Device::RemoveUnsuitableExtensions() {
extensions.extended_dynamic_state3 = dynamic_state3_blending || dynamic_state3_enables;
dynamic_state3_blending = dynamic_state3_blending && extensions.extended_dynamic_state3;
dynamic_state3_enables = dynamic_state3_enables && extensions.extended_dynamic_state3;
- RemoveExtensionIfUnsuitable(extensions.extended_dynamic_state3,
- VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
+ RemoveExtensionFeatureIfUnsuitable(extensions.extended_dynamic_state3,
+ features.extended_dynamic_state3,
+ VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
// VK_EXT_provoking_vertex
extensions.provoking_vertex =
features.provoking_vertex.provokingVertexLast &&
features.provoking_vertex.transformFeedbackPreservesProvokingVertex;
- RemoveExtensionIfUnsuitable(extensions.provoking_vertex,
- VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME);
+ RemoveExtensionFeatureIfUnsuitable(extensions.provoking_vertex, features.provoking_vertex,
+ VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME);
// VK_KHR_shader_atomic_int64
extensions.shader_atomic_int64 = features.shader_atomic_int64.shaderBufferInt64Atomics &&
features.shader_atomic_int64.shaderSharedInt64Atomics;
- RemoveExtensionIfUnsuitable(extensions.shader_atomic_int64,
- VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME);
+ RemoveExtensionFeatureIfUnsuitable(extensions.shader_atomic_int64, features.shader_atomic_int64,
+ VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME);
// VK_EXT_shader_demote_to_helper_invocation
extensions.shader_demote_to_helper_invocation =
features.shader_demote_to_helper_invocation.shaderDemoteToHelperInvocation;
- RemoveExtensionIfUnsuitable(extensions.shader_demote_to_helper_invocation,
- VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME);
+ RemoveExtensionFeatureIfUnsuitable(extensions.shader_demote_to_helper_invocation,
+ features.shader_demote_to_helper_invocation,
+ VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME);
// VK_EXT_subgroup_size_control
extensions.subgroup_size_control =
features.subgroup_size_control.subgroupSizeControl &&
properties.subgroup_size_control.minSubgroupSize <= GuestWarpSize &&
properties.subgroup_size_control.maxSubgroupSize >= GuestWarpSize;
- RemoveExtensionIfUnsuitable(extensions.subgroup_size_control,
- VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME);
+ RemoveExtensionFeatureIfUnsuitable(extensions.subgroup_size_control,
+ features.subgroup_size_control,
+ VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME);
// VK_EXT_transform_feedback
extensions.transform_feedback =
@@ -1086,24 +1113,27 @@ void Device::RemoveUnsuitableExtensions() {
properties.transform_feedback.maxTransformFeedbackBuffers > 0 &&
properties.transform_feedback.transformFeedbackQueries &&
properties.transform_feedback.transformFeedbackDraw;
- RemoveExtensionIfUnsuitable(extensions.transform_feedback,
- VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME);
+ RemoveExtensionFeatureIfUnsuitable(extensions.transform_feedback, features.transform_feedback,
+ VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME);
// VK_EXT_vertex_input_dynamic_state
extensions.vertex_input_dynamic_state =
features.vertex_input_dynamic_state.vertexInputDynamicState;
- RemoveExtensionIfUnsuitable(extensions.vertex_input_dynamic_state,
- VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME);
+ RemoveExtensionFeatureIfUnsuitable(extensions.vertex_input_dynamic_state,
+ features.vertex_input_dynamic_state,
+ VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME);
// VK_KHR_pipeline_executable_properties
if (Settings::values.renderer_shader_feedback.GetValue()) {
extensions.pipeline_executable_properties =
features.pipeline_executable_properties.pipelineExecutableInfo;
- RemoveExtensionIfUnsuitable(extensions.pipeline_executable_properties,
- VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME);
+ RemoveExtensionFeatureIfUnsuitable(extensions.pipeline_executable_properties,
+ features.pipeline_executable_properties,
+ VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME);
} else {
- extensions.pipeline_executable_properties = false;
- loaded_extensions.erase(VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME);
+ RemoveExtensionFeature(extensions.pipeline_executable_properties,
+ features.pipeline_executable_properties,
+ VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME);
}
// VK_KHR_workgroup_memory_explicit_layout
@@ -1113,8 +1143,9 @@ void Device::RemoveUnsuitableExtensions() {
features.workgroup_memory_explicit_layout.workgroupMemoryExplicitLayout8BitAccess &&
features.workgroup_memory_explicit_layout.workgroupMemoryExplicitLayout16BitAccess &&
features.workgroup_memory_explicit_layout.workgroupMemoryExplicitLayoutScalarBlockLayout;
- RemoveExtensionIfUnsuitable(extensions.workgroup_memory_explicit_layout,
- VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME);
+ RemoveExtensionFeatureIfUnsuitable(extensions.workgroup_memory_explicit_layout,
+ features.workgroup_memory_explicit_layout,
+ VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME);
}
void Device::SetupFamilies(VkSurfaceKHR surface) {
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h
index d8dd41e51..488fdd313 100644
--- a/src/video_core/vulkan_common/vulkan_device.h
+++ b/src/video_core/vulkan_common/vulkan_device.h
@@ -639,8 +639,17 @@ private:
// Remove extensions which have incomplete feature support.
void RemoveUnsuitableExtensions();
+
+ void RemoveExtension(bool& extension, const std::string& extension_name);
void RemoveExtensionIfUnsuitable(bool is_suitable, const std::string& extension_name);
+ template <typename Feature>
+ void RemoveExtensionFeature(bool& extension, Feature& feature,
+ const std::string& extension_name);
+ template <typename Feature>
+ void RemoveExtensionFeatureIfUnsuitable(bool is_suitable, Feature& feature,
+ const std::string& extension_name);
+
/// Sets up queue families.
void SetupFamilies(VkSurfaceKHR surface);
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index 465084fea..b5a02700d 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -214,13 +214,17 @@ void GameList::OnTextChanged(const QString& new_text) {
const int children_count = folder->rowCount();
for (int j = 0; j < children_count; ++j) {
++children_total;
+
const QStandardItem* child = folder->child(j, 0);
+
+ const auto program_id = child->data(GameListItemPath::ProgramIdRole).toULongLong();
+
const QString file_path =
child->data(GameListItemPath::FullPathRole).toString().toLower();
const QString file_title =
child->data(GameListItemPath::TitleRole).toString().toLower();
const QString file_program_id =
- child->data(GameListItemPath::ProgramIdRole).toString().toLower();
+ QStringLiteral("%1").arg(program_id, 16, 16, QLatin1Char{'0'});
// Only items which filename in combination with its title contains all words
// that are in the searchfield will be visible in the gamelist
@@ -231,7 +235,7 @@ void GameList::OnTextChanged(const QString& new_text) {
file_path.mid(file_path.lastIndexOf(QLatin1Char{'/'}) + 1) + QLatin1Char{' '} +
file_title;
if (ContainsAllWords(file_name, edit_filter_text) ||
- (file_program_id.count() == 16 && edit_filter_text.contains(file_program_id))) {
+ (file_program_id.count() == 16 && file_program_id.contains(edit_filter_text))) {
tree_view->setRowHidden(j, folder_index, false);
++result_count;
} else {