Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lp2 jan 2024 take2 #15

Merged
merged 3 commits into from Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
91 changes: 88 additions & 3 deletions src/android/app/build.gradle.kts
Expand Up @@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.

import java.util.Properties
import android.databinding.tool.ext.capitalizeUS
import de.undercouch.gradle.tasks.download.Download

Expand All @@ -20,10 +21,71 @@ plugins {
* next 680 years.
*/
val autoVersion = (((System.currentTimeMillis() / 1000) - 1451606400) / 10).toInt()
val abiFilter = listOf("arm64-v8a", "x86_64")
val abiFilter = listOf("arm64-v8a") // val abiFilter = listOf("arm64-v8a", "x86_64") (removed x86_64 for Leia)

val downloadedJniLibsPath = "${buildDir}/downloadedJniLibs"

// Leia
val shouldAddDebugInfo: () -> Boolean = { true }
val useInAppFaceTracking: () -> Boolean = { false }

val localPropertiesFile = File(rootProject.projectDir, "local.properties")
val properties = Properties()
check(localPropertiesFile.exists())
localPropertiesFile.reader(charset = Charsets.UTF_8).use { reader ->
properties.load(reader)
}
//extra.set("cnsdkPath", properties.getProperty("cnsdk.dir").also {
// check(it != null) { "cnsdk.dir not set in local.properties" }
// if (!File(it).isAbsolute) {
// File(rootProject.projectDir, it).absolutePath
// } else {
// File(it).absolutePath
// }
//}.apply {
// println("CNSDK directory: $this")
//})
val cnsdkPath: String = properties.getProperty("cnsdk.dir").also {
check(it != null) { "cnsdk.dir not set in local.properties" }
if (!File(it).isAbsolute) {
File(rootProject.projectDir, it).absolutePath
} else {
File(it).absolutePath
}
}
println("CNSDK directory: $cnsdkPath")
val getCNSDKVersionName: () -> String = {
file(File(cnsdkPath, "VERSION.txt")).readText()
}
fun getCNSDKLibName(forceInApp: Boolean): String {
return if (useInAppFaceTracking() || forceInApp) {
"sdk-faceTrackingInApp-${getCNSDKVersionName()}.aar"
} else {
"sdk-faceTrackingService-${getCNSDKVersionName()}.aar"
}
}
tasks.register("copyNativeLibs") {
doLast {
copy {
from(zipTree("${cnsdkPath}/android/${getCNSDKLibName(false)}"))
include("jni/*/*.so")
into("${cnsdkPath}/lib")
}
}
}
fun DependencyHandler.addDependency(depFile: String) {
check(file(depFile).exists())
add("implementation", files(depFile))
}
fun DependencyHandler.addSdkDependency(forceInApp: Boolean) {
addDependency("${cnsdkPath}/android/${getCNSDKLibName(forceInApp)}")
if (useInAppFaceTracking() || forceInApp) {
addDependency("${cnsdkPath}/android/third_party/snpe-release.aar")
}
}



@Suppress("UnstableApiUsage")
android {
namespace = "org.citra.citra_emu"
Expand All @@ -40,13 +102,31 @@ android {
jvmTarget = "17"
}


if (shouldAddDebugInfo()) {
packaging {
jniLibs.keepDebugSymbols.add("**/*.so")

jniLibs {
keepDebugSymbols.add("**/*.so")
}
}

// ndk {
// debugSymbolLevel.set("FULL")
// }
}

androidResources {
generateLocaleConfig = true
}

packaging {
// This is necessary for libadrenotools custom driver loading
jniLibs.useLegacyPackaging = true

//resources.pickFirsts.add("**/libleiaSDK.so")
resources.pickFirsts.add("**/lib*blink.so")
}

buildFeatures {
Expand All @@ -62,7 +142,7 @@ android {
defaultConfig {
// TODO If this is ever modified, change application_id in strings.xml
applicationId = "org.citra.citra_emu"
minSdk = 28
minSdk = 29
targetSdk = 34
versionCode = autoVersion
versionName = getGitVersion()
Expand All @@ -77,7 +157,8 @@ android {
arguments(
"-DENABLE_QT=0", // Don't use QT
"-DENABLE_SDL2=0", // Don't use SDL
"-DANDROID_ARM_NEON=true" // cryptopp requires Neon to work
"-DANDROID_ARM_NEON=true", // cryptopp requires Neon to work
"-DCMAKE_OBJECT_PATH_MAX=1024"
)
}
}
Expand All @@ -98,6 +179,8 @@ android {
}
}



// Define build types, which are orthogonal to product flavors.
buildTypes {
// Signed by release key, allowing for upload to Play Store.
Expand Down Expand Up @@ -190,8 +273,10 @@ dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0")
implementation("androidx.preference:preference-ktx:1.2.1")
implementation("io.coil-kt:coil:2.2.2")
addSdkDependency(false)
}


// Download Vulkan Validation Layers from the KhronosGroup GitHub.
val downloadVulkanValidationLayers = tasks.register<Download>("downloadVulkanValidationLayers") {
src("https://github.com/KhronosGroup/Vulkan-ValidationLayers/releases/download/sdk-1.3.261.1/android-binaries-sdk-1.3.261.1-android.zip")
Expand Down
5 changes: 5 additions & 0 deletions src/android/app/proguard-rules.pro
Expand Up @@ -23,3 +23,8 @@
-dontwarn java.beans.Introspector
-dontwarn java.beans.VetoableChangeListener
-dontwarn java.beans.VetoableChangeSupport

-keep class com.leia.sdk.** { *; }
-keep class com.leia.core.** { *; }
-keep class com.leia.internal.** { *; }
-keep class com.leia.headtracking.** { *; }
78 changes: 78 additions & 0 deletions src/android/app/src/main/java/org/citra/citra_emu/LeiaHelper3D.kt
@@ -0,0 +1,78 @@
package org.citra.citra_emu

import android.app.Application
import android.content.Context
import android.graphics.SurfaceTexture
import android.util.AttributeSet
import android.util.Log
import android.view.Surface
import android.widget.Toast
import com.leia.core.LogLevel
import com.leia.sdk.LeiaSDK
import com.leia.sdk.views.InputViewsAsset
import com.leia.sdk.views.InterlacedSurfaceView
import org.citra.citra_emu.vendor.simongellis.leia.webxr.LeiaTextureRenderer
import org.citra.citra_emu.vendor.simongellis.leia.webxr.RendererImpl

class LeiaSurfaceView(context: Context, attrs: AttributeSet) : InterlacedSurfaceView(context, attrs) {
private val textureRenderer = LeiaTextureRenderer()
private val asset = InputViewsAsset(RendererImpl(textureRenderer))

// constructor(context: Context?) : this(context, null)
// constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)

fun init() {
Log.i("LeiaHelper3D: LeiaSurfaceView","init")
setViewAsset(asset)
}

fun setSurfaceListener(surfaceListener: LeiaHelper3D.SurfaceListener) {
val surfaceAsset = InputViewsAsset.createEmptySurfaceForVideo {
surfaceTexture: SurfaceTexture? ->
surfaceTexture?.setDefaultBufferSize(2560, 1600)
Log.d("SurfaceListener", "createEmptySurfaceForVideo -> calling onSurfaceChanged")
surfaceListener.onSurfaceChanged(Surface(surfaceTexture))
}
setViewAsset(surfaceAsset)
}

fun addTexture(texture: SurfaceTexture, transform: FloatArray) {
Log.d("SurfaceListener", "addTexture")
textureRenderer.addTexture(texture, transform)
}
}

class LeiaHelper3D {

fun interface SurfaceListener {
fun onSurfaceChanged(surface: Surface)
}

companion object {
fun init(application: Application) {
try {
val initArgs = LeiaSDK.InitArgs().apply {
platform.app = application
platform.logLevel = LogLevel.Trace
}
val leiaSDK = LeiaSDK.createSDK(initArgs)
leiaSDK.startFaceTracking(false)
} catch (e: Exception) {
Log.e("MainApp", "Failed to initialize LeiaSDK: ${e.message}")
Toast.makeText(application, "Failed to initialize LeiaSDK", Toast.LENGTH_SHORT).show()
}
}

fun update3dMode(surfaceView: InterlacedSurfaceView, enable3dMode: Boolean, hasFocus: Boolean) {
surfaceView.config.use { config ->
config.setNumTiles(if (enable3dMode) 2 else 1, 1)
}

val leiaSDK = LeiaSDK.getInstance()
leiaSDK?.let {
it.startFaceTracking(enable3dMode && hasFocus)
it.enableBacklight(enable3dMode && hasFocus)
}
}
}
}
Expand Up @@ -26,6 +26,7 @@ import androidx.core.view.WindowInsetsControllerCompat
import androidx.navigation.fragment.NavHostFragment
import androidx.preference.PreferenceManager
import org.citra.citra_emu.CitraApplication
import org.citra.citra_emu.LeiaHelper3D
import org.citra.citra_emu.NativeLibrary
import org.citra.citra_emu.R
import org.citra.citra_emu.camera.StillImageCameraHelper.OnFilePickerResult
Expand Down Expand Up @@ -60,6 +61,8 @@ class EmulationActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
ThemeUtil.setTheme(this)

LeiaHelper3D.init(application)

settingsViewModel.settings.loadSettings()

super.onCreate(savedInstanceState)
Expand Down
Expand Up @@ -17,8 +17,8 @@ enum class IntSetting(
CAMERA_OUTER_RIGHT_FLIP("camera_outer_right_flip", Settings.SECTION_CAMERA, 0),
GRAPHICS_API("graphics_api", Settings.SECTION_RENDERER, 1),
RESOLUTION_FACTOR("resolution_factor", Settings.SECTION_RENDERER, 1),
STEREOSCOPIC_3D_MODE("render_3d", Settings.SECTION_RENDERER, 0),
STEREOSCOPIC_3D_DEPTH("factor_3d", Settings.SECTION_RENDERER, 0),
STEREOSCOPIC_3D_MODE("render_3d", Settings.SECTION_RENDERER, 7),
STEREOSCOPIC_3D_DEPTH("factor_3d", Settings.SECTION_RENDERER, 50),
CARDBOARD_SCREEN_SIZE("cardboard_screen_size", Settings.SECTION_LAYOUT, 85),
CARDBOARD_X_SHIFT("cardboard_x_shift", Settings.SECTION_LAYOUT, 0),
CARDBOARD_Y_SHIFT("cardboard_y_shift", Settings.SECTION_LAYOUT, 0),
Expand Down
Expand Up @@ -59,14 +59,18 @@ import org.citra.citra_emu.features.settings.utils.SettingsFile
import org.citra.citra_emu.model.Game
import org.citra.citra_emu.utils.DirectoryInitialization
import org.citra.citra_emu.utils.DirectoryInitialization.DirectoryInitializationState
import org.citra.citra_emu.utils.EmulationLifecycleUtil
import org.citra.citra_emu.utils.EmulationMenuSettings
import org.citra.citra_emu.utils.FileUtil
import org.citra.citra_emu.utils.GameHelper
import org.citra.citra_emu.utils.GameIconUtils
import org.citra.citra_emu.utils.EmulationLifecycleUtil
import org.citra.citra_emu.utils.Log
import org.citra.citra_emu.utils.ViewUtils
import org.citra.citra_emu.viewmodel.EmulationViewModel
// -- leia --
import org.citra.citra_emu.LeiaHelper3D
import org.citra.citra_emu.LeiaSurfaceView;


class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.FrameCallback {
private val preferences: SharedPreferences
Expand All @@ -76,6 +80,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
private var perfStatsUpdater: Runnable? = null

private lateinit var emulationActivity: EmulationActivity
private lateinit var leiaSurfaceView: LeiaSurfaceView

private var _binding: FragmentEmulationBinding? = null
private val binding get() = _binding!!
Expand Down Expand Up @@ -164,7 +169,20 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
return
}

binding.surfaceEmulation.holder.addCallback(this)


val sL = LeiaHelper3D.SurfaceListener{ surface ->
Log.debug("SurfaceListener onSurfaceChanged called") // Log debug warning
emulationState.newSurface(surface)
}
binding.surfaceEmulation.setSurfaceListener(sL)

/*try{
binding.surfaceEmulation.holder.addCallback(this);
}catch(e: Exception){
Log.debug("SurfaceListener error: $e") // Log debug warning
}*/

binding.doneControlConfig.setOnClickListener {
binding.doneControlConfig.visibility = View.GONE
binding.surfaceInputOverlay.setIsInEditMode(false)
Expand Down Expand Up @@ -225,6 +243,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
binding.inGameMenu.setNavigationItemSelectedListener {
when (it.itemId) {
R.id.menu_emulation_pause -> {
LeiaHelper3D.update3dMode(binding.surfaceEmulation, !emulationState.isPaused, !emulationState.isPaused)
if (emulationState.isPaused) {
emulationState.unpause()
it.title = resources.getString(R.string.pause_emulation)
Expand Down Expand Up @@ -340,6 +359,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
return
}

LeiaHelper3D.update3dMode(binding.surfaceEmulation, false, false)

if (binding.drawerLayout.isOpen) {
binding.drawerLayout.close()
} else {
Expand Down Expand Up @@ -422,6 +443,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram

override fun onResume() {
super.onResume()
LeiaHelper3D.update3dMode(binding.surfaceEmulation, true, true)
Choreographer.getInstance().postFrameCallback(this)
if (NativeLibrary.isRunning()) {
NativeLibrary.unPauseEmulation()
Expand All @@ -436,6 +458,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
}

override fun onPause() {
LeiaHelper3D.update3dMode(binding.surfaceEmulation, false, false)
if (NativeLibrary.isRunning()) {
emulationState.pause()
}
Expand Down Expand Up @@ -856,8 +879,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
}

override fun surfaceCreated(holder: SurfaceHolder) {
// We purposely don't do anything here.
// All work is done in surfaceChanged, which we are guaranteed to get even for surface creation.
Log.debug("[EmulationFragment] Surface Created")
}

override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
Expand All @@ -867,6 +889,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram

override fun surfaceDestroyed(holder: SurfaceHolder) {
emulationState.clearSurface()
LeiaHelper3D.update3dMode(binding.surfaceEmulation, false, false)
}

override fun doFrame(frameTimeNanos: Long) {
Expand Down
@@ -0,0 +1,22 @@
package org.citra.citra_emu.vendor.simongellis.leia.webxr

import android.content.Context
import android.graphics.SurfaceTexture
import android.util.AttributeSet
import android.util.Log
import com.leia.sdk.views.InputViewsAsset
import com.leia.sdk.views.InterlacedSurfaceView

class LeiaSurfaceView(context: Context, attrs: AttributeSet) : InterlacedSurfaceView(context, attrs) {
private val textureRenderer = LeiaTextureRenderer()
private val asset = InputViewsAsset(RendererImpl(textureRenderer))

init {
Log.i("LeiaSurfaceView", "init")
setViewAsset(asset)
}

fun addTexture(texture: SurfaceTexture, transform: FloatArray) {
textureRenderer.addTexture(texture, transform)
}
}