This commit is contained in:
2026-09-25 13:24:56 +03:00
parent 45066a65a1
commit 987f9e5547
47 changed files with 4998 additions and 1 deletions
@@ -0,0 +1,90 @@
package pw.binom.rayneovm.glasses.shizuku
import android.graphics.SurfaceTexture
import android.os.IBinder
import android.util.Log
import android.view.Surface
import pw.binom.mercury.binocular.SurfaceTextureFrameSource
import pw.binom.mercury.shizuku.ShizukuVdBinder
import pw.binom.mercury.shizuku.ShizukuVdClient
/**
* Связка между VirtualDisplay на стороне очков и [FrameSource] для бинокулярного рендерера.
*
* Жизненный цикл:
* 1. Создаём SurfaceTexture в этом процессе (он будет жить в GL-контексте рендерера).
* 2. Оборачиваем её в Surface.
* 3. Получаем Shizuku Binder и создаём VirtualDisplay через [ShizukuVdBinder.createDisplay],
* передавая клиентский Surface. Display пишет кадры прямо в этот Surface → рендерер
* читает кадры из той же SurfaceTexture.
* 4. Возвращаем [FrameSource] рендереру — он получает кадры через onFrameAvailable.
* 5. При release — [ShizukuVdBinder.releaseDisplay] и SurfaceTexture.release().
*/
class VirtualDisplayFrameSource private constructor(
source: SurfaceTexture,
private val surface: Surface,
private val binder: IBinder,
private val displayId: Int,
width: Int,
height: Int,
) : SurfaceTextureFrameSource(source, width, height) {
override fun release() {
runCatching { ShizukuVdBinder.releaseDisplay(binder, displayId) }
runCatching { surface.release() }
super.release()
Log.i(TAG, "VirtualDisplayFrameSource released: displayId=$displayId")
}
companion object {
private const val TAG = "VirtualDisplayFrameSource"
/**
* Создаёт VirtualDisplay и возвращает FrameSource для рендерера.
*
* @param context Android context
* @param surfaceTexture GL-текстура, привязанная к GLSurfaceView (рендерер создаёт сам)
* @param serviceClass класс ShizukuVdService наследника (например, VmShizukuService::class.java)
* @param width виртуальный размер дисплея (для очков одного глаза — 640×480)
* @param height то же
* @param density плотность экрана (dpi)
*/
suspend fun acquire(
context: android.content.Context,
surfaceTexture: SurfaceTexture,
serviceClass: Class<*>,
width: Int = 640,
height: Int = 480,
density: Int = 160,
): VirtualDisplayFrameSource? {
val surface = Surface(surfaceTexture)
val client = ShizukuVdClient(context, serviceClass)
return try {
var binder: IBinder? = null
client.start { b -> binder = b }
val b = binder ?: run {
Log.w(TAG, "Shizuku binder not ready, returning null")
surface.release()
client.stop()
return null
}
val displayId = ShizukuVdBinder.createDisplay(
b, "VmDisplay", width, height, density, surface
)
if (displayId <= 0) {
Log.w(TAG, "createDisplay returned $displayId")
surface.release()
client.stop()
return null
}
Log.i(TAG, "Acquired VirtualDisplay id=$displayId ${width}x${height}")
VirtualDisplayFrameSource(surfaceTexture, surface, b, displayId, width, height)
} catch (t: Throwable) {
Log.e(TAG, "acquire failed", t)
runCatching { surface.release() }
client.stop()
null
}
}
}
}