emulator: malloc viewer

This commit is contained in:
minjaesong
2023-01-03 00:50:48 +09:00
parent 5cfbf2ac24
commit e0d1948bfc
7 changed files with 235 additions and 35 deletions

View File

@@ -0,0 +1,24 @@
package net.torvald.tsvm
import com.badlogic.gdx.graphics.g2d.SpriteBatch
/**
* Created by minjaesong on 2023-01-02.
*/
class DummyMenu(parent: VMEmuExecutable, x: Int, y: Int, w: Int, h: Int) : EmuMenu(parent, x, y, w, h) {
override fun show() {
}
override fun hide() {
}
override fun update() {
}
override fun render(batch: SpriteBatch) {
}
override fun dispose() {
}
}

View File

@@ -11,5 +11,6 @@ abstract class EmuMenu(val parent: VMEmuExecutable, val x: Int, val y: Int, val
abstract fun hide()
abstract fun update()
abstract fun render(batch: SpriteBatch)
abstract fun dispose()
}

View File

@@ -0,0 +1,123 @@
package net.torvald.tsvm
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.Pixmap
import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import net.torvald.tsvm.EmulatorGuiToolkit.Theme.COL_LAND
import net.torvald.tsvm.EmulatorGuiToolkit.Theme.COL_WELL
import net.torvald.tsvm.VMEmuExecutableWrapper.Companion.FONT
/**
* Created by minjaesong on 2023-01-02.
*/
class MMUMenu(parent: VMEmuExecutable, x: Int, y: Int, w: Int, h: Int) : EmuMenu(parent, x, y, w, h) {
override fun show() {
}
override fun hide() {
}
override fun update() {
}
override fun render(batch: SpriteBatch) {
batch.color = Color.WHITE
val vmInfo = parent.getCurrentlySelectedVM()
if (vmInfo == null) {
batch.inUse {
FONT.draw(batch, "Please select a VM", 12f, 11f + 0* FONT.H)
}
}
else vmInfo.let { (vm, vmName) ->
batch.inUse {
FONT.draw(batch, "Allocated size: ${vm.allocatedBlockCount * vm.MALLOC_UNIT}", 12f, 11f + 0* FONT.H)
}
drawAllocMap(batch, vm, 62f, 2f * FONT.H)
}
}
private val plotColset = intArrayOf(
0xea5545ff.toInt(), 0xf46a9bff.toInt(), 0xef9b20ff.toInt(), 0xedbf33ff.toInt(), 0xede15bff.toInt(), 0xbdcf32ff.toInt(),
0x87bc45ff.toInt(), 0x27aeefff.toInt(), 0xb33dc6ff.toInt(), 0xe60049ff.toInt(), 0x0bb4ffff.toInt(), 0x50e991ff.toInt(),
0xe6d800ff.toInt(), 0x9b19f5ff.toInt(), 0xffa300ff.toInt(), 0xdc0ab4ff.toInt(), 0xb3d4ffff.toInt(), 0x00bfa0ff.toInt(),
)
private val plotColours = plotColset.map { Color(it) }
private val memmapPixmap = Pixmap(512, 256, Pixmap.Format.RGBA8888)
private var mallocMap: List<Pair<Int, Int>> = listOf()
private fun drawAllocMap(batch: SpriteBatch, vm: VM, x: Float, y: Float) {
// clear the memmapPixmap
memmapPixmap.setColor(0)
memmapPixmap.fill()
// unallocated map as black
for (i in 0 until vm.memsize / vm.MALLOC_UNIT) {
paintPixel(i.toInt(), 255)
}
try {
// try to update the mallocMap
mallocMap = vm.javaClass.getDeclaredField("mallocSizes").let {
it.isAccessible = true
it.get(vm) as HashMap<Int, Int>
}.entries.map { it.key to it.value }.sortedBy { it.first }
}
catch (e: ConcurrentModificationException) { /* skip update for this frame */ }
// allocated map
mallocMap.forEachIndexed { index, (ptr, size) ->
for (i in 0 until size) {
paintPixel(ptr + i, plotColset[ptr % plotColset.size])
}
}
val memmapTex = Texture(memmapPixmap)
batch.inUse {
// draw allocation map
batch.color = COL_WELL
batch.fillRect(x, y, 512, 256)
batch.color = Color.WHITE
batch.draw(memmapTex, x, y)
// draw textual list
mallocMap.forEachIndexed { index, (ptr, size) ->
// hackishly draw textual list
if (index < 52) {
val xoff = 15f + 155f * (index / 13)
val yoff = 286f + ((index % 13) * FONT.H)
batch.color = plotColours[ptr % plotColset.size]
batch.fillRect(xoff, yoff + 1, 10, 10)
batch.color = Color.WHITE
FONT.draw(batch, " $size at $ptr", xoff, yoff)
}
}
}
memmapTex.dispose()
}
private fun paintPixel(index: Int, colour: Int) {
memmapPixmap.setColor(colour)
memmapPixmap.drawPixel(index / 256, index % 256)
}
override fun dispose() {
memmapPixmap.dispose()
}
}

View File

@@ -206,7 +206,10 @@ class ProfilesMenu(parent: VMEmuExecutable, x: Int, y: Int, w: Int, h: Int) : Em
}
}
private fun SpriteBatch.setColourBy(colourIfTrue: Color = EmulatorGuiToolkit.Theme.COL_ACTIVE3, colourIfFalse: Color = Color.WHITE, predicate: () -> Boolean) {
this.color = if (predicate()) colourIfTrue else colourIfFalse
override fun dispose() {
}
}
}
fun SpriteBatch.setColourBy(colourIfTrue: Color = EmulatorGuiToolkit.Theme.COL_ACTIVE3, colourIfFalse: Color = Color.WHITE, predicate: () -> Boolean) {
this.color = if (predicate()) colourIfTrue else colourIfFalse
}

View File

@@ -2,6 +2,7 @@ package net.torvald.tsvm
import com.badlogic.gdx.ApplicationAdapter
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.Input.Buttons
import com.badlogic.gdx.files.FileHandle
import com.badlogic.gdx.graphics.*
import com.badlogic.gdx.graphics.g2d.SpriteBatch
@@ -64,11 +65,11 @@ class VMEmuExecutable(val windowWidth: Int, val windowHeight: Int, var panelsX:
val watchdogs = hashMapOf<String, VMWatchdog>("TEVD_SYNC" to TEVD_SYNC)
private data class VMRunnerInfo(val vm: VM, val name: String)
data class VMRunnerInfo(val vm: VM, val name: String)
private val vms = arrayOfNulls<VMRunnerInfo>(this.panelsX * this.panelsY - 1) // index: # of the window where the reboot was requested
private var currentVMselection: Int? = 0 // null: emulator menu is selected
var currentVMselection: Int? = 0 // null: emulator menu is selected
lateinit var batch: SpriteBatch
lateinit var fbatch: FlippingSpriteBatch
@@ -117,6 +118,8 @@ class VMEmuExecutable(val windowWidth: Int, val windowHeight: Int, var panelsX:
vms[index] = VMRunnerInfo(vm, profileName)
}
internal fun getCurrentlySelectedVM(): VMRunnerInfo? = if (currentVMselection == null) null else vms[currentVMselection!!]
private fun writeProfilesToFile(outFile: FileHandle) {
val out = StringBuilder()
out.append('{')
@@ -376,6 +379,7 @@ class VMEmuExecutable(val windowWidth: Int, val windowHeight: Int, var panelsX:
override fun dispose() {
super.dispose()
tabs.forEach { it.dispose() }
batch.dispose()
fbatch.dispose()
fullscreenQuad.dispose()
@@ -390,9 +394,16 @@ class VMEmuExecutable(val windowWidth: Int, val windowHeight: Int, var panelsX:
private val menuTabX = windowWidth * (panelsX-1) + 2
private val menuTabY =windowHeight * (panelsY-1) + FONT.H + 2
private val menuTabs = listOf("Profiles", "Machine", "COMs", "Cards", "Setup")
private val menuTabs = listOf("Profiles", "MMU", "Machine", "COMs", "Cards", "Setup")
private val tabPos = (menuTabs + "").mapIndexed { index, _ -> 1 + menuTabs.subList(0, index).sumBy { it.length } + 2 * index }
private val tabs = listOf(ProfilesMenu(this, menuTabX, menuTabY, menuTabW, menuTabH))
private val tabs = listOf(
ProfilesMenu(this, menuTabX, menuTabY, menuTabW, menuTabH),
MMUMenu(this, menuTabX, menuTabY, menuTabW, menuTabH),
DummyMenu(this, menuTabX, menuTabY, menuTabW, menuTabH),
DummyMenu(this, menuTabX, menuTabY, menuTabW, menuTabH),
DummyMenu(this, menuTabX, menuTabY, menuTabW, menuTabH),
DummyMenu(this, menuTabX, menuTabY, menuTabW, menuTabH),
)
private var menuTabSel = 0
private var tabChangeRequested: Int? = 0 // null: not requested
@@ -423,7 +434,7 @@ class VMEmuExecutable(val windowWidth: Int, val windowHeight: Int, var panelsX:
FONT.draw(batch, menuTabs[k], textX, y)
}
else {
batch.color = EmulatorGuiToolkit.Theme.COL_TAB_NOT_SELECTED
batch.color = if (k % 2 == 0) EmulatorGuiToolkit.Theme.COL_TAB_NOT_SELECTED else EmulatorGuiToolkit.Theme.COL_TAB_NOT_SELECTED2
batch.fillRect(textX - FONT.W, y, FONT.W * (menuTabs[k].length + 2f), FONT.H.toFloat())
batch.color = EmulatorGuiToolkit.Theme.COL_ACTIVE2
@@ -447,7 +458,22 @@ class VMEmuExecutable(val windowWidth: Int, val windowHeight: Int, var panelsX:
private fun updateMenu() {
// update the tab
var tabSelected = -1
val x = (panelsX - 1) * windowWidth
val y = (panelsY - 1) * windowHeight
val mx = Gdx.input.x
val my = Gdx.input.y
if (Gdx.input.isButtonPressed(Buttons.LEFT) && my in y until y + FONT.H) {
for (k in menuTabs.indices) {
val textX = x + FONT.W * tabPos[k]
if (mx in textX - FONT.W until textX - FONT.W + FONT.W * (menuTabs[k].length + 2)) {
tabSelected = k
}
}
}
if (tabSelected >= 0 && tabSelected != menuTabSel) {
tabChangeRequested = tabSelected
}
// actually update the view within the tabs
tabs[menuTabSel].update()
@@ -584,11 +610,12 @@ object EmulatorGuiToolkit {
val COL_HIGHLIGHT = Color(0xe43380ff.toInt()) // magenta
val COL_DISABLED = Color(0xaaaaaaff.toInt())
val COL_TAB_NOT_SELECTED = Color(0x503cd4ff) // dark blue
val COL_TAB_NOT_SELECTED = Color(0x4d39cbff) // dark blue
val COL_TAB_NOT_SELECTED2 = Color(0x5949e0ff) // dark blue
val COL_LAND = Color(0x6b8ba2ff.toInt())
val COL_WELL = Color(0x374854ff.toInt())
val COL_WELL2 = Color(0x3e5261ff.toInt())
val COL_WELL2 = Color(0x3f5360ff.toInt())
}
}