vmgui now exits on exit

This commit is contained in:
minjaesong
2024-08-13 23:52:36 +09:00
parent 6325684610
commit adae75ab69
3 changed files with 75 additions and 57 deletions

View File

@@ -16,46 +16,46 @@ private class RenderRunnable(val playhead: AudioAdapter.Playhead) : Runnable {
private fun printdbg(msg: Any) { private fun printdbg(msg: Any) {
if (AudioAdapter.DBGPRN) println("[AudioAdapter] $msg") if (AudioAdapter.DBGPRN) println("[AudioAdapter] $msg")
} }
@Volatile private var exit = false
override fun run() { override fun run() {
while (!exit) { while (!Thread.currentThread().isInterrupted) {
if (playhead.isPcmMode) { try {
if (playhead.isPcmMode) {
val writeQueue = playhead.pcmQueue val writeQueue = playhead.pcmQueue
if (playhead.isPlaying && writeQueue.notEmpty()) { if (playhead.isPlaying && writeQueue.notEmpty()) {
printdbg("Taking samples from queue (queue size: ${writeQueue.size}/${playhead.getPcmQueueCapacity()})") printdbg("Taking samples from queue (queue size: ${writeQueue.size}/${playhead.getPcmQueueCapacity()})")
val samples = writeQueue.removeFirst() val samples = writeQueue.removeFirst()
playhead.position = writeQueue.size playhead.position = writeQueue.size
// printdbg("P${playhead.index+1} Vol ${playhead.masterVolume}; LpP ${playhead.pcmUploadLength}; start playback...") // printdbg("P${playhead.index+1} Vol ${playhead.masterVolume}; LpP ${playhead.pcmUploadLength}; start playback...")
// printdbg(""+(0..42).joinToString { String.format("%.2f", samples[it]) }) // printdbg(""+(0..42).joinToString { String.format("%.2f", samples[it]) })
playhead.audioDevice.writeSamplesUI8(samples, 0, samples.size) playhead.audioDevice.writeSamplesUI8(samples, 0, samples.size)
// printdbg("P${playhead.index+1} go back to spinning") // printdbg("P${playhead.index+1} go back to spinning")
Thread.sleep(12) Thread.sleep(12)
} }
else if (playhead.isPlaying && writeQueue.isEmpty) { else if (playhead.isPlaying && writeQueue.isEmpty) {
printdbg("!! QUEUE EXHAUSTED !! QUEUE EXHAUSTED !! QUEUE EXHAUSTED !! QUEUE EXHAUSTED !! QUEUE EXHAUSTED !! QUEUE EXHAUSTED ") printdbg("!! QUEUE EXHAUSTED !! QUEUE EXHAUSTED !! QUEUE EXHAUSTED !! QUEUE EXHAUSTED !! QUEUE EXHAUSTED !! QUEUE EXHAUSTED ")
// TODO: wait for 1-2 seconds then finally stop the device // TODO: wait for 1-2 seconds then finally stop the device
// playhead.audioDevice.stop() // playhead.audioDevice.stop()
Thread.sleep(12) Thread.sleep(12)
}
} }
Thread.sleep(1)
}
catch (_: InterruptedException) {
Thread.currentThread().interrupt()
} }
Thread.sleep(1)
} }
playhead.audioDevice.dispose()
}
fun stop() {
exit = true
} }
} }
@@ -63,35 +63,40 @@ private class WriteQueueingRunnable(val playhead: AudioAdapter.Playhead, val pcm
private fun printdbg(msg: Any) { private fun printdbg(msg: Any) {
if (AudioAdapter.DBGPRN) println("[AudioAdapter] $msg") if (AudioAdapter.DBGPRN) println("[AudioAdapter] $msg")
} }
@Volatile private var exit = false
override fun run() { override fun run() {
while (!exit) { while (!Thread.currentThread().isInterrupted) {
try {
playhead.let {
if (/*it.pcmQueue.size < it.getPcmQueueCapacity() &&*/ it.pcmUpload && it.pcmUploadLength > 0) {
printdbg("Downloading samples ${it.pcmUploadLength}")
playhead.let { val samples = ByteArray(it.pcmUploadLength)
if (/*it.pcmQueue.size < it.getPcmQueueCapacity() &&*/ it.pcmUpload && it.pcmUploadLength > 0) { UnsafeHelper.memcpyRaw(
printdbg("Downloading samples ${it.pcmUploadLength}") null,
pcmBin.ptr,
samples,
UnsafeHelper.getArrayOffset(samples),
it.pcmUploadLength.toLong()
)
it.pcmQueue.addLast(samples)
val samples = ByteArray(it.pcmUploadLength) it.pcmUploadLength = 0
UnsafeHelper.memcpyRaw(null, pcmBin.ptr, samples, UnsafeHelper.getArrayOffset(samples), it.pcmUploadLength.toLong()) it.position = it.pcmQueue.size
it.pcmQueue.addLast(samples) Thread.sleep(6)
}
it.pcmUploadLength = 0 else if (it.pcmUpload) {
it.position = it.pcmQueue.size
Thread.sleep(6)
}
else if (it.pcmUpload) {
// printdbg("Rejecting samples (queueSize: ${it.pcmQueue.size}, uploadLength: ${it.pcmUploadLength})") // printdbg("Rejecting samples (queueSize: ${it.pcmQueue.size}, uploadLength: ${it.pcmUploadLength})")
Thread.sleep(6) Thread.sleep(6)
}
} }
}
Thread.sleep(1) Thread.sleep(1)
}
catch (_: InterruptedException) {
Thread.currentThread().interrupt()
}
} }
} }
fun stop() {
exit = true
}
} }
/** /**
@@ -125,6 +130,9 @@ class AudioAdapter(val vm: VM) : PeriBase(VM.PERITYPE_SOUND) {
private val writeQueueingRunnables: Array<WriteQueueingRunnable> private val writeQueueingRunnables: Array<WriteQueueingRunnable>
private val writeQueueingThreads: Array<Thread> private val writeQueueingThreads: Array<Thread>
private val renderThreadGroup = ThreadGroup("AudioRenderThreadGroup")
private val writeQueueingGroup = ThreadGroup("AudioQriteQueueingThreadGroup")
private val threadExceptionHandler = Thread.UncaughtExceptionHandler { thread, throwable -> private val threadExceptionHandler = Thread.UncaughtExceptionHandler { thread, throwable ->
throwable.printStackTrace() throwable.printStackTrace()
} }
@@ -163,9 +171,9 @@ class AudioAdapter(val vm: VM) : PeriBase(VM.PERITYPE_SOUND) {
renderRunnables = Array(4) { RenderRunnable(playheads[it]) } renderRunnables = Array(4) { RenderRunnable(playheads[it]) }
renderThreads = Array(4) { Thread(renderRunnables[it], "AudioRenderHead${it+1}!$hash") } renderThreads = Array(4) { Thread(renderThreadGroup, renderRunnables[it], "AudioRenderHead${it+1}!$hash") }
writeQueueingRunnables = Array(4) { WriteQueueingRunnable(playheads[it], pcmBin) } writeQueueingRunnables = Array(4) { WriteQueueingRunnable(playheads[it], pcmBin) }
writeQueueingThreads = Array(4) { Thread(writeQueueingRunnables[it], "AudioQueueingHead${it+1}!$hash") } writeQueueingThreads = Array(4) { Thread(writeQueueingGroup, writeQueueingRunnables[it], "AudioQueueingHead${it+1}!$hash") }
// printdbg("AudioAdapter latency: ${audioDevice.latency}") // printdbg("AudioAdapter latency: ${audioDevice.latency}")
renderThreads.forEach { it.uncaughtExceptionHandler = threadExceptionHandler; it.start() } renderThreads.forEach { it.uncaughtExceptionHandler = threadExceptionHandler; it.start() }
@@ -266,17 +274,23 @@ class AudioAdapter(val vm: VM) : PeriBase(VM.PERITYPE_SOUND) {
} }
} }
private var disposed = false
override fun dispose() { override fun dispose() {
System.err.println("Dispose AudioAdapter") if (!disposed) {
renderRunnables.forEach { it.stop() } disposed = true
renderThreads.forEach { it.interrupt() } System.err.println("Dispose AudioAdapter")
writeQueueingRunnables.forEach { it.stop() } renderThreadGroup.interrupt()
writeQueueingThreads.forEach { it.interrupt() } writeQueueingGroup.interrupt()
playheads.forEach { it.dispose() } playheads.forEach { it.dispose() }
sampleBin.destroy() sampleBin.destroy()
pcmBin.destroy() pcmBin.destroy()
mediaFrameBin.destroy() mediaFrameBin.destroy()
mediaDecodedBin.destroy() mediaDecodedBin.destroy()
}
else {
System.err.println("AudioAdapter already disposed")
}
} }
override fun getVM(): VM { override fun getVM(): VM {
@@ -435,7 +449,7 @@ class AudioAdapter(val vm: VM) : PeriBase(VM.PERITYPE_SOUND) {
fun dispose() { fun dispose() {
// audioDevice.dispose() is called by RenderRunnable.stop() // audioDevice.dispose() is called by RenderRunnable.stop()
System.err.println("AudioDevice dispose ${parent.renderThreads[index]}") System.err.println("AudioDevice dispose ${parent.renderThreads[index]}")
try { audioDevice.dispose() } catch (e: GdxRuntimeException) { println(" "+ e.message) } try { audioDevice.dispose() } catch (e: GdxRuntimeException) { System.err.println(" "+ e.message) }
} }
companion object { companion object {

View File

@@ -54,7 +54,7 @@ class VMEmuExecutableWrapper(val windowWidth: Int, val windowHeight: Int, var pa
// println("App Dispose") // println("App Dispose")
executable.dispose() executable.dispose()
SQTEX.dispose() SQTEX.dispose()
exitProcess(1) exitProcess(0)
} }
} }

View File

@@ -14,6 +14,7 @@ import java.util.*
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicLong import java.util.concurrent.atomic.AtomicLong
import kotlin.coroutines.* import kotlin.coroutines.*
import kotlin.system.exitProcess
class EmulInstance( class EmulInstance(
@@ -320,6 +321,9 @@ class VMGUI(val loaderInfo: EmulInstance, val viewportWidth: Int, val viewportHe
crtShader.dispose() crtShader.dispose()
gpuFBO.dispose() gpuFBO.dispose()
vm.dispose() vm.dispose()
System.err.println("VM disposed: ${vm.id}")
exitProcess(0)
} }
companion object { companion object {