mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-11-11 02:51:10 +00:00
fix(vkbridge): Mali memory sharing via dma-heap; debuggable fork builds with a server override
Tablet run 2: dma-heap and AHB imports both land in type 1 (HOST_CACHED, not COHERENT) and pass the sharing test without any flush (uncached heap pages), so the self-test now tries each type without flushes first and counts a pass as coherent; the client reports such a type HOST_COHERENT (and not HOST_CACHED for dma-heap). On the SM-X826B: memory sharing = dmaheap. Also: release builds of this fork are debuggable (run-as reaches the session logs), and a debuggable build loads files/vkbridge/dev/libvkbridge_jni.so when present, so a rebuilt server can be tried without a new APK. Self-test switches VKBRIDGE_SELFTEST_NOFLUSH, VKBRIDGE_AHB_RARELY, VKBRIDGE_DMAHEAP_CACHED. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ce34349ffb
commit
6b82334145
5 files changed
+55
-8
No files matched your search
@@ -142,6 +142,9 @@ android {
|
||||
release {
|
||||
minifyEnabled false
|
||||
signingConfig signingConfigs.testkey
|
||||
// Mali bridge development fork: debuggable so `adb shell run-as` reaches the session
|
||||
// logs and VkBridgeNative's development override (-Pdroiddeck.notDebuggable to drop).
|
||||
debuggable !project.hasProperty('droiddeck.notDebuggable')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -186,6 +186,7 @@ static int dmaheap_fd(void)
|
||||
pthread_mutex_lock(&lock);
|
||||
if (fd == -2) {
|
||||
const char *names[] = {"/dev/dma_heap/system-uncached", "/dev/dma_heap/system"};
|
||||
if (getenv("VKBRIDGE_DMAHEAP_CACHED")) names[0] = "/dev/dma_heap/system";
|
||||
fd = -1;
|
||||
for (int i = 0; i < 2 && fd < 0; i++) {
|
||||
fd = open(names[i], O_RDONLY | O_CLOEXEC);
|
||||
@@ -346,8 +347,9 @@ static VkResult alloc_shared(const vkb_dispatch *dt, VkDevice dev, uint32_t s, c
|
||||
r = VK_ERROR_OUT_OF_DEVICE_MEMORY;
|
||||
break;
|
||||
}
|
||||
vkb_ahb_desc d = {(uint32_t)sz, 1, 1, AHB_FORMAT_BLOB,
|
||||
AHB_USAGE_CPU_READ_OFTEN | AHB_USAGE_CPU_WRITE_OFTEN | AHB_USAGE_GPU_DATA_BUFFER, 0, 0, 0};
|
||||
/* CPU usage decides how gralloc caches the pages; VKBRIDGE_AHB_RARELY=1 asks for uncached. */
|
||||
uint64_t cpu = getenv("VKBRIDGE_AHB_RARELY") ? (2ull | (2ull << 4)) : (AHB_USAGE_CPU_READ_OFTEN | AHB_USAGE_CPU_WRITE_OFTEN);
|
||||
vkb_ahb_desc d = {(uint32_t)sz, 1, 1, AHB_FORMAT_BLOB, cpu | AHB_USAGE_GPU_DATA_BUFFER, 0, 0, 0};
|
||||
struct AHardwareBuffer *ahb = NULL;
|
||||
int ar = p_AHardwareBuffer_allocate(&d, &ahb);
|
||||
if (ar != 0 || !ahb) {
|
||||
@@ -549,7 +551,25 @@ static int submit_and_wait(selftest *st, VkCommandBuffer cb)
|
||||
|
||||
/* One allocation of `type` with strategy `s`, checked from both sides. 1 = shared and coherent
|
||||
* (no flush needed), 2 = shared when flushed, 0 = not shared. */
|
||||
static int test_type_mode(selftest *st, uint32_t s, uint32_t type, int no_flush);
|
||||
|
||||
/* Without flushes first: imported pages from an uncached heap are coherent in practice even where
|
||||
* the driver's type does not say HOST_COHERENT (Mali-G720: dma-heap imports land in type 1,
|
||||
* HOST_CACHED without COHERENT, and pass with no flush). Only if that fails, with flushes. */
|
||||
static int test_type(selftest *st, uint32_t s, uint32_t type)
|
||||
{
|
||||
int coherent_flag = (st->mp.memoryTypes[type].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0;
|
||||
if (!coherent_flag && !getenv("VKBRIDGE_SELFTEST_NOFLUSH")) {
|
||||
int r = test_type_mode(st, s, type, 1);
|
||||
if (r) {
|
||||
VKB_INFO(" %s, type %u: coherent in practice (no flushes needed)", vkb_mem_strategy_name(s), type);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return test_type_mode(st, s, type, 0);
|
||||
}
|
||||
|
||||
static int test_type_mode(selftest *st, uint32_t s, uint32_t type, int no_flush)
|
||||
{
|
||||
const vkb_dispatch *dt = &st->dt;
|
||||
int result = 0;
|
||||
@@ -603,6 +623,8 @@ static int test_type(selftest *st, uint32_t s, uint32_t type)
|
||||
goto out;
|
||||
}
|
||||
int coherent = (st->mp.memoryTypes[type].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0;
|
||||
/* VKBRIDGE_SELFTEST_NOFLUSH=1 forces it for every type. */
|
||||
if (no_flush || getenv("VKBRIDGE_SELFTEST_NOFLUSH")) coherent = 1;
|
||||
VkMappedMemoryRange whole = {VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, NULL, m->mem, 0, VK_WHOLE_SIZE};
|
||||
|
||||
/* 1: the two CPU mappings are the same pages. */
|
||||
|
||||
@@ -34,7 +34,7 @@ class VkBridgeComponent(private val socket: File, private val logFile: File) : S
|
||||
socket.parentFile?.mkdirs()
|
||||
// Pipeline cache kept across sessions (Mali recompiles everything in a new process otherwise).
|
||||
val cacheDir = File(app().cacheDir, "vkbridge-pipelines").apply { mkdirs() }
|
||||
if (VkBridgeNative.start(socket, logFile, cacheDir)) {
|
||||
if (VkBridgeNative.start(app(), socket, logFile, cacheDir)) {
|
||||
Log.i(TAG, "server ready in the app's process at $socket")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.droiddeck.launcher.gpu
|
||||
|
||||
import android.content.Context
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.util.Log
|
||||
import java.io.File
|
||||
|
||||
@@ -15,14 +17,31 @@ import java.io.File
|
||||
object VkBridgeNative {
|
||||
private const val TAG = "VkBridge"
|
||||
|
||||
private val loaded: Boolean by lazy {
|
||||
try {
|
||||
System.loadLibrary("vkbridge_jni")
|
||||
@Volatile private var loaded: Boolean? = null
|
||||
|
||||
/**
|
||||
* The packaged library, or - in a debuggable build only - files/vkbridge/dev/libvkbridge_jni.so
|
||||
* when present, so a rebuilt server can be tried with `adb push` + `run-as cp` and an app
|
||||
* restart instead of a new APK (the app targets SDK 28 and may load code from its files).
|
||||
*/
|
||||
private fun load(context: Context): Boolean {
|
||||
loaded?.let { return it }
|
||||
val ok = try {
|
||||
val dev = File(context.filesDir, "vkbridge/dev/libvkbridge_jni.so")
|
||||
val debuggable = context.applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE != 0
|
||||
if (debuggable && dev.isFile) {
|
||||
Log.w(TAG, "in-app server from the development override $dev")
|
||||
System.load(dev.absolutePath)
|
||||
} else {
|
||||
System.loadLibrary("vkbridge_jni")
|
||||
}
|
||||
true
|
||||
} catch (e: Throwable) {
|
||||
Log.w(TAG, "in-app server unavailable: $e")
|
||||
false
|
||||
}
|
||||
loaded = ok
|
||||
return ok
|
||||
}
|
||||
|
||||
/** Whether the in-app server is serving (its socket must then be left alone). */
|
||||
@@ -30,8 +49,8 @@ object VkBridgeNative {
|
||||
private set
|
||||
|
||||
/** Starts the server, or points its log at [log] when it already runs; false when it cannot serve. */
|
||||
fun start(socket: File, log: File, cacheDir: File): Boolean {
|
||||
if (!loaded) return false
|
||||
fun start(context: Context, socket: File, log: File, cacheDir: File): Boolean {
|
||||
if (!load(context)) return false
|
||||
val ok = try {
|
||||
nativeStart(socket.absolutePath, log.absolutePath, cacheDir.absolutePath) == 1
|
||||
} catch (e: Throwable) {
|
||||
|
||||
@@ -71,6 +71,9 @@ static void build_memory_model(vkb_physdev *pd)
|
||||
if (!(share & (1u << t))) continue; /* host-visible but not shareable: not offered */
|
||||
VkMemoryPropertyFlags cf = f;
|
||||
if (!(pd->info.coherent_types & (1u << t))) cf &= ~VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||
else cf |= VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; /* coherent in practice (the self-test says so) */
|
||||
/* dma-heap pages come from the uncached heap: not what an app asking for cached reads wants. */
|
||||
if (pd->info.strategy == VKB_MEM_DMAHEAP) cf &= ~VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
|
||||
if (uma) {
|
||||
cf &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
if (host_heap == UINT32_MAX && c->memoryHeapCount < VK_MAX_MEMORY_HEAPS) {
|
||||
|
||||
Reference in new issue
Block a user