diff --git a/assets/disk0/decodemov.js b/assets/disk0/decodemov.js index 1682922..01a038a 100644 --- a/assets/disk0/decodemov.js +++ b/assets/disk0/decodemov.js @@ -137,7 +137,13 @@ let framesRendered = 0 //serial.println(readCount) // must say 18 //serial.println(`Dim: (${width}x${height}), FPS: ${fps}, Frames: ${frameCount}`) +if (type != 0) { + printerrln("Not a type 0 mov") + return 1 +} + let fbuf = sys.malloc(FBUF_SIZE) +graphics.setGraphicsMode(0) let startTime = sys.nanoTime() while (framesRendered < frameCount) { diff --git a/assets/disk0/decodemovhi.js b/assets/disk0/decodemovhi.js new file mode 100644 index 0000000..0606ebd --- /dev/null +++ b/assets/disk0/decodemovhi.js @@ -0,0 +1,187 @@ + +let filename = exec_args[1] + +const FBUF_SIZE = 560*448 +const MAGIC = [0x1F, 0x54, 0x53, 0x56, 0x4D, 0x4D, 0x4F, 0x56] +const port = filesystem._toPorts("A")[0] + +println("Reading...") + +com.sendMessage(port, "DEVRST\x17") +com.sendMessage(port, `OPENR"${filename}",1`) +let statusCode = com.getStatusCode(port) + +if (statusCode != 0) { + printerrln(`No such file (${statusCode})`) + return statusCode +} + +com.sendMessage(port, "READ") +statusCode = com.getStatusCode(port) +if (statusCode != 0) { + printerrln("READ failed with "+statusCode) + return statusCode +} + +con.clear(); con.curs_set(0) + +let readCount = 0 + +function readBytes(length) { + let ptr = sys.malloc(length) + let requiredBlocks = Math.floor((readCount + length) / 4096) - Math.floor(readCount / 4096) + + let completedReads = 0 + + //serial.println(`readBytes(${length}); readCount = ${readCount}`) + + for (let bc = 0; bc < requiredBlocks + 1; bc++) { + if (completedReads >= length) break + + if (readCount % 4096 == 0) { + //serial.println("READ from serial") + // pull the actual message + sys.poke(-4093 - port, 6);sys.sleep(0) // spinning is required as Graal run is desynced with the Java side + + let blockTransferStatus = ((sys.peek(-4085 - port*2) & 255) | ((sys.peek(-4086 - port*2) & 255) << 8)) + let thisBlockLen = blockTransferStatus & 4095 + if (thisBlockLen == 0) thisBlockLen = 4096 // [1, 4096] + let hasMore = (blockTransferStatus & 0x8000 != 0) + + + //serial.println(`block: (${thisBlockLen})[${[...Array(thisBlockLen).keys()].map(k => (sys.peek(-4097 - k) & 255).toString(16).padStart(2,'0')).join()}]`) + + let remaining = Math.min(thisBlockLen, length - completedReads) + + //serial.println(`Pulled a block (${thisBlockLen}); readCount = ${readCount}, completedReads = ${completedReads}, remaining = ${remaining}`) + + // copy from read buffer to designated position + sys.memcpy(-4097, ptr + completedReads, remaining) + + // increment readCount properly + readCount += remaining + completedReads += remaining + } + else { + let padding = readCount % 4096 + let remaining = length - completedReads + let thisBlockLen = Math.min(4096 - padding, length - completedReads) + + //serial.println(`padding = ${padding}; remaining = ${remaining}`) + + //serial.println(`block: (${thisBlockLen})[${[...Array(thisBlockLen).keys()].map(k => (sys.peek(-4097 - padding - k) & 255).toString(16).padStart(2,'0')).join()}]`) + + //serial.println(`Reusing a block (${thisBlockLen}); readCount = ${readCount}, completedReads = ${completedReads}`) + + // copy from read buffer to designated position + sys.memcpy(-4097 - padding, ptr + completedReads, thisBlockLen) + + // increment readCount properly + readCount += thisBlockLen + completedReads += thisBlockLen + } + } + + //serial.println(`END readBytes(${length}); readCount = ${readCount}\n`) + + return ptr +} + +function readInt() { + let b = readBytes(4) + let i = (sys.peek(b) & 255) | ((sys.peek(b+1) & 255) << 8) | ((sys.peek(b+2) & 255) << 16) | ((sys.peek(b+3) & 255) << 24) + + //serial.println(`readInt(); bytes: ${sys.peek(b)}, ${sys.peek(b+1)}, ${sys.peek(b+2)}, ${sys.peek(b+3)} = ${i}\n`) + + sys.free(b) + return i +} + +function readShort() { + let b = readBytes(2) + let i = (sys.peek(b) & 255) | ((sys.peek(b+1) & 255) << 8) + + //serial.println(`readShort(); bytes: ${sys.peek(b)}, ${sys.peek(b+1)} = ${i}\n`) + + sys.free(b) + return i +} + + +let magic = readBytes(8) +let magicMatching = true + +// check if magic number matches +MAGIC.forEach((b,i) => { + let testb = sys.peek(magic + i) & 255 // for some reason this must be located here + if (testb != b) { + magicMatching = false + } +}) +sys.free(magic) +if (!magicMatching) { + println("Not a movie file (MAGIC mismatch)") + return 1 +} + + +let width = readShort() +let height = readShort() +let fps = readShort(); if (fps == 0) fps = 9999 +let frameTime = 1.0 / fps +let frameCount = readInt() % 16777216 +let type = readShort() +sys.free(readBytes(12)) // skip 12 bytes +let akku = frameTime +let framesRendered = 0 +//serial.println(readCount) // must say 18 +//serial.println(`Dim: (${width}x${height}), FPS: ${fps}, Frames: ${frameCount}`) + +if (type != 2) { + printerrln("Not a type 2 mov") + return 1 +} + +let fbuf1 = sys.malloc(FBUF_SIZE) +let fbuf2 = sys.malloc(FBUF_SIZE) +graphics.setGraphicsMode(4) + +let startTime = sys.nanoTime() +while (framesRendered < frameCount) { + //serial.println(`Frame #${f+1}`) + + let t1 = sys.nanoTime() + + if (akku >= frameTime) { + akku -= frameTime + + // plane 1 + let payloadLen1 = readInt() + let gzippedPtr1 = readBytes(payloadLen1) + let payloadLen2 = readInt() + let gzippedPtr2 = readBytes(payloadLen2) + + gzip.decompFromTo(gzippedPtr1, payloadLen1, fbuf1) // should return FBUF_SIZE + gzip.decompFromTo(gzippedPtr2, payloadLen2, fbuf2) // should return FBUF_SIZE + dma.ramToFrame(fbuf1, 0, FBUF_SIZE) + dma.ramToFrame2(fbuf2, 0, FBUF_SIZE) + + sys.free(gzippedPtr1) + sys.free(gzippedPtr2) + + + framesRendered += 1 + } + sys.sleep(1) + + let t2 = sys.nanoTime() + akku += (t2 - t1) / 1000000000.0 +} +let endTime = sys.nanoTime() + +sys.free(fbuf1) +sys.free(fbuf2) + +let timeTook = (endTime - startTime) / 1000000000.0 + +//println(`Actual FPS: ${frameCount / timeTook}`) \ No newline at end of file diff --git a/assets/disk0/decodemovhimjpg.js b/assets/disk0/decodemovhimjpg.js new file mode 100644 index 0000000..bbbf7e9 --- /dev/null +++ b/assets/disk0/decodemovhimjpg.js @@ -0,0 +1,187 @@ + +let filename = exec_args[1] + +const FBUF_SIZE = 560*448 +const MAGIC = [0x1F, 0x54, 0x53, 0x56, 0x4D, 0x4D, 0x4F, 0x56] +const port = filesystem._toPorts("A")[0] + +println("Reading...") + +com.sendMessage(port, "DEVRST\x17") +com.sendMessage(port, `OPENR"${filename}",1`) +let statusCode = com.getStatusCode(port) + +if (statusCode != 0) { + printerrln(`No such file (${statusCode})`) + return statusCode +} + +com.sendMessage(port, "READ") +statusCode = com.getStatusCode(port) +if (statusCode != 0) { + printerrln("READ failed with "+statusCode) + return statusCode +} + +con.clear(); con.curs_set(0) + +let readCount = 0 + +function readBytes(length) { + let ptr = sys.malloc(length) + let requiredBlocks = Math.floor((readCount + length) / 4096) - Math.floor(readCount / 4096) + + let completedReads = 0 + + //serial.println(`readBytes(${length}); readCount = ${readCount}`) + + for (let bc = 0; bc < requiredBlocks + 1; bc++) { + if (completedReads >= length) break + + if (readCount % 4096 == 0) { + //serial.println("READ from serial") + // pull the actual message + sys.poke(-4093 - port, 6);sys.sleep(0) // spinning is required as Graal run is desynced with the Java side + + let blockTransferStatus = ((sys.peek(-4085 - port*2) & 255) | ((sys.peek(-4086 - port*2) & 255) << 8)) + let thisBlockLen = blockTransferStatus & 4095 + if (thisBlockLen == 0) thisBlockLen = 4096 // [1, 4096] + let hasMore = (blockTransferStatus & 0x8000 != 0) + + + //serial.println(`block: (${thisBlockLen})[${[...Array(thisBlockLen).keys()].map(k => (sys.peek(-4097 - k) & 255).toString(16).padStart(2,'0')).join()}]`) + + let remaining = Math.min(thisBlockLen, length - completedReads) + + //serial.println(`Pulled a block (${thisBlockLen}); readCount = ${readCount}, completedReads = ${completedReads}, remaining = ${remaining}`) + + // copy from read buffer to designated position + sys.memcpy(-4097, ptr + completedReads, remaining) + + // increment readCount properly + readCount += remaining + completedReads += remaining + } + else { + let padding = readCount % 4096 + let remaining = length - completedReads + let thisBlockLen = Math.min(4096 - padding, length - completedReads) + + //serial.println(`padding = ${padding}; remaining = ${remaining}`) + + //serial.println(`block: (${thisBlockLen})[${[...Array(thisBlockLen).keys()].map(k => (sys.peek(-4097 - padding - k) & 255).toString(16).padStart(2,'0')).join()}]`) + + //serial.println(`Reusing a block (${thisBlockLen}); readCount = ${readCount}, completedReads = ${completedReads}`) + + // copy from read buffer to designated position + sys.memcpy(-4097 - padding, ptr + completedReads, thisBlockLen) + + // increment readCount properly + readCount += thisBlockLen + completedReads += thisBlockLen + } + } + + //serial.println(`END readBytes(${length}); readCount = ${readCount}\n`) + + return ptr +} + +function readInt() { + let b = readBytes(4) + let i = (sys.peek(b) & 255) | ((sys.peek(b+1) & 255) << 8) | ((sys.peek(b+2) & 255) << 16) | ((sys.peek(b+3) & 255) << 24) + + //serial.println(`readInt(); bytes: ${sys.peek(b)}, ${sys.peek(b+1)}, ${sys.peek(b+2)}, ${sys.peek(b+3)} = ${i}\n`) + + sys.free(b) + return i +} + +function readShort() { + let b = readBytes(2) + let i = (sys.peek(b) & 255) | ((sys.peek(b+1) & 255) << 8) + + //serial.println(`readShort(); bytes: ${sys.peek(b)}, ${sys.peek(b+1)} = ${i}\n`) + + sys.free(b) + return i +} + + +let magic = readBytes(8) +let magicMatching = true + +// check if magic number matches +MAGIC.forEach((b,i) => { + let testb = sys.peek(magic + i) & 255 // for some reason this must be located here + if (testb != b) { + magicMatching = false + } +}) +sys.free(magic) +if (!magicMatching) { + println("Not a movie file (MAGIC mismatch)") + return 1 +} + + +let width = readShort() +let height = readShort() +let fps = readShort(); if (fps == 0) fps = 9999 +let frameTime = 1.0 / fps +let frameCount = readInt() % 16777216 +let type = readShort() +sys.free(readBytes(12)) // skip 12 bytes +let akku = frameTime +let framesRendered = 0 +//serial.println(readCount) // must say 18 +//serial.println(`Dim: (${width}x${height}), FPS: ${fps}, Frames: ${frameCount}`) + +if (type != 16) { + printerrln("Not a type 16 mov") + return 1 +} + +let fbuf1 = sys.malloc(FBUF_SIZE) +let fbuf2 = sys.malloc(FBUF_SIZE) +graphics.setGraphicsMode(4) + +let imagearea = sys.malloc(FBUF_SIZE) +let decodearea1 = sys.malloc(FBUF_SIZE) +let decodearea2 = sys.malloc(FBUF_SIZE) + +let startTime = sys.nanoTime() +while (framesRendered < frameCount) { + //serial.println(`Frame #${f+1}`) + + let t1 = sys.nanoTime() + + if (akku >= frameTime) { + akku -= frameTime + + let payloadLen = readInt() + let jpgPtr = readBytes(payloadLen) + + graphics.decodeImageTo(jpgPtr, payloadLen, imagearea) + graphics.imageToDirectCol(imagearea, -1048577, -1310721, 560, 448, 3, framesRendered) + + sys.free(jpgPtr) + + framesRendered += 1 + } + sys.sleep(1) + + let t2 = sys.nanoTime() + akku += (t2 - t1) / 1000000000.0 +} +let endTime = sys.nanoTime() + +sys.free(fbuf1) +sys.free(fbuf2) +sys.free(imagearea) +sys.free(decodearea1) +sys.free(decodearea2) + +let timeTook = (endTime - startTime) / 1000000000.0 + +//println(`Actual FPS: ${frameCount / timeTook}`) \ No newline at end of file diff --git a/assets/disk0/encodemovhi.js b/assets/disk0/encodemovhi.js new file mode 100644 index 0000000..5e3f87f --- /dev/null +++ b/assets/disk0/encodemovhi.js @@ -0,0 +1,80 @@ + +const FBUF_SIZE = 560*448 +let infile = sys.malloc(120000) // somewhat arbitrary +let imagearea = sys.malloc(FBUF_SIZE*3) +let decodearea1 = sys.malloc(FBUF_SIZE) +let decodearea2 = sys.malloc(FBUF_SIZE) +let gzippedImage1 = sys.malloc(180000) // somewhat arbitrary +let gzippedImage2 = sys.malloc(180000) // somewhat arbitrary + +let outfilename = exec_args[1] + +if (!outfilename) return 1 + +function appendToOutfile(bytes) { + filesystem.open("A", outfilename, "A") + filesystem.writeBytes("A", bytes) +} + +function appendToOutfilePtr(ptr, len) { + filesystem.open("A", outfilename, "A") + dma.ramToCom(ptr, 0, len) +} + +// write header to the file +let headerBytes = [ + 0x1F, 0x54, 0x53, 0x56, 0x4D, 0x4D, 0x4F, 0x56, // magic + 0x30, 0x02, // width (560) + 0xC0, 0x01, // height (448) + 0x1E, 0x00, // FPS (30) + 0x34, 0x00, 0x00, 0x00, // frame count (52) + 0x02, 0x00, // type 2 frames + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // reserved +] + +filesystem.open("A", outfilename, "W") +filesystem.writeBytes("A", headerBytes) + +for (let f = 1; f <=52; f++) { + let fname = `/movtestimg/${(''+f).padStart(3,'0')}.jpg` + filesystem.open("A", fname, "R") + let fileLen = filesystem.getFileLen("A") + dma.comToRam(0, 0, infile, fileLen) + + graphics.decodeImageTo(infile, fileLen, imagearea) + + print(`Encoding frame ${f}...`) + + graphics.imageToDirectCol(imagearea, decodearea1, decodearea2, 560, 448, 3, f) + + let gzlen1 = gzip.compFromTo(decodearea1, FBUF_SIZE, gzippedImage1) + let gzlen2 = gzip.compFromTo(decodearea2, FBUF_SIZE, gzippedImage2) + + let frameSize1 = [ + (gzlen1 >>> 0) & 255, + (gzlen1 >>> 8) & 255, + (gzlen1 >>> 16) & 255, + (gzlen1 >>> 24) & 255 + ] + let frameSize2 = [ + (gzlen2 >>> 0) & 255, + (gzlen2 >>> 8) & 255, + (gzlen2 >>> 16) & 255, + (gzlen2 >>> 24) & 255 + ] + + appendToOutfile(frameSize1) + appendToOutfilePtr(gzippedImage1, gzlen1) + + appendToOutfile(frameSize2) + appendToOutfilePtr(gzippedImage2, gzlen2) + + print(` ${gzlen1 + gzlen2} bytes\n`) +} + +sys.free(infile) +sys.free(imagearea) +sys.free(decodearea1) +sys.free(decodearea2) +sys.free(gzippedImage1) +sys.free(gzippedImage2) \ No newline at end of file diff --git a/assets/disk0/encodemovmjpg.js b/assets/disk0/encodemovmjpg.js new file mode 100644 index 0000000..03113e1 --- /dev/null +++ b/assets/disk0/encodemovmjpg.js @@ -0,0 +1,55 @@ + +const FBUF_SIZE = 560*448 +let infile = sys.malloc(120000) // somewhat arbitrary + +let outfilename = exec_args[1] + +if (!outfilename) return 1 + +function appendToOutfile(bytes) { + filesystem.open("A", outfilename, "A") + filesystem.writeBytes("A", bytes) +} + +function appendToOutfilePtr(ptr, len) { + filesystem.open("A", outfilename, "A") + dma.ramToCom(ptr, 0, len) +} + +// write header to the file +let headerBytes = [ + 0x1F, 0x54, 0x53, 0x56, 0x4D, 0x4D, 0x4F, 0x56, // magic + 0x30, 0x02, // width (560) + 0xC0, 0x01, // height (448) + 0x1E, 0x00, // FPS (30) + 0x34, 0x00, 0x00, 0x00, // frame count (52) + 0x10, 0x00, // type 16 frames + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // reserved +] + +filesystem.open("A", outfilename, "W") +filesystem.writeBytes("A", headerBytes) + +for (let f = 1; f <=52; f++) { + let fname = `/movtestimg/${(''+f).padStart(3,'0')}.jpg` + filesystem.open("A", fname, "R") + let fileLen = filesystem.getFileLen("A") + dma.comToRam(0, 0, infile, fileLen) + + + print(`Encoding frame ${f}...`) + + let frameSize = [ + (fileLen >>> 0) & 255, + (fileLen >>> 8) & 255, + (fileLen >>> 16) & 255, + (fileLen >>> 24) & 255 + ] + + appendToOutfile(frameSize) + appendToOutfilePtr(infile, fileLen) + + print(` ${fileLen} bytes\n`) +} + +sys.free(infile) diff --git a/tsvm_core/src/net/torvald/tsvm/DMADelegate.kt b/tsvm_core/src/net/torvald/tsvm/DMADelegate.kt index b75cee6..0d289a9 100644 --- a/tsvm_core/src/net/torvald/tsvm/DMADelegate.kt +++ b/tsvm_core/src/net/torvald/tsvm/DMADelegate.kt @@ -20,6 +20,12 @@ class DMADelegate(val vm: VM) { } } + fun ramToFrame2(from: Int, devnum: Int, offset: Int, length: Int) { + (vm.peripheralTable[devnum].peripheral as? GraphicsAdapter)?.let { + UnsafeHelper.memcpyRaw(null, vm.usermem.ptr + from, null, it.framebuffer2!!.ptr + offset, length.toLong()) + } + } + fun ramToFrame(from: Int, to: Int, length: Int) { for (i in 0..7) { if (vm.peripheralTable[i].type == VM.PERITYPE_GPU_AND_TERM) { @@ -29,6 +35,15 @@ class DMADelegate(val vm: VM) { } } + fun ramToFrame2(from: Int, to: Int, length: Int) { + for (i in 0..7) { + if (vm.peripheralTable[i].type == VM.PERITYPE_GPU_AND_TERM) { + ramToFrame2(from, i, to, length) + return + } + } + } + fun frameToRam(from: Int, to: Int, devnum: Int, length: Int) { (vm.peripheralTable[devnum].peripheral as? GraphicsAdapter)?.let { UnsafeHelper.memcpyRaw(null, it.framebuffer.ptr + from, null, vm.usermem.ptr + to, length.toLong()) diff --git a/tsvm_core/src/net/torvald/tsvm/GraphicsJSR223Delegate.kt b/tsvm_core/src/net/torvald/tsvm/GraphicsJSR223Delegate.kt index 4bf2455..8b7fdcf 100644 --- a/tsvm_core/src/net/torvald/tsvm/GraphicsJSR223Delegate.kt +++ b/tsvm_core/src/net/torvald/tsvm/GraphicsJSR223Delegate.kt @@ -502,7 +502,7 @@ class GraphicsJSR223Delegate(val vm: VM) { for (k in 0L until len) { val x = (k % width).toInt() val y = (k / width).toInt() - val t = bayerKernels[pattern][4 * (y % 4) + (x % 4)] + val t = bayerKernels[pattern % bayerKernels.size][4 * (y % 4) + (x % 4)] val r = vm.peek(srcPtr + channels * k + 0)!!.toUint().toFloat() / 255f val g = vm.peek(srcPtr + channels * k + 1)!!.toUint().toFloat() / 255f