[android, ui] unswizzle combo picker core (#3516)
Combo picker for unswizzle. Attempt to combine settings + Enable toggle added. WARNING! The toggle won't have effect! It just controls GPU_UNSWIZZLE_ENABLED boolean setting, and will need @PavelBARABANOV unswizzle enable/disable integration. Co-authored-by: PavelBARABANOV <pavelbarabanov94@gmail.com> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3516 Reviewed-by: CamilleLaVey <camillelavey99@gmail.com> Reviewed-by: Maufeat <sahyno1996@gmail.com> Co-authored-by: xbzk <xbzk@eden-emu.dev> Co-committed-by: xbzk <xbzk@eden-emu.dev>
This commit is contained in:
parent
f6547fac8c
commit
2ab5b37137
|
|
@ -33,6 +33,7 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
|
||||||
RENDERER_PROVOKING_VERTEX("provoking_vertex"),
|
RENDERER_PROVOKING_VERTEX("provoking_vertex"),
|
||||||
RENDERER_DESCRIPTOR_INDEXING("descriptor_indexing"),
|
RENDERER_DESCRIPTOR_INDEXING("descriptor_indexing"),
|
||||||
RENDERER_SAMPLE_SHADING("sample_shading"),
|
RENDERER_SAMPLE_SHADING("sample_shading"),
|
||||||
|
GPU_UNSWIZZLE_ENABLED("gpu_unswizzle_enabled"),
|
||||||
PICTURE_IN_PICTURE("picture_in_picture"),
|
PICTURE_IN_PICTURE("picture_in_picture"),
|
||||||
USE_CUSTOM_RTC("custom_rtc_enabled"),
|
USE_CUSTOM_RTC("custom_rtc_enabled"),
|
||||||
BLACK_BACKGROUNDS("black_backgrounds"),
|
BLACK_BACKGROUNDS("black_backgrounds"),
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
package org.yuzu.yuzu_emu.features.settings.model.view
|
||||||
|
|
||||||
|
import androidx.annotation.ArrayRes
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting
|
||||||
|
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
|
||||||
|
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
|
||||||
|
|
||||||
|
class GpuUnswizzleSetting(
|
||||||
|
@StringRes titleId: Int = 0,
|
||||||
|
titleString: String = "",
|
||||||
|
@StringRes descriptionId: Int = 0,
|
||||||
|
descriptionString: String = "",
|
||||||
|
@ArrayRes val textureSizeChoicesId: Int,
|
||||||
|
@ArrayRes val textureSizeValuesId: Int,
|
||||||
|
@ArrayRes val streamSizeChoicesId: Int,
|
||||||
|
@ArrayRes val streamSizeValuesId: Int,
|
||||||
|
@ArrayRes val chunkSizeChoicesId: Int,
|
||||||
|
@ArrayRes val chunkSizeValuesId: Int
|
||||||
|
) : SettingsItem(
|
||||||
|
object : AbstractSetting {
|
||||||
|
override val key: String = SettingsItem.GPU_UNSWIZZLE_COMBINED
|
||||||
|
override val defaultValue: Any = false
|
||||||
|
override val isSaveable = true
|
||||||
|
override val isRuntimeModifiable = true
|
||||||
|
override val isSwitchable = true
|
||||||
|
override fun getValueAsString(needsGlobal: Boolean): String = "combined"
|
||||||
|
override fun reset() {
|
||||||
|
BooleanSetting.GPU_UNSWIZZLE_ENABLED.reset()
|
||||||
|
IntSetting.GPU_UNSWIZZLE_TEXTURE_SIZE.reset()
|
||||||
|
IntSetting.GPU_UNSWIZZLE_STREAM_SIZE.reset()
|
||||||
|
IntSetting.GPU_UNSWIZZLE_CHUNK_SIZE.reset()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
titleId,
|
||||||
|
titleString,
|
||||||
|
descriptionId,
|
||||||
|
descriptionString
|
||||||
|
) {
|
||||||
|
override val type = SettingsItem.TYPE_GPU_UNSWIZZLE
|
||||||
|
|
||||||
|
// Check if GPU unswizzle is enabled via the dedicated boolean setting
|
||||||
|
fun isEnabled(needsGlobal: Boolean = false): Boolean =
|
||||||
|
BooleanSetting.GPU_UNSWIZZLE_ENABLED.getBoolean(needsGlobal)
|
||||||
|
|
||||||
|
fun setEnabled(value: Boolean) =
|
||||||
|
BooleanSetting.GPU_UNSWIZZLE_ENABLED.setBoolean(value)
|
||||||
|
|
||||||
|
fun enable() = setEnabled(true)
|
||||||
|
|
||||||
|
fun disable() = setEnabled(false)
|
||||||
|
|
||||||
|
fun getTextureSize(needsGlobal: Boolean = false): Int =
|
||||||
|
IntSetting.GPU_UNSWIZZLE_TEXTURE_SIZE.getInt(needsGlobal)
|
||||||
|
|
||||||
|
fun setTextureSize(value: Int) =
|
||||||
|
IntSetting.GPU_UNSWIZZLE_TEXTURE_SIZE.setInt(value)
|
||||||
|
|
||||||
|
fun getStreamSize(needsGlobal: Boolean = false): Int =
|
||||||
|
IntSetting.GPU_UNSWIZZLE_STREAM_SIZE.getInt(needsGlobal)
|
||||||
|
|
||||||
|
fun setStreamSize(value: Int) =
|
||||||
|
IntSetting.GPU_UNSWIZZLE_STREAM_SIZE.setInt(value)
|
||||||
|
|
||||||
|
fun getChunkSize(needsGlobal: Boolean = false): Int =
|
||||||
|
IntSetting.GPU_UNSWIZZLE_CHUNK_SIZE.getInt(needsGlobal)
|
||||||
|
|
||||||
|
fun setChunkSize(value: Int) =
|
||||||
|
IntSetting.GPU_UNSWIZZLE_CHUNK_SIZE.setInt(value)
|
||||||
|
|
||||||
|
fun reset() = setting.reset()
|
||||||
|
}
|
||||||
|
|
@ -104,8 +104,10 @@ abstract class SettingsItem(
|
||||||
const val TYPE_SPINBOX = 12
|
const val TYPE_SPINBOX = 12
|
||||||
const val TYPE_LAUNCHABLE = 13
|
const val TYPE_LAUNCHABLE = 13
|
||||||
const val TYPE_PATH = 14
|
const val TYPE_PATH = 14
|
||||||
|
const val TYPE_GPU_UNSWIZZLE = 15
|
||||||
|
|
||||||
const val FASTMEM_COMBINED = "fastmem_combined"
|
const val FASTMEM_COMBINED = "fastmem_combined"
|
||||||
|
const val GPU_UNSWIZZLE_COMBINED = "gpu_unswizzle_combined"
|
||||||
|
|
||||||
val emptySetting = object : AbstractSetting {
|
val emptySetting = object : AbstractSetting {
|
||||||
override val key: String = ""
|
override val key: String = ""
|
||||||
|
|
@ -684,6 +686,18 @@ abstract class SettingsItem(
|
||||||
valuesId = R.array.gpuSwizzleChunkValues
|
valuesId = R.array.gpuSwizzleChunkValues
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
put(
|
||||||
|
GpuUnswizzleSetting(
|
||||||
|
titleId = R.string.gpu_unswizzle_settings,
|
||||||
|
descriptionId = R.string.gpu_unswizzle_settings_description,
|
||||||
|
textureSizeChoicesId = R.array.gpuTextureSizeSwizzleEntries,
|
||||||
|
textureSizeValuesId = R.array.gpuTextureSizeSwizzleValues,
|
||||||
|
streamSizeChoicesId = R.array.gpuSwizzleEntries,
|
||||||
|
streamSizeValuesId = R.array.gpuSwizzleValues,
|
||||||
|
chunkSizeChoicesId = R.array.gpuSwizzleChunkEntries,
|
||||||
|
chunkSizeValuesId = R.array.gpuSwizzleChunkValues
|
||||||
|
)
|
||||||
|
)
|
||||||
put(
|
put(
|
||||||
SingleChoiceSetting(
|
SingleChoiceSetting(
|
||||||
IntSetting.FAST_CPU_TIME,
|
IntSetting.FAST_CPU_TIME,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,206 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
package org.yuzu.yuzu_emu.features.settings.ui
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.content.DialogInterface
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.widget.ArrayAdapter
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import androidx.fragment.app.activityViewModels
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import org.yuzu.yuzu_emu.R
|
||||||
|
import org.yuzu.yuzu_emu.databinding.DialogGpuUnswizzleBinding
|
||||||
|
import org.yuzu.yuzu_emu.features.settings.model.view.GpuUnswizzleSetting
|
||||||
|
|
||||||
|
class GpuUnswizzleDialogFragment : DialogFragment() {
|
||||||
|
private var position = 0
|
||||||
|
private val settingsViewModel: SettingsViewModel by activityViewModels()
|
||||||
|
private lateinit var binding: DialogGpuUnswizzleBinding
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
position = requireArguments().getInt(POSITION)
|
||||||
|
|
||||||
|
if (settingsViewModel.clickedItem == null) dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
|
binding = DialogGpuUnswizzleBinding.inflate(LayoutInflater.from(requireContext()))
|
||||||
|
val item = settingsViewModel.clickedItem as GpuUnswizzleSetting
|
||||||
|
|
||||||
|
// Setup texture size dropdown
|
||||||
|
val textureSizeEntries = resources.getStringArray(item.textureSizeChoicesId)
|
||||||
|
val textureSizeValues = resources.getIntArray(item.textureSizeValuesId)
|
||||||
|
val textureSizeAdapter = ArrayAdapter(
|
||||||
|
requireContext(),
|
||||||
|
android.R.layout.simple_dropdown_item_1line,
|
||||||
|
textureSizeEntries.toMutableList()
|
||||||
|
)
|
||||||
|
binding.dropdownTextureSize.setAdapter(textureSizeAdapter)
|
||||||
|
|
||||||
|
// Setup stream size dropdown
|
||||||
|
val streamSizeEntries = resources.getStringArray(item.streamSizeChoicesId)
|
||||||
|
val streamSizeValues = resources.getIntArray(item.streamSizeValuesId)
|
||||||
|
val streamSizeAdapter = ArrayAdapter(
|
||||||
|
requireContext(),
|
||||||
|
android.R.layout.simple_dropdown_item_1line,
|
||||||
|
streamSizeEntries.toMutableList()
|
||||||
|
)
|
||||||
|
binding.dropdownStreamSize.setAdapter(streamSizeAdapter)
|
||||||
|
|
||||||
|
// Setup chunk size dropdown
|
||||||
|
val chunkSizeEntries = resources.getStringArray(item.chunkSizeChoicesId)
|
||||||
|
val chunkSizeValues = resources.getIntArray(item.chunkSizeValuesId)
|
||||||
|
val chunkSizeAdapter = ArrayAdapter(
|
||||||
|
requireContext(),
|
||||||
|
android.R.layout.simple_dropdown_item_1line,
|
||||||
|
chunkSizeEntries.toMutableList()
|
||||||
|
)
|
||||||
|
binding.dropdownChunkSize.setAdapter(chunkSizeAdapter)
|
||||||
|
|
||||||
|
// Load current values
|
||||||
|
val isEnabled = item.isEnabled()
|
||||||
|
binding.switchEnable.isChecked = isEnabled
|
||||||
|
|
||||||
|
if (isEnabled) {
|
||||||
|
val textureSizeIndex = textureSizeValues.indexOf(item.getTextureSize())
|
||||||
|
if (textureSizeIndex >= 0) {
|
||||||
|
binding.dropdownTextureSize.setText(textureSizeEntries[textureSizeIndex], false)
|
||||||
|
}
|
||||||
|
|
||||||
|
val streamSizeIndex = streamSizeValues.indexOf(item.getStreamSize())
|
||||||
|
if (streamSizeIndex >= 0) {
|
||||||
|
binding.dropdownStreamSize.setText(streamSizeEntries[streamSizeIndex], false)
|
||||||
|
}
|
||||||
|
|
||||||
|
val chunkSizeIndex = chunkSizeValues.indexOf(item.getChunkSize())
|
||||||
|
if (chunkSizeIndex >= 0) {
|
||||||
|
binding.dropdownChunkSize.setText(chunkSizeEntries[chunkSizeIndex], false)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Set default/recommended values when disabling
|
||||||
|
binding.dropdownTextureSize.setText(textureSizeEntries[3], false)
|
||||||
|
binding.dropdownStreamSize.setText(streamSizeEntries[3], false)
|
||||||
|
binding.dropdownChunkSize.setText(chunkSizeEntries[3], false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear adapter filters after setText to fix rotation bug
|
||||||
|
textureSizeAdapter.filter.filter(null)
|
||||||
|
streamSizeAdapter.filter.filter(null)
|
||||||
|
chunkSizeAdapter.filter.filter(null)
|
||||||
|
|
||||||
|
// Enable/disable dropdowns based on switch state
|
||||||
|
updateDropdownsState(isEnabled)
|
||||||
|
binding.switchEnable.setOnCheckedChangeListener { _, checked ->
|
||||||
|
updateDropdownsState(checked)
|
||||||
|
}
|
||||||
|
|
||||||
|
val dialog = MaterialAlertDialogBuilder(requireContext())
|
||||||
|
.setTitle(item.title)
|
||||||
|
.setView(binding.root)
|
||||||
|
.create()
|
||||||
|
|
||||||
|
// Setup button listeners
|
||||||
|
binding.btnDefault.setOnClickListener {
|
||||||
|
// Reset to defaults
|
||||||
|
item.reset()
|
||||||
|
// Refresh values with adapters reset
|
||||||
|
val textureSizeIndex = textureSizeValues.indexOf(item.getTextureSize())
|
||||||
|
if (textureSizeIndex >= 0) {
|
||||||
|
binding.dropdownTextureSize.setText(textureSizeEntries[textureSizeIndex], false)
|
||||||
|
}
|
||||||
|
val streamSizeIndex = streamSizeValues.indexOf(item.getStreamSize())
|
||||||
|
if (streamSizeIndex >= 0) {
|
||||||
|
binding.dropdownStreamSize.setText(streamSizeEntries[streamSizeIndex], false)
|
||||||
|
}
|
||||||
|
val chunkSizeIndex = chunkSizeValues.indexOf(item.getChunkSize())
|
||||||
|
if (chunkSizeIndex >= 0) {
|
||||||
|
binding.dropdownChunkSize.setText(chunkSizeEntries[chunkSizeIndex], false)
|
||||||
|
}
|
||||||
|
// Clear filters
|
||||||
|
textureSizeAdapter.filter.filter(null)
|
||||||
|
streamSizeAdapter.filter.filter(null)
|
||||||
|
chunkSizeAdapter.filter.filter(null)
|
||||||
|
|
||||||
|
settingsViewModel.setAdapterItemChanged(position)
|
||||||
|
settingsViewModel.setShouldReloadSettingsList(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.btnCancel.setOnClickListener {
|
||||||
|
dialog.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.btnOk.setOnClickListener {
|
||||||
|
if (binding.switchEnable.isChecked) {
|
||||||
|
item.enable()
|
||||||
|
// Save the selected values
|
||||||
|
val selectedTextureIndex = textureSizeEntries.indexOf(
|
||||||
|
binding.dropdownTextureSize.text.toString()
|
||||||
|
)
|
||||||
|
if (selectedTextureIndex >= 0) {
|
||||||
|
item.setTextureSize(textureSizeValues[selectedTextureIndex])
|
||||||
|
}
|
||||||
|
|
||||||
|
val selectedStreamIndex = streamSizeEntries.indexOf(
|
||||||
|
binding.dropdownStreamSize.text.toString()
|
||||||
|
)
|
||||||
|
if (selectedStreamIndex >= 0) {
|
||||||
|
item.setStreamSize(streamSizeValues[selectedStreamIndex])
|
||||||
|
}
|
||||||
|
|
||||||
|
val selectedChunkIndex = chunkSizeEntries.indexOf(
|
||||||
|
binding.dropdownChunkSize.text.toString()
|
||||||
|
)
|
||||||
|
if (selectedChunkIndex >= 0) {
|
||||||
|
item.setChunkSize(chunkSizeValues[selectedChunkIndex])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Disable GPU unswizzle
|
||||||
|
item.disable()
|
||||||
|
}
|
||||||
|
|
||||||
|
settingsViewModel.setAdapterItemChanged(position)
|
||||||
|
settingsViewModel.setShouldReloadSettingsList(true)
|
||||||
|
dialog.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure filters are cleared after dialog is shown
|
||||||
|
binding.root.post {
|
||||||
|
textureSizeAdapter.filter.filter(null)
|
||||||
|
streamSizeAdapter.filter.filter(null)
|
||||||
|
chunkSizeAdapter.filter.filter(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
return dialog
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateDropdownsState(enabled: Boolean) {
|
||||||
|
binding.layoutTextureSize.isEnabled = enabled
|
||||||
|
binding.dropdownTextureSize.isEnabled = enabled
|
||||||
|
binding.layoutStreamSize.isEnabled = enabled
|
||||||
|
binding.dropdownStreamSize.isEnabled = enabled
|
||||||
|
binding.layoutChunkSize.isEnabled = enabled
|
||||||
|
binding.dropdownChunkSize.isEnabled = enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG = "GpuUnswizzleDialogFragment"
|
||||||
|
const val POSITION = "Position"
|
||||||
|
|
||||||
|
fun newInstance(
|
||||||
|
settingsViewModel: SettingsViewModel,
|
||||||
|
item: GpuUnswizzleSetting,
|
||||||
|
position: Int
|
||||||
|
): GpuUnswizzleDialogFragment {
|
||||||
|
val dialog = GpuUnswizzleDialogFragment()
|
||||||
|
val args = Bundle()
|
||||||
|
args.putInt(POSITION, position)
|
||||||
|
dialog.arguments = args
|
||||||
|
settingsViewModel.clickedItem = item
|
||||||
|
return dialog
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.features.settings.ui
|
package org.yuzu.yuzu_emu.features.settings.ui
|
||||||
|
|
@ -101,6 +101,11 @@ class SettingsAdapter(
|
||||||
SettingsItem.TYPE_PATH -> {
|
SettingsItem.TYPE_PATH -> {
|
||||||
PathViewHolder(ListItemSettingBinding.inflate(inflater), this)
|
PathViewHolder(ListItemSettingBinding.inflate(inflater), this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SettingsItem.TYPE_GPU_UNSWIZZLE -> {
|
||||||
|
GpuUnswizzleViewHolder(ListItemSettingBinding.inflate(inflater), this)
|
||||||
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
HeaderViewHolder(ListItemSettingsHeaderBinding.inflate(inflater), this)
|
HeaderViewHolder(ListItemSettingsHeaderBinding.inflate(inflater), this)
|
||||||
}
|
}
|
||||||
|
|
@ -474,6 +479,14 @@ class SettingsAdapter(
|
||||||
settingsViewModel.setShouldShowPathResetDialog(true)
|
settingsViewModel.setShouldShowPathResetDialog(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onGpuUnswizzleClick(item: GpuUnswizzleSetting, position: Int) {
|
||||||
|
GpuUnswizzleDialogFragment.newInstance(
|
||||||
|
settingsViewModel,
|
||||||
|
item,
|
||||||
|
position
|
||||||
|
).show(fragment.childFragmentManager, GpuUnswizzleDialogFragment.TAG)
|
||||||
|
}
|
||||||
|
|
||||||
private class DiffCallback : DiffUtil.ItemCallback<SettingsItem>() {
|
private class DiffCallback : DiffUtil.ItemCallback<SettingsItem>() {
|
||||||
override fun areItemsTheSame(oldItem: SettingsItem, newItem: SettingsItem): Boolean {
|
override fun areItemsTheSame(oldItem: SettingsItem, newItem: SettingsItem): Boolean {
|
||||||
return oldItem.setting.key == newItem.setting.key
|
return oldItem.setting.key == newItem.setting.key
|
||||||
|
|
|
||||||
|
|
@ -282,9 +282,7 @@ class SettingsFragmentPresenter(
|
||||||
add(BooleanSetting.SKIP_CPU_INNER_INVALIDATION.key)
|
add(BooleanSetting.SKIP_CPU_INNER_INVALIDATION.key)
|
||||||
add(BooleanSetting.FIX_BLOOM_EFFECTS.key)
|
add(BooleanSetting.FIX_BLOOM_EFFECTS.key)
|
||||||
add(BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS.key)
|
add(BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS.key)
|
||||||
add(IntSetting.GPU_UNSWIZZLE_TEXTURE_SIZE.key)
|
add(SettingsItem.GPU_UNSWIZZLE_COMBINED)
|
||||||
add(IntSetting.GPU_UNSWIZZLE_STREAM_SIZE.key)
|
|
||||||
add(IntSetting.GPU_UNSWIZZLE_CHUNK_SIZE.key)
|
|
||||||
|
|
||||||
add(HeaderSetting(R.string.extensions))
|
add(HeaderSetting(R.string.extensions))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
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.GpuUnswizzleSetting
|
||||||
|
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
|
||||||
|
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
|
||||||
|
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
||||||
|
|
||||||
|
class GpuUnswizzleViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
|
||||||
|
SettingViewHolder(binding.root, adapter) {
|
||||||
|
private lateinit var setting: GpuUnswizzleSetting
|
||||||
|
|
||||||
|
override fun bind(item: SettingsItem) {
|
||||||
|
setting = item as GpuUnswizzleSetting
|
||||||
|
binding.textSettingName.text = setting.title
|
||||||
|
binding.textSettingDescription.setVisible(item.description.isNotEmpty())
|
||||||
|
binding.textSettingDescription.text = item.description
|
||||||
|
|
||||||
|
binding.textSettingValue.setVisible(true)
|
||||||
|
val resMgr = binding.root.context.resources
|
||||||
|
|
||||||
|
if (setting.isEnabled()) {
|
||||||
|
// Show a summary of current settings
|
||||||
|
val textureSizeEntries = resMgr.getStringArray(setting.textureSizeChoicesId)
|
||||||
|
val textureSizeValues = resMgr.getIntArray(setting.textureSizeValuesId)
|
||||||
|
val textureSizeIndex = textureSizeValues.indexOf(setting.getTextureSize())
|
||||||
|
val textureSizeLabel = if (textureSizeIndex >= 0) textureSizeEntries[textureSizeIndex] else "?"
|
||||||
|
|
||||||
|
val streamSizeEntries = resMgr.getStringArray(setting.streamSizeChoicesId)
|
||||||
|
val streamSizeValues = resMgr.getIntArray(setting.streamSizeValuesId)
|
||||||
|
val streamSizeIndex = streamSizeValues.indexOf(setting.getStreamSize())
|
||||||
|
val streamSizeLabel = if (streamSizeIndex >= 0) streamSizeEntries[streamSizeIndex] else "?"
|
||||||
|
|
||||||
|
val chunkSizeEntries = resMgr.getStringArray(setting.chunkSizeChoicesId)
|
||||||
|
val chunkSizeValues = resMgr.getIntArray(setting.chunkSizeValuesId)
|
||||||
|
val chunkSizeIndex = chunkSizeValues.indexOf(setting.getChunkSize())
|
||||||
|
val chunkSizeLabel = if (chunkSizeIndex >= 0) chunkSizeEntries[chunkSizeIndex] else "?"
|
||||||
|
|
||||||
|
binding.textSettingValue.text = "$textureSizeLabel ⋅ $streamSizeLabel ⋅ $chunkSizeLabel"
|
||||||
|
} else {
|
||||||
|
binding.textSettingValue.text = resMgr.getString(R.string.gpu_unswizzle_disabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.buttonClear.setVisible(setting.clearable)
|
||||||
|
binding.buttonClear.setOnClickListener {
|
||||||
|
adapter.onClearClick(setting, bindingAdapterPosition)
|
||||||
|
}
|
||||||
|
|
||||||
|
setStyle(setting.isEditable, binding)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onClick(clicked: View) {
|
||||||
|
if (!setting.isEditable) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
adapter.onGpuUnswizzleClick(setting, bindingAdapterPosition)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLongClick(clicked: View): Boolean {
|
||||||
|
if (setting.isEditable) {
|
||||||
|
return adapter.onLongClick(setting, bindingAdapterPosition)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:scrollbars="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="24dp">
|
||||||
|
|
||||||
|
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||||
|
android:id="@+id/switch_enable"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:text="@string/gpu_unswizzle_enable" />
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/layout_texture_size"
|
||||||
|
style="@style/Widget.Material3.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:hint="@string/gpu_unswizzle_texture_size">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.MaterialAutoCompleteTextView
|
||||||
|
android:id="@+id/dropdown_texture_size"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="none" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/layout_stream_size"
|
||||||
|
style="@style/Widget.Material3.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:hint="@string/gpu_unswizzle_stream_size">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.MaterialAutoCompleteTextView
|
||||||
|
android:id="@+id/dropdown_stream_size"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="none" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/layout_chunk_size"
|
||||||
|
style="@style/Widget.Material3.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/gpu_unswizzle_chunk_size">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.MaterialAutoCompleteTextView
|
||||||
|
android:id="@+id/dropdown_chunk_size"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="none" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="end"
|
||||||
|
android:spacing="8dp">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_default"
|
||||||
|
style="@style/Widget.Material3.Button.TextButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/gpu_unswizzle_default_button" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_cancel"
|
||||||
|
style="@style/Widget.Material3.Button.TextButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@android:string/cancel" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_ok"
|
||||||
|
style="@style/Widget.Material3.Button.TextButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@android:string/ok" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
|
|
@ -504,12 +504,17 @@
|
||||||
<string name="fix_bloom_effects_description">Reduces bloom blur in LA/EOW (Adreno 700), removes bloom in Burnout</string>
|
<string name="fix_bloom_effects_description">Reduces bloom blur in LA/EOW (Adreno 700), removes bloom in Burnout</string>
|
||||||
<string name="renderer_asynchronous_shaders">Use asynchronous shaders</string>
|
<string name="renderer_asynchronous_shaders">Use asynchronous shaders</string>
|
||||||
<string name="renderer_asynchronous_shaders_description">Compiles shaders asynchronously. This may reduce stutters but may also introduce glitches.</string>
|
<string name="renderer_asynchronous_shaders_description">Compiles shaders asynchronously. This may reduce stutters but may also introduce glitches.</string>
|
||||||
|
<string name="gpu_unswizzle_settings">GPU Unswizzle Settings</string>
|
||||||
|
<string name="gpu_unswizzle_settings_description">Configure GPU-based texture unswizzling parameters or disable it entirely. Adjust these settings to balance performance and texture loading quality.</string>
|
||||||
|
<string name="gpu_unswizzle_enable">Enable GPU Unswizzle</string>
|
||||||
|
<string name="gpu_unswizzle_disabled">Disabled</string>
|
||||||
<string name="gpu_unswizzle_texture_size">GPU Unswizzle Max Texture Size</string>
|
<string name="gpu_unswizzle_texture_size">GPU Unswizzle Max Texture Size</string>
|
||||||
<string name="gpu_unswizzle_texture_size_description">Sets the maximum size (MB) for GPU-based texture unswizzling. While the GPU is faster for medium and large textures, the CPU may be more efficient for very small ones. Adjust this to find the balance between GPU acceleration and CPU overhead.</string>
|
<string name="gpu_unswizzle_texture_size_description">Sets the maximum size (MB) for GPU-based texture unswizzling. While the GPU is faster for medium and large textures, the CPU may be more efficient for very small ones. Adjust this to find the balance between GPU acceleration and CPU overhead.</string>
|
||||||
<string name="gpu_unswizzle_stream_size">GPU Unswizzle Stream Size</string>
|
<string name="gpu_unswizzle_stream_size">GPU Unswizzle Stream Size</string>
|
||||||
<string name="gpu_unswizzle_stream_size_description">Sets the data limit per frame for unswizzling large textures. Higher values speed up texture loading at the cost of higher frame latency; lower values reduce GPU overhead but may cause visible texture pop-in.</string>
|
<string name="gpu_unswizzle_stream_size_description">Sets the data limit per frame for unswizzling large textures. Higher values speed up texture loading at the cost of higher frame latency; lower values reduce GPU overhead but may cause visible texture pop-in.</string>
|
||||||
<string name="gpu_unswizzle_chunk_size">GPU Unswizzle Chunk Size</string>
|
<string name="gpu_unswizzle_chunk_size">GPU Unswizzle Chunk Size</string>
|
||||||
<string name="gpu_unswizzle_chunk_size_description">Defines the number of depth slices processed per batch for 3D textures. Increasing this improves throughput efficiency on powerful GPUs but may cause stuttering or driver timeouts on weaker hardware.</string>
|
<string name="gpu_unswizzle_chunk_size_description">Defines the number of depth slices processed per batch for 3D textures. Increasing this improves throughput efficiency on powerful GPUs but may cause stuttering or driver timeouts on weaker hardware.</string>
|
||||||
|
<string name="gpu_unswizzle_default_button">Default</string>
|
||||||
|
|
||||||
|
|
||||||
<string name="extensions">Extensions</string>
|
<string name="extensions">Extensions</string>
|
||||||
|
|
|
||||||
|
|
@ -532,6 +532,9 @@ struct Values {
|
||||||
Category::RendererHacks,
|
Category::RendererHacks,
|
||||||
Specialization::Default};
|
Specialization::Default};
|
||||||
|
|
||||||
|
SwitchableSetting<bool> gpu_unswizzle_enabled{linkage, false, "gpu_unswizzle_enabled",
|
||||||
|
Category::RendererHacks};
|
||||||
|
|
||||||
SwitchableSetting<ExtendedDynamicState> dyna_state{linkage,
|
SwitchableSetting<ExtendedDynamicState> dyna_state{linkage,
|
||||||
#if defined (_WIN32)
|
#if defined (_WIN32)
|
||||||
ExtendedDynamicState::EDS3,
|
ExtendedDynamicState::EDS3,
|
||||||
|
|
|
||||||
|
|
@ -284,6 +284,11 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent)
|
||||||
tr("Fast GPU Time"),
|
tr("Fast GPU Time"),
|
||||||
tr("Overclocks the emulated GPU to increase dynamic resolution and render "
|
tr("Overclocks the emulated GPU to increase dynamic resolution and render "
|
||||||
"distance.\nUse 256 for maximal performance and 512 for maximal graphics fidelity."));
|
"distance.\nUse 256 for maximal performance and 512 for maximal graphics fidelity."));
|
||||||
|
INSERT(Settings,
|
||||||
|
gpu_unswizzle_enabled,
|
||||||
|
tr("GPU Unswizzle"),
|
||||||
|
tr("Accelerates BCn 3D texture decoding using GPU compute.\n"
|
||||||
|
"Disable if experiencing crashes or graphical glitches."));
|
||||||
INSERT(Settings,
|
INSERT(Settings,
|
||||||
gpu_unswizzle_texture_size,
|
gpu_unswizzle_texture_size,
|
||||||
tr("GPU Unswizzle Max Texture Size"),
|
tr("GPU Unswizzle Max Texture Size"),
|
||||||
|
|
|
||||||
|
|
@ -893,8 +893,10 @@ TextureCacheRuntime::TextureCacheRuntime(const Device& device_, Scheduler& sched
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bl3d_unswizzle_pass.emplace(device, scheduler, descriptor_pool,
|
if (Settings::values.gpu_unswizzle_enabled.GetValue()) {
|
||||||
staging_buffer_pool, compute_pass_descriptor_queue);
|
bl3d_unswizzle_pass.emplace(device, scheduler, descriptor_pool,
|
||||||
|
staging_buffer_pool, compute_pass_descriptor_queue);
|
||||||
|
}
|
||||||
|
|
||||||
// --- Create swizzle table buffer ---
|
// --- Create swizzle table buffer ---
|
||||||
{
|
{
|
||||||
|
|
@ -2538,6 +2540,14 @@ void TextureCacheRuntime::AccelerateImageUpload(
|
||||||
return astc_decoder_pass->Assemble(image, map, swizzles);
|
return astc_decoder_pass->Assemble(image, map, swizzles);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!Settings::values.gpu_unswizzle_enabled.GetValue() || !bl3d_unswizzle_pass) {
|
||||||
|
if (IsPixelFormatBCn(image.info.format) && image.info.type == ImageType::e3D) {
|
||||||
|
ASSERT_MSG(false, "GPU unswizzle is disabled for BCn 3D texture");
|
||||||
|
}
|
||||||
|
ASSERT(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (bl3d_unswizzle_pass &&
|
if (bl3d_unswizzle_pass &&
|
||||||
IsPixelFormatBCn(image.info.format) &&
|
IsPixelFormatBCn(image.info.format) &&
|
||||||
image.info.type == ImageType::e3D &&
|
image.info.type == ImageType::e3D &&
|
||||||
|
|
|
||||||
|
|
@ -80,31 +80,39 @@ TextureCache<P>::TextureCache(Runtime& runtime_, Tegra::MaxwellDeviceMemoryManag
|
||||||
lowmemorydevice = true;
|
lowmemorydevice = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (Settings::values.gpu_unswizzle_texture_size.GetValue()) {
|
const bool gpu_unswizzle_enabled = Settings::values.gpu_unswizzle_enabled.GetValue();
|
||||||
case Settings::GpuUnswizzleSize::VerySmall: gpu_unswizzle_maxsize = 16_MiB; break;
|
|
||||||
case Settings::GpuUnswizzleSize::Small: gpu_unswizzle_maxsize = 32_MiB; break;
|
|
||||||
case Settings::GpuUnswizzleSize::Normal: gpu_unswizzle_maxsize = 128_MiB; break;
|
|
||||||
case Settings::GpuUnswizzleSize::Large: gpu_unswizzle_maxsize = 256_MiB; break;
|
|
||||||
case Settings::GpuUnswizzleSize::VeryLarge: gpu_unswizzle_maxsize = 512_MiB; break;
|
|
||||||
default: gpu_unswizzle_maxsize = 128_MiB; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (Settings::values.gpu_unswizzle_stream_size.GetValue()) {
|
if (gpu_unswizzle_enabled) {
|
||||||
case Settings::GpuUnswizzle::VeryLow: swizzle_chunk_size = 4_MiB; break;
|
switch (Settings::values.gpu_unswizzle_texture_size.GetValue()) {
|
||||||
case Settings::GpuUnswizzle::Low: swizzle_chunk_size = 8_MiB; break;
|
case Settings::GpuUnswizzleSize::VerySmall: gpu_unswizzle_maxsize = 16_MiB; break;
|
||||||
case Settings::GpuUnswizzle::Normal: swizzle_chunk_size = 16_MiB; break;
|
case Settings::GpuUnswizzleSize::Small: gpu_unswizzle_maxsize = 32_MiB; break;
|
||||||
case Settings::GpuUnswizzle::Medium: swizzle_chunk_size = 32_MiB; break;
|
case Settings::GpuUnswizzleSize::Normal: gpu_unswizzle_maxsize = 128_MiB; break;
|
||||||
case Settings::GpuUnswizzle::High: swizzle_chunk_size = 64_MiB; break;
|
case Settings::GpuUnswizzleSize::Large: gpu_unswizzle_maxsize = 256_MiB; break;
|
||||||
default: swizzle_chunk_size = 16_MiB;
|
case Settings::GpuUnswizzleSize::VeryLarge: gpu_unswizzle_maxsize = 512_MiB; break;
|
||||||
}
|
default: gpu_unswizzle_maxsize = 128_MiB; break;
|
||||||
|
}
|
||||||
|
|
||||||
switch (Settings::values.gpu_unswizzle_chunk_size.GetValue()) {
|
switch (Settings::values.gpu_unswizzle_stream_size.GetValue()) {
|
||||||
case Settings::GpuUnswizzleChunk::VeryLow: swizzle_slices_per_batch = 32; break;
|
case Settings::GpuUnswizzle::VeryLow: swizzle_chunk_size = 4_MiB; break;
|
||||||
case Settings::GpuUnswizzleChunk::Low: swizzle_slices_per_batch = 64; break;
|
case Settings::GpuUnswizzle::Low: swizzle_chunk_size = 8_MiB; break;
|
||||||
case Settings::GpuUnswizzleChunk::Normal: swizzle_slices_per_batch = 128; break;
|
case Settings::GpuUnswizzle::Normal: swizzle_chunk_size = 16_MiB; break;
|
||||||
case Settings::GpuUnswizzleChunk::Medium: swizzle_slices_per_batch = 256; break;
|
case Settings::GpuUnswizzle::Medium: swizzle_chunk_size = 32_MiB; break;
|
||||||
case Settings::GpuUnswizzleChunk::High: swizzle_slices_per_batch = 512; break;
|
case Settings::GpuUnswizzle::High: swizzle_chunk_size = 64_MiB; break;
|
||||||
default: swizzle_slices_per_batch = 128;
|
default: swizzle_chunk_size = 16_MiB;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (Settings::values.gpu_unswizzle_chunk_size.GetValue()) {
|
||||||
|
case Settings::GpuUnswizzleChunk::VeryLow: swizzle_slices_per_batch = 32; break;
|
||||||
|
case Settings::GpuUnswizzleChunk::Low: swizzle_slices_per_batch = 64; break;
|
||||||
|
case Settings::GpuUnswizzleChunk::Normal: swizzle_slices_per_batch = 128; break;
|
||||||
|
case Settings::GpuUnswizzleChunk::Medium: swizzle_slices_per_batch = 256; break;
|
||||||
|
case Settings::GpuUnswizzleChunk::High: swizzle_slices_per_batch = 512; break;
|
||||||
|
default: swizzle_slices_per_batch = 128;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
gpu_unswizzle_maxsize = 0;
|
||||||
|
swizzle_chunk_size = 0;
|
||||||
|
swizzle_slices_per_batch = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1161,7 +1169,11 @@ void TextureCache<P>::RefreshContents(Image& image, ImageId image_id) {
|
||||||
QueueAsyncDecode(image, image_id);
|
QueueAsyncDecode(image, image_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (IsPixelFormatBCn(image.info.format) &&
|
|
||||||
|
const bool gpu_unswizzle_enabled = Settings::values.gpu_unswizzle_enabled.GetValue();
|
||||||
|
|
||||||
|
if (gpu_unswizzle_enabled &&
|
||||||
|
IsPixelFormatBCn(image.info.format) &&
|
||||||
image.info.type == ImageType::e3D &&
|
image.info.type == ImageType::e3D &&
|
||||||
image.info.resources.levels == 1 &&
|
image.info.resources.levels == 1 &&
|
||||||
image.info.resources.layers == 1 &&
|
image.info.resources.layers == 1 &&
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue