Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ runtime=26.1.5-jammy
abi=arm64-v8a
source_package=mesa
mesa_commit=6a02618ccf6c5651ecb9cccbde571eb61fd73592
bin/zink_check_requirements.sha256=690177f11f92a12ab413b4548051362960c4df892ad3124a89c7ad2e6b16d438
lib/dri/zink_dri.so.sha256=a85c32422ab9c0b1b98495fc2274d8bfc7c6892f02496d60f884023ca45ccc41
lib/libEGL_mesa.so.0.sha256=b6b2e58a5e2b0b1aa6687891272625c89d727166b326cdf67cc2f040ae1cc484
lib/libEGL_mesa.so.0.sha256=013607840e63dc6cbca87e3ca3126f46734ec102b2072b5757d509615a3a1a46
lib/libGLX_mesa.so.0.sha256=36bad44d10cdb8610cbdfce7c532c4520acd4f1a9f9e92943e66606cc530b2fb
lib/libgallium-26.1.5.so.sha256=1a190093d84f64372c9ae1b001b4adc0d226b308486dc21d8565c53f2a1df75b
lib/libvulkan_virtio.so.sha256=82b57a2c7b7ea71e2cef92919a9529c5ff2dcda9bc7f53ed1bdf38bc81ca6e47
lib/libgallium-26.1.5.so.sha256=00de405a69fab61c49f0dbbe6a13c0b8332ffb664f20ed021baba0b713d2f06c
lib/libvulkan_virtio.so.sha256=9a21b21f90484960b3a3383144e7bd65bb725ede546ae4ce205f978b894f54a1
share/doc/license.rst.sha256=0d1a0472ecc81830e75c20d59b0ea02841e3db21255e0ebad97ab682c54d6615
share/drirc.d/00-mesa-defaults.conf.sha256=1406e018d5a83dacc9dceb5cecdc47410ad7f31a573390ec8c41c729e23c038a
share/glvnd/egl_vendor.d/50_mesa.json.sha256=cd3881df4227c13ca7f9cfe6c78820f21d5f7a00a41b299214f6f827e63be369
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
format=1
runtime=1.3.0-6
runtime=1.3.0-7
abi=arm64-v8a
source_package=virglrenderer-android
termux_packages_commit=978cdac5bdeb47f6061996240b65fc4e4dff11df
source_deb_sha256=847839a8cac5a349052e396f28bfe68061791e34901d4413b490e4555701399f
bin/virgl_test_server_android.sha256=c4fa02e432f2edbf974c8bf85922b6d1f7418be633bce443e5b1893c312273aa
libexec/virgl_render_server.sha256=e93c0082b7c82a8ec4c54c621e9d4c0e12fccbc7049f77b92398126199418c9e
lib/libepoxy.so.sha256=7b50fe1ef66cfea354f398523169bdb4ac8ec3b2715ac77073540bd5a1b3075f
lib/libvirglrenderer.so.sha256=15afb2811333f6947e29ebb498738bc9523708aeb05dbc9ae6630a708666798c
termux_packages_commit=d9696948261f136ccb9826a047c432f526dc99ba
source_deb_sha256=11595cd177b64c783b0ed6d3669e26b6bbd62f39e0426f1dbaf85d1a035f1c12
bin/virgl_test_server_android.sha256=62855b51d45eb8200c19ad3710bd6e426d4e19ff5dd28061e9c094b741f5b468
libexec/virgl_render_server.sha256=659544b68466d8af6ed85bdfd2f126903b9f36ebc6968dad034de0075b7de09c
lib/libepoxy.so.sha256=a50c278d336031d07a5e0ab43b7868496f71e56c7bf908daa0ada7bc32f0d5d8
lib/libvirglrenderer.so.sha256=af425d45e96916d36417f45157f78518189345ff4a5611d97f5ef3ae28a89c86
share/doc/COPYING-gl4es.sha256=69a3049c77abd88658f6ad7cf6a5b6ceb5cf03b80e60f7c4657d90322cfab7bd
share/doc/COPYING-libepoxy.sha256=8d5144666f9c4df9bbd69b8900086d5979259152a1060421cdcc0fb9061a1c12
share/doc/COPYING-virglrenderer.sha256=3b32caf16e2402c2aff2b716858713f3e1feded85c25e71bf829816ee5009402
Binary file not shown.
Binary file modified app/src/main/assets/runtime/arm64-v8a/virgl-host/lib/libepoxy.so
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import org.randomcoder.udroid.virgl.VirglHostBackend
import org.randomcoder.udroid.virgl.VirglHostSnapshot
import org.randomcoder.udroid.virgl.VirglProotLaunchProfile
import org.randomcoder.udroid.virgl.VenusGuestRuntimeInstaller
import org.randomcoder.udroid.virgl.parseZinkRequirements
import org.randomcoder.udroid.x11.X11ServerController
import java.io.BufferedReader
import java.io.File
Expand Down Expand Up @@ -816,6 +817,28 @@ class RuntimeSupervisorService : Service() {
)
}
}
if (request.configuration.graphicsProfile ==
DesktopGraphicsProfile.VENUS_EXPERIMENTAL
) {
runCatching {
logZinkRequirements(
rootfs = rootfs,
socketDirectory = socketDirectory,
launchProfile = launchProfile,
bootId = runtime.bootId,
)
}.onFailure { error ->
app.journal.append(
component = "graphics",
severity = "warning",
event = "zink_requirements_failed",
message =
error.message ?: "Could not run the Zink requirements probe",
bootId = runtime.bootId,
fields = mapOf("rootfs" to rootfs.name),
)
}
}
val launch =
ProotDesktopLaunchBuilder.create(
context = this,
Expand Down Expand Up @@ -1147,6 +1170,83 @@ class RuntimeSupervisorService : Service() {
}
}

private fun logZinkRequirements(
rootfs: File,
socketDirectory: File,
launchProfile: ProotLaunchProfile?,
bootId: String?,
) {
val profile = launchProfile as? VirglProotLaunchProfile ?: return
if (profile.backend != VirglHostBackend.VENUS || profile.venusGuestRuntime == null) return
val checker = "${VenusGuestRuntimeInstaller.GUEST_DIRECTORY}/bin/zink_check_requirements"
val launch =
ProotApplicationLaunchBuilder.create(
context = this,
runtime = ProotRuntimeInstaller.install(this),
rootfs = rootfs,
x11SocketDirectory = socketDirectory,
application =
LinuxApplication(
id = "udroid-zink-requirements",
name = "Zink requirements",
genericName = null,
comment = null,
executable = "/usr/bin/timeout",
arguments = listOf("5s", checker),
iconName = null,
iconPath = null,
desktopFilePath = "",
desktopFileGuestPath = "",
workingDirectory = "/root",
categories = emptyList(),
terminal = true,
),
launchProfile = profile,
)
app.journal.appendCommand(
component = "graphics",
command = launch.command,
bootId = bootId,
fields = mapOf("probe" to "zink_check_requirements", "rootfs" to rootfs.name),
)
val process =
ProcessBuilder(launch.command)
.directory(launch.workingDirectory)
.redirectErrorStream(true)
.apply {
environment().clear()
environment().putAll(launch.environment)
}.start()
val output = process.inputStream.bufferedReader().use { it.readText() }
val exitCode = process.waitFor()
val results = parseZinkRequirements(output)
val highest = results.lastOrNull { it.supported }
val summary =
when {
exitCode != 0 -> "Zink requirements probe failed with exit code $exitCode"
highest == null -> "Venus does not satisfy the minimum Zink profile"
else -> "Highest supported Zink profile: ${highest.label}"
}
app.journal.append(
component = "graphics",
severity = if (exitCode != 0 || highest == null) "warning" else "info",
event = "zink_requirements",
message = summary,
bootId = bootId,
fields = mapOf("report" to output.trim(), "rootfs" to rootfs.name),
)
results.forEach { result ->
app.journal.append(
component = "graphics",
severity = if (result.supported) "debug" else "info",
event = "zink_profile",
message = "${result.label}: ${if (result.supported) "supported" else "unsupported"}",
bootId = bootId,
fields = mapOf("profile" to result.profile),
)
}
}

private fun closeVirglHost() {
synchronized(virglHostLock) {
ownedVirglHosts.values.forEach(VirglHostController::close)
Expand Down
31 changes: 31 additions & 0 deletions app/src/main/java/org/randomcoder/udroid/ui/AppShell.kt
Original file line number Diff line number Diff line change
Expand Up @@ -959,6 +959,7 @@ private fun ManagementPane(
UdroidDestination.DEVICE ->
DevicePage(
capabilities = capabilities,
journalLines = journalLines,
onRefresh = onRefresh,
)
UdroidDestination.ABOUT ->
Expand Down Expand Up @@ -1316,9 +1317,11 @@ private fun updateStatusText(state: AppUpdateState): String =
@Composable
private fun DevicePage(
capabilities: List<CapabilityResult>,
journalLines: List<String>,
onRefresh: () -> Unit,
) {
val openDeveloperOptions = rememberDeveloperOptionsAction(onRefresh)
val zinkCapabilities = remember(journalLines) { zinkCompatibilityResults(journalLines) }
LazyColumn(
modifier =
Modifier
Expand Down Expand Up @@ -1348,6 +1351,34 @@ private fun DevicePage(
onOpenDeveloperOptions = openDeveloperOptions,
)
}
item {
UdroidSectionLabel(
text = "Venus and Zink",
modifier = Modifier.padding(top = 8.dp),
)
}
if (zinkCapabilities.isEmpty()) {
item {
CapabilityRow(
capability =
CapabilityResult(
name = "Zink through Venus",
status = CapabilityStatus.INFO,
detail =
"Not checked yet. Start a desktop with Venus, then refresh this page.",
required = false,
),
onOpenDeveloperOptions = openDeveloperOptions,
)
}
} else {
items(zinkCapabilities) { capability ->
CapabilityRow(
capability = capability,
onOpenDeveloperOptions = openDeveloperOptions,
)
}
}
item { Spacer(Modifier.height(16.dp)) }
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1207,7 +1207,8 @@ private fun GraphicsProfileSelector(
title = "Venus (experimental)",
detail =
"Accelerate Vulkan apps through Android’s driver. OpenGL stays on software " +
"rendering; X11 presentation uses Mesa’s copy path.",
"rendering; X11 presentation uses Mesa’s copy path. Zink profile results " +
"appear in Device compatibility after starting a desktop.",
selected = selected,
support = support,
onSelected = onSelected,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -593,7 +593,6 @@ private fun automaticManagedEnvironmentValues(
-> set("GALLIUM_DRIVER", "virpipe")
DesktopGraphicsProfile.VENUS_EXPERIMENTAL -> {
set("VN_DEBUG", "vtest")
set("MESA_VK_WSI_DEBUG", "sw")
}
DesktopGraphicsProfile.GFXSTREAM_EXPERIMENTAL -> Unit
}
Expand Down
63 changes: 60 additions & 3 deletions app/src/main/java/org/randomcoder/udroid/ui/SupervisorReport.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import org.randomcoder.udroid.runtime.CapabilityResult
import org.randomcoder.udroid.runtime.CapabilityStatus

internal data class DiagnosticLogEntry(
val raw: String,
Expand All @@ -14,6 +16,7 @@ internal data class DiagnosticLogEntry(
val event: String,
val message: String,
val fields: String,
val fieldValues: Map<String, String> = emptyMap(),
)

internal fun formatDiagnosticLogEntry(entry: DiagnosticLogEntry): String =
Expand Down Expand Up @@ -51,6 +54,10 @@ private fun parseDiagnosticLogEntry(line: String): DiagnosticLogEntry {
val payload = runCatching { Json.parseToJsonElement(line).jsonObject }.getOrNull()
?: return DiagnosticLogEntry(line, "", "raw", "journal", "event", line, "")
val fields = payload["fields"] as? JsonObject
val fieldValues =
fields
?.mapValues { (_, value) -> (value as? JsonPrimitive)?.content ?: value.toString() }
.orEmpty()
return DiagnosticLogEntry(
raw = line,
timestamp = payload.string("timestamp").replace('T', ' '),
Expand All @@ -59,16 +66,66 @@ private fun parseDiagnosticLogEntry(line: String): DiagnosticLogEntry {
event = payload.string("event").ifBlank { "event" },
message = payload.string("message").ifBlank { line },
fields =
fields
?.toSortedMap()
fieldValues
.toSortedMap()
?.entries
?.joinToString(" ") { (key, value) ->
"$key=${(value as? JsonPrimitive)?.content ?: value}"
"$key=$value"
}
.orEmpty(),
fieldValues = fieldValues,
)
}

internal fun zinkCompatibilityResults(
newestFirstJournalLines: List<String>,
): List<CapabilityResult> {
val entries = newestFirstJournalLines.map(::parseDiagnosticLogEntry)
val summaryIndex =
entries.indexOfFirst {
it.component == "graphics" &&
it.event in setOf("zink_requirements", "zink_requirements_failed")
}
if (summaryIndex < 0) return emptyList()

val summary = entries[summaryIndex]
val rootfs = summary.fieldValues["rootfs"]
return buildList {
add(
CapabilityResult(
name = "Zink through Venus",
status =
if (summary.severity.equals("warning", ignoreCase = true)) {
CapabilityStatus.WARNING
} else {
CapabilityStatus.PASS
},
detail = listOfNotNull(summary.message, rootfs?.let { "Linux system: $it" }).joinToString(" · "),
required = false,
),
)
entries
.take(summaryIndex)
.filter { it.component == "graphics" && it.event == "zink_profile" }
.asReversed()
.forEach { entry ->
val supported = entry.message.endsWith(": supported")
add(
CapabilityResult(
name = entry.message.substringBeforeLast(": "),
status = if (supported) CapabilityStatus.PASS else CapabilityStatus.FAIL,
detail =
listOfNotNull(
entry.fieldValues["profile"],
rootfs?.let { "Linux system: $it" },
).joinToString(" · "),
required = false,
),
)
}
}
}

private fun JsonObject.string(key: String): String = this[key]?.jsonPrimitive?.content.orEmpty()

internal fun buildSupervisorReport(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ internal data class VenusGuestRuntime(
)

internal object VirglHostRuntimeInstaller {
const val VERSION = "1.3.0-6"
const val VERSION = "1.3.0-7"
private val bundle =
VerifiedRuntimeAssetBundle(
name = "VirGL host",
Expand Down Expand Up @@ -92,6 +92,7 @@ internal object VenusGuestRuntimeInstaller {
version = VERSION,
entries =
listOf(
"bin/zink_check_requirements",
"lib/dri/zink_dri.so",
"lib/libEGL_mesa.so.0",
"lib/libGLX_mesa.so.0",
Expand All @@ -102,6 +103,7 @@ internal object VenusGuestRuntimeInstaller {
"share/glvnd/egl_vendor.d/50_mesa.json",
"share/vulkan/icd.d/virtio_icd.aarch64.json",
),
executables = setOf("bin/zink_check_requirements"),
metadataKeys = setOf("mesa_commit"),
)

Expand Down Expand Up @@ -129,3 +131,34 @@ internal object VenusGuestRuntimeInstaller {
return values["ID"] == "ubuntu" && values["VERSION_ID"] in setOf("22.04", "24.04")
}
}

internal data class ZinkRequirementResult(
val profile: String,
val supported: Boolean,
) {
val label: String =
profile
.removePrefix("VP_ZINK_")
.replace(Regex("^gl(\\d)(\\d)_"), "OpenGL $1.$2 ")
.replace('_', ' ')
}

internal fun parseZinkRequirements(output: String): List<ZinkRequirementResult> {
var profile: String? = null
return buildList {
output.lineSequence().forEach { line ->
when {
line.startsWith("Checking profile ") ->
profile = line.removePrefix("Checking profile ").trim()
line == "Supported" -> {
profile?.let { add(ZinkRequirementResult(it, true)) }
profile = null
}
line.startsWith("UNSUPPORTED") -> {
profile?.let { add(ZinkRequirementResult(it, false)) }
profile = null
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ internal data class VirglProotLaunchProfile(
"GALLIUM_DRIVER",
"-u",
"MESA_LOADER_DRIVER_OVERRIDE",
"-u",
"MESA_VK_WSI_DEBUG",
"VN_DEBUG=vtest",
"MESA_VK_WSI_DEBUG=sw",
) +
if (venusGuestRuntime != null) {
listOf(
Expand Down
Loading
Loading