From 470d67403233ed46ba2052ba501ff49c85a71a80 Mon Sep 17 00:00:00 2001 From: squid233 <60126026+squid233@users.noreply.github.com> Date: Fri, 12 Apr 2024 20:09:10 +0800 Subject: [PATCH] Use commons-pool --- build.gradle.kts | 4 +- gradle.properties | 1 + .../client/render/world/ChunkCompileTask.java | 6 +- .../render/world/VertexBuilderPool.java | 67 ----------------- .../client/render/world/WorldRenderer.java | 31 ++++++-- .../client/world/chunk/ClientChunk.java | 72 +++++++++---------- .../src/main/java/module-info.java | 1 + 7 files changed, 70 insertions(+), 112 deletions(-) delete mode 100644 modules/io.github.xenfork.freeworld.client/src/main/java/io/github/xenfork/freeworld/client/render/world/VertexBuilderPool.java diff --git a/build.gradle.kts b/build.gradle.kts index f70cecf..86cdb6a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ * version 2.1 of the License, or (at your option) any later version. */ -// last updated: 2024/3/16 +// last updated: 2024/3/30 plugins { `java-platform` @@ -84,6 +84,7 @@ val coreVersion: String by rootProject val clientVersion: String by rootProject val annotationsVersion: String by rootProject +val commonsPoolVersion: String by rootProject val gsonVersion: String by rootProject val jomlVersion: String by rootProject val logbackVersion: String by rootProject @@ -135,6 +136,7 @@ subprojects { implementation("org.joml:joml:$jomlVersion") implementation("ch.qos.logback:logback-classic:$logbackVersion") implementation("com.google.code.gson:gson:$gsonVersion") + implementation("org.apache.commons:commons-pool2:$commonsPoolVersion") } } diff --git a/gradle.properties b/gradle.properties index 1a713b1..bf1a942 100644 --- a/gradle.properties +++ b/gradle.properties @@ -48,6 +48,7 @@ coreVersion=0.1.0-SNAPSHOT clientVersion=0.1.0-SNAPSHOT annotationsVersion=24.1.0 +commonsPoolVersion=2.12.0 gsonVersion=2.10.1 jomlVersion=1.10.5 logbackVersion=1.4.14 diff --git a/modules/io.github.xenfork.freeworld.client/src/main/java/io/github/xenfork/freeworld/client/render/world/ChunkCompileTask.java b/modules/io.github.xenfork.freeworld.client/src/main/java/io/github/xenfork/freeworld/client/render/world/ChunkCompileTask.java index c4357dc..b1d1d47 100644 --- a/modules/io.github.xenfork.freeworld.client/src/main/java/io/github/xenfork/freeworld/client/render/world/ChunkCompileTask.java +++ b/modules/io.github.xenfork.freeworld.client/src/main/java/io/github/xenfork/freeworld/client/render/world/ChunkCompileTask.java @@ -38,9 +38,9 @@ public ChunkCompileTask(GameRenderer gameRenderer, WorldRenderer worldRenderer, } @Override - public ChunkVertexData call() { + public ChunkVertexData call() throws Exception { final var pool = worldRenderer.vertexBuilderPool(); - final DefaultVertexBuilder builder = pool.acquire(); + final DefaultVertexBuilder builder = pool.borrowObject(); builder.reset(); final int cx = chunk.x(); final int cy = chunk.y(); @@ -79,7 +79,7 @@ public ChunkVertexData call() { builder.shouldReallocateVertexData(), builder.shouldReallocateIndexData() ); - pool.release(builder); + pool.returnObject(builder); return data; } } diff --git a/modules/io.github.xenfork.freeworld.client/src/main/java/io/github/xenfork/freeworld/client/render/world/VertexBuilderPool.java b/modules/io.github.xenfork.freeworld.client/src/main/java/io/github/xenfork/freeworld/client/render/world/VertexBuilderPool.java deleted file mode 100644 index 85158fb..0000000 --- a/modules/io.github.xenfork.freeworld.client/src/main/java/io/github/xenfork/freeworld/client/render/world/VertexBuilderPool.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * freeworld - 3D sandbox game - * Copyright (C) 2024 XenFork Union - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - */ - -package io.github.xenfork.freeworld.client.render.world; - -import io.github.xenfork.freeworld.client.render.builder.VertexBuilder; - -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Supplier; - -/** - * @author squid233 - * @since 0.1.0 - */ -public final class VertexBuilderPool { - private final Map> map = new ConcurrentHashMap<>(); - private final Supplier factory; - - public VertexBuilderPool(Supplier factory) { - this.factory = factory; - } - - private static final class Pair { - final T builder; - final AtomicBoolean acquired; - - Pair(T builder, boolean acquired) { - this.builder = builder; - this.acquired = new AtomicBoolean(acquired); - } - } - - public T acquire() { - for (var entry : map.entrySet()) { - final Pair value = entry.getValue(); - if (!value.acquired.get()) { - value.acquired.set(true); - return value.builder; - } - } - final T t = factory.get(); - final int hashCode = System.identityHashCode(t); - map.put(hashCode, new Pair<>(t, true)); - return t; - } - - public void release(T t) { - Objects.requireNonNull(t); - final int hashCode = System.identityHashCode(t); - if (map.containsKey(hashCode)) { - final Pair pair = map.get(hashCode); - if (pair.acquired.get()) { - pair.acquired.set(false); - } - } - } -} diff --git a/modules/io.github.xenfork.freeworld.client/src/main/java/io/github/xenfork/freeworld/client/render/world/WorldRenderer.java b/modules/io.github.xenfork.freeworld.client/src/main/java/io/github/xenfork/freeworld/client/render/world/WorldRenderer.java index d0745cb..3b21824 100644 --- a/modules/io.github.xenfork.freeworld.client/src/main/java/io/github/xenfork/freeworld/client/render/world/WorldRenderer.java +++ b/modules/io.github.xenfork.freeworld.client/src/main/java/io/github/xenfork/freeworld/client/render/world/WorldRenderer.java @@ -23,6 +23,10 @@ import io.github.xenfork.freeworld.world.block.BlockType; import io.github.xenfork.freeworld.world.chunk.Chunk; import io.github.xenfork.freeworld.world.chunk.ChunkPos; +import org.apache.commons.pool2.BasePooledObjectFactory; +import org.apache.commons.pool2.PooledObject; +import org.apache.commons.pool2.impl.DefaultPooledObject; +import org.apache.commons.pool2.impl.GenericObjectPool; import org.jetbrains.annotations.NotNull; import org.joml.*; @@ -39,7 +43,22 @@ public final class WorldRenderer implements GLResource, WorldListener { private final GameRenderer gameRenderer; private final World world; private final ExecutorService executor; - private final VertexBuilderPool vertexBuilderPool = new VertexBuilderPool<>(WorldRenderer::createVertexBuilder); + private final GenericObjectPool vertexBuilderPool = new GenericObjectPool<>(new BasePooledObjectFactory<>() { + @Override + public DefaultVertexBuilder create() { + return createVertexBuilder(); + } + + @Override + public void activateObject(PooledObject p) { + p.getObject().reset(); + } + + @Override + public PooledObject wrap(DefaultVertexBuilder obj) { + return new DefaultPooledObject<>(obj); + } + }); private final ClientChunk[] chunks; private final FrustumIntersection frustumIntersection = new FrustumIntersection(); private final FrustumRayBuilder frustumRayBuilder = new FrustumRayBuilder(); @@ -83,13 +102,16 @@ private static DefaultVertexBuilder createVertexBuilder() { public void compileChunks() { for (ClientChunk chunk : chunks) { - if (chunk.shouldRecompile && !chunk.submitted) { + if (chunk.dirty) { + if (chunk.future != null && chunk.future.state() == Future.State.RUNNING) { + chunk.future.cancel(false); + } final Chunk chunk1 = world.getChunk(chunk.x(), chunk.y(), chunk.z()); if (chunk1 != null) { chunk.copyFrom(chunk1); } chunk.future = executor.submit(new ChunkCompileTask(gameRenderer, this, chunk)); - chunk.submitted = true; + chunk.dirty = false; } } } @@ -207,13 +229,14 @@ private ClientChunk getChunkByAbsolutePos(int x, int y, int z) { ); } - public VertexBuilderPool vertexBuilderPool() { + public GenericObjectPool vertexBuilderPool() { return vertexBuilderPool; } @Override public void close(GLStateMgr gl) { executor.close(); + vertexBuilderPool.close(); for (ClientChunk chunk : chunks) { chunk.close(gl); } diff --git a/modules/io.github.xenfork.freeworld.client/src/main/java/io/github/xenfork/freeworld/client/world/chunk/ClientChunk.java b/modules/io.github.xenfork.freeworld.client/src/main/java/io/github/xenfork/freeworld/client/world/chunk/ClientChunk.java index 3f06deb..3abd5f5 100644 --- a/modules/io.github.xenfork.freeworld.client/src/main/java/io/github/xenfork/freeworld/client/world/chunk/ClientChunk.java +++ b/modules/io.github.xenfork.freeworld.client/src/main/java/io/github/xenfork/freeworld/client/world/chunk/ClientChunk.java @@ -28,8 +28,10 @@ */ public final class ClientChunk extends Chunk implements GLResource { public Future future = null; - public boolean submitted = false; - public boolean shouldRecompile = true; + /** + * Is this chunk changed? + */ + public boolean dirty = true; private int indexCount = 0; private int vao = 0; private int vbo = 0; @@ -40,43 +42,39 @@ public ClientChunk(World world, int x, int y, int z) { } public void render(GLStateMgr gl) { - if (shouldRecompile && submitted) { - try { - if (future.isDone()) { - final ChunkVertexData data = future.get(); - try { - final MemorySegment vertexData = data.vertexData(); - final MemorySegment indexData = data.indexData(); - indexCount = data.indexCount(); - if (vao == 0) vao = gl.genVertexArrays(); - if (vbo == 0) vbo = gl.genBuffers(); - if (ebo == 0) ebo = gl.genBuffers(); - gl.setVertexArrayBinding(vao); - gl.setArrayBufferBinding(vbo); - if (data.shouldReallocateVertexData()) { - gl.bufferData(GL15C.ARRAY_BUFFER, vertexData, GL15C.DYNAMIC_DRAW); - final VertexLayout layout = data.vertexLayout(); - layout.enableAttribs(gl); - layout.specifyAttribPointers(gl); - } else { - gl.bufferSubData(GL15C.ARRAY_BUFFER, 0L, vertexData); - } - gl.bindBuffer(GL15C.ELEMENT_ARRAY_BUFFER, ebo); - if (data.shouldReallocateIndexData()) { - gl.bufferData(GL15C.ELEMENT_ARRAY_BUFFER, indexData, GL15C.DYNAMIC_DRAW); - } else { - gl.bufferSubData(GL15C.ELEMENT_ARRAY_BUFFER, 0L, indexData); - } - } finally { - data.arena().close(); + try { + if (future != null && future.state() == Future.State.SUCCESS) { + final ChunkVertexData data = future.get(); + try { + final MemorySegment vertexData = data.vertexData(); + final MemorySegment indexData = data.indexData(); + indexCount = data.indexCount(); + if (vao == 0) vao = gl.genVertexArrays(); + if (vbo == 0) vbo = gl.genBuffers(); + if (ebo == 0) ebo = gl.genBuffers(); + gl.setVertexArrayBinding(vao); + gl.setArrayBufferBinding(vbo); + if (data.shouldReallocateVertexData()) { + gl.bufferData(GL15C.ARRAY_BUFFER, vertexData, GL15C.DYNAMIC_DRAW); + final VertexLayout layout = data.vertexLayout(); + layout.enableAttribs(gl); + layout.specifyAttribPointers(gl); + } else { + gl.bufferSubData(GL15C.ARRAY_BUFFER, 0L, vertexData); } - shouldRecompile = false; - submitted = false; - future = null; + gl.bindBuffer(GL15C.ELEMENT_ARRAY_BUFFER, ebo); + if (data.shouldReallocateIndexData()) { + gl.bufferData(GL15C.ELEMENT_ARRAY_BUFFER, indexData, GL15C.DYNAMIC_DRAW); + } else { + gl.bufferSubData(GL15C.ELEMENT_ARRAY_BUFFER, 0L, indexData); + } + } finally { + data.arena().close(); } - } catch (InterruptedException | ExecutionException e) { - throw new RuntimeException(e); + future = null; } + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); } if (vao != 0) { gl.setVertexArrayBinding(vao); @@ -87,7 +85,7 @@ public void render(GLStateMgr gl) { @Override public void markDirty() { super.markDirty(); - shouldRecompile = true; + dirty = true; } @Override diff --git a/modules/io.github.xenfork.freeworld.client/src/main/java/module-info.java b/modules/io.github.xenfork.freeworld.client/src/main/java/module-info.java index 00eb5a8..a314e17 100644 --- a/modules/io.github.xenfork.freeworld.client/src/main/java/module-info.java +++ b/modules/io.github.xenfork.freeworld.client/src/main/java/module-info.java @@ -32,5 +32,6 @@ requires overrungl.glfw; requires overrungl.opengl; requires overrungl.stb; + requires org.apache.commons.pool2; requires static org.jetbrains.annotations; }