Introduce off heap garbage collector

This commit is contained in:
2021-02-01 12:38:11 +01:00
parent 71a1e47d24
commit b6439e010a
25 changed files with 103 additions and 42 deletions

View File

@@ -1,5 +1,6 @@
package com.bartlomiejpluta.base.core.engine; package com.bartlomiejpluta.base.core.engine;
import com.bartlomiejpluta.base.core.gc.OffHeapGarbageCollector;
import com.bartlomiejpluta.base.core.logic.GameLogic; import com.bartlomiejpluta.base.core.logic.GameLogic;
import com.bartlomiejpluta.base.core.thread.ThreadManager; import com.bartlomiejpluta.base.core.thread.ThreadManager;
import com.bartlomiejpluta.base.core.time.ChronoMeter; import com.bartlomiejpluta.base.core.time.ChronoMeter;
@@ -18,6 +19,7 @@ public class DefaultGameEngine implements GameEngine {
private final WindowManager windowManager; private final WindowManager windowManager;
private final ThreadManager threadManager; private final ThreadManager threadManager;
private final GameLogic logic; private final GameLogic logic;
private final OffHeapGarbageCollector garbageCollector;
private final Thread thread; private final Thread thread;
private final Window window; private final Window window;
@@ -30,6 +32,7 @@ public class DefaultGameEngine implements GameEngine {
public DefaultGameEngine(WindowManager windowManager, public DefaultGameEngine(WindowManager windowManager,
ThreadManager threadManager, ThreadManager threadManager,
GameLogic logic, GameLogic logic,
OffHeapGarbageCollector garbageCollector,
@Value("${app.window.title}") String title, @Value("${app.window.title}") String title,
@Value("${app.window.width}") int width, @Value("${app.window.width}") int width,
@Value("${app.window.height}") int height, @Value("${app.window.height}") int height,
@@ -37,6 +40,7 @@ public class DefaultGameEngine implements GameEngine {
this.windowManager = windowManager; this.windowManager = windowManager;
this.threadManager = threadManager; this.threadManager = threadManager;
this.logic = logic; this.logic = logic;
this.garbageCollector = garbageCollector;
this.window = windowManager.createWindow(title, width, height); this.window = windowManager.createWindow(title, width, height);
this.thread = threadManager.createThread(THREAD_NAME, this::run); this.thread = threadManager.createThread(THREAD_NAME, this::run);
@@ -96,7 +100,8 @@ public class DefaultGameEngine implements GameEngine {
} }
private void cleanUp() { private void cleanUp() {
logic.cleanUp(); log.info("Performing off heap garbage collection");
garbageCollector.cleanUp();
} }
@Override @Override

View File

@@ -0,0 +1,5 @@
package com.bartlomiejpluta.base.core.gc;
public interface Cleanable {
void cleanUp();
}

View File

@@ -0,0 +1,22 @@
package com.bartlomiejpluta.base.core.gc;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
@Slf4j
@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class DefaultOffHeapGarbageCollector implements OffHeapGarbageCollector {
private final List<Cleanable> cleanables;
@Override
public void cleanUp() {
cleanables.stream()
.peek(cleanable -> log.info("Performing {} cleaning", cleanable.getClass().getSimpleName()))
.forEach(Cleanable::cleanUp);
}
}

View File

@@ -0,0 +1,5 @@
package com.bartlomiejpluta.base.core.gc;
public interface Disposable {
void dispose();
}

View File

@@ -0,0 +1,5 @@
package com.bartlomiejpluta.base.core.gc;
public interface OffHeapGarbageCollector {
void cleanUp();
}

View File

@@ -1,5 +1,6 @@
package com.bartlomiejpluta.base.core.gl.object.mesh; package com.bartlomiejpluta.base.core.gl.object.mesh;
import com.bartlomiejpluta.base.core.gc.Disposable;
import com.bartlomiejpluta.base.core.gl.render.Renderable; import com.bartlomiejpluta.base.core.gl.render.Renderable;
import com.bartlomiejpluta.base.core.gl.shader.manager.ShaderManager; import com.bartlomiejpluta.base.core.gl.shader.manager.ShaderManager;
import com.bartlomiejpluta.base.core.ui.Window; import com.bartlomiejpluta.base.core.ui.Window;
@@ -13,7 +14,7 @@ import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*; import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*; import static org.lwjgl.opengl.GL30.*;
public class Mesh implements Renderable { public class Mesh implements Renderable, Disposable {
private final int vaoId; private final int vaoId;
private final List<Integer> vboIds = new ArrayList<>(2); private final List<Integer> vboIds = new ArrayList<>(2);
private final int elementsCount; private final int elementsCount;
@@ -65,7 +66,7 @@ public class Mesh implements Renderable {
} }
@Override @Override
public void cleanUp() { public void dispose() {
glDisableVertexAttribArray(0); glDisableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

View File

@@ -29,4 +29,11 @@ public class DefaultTextureManager implements TextureManager {
return texture; return texture;
} }
@Override
public void cleanUp() {
log.info("Disposing textures");
loadedTextures.forEach((name, texture) -> texture.dispose());
log.info("{} textures has been disposed", loadedTextures.size());
}
} }

View File

@@ -1,6 +1,7 @@
package com.bartlomiejpluta.base.core.gl.object.texture; package com.bartlomiejpluta.base.core.gl.object.texture;
import com.bartlomiejpluta.base.core.error.AppException; import com.bartlomiejpluta.base.core.error.AppException;
import com.bartlomiejpluta.base.core.gc.Disposable;
import lombok.Getter; import lombok.Getter;
import org.lwjgl.system.MemoryStack; import org.lwjgl.system.MemoryStack;
@@ -12,7 +13,7 @@ import static org.lwjgl.opengl.GL13.glActiveTexture;
import static org.lwjgl.stb.STBImage.stbi_failure_reason; import static org.lwjgl.stb.STBImage.stbi_failure_reason;
import static org.lwjgl.stb.STBImage.stbi_load_from_memory; import static org.lwjgl.stb.STBImage.stbi_load_from_memory;
public class Texture { public class Texture implements Disposable {
private static final int DESIRED_CHANNELS = 4; private static final int DESIRED_CHANNELS = 4;
private final int textureId; private final int textureId;
@@ -57,4 +58,9 @@ public class Texture {
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureId); glBindTexture(GL_TEXTURE_2D, textureId);
} }
@Override
public void dispose() {
glDeleteTextures(textureId);
}
} }

View File

@@ -1,5 +1,7 @@
package com.bartlomiejpluta.base.core.gl.object.texture; package com.bartlomiejpluta.base.core.gl.object.texture;
public interface TextureManager { import com.bartlomiejpluta.base.core.gc.Cleanable;
public interface TextureManager extends Cleanable {
Texture loadTexture(String textureFileName); Texture loadTexture(String textureFileName);
} }

View File

@@ -57,6 +57,6 @@ public class DefaultRenderer implements Renderer {
@Override @Override
public void cleanUp() { public void cleanUp() {
shaderManager.cleanUp(); log.info("There is nothing to clean up here");
} }
} }

View File

@@ -5,5 +5,4 @@ import com.bartlomiejpluta.base.core.ui.Window;
public interface Renderable { public interface Renderable {
void render(Window window, ShaderManager shaderManager); void render(Window window, ShaderManager shaderManager);
void cleanUp();
} }

View File

@@ -1,11 +1,9 @@
package com.bartlomiejpluta.base.core.gl.render; package com.bartlomiejpluta.base.core.gl.render;
import com.bartlomiejpluta.base.core.gc.Cleanable;
import com.bartlomiejpluta.base.core.ui.Window; import com.bartlomiejpluta.base.core.ui.Window;
public interface Renderer { public interface Renderer extends Cleanable {
void init(); void init();
void render(Window window, Renderable renderable); void render(Window window, Renderable renderable);
void cleanUp();
} }

View File

@@ -142,7 +142,8 @@ public class DefaultShaderManager implements ShaderManager {
@Override @Override
public void cleanUp() { public void cleanUp() {
log.info("Cleaning up shaders"); log.info("Disposing shaders");
shaders.forEach((name, program) -> program.cleanUp()); shaders.forEach((name, program) -> program.dispose());
log.info("{} shaders has been disposed", shaders.size());
} }
} }

View File

@@ -1,9 +1,10 @@
package com.bartlomiejpluta.base.core.gl.shader.manager; package com.bartlomiejpluta.base.core.gl.shader.manager;
import com.bartlomiejpluta.base.core.gc.Cleanable;
import com.bartlomiejpluta.base.core.gl.shader.uniform.Uniform; import com.bartlomiejpluta.base.core.gl.shader.uniform.Uniform;
import org.joml.*; import org.joml.*;
public interface ShaderManager { public interface ShaderManager extends Cleanable {
ShaderManager createShader(String programName, String vertexShaderFilename, String fragmentShaderFilename); ShaderManager createShader(String programName, String vertexShaderFilename, String fragmentShaderFilename);
ShaderManager selectShader(String programName); ShaderManager selectShader(String programName);
@@ -41,6 +42,4 @@ public interface ShaderManager {
ShaderManager setUniform(String uniformName, int index, Uniform uniform); ShaderManager setUniform(String uniformName, int index, Uniform uniform);
ShaderManager setUniforms(String uniformName, Uniform[] uniforms); ShaderManager setUniforms(String uniformName, Uniform[] uniforms);
void cleanUp();
} }

View File

@@ -1,6 +1,7 @@
package com.bartlomiejpluta.base.core.gl.shader.program; package com.bartlomiejpluta.base.core.gl.shader.program;
import com.bartlomiejpluta.base.core.error.AppException; import com.bartlomiejpluta.base.core.error.AppException;
import com.bartlomiejpluta.base.core.gc.Disposable;
import com.bartlomiejpluta.base.core.gl.shader.uniform.Uniform; import com.bartlomiejpluta.base.core.gl.shader.uniform.Uniform;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.joml.*; import org.joml.*;
@@ -13,7 +14,7 @@ import static java.lang.String.format;
import static org.lwjgl.opengl.GL20.*; import static org.lwjgl.opengl.GL20.*;
@Slf4j @Slf4j
public class ShaderProgram { public class ShaderProgram implements Disposable {
private final int programId; private final int programId;
private final int vertexShaderId; private final int vertexShaderId;
private final int fragmentShaderId; private final int fragmentShaderId;
@@ -159,7 +160,8 @@ public class ShaderProgram {
glUseProgram(0); glUseProgram(0);
} }
public void cleanUp() { @Override
public void dispose() {
glUseProgram(0); glUseProgram(0);
if(programId != 0) { if(programId != 0) {

View File

@@ -1,8 +1,9 @@
package com.bartlomiejpluta.base.core.logic; package com.bartlomiejpluta.base.core.logic;
import com.bartlomiejpluta.base.core.gc.Cleanable;
import com.bartlomiejpluta.base.core.ui.Window; import com.bartlomiejpluta.base.core.ui.Window;
public interface GameLogic { public interface GameLogic extends Cleanable {
void init(Window window); void init(Window window);
void input(Window window); void input(Window window);
@@ -10,6 +11,4 @@ public interface GameLogic {
void update(float dt); void update(float dt);
void render(Window window); void render(Window window);
void cleanUp();
} }

View File

@@ -28,6 +28,13 @@ public class DefaultMeshManager implements MeshManager {
return mesh; return mesh;
} }
@Override
public void cleanUp() {
log.info("Disposing meshes");
quads.forEach((dim, mesh) -> mesh.dispose());
log.info("{} meshes has been disposed", quads.size());
}
@Data @Data
private static class QuadDimension { private static class QuadDimension {
private final Vector2f size; private final Vector2f size;

View File

@@ -1,7 +1,8 @@
package com.bartlomiejpluta.base.core.util.mesh; package com.bartlomiejpluta.base.core.util.mesh;
import com.bartlomiejpluta.base.core.gc.Cleanable;
import com.bartlomiejpluta.base.core.gl.object.mesh.Mesh; import com.bartlomiejpluta.base.core.gl.object.mesh.Mesh;
public interface MeshManager { public interface MeshManager extends Cleanable {
Mesh createQuad(float width, float height, float originX, float originY); Mesh createQuad(float width, float height, float originX, float originY);
} }

View File

@@ -5,14 +5,11 @@ import com.bartlomiejpluta.base.core.world.movement.Movement;
import com.bartlomiejpluta.base.core.world.tileset.model.Tile; import com.bartlomiejpluta.base.core.world.tileset.model.Tile;
import com.bartlomiejpluta.base.core.world.tileset.model.TileSet; import com.bartlomiejpluta.base.core.world.tileset.model.TileSet;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.joml.Vector2f; import org.joml.Vector2f;
import org.joml.Vector2i; import org.joml.Vector2i;
import java.util.Arrays; import java.util.Arrays;
import java.util.Objects;
@Slf4j
public class GameMap { public class GameMap {
private static final int LAYERS = 4; private static final int LAYERS = 4;
private final TileSet tileSet; private final TileSet tileSet;
@@ -92,8 +89,4 @@ public class GameMap {
return isTargetReachable && canMoveFromCurrentTile; return isTargetReachable && canMoveFromCurrentTile;
} }
public void cleanUp() {
Arrays.stream(map).flatMap(Arrays::stream).filter(Objects::nonNull).forEach(Tile::cleanUp);
}
} }

View File

@@ -25,11 +25,6 @@ public abstract class RenderableObject extends Object implements Renderable {
mesh.render(window, shaderManager); mesh.render(window, shaderManager);
} }
@Override
public void cleanUp() {
mesh.cleanUp();
}
public void setAlpha(float alpha) { public void setAlpha(float alpha) {
material.setAlpha(alpha); material.setAlpha(alpha);
} }

View File

@@ -7,8 +7,8 @@ import com.bartlomiejpluta.base.core.ui.Window;
import com.bartlomiejpluta.base.core.world.animation.AnimationableObject; import com.bartlomiejpluta.base.core.world.animation.AnimationableObject;
import com.bartlomiejpluta.base.core.world.animation.Animator; import com.bartlomiejpluta.base.core.world.animation.Animator;
import com.bartlomiejpluta.base.core.world.camera.Camera; import com.bartlomiejpluta.base.core.world.camera.Camera;
import com.bartlomiejpluta.base.core.world.object.RenderableObject;
import com.bartlomiejpluta.base.core.world.map.GameMap; import com.bartlomiejpluta.base.core.world.map.GameMap;
import com.bartlomiejpluta.base.core.world.object.RenderableObject;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Setter; import lombok.Setter;
@@ -71,9 +71,4 @@ public class Scene implements Renderable {
object.render(window, shaderManager); object.render(window, shaderManager);
} }
@Override
public void cleanUp() {
map.cleanUp();
}
} }

View File

@@ -34,4 +34,9 @@ public class DefaultTileSetManager implements TileSetManager {
return tileset; return tileset;
} }
@Override
public void cleanUp() {
log.info("There is nothing to clean up here");
}
} }

View File

@@ -1,7 +1,8 @@
package com.bartlomiejpluta.base.core.world.tileset.manager; package com.bartlomiejpluta.base.core.world.tileset.manager;
import com.bartlomiejpluta.base.core.gc.Cleanable;
import com.bartlomiejpluta.base.core.world.tileset.model.TileSet; import com.bartlomiejpluta.base.core.world.tileset.model.TileSet;
public interface TileSetManager { public interface TileSetManager extends Cleanable {
TileSet createTileSet(String tileSetFileName, int rows, int columns); TileSet createTileSet(String tileSetFileName, int rows, int columns);
} }

View File

@@ -6,10 +6,12 @@ import com.bartlomiejpluta.base.core.util.mesh.MeshManager;
import com.bartlomiejpluta.base.game.world.entity.model.Entity; import com.bartlomiejpluta.base.game.world.entity.model.Entity;
import com.bartlomiejpluta.base.game.world.entity.config.EntitySpriteConfiguration; import com.bartlomiejpluta.base.game.world.entity.config.EntitySpriteConfiguration;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.joml.Vector2f; import org.joml.Vector2f;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@Slf4j
@Component @Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired)) @RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class DefaultEntityManager implements EntityManager { public class DefaultEntityManager implements EntityManager {
@@ -28,4 +30,9 @@ public class DefaultEntityManager implements EntityManager {
var spriteHeight = texture.getHeight() / (float) dimension.x; var spriteHeight = texture.getHeight() / (float) dimension.x;
return meshManager.createQuad(spriteWidth, spriteHeight, spriteWidth / 2, spriteHeight*0.9f); return meshManager.createQuad(spriteWidth, spriteHeight, spriteWidth / 2, spriteHeight*0.9f);
} }
@Override
public void cleanUp() {
log.info("There is nothing to clean up");
}
} }

View File

@@ -1,9 +1,10 @@
package com.bartlomiejpluta.base.game.world.entity.manager; package com.bartlomiejpluta.base.game.world.entity.manager;
import com.bartlomiejpluta.base.core.gc.Cleanable;
import com.bartlomiejpluta.base.core.gl.object.material.Material; import com.bartlomiejpluta.base.core.gl.object.material.Material;
import com.bartlomiejpluta.base.game.world.entity.model.Entity; import com.bartlomiejpluta.base.game.world.entity.model.Entity;
import org.joml.Vector2f; import org.joml.Vector2f;
public interface EntityManager { public interface EntityManager extends Cleanable {
Entity createEntity(Material material, Vector2f coordinateStepSize); Entity createEntity(Material material, Vector2f coordinateStepSize);
} }