painting screen on lua's side

This commit is contained in:
minjaesong
2020-04-16 10:18:45 +09:00
parent e35dad635f
commit 373bfdb11e
6 changed files with 131 additions and 39 deletions

View File

@@ -114,6 +114,11 @@ internal class UnsafePtr(pointer: Long, allocSize: Long) {
return UnsafeHelper.unsafe.getInt(ptr + index) return UnsafeHelper.unsafe.getInt(ptr + index)
} }
fun getShort(index: Long): Short {
checkNullPtr(index)
return UnsafeHelper.unsafe.getShort(ptr + index)
}
fun setFloat(index: Long, value: Float) { fun setFloat(index: Long, value: Float) {
checkNullPtr(index) checkNullPtr(index)
UnsafeHelper.unsafe.putFloat(ptr + index, value) UnsafeHelper.unsafe.putFloat(ptr + index, value)
@@ -124,6 +129,11 @@ internal class UnsafePtr(pointer: Long, allocSize: Long) {
UnsafeHelper.unsafe.putInt(ptr + index, value) UnsafeHelper.unsafe.putInt(ptr + index, value)
} }
fun setShort(index: Long, value: Short) {
checkNullPtr(index)
UnsafeHelper.unsafe.putShort(ptr + index, value)
}
fun fillWith(byte: Byte) { fun fillWith(byte: Byte) {
UnsafeHelper.unsafe.setMemory(ptr, size, byte) UnsafeHelper.unsafe.setMemory(ptr, size, byte)
} }

View File

@@ -7,6 +7,7 @@ import net.torvald.tsvm.firmware.Firmware.Companion.toLuaValue
import net.torvald.tsvm.peripheral.IOSpace import net.torvald.tsvm.peripheral.IOSpace
import net.torvald.tsvm.peripheral.PeriBase import net.torvald.tsvm.peripheral.PeriBase
import org.luaj.vm2.LuaValue import org.luaj.vm2.LuaValue
import kotlin.random.Random
/** /**
* 1 byte = 2 pixels * 1 byte = 2 pixels
@@ -51,6 +52,8 @@ class VM(
_memsize: Int _memsize: Int
) { ) {
val id = java.util.Random().nextInt()
val memsize = minOf(USER_SPACE_SIZE, _memsize.toLong()) val memsize = minOf(USER_SPACE_SIZE, _memsize.toLong())
internal val usermem = UnsafeHelper.allocate(memsize) internal val usermem = UnsafeHelper.allocate(memsize)
@@ -65,6 +68,8 @@ class VM(
MMIO_SIZE.toInt() - 256, MMIO_SIZE.toInt() - 256,
64 64
) )
println("[VM] Creating new VM with ID of $id, memesize $memsize")
} }

View File

@@ -11,12 +11,13 @@ import kotlin.math.roundToInt
class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter() { class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter() {
val vm = VM(8192) val vm = VM(8192)
val vmLua = VMLuaAdapter(vm)
lateinit var gpu: GraphicsAdapter lateinit var gpu: GraphicsAdapter
lateinit var batch: SpriteBatch lateinit var batch: SpriteBatch
lateinit var camera: OrthographicCamera lateinit var camera: OrthographicCamera
lateinit var vmRunner: VMRunner
override fun create() { override fun create() {
super.create() super.create()
@@ -37,9 +38,11 @@ class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter()
batch.projectionMatrix = camera.combined batch.projectionMatrix = camera.combined
Gdx.gl20.glViewport(0, 0, appConfig.width, appConfig.height) Gdx.gl20.glViewport(0, 0, appConfig.width, appConfig.height)
vmRunner = VMRunnerFactory(vm, "lua")
// TEST LUA PRG // TEST LUA PRG
//vmLua.lua.load(gpuTestPalette).call() //vmLua.lua.load(gpuTestPalette).call()
vmRunner.executeCommand(gpuTestPalette)
} }
private var updateAkku = 0.0 private var updateAkku = 0.0
@@ -60,18 +63,19 @@ class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter()
i += 1 i += 1
} }
renderGame() renderGame(dt)
} }
private fun updateGame(delta: Float) { private fun updateGame(delta: Float) {
paintTestPalette()
} }
private fun paintTestPalette() { private fun paintTestPalette() {
val peripheralSlot = vm.findPeribyType(VM.PERITYPE_GRAPHICS)!! val peripheralSlot = vm.findPeribyType(VM.PERITYPE_GRAPHICS)!!
val hwoff = VM.HW_RESERVE_SIZE * peripheralSlot val hwoff = VM.HW_RESERVE_SIZE * peripheralSlot
for (y in 0 until 360) { /*for (y in 0 until 360) {
for (x in 0 until GraphicsAdapter.WIDTH) { for (x in 0 until GraphicsAdapter.WIDTH) {
val palnum = 20 * (y / 30) + (x / (GraphicsAdapter.WIDTH / 20)) val palnum = 20 * (y / 30) + (x / (GraphicsAdapter.WIDTH / 20))
vm.poke(-(y.toLong() * GraphicsAdapter.WIDTH + x + 1) - hwoff, palnum.toByte()) vm.poke(-(y.toLong() * GraphicsAdapter.WIDTH + x + 1) - hwoff, palnum.toByte())
@@ -83,47 +87,57 @@ class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter()
val palnum = 240 + (x / 35) val palnum = 240 + (x / 35)
vm.poke(-(y.toLong() * GraphicsAdapter.WIDTH + x + 1) - hwoff, palnum.toByte()) vm.poke(-(y.toLong() * GraphicsAdapter.WIDTH + x + 1) - hwoff, palnum.toByte())
} }
} }*/
//vm.poke(-262143L - hwoff, Math.random().times(255.0).toByte()) //vm.poke(-262143L - hwoff, Math.random().times(255.0).toByte())
//vm.poke(-262144L - hwoff, Math.random().times(255.0).toByte()) //vm.poke(-262144L - hwoff, Math.random().times(255.0).toByte())
for (k in 0 until 2240) { for (k in 0 until 2240) {
// text foreground // text foreground
vm.poke(-(254912 + k + 1) - hwoff, (Math.random().times(255f).roundToInt()).toByte()) // white vm.poke(-(254912 + k + 1) - hwoff, -2) // white
// text background // text background
vm.poke(-(254912 + 2240 + k + 1) - hwoff, (Math.random().times(255f).roundToInt()).toByte()) // transparent vm.poke(-(254912 + 2240 + k + 1) - hwoff, -1) // transparent
// texts // texts
vm.poke(-(254912 + 2240*2 + k + 1) - hwoff, (Math.random().times(255f).roundToInt()).toByte()) vm.poke(-(254912 + 2240*2 + k + 1) - hwoff, if (k == 0) 0x30 else 0x40)
} }
} }
private val gpuTestPalette = """ private val gpuTestPalette = """
local vm = require("rawmem") local vm = require("rawmem")
local w = 560 local w = 560
local h = 448 local h = 448
local hwoff = 1048576 local hwoff = 1048576
for y = 0, 359 do while true do
for x = 0, w - 1 do local tstart = os.clock()
palnum = 20 * int(y / 30) + int(x / 28)
vm.poke(-(y * w + x + 1) - hwoff, palnum) for y = 0, 359 do
end for x = 0, w - 1 do
palnum = 20 * int(y / 30) + int(x / 28)
vm.poke(-(y * w + x + 1) - hwoff, palnum)
end end
end
for y = 360, h - 1 do for y = 360, h - 1 do
for x = 0, w - 1 do for x = 0, w - 1 do
palnum = 240 + int(x / 35) palnum = 240 + int(x / 35)
vm.poke(-(y * w + x + 1) - hwoff, palnum) vm.poke(-(y * w + x + 1) - hwoff, palnum)
end
end end
end
vm.poke(-262143 - hwoff, math.floor(math.random() * 255.0)) for k = 0, 2239 do
vm.poke(-262144 - hwoff, math.floor(math.random() * 255.0)) vm.poke(-(254912 + k + 1) - hwoff, 254)
vm.poke(-(254912 + 2240 + k + 1) - hwoff, 255)
vm.poke(-(254912 + 2240*2 + k + 1) - hwoff, math.floor(math.random() * 255.0))
end
local tend = os.clock()
print("Apparent FPS: "..tostring(1.0 / (tend - tstart)))
end
""".trimIndent() """.trimIndent()
private fun renderGame() { private fun renderGame(delta: Float) {
gpu.render(batch, 0f, 0f) gpu.render(delta, batch, 0f, 0f)
} }

View File

@@ -0,0 +1,30 @@
package net.torvald.tsvm
abstract class VMRunner(val extension: String) {
var thread = Thread()
abstract fun executeCommand(command: String)
}
object VMRunnerFactory {
operator fun invoke(vm: VM, extension: String): VMRunner {
return when (extension) {
"lua" -> {
object : VMRunner(extension) {
private val vmLua = VMLuaAdapter(vm)
override fun executeCommand(command: String) {
thread = Thread {
vmLua.lua.load(command).call()
}
thread.start()
}
}
}
else -> throw UnsupportedOperationException("Unsupported script extension: $extension")
}
}
}

View File

@@ -16,7 +16,7 @@ class GraphicsAdapter : PeriBase {
internal val framebuffer = Pixmap(WIDTH, HEIGHT, Pixmap.Format.RGBA8888) internal val framebuffer = Pixmap(WIDTH, HEIGHT, Pixmap.Format.RGBA8888)
private var rendertex = Texture(1, 1, Pixmap.Format.RGBA8888) private var rendertex = Texture(1, 1, Pixmap.Format.RGBA8888)
private val paletteOfFloats = FloatArray(1024) { internal val paletteOfFloats = FloatArray(1024) {
val rgba = DEFAULT_PALETTE[it / 4] val rgba = DEFAULT_PALETTE[it / 4]
val channel = it % 4 val channel = it % 4
rgba.shr((3 - channel) * 8).and(255) / 255f rgba.shr((3 - channel) * 8).and(255) / 255f
@@ -34,7 +34,11 @@ class GraphicsAdapter : PeriBase {
private var graphicsUseSprites = false private var graphicsUseSprites = false
private var lastUsedColour = (-1).toByte() private var lastUsedColour = (-1).toByte()
private var currentChrRom = 0 private var currentChrRom = 0
private var chrWidth = 8f
private var chrHeight = 14f
private var ttyFore = 254
private var ttyBack = 255
private val textForePixmap = Pixmap(TEXT_COLS, TEXT_ROWS, Pixmap.Format.RGBA8888) private val textForePixmap = Pixmap(TEXT_COLS, TEXT_ROWS, Pixmap.Format.RGBA8888)
private val textBackPixmap = Pixmap(TEXT_COLS, TEXT_ROWS, Pixmap.Format.RGBA8888) private val textBackPixmap = Pixmap(TEXT_COLS, TEXT_ROWS, Pixmap.Format.RGBA8888)
@@ -44,7 +48,7 @@ class GraphicsAdapter : PeriBase {
private var textBackTex = Texture(textBackPixmap) private var textBackTex = Texture(textBackPixmap)
private var textTex = Texture(textPixmap) private var textTex = Texture(textPixmap)
private fun getTtyCursorPos() = spriteAndTextArea.getShort(3938L) % TEXT_COLS to spriteAndTextArea.getShort(3938L) / TEXT_COLS
init { init {
framebuffer.blending = Pixmap.Blending.None framebuffer.blending = Pixmap.Blending.None
@@ -57,6 +61,8 @@ class GraphicsAdapter : PeriBase {
pm.drawPixel(0, 0, -1) pm.drawPixel(0, 0, -1)
faketex = Texture(pm) faketex = Texture(pm)
pm.dispose() pm.dispose()
spriteAndTextArea.fillWith(0)
} }
override fun peek(addr: Long): Byte? { override fun peek(addr: Long): Byte? {
@@ -143,7 +149,11 @@ class GraphicsAdapter : PeriBase {
chrrom0.dispose() chrrom0.dispose()
} }
fun render(batch: SpriteBatch, x: Float, y: Float) { private var textCursorBlinkTimer = 0f
private val textCursorBlinkInterval = 0.5f
private var textCursorIsOn = true
fun render(delta: Float, batch: SpriteBatch, x: Float, y: Float) {
rendertex.dispose() rendertex.dispose()
rendertex = Texture(framebuffer) rendertex = Texture(framebuffer)
@@ -163,16 +173,13 @@ class GraphicsAdapter : PeriBase {
// feed palette data // feed palette data
// must be done every time the shader is "actually loaded" // must be done every time the shader is "actually loaded"
// try this: if above line precedes 'batch.shader = paletteShader', it won't work // try this: if above line precedes 'batch.shader = paletteShader', it won't work
paletteShader.setUniform4fv("pal", paletteOfFloats, 0, paletteOfFloats.size) batch.shader.setUniform4fv("pal", paletteOfFloats, 0, paletteOfFloats.size)
// draw framebuffer // draw framebuffer
batch.draw(rendertex, x, y) batch.draw(rendertex, x, y)
batch.end()
// draw texts or sprites // draw texts or sprites
batch.begin()
batch.color = Color.WHITE batch.color = Color.WHITE
@@ -222,6 +229,19 @@ class GraphicsAdapter : PeriBase {
textShader.setUniformf("atlasTexSize", chrrom0.width.toFloat(), chrrom0.height.toFloat()) textShader.setUniformf("atlasTexSize", chrrom0.width.toFloat(), chrrom0.height.toFloat())
batch.draw(faketex, 0f, 0f, WIDTH.toFloat(), HEIGHT.toFloat()) batch.draw(faketex, 0f, 0f, WIDTH.toFloat(), HEIGHT.toFloat())
batch.shader = null
if (textCursorIsOn) {
batch.color = Color(
paletteOfFloats[4 * ttyFore],
paletteOfFloats[4 * ttyFore + 1],
paletteOfFloats[4 * ttyFore + 2],
paletteOfFloats[4 * ttyFore + 3]
)
val (cursorx, cursory) = getTtyCursorPos()
batch.draw(faketex, cursorx * chrWidth, (TEXT_ROWS - cursory - 1) * chrHeight, chrWidth, chrHeight)
}
} }
else { else {
// draw sprites // draw sprites
@@ -238,11 +258,19 @@ class GraphicsAdapter : PeriBase {
batch.end() batch.end()
batch.shader = null batch.shader = null
textCursorBlinkTimer += delta
if (textCursorBlinkTimer > textCursorBlinkInterval) {
textCursorBlinkTimer -= 0.5f
textCursorIsOn = !textCursorIsOn
}
} }
private fun peekPalette(offset: Int): Byte { private fun peekPalette(offset: Int): Byte {
if (offset == 255) return 0 // palette 255 is always transparent if (offset == 255) return 0 // palette 255 is always transparent
// FIXME always return zero?
val highvalue = paletteOfFloats[offset * 2] // R, B val highvalue = paletteOfFloats[offset * 2] // R, B
val lowvalue = paletteOfFloats[offset * 2 + 1] // G, A val lowvalue = paletteOfFloats[offset * 2 + 1] // G, A
return (highvalue.div(15f).toInt().shl(4) or lowvalue.div(15f).toInt()).toByte() return (highvalue.div(15f).toInt().shl(4) or lowvalue.div(15f).toInt()).toByte()
@@ -322,7 +350,7 @@ uniform sampler2D u_texture;
uniform vec2 screenDimension; uniform vec2 screenDimension;
uniform vec2 tilesInAxes; // basically a screen dimension; vec2(tiles_in_horizontal, tiles_in_vertical) uniform vec2 tilesInAxes; // size of the tilemap texture; vec2(tiles_in_horizontal, tiles_in_vertical)
uniform sampler2D tilesAtlas; uniform sampler2D tilesAtlas;
uniform sampler2D foreColours; uniform sampler2D foreColours;
@@ -358,14 +386,13 @@ void main() {
// default gl_FragCoord takes half-integer (represeting centre of the pixel) -- could be useful for phys solver? // default gl_FragCoord takes half-integer (represeting centre of the pixel) -- could be useful for phys solver?
// This one, however, takes exact integer by rounding down. // // This one, however, takes exact integer by rounding down. //
vec2 overscannedScreenDimension = tilesInAxes * tileSizeInPx; // how many tiles will fit into a screen; one used by the tileFromMap
vec2 flippedFragCoord = vec2(gl_FragCoord.x, screenDimension.y - gl_FragCoord.y); // NO IVEC2!!; this flips Y vec2 flippedFragCoord = vec2(gl_FragCoord.x, screenDimension.y - gl_FragCoord.y); // NO IVEC2!!; this flips Y
// get required tile numbers // // get required tile numbers //
vec4 tileFromMap = texture2D(tilemap, flippedFragCoord / overscannedScreenDimension); // raw tile number vec4 tileFromMap = texture2D(tilemap, flippedFragCoord / screenDimension); // raw tile number
vec4 foreColFromMap = texture2D(foreColours, flippedFragCoord / overscannedScreenDimension); vec4 foreColFromMap = texture2D(foreColours, flippedFragCoord / screenDimension);
vec4 backColFromMap = texture2D(backColours, flippedFragCoord / overscannedScreenDimension); vec4 backColFromMap = texture2D(backColours, flippedFragCoord / screenDimension);
int tile = getTileFromColor(tileFromMap); int tile = getTileFromColor(tileFromMap);
ivec2 tileXY = getTileXY(tile); ivec2 tileXY = getTileXY(tile);

View File

@@ -39,6 +39,8 @@ User area: 8 MB, hardware area: 8 MB
VRAM Bank 0 (256 kB) VRAM Bank 0 (256 kB)
Endianness: little
From the start of the memory space: From the start of the memory space:
250880 bytes 250880 bytes
Framebuffer Framebuffer
@@ -87,6 +89,10 @@ MMIO
0b 0000 000g (g: Use sprites(wipes out text buffer)) 0b 0000 000g (g: Use sprites(wipes out text buffer))
1 bytes RO 1 bytes RO
Last used colour (set by poking at the framebuffer) Last used colour (set by poking at the framebuffer)
1 bytes RW
current TTY foreground colour (useful for print() function)
1 bytes RW
current TTY background colour (useful for print() function)
Text-mode-font-ROM is immutable and does not belong to VRAM Text-mode-font-ROM is immutable and does not belong to VRAM
Even in the text mode framebuffer is still being drawn onto the screen, and the texts are drawn on top of it Even in the text mode framebuffer is still being drawn onto the screen, and the texts are drawn on top of it