no memory leak on ImageBuffer rendering

Turns out, <ImageBuffer>.image creates new Image instance which will NEVER be reclaimed (which causes OutOfMemoryError) unless manually destroy()ed.


Former-commit-id: 34840cf63e52e5635ec8acd5fb1bb78923c61063
Former-commit-id: aca4388320fae022a4744f75c1b0f66b544bdafb
This commit is contained in:
Song Minjae
2017-02-25 02:39:02 +09:00
parent 30b82acb4b
commit fed45d9fe6
6 changed files with 61 additions and 24 deletions

View File

@@ -23,21 +23,21 @@ class StateBlurTest : BasicGameState() {
override fun init(gc: GameContainer, sbg: StateBasedGame) {
testImage.flushPixelData()
System.arraycopy(
/*System.arraycopy(
testImage.texture.textureData, 0,
bluredImage.rgba, 0, testImage.texture.textureData.size
)
kotlin.repeat(3, { fastBoxBlur(bluredImage, 3) })
kotlin.repeat(3, { fastBoxBlur(bluredImage, 3) })*/
}
override fun update(gc: GameContainer, sbg: StateBasedGame, delta: Int) {
Terrarum.appgc.setTitle("${Terrarum.NAME} — F: ${Terrarum.appgc.fps}")
/*System.arraycopy(
System.arraycopy(
testImage.texture.textureData, 0,
bluredImage.rgba, 0, testImage.texture.textureData.size
)*/
//fastBoxBlur(testImage, bluredImage, 3)
)
fastBoxBlur(testImage, bluredImage, 3)
//fastBoxBlur(bluredImage, 3)
//fastBoxBlur(bluredImage, 3)
}
@@ -46,11 +46,14 @@ class StateBlurTest : BasicGameState() {
override fun render(gc: GameContainer, sbg: StateBasedGame, g: Graphics) {
g.background = Color(0x404040)
g.drawImage(bluredImage.image,
val image = bluredImage.image
g.drawImage(image,
Terrarum.WIDTH.minus(testImage.width).div(2f).floor(),
Terrarum.HEIGHT.minus(testImage.height).div(2f).floor()
)
g.flush()
image.destroy()
}
private val isLE: Boolean

View File

@@ -49,20 +49,26 @@ class StateGraphicComputerTest : BasicGameState() {
monitor.update(container, delta)
computer.update(container, delta)
val sprite = (computer.getPeripheral("ppu") as PeripheralVideoCard).vram.sprites[0]
val vcard = (computer.getPeripheral("ppu") as PeripheralVideoCard)
val sprite = vcard.vram.sprites[0]
angle += delta / 500.0
sprite.posX = (Math.cos(angle) * 80 + 100).roundInt()
sprite.posY = (Math.sin(angle) * 80 + 100).roundInt()
sprite.pal0 = (sprite.pal0 + 1) % 65
sprite.pal1 = (sprite.pal1 + 1) % 65
sprite.pal2 = (sprite.pal2 + 1) % 65
sprite.pal3 = (sprite.pal3 + 1) % 65
//sprite.pal0 = (sprite.pal0 + 1) % 65
//sprite.pal1 = (sprite.pal1 + 1) % 65
//sprite.pal2 = (sprite.pal2 + 1) % 65
//sprite.pal3 = (sprite.pal3 + 1) % 65
sprite.rotation = (angle * 2 / Math.PI).roundInt() % 4
//vcard.vram.setBackgroundPixel(Random().nextInt(320), Random().nextInt(200), Random().nextInt(64))
//kotlin.repeat(64) {
// vcard.vram.setBackgroundPixel(Random().nextInt(320), Random().nextInt(200), 0)
//}
}
override fun getID() = Terrarum.STATE_ID_TEST_TTY

View File

@@ -155,10 +155,13 @@ class StateNoiseTexGen : BasicGameState() {
g.drawString("CPUs: ${Terrarum.THREADS}", Terrarum.WIDTH - 90f, 8f)
g.background = Color.cyan
g.drawImage(noiseImageBuffer.image,//noiseImage,
val img = noiseImageBuffer.image
g.drawImage(img,//noiseImage,
Terrarum.WIDTH.minus(imagesize).div(2).toFloat(),
Terrarum.HEIGHT.minus(imagesize).div(2).toFloat()
)
img.destroy()
}
override fun keyPressed(key: Int, c: Char) {

View File

@@ -44,6 +44,10 @@ constructor(gamename: String) : StateBasedGame(gamename) {
// just in case
println("[Terrarum] os.arch = $systemArch")
if (is32Bit) {
println("Java is running in 32 Bit")
}
gameConfig = GameConfig()
joypadLabelStart = when (getConfigString("joypadlabelstyle")) {
@@ -131,7 +135,7 @@ constructor(gamename: String) : StateBasedGame(gamename) {
gc.graphics.clear() // clean up any 'dust' in the buffer
//addState(StateVTTest())
addState(StateGraphicComputerTest())
//addState(StateGraphicComputerTest())
//addState(StateTestingLightning())
//addState(StateSplash())
//addState(StateMonitorCheck())

View File

@@ -10,7 +10,7 @@ import org.newdawn.slick.Image
/**
* Created by minjaesong on 2017-01-07.
*/
class TapestryObject(val image: Image, val artName: String, val artAuthor: String) : FixtureBase(physics = false) {
class TapestryObject(image: Image, val artName: String, val artAuthor: String) : FixtureBase(physics = false) {
// physics = false only speeds up for ~2 frames with 50 tapestries
@@ -19,6 +19,7 @@ class TapestryObject(val image: Image, val artName: String, val artAuthor: Strin
makeNewSprite(image.width, image.height, image)
setHitboxDimension(image.width, image.height, 0, 0)
setPosition(Terrarum.appgc.mouseX, Terrarum.appgc.mouseY)
// you CAN'T destroy the image
}
override fun update(gc: GameContainer, delta: Int) {

View File

@@ -45,8 +45,8 @@ class PeripheralVideoCard(val termW: Int = 40, val termH: Int = 25) :
val height = termH * blockH
val vram = VRAM(width, height, 64)
val frameBuffer = Image(width, height)
val frameBufferG = frameBuffer.graphics
val frameBuffer = ImageBuffer(width, height)
val frameBufferImage = frameBuffer.image
// hard-coded 8x8
var fontRom = Array<IntArray>(256, { Array<Int>(blockH, { 0 }).toIntArray() })
@@ -54,6 +54,8 @@ class PeripheralVideoCard(val termW: Int = 40, val termH: Int = 25) :
init {
// build it for first time
resetTextRom()
frameBufferImage.filter = Image.FILTER_NEAREST
}
val CLUT = VRAM.CLUT
@@ -119,27 +121,45 @@ class PeripheralVideoCard(val termW: Int = 40, val termH: Int = 25) :
}
}
frameBuffer.filter = Image.FILTER_NEAREST
frameBufferG.clear()
frameBufferG.drawImage(vram.background.image, 0f, 0f)
System.arraycopy(vram.background.rgba, 0, frameBuffer.rgba, 0, vram.background.rgba.size)
vram.sprites.forEach {
if (it.isBackground) {
it.render()
frameBufferG.drawImage(spriteBuffer.image, it.posX.toFloat(), it.posY.toFloat())
frameBuffer.softwareRender(spriteBuffer, it.posX, it.posY)
}
}
frameBufferG.drawImage(vram.foreground.image, 0f, 0f)
frameBuffer.softwareRender(vram.foreground, 0, 0)
vram.sprites.forEach {
if (!it.isBackground) {
it.render()
frameBufferG.drawImage(spriteBuffer.image, it.posX.toFloat(), it.posY.toFloat())
frameBuffer.softwareRender(spriteBuffer, it.posX, it.posY)
}
}
frameBufferG.flush()
g.drawImage(frameBuffer.getScaledCopy(2f), 0f, 0f)
val img = frameBuffer.image
img.filter = Image.FILTER_NEAREST
g.drawImage(img.getScaledCopy(2f), 0f, 0f)
img.destroy()
}
fun ImageBuffer.softwareRender(other: ImageBuffer, posX: Int, posY: Int) {
for (y in 0..other.height - 1) {
for (x in 0..other.width - 1) {
val ix = posX + x
val iy = posY + y
if (ix >= 0 && iy >= 0 && ix < this.width && iy < this.height) {
if (other.rgba[4 * (y * other.width + x) + 3] != 0.toByte()) { // if not transparent
this.rgba[4 * (iy * this.texWidth + ix) + 0] = other.rgba[4 * (y * other.texWidth + x) + 0]
this.rgba[4 * (iy * this.texWidth + ix) + 1] = other.rgba[4 * (y * other.texWidth + x) + 1]
this.rgba[4 * (iy * this.texWidth + ix) + 2] = other.rgba[4 * (y * other.texWidth + x) + 2]
this.rgba[4 * (iy * this.texWidth + ix) + 3] = other.rgba[4 * (y * other.texWidth + x) + 3]
}
}
}
}
}
private var foreColor = 49 // white