added custom driver option in settings

This commit is contained in:
izzy2lost
2026-02-28 07:04:12 -05:00
parent 13634f1db8
commit df7ee9b563
5 changed files with 163 additions and 2 deletions
+12
View File
@@ -805,6 +805,18 @@ static SetupFiles SyncSetupFiles() {
int displayMode = GetPrefInt(env, activity, "setting_display_mode", 0);
xemu_android_set_display_mode_setting(displayMode);
const std::string vulkanDriverUri = GetPrefString(env, activity, "setting_vulkan_driver_uri");
if (!vulkanDriverUri.empty()) {
std::string driverPath = base + "/vulkan_driver.so";
if (CopyUriToPath(env, activity, vulkanDriverUri, driverPath)) {
chmod(driverPath.c_str(), 0755);
setenv("XEMU_VULKAN_DRIVER", driverPath.c_str(), 1);
LogInfoFmt("Custom Vulkan driver staged: %s", driverPath.c_str());
} else {
LogError("Failed to copy custom Vulkan driver; using system default");
}
}
out.config_path = base + "/xemu.toml";
WriteConfigToml(out.config_path, out.mcpx, out.flash, out.hdd, out.dvd, out.eeprom, emuSettings);
LogInfoFmt("SyncSetupFiles: config %s", out.config_path.c_str());
@@ -1,8 +1,12 @@
package com.izzy2lost.x1box
import android.content.Context
import android.net.Uri
import android.os.Bundle
import android.provider.OpenableColumns
import android.widget.TextView
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.button.MaterialButton
import com.google.android.material.button.MaterialButtonToggleGroup
@@ -12,6 +16,21 @@ class SettingsActivity : AppCompatActivity() {
private val prefs by lazy { getSharedPreferences("x1box_prefs", Context.MODE_PRIVATE) }
private var pendingVulkanUri: String? = null
private var pendingVulkanName: String? = null
private var clearVulkan = false
private lateinit var tvVulkanDriverName: TextView
private val pickDriver =
registerForActivityResult(ActivityResultContracts.OpenDocument()) { uri: Uri? ->
uri ?: return@registerForActivityResult
pendingVulkanUri = uri.toString()
pendingVulkanName = getFileName(uri) ?: uri.lastPathSegment ?: "custom_driver.so"
clearVulkan = false
tvVulkanDriverName.text = pendingVulkanName
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_settings)
@@ -30,6 +49,9 @@ class SettingsActivity : AppCompatActivity() {
val switchFpu = findViewById<MaterialSwitch>(R.id.switch_hard_fpu)
val toggleAudioDriver = findViewById<MaterialButtonToggleGroup>(R.id.toggle_audio_driver)
val btnSave = findViewById<MaterialButton>(R.id.btn_settings_save)
tvVulkanDriverName = findViewById(R.id.tv_vulkan_driver_name)
val btnVulkanBrowse = findViewById<MaterialButton>(R.id.btn_vulkan_browse)
val btnVulkanClear = findViewById<MaterialButton>(R.id.btn_vulkan_clear)
// Load current values
val scale = prefs.getInt("setting_surface_scale", 1)
@@ -46,6 +68,10 @@ class SettingsActivity : AppCompatActivity() {
else -> toggleDisplayMode.check(R.id.btn_display_stretch)
}
tvVulkanDriverName.text =
prefs.getString("setting_vulkan_driver_name", null)
?: getString(R.string.settings_vulkan_driver_none)
val tcgThread = prefs.getString("setting_tcg_thread", "multi") ?: "multi"
if (tcgThread == "single") {
toggleThread.check(R.id.btn_thread_single)
@@ -65,6 +91,17 @@ class SettingsActivity : AppCompatActivity() {
else -> toggleAudioDriver.check(R.id.btn_audio_opensles)
}
btnVulkanBrowse.setOnClickListener {
pickDriver.launch(arrayOf("*/*"))
}
btnVulkanClear.setOnClickListener {
pendingVulkanUri = null
pendingVulkanName = null
clearVulkan = true
tvVulkanDriverName.text = getString(R.string.settings_vulkan_driver_none)
}
btnSave.setOnClickListener {
val selectedDisplayMode = when (toggleDisplayMode.checkedButtonId) {
R.id.btn_display_4_3 -> 1
@@ -86,7 +123,7 @@ class SettingsActivity : AppCompatActivity() {
else -> "openslES"
}
prefs.edit()
val edit = prefs.edit()
.putInt("setting_display_mode", selectedDisplayMode)
.putInt("setting_surface_scale", selectedScale)
.putString("setting_tcg_thread", selectedThread)
@@ -95,10 +132,27 @@ class SettingsActivity : AppCompatActivity() {
.putBoolean("setting_cache_shaders", switchShaders.isChecked)
.putBoolean("setting_hard_fpu", switchFpu.isChecked)
.putString("setting_audio_driver", selectedAudioDriver)
.apply()
when {
clearVulkan -> edit
.remove("setting_vulkan_driver_uri")
.remove("setting_vulkan_driver_name")
pendingVulkanUri != null -> edit
.putString("setting_vulkan_driver_uri", pendingVulkanUri)
.putString("setting_vulkan_driver_name", pendingVulkanName)
}
edit.apply()
Toast.makeText(this, R.string.settings_saved, Toast.LENGTH_SHORT).show()
finish()
}
}
private fun getFileName(uri: Uri): String? {
return contentResolver.query(uri, null, null, null, null)?.use { cursor ->
val col = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
if (col >= 0 && cursor.moveToFirst()) cursor.getString(col) else null
}
}
}
@@ -140,6 +140,59 @@
</com.google.android.material.button.MaterialButtonToggleGroup>
<!-- ── VULKAN DRIVER ── -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:text="@string/settings_section_vulkan_driver"
android:textAppearance="@style/TextAppearance.Material3.LabelLarge"
android:textColor="@color/xemu_green" />
<TextView
android:id="@+id/tv_vulkan_driver_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:textAppearance="@style/TextAppearance.Material3.BodyMedium"
android:textColor="@color/xemu_text_muted" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:orientation="horizontal"
android:weightSum="2">
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_vulkan_browse"
style="?attr/materialButtonOutlinedStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="4dp"
android:layout_weight="1"
android:text="@string/settings_vulkan_driver_browse" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_vulkan_clear"
style="?attr/materialButtonOutlinedStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_weight="1"
android:text="@string/settings_vulkan_driver_clear" />
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="12dp"
android:text="@string/settings_vulkan_driver_hint"
android:textAppearance="@style/TextAppearance.Material3.BodySmall"
android:textColor="@color/xemu_text_muted" />
<!-- ── PERFORMANCE ── -->
<TextView
android:layout_width="match_parent"
@@ -80,6 +80,11 @@
<string name="settings_save">Save</string>
<string name="settings_section_display">Display</string>
<string name="settings_section_vulkan_driver">Custom Vulkan Driver</string>
<string name="settings_vulkan_driver_none">System Default</string>
<string name="settings_vulkan_driver_browse">Browse…</string>
<string name="settings_vulkan_driver_clear">Clear</string>
<string name="settings_vulkan_driver_hint">For Adreno GPUs with Turnip/Mesa. Restart required.</string>
<string name="settings_display_mode">Aspect Ratio</string>
<string name="settings_display_mode_stretch">Stretch</string>
<string name="settings_display_mode_4_3">4:3</string>
+37
View File
@@ -24,9 +24,38 @@
#ifdef __ANDROID__
#include <android/log.h>
#include <dlfcn.h>
#endif
#include <volk.h>
#ifdef __ANDROID__
static void *g_custom_vk_handle = NULL;
static bool android_try_load_custom_vulkan(void)
{
const char *path = getenv("XEMU_VULKAN_DRIVER");
if (!path || path[0] == '\0') {
return false;
}
g_custom_vk_handle = dlopen(path, RTLD_NOW | RTLD_LOCAL);
if (!g_custom_vk_handle) {
fprintf(stderr, "Custom Vulkan driver dlopen failed: %s\n", dlerror());
return false;
}
PFN_vkGetInstanceProcAddr proc =
(PFN_vkGetInstanceProcAddr)dlsym(g_custom_vk_handle, "vkGetInstanceProcAddr");
if (!proc) {
fprintf(stderr, "Custom Vulkan driver: vkGetInstanceProcAddr not found\n");
dlclose(g_custom_vk_handle);
g_custom_vk_handle = NULL;
return false;
}
volkInitializeCustom(proc);
fprintf(stderr, "Custom Vulkan driver loaded: %s\n", path);
return true;
}
#endif
#define VkExtensionPropertiesArray GArray
#define StringArray GArray
@@ -154,7 +183,15 @@ static bool create_instance(PGRAPHState *pg, Error **errp)
PGRAPHVkState *r = pg->vk_renderer_state;
VkResult result;
#ifdef __ANDROID__
if (!android_try_load_custom_vulkan()) {
result = volkInitialize();
} else {
result = VK_SUCCESS;
}
#else
result = volkInitialize();
#endif
if (result != VK_SUCCESS) {
error_setg(errp, "volkInitialize failed");
return false;