feat(renderer): Refactor rendering object pool management and update related tests

This commit is contained in:
extio-de
2025-12-26 17:09:01 +01:00
parent a119b4b5e9
commit c393fa55c8
7 changed files with 132 additions and 40 deletions

View File

@@ -204,6 +204,8 @@ public class G2DRenderer implements Renderer {
for (final RenderingBo bo : usedRenderingBoTypes.values()) {
bo.staticCleanupAfterFrame();
}
this.rendererData.getRenderingBoPool().releasePending();
//
// Rendering cycle END

View File

@@ -26,9 +26,9 @@ public class G2DRendererControl implements RendererControl {
private RendererData rendererData;
private CoordI2 absoluteViewportDimension = ImmutableCoordI2.one();
private CoordI2 absoluteViewportDimension = RendererControl.REFERENCE_RESOLUTION;
private CoordI2 effectiveViewportDimension = ImmutableCoordI2.one();
private CoordI2 effectiveViewportDimension = RendererControl.REFERENCE_RESOLUTION;
private double scaleFactor = 1.0;

View File

@@ -31,7 +31,7 @@ public class RendererWorkingSetImpl implements RendererWorkingSet {
.next()
.put(work.getId(), work);
if (previous != null && previous != work) {
this.rendererBoPool.release(previous);
this.rendererBoPool.returnToPool(previous);
}
}
@@ -41,7 +41,7 @@ public class RendererWorkingSetImpl implements RendererWorkingSet {
for (final RenderingBo bo : work) {
final var previous = nextMap.put(bo.getId(), bo);
if (previous != null && previous != bo) {
this.rendererBoPool.release(previous);
this.rendererBoPool.returnToPool(previous);
}
}
}
@@ -52,7 +52,7 @@ public class RendererWorkingSetImpl implements RendererWorkingSet {
.next()
.remove(id);
if (previous != null) {
this.rendererBoPool.release(previous);
this.rendererBoPool.returnToPool(previous);
}
}
@@ -108,7 +108,7 @@ public class RendererWorkingSetImpl implements RendererWorkingSet {
final var previousLiveSet = previousLiveRef.get();
if (previousLiveSet != null) {
if (clone) {
previousLiveSet.values().forEach(this.rendererBoPool::release);
previousLiveSet.values().forEach(this.rendererBoPool::returnToPool);
}
this.returnMapToPool(previousLiveSet);
}
@@ -119,7 +119,7 @@ public class RendererWorkingSetImpl implements RendererWorkingSet {
@Override
public void clearNext(final String producerId) {
final var next = this.getWorkingSetByProducer(producerId).next();
next.values().forEach(this.rendererBoPool::release);
next.values().forEach(this.rendererBoPool::returnToPool);
next.clear();
}
@@ -127,8 +127,8 @@ public class RendererWorkingSetImpl implements RendererWorkingSet {
public void clear(final String producerId) {
final RendererWork rendererWork = this.workingSet.remove(producerId);
if (rendererWork != null) {
rendererWork.live().values().forEach(this.rendererBoPool::release);
rendererWork.next().values().forEach(this.rendererBoPool::release);
rendererWork.live().values().forEach(this.rendererBoPool::returnToPool);
rendererWork.next().values().forEach(this.rendererBoPool::returnToPool);
}
}

View File

@@ -20,9 +20,14 @@ public interface RenderingBoPool {
<T extends RenderingBo> T copy(T original);
/**
* Releases a rendering business object back to the pool. This is usually managed by the renderer.
* Queues a rendering business object for return back to the pool. Renderer will release the BO after the current rendering cycle is complete.
*/
void release(RenderingBo obj);
void returnToPool(RenderingBo obj);
/**
* Releases all pending rendering business objects back to the pool. This is managed by the renderer.
*/
void releasePending();
void setRendererData(RendererData rendererData);
}

View File

@@ -1,9 +1,13 @@
package de.extio.game_engine.renderer.work;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import de.extio.game_engine.renderer.RendererData;
import de.extio.game_engine.renderer.model.RenderingBo;
@@ -14,6 +18,10 @@ public class RenderingBoPoolImpl implements RenderingBoPool {
private final Map<Class<? extends RenderingBo>, Stack<RenderingBo>> pool = new HashMap<>();
private final BlockingQueue<RenderingBo> returnQueue = new ArrayBlockingQueue<>(1000);
private final Deque<RenderingBo> returnSink = new ArrayDeque<>(1000);
private final LastMapping lastMapping = new LastMapping();
private final LastReverseMapping lastReverseMapping = new LastReverseMapping();
@@ -98,28 +106,37 @@ public class RenderingBoPoolImpl implements RenderingBoPool {
}
@Override
public synchronized void release(final RenderingBo obj) {
public void returnToPool(final RenderingBo obj) {
this.returnQueue.offer(obj);
}
@Override
public synchronized void releasePending() {
try {
obj.close();
final Class<? extends RenderingBo> clazz = obj.getClass();
Stack<RenderingBo> pooled;
if (this.lastReverseMapping != null && this.lastReverseMapping.clazz == clazz) {
pooled = this.lastReverseMapping.pooled;
}
else {
pooled = this.pool.get(clazz);
if (pooled == null) {
pooled = new Stack<>();
this.pool.put(clazz, pooled);
this.returnQueue.drainTo(this.returnSink);
RenderingBo obj;
while ((obj = this.returnSink.poll()) != null) {
obj.close();
final Class<? extends RenderingBo> clazz = obj.getClass();
Stack<RenderingBo> pooled;
if (this.lastReverseMapping != null && this.lastReverseMapping.clazz == clazz) {
pooled = this.lastReverseMapping.pooled;
}
else {
pooled = this.pool.get(clazz);
if (pooled == null) {
pooled = new Stack<>();
this.pool.put(clazz, pooled);
}
this.lastReverseMapping.clazz = clazz;
this.lastReverseMapping.pooled = pooled;
}
this.lastReverseMapping.clazz = clazz;
this.lastReverseMapping.pooled = pooled;
pooled.push(obj);
}
pooled.push(obj);
}
catch (final Exception e) {
throw new RuntimeException(e);