make render system safer, detect gpu memory leaks

This commit is contained in:
Bixilon 2022-09-26 13:52:09 +02:00
parent 0eee704cdf
commit 2c76371578
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
10 changed files with 91 additions and 6 deletions

View File

@ -301,6 +301,7 @@ class RenderWindow(
Log.log(LogMessageType.RENDERING_LOADING) { "Destroying render window..." } Log.log(LogMessageType.RENDERING_LOADING) { "Destroying render window..." }
renderingState = RenderingStates.STOPPED renderingState = RenderingStates.STOPPED
renderSystem.destroy()
window.destroy() window.destroy()
Log.log(LogMessageType.RENDERING_LOADING) { "Render window destroyed!" } Log.log(LogMessageType.RENDERING_LOADING) { "Render window destroyed!" }
// disconnect // disconnect

View File

@ -37,7 +37,10 @@ interface RenderSystem {
var shader: Shader? var shader: Shader?
var framebuffer: Framebuffer? var framebuffer: Framebuffer?
val active: Boolean
fun init() fun init()
fun destroy()
fun reset( fun reset(
depthTest: Boolean = true, depthTest: Boolean = true,

View File

@ -18,6 +18,7 @@ import de.bixilon.kotlinglm.vec2.Vec2i
interface Renderbuffer { interface Renderbuffer {
val mode: RenderbufferModes val mode: RenderbufferModes
val size: Vec2i val size: Vec2i
val state: RenderbufferStates
fun init() fun init()
fun unload() fun unload()

View File

@ -0,0 +1,21 @@
/*
* Minosoft
* Copyright (C) 2020-2022 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.system.base.buffer.render
enum class RenderbufferStates {
PREPARING,
GENERATED,
UNLOADED,
;
}

View File

@ -0,0 +1,16 @@
/*
* Minosoft
* Copyright (C) 2020-2022 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.system.opengl
class MemoryLeakException(message: String? = null) : Exception(message)

View File

@ -55,6 +55,8 @@ class OpenGLRenderSystem(
private val capabilities: MutableSet<RenderingCapabilities> = synchronizedSetOf() private val capabilities: MutableSet<RenderingCapabilities> = synchronizedSetOf()
override lateinit var vendor: OpenGLVendor override lateinit var vendor: OpenGLVendor
private set private set
override var active: Boolean = false
private set
var blendingSource = BlendingFunctions.ONE var blendingSource = BlendingFunctions.ONE
private set private set
@ -140,6 +142,11 @@ class OpenGLRenderSystem(
Log.log(LogMessageType.RENDERING_GENERAL, LogLevels.VERBOSE) { "OpenGL error: source=$source, type=$type, id=$id, severity=$severity, length=$length, message=$message, userParameter=$userParameter" } Log.log(LogMessageType.RENDERING_GENERAL, LogLevels.VERBOSE) { "OpenGL error: source=$source, type=$type, id=$id, severity=$severity, length=$length, message=$message, userParameter=$userParameter" }
}, 0) }, 0)
} }
active = true
}
override fun destroy() {
active = false
} }
override fun enable(capability: RenderingCapabilities) { override fun enable(capability: RenderingCapabilities) {
@ -184,6 +191,7 @@ class OpenGLRenderSystem(
private var destinationRGB: BlendingFunctions = BlendingFunctions.ONE private var destinationRGB: BlendingFunctions = BlendingFunctions.ONE
private var sourceAlpha: BlendingFunctions = BlendingFunctions.ONE private var sourceAlpha: BlendingFunctions = BlendingFunctions.ONE
private var destinationAlpha: BlendingFunctions = BlendingFunctions.ONE private var destinationAlpha: BlendingFunctions = BlendingFunctions.ONE
override fun setBlendFunction(sourceRGB: BlendingFunctions, destinationRGB: BlendingFunctions, sourceAlpha: BlendingFunctions, destinationAlpha: BlendingFunctions) { override fun setBlendFunction(sourceRGB: BlendingFunctions, destinationRGB: BlendingFunctions, sourceAlpha: BlendingFunctions, destinationAlpha: BlendingFunctions) {
if (this.sourceRGB == sourceRGB && this.destinationRGB == destinationRGB && this.sourceAlpha == sourceAlpha && this.destinationAlpha == destinationAlpha) { if (this.sourceRGB == sourceRGB && this.destinationRGB == destinationRGB && this.sourceAlpha == sourceAlpha && this.destinationAlpha == destinationAlpha) {
return return
@ -261,7 +269,7 @@ class OpenGLRenderSystem(
} }
override fun createFramebuffer(): OpenGLFramebuffer { override fun createFramebuffer(): OpenGLFramebuffer {
return OpenGLFramebuffer(renderWindow.window.size) return OpenGLFramebuffer(this, renderWindow.window.size)
} }
override fun createTextureManager(): OpenGLTextureManager { override fun createTextureManager(): OpenGLTextureManager {

View File

@ -17,6 +17,7 @@ import de.bixilon.minosoft.gui.rendering.system.base.buffer.RenderableBuffer
import de.bixilon.minosoft.gui.rendering.system.base.buffer.RenderableBufferDrawTypes import de.bixilon.minosoft.gui.rendering.system.base.buffer.RenderableBufferDrawTypes
import de.bixilon.minosoft.gui.rendering.system.base.buffer.RenderableBufferStates import de.bixilon.minosoft.gui.rendering.system.base.buffer.RenderableBufferStates
import de.bixilon.minosoft.gui.rendering.system.base.buffer.RenderableBufferTypes import de.bixilon.minosoft.gui.rendering.system.base.buffer.RenderableBufferTypes
import de.bixilon.minosoft.gui.rendering.system.opengl.MemoryLeakException
import de.bixilon.minosoft.gui.rendering.system.opengl.OpenGLRenderSystem import de.bixilon.minosoft.gui.rendering.system.opengl.OpenGLRenderSystem
import org.lwjgl.opengl.GL15.* import org.lwjgl.opengl.GL15.*
import org.lwjgl.opengl.GL31.GL_UNIFORM_BUFFER import org.lwjgl.opengl.GL31.GL_UNIFORM_BUFFER
@ -59,6 +60,11 @@ abstract class OpenGLRenderableBuffer(
state = RenderableBufferStates.UNLOADED state = RenderableBufferStates.UNLOADED
} }
protected fun finalize() {
if (state == RenderableBufferStates.UPLOADED && renderSystem.active) {
throw MemoryLeakException("Buffer has not been unloaded!")
}
}
protected companion object { protected companion object {
val RenderableBufferTypes.gl: Int val RenderableBufferTypes.gl: Int

View File

@ -19,12 +19,14 @@ import de.bixilon.minosoft.gui.rendering.system.base.buffer.frame.FramebufferSta
import de.bixilon.minosoft.gui.rendering.system.base.buffer.frame.texture.FramebufferTexture import de.bixilon.minosoft.gui.rendering.system.base.buffer.frame.texture.FramebufferTexture
import de.bixilon.minosoft.gui.rendering.system.base.buffer.render.Renderbuffer import de.bixilon.minosoft.gui.rendering.system.base.buffer.render.Renderbuffer
import de.bixilon.minosoft.gui.rendering.system.base.buffer.render.RenderbufferModes import de.bixilon.minosoft.gui.rendering.system.base.buffer.render.RenderbufferModes
import de.bixilon.minosoft.gui.rendering.system.opengl.MemoryLeakException
import de.bixilon.minosoft.gui.rendering.system.opengl.OpenGLRenderSystem
import de.bixilon.minosoft.gui.rendering.system.opengl.buffer.frame.texture.OpenGLFramebufferColorTexture import de.bixilon.minosoft.gui.rendering.system.opengl.buffer.frame.texture.OpenGLFramebufferColorTexture
import de.bixilon.minosoft.gui.rendering.system.opengl.buffer.frame.texture.OpenGLFramebufferDepthTexture import de.bixilon.minosoft.gui.rendering.system.opengl.buffer.frame.texture.OpenGLFramebufferDepthTexture
import de.bixilon.minosoft.gui.rendering.system.opengl.buffer.render.OpenGLRenderbuffer import de.bixilon.minosoft.gui.rendering.system.opengl.buffer.render.OpenGLRenderbuffer
import org.lwjgl.opengl.GL30.* import org.lwjgl.opengl.GL30.*
class OpenGLFramebuffer(var size: Vec2i) : Framebuffer { class OpenGLFramebuffer(val renderSystem: OpenGLRenderSystem, var size: Vec2i) : Framebuffer {
override var state: FramebufferState = FramebufferState.PREPARING override var state: FramebufferState = FramebufferState.PREPARING
private set private set
@ -45,7 +47,7 @@ class OpenGLFramebuffer(var size: Vec2i) : Framebuffer {
colorTexture.init() colorTexture.init()
attach(colorTexture) attach(colorTexture)
renderbuffer = OpenGLRenderbuffer(RenderbufferModes.DEPTH_COMPONENT24, size) renderbuffer = OpenGLRenderbuffer(renderSystem, RenderbufferModes.DEPTH_COMPONENT24, size)
renderbuffer.init() renderbuffer.init()
attach(renderbuffer) attach(renderbuffer)
@ -109,4 +111,10 @@ class OpenGLFramebuffer(var size: Vec2i) : Framebuffer {
delete() delete()
init() init()
} }
protected fun finalize() {
if (state == FramebufferState.COMPLETE && renderSystem.active) {
throw MemoryLeakException("Buffer has not been unloaded!")
}
}
} }

View File

@ -16,28 +16,49 @@ package de.bixilon.minosoft.gui.rendering.system.opengl.buffer.render
import de.bixilon.kotlinglm.vec2.Vec2i import de.bixilon.kotlinglm.vec2.Vec2i
import de.bixilon.minosoft.gui.rendering.system.base.buffer.render.Renderbuffer import de.bixilon.minosoft.gui.rendering.system.base.buffer.render.Renderbuffer
import de.bixilon.minosoft.gui.rendering.system.base.buffer.render.RenderbufferModes import de.bixilon.minosoft.gui.rendering.system.base.buffer.render.RenderbufferModes
import de.bixilon.minosoft.gui.rendering.system.base.buffer.render.RenderbufferStates
import de.bixilon.minosoft.gui.rendering.system.opengl.MemoryLeakException
import de.bixilon.minosoft.gui.rendering.system.opengl.OpenGLRenderSystem
import org.lwjgl.opengl.GL30.* import org.lwjgl.opengl.GL30.*
class OpenGLRenderbuffer( class OpenGLRenderbuffer(
private val renderSystem: OpenGLRenderSystem,
override val mode: RenderbufferModes, override val mode: RenderbufferModes,
override val size: Vec2i, override val size: Vec2i,
) : Renderbuffer { ) : Renderbuffer {
override var state: RenderbufferStates = RenderbufferStates.PREPARING
private set
var id = -1 var id = -1
private set private set
override fun init() { override fun init() {
check(state == RenderbufferStates.PREPARING) { "Can not init renderbuffer in $state" }
id = glGenRenderbuffers() id = glGenRenderbuffers()
bind() unsafeBind()
glRenderbufferStorage(GL_RENDERBUFFER, mode.gl, size.x, size.y) glRenderbufferStorage(GL_RENDERBUFFER, mode.gl, size.x, size.y)
state = RenderbufferStates.GENERATED
} }
fun bind() { fun bind() {
check(state == RenderbufferStates.GENERATED) { "Can not bind renderbuffer in $state" }
unsafeBind()
}
fun unsafeBind() {
glBindRenderbuffer(GL_RENDERBUFFER, id) glBindRenderbuffer(GL_RENDERBUFFER, id)
} }
override fun unload() { override fun unload() {
check(state == RenderbufferStates.GENERATED) { "Can not unload renderbuffer in $state" }
glDeleteRenderbuffers(id) glDeleteRenderbuffers(id)
id = -1 id = -1
state = RenderbufferStates.UNLOADED
}
protected fun finalize() {
if (state == RenderbufferStates.GENERATED && renderSystem.active) {
throw MemoryLeakException("Renderbuffer has not been unloaded!")
}
} }
companion object { companion object {

View File

@ -27,7 +27,8 @@ import java.nio.FloatBuffer
class FloatOpenGLVertexBuffer( class FloatOpenGLVertexBuffer(
renderSystem: OpenGLRenderSystem, renderSystem: OpenGLRenderSystem,
override val structure: MeshStruct, data: FloatBuffer, override val structure: MeshStruct,
data: FloatBuffer,
override val primitiveType: PrimitiveTypes, override val primitiveType: PrimitiveTypes,
) : FloatOpenGLBuffer(renderSystem, data), FloatVertexBuffer { ) : FloatOpenGLBuffer(renderSystem, data), FloatVertexBuffer {
override var vertices = -1 override var vertices = -1
@ -89,7 +90,6 @@ class FloatOpenGLVertexBuffer(
super.unload() super.unload()
} }
private companion object { private companion object {
val PrimitiveTypes.gl: Int val PrimitiveTypes.gl: Int
get() { get() {